@snack-uikit/table 0.18.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,29 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 0.19.0 (2024-06-06)
7
+
8
+
9
+ ### Features
10
+
11
+ * **PDS-287:** add row pinning functionality to table ([f33a911](https://github.com/cloud-ru-tech/snack-uikit/commit/f33a9116d78de8ab09a01a0db22999e09c7fd773))
12
+
13
+
14
+
15
+
16
+
17
+ ## 0.18.1 (2024-06-06)
18
+
19
+ ### Only dependencies have been changed
20
+ * [@snack-uikit/chips@0.14.7](https://github.com/cloud-ru-tech/snack-uikit/blob/master/packages/chips/CHANGELOG.md)
21
+ * [@snack-uikit/info-block@0.4.0](https://github.com/cloud-ru-tech/snack-uikit/blob/master/packages/info-block/CHANGELOG.md)
22
+ * [@snack-uikit/list@0.13.5](https://github.com/cloud-ru-tech/snack-uikit/blob/master/packages/list/CHANGELOG.md)
23
+ * [@snack-uikit/toolbar@0.7.40](https://github.com/cloud-ru-tech/snack-uikit/blob/master/packages/toolbar/CHANGELOG.md)
24
+
25
+
26
+
27
+
28
+
6
29
  # 0.18.0 (2024-06-03)
7
30
 
8
31
 
package/README.md CHANGED
@@ -111,6 +111,8 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
111
111
  |------|------|---------------|-------------|
112
112
  | columnDefinitions* | `ColumnDefinition<TData>[]` | - | Определение внешнего вида и функционала колонок |
113
113
  | data* | `TData[]` | - | Данные для отрисовки |
114
+ | keepPinnedRows | `boolean` | - | Параметр овтечает за сохранение закрепленных строк на всех страницах таблицы |
115
+ | enableSelectPinned | `boolean` | - | Параметр овтечает за чекбокс выбора закрепленных строк |
114
116
  | sorting | `{ initialState?: SortingState; state?: SortingState; onChange?(state: SortingState): void; }` | - | Параметры отвечают за возможность сортировки, их стоит использовать если нужно отслеживать состояние <br> <strong>initialState</strong>: Начальное состояние сортировки <br> <strong>state</strong>: Состояние сортировки, жестко устанавливаемое снаружи <br> <strong>onChange</strong>: Колбэк на изменение сортировки |
115
117
  | rowSelection | `{ initialState?: RowSelectionState; state?: RowSelectionState; enable?: boolean \| ((row: Row<TData>) => boolean); multiRow?: boolean; onChange?(state: RowSelectionState): void; }` | - | Параметры отвечают за возможность выбора строк <br> <strong>initialState</strong>: Начальное состояние выбора строк <br> <strong>state</strong>: Состояние выбора строк, жестко устанавливаемое снаружи <br> <strong>enable</strong>: Колбэк определяющий можно ли выбрать строку <br> <strong>multiRow</strong>: Мульти-выбор строк (включен по-умолчанию, когда включается выбор) <br> <strong>onChange</strong>: Колбэк на выбор строк |
116
118
  | search | `{ initialState?: string; state?: string; placeholder?: string; loading?: boolean; onChange?(value: string): void; }` | 'Search'<br> <strong>loading</strong>: Состояние загрузки в строке поиска <br> <strong>onChange</strong>: Колбэк на изменение данных в строке поиска | Параметры отвечают за глобальный поиск в таблице <br> <strong>initialState</strong>: Начальное состояние строки поиска <br> <strong>state</strong>: Состояние строки поиска, жестко устанавливаемое снаружи <br> <strong>placeholder</strong>: Placeholder строки поиска |
@@ -142,6 +144,7 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
142
144
  | getRowId | `(originalRow: TData, index: number, parent?: Row<TData>) => string` | - | Дополнительная функция используется для получения уникального идентификатора для любой заданной строки |
143
145
  | scrollRef | `RefObject<HTMLElement>` | - | Ссылка на элемент, обозначающий самый конец прокручиваемого списка |
144
146
  | scrollContainerRef | `RefObject<HTMLElement>` | - | Ссылка на контейнер, который скроллится |
147
+ | rowPinning | `Pick<RowPinningState, "top">` | { top: [], } | Определение какие строки должны быть закреплены в таблице |
145
148
  ## Table.getStatusColumnDef
146
149
  Вспомогательная функция для создания ячейки со статусом
147
150
  ### Props
@@ -168,6 +171,8 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
168
171
  | onChangePage* | `(offset: number, limit: number) => void` | - | |
169
172
  | columnDefinitions* | `ColumnDefinition<TData>[]` | - | Определение внешнего вида и функционала колонок |
170
173
  | loading | `boolean` | - | Состояние загрузки |
174
+ | keepPinnedRows | `boolean` | - | Параметр овтечает за сохранение закрепленных строк на всех страницах таблицы |
175
+ | enableSelectPinned | `boolean` | - | Параметр овтечает за чекбокс выбора закрепленных строк |
171
176
  | sorting | `{ initialState?: SortingState; state?: SortingState; onChange?(state: SortingState): void; }` | - | Параметры отвечают за возможность сортировки, их стоит использовать если нужно отслеживать состояние <br> <strong>initialState</strong>: Начальное состояние сортировки <br> <strong>state</strong>: Состояние сортировки, жестко устанавливаемое снаружи <br> <strong>onChange</strong>: Колбэк на изменение сортировки |
172
177
  | rowSelection | `{ initialState?: RowSelectionState; state?: RowSelectionState; enable?: boolean \| ((row: Row<TData>) => boolean); multiRow?: boolean; onChange?(state: RowSelectionState): void; }` | - | Параметры отвечают за возможность выбора строк <br> <strong>initialState</strong>: Начальное состояние выбора строк <br> <strong>state</strong>: Состояние выбора строк, жестко устанавливаемое снаружи <br> <strong>enable</strong>: Колбэк определяющий можно ли выбрать строку <br> <strong>multiRow</strong>: Мульти-выбор строк (включен по-умолчанию, когда включается выбор) <br> <strong>onChange</strong>: Колбэк на выбор строк |
173
178
  | enableFuzzySearch | `boolean` | - | Включить нечеткий поиск |
@@ -194,6 +199,7 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
194
199
  | getRowId | `(originalRow: TData, index: number, parent?: Row<TData>) => string` | - | Дополнительная функция используется для получения уникального идентификатора для любой заданной строки |
195
200
  | scrollRef | `RefObject<HTMLElement>` | - | Ссылка на элемент, обозначающий самый конец прокручиваемого списка |
196
201
  | scrollContainerRef | `RefObject<HTMLElement>` | - | Ссылка на контейнер, который скроллится |
202
+ | rowPinning | `Pick<RowPinningState, "top">` | - | Определение какие строки должны быть закреплены в таблице |
197
203
  | items | `TData[]` | - | Данные для отрисовки |
198
204
  | total | `number` | 10 | Общее кол-во строк |
199
205
  | limit | `number` | 10 | Кол-во строк на страницу |
@@ -1,6 +1,6 @@
1
1
  import { TableProps } from '../types';
2
2
  /** Компонент таблицы */
3
- export declare function Table<TData extends object>({ data, columnDefinitions, rowSelection: rowSelectionProp, search, sorting: sortingProp, columnFilters, pagination: paginationProp, className, onRowClick, onRefresh, onDelete, pageSize, pageCount, loading, outline, moreActions, exportFileName, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar, toolbarBefore, toolbarAfter, suppressPagination, manualSorting, manualPagination, manualFiltering, scrollRef, scrollContainerRef, getRowId, enableFuzzySearch, ...rest }: TableProps<TData>): import("react/jsx-runtime").JSX.Element;
3
+ export declare function Table<TData extends object>({ data, rowPinning, columnDefinitions, keepPinnedRows, enableSelectPinned, rowSelection: rowSelectionProp, search, sorting: sortingProp, columnFilters, pagination: paginationProp, className, onRowClick, onRefresh, onDelete, pageSize, pageCount, loading, outline, moreActions, exportFileName, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar, toolbarBefore, toolbarAfter, suppressPagination, manualSorting, manualPagination, manualFiltering, scrollRef, scrollContainerRef, getRowId, enableFuzzySearch, ...rest }: TableProps<TData>): import("react/jsx-runtime").JSX.Element;
4
4
  export declare namespace Table {
5
5
  var getStatusColumnDef: typeof import("../../helperComponents").getStatusColumnDef;
6
6
  var statusAppearances: {
@@ -28,7 +28,9 @@ import styles from './styles.module.css';
28
28
  import { getColumnStyleVars, getCurrentlyConfiguredHeaderWidth } from './utils';
29
29
  /** Компонент таблицы */
30
30
  export function Table(_a) {
31
- var { data, columnDefinitions, rowSelection: rowSelectionProp, search, sorting: sortingProp, columnFilters, pagination: paginationProp, className, onRowClick, onRefresh, onDelete, pageSize = DEFAULT_PAGE_SIZE, pageCount, loading = false, outline = false, moreActions, exportFileName, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar = false, toolbarBefore, toolbarAfter, suppressPagination = false, manualSorting = false, manualPagination = false, manualFiltering = false, scrollRef, scrollContainerRef, getRowId, enableFuzzySearch } = _a, rest = __rest(_a, ["data", "columnDefinitions", "rowSelection", "search", "sorting", "columnFilters", "pagination", "className", "onRowClick", "onRefresh", "onDelete", "pageSize", "pageCount", "loading", "outline", "moreActions", "exportFileName", "dataFiltered", "dataError", "noDataState", "noResultsState", "errorDataState", "suppressToolbar", "toolbarBefore", "toolbarAfter", "suppressPagination", "manualSorting", "manualPagination", "manualFiltering", "scrollRef", "scrollContainerRef", "getRowId", "enableFuzzySearch"]);
31
+ var { data, rowPinning = {
32
+ top: [],
33
+ }, columnDefinitions, keepPinnedRows = false, enableSelectPinned = false, rowSelection: rowSelectionProp, search, sorting: sortingProp, columnFilters, pagination: paginationProp, className, onRowClick, onRefresh, onDelete, pageSize = DEFAULT_PAGE_SIZE, pageCount, loading = false, outline = false, moreActions, exportFileName, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar = false, toolbarBefore, toolbarAfter, suppressPagination = false, manualSorting = false, manualPagination = false, manualFiltering = false, scrollRef, scrollContainerRef, getRowId, enableFuzzySearch } = _a, rest = __rest(_a, ["data", "rowPinning", "columnDefinitions", "keepPinnedRows", "enableSelectPinned", "rowSelection", "search", "sorting", "columnFilters", "pagination", "className", "onRowClick", "onRefresh", "onDelete", "pageSize", "pageCount", "loading", "outline", "moreActions", "exportFileName", "dataFiltered", "dataError", "noDataState", "noResultsState", "errorDataState", "suppressToolbar", "toolbarBefore", "toolbarAfter", "suppressPagination", "manualSorting", "manualPagination", "manualFiltering", "scrollRef", "scrollContainerRef", "getRowId", "enableFuzzySearch"]);
32
34
  const { state: globalFilter, onStateChange: onGlobalFilterChange } = useStateControl(search, '');
33
35
  const { state: rowSelection, onStateChange: onRowSelectionChange } = useStateControl(rowSelectionProp, {});
34
36
  const defaultPaginationState = useMemo(() => ({
@@ -41,10 +43,10 @@ export function Table(_a) {
41
43
  const tableColumns = useMemo(() => {
42
44
  let cols = columnDefinitions;
43
45
  if (enableSelection) {
44
- cols = [getSelectionCellColumnDef(), ...cols];
46
+ cols = [getSelectionCellColumnDef(enableSelectPinned), ...cols];
45
47
  }
46
48
  return cols;
47
- }, [columnDefinitions, enableSelection]);
49
+ }, [columnDefinitions, enableSelection, enableSelectPinned]);
48
50
  const columnPinning = useMemo(() => {
49
51
  var _a;
50
52
  const pinningState = { left: [], right: [] };
@@ -65,6 +67,7 @@ export function Table(_a) {
65
67
  rowSelection,
66
68
  sorting,
67
69
  pagination,
70
+ rowPinning,
68
71
  },
69
72
  pageCount,
70
73
  defaultColumn: {
@@ -94,6 +97,7 @@ export function Table(_a) {
94
97
  getPaginationRowModel: getPaginationRowModel(),
95
98
  getCoreRowModel: getCoreRowModel(),
96
99
  columnResizeMode: 'onEnd',
100
+ keepPinnedRows,
97
101
  });
98
102
  const { loadingTable } = useLoadingTable({ pageSize, columnDefinitions: tableColumns, columnPinning });
99
103
  const handleOnRefresh = useCallback(() => {
@@ -160,8 +164,15 @@ export function Table(_a) {
160
164
  columnSizeVarsRef.current = columnSizeVars;
161
165
  }, [columnSizeVars]);
162
166
  const tableRows = table.getRowModel().rows;
167
+ const tableCenterRows = table.getCenterRows();
168
+ const tableFilteredRows = table.getFilteredRowModel().rows;
169
+ const tableFilteredRowsIds = tableFilteredRows.map(row => row.id);
170
+ const topRows = table.getTopRows();
163
171
  const loadingTableRows = loadingTable.getRowModel().rows;
164
172
  const tablePagination = table.getState().pagination;
173
+ const filteredTopRows = table.getState().globalFilter
174
+ ? topRows.filter(tr => tableFilteredRowsIds.includes(tr.id))
175
+ : topRows;
165
176
  const { t } = useLocale('Table');
166
177
  const emptyStates = useEmptyState({ noDataState, noResultsState, errorDataState });
167
178
  const cssPageSize = useMemo(() => {
@@ -181,7 +192,7 @@ export function Table(_a) {
181
192
  onChange: onGlobalFilterChange,
182
193
  loading: search === null || search === void 0 ? void 0 : search.loading,
183
194
  placeholder: (search === null || search === void 0 ? void 0 : search.placeholder) || t('searchPlaceholder'),
184
- }, checked: table.getIsAllPageRowsSelected(), indeterminate: table.getIsSomePageRowsSelected(), className: styles.toolbar, onRefresh: onRefresh ? handleOnRefresh : undefined, onDelete: enableSelection && onDelete ? handleOnDelete : undefined, onCheck: enableSelection ? handleOnCheck : undefined, outline: outline, selectionMode: (rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.multiRow) ? 'multiple' : 'single', before: toolbarBefore, after: toolbarAfter || exportFileName ? (_jsxs(_Fragment, { children: [toolbarAfter, exportFileName && (_jsx(ExportButton, { fileName: exportFileName, columnDefinitions: columnDefinitions, data: data }))] })) : undefined, moreActions: moreActions }), columnFilters && _jsxs("div", { className: styles.filtersWrapper, children: [" ", columnFilters, " "] })] })), _jsx("div", { className: styles.scrollWrapper, "data-outline": outline || undefined, children: _jsxs(Scroll, { size: 's', className: styles.table, ref: scrollContainerRef, children: [_jsx("div", { className: styles.tableContent, style: columnSizeVars, children: _jsx(TableContext.Provider, { value: { table }, children: loading ? (_jsxs(SkeletonContextProvider, { loading: true, children: [_jsx(HeaderRow, {}), loadingTableRows.map(row => (_jsx(BodyRow, { row: row }, row.id)))] })) : (_jsxs(_Fragment, { children: [tableRows.length ? _jsx(HeaderRow, {}) : null, tableRows.map(row => (_jsx(BodyRow, { row: row, onRowClick: onRowClick }, row.id))), _jsx(TableEmptyState, { emptyStates: emptyStates, dataError: dataError, dataFiltered: dataFiltered || Boolean(table.getState().globalFilter), tableRowsLength: tableRows.length })] })) }) }), _jsx("div", { className: styles.scrollStub, ref: scrollRef })] }) }), !suppressPagination && (_jsx(TablePagination, { table: table, options: paginationProp === null || paginationProp === void 0 ? void 0 : paginationProp.options, optionsLabel: paginationProp === null || paginationProp === void 0 ? void 0 : paginationProp.optionsLabel, pageCount: pageCount }))] })) }));
195
+ }, checked: table.getIsAllPageRowsSelected(), indeterminate: table.getIsSomePageRowsSelected(), className: styles.toolbar, onRefresh: onRefresh ? handleOnRefresh : undefined, onDelete: enableSelection && onDelete ? handleOnDelete : undefined, onCheck: enableSelection ? handleOnCheck : undefined, outline: outline, selectionMode: (rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.multiRow) ? 'multiple' : 'single', before: toolbarBefore, after: toolbarAfter || exportFileName ? (_jsxs(_Fragment, { children: [toolbarAfter, exportFileName && (_jsx(ExportButton, { fileName: exportFileName, columnDefinitions: columnDefinitions, data: data }))] })) : undefined, moreActions: moreActions }), columnFilters && _jsxs("div", { className: styles.filtersWrapper, children: [" ", columnFilters, " "] })] })), _jsx("div", { className: styles.scrollWrapper, "data-outline": outline || undefined, children: _jsxs(Scroll, { size: 's', className: styles.table, ref: scrollContainerRef, children: [_jsx("div", { className: styles.tableContent, style: columnSizeVars, children: _jsx(TableContext.Provider, { value: { table }, children: loading ? (_jsxs(SkeletonContextProvider, { loading: true, children: [_jsx(HeaderRow, {}), loadingTableRows.map(row => (_jsx(BodyRow, { row: row }, row.id)))] })) : (_jsxs(_Fragment, { children: [tableCenterRows.length || filteredTopRows.length ? _jsx(HeaderRow, {}) : null, filteredTopRows.length ? (_jsx("div", { className: styles.topRowWrapper, children: filteredTopRows.map(row => (_jsx(BodyRow, { row: row, onRowClick: onRowClick }, row.id))) })) : null, tableCenterRows.map(row => (_jsx(BodyRow, { row: row, onRowClick: onRowClick }, row.id))), _jsx(TableEmptyState, { emptyStates: emptyStates, dataError: dataError, dataFiltered: dataFiltered || Boolean(table.getState().globalFilter), tableRowsLength: tableRows.length })] })) }) }), _jsx("div", { className: styles.scrollStub, ref: scrollRef })] }) }), !suppressPagination && (_jsx(TablePagination, { table: table, options: paginationProp === null || paginationProp === void 0 ? void 0 : paginationProp.options, optionsLabel: paginationProp === null || paginationProp === void 0 ? void 0 : paginationProp.optionsLabel, pageCount: pageCount }))] })) }));
185
196
  }
