3.1.1 • Published 3 months ago

@eisgs/table v3.1.1

Weekly downloads
-
License
MIT
Repository
-
Last release
3 months ago

Компонент Table

columns в качестве опций принимает массив с ключами id,title,renderInfo,render,sort,styles

variant переключает внешний вид шапки

cellAlign выравнивает контент в ячейках, subColumns наследуют переданное значение

sort и onSort управляют сортировкой. sort объект с ключами key и direction

import { Typography } from '@eisgs/typography';
import { Radio } from '@eisgs/radio';
import { Checkbox } from '@eisgs/checkbox';

const columns = [
  {
    id: 1,
    title: 'Адрес объекта',
    size: 2,
    renderInfo: 'Подсказка к колонке',
    render: ({ address }) => (
      <Typography type="p2" weight="bold">
        {address}
      </Typography>
    ),
    sort: {
      key: 'address',
    },
  },
  {
    id: 2,
    title: 'Застройщик банкрот',
    size: 2,
    render: ({ developer }) => (
      <Typography type="p2">
        {developer}
      </Typography>
    ),
    sort: {
      key: 'developer',
    },
  },
  {
    id: 3,
    title: 'Решение наб.совета Фонда',
    render: ({ decision }) => (
      <Typography type="p2">
        {decision}
      </Typography>
    ),
    sort: {
      key: 'decision',
    },
  },
  {
    id: 4,
    title: 'Определение арбитражного суда',
    render: ({ definition }) => (
      <Typography type="p2">
        {definition}
      </Typography>
    ),
    sort: {
      key: 'definition',
    },
  },
  {
    id: 5,
    title: 'Статус объекта',
    render: ({ status }) => (
      <Typography type="p2">
        {status}
      </Typography>
    ),
    sort: {
      key: 'status',
      direction: 'DESC',
    },
  },
];
const data = [
  {
    address: 'город Москва, Ленинградский проспект, д. 14',
    developer: 'ООО Одуванчик',
    decision: 'Нет',
    definition: 'Нет',
    status: 0,
  },
  {
    address: 'город Магадан, район Центральный, улица Строителей, д. 77',
    developer: 'ООО ЛенИнвестСтрой',
    decision: 'Есть',
    definition: 'Есть',
    status: 6,
  },
  {
    address: 'город Москва, Ленинградский проспект, д. 14',
    developer: 'ООО Одуванчик',
    decision: 'Есть',
    definition: 'Есть',
    status: 29,
  },
  {
    address: 'город Екатеринбург, район Верх-Исетский, улица Суходольская, д. 2',
    developer: 'ООО Успех',
    decision: 'Нет',
    definition: 'Есть',
    status: 3,
  },
  {
    address: 'город Магадан, район Центральный, улица Строителей, д. 77',
    developer: 'ООО ЛенИнвестСтрой',
    decision: 'Есть',
    definition: 'Нет',
    status: 1,
  },
  {
    address: 'город Магадан, район Центральный, улица Строителей, д. 77',
    developer: 'ООО ЛенИнвестСтрой',
    decision: 'Нет',
    definition: 'Есть',
    status: 25,
  },
];
const ColumnKeys = ['address', 'developer', 'decision', 'definition', 'status'];
const variantOptions = ['base', 'inner', 'sidebar'].map((variant) => ({ id: variant, description: variant, code: variant }));

const [tableData, setTableData] = React.useState(data);
const [sort, setSort] = React.useState(undefined);
const [variant, setVariant] = React.useState(variantOptions[0].code);
const [cellAlign, setCellAlign] = React.useState(false);

const handleSort = (argSort) => {
  setSort(argSort);
  if (argSort && !argSort.key) {
    return;
  }
  if (ColumnKeys.includes(argSort.key)) {
    const sorted = [...tableData].sort((a, b) => {
      if (argSort.direction === 'ASC') {
        return a[argSort.key] > b[argSort.key] ? 1 : -1;
      }
      return a[argSort.key] > b[argSort.key] ? -1 : 1;
    });
    setTableData(sorted);
  }
};

