diff --git a/src/components/Table/__stand__/Table.dev.stand.mdx b/src/components/Table/__stand__/Table.dev.stand.mdx index 2ba9b96..8ad09b2 100644 --- a/src/components/Table/__stand__/Table.dev.stand.mdx +++ b/src/components/Table/__stand__/Table.dev.stand.mdx @@ -17,6 +17,11 @@ import { TableExampleActiveRow } from './examples/TableExampleActiveRow/TableExa import { TableExampleActiveRowWithNumbering } from './examples/TableExampleActiveRowWithNumbering/TableExampleActiveRowWithNumbering'; import { TableExampleRowHoverEffect } from './examples/TableExampleRowHoverEffect/TableExampleRowHoverEffect'; import { TableExampleHoveredControlled } from './examples/TableExampleHoveredControlled/TableExampleHoveredControlled'; +import { TableExampleLoadingDataWithLoader } from './examples/TableExampleLoadingDataWithLoader/TableExampleLoadingDataWithLoader'; +import { TableExampleLoadingDataWithSkeleton } from './examples/TableExampleLoadingDataWithSkeleton/TableExampleLoadingDataWithSkeleton'; +import { TableExampleLoadingRowWithLoader } from './examples/TableExampleLoadingRowWithLoader/TableExampleLoadingRowWithLoader'; +import { TableExampleLoadingRowWithSkeleton } from './examples/TableExampleLoadingRowWithSkeleton/TableExampleLoadingRowWithSkeleton'; +import { TableExampleLoadingNestedRowWithLoader } from './examples/TableExampleLoadingNestedRowWithLoader/TableExampleLoadingNestedRowWithLoader'; import { TableExampleResizableInside, TableExampleResizableOutside, @@ -1030,9 +1035,9 @@ import { action, atom, AtomMut } from '@reatom/core'; import { useAction, useAtom } from '@reatom/npm-react'; import React from 'react'; -import { DataCell } from '##/components/DataCell'; -import { DataNumberingCell } from '##/components/DataNumberingCell'; -import { Table, TableColumn, TableRenderCell } from '##/components/Table'; +import { DataCell } from '@consta/table/DataCell'; +import { DataNumberingCell } from '@consta/table/DataNumberingCell'; +import { Table, TableColumn, TableRenderCell } from '@consta/table/Table'; // Types @@ -1173,7 +1178,7 @@ export const TableExampleActiveRowWithNumbering = () => { import React from 'react'; import { Table, TableColumn } from '@consta/table/Table'; -import rows from '##/components/Table/__mocks__/olympic-winners.json'; +import rows from '@consta/table/Table/__mocks__/olympic-winners.json'; type ROW = { athlete: string; @@ -1351,8 +1356,8 @@ import { atom, AtomMut } from '@reatom/core'; import { useAction, useAtom } from '@reatom/npm-react'; import React from 'react'; -import { DataCell } from '##/components/DataCell'; -import { Table, TableColumn, TableRenderCell } from '##/components/Table'; +import { DataCell } from '@consta/table/DataCell'; +import { Table, TableColumn, TableRenderCell } from '@consta/table/Table'; type ROW = { id: number; @@ -1459,7 +1464,7 @@ import { Example } from '@consta/stand'; import React from 'react'; import { Table, TableColumn } from '@consta/table/Table'; -import rows from '##/components/Table/__mocks__/olympic-winners.json'; +import rows from '@consta/table/Table/__mocks__/olympic-winners.json'; type ROW = { athlete: string; @@ -1515,7 +1520,7 @@ import { Example } from '@consta/stand'; import React from 'react'; import { Table, TableColumn } from '@consta/table/Table'; -import rows from '##/components/Table/__mocks__/olympic-winners.json'; +import rows from '@consta/table/Table/__mocks__/olympic-winners.json'; type ROW = { athlete: string; @@ -1793,7 +1798,7 @@ import { Text } from '@consta/uikit/Text'; import { useMutableRef } from '@consta/uikit/useMutableRef'; import React, { useCallback, useMemo, useState } from 'react'; -import { DataCell } from '##/components/DataCell'; +import { DataCell } from '@consta/table/DataCell'; import { Table, TableColumn, TableRenderCell } from '@consta/table/Table'; const IconArrow = withAnimateSwitcherHOC({ @@ -2034,6 +2039,385 @@ export const TableExampleRenderRow = () => { +## Состояние загрузки + +Загрузку можно отобразить двумя видами с помощью `Loader` или `Skeleton`. + +**Пример загрузки данных всей таблицы с помощью `Loader`:** + + + + + +```tsx +import { Loader } from '@consta/uikit/Loader'; +import React from 'react'; + +import { DataCell } from '@consta/table/DataCell'; +import { Table, TableColumn, TableRenderCell } from '@consta/table/Table'; + +type Item = { + id: number; + label: string; +}; + +type Loader = { + isLoader: true; +}; + +type Row = Item | Loader; + +const data: Row[] = [{ isLoader: true }]; + +const isLoader = (arg: Row): arg is Loader => + Object.prototype.hasOwnProperty.call(arg, 'isLoader'); + +const renderIdCell: TableRenderCell = ({ row }) => { + if (isLoader(row)) { + return ( + + + + ); + } + return {row.id}; +}; + +const columns: TableColumn[] = [ + { + title: 'Номер', + accessor: 'id', + renderCell: renderIdCell, + colSpan: ({ row }) => (isLoader(row) ? 'end' : 1), + minWidth: 300, + }, + { + title: 'Наименование', + accessor: 'label', + minWidth: 300, + }, +]; + +export const TableExampleLoadingDataWithLoader = () => { + return ( + + ); +}; +``` + + + +**Пример загрузки данных всей таблицы с помощью `Skeleton`:** + + + + + +```tsx +import { Loader } from '@consta/uikit/Loader'; +import { cnMixSpace } from '@consta/uikit/MixSpace'; +import { SkeletonBrick } from '@consta/uikit/Skeleton'; +import React from 'react'; + +import { DataCell } from '@consta/table/DataCell'; +import { Table, TableColumn, TableRenderCell } from '@consta/table/Table'; + +type Item = { + id: number; + label: string; +}; + +type Loader = { + isLoader: true; +}; + +type Row = Item | Loader; + +const data: Row[] = [ + { isLoader: true }, + { isLoader: true }, + { isLoader: true }, +]; + +const isLoader = (arg: Row): arg is Loader => + Object.prototype.hasOwnProperty.call(arg, 'isLoader'); + +const renderIdCell: TableRenderCell = ({ row }) => { + if (isLoader(row)) { + return ( +
+ +
+ ); + } + return {row.id}; +}; + +const columns: TableColumn[] = [ + { + title: 'Номер', + accessor: 'id', + renderCell: renderIdCell, + colSpan: ({ row }) => (isLoader(row) ? 'end' : 1), + minWidth: 300, + }, + { + title: 'Наименование', + accessor: 'label', + minWidth: 300, + }, +]; + +export const TableExampleLoadingDataWithSkeleton = () => { + return ( +
+ ); +}; +``` + + + +**Пример подгрузки строки с помощью `Loader`:** + + + + + +```tsx +import { Loader } from '@consta/uikit/Loader'; +import React from 'react'; + +import { DataCell } from '@consta/table/DataCell'; +import { Table, TableColumn, TableRenderCell } from '@consta/table/Table'; + +type Item = { + id: number; + label: string; +}; + +type Loader = { + isLoader: true; +}; + +type Row = Item | Loader; + +const data: Row[] = [ + { id: 1, label: 'Item 1' }, + { id: 2, label: 'Item 2' }, + { id: 3, label: 'Item 3' }, + { isLoader: true }, +]; + +const isLoader = (arg: Row): arg is Loader => + Object.prototype.hasOwnProperty.call(arg, 'isLoader'); + +const renderIdCell: TableRenderCell = ({ row }) => { + if (isLoader(row)) { + return ( + + + + ); + } + return {row.id}; +}; + +const columns: TableColumn[] = [ + { + title: 'Номер', + accessor: 'id', + renderCell: renderIdCell, + colSpan: ({ row }) => (isLoader(row) ? 'end' : 1), + minWidth: 300, + }, + { + title: 'Наименование', + accessor: 'label', + minWidth: 300, + }, +]; + +export const TableExampleLoadingRowWithLoader = () => { + return ( +
(isLoader(row) ? `loader` : `${row.id}`)} + /> + ); +}; +``` + + + +**Пример подгрузки строки с помощью `Skeleton`:** + + + + + +```tsx +import { Loader } from '@consta/uikit/Loader'; +import { cnMixSpace } from '@consta/uikit/MixSpace'; +import { SkeletonBrick } from '@consta/uikit/Skeleton'; +import React from 'react'; + +import { DataCell } from '@consta/table/DataCell'; +import { Table, TableColumn, TableRenderCell } from '@consta/table/Table'; + +type Item = { + id: number; + label: string; +}; + +type Loader = { + isLoader: true; +}; + +type Row = Item | Loader; + +const data: Row[] = [ + { id: 1, label: 'Item 1' }, + { id: 2, label: 'Item 2' }, + { id: 3, label: 'Item 3' }, + { isLoader: true }, +]; + +const isLoader = (arg: Row): arg is Loader => + Object.prototype.hasOwnProperty.call(arg, 'isLoader'); + +const renderIdCell: TableRenderCell = ({ row }) => { + if (isLoader(row)) { + return ( +
+ +
+ ); + } + return {row.id}; +}; + +const columns: TableColumn[] = [ + { + title: 'Номер', + accessor: 'id', + renderCell: renderIdCell, + colSpan: ({ row }) => (isLoader(row) ? 'end' : 1), + minWidth: 300, + }, + { + title: 'Наименование', + accessor: 'label', + minWidth: 300, + }, +]; + +export const TableExampleLoadingRowWithSkeleton = () => { + return ( +
(isLoader(row) ? `loader` : `${row.id}`)} + /> + ); +}; +``` + + + +В состоянии загрузки вы можете показывать не только единую строку-заглушку на всю ширину таблицы. При необходимости `Skeleton` можно отрисовывать отдельно в каждой ячейке. + +**Пример подгрузки вложенной строки с помощью `Loader`:** + + + + + +```tsx +import { IconArrowRight } from '@consta/icons/IconArrowRight'; + +import { Button } from '@consta/uikit/Button'; +import React from 'react'; + +import { DataCell } from '@consta/table/DataCell'; +import { Table, TableColumn, TableRenderCell } from '@consta/table/Table'; + +type Item = { + id: number; + label: string; + loading?: boolean; +}; + +type Row = Item; + +const data: Row[] = [ + { id: 1, label: 'Item 1' }, + { id: 2, label: 'Item 2' }, + { id: 3, label: 'Item 3' }, + { id: 4, label: 'Item 4', loading: true }, + { id: 5, label: 'Item 5' }, + { id: 6, label: 'Item 6' }, + { id: 7, label: 'Item 7' }, +]; + +const renderIdCell: TableRenderCell = ({ row }) => ( + + } + > + {row.id} + +); + +const columns: TableColumn[] = [ + { + title: 'Номер', + accessor: 'id', + renderCell: renderIdCell, + minWidth: 300, + }, + { + title: 'Наименование', + accessor: 'label', + minWidth: 300, + }, +]; + +export const TableExampleLoadingNestedRowWithLoader = () => { + return ( +
row.id} + /> + ); +}; +``` + + + ## Индикатор ячейки и подсказки Для отображения индикатора используйте свойство `indicator` у компонента `DataCell`. Для вывода подсказок используйте компонент `Popover`. В примере ниже реализована логика показа подсказок по наведению курсора. diff --git a/src/components/Table/__stand__/examples/TableExampleLoadingDataWithLoader/TableExampleLoadingDataWithLoader.tsx b/src/components/Table/__stand__/examples/TableExampleLoadingDataWithLoader/TableExampleLoadingDataWithLoader.tsx new file mode 100644 index 0000000..07699a1 --- /dev/null +++ b/src/components/Table/__stand__/examples/TableExampleLoadingDataWithLoader/TableExampleLoadingDataWithLoader.tsx @@ -0,0 +1,61 @@ +import { Example } from '@consta/stand'; +import { Loader } from '@consta/uikit/Loader'; +import React from 'react'; + +import { DataCell } from '##/components/DataCell'; +import { Table, TableColumn, TableRenderCell } from '##/components/Table'; + +type Item = { + id: number; + label: string; +}; + +type Loader = { + isLoader: true; +}; + +type Row = Item | Loader; + +const data: Row[] = [{ isLoader: true }]; + +const isLoader = (arg: Row): arg is Loader => + Object.prototype.hasOwnProperty.call(arg, 'isLoader'); + +const renderIdCell: TableRenderCell = ({ row }) => { + if (isLoader(row)) { + return ( + + + + ); + } + return {row.id}; +}; + +const columns: TableColumn[] = [ + { + title: 'Номер', + accessor: 'id', + renderCell: renderIdCell, + colSpan: ({ row }) => (isLoader(row) ? 'end' : 1), + minWidth: 300, + }, + { + title: 'Наименование', + accessor: 'label', + minWidth: 300, + }, +]; + +export const TableExampleLoadingDataWithLoader = () => { + return ( + +
+ + ); +}; diff --git a/src/components/Table/__stand__/examples/TableExampleLoadingDataWithSkeleton/TableExampleLoadingDataWithSkeleton.tsx b/src/components/Table/__stand__/examples/TableExampleLoadingDataWithSkeleton/TableExampleLoadingDataWithSkeleton.tsx new file mode 100644 index 0000000..16b9bc2 --- /dev/null +++ b/src/components/Table/__stand__/examples/TableExampleLoadingDataWithSkeleton/TableExampleLoadingDataWithSkeleton.tsx @@ -0,0 +1,67 @@ +import { Example } from '@consta/stand'; +import { Loader } from '@consta/uikit/Loader'; +import { cnMixSpace } from '@consta/uikit/MixSpace'; +import { SkeletonBrick } from '@consta/uikit/Skeleton'; +import React from 'react'; + +import { DataCell } from '##/components/DataCell'; +import { Table, TableColumn, TableRenderCell } from '##/components/Table'; + +type Item = { + id: number; + label: string; +}; + +type Loader = { + isLoader: true; +}; + +type Row = Item | Loader; + +const data: Row[] = [ + { isLoader: true }, + { isLoader: true }, + { isLoader: true }, +]; + +const isLoader = (arg: Row): arg is Loader => + Object.prototype.hasOwnProperty.call(arg, 'isLoader'); + +const renderIdCell: TableRenderCell = ({ row }) => { + if (isLoader(row)) { + return ( +
+ +
+ ); + } + return {row.id}; +}; + +const columns: TableColumn[] = [ + { + title: 'Номер', + accessor: 'id', + renderCell: renderIdCell, + colSpan: ({ row }) => (isLoader(row) ? 'end' : 1), + minWidth: 300, + }, + { + title: 'Наименование', + accessor: 'label', + minWidth: 300, + }, +]; + +export const TableExampleLoadingDataWithSkeleton = () => { + return ( + +
+ + ); +}; diff --git a/src/components/Table/__stand__/examples/TableExampleLoadingNestedRowWithLoader/TableExampleLoadingNestedRowWithLoader.tsx b/src/components/Table/__stand__/examples/TableExampleLoadingNestedRowWithLoader/TableExampleLoadingNestedRowWithLoader.tsx new file mode 100644 index 0000000..623df41 --- /dev/null +++ b/src/components/Table/__stand__/examples/TableExampleLoadingNestedRowWithLoader/TableExampleLoadingNestedRowWithLoader.tsx @@ -0,0 +1,68 @@ +import { IconArrowRight } from '@consta/icons/IconArrowRight'; +import { Example } from '@consta/stand'; +import { Button } from '@consta/uikit/Button'; +import React from 'react'; + +import { DataCell } from '##/components/DataCell'; +import { Table, TableColumn, TableRenderCell } from '##/components/Table'; + +type Item = { + id: number; + label: string; + loading?: boolean; +}; + +type Row = Item; + +const data: Row[] = [ + { id: 1, label: 'Item 1' }, + { id: 2, label: 'Item 2' }, + { id: 3, label: 'Item 3' }, + { id: 4, label: 'Item 4', loading: true }, + { id: 5, label: 'Item 5' }, + { id: 6, label: 'Item 6' }, + { id: 7, label: 'Item 7' }, +]; + +const renderIdCell: TableRenderCell = ({ row }) => ( + + } + > + {row.id} + +); + +const columns: TableColumn[] = [ + { + title: 'Номер', + accessor: 'id', + renderCell: renderIdCell, + minWidth: 300, + }, + { + title: 'Наименование', + accessor: 'label', + minWidth: 300, + }, +]; + +export const TableExampleLoadingNestedRowWithLoader = () => { + return ( + +
row.id} + /> + + ); +}; diff --git a/src/components/Table/__stand__/examples/TableExampleLoadingRowWithLoader/TableExampleLoadingRowWithLoader.tsx b/src/components/Table/__stand__/examples/TableExampleLoadingRowWithLoader/TableExampleLoadingRowWithLoader.tsx new file mode 100644 index 0000000..fa49b35 --- /dev/null +++ b/src/components/Table/__stand__/examples/TableExampleLoadingRowWithLoader/TableExampleLoadingRowWithLoader.tsx @@ -0,0 +1,67 @@ +import { Example } from '@consta/stand'; +import { Loader } from '@consta/uikit/Loader'; +import React from 'react'; + +import { DataCell } from '##/components/DataCell'; +import { Table, TableColumn, TableRenderCell } from '##/components/Table'; + +type Item = { + id: number; + label: string; +}; + +type Loader = { + isLoader: true; +}; + +type Row = Item | Loader; + +const data: Row[] = [ + { id: 1, label: 'Item 1' }, + { id: 2, label: 'Item 2' }, + { id: 3, label: 'Item 3' }, + { isLoader: true }, +]; + +const isLoader = (arg: Row): arg is Loader => + Object.prototype.hasOwnProperty.call(arg, 'isLoader'); + +const renderIdCell: TableRenderCell = ({ row }) => { + if (isLoader(row)) { + return ( + + + + ); + } + return {row.id}; +}; + +const columns: TableColumn[] = [ + { + title: 'Номер', + accessor: 'id', + renderCell: renderIdCell, + colSpan: ({ row }) => (isLoader(row) ? 'end' : 1), + minWidth: 300, + }, + { + title: 'Наименование', + accessor: 'label', + minWidth: 300, + }, +]; + +export const TableExampleLoadingRowWithLoader = () => { + return ( + +
(isLoader(row) ? `loader` : `${row.id}`)} + /> + + ); +}; diff --git a/src/components/Table/__stand__/examples/TableExampleLoadingRowWithSkeleton/TableExampleLoadingRowWithSkeleton.tsx b/src/components/Table/__stand__/examples/TableExampleLoadingRowWithSkeleton/TableExampleLoadingRowWithSkeleton.tsx new file mode 100644 index 0000000..2920aad --- /dev/null +++ b/src/components/Table/__stand__/examples/TableExampleLoadingRowWithSkeleton/TableExampleLoadingRowWithSkeleton.tsx @@ -0,0 +1,69 @@ +import { Example } from '@consta/stand'; +import { Loader } from '@consta/uikit/Loader'; +import { cnMixSpace } from '@consta/uikit/MixSpace'; +import { SkeletonBrick } from '@consta/uikit/Skeleton'; +import React from 'react'; + +import { DataCell } from '##/components/DataCell'; +import { Table, TableColumn, TableRenderCell } from '##/components/Table'; + +type Item = { + id: number; + label: string; +}; + +type Loader = { + isLoader: true; +}; + +type Row = Item | Loader; + +const data: Row[] = [ + { id: 1, label: 'Item 1' }, + { id: 2, label: 'Item 2' }, + { id: 3, label: 'Item 3' }, + { isLoader: true }, +]; + +const isLoader = (arg: Row): arg is Loader => + Object.prototype.hasOwnProperty.call(arg, 'isLoader'); + +const renderIdCell: TableRenderCell = ({ row }) => { + if (isLoader(row)) { + return ( +
+ +
+ ); + } + return {row.id}; +}; + +const columns: TableColumn[] = [ + { + title: 'Номер', + accessor: 'id', + renderCell: renderIdCell, + colSpan: ({ row }) => (isLoader(row) ? 'end' : 1), + minWidth: 300, + }, + { + title: 'Наименование', + accessor: 'label', + minWidth: 300, + }, +]; + +export const TableExampleLoadingRowWithSkeleton = () => { + return ( + +
(isLoader(row) ? `loader` : `${row.id}`)} + /> + + ); +};