186
197
  Table.getStatusColumnDef = getStatusColumnDef;
187
198
  Table.statusAppearances = STATUS_APPEARANCE;
@@ -54,4 +54,12 @@
54
54
  height:calc(var(--dimension-025m, 2px) / 2);
55
55
  margin-top:calc(var(--dimension-025m, 2px) / -2);
56
56
  background:transparent;
57
+ }
58
+
59
+ .topRowWrapper{
60
+ position:sticky;
61
+ z-index:3;
62
+ top:calc(var(--size-table-line-height, 40px));
63
+ margin-bottom:calc(-1 * var(--border-width-table, 1px));
64
+ border-bottom:var(--border-width-table, 1px) solid var(--sys-neutral-decor-default, #dfe2ec);
57
65
  }
@@ -1,15 +1,18 @@
1
- import { PaginationState, Row, RowSelectionOptions, RowSelectionState, SortingState } from '@tanstack/react-table';
1
+ import { PaginationState, Row, RowPinningState, RowSelectionOptions, RowSelectionState, SortingState } from '@tanstack/react-table';
2
2
  import { ReactNode, RefObject } from 'react';
3
3
  import { ToolbarProps } from '@snack-uikit/toolbar';
4
4
  import { WithSupportProps } from '@snack-uikit/utils';
5
- import { RowClickHandler } from '../helperComponents';
6
- import { EmptyStateProps } from '../helperComponents/TableEmptyState';
5
+ import { EmptyStateProps, RowClickHandler } from '../helperComponents';
7
6
  import { ColumnDefinition } from '../types';
8
7
  export type TableProps<TData extends object> = WithSupportProps<{
9
8
  /** Данные для отрисовки */
10
9
  data: TData[];
11
10
  /** Определение внешнего вида и функционала колонок */
12
11
  columnDefinitions: ColumnDefinition<TData>[];
12
+ /** Параметр овтечает за сохранение закрепленных строк на всех страницах таблицы */
13
+ keepPinnedRows?: boolean;
14
+ /** Параметр овтечает за чекбокс выбора закрепленных строк */
15
+ enableSelectPinned?: boolean;
13
16
  /** Параметры отвечают за возможность сортировки, их стоит использовать если нужно отслеживать состояние <br>
14
17
  * <strong>initialState</strong>: Начальное состояние сортировки <br>
15
18
  * <strong>state</strong>: Состояние сортировки, жестко устанавливаемое снаружи <br>
@@ -109,6 +112,8 @@ export type TableProps<TData extends object> = WithSupportProps<{
109
112
  scrollRef?: RefObject<HTMLElement>;
110
113
  /** Ссылка на контейнер, который скроллится */
111
114
  scrollContainerRef?: RefObject<HTMLElement>;
115
+ /** Определение какие строки должны быть закреплены в таблице */
116
+ rowPinning?: Pick<RowPinningState, 'top'>;
112
117
  }>;
113
118
  export type ServerTableProps<TData extends object> = Omit<TableProps<TData>, 'pageSize' | 'pageCount' | 'pagination' | 'search' | 'data'> & {
114
119
  /** Данные для отрисовки */
@@ -1,2 +1,2 @@
1
1
  import { ColumnDefinition } from '../../../types';
2
- export declare function getSelectionCellColumnDef<TData>(): ColumnDefinition<TData>;
2
+ export declare function getSelectionCellColumnDef<TData>(enableSelectPinned: boolean): ColumnDefinition<TData>;
@@ -23,7 +23,7 @@ function SelectionCell(_a) {
23
23
  // eslint-disable-next-line jsx-a11y/no-static-element-interactions
24
24
  _jsx("div", { onClick: handleCellClick, className: styles.selectionCell, "data-test-id": TEST_IDS.rowSelect, children: isMulti ? _jsx(Checkbox, Object.assign({}, props, { size: 's' })) : _jsx(Radio, Object.assign({}, props, { size: 's' })) }));
25
25
  }
26
- export function getSelectionCellColumnDef() {
26
+ export function getSelectionCellColumnDef(enableSelectPinned) {
27
27
  return {
28
28
  id: 'selectionCell',
29
29
  pinned: COLUMN_PIN_POSITION.Left,
@@ -33,7 +33,7 @@ export function getSelectionCellColumnDef() {
33
33
  enableResizing: false,
34
34
  cell: ({ row, table }) => {
35
35
  const disabled = !row.getCanSelect();
36
- if (disabled)
36
+ if (disabled || (!enableSelectPinned && row.getIsPinned()))
37
37
  return null;
38
38
  const { enableMultiRowSelection } = table.options;
39
39
  const isMulti = typeof enableMultiRowSelection === 'boolean' ? enableMultiRowSelection : true;
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public"
5
5
  },
6
6
  "title": "Table",
7
- "version": "0.18.0",
7
+ "version": "0.19.0",
8
8
  "sideEffects": [
9
9
  "*.css",
10
10
  "*.woff",
@@ -33,16 +33,16 @@
33
33
  "scripts": {},
34
34
  "dependencies": {
35
35
  "@snack-uikit/button": "0.17.1",
36
- "@snack-uikit/chips": "0.14.6",
36
+ "@snack-uikit/chips": "0.14.7",
37
37
  "@snack-uikit/icon-predefined": "0.5.1",
38
38
  "@snack-uikit/icons": "0.21.0",
39
- "@snack-uikit/info-block": "0.3.6",
40
- "@snack-uikit/list": "0.13.4",
39
+ "@snack-uikit/info-block": "0.4.0",
40
+ "@snack-uikit/list": "0.13.5",
41
41
  "@snack-uikit/pagination": "0.6.8",
42
42
  "@snack-uikit/scroll": "0.6.0",
43
43
  "@snack-uikit/skeleton": "0.3.4",
44
44
  "@snack-uikit/toggles": "0.9.10",
45
- "@snack-uikit/toolbar": "0.7.39",
45
+ "@snack-uikit/toolbar": "0.7.40",
46
46
  "@snack-uikit/truncate-string": "0.4.17",
47
47
  "@snack-uikit/typography": "0.6.2",
48
48
  "@snack-uikit/utils": "3.3.0",
@@ -57,5 +57,5 @@
57
57
  "peerDependencies": {
58
58
  "@snack-uikit/locale": "*"
59
59
  },
60
- "gitHead": "6d0c73127e9874b0a302e4a2ea2ed41cb9adae2d"
60
+ "gitHead": "2073ec039b8c391a322e0ad3016fabbe6dfb54bd"
61
61
  }
@@ -46,7 +46,12 @@ import { getColumnStyleVars, getCurrentlyConfiguredHeaderWidth } from './utils';
46
46
  /** Компонент таблицы */
47
47
  export function Table<TData extends object>({
48
48
  data,
49
+ rowPinning = {
50
+ top: [],
51
+ },
49
52
  columnDefinitions,
53
+ keepPinnedRows = false,
54
+ enableSelectPinned = false,
50
55
  rowSelection: rowSelectionProp,
51
56
  search,
52
57
  sorting: sortingProp,
@@ -78,6 +83,7 @@ export function Table<TData extends object>({
78
83
  scrollContainerRef,
79
84
  getRowId,
80
85
  enableFuzzySearch,
86
+
81
87
  ...rest
82
88
  }: TableProps<TData>) {
83
89
  const { state: globalFilter, onStateChange: onGlobalFilterChange } = useStateControl<string>(search, '');
@@ -85,6 +91,7 @@ export function Table<TData extends object>({
85
91
  rowSelectionProp,
86
92
  {},
87
93
  );
94
+
88
95
  const defaultPaginationState = useMemo(
89
96
  () => ({
90
97
  pageIndex: 0,
@@ -103,10 +110,10 @@ export function Table<TData extends object>({
103
110
  const tableColumns: ColumnDefinition<TData>[] = useMemo(() => {
104
111
  let cols: ColumnDefinition<TData>[] = columnDefinitions;
105
112
  if (enableSelection) {
106
- cols = [getSelectionCellColumnDef(), ...cols];
113
+ cols = [getSelectionCellColumnDef(enableSelectPinned), ...cols];
107
114
  }
108
115
  return cols;
109
- }, [columnDefinitions, enableSelection]);
116
+ }, [columnDefinitions, enableSelection, enableSelectPinned]);
110
117
 
111
118
  const columnPinning = useMemo(() => {
112
119
  const pinningState: Required<ColumnPinningState> = { left: [], right: [] };
@@ -128,6 +135,7 @@ export function Table<TData extends object>({
128
135
  rowSelection,
129
136
  sorting,
130
137
  pagination,
138
+ rowPinning,
131
139
  },
132
140
  pageCount,
133
141
  defaultColumn: {
@@ -160,6 +168,7 @@ export function Table<TData extends object>({
160
168
  getPaginationRowModel: getPaginationRowModel(),
161
169
  getCoreRowModel: getCoreRowModel(),
162
170
  columnResizeMode: 'onEnd',
171
+ keepPinnedRows,
163
172
  });
164
173
 
165
174
  const { loadingTable } = useLoadingTable({ pageSize, columnDefinitions: tableColumns, columnPinning });
@@ -243,9 +252,17 @@ export function Table<TData extends object>({
243
252
  }, [columnSizeVars]);
244
253
 
245
254
  const tableRows = table.getRowModel().rows;
255
+ const tableCenterRows = table.getCenterRows();
256
+ const tableFilteredRows = table.getFilteredRowModel().rows;
257
+ const tableFilteredRowsIds = tableFilteredRows.map(row => row.id);
258
+ const topRows = table.getTopRows();
246
259
  const loadingTableRows = loadingTable.getRowModel().rows;
247
260
  const tablePagination = table.getState().pagination;
248
261
 
262
+ const filteredTopRows = table.getState().globalFilter
263
+ ? topRows.filter(tr => tableFilteredRowsIds.includes(tr.id))
264
+ : topRows;
265
+
249
266
  const { t } = useLocale('Table');
250
267
  const emptyStates = useEmptyState({ noDataState, noResultsState, errorDataState });
251
268
 
@@ -319,8 +336,16 @@ export function Table<TData extends object>({
319
336
  </SkeletonContextProvider>
320
337
  ) : (
321
338
  <>
322
- {tableRows.length ? <HeaderRow /> : null}
323
- {tableRows.map(row => (
339
+ {tableCenterRows.length || filteredTopRows.length ? <HeaderRow /> : null}
340
+ {filteredTopRows.length ? (
341
+ <div className={styles.topRowWrapper}>
342
+ {filteredTopRows.map(row => (
343
+ <BodyRow key={row.id} row={row} onRowClick={onRowClick} />
344
+ ))}
345
+ </div>
346
+ ) : null}
347
+
348
+ {tableCenterRows.map(row => (
324
349
  <BodyRow key={row.id} row={row} onRowClick={onRowClick} />
325
350
  ))}
326
351
 
@@ -66,3 +66,13 @@
66
66
  margin-top: calc($dimension-025m / -2);
67
67
  background: transparent;
68
68
  }
69
+
70
+ .topRowWrapper {
71
+ position: sticky;
72
+ z-index: 3;
73
+ top: calc($size-table-line-height);
74
+
75
+ margin-bottom: calc(-1 * $border-width-table);
76
+
77
+ border-bottom: $border-width-table solid $sys-neutral-decor-default;
78
+ }
@@ -1,11 +1,17 @@
1
- import { PaginationState, Row, RowSelectionOptions, RowSelectionState, SortingState } from '@tanstack/react-table';
1
+ import {
2
+ PaginationState,
3
+ Row,
4
+ RowPinningState,
5
+ RowSelectionOptions,
6
+ RowSelectionState,
7
+ SortingState,
8
+ } from '@tanstack/react-table';
2
9
  import { ReactNode, RefObject } from 'react';
3
10
 
4
11
  import { ToolbarProps } from '@snack-uikit/toolbar';
5
12
  import { WithSupportProps } from '@snack-uikit/utils';
6
13
 
7
- import { RowClickHandler } from '../helperComponents';
8
- import { EmptyStateProps } from '../helperComponents/TableEmptyState';
14
+ import { EmptyStateProps, RowClickHandler } from '../helperComponents';
9
15
  import { ColumnDefinition } from '../types';
10
16
 
11
17
  export type TableProps<TData extends object> = WithSupportProps<{
@@ -13,6 +19,10 @@ export type TableProps<TData extends object> = WithSupportProps<{
13
19
  data: TData[];
14
20
  /** Определение внешнего вида и функционала колонок */
15
21
  columnDefinitions: ColumnDefinition<TData>[];
22
+ /** Параметр овтечает за сохранение закрепленных строк на всех страницах таблицы */
23
+ keepPinnedRows?: boolean;
24
+ /** Параметр овтечает за чекбокс выбора закрепленных строк */
25
+ enableSelectPinned?: boolean;
16
26
  /** Параметры отвечают за возможность сортировки, их стоит использовать если нужно отслеживать состояние <br>
17
27
  * <strong>initialState</strong>: Начальное состояние сортировки <br>
18
28
  * <strong>state</strong>: Состояние сортировки, жестко устанавливаемое снаружи <br>
@@ -132,6 +142,8 @@ export type TableProps<TData extends object> = WithSupportProps<{
132
142
  scrollRef?: RefObject<HTMLElement>;
133
143
  /** Ссылка на контейнер, который скроллится */
134
144
  scrollContainerRef?: RefObject<HTMLElement>;
145
+ /** Определение какие строки должны быть закреплены в таблице */
146
+ rowPinning?: Pick<RowPinningState, 'top'>;
135
147
  }>;
136
148
 
137
149
  export type ServerTableProps<TData extends object> = Omit<
@@ -27,7 +27,7 @@ function SelectionCell({ isMulti, onChange, ...props }: SelectionCellProps) {
27
27
  );
28
28
  }
29
29
 
30
- export function getSelectionCellColumnDef<TData>(): ColumnDefinition<TData> {
30
+ export function getSelectionCellColumnDef<TData>(enableSelectPinned: boolean): ColumnDefinition<TData> {
31
31
  return {
32
32
  id: 'selectionCell',
33
33
  pinned: COLUMN_PIN_POSITION.Left,
@@ -38,7 +38,7 @@ export function getSelectionCellColumnDef<TData>(): ColumnDefinition<TData> {
38
38
  cell: ({ row, table }) => {
39
39
  const disabled = !row.getCanSelect();
40
40
 
41
- if (disabled) return null;
41
+ if (disabled || (!enableSelectPinned && row.getIsPinned())) return null;
42
42
 
43
43
  const { enableMultiRowSelection } = table.options;
44
44