<>
  <Typography type="p1" weight="bold" style={{ margin: '20px 0' }}>
    Variant:
  </Typography>
  <Radio options={variantOptions} onChange={setVariant} value={variant} />
  <Typography type="p1" weight="bold" style={{ margin: '20px 0' }}>
    Cell align:
  </Typography>
  <Checkbox onChange={setCellAlign} checked={cellAlign}>
    Top
  </Checkbox>
    
  <Table
    {...cellAlign && {cellAlign: 'top'}}
    variant={variant}
    columns={columns} 
    data={tableData} 
    sort={sort} 
    onSort={handleSort}
  />
</>;

Вложенные таблицы

Для отображения вложенных элементов необходимо передать конфиг subColumns, по аналогии с columns.

Чтобы по нажатию на <Row> отображались подтаблицы, необходимо передать флаг withSubRowCollapseOnClick.

Ожидается, что в <Table> будет передан параметр subColumnsDataKey, который представляет собой ключ в массив данных, содержимое которого будет использовано при рендере подтаблиц.

Для кастомной логики есть возможность передать кастомный компонент SubRowComponent.

В массиве с данными в data крайне желательно иметь стабильные ID у элементов. В противном случае, при, например, сортировке данных, т.е. при измении data, информация о открытых/закрытых подтаблиц будет потеряна.

import { Typography } from '@eisgs/typography';
import { Radio } from '@eisgs/radio';
import { Checkbox } from '@eisgs/checkbox';

const columns = [
  {
    id: 1,
    title: 'Адрес объекта',
    size: 2,
    renderInfo: 'Подсказка к колонке',
    render: ({ address }) => (
      <Typography type="p2" weight="bold">
        {address}
      </Typography>
    ),
    sort: {
      key: 'address',
    },
  },
  {
    id: 2,
    title: 'Застройщик банкрот',
    size: 2,
    render: ({ developer }) => (
      <Typography type="p2">
        {developer}
      </Typography>
    ),
    sort: {
      key: 'developer',
    },
  },
  {
    id: 3,
    title: 'Решение наб.совета Фонда',
    render: ({ decision }) => (
      <Typography type="p2">
        {decision}
      </Typography>
    ),
    sort: {
      key: 'decision',
    },
  },
  {
    id: 4,
    title: 'Определение арбитражного суда',
    render: ({ definition }) => (
      <Typography type="p2">
        {definition}
      </Typography>
    ),
    sort: {
      key: 'definition',
    },
  },
  {
    id: 5,
    title: 'Статус объекта',
    render: ({ status }) => (
      <Typography type="p2">
        {status}
      </Typography>
    ),
    sort: {
      key: 'status',
      direction: 'DESC',
    },
  },
];
const subColumns = [
  {
    id: 1,
    title: 'Sub table',
    size: 2,
    renderInfo: 'Подсказка к колонке',
    render: ({ address }) => (
      <Typography type="p2">
        {address}
      </Typography>
    ),
  },
  {
    id: 2,
    title: 'Sub table',
    size: 2,
    renderInfo: 'Подсказка к колонке',
    render: ({ developer }) => (
      <Typography type="p2">
        {developer}
      </Typography>
    ),
  },
  {
    id: 3,
    title: 'Sub table',
    renderInfo: 'Подсказка к колонке',
    render: ({ decision }) => (
      <Typography type="p2">
        {decision}
      </Typography>
    ),
  },
  {
    id: 4,
    title: 'Sub table',
    renderInfo: 'Подсказка к колонке',
    render: ({ definition }) => (
      <Typography type="p2">
        {definition}
      </Typography>
    ),
  },
  {
    id: 5,
    title: 'Sub table',
    renderInfo: 'Подсказка к колонке',
    render: ({ status }) => (
      <Typography type="p2">
        {status}
      </Typography>
    ),
  },
]
const data = [
  {
    id: 'id1',
    address: 'город Москва, Ленинградский проспект, д. 14',
    developer: 'ООО Одуванчик',
    decision: 'Нет',
    definition: 'Нет',
    status: 0,
    history: [
      {
        id: 1,
        address: 'город Москва, Ленинградский проспект, д. 14 город Москва, Ленинградский проспект, д. 14',
        developer: 'ООО Одуванчик',
        decision: 'Нет',
        definition: 'Нет',
        status: 0,
      },
      {
        id: 2,
        address: 'город Москва, Ленинградский проспект, д. 14',
        developer: 'ООО Одуванчик',
        decision: 'Нет',
        definition: 'Нет',
        status: 0,
      },
    ],
  },
  {
    id: 'id2',
    address: 'город Москва, Неленинградский проспект, д. 14',
    developer: 'ООО Одуванчик',
    decision: 'Нет',
    definition: 'Нет',
    status: 0,
    history: [
      {
        id: 1,
        address: 'город Москва, Ленинградский проспект, д. 14',
        developer: 'ООО Одуванчик',
        decision: 'Нет',
        definition: 'Нет',
        status: 0,
      },
      {
        id: 2,
        address: 'город Москва, Ленинградский проспект, д. 14',
        developer: 'ООО Одуванчик',
        decision: 'Нет',
        definition: 'Нет',
        status: 0,
      },
    ],
  },
];
const ColumnKeys = ['address', 'developer', 'decision', 'definition', 'status'];
const variantOptions = ['base', 'inner', 'sidebar'].map((variant) => ({ id: variant, description: variant, code: variant }));

const [tableData, setTableData] = React.useState(data);
const [sort, setSort] = React.useState(undefined);
const [variant, setVariant] = React.useState(variantOptions[0].code);
const [cellAlign, setCellAlign] = React.useState(false);

const handleSort = (argSort) => {
  setSort(argSort);
  if (argSort && !argSort.key) {
    return;
  }
  if (ColumnKeys.includes(argSort.key)) {
    const sorted = [...tableData].sort((a, b) => {
      if (argSort.direction === 'ASC') {
        return a[argSort.key] > b[argSort.key] ? 1 : -1;
      }
      return a[argSort.key] > b[argSort.key] ? -1 : 1;
    });
    setTableData(sorted);
  }
};

const SubRowComponent = ({ row }) => {
  return <code>{JSON.stringify(row)}</code>;
}

<>
  <Typography type="p1" weight="bold" style={{ margin: '20px 0' }}>
    Variant:
  </Typography>
  <Radio options={variantOptions} onChange={setVariant} value={variant} />
  <Typography type="p1" weight="bold" style={{ margin: '20px 0' }}>
    Cell align:
  </Typography>
  <Checkbox onChange={setCellAlign} checked={cellAlign}>
    Top
  </Checkbox>
    
  <Table
    {...cellAlign && {cellAlign: 'top'}}
    withSubRowCollapseOnClick
    variant={variant}
    columns={columns}
    subColumns={subColumns}
    data={tableData}
    subColumnsDataKey="history"
    onSubRowClick={() => { alert('Обработчик нажатия на subRow'); }}
    sort={sort}
    onSort={handleSort}
  />

  <Typography type="p1" style={{ margin: '20px 0' }}>
    Кастомный SubRowComponent
  </Typography>

  <Table
    {...cellAlign && {cellAlign: 'top'}}
    withSubRowCollapseOnClick
    variant={variant}
    columns={columns}
    subColumns={subColumns}
    data={tableData}
    subColumnsDataKey="history"
    onSubRowClick={() => { alert('Обработчик нажатия на subRow'); }}
    sort={sort}
    onSort={handleSort}
    SubRowComponent={<SubRowComponent />}
  />
</>

Пагинация

В компонент можно передать конфиг для пагинации pagination (принимает все обязательные параметры компонента Pagination), по умолчанию пагинация отключена

import { Typography } from '@eisgs/typography';

