Version

Table

Interactive table with selection and keyboard navigation support.

Table

Example
<div id="demo"></div>
body {
  margin: 0;
  padding: 0;
}
import React, {Component, createElement} from 'react';
import {render} from 'react-dom';
import Table, {THEMES} from '@jetbrains/ring-ui/components/table/table';
import Selection from '@jetbrains/ring-ui/components/table/selection';
import {Grid, Row, Col} from '@jetbrains/ring-ui/components/grid/grid';
import Link from '@jetbrains/ring-ui/components/link/link';
import Pager from '@jetbrains/ring-ui/components/pager/pager';
import Button from '@jetbrains/ring-ui/components/button/button';
import mock from '@jetbrains/ring-ui/components/table/table.examples.json';

const pageSize = 7;
const total = mock.length;

class Example extends Component {
  state = {
    data: [],
    selection: new Selection(),
    caption: undefined,
    selectable: true,
    draggable: true,
    page: 1,
    pageSize,
    total,
    sortKey: 'country',
    sortOrder: true,
    loading: false
  }

  columns = [
    {
      id: 'country',
      title: 'Country',
      sortable: true
    },

    {
      id: 'id',
      title: 'ID',
      rightAlign: true
    },

    {
      id: 'city',
      title: 'City',
      sortable: true
    },

    {
      id: 'url',
      title: 'URL',
      getValue: ({url}) => <Link href={url}>{url}</Link>
    }
  ]

  onSort = ({column: {id: sortKey}, order: sortOrder}) => {
    this.setState({sortKey, sortOrder});
  }

  onPageChange = page => {
    this.setState({page});
  }

  componentWillMount() {
    this.loadPage();
  }

  componentDidUpdate(prevProps, prevState) {
    const {page, sortKey, sortOrder} = this.state;
    if (page !== prevState.page || sortKey !== prevState.sortKey || sortOrder !== prevState.sortOrder) {
      this.loadPage();
    }
  }

  isItemSelectable(item) {
    return item.id !== 14;
  }

  loadPage = () => {
    const {page, pageSize, sortKey, sortOrder} = this.state;

    let data = [...mock];
    data.sort((a, b) => a[sortKey].localeCompare(b[sortKey]) * (sortOrder ? 1 : -1));
    data = data.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize);

    const selection = new Selection({data, isItemSelectable: this.isItemSelectable});

    this.setState({data, selection});
  }

  render() {
    const {data, caption, selectable, draggable,  loading, page, pageSize, total, selection, sortKey, sortOrder} = this.state;

    return (
      <div>
        <Table
          data={data}
          columns={this.columns}
          selection={selection}
          onSelect={selection => this.setState({selection})}
          onReorder={({data}) => this.setState({data})}
          loading={loading}
          onSort={this.onSort}
          sortKey={sortKey}
          sortOrder={sortOrder}
          caption={caption}
          selectable={selectable}
          isItemSelectable={this.isItemSelectable}
          draggable={draggable}
          autofocus
        />

        <Grid>
          <Row>
            <Col>
              <Pager
                total={total}
                pageSize={pageSize}
                currentPage={page}
                disablePageSizeSelector
                onPageChange={this.onPageChange}
              />
            </Col>
          </Row>

          <Row>
            <Col>Active items: {[...selection.getActive()].map(item => item.country).join(', ')}</Col>
          </Row>

          <Row>
            <Col>
              <Button onClick={() => this.setState({data: [...this.state.data]}) }>Recreate data array</Button>
              {" "}
              <span id="button-non-selectable">
              {
                selectable
                ? <Button onClick={() => this.setState({selectable: false})}>Non-selectable</Button>
                : <Button onClick={() => this.setState({selectable: true})}>Selectable</Button>
              }
              </span>

              {" "}
              {  draggable
                ? <Button onClick={() => this.setState({draggable: false})}>Non-draggable</Button>
                : <Button onClick={() => this.setState({draggable: true})}>Draggable</Button>
              }
              {" "}

              <span id="button-with-a-caption">
              {" "}
              {
                caption
                ? <Button onClick={() => this.setState({caption: undefined})}>Without a caption</Button>
                : <Button onClick={() => this.setState({caption: 'Countries'})}>With a caption</Button>
              }
              {" "}
              </span>
              {" "}

              {
                loading
                ? <Button onClick={() => this.setState({loading: false})}>Not loading</Button>
                : <Button onClick={() => this.setState({loading: true})}>Loading</Button>
              }
            </Col>
          </Row>

          {page === 1 && data.length > 5 && <Row>
            <Col>
            <span id="button-select-bulgaria">{
              selection.isSelected(data[3])
              ? <Button onClick={() => this.setState({selection: selection.deselect(data[3])})}>Deselect {data[3].country}</Button>
              : <Button onClick={() => this.setState({selection: selection.select(data[3])})}>Select {data[3].country}</Button>
            }
            </span>

              <span id="button-select-finland">{" "}
              {selection.isSelected(data[5])
              ? <Button onClick={() => this.setState({selection: selection.deselect(data[5])})}>Deselect {data[5].country}</Button>
              : <Button onClick={() => this.setState({selection: selection.select(data[5])})}>Select {data[5].country}</Button>
            }</span>
            </Col>
          </Row>}
        </Grid>
      </div>
    );
  }
}

render(createElement(Example, {}), document.getElementById('demo'));

MultiTable

Example
<div id="demo"></div>
body {
  margin: 0;
  padding: 0;
}
import React, {Component, createElement} from 'react';
import {render} from 'react-dom';
import MultiTable from '@jetbrains/ring-ui/components/table/multitable';
import Table from '@jetbrains/ring-ui/components/table/table';
import mock from '@jetbrains/ring-ui/components/table/table.examples2.json';
import Selection from '@jetbrains/ring-ui/components/table/selection';

const data1 = mock.continents;
const data2 = mock.countries;

class Example extends Component {
  state = {
    selection1: new Selection({data: data1}),
    selection2: new Selection({data: data2})
  };

  columns1 = [
    {
      id: 'continent',
      title: 'Continent'
    },
    {
      id: 'url',
      title: 'URL'
    }
  ]

  columns2 = [
    {
      id: 'country',
      title: 'Country'
    },
    {
      id: 'city',
      title: 'City'
    },
    {
      id: 'url',
      title: 'URL'
    }
  ]

  render() {
    return (
      <MultiTable>
        <Table
          data={data1}
          columns={this.columns1}
          caption="Continents"
          selection={this.state.selection1}
          onSelect={selection => this.setState({selection1: selection})}
        />

        <Table
          data={data2}
          columns={this.columns2}
          caption="Countries"
          autofocus
          selection={this.state.selection2}
          onSelect={selection => this.setState({selection2: selection})}
        />
      </MultiTable>
    );
  }
}

render(createElement(Example, {}), document.getElementById('demo'));