const columns = [
  {
    id: 1,
    title: 'Адрес объекта',
    size: 2,
    renderInfo: 'Подсказка к колонке',
    render: ({ address }) => (
      <Typography type="p2" weight="bold">
        {address}
      </Typography>
    ),
    sort: {
      key: 'address',
    },
  },
  {
    id: 2,
    title: 'Застройщик банкрот',
    size: 2,
    render: ({ developer }) => (
      <Typography type="p2">
        {developer}
      </Typography>
    ),
    sort: {
      key: 'developer',
    },
  },
  {
    id: 3,
    title: 'Решение наб.совета Фонда',
    render: ({ decision }) => (
      <Typography type="p2">
        {decision}
      </Typography>
    ),
    sort: {
      key: 'decision',
    },
  },
  {
    id: 4,
    title: 'Определение арбитражного суда',
    render: ({ definition }) => (
      <Typography type="p2">
        {definition}
      </Typography>
    ),
    sort: {
      key: 'definition',
    },
  },
  {
    id: 5,
    title: 'Статус объекта',
    render: ({ status }) => (
      <Typography type="p2">
        {status}
      </Typography>
    ),
    sort: {
      key: 'status',
      direction: 'DESC',
    },
  },
];

function getRandom(min, max) {
  return min + Math.random() * (max - min);
}

const data = Array.from(Array(100)).map((_, index) => {
  const realIndex = index + 1;
  const random = getRandom(0, 1);
  
  return {
    address: `Адрес ${realIndex}`,
    developer: `${random > .5 ? 'ООО' : 'ЗАО'} Застройщик ${realIndex}`,
    decision: random > .5 ? 'Есть' : 'Нет',
    definition: random > .5 ? 'Есть' : 'Нет',
    status: realIndex,
  }
})

const ColumnKeys = ['address', 'developer', 'decision', 'definition', 'status'];
const limits = [10, 20, 50];

const [tableData, setTableData] = React.useState(data);
const [sort, setSort] = React.useState(undefined);
const [page, setPage] = React.useState(1);
const [limit, setLimit] = React.useState(limits[0]);

const dataByParams = tableData.slice((page - 1) * limit, page * limit);
const total = tableData.length;

const handleSort = (argSort) => {
  setSort(argSort);
  
  if (argSort && !argSort.key) {
    return;
  }
  
  if (ColumnKeys.includes(argSort.key)) {
    const sorted = [...tableData].sort((a, b) => {
      if (argSort.direction === 'ASC') {
        return a[argSort.key] > b[argSort.key] ? 1 : -1;
      }
      
      return a[argSort.key] > b[argSort.key] ? -1 : 1;
    });
    
    setTableData(sorted);
  }
};

const pagination = React.useMemo(() => ({
  limit,
  limits,
  page,
  total,
  onLimitChange: setLimit,
  onPageChange: setPage,
}), [limits, limit, page, total]);

<Table 
  variant="base" 
  columns={columns} 
  data={tableData.slice((page - 1) * limit, page * limit)} 
  sort={sort} 
  onSort={handleSort}
  pagination={{
    limit,
    limits,
    page,
    total: tableData.length,
    onLimitChange: setLimit,
    onPageChange: setPage,
  }}
/>
3.1.1

3 months ago

3.1.0

4 months ago

3.0.0

1 year ago

2.0.7

1 year ago

2.1.0

1 year ago

2.0.5

2 years ago

2.0.4

2 years ago

2.0.6

1 year ago

2.0.3

2 years ago

2.0.2

2 years ago

2.0.0

2 years ago

1.2.0

2 years ago

1.2.3

2 years ago

1.2.2

2 years ago

1.1.3

2 years ago

1.1.2

3 years ago

1.1.1

3 years ago

1.1.0

3 years ago

1.0.6

3 years ago

1.0.2

3 years ago

1.0.5

3 years ago

1.0.4

3 years ago

1.0.3

3 years ago

1.0.1

3 years ago