@cloud-ru/uikit-product-mobile-table 0.14.0 → 0.16.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.
Files changed (58) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/cjs/components/MobileTable.d.ts +2 -2
  3. package/dist/cjs/components/MobileTable.js +82 -6
  4. package/dist/cjs/components/index.d.ts +1 -0
  5. package/dist/cjs/components/index.js +1 -0
  6. package/dist/cjs/helperComponents/ColumnsSettings/ColumnsSettings.d.ts +7 -0
  7. package/dist/cjs/helperComponents/ColumnsSettings/ColumnsSettings.js +18 -0
  8. package/dist/cjs/helperComponents/ColumnsSettings/index.d.ts +1 -0
  9. package/dist/cjs/helperComponents/ColumnsSettings/index.js +17 -0
  10. package/dist/cjs/helperComponents/ColumnsSettings/styles.module.css +3 -0
  11. package/dist/cjs/helperComponents/TableCard/TableCard.d.ts +3 -1
  12. package/dist/cjs/helperComponents/TableCard/TableCard.js +10 -3
  13. package/dist/cjs/helperComponents/TableSorting/TableSorting.d.ts +10 -0
  14. package/dist/cjs/helperComponents/TableSorting/TableSorting.js +29 -0
  15. package/dist/cjs/helperComponents/TableSorting/index.d.ts +1 -0
  16. package/dist/cjs/helperComponents/TableSorting/index.js +17 -0
  17. package/dist/cjs/helperComponents/TableSorting/styles.module.css +3 -0
  18. package/dist/cjs/helperComponents/TableSorting/useTableSorting.d.ts +23 -0
  19. package/dist/cjs/helperComponents/TableSorting/useTableSorting.js +189 -0
  20. package/dist/cjs/helperComponents/TableSorting/utils.d.ts +9 -0
  21. package/dist/cjs/helperComponents/TableSorting/utils.js +75 -0
  22. package/dist/cjs/helperComponents/index.d.ts +3 -1
  23. package/dist/cjs/helperComponents/index.js +3 -1
  24. package/dist/esm/components/MobileTable.d.ts +2 -2
  25. package/dist/esm/components/MobileTable.js +84 -8
  26. package/dist/esm/components/index.d.ts +1 -0
  27. package/dist/esm/components/index.js +1 -0
  28. package/dist/esm/helperComponents/ColumnsSettings/ColumnsSettings.d.ts +7 -0
  29. package/dist/esm/helperComponents/ColumnsSettings/ColumnsSettings.js +12 -0
  30. package/dist/esm/helperComponents/ColumnsSettings/index.d.ts +1 -0
  31. package/dist/esm/helperComponents/ColumnsSettings/index.js +1 -0
  32. package/dist/esm/helperComponents/ColumnsSettings/styles.module.css +3 -0
  33. package/dist/esm/helperComponents/TableCard/TableCard.d.ts +3 -1
  34. package/dist/esm/helperComponents/TableCard/TableCard.js +10 -3
  35. package/dist/esm/helperComponents/TableSorting/TableSorting.d.ts +10 -0
  36. package/dist/esm/helperComponents/TableSorting/TableSorting.js +26 -0
  37. package/dist/esm/helperComponents/TableSorting/index.d.ts +1 -0
  38. package/dist/esm/helperComponents/TableSorting/index.js +1 -0
  39. package/dist/esm/helperComponents/TableSorting/styles.module.css +3 -0
  40. package/dist/esm/helperComponents/TableSorting/useTableSorting.d.ts +23 -0
  41. package/dist/esm/helperComponents/TableSorting/useTableSorting.js +183 -0
  42. package/dist/esm/helperComponents/TableSorting/utils.d.ts +9 -0
  43. package/dist/esm/helperComponents/TableSorting/utils.js +70 -0
  44. package/dist/esm/helperComponents/index.d.ts +3 -1
  45. package/dist/esm/helperComponents/index.js +3 -1
  46. package/package.json +6 -3
  47. package/src/components/MobileTable.tsx +144 -9
  48. package/src/components/index.ts +1 -0
  49. package/src/helperComponents/ColumnsSettings/ColumnsSettings.tsx +28 -0
  50. package/src/helperComponents/ColumnsSettings/index.ts +1 -0
  51. package/src/helperComponents/ColumnsSettings/styles.module.scss +5 -0
  52. package/src/helperComponents/TableCard/TableCard.tsx +21 -4
  53. package/src/helperComponents/TableSorting/TableSorting.tsx +60 -0
  54. package/src/helperComponents/TableSorting/index.ts +1 -0
  55. package/src/helperComponents/TableSorting/styles.module.scss +9 -0
  56. package/src/helperComponents/TableSorting/useTableSorting.tsx +248 -0
  57. package/src/helperComponents/TableSorting/utils.ts +89 -0
  58. package/src/helperComponents/index.ts +3 -1
@@ -0,0 +1,9 @@
1
+ import { Header } from '@tanstack/react-table';
2
+ import { ColumnDefinition } from '@snack-uikit/table';
3
+ export declare function getHeaderLabel<TData extends object>(header: Header<TData, unknown>): string;
4
+ export declare function createColumnDefMap<TData extends object>(columnDefinitions: ColumnDefinition<TData>[]): Map<string, ColumnDefinition<TData>>;
5
+ export declare function groupHeadersByPinned<TData extends object>(headers: Header<TData, unknown>[], columnDefMap: Map<string, ColumnDefinition<TData>>): {
6
+ leftHeaders: Header<TData, unknown>[];
7
+ unpinnedHeaders: Header<TData, unknown>[];
8
+ rightHeaders: Header<TData, unknown>[];
9
+ };
@@ -0,0 +1,70 @@
1
+ export function getHeaderLabel(header) {
2
+ const headerDef = header.column.columnDef.header;
3
+ if (typeof headerDef === 'string') {
4
+ return headerDef;
5
+ }
6
+ if (typeof headerDef === 'function') {
7
+ try {
8
+ const context = header.getContext();
9
+ const result = headerDef(context);
10
+ if (typeof result === 'string' || typeof result === 'number') {
11
+ return String(result);
12
+ }
13
+ if (result != null && typeof result === 'object' && 'props' in result && result.props) {
14
+ const children = result.props.children;
15
+ if (typeof children === 'string' || typeof children === 'number') {
16
+ return String(children);
17
+ }
18
+ if (Array.isArray(children)) {
19
+ const textChild = children.find(child => typeof child === 'string' || typeof child === 'number');
20
+ if (textChild != null) {
21
+ return String(textChild);
22
+ }
23
+ }
24
+ }
25
+ }
26
+ catch (error) {
27
+ console.error('Error getting header label:', error);
28
+ }
29
+ }
30
+ return header.id || header.column.id || '';
31
+ }
32
+ export function createColumnDefMap(columnDefinitions) {
33
+ const map = new Map();
34
+ columnDefinitions.forEach(colDef => {
35
+ let id;
36
+ if ('id' in colDef && colDef.id) {
37
+ id = colDef.id;
38
+ }
39
+ else if ('accessorKey' in colDef && colDef.accessorKey) {
40
+ id = String(colDef.accessorKey);
41
+ }
42
+ if (id) {
43
+ map.set(id, colDef);
44
+ }
45
+ });
46
+ return map;
47
+ }
48
+ export function groupHeadersByPinned(headers, columnDefMap) {
49
+ const leftHeaders = [];
50
+ const unpinnedHeaders = [];
51
+ const rightHeaders = [];
52
+ headers.forEach(header => {
53
+ const columnDef = columnDefMap.get(header.id);
54
+ if (!columnDef) {
55
+ unpinnedHeaders.push(header);
56
+ return;
57
+ }
58
+ switch (columnDef.pinned) {
59
+ case 'left':
60
+ leftHeaders.push(header);
61
+ break;
62
+ case 'right':
63
+ rightHeaders.push(header);
64
+ break;
65
+ default:
66
+ unpinnedHeaders.push(header);
67
+ }
68
+ });
69
+ return { leftHeaders, unpinnedHeaders, rightHeaders };
70
+ }
@@ -1,5 +1,7 @@
1
+ export * from './ColumnsSettings';
1
2
  export * from './RowActionsCell';
2
3
  export * from './StatusColumnDef';
3
4
  export * from './TableCard';
4
- export * from './TablePagination';
5
5
  export * from './TableEmptyState';
6
+ export * from './TablePagination';
7
+ export * from './TableSorting';
@@ -1,5 +1,7 @@
1
+ export * from './ColumnsSettings';
1
2
  export * from './RowActionsCell';
2
3
  export * from './StatusColumnDef';
3
4
  export * from './TableCard';
4
- export * from './TablePagination';
5
5
  export * from './TableEmptyState';
6
+ export * from './TablePagination';
7
+ export * from './TableSorting';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloud-ru/uikit-product-mobile-table",
3
3
  "title": "Mobile Table",
4
- "version": "0.14.0",
4
+ "version": "0.16.0",
5
5
  "sideEffects": [
6
6
  "*.css",
7
7
  "*.woff",
@@ -42,11 +42,14 @@
42
42
  "@cloud-ru/uikit-product-mobile-toolbar": "0.4.11",
43
43
  "@cloud-ru/uikit-product-utils": "8.0.1",
44
44
  "@snack-uikit/button": "0.19.16",
45
+ "@snack-uikit/figma-tokens": "18.0.1",
46
+ "@snack-uikit/icons": "0.27.4",
45
47
  "@snack-uikit/info-block": "0.6.35",
48
+ "@snack-uikit/list": "0.32.10",
46
49
  "@snack-uikit/pagination": "0.10.21",
47
50
  "@snack-uikit/skeleton": "0.6.9",
48
51
  "@snack-uikit/status": "0.10.7",
49
- "@snack-uikit/table": "0.37.23",
52
+ "@snack-uikit/table": "0.37.25",
50
53
  "@snack-uikit/toggles": "0.13.23",
51
54
  "@tanstack/match-sorter-utils": "8.19.4",
52
55
  "@tanstack/react-table": "8.12.0",
@@ -60,5 +63,5 @@
60
63
  "devDependencies": {
61
64
  "@types/lodash.debounce": "4.0.9"
62
65
  },
63
- "gitHead": "6366d4a4912c09f95af6ba794df7b5a246893762"
66
+ "gitHead": "10d32fab2d99b115e56be7ea6025eae9ad31304b"
64
67
  }
@@ -9,14 +9,21 @@ import {
9
9
  useReactTable,
10
10
  } from '@tanstack/react-table';
11
11
  import cn from 'classnames';
12
- import { useCallback, useMemo } from 'react';
12
+ import { useCallback, useEffect, useMemo } from 'react';
13
13
 
14
14
  import { useLocale } from '@cloud-ru/uikit-product-locale';
15
15
  import { FiltersState, MobileChipChoiceRowProps } from '@cloud-ru/uikit-product-mobile-chips';
16
16
  import { MobileToolbar, MobileToolbarProps } from '@cloud-ru/uikit-product-mobile-toolbar';
17
17
  import { extractSupportProps, WithSupportProps } from '@cloud-ru/uikit-product-utils';
18
18
  import { SkeletonContextProvider } from '@snack-uikit/skeleton';
19
- import { PaginationState, TableProps } from '@snack-uikit/table';
19
+ import {
20
+ getPinnedGroups,
21
+ PaginationState,
22
+ TableProps,
23
+ useColumnOrderByDrag,
24
+ useColumnSettings,
25
+ usePageReset,
26
+ } from '@snack-uikit/table';
20
27
 
21
28
  import {
22
29
  getRowActionsColumnDef,
@@ -24,8 +31,10 @@ import {
24
31
  TableCard,
25
32
  TableEmptyState,
26
33
  TablePagination,
34
+ TableSorting,
27
35
  useEmptyState,
28
36
  } from '../helperComponents';
37
+ import { ColumnsSettings } from '../helperComponents/ColumnsSettings';
29
38
  import { DEFAULT_PAGE_SIZE } from './constants';
30
39
  import { useLoadingTable, useStateControl } from './hooks';
31
40
  import styles from './styles.module.scss';
@@ -40,7 +49,6 @@ export type MobileTableProps<TData extends object, TFilters extends FiltersState
40
49
  | 'suppressSearch'
41
50
  | 'search'
42
51
  | 'onRefresh'
43
- | 'toolbarAfter'
44
52
  | 'moreActions'
45
53
  | 'className'
46
54
  | 'enableFuzzySearch'
@@ -59,6 +67,10 @@ export type MobileTableProps<TData extends object, TFilters extends FiltersState
59
67
  | 'getRowId'
60
68
  | 'rowSelection'
61
69
  | 'bulkActions'
70
+ | 'columnsSettings'
71
+ | 'savedState'
72
+ | 'autoResetPageIndex'
73
+ | 'toolbarAfter'
62
74
  > &
63
75
  WithSupportProps<{
64
76
  headlineId?: string;
@@ -93,9 +105,12 @@ export function MobileTable<TData extends object, TFilters extends FiltersState
93
105
  manualSorting = false,
94
106
  manualPagination = false,
95
107
  manualFiltering = false,
108
+ autoResetPageIndex = false,
96
109
  getRowId,
97
110
  rowSelection: rowSelectionProp,
98
111
  bulkActions: bulkActionsProp,
112
+ columnsSettings: columnsSettingsProp,
113
+ savedState,
99
114
  ...rest
100
115
  }: MobileTableProps<TData, TFilters>) {
101
116
  const defaultPaginationState = useMemo(() => ({ pageIndex: 0, pageSize: DEFAULT_PAGE_SIZE }), []);
@@ -126,18 +141,96 @@ export function MobileTable<TData extends object, TFilters extends FiltersState
126
141
  [rowSelectionProp],
127
142
  );
128
143
 
144
+ const enableSelection = Boolean(rowSelectionProp?.enable);
145
+
146
+ const pinnedGroups = useMemo(() => getPinnedGroups(columnDefinitions), [columnDefinitions]);
147
+
148
+ const {
149
+ enabledColumns,
150
+ setEnabledColumns,
151
+ getColumnsSettings,
152
+ enabledTableColumns,
153
+ enabledColumnsDefinitions,
154
+ areColumnsSettingsEnabled,
155
+ } = useColumnSettings({
156
+ columnDefinitions,
157
+ pinnedGroups,
158
+ savedState,
159
+ columnsSettings: columnsSettingsProp,
160
+ rowSelection: undefined,
161
+ enableSelectPinned: false,
162
+ expanding: undefined,
163
+ });
164
+
165
+ const { columnOrder, setColumnOrder, enableColumnsOrderSortByDrag } = useColumnOrderByDrag<TData>({
166
+ tableColumns: columnDefinitions,
167
+ savedState,
168
+ columnSettings: columnsSettingsProp,
169
+ });
170
+
171
+ const columnsSettings = useMemo(() => getColumnsSettings(columnOrder), [columnOrder, getColumnsSettings]);
172
+
173
+ // Получаем список колонок с mode: 'hidden', которые всегда доступны для сортировки
174
+ const hiddenColumnsBySettings = useMemo(() => {
175
+ if (!areColumnsSettingsEnabled) return new Set<string>();
176
+
177
+ const hidden = new Set<string>();
178
+ columnDefinitions.forEach(colDef => {
179
+ let columnId: string | undefined;
180
+ if ('id' in colDef && colDef.id) {
181
+ columnId = colDef.id;
182
+ } else if ('accessorKey' in colDef && colDef.accessorKey) {
183
+ columnId = String(colDef.accessorKey);
184
+ }
185
+
186
+ if (columnId) {
187
+ const colDefWithSettings = colDef as typeof colDef & {
188
+ columnSettings?: { mode?: 'hidden' | string };
189
+ };
190
+ if (colDefWithSettings.columnSettings?.mode === 'hidden') {
191
+ hidden.add(columnId);
192
+ }
193
+ }
194
+ });
195
+ return hidden;
196
+ }, [areColumnsSettingsEnabled, columnDefinitions]);
197
+
198
+ // Сбрасываем сортировку, если колонка с активной сортировкой была скрыта
199
+ // Колонки с mode: 'hidden' всегда доступны для сортировки
200
+ useEffect(() => {
201
+ if (areColumnsSettingsEnabled && enabledColumns && sorting.length > 0) {
202
+ const activeSortColumnId = sorting[0]?.id;
203
+ if (activeSortColumnId) {
204
+ const isHiddenColumn = hiddenColumnsBySettings.has(activeSortColumnId);
205
+ const isEnabledColumn = enabledColumns.includes(activeSortColumnId);
206
+ // Сбрасываем сортировку только если колонка не скрыта через mode: 'hidden' и не включена
207
+ if (!isHiddenColumn && !isEnabledColumn) {
208
+ // Колонка с активной сортировкой скрыта - сбрасываем сортировку
209
+ onSortingChange([]);
210
+ }
211
+ }
212
+ }
213
+ }, [areColumnsSettingsEnabled, enabledColumns, sorting, onSortingChange, hiddenColumnsBySettings]);
214
+
129
215
  const table = useReactTable<TData>({
130
216
  data,
131
- columns: columnDefinitions,
217
+ columns: enabledTableColumns,
132
218
  getCoreRowModel: getCoreRowModel(),
133
219
  getPaginationRowModel: getPaginationRowModel(),
134
220
  getFilteredRowModel: getFilteredRowModel(),
135
221
  getSortedRowModel: getSortedRowModel(),
136
222
 
137
- state: { pagination, globalFilter, sorting, rowSelection },
223
+ state: {
224
+ pagination,
225
+ globalFilter,
226
+ sorting,
227
+ rowSelection,
228
+ columnOrder: enableColumnsOrderSortByDrag ? columnOrder : undefined,
229
+ },
138
230
  pageCount,
139
231
  onPaginationChange,
140
232
  onSortingChange,
233
+ onColumnOrderChange: enableColumnsOrderSortByDrag ? setColumnOrder : undefined,
141
234
  globalFilterFn: enableFuzzySearch ? fuzzyFilter : 'includesString',
142
235
 
143
236
  enableFilters: true,
@@ -146,6 +239,8 @@ export function MobileTable<TData extends object, TFilters extends FiltersState
146
239
  manualFiltering,
147
240
  getRowId,
148
241
 
242
+ autoResetPageIndex,
243
+
149
244
  onRowSelectionChange,
150
245
  enableGrouping: true,
151
246
  enableRowSelection,
@@ -155,7 +250,7 @@ export function MobileTable<TData extends object, TFilters extends FiltersState
155
250
 
156
251
  const { loadingTable } = useLoadingTable<TData, TFilters>({
157
252
  pageSize: DEFAULT_PAGE_SIZE,
158
- columnDefinitions,
253
+ columnDefinitions: enabledColumnsDefinitions,
159
254
  });
160
255
 
161
256
  const tableRows = table.getRowModel().rows;
@@ -169,8 +264,6 @@ export function MobileTable<TData extends object, TFilters extends FiltersState
169
264
  onRefresh?.();
170
265
  }, [onRefresh, table]);
171
266
 
172
- const enableSelection = Boolean(rowSelectionProp?.enable);
173
-
174
267
  const bulkActions: MobileToolbarProps<TFilters>['bulkActions'] = useMemo(
175
268
  () =>
176
269
  enableSelection
@@ -206,6 +299,26 @@ export function MobileTable<TData extends object, TFilters extends FiltersState
206
299
  ? 'multiple'
207
300
  : 'single';
208
301
 
302
+ const hasSortableColumns = useMemo(
303
+ () => columnDefinitions.some(column => column.enableSorting !== false),
304
+ [columnDefinitions],
305
+ );
306
+
307
+ const shouldShowSorting = useMemo(
308
+ () => Boolean(sortingProp) || hasSortableColumns,
309
+ [sortingProp, hasSortableColumns],
310
+ );
311
+
312
+ const tableFilteredRows = table.getFilteredRowModel().rows;
313
+
314
+ usePageReset({
315
+ manualPagination,
316
+ maximumAvailablePage: pageCount || tableFilteredRows.length / pagination.pageSize,
317
+ pagination,
318
+ onPaginationChange,
319
+ autoResetPageIndex,
320
+ });
321
+
209
322
  return (
210
323
  <div className={cn(styles.tableWrapper, className)} {...extractSupportProps(rest)}>
211
324
  {(!suppressToolbar || columnFilters) && (
@@ -224,7 +337,28 @@ export function MobileTable<TData extends object, TFilters extends FiltersState
224
337
  onRefresh={onRefresh ? handleOnRefresh : undefined}
225
338
  outline
226
339
  filterRow={columnFilters}
227
- after={toolbarAfter}
340
+ after={
341
+ toolbarAfter || shouldShowSorting || (areColumnsSettingsEnabled && columnsSettings) ? (
342
+ <>
343
+ {toolbarAfter}
344
+ {shouldShowSorting && (
345
+ <TableSorting
346
+ table={table}
347
+ columnDefinitions={columnDefinitions}
348
+ enabledColumns={areColumnsSettingsEnabled ? enabledColumns : undefined}
349
+ areColumnsSettingsEnabled={areColumnsSettingsEnabled}
350
+ />
351
+ )}
352
+ {areColumnsSettingsEnabled && columnsSettings && (
353
+ <ColumnsSettings
354
+ columnsSettings={columnsSettings}
355
+ enabledColumns={enabledColumns}
356
+ setEnabledColumns={setEnabledColumns}
357
+ />
358
+ )}
359
+ </>
360
+ ) : undefined
361
+ }
228
362
  moreActions={moreActions}
229
363
  bulkActions={bulkActions}
230
364
  selectedCount={table.getSelectedRowModel().rows.length}
@@ -251,6 +385,7 @@ export function MobileTable<TData extends object, TFilters extends FiltersState
251
385
  headlineId={headlineId}
252
386
  row={row}
253
387
  table={table}
388
+ selectionAppearance={rowSelectionProp?.appearance}
254
389
  selection={enableSelection ? selectionMode : 'none'}
255
390
  />
256
391
  ))}
@@ -1,3 +1,4 @@
1
1
  export * from './AdaptiveTable';
2
2
  export * from './AdaptiveServerTable';
3
3
  export * from './MobileTable';
4
+ export * from '../helperComponents';
@@ -0,0 +1,28 @@
1
+ import { MobileDroplist } from '@cloud-ru/uikit-product-mobile-dropdown';
2
+ import { ButtonFunction } from '@snack-uikit/button';
3
+ import { FunctionSettingsSVG } from '@snack-uikit/icons';
4
+ import { GroupSelectItemProps } from '@snack-uikit/list';
5
+
6
+ import styles from './styles.module.scss';
7
+ export type ColumnsSettingsProps = {
8
+ enabledColumns: string[];
9
+ setEnabledColumns(enabledColumns: string[]): void;
10
+ columnsSettings: [GroupSelectItemProps];
11
+ };
12
+
13
+ export function ColumnsSettings({ columnsSettings, enabledColumns, setEnabledColumns }: ColumnsSettingsProps) {
14
+ return (
15
+ <MobileDroplist
16
+ className={styles.columnsSettings}
17
+ items={columnsSettings}
18
+ selection={{
19
+ value: enabledColumns,
20
+ onChange: setEnabledColumns,
21
+ mode: 'multiple',
22
+ }}
23
+ data-test-id='table__column-settings-droplist'
24
+ >
25
+ <ButtonFunction size='m' data-test-id='table__column-settings' icon={<FunctionSettingsSVG />} />
26
+ </MobileDroplist>
27
+ );
28
+ }
@@ -0,0 +1 @@
1
+ export * from './ColumnsSettings';
@@ -0,0 +1,5 @@
1
+ @use '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-table' as table;
2
+
3
+ .columnsSettings {
4
+ min-width: 256px;
5
+ }
@@ -1,6 +1,7 @@
1
1
  import { flexRender, Row, Table } from '@tanstack/react-table';
2
2
  import { useCallback } from 'react';
3
3
 
4
+ import { RowAppearance } from '@snack-uikit/table';
4
5
  import { Checkbox, Radio } from '@snack-uikit/toggles';
5
6
 
6
7
  import { ROW_ACTIONS_COLUMN_ID } from '../../constants';
@@ -11,9 +12,16 @@ type TableCardProps<TData extends object> = {
11
12
  row: Row<TData>;
12
13
  table: Table<TData>;
13
14
  selection: 'multiple' | 'single' | 'none';
15
+ selectionAppearance?: RowAppearance;
14
16
  };
15
17
 
16
- export function TableCard<TData extends object>({ headlineId, table, row, selection }: TableCardProps<TData>) {
18
+ export function TableCard<TData extends object>({
19
+ headlineId,
20
+ table,
21
+ row,
22
+ selection,
23
+ selectionAppearance = RowAppearance.Disabled,
24
+ }: TableCardProps<TData>) {
17
25
  const headerGroups = table.getHeaderGroups();
18
26
 
19
27
  const headerCell = row._getAllCellsByColumnId()[headlineId ?? ''];
@@ -23,11 +31,14 @@ export function TableCard<TData extends object>({ headlineId, table, row, select
23
31
  const actionsColumn = table.getFlatHeaders().find(header => header.id === ROW_ACTIONS_COLUMN_ID);
24
32
 
25
33
  const isSelected = row.getIsSelected();
34
+ const canSelect = row.getCanSelect();
35
+ const isDisabled = !canSelect;
26
36
 
27
37
  const handleSelection = useCallback(() => {
38
+ if (isDisabled) return;
28
39
  if (selection === 'single') row.toggleSelected(true);
29
40
  if (selection === 'multiple') row.toggleSelected(!isSelected);
30
- }, [isSelected, row, selection]);
41
+ }, [isDisabled, isSelected, row, selection]);
31
42
 
32
43
  return (
33
44
  // eslint-disable-next-line jsx-a11y/no-static-element-interactions
@@ -65,8 +76,14 @@ export function TableCard<TData extends object>({ headlineId, table, row, select
65
76
  </div>
66
77
  </div>
67
78
 
68
- {selection === 'single' && <Radio size='m' className={styles.selectionController} checked={isSelected} />}
69
- {selection === 'multiple' && <Checkbox size='m' className={styles.selectionController} checked={isSelected} />}
79
+ {selection === 'single' &&
80
+ (isDisabled && selectionAppearance === RowAppearance.HideToggler ? null : (
81
+ <Radio size='m' className={styles.selectionController} checked={isSelected} disabled={isDisabled} />
82
+ ))}
83
+ {selection === 'multiple' &&
84
+ (isDisabled && selectionAppearance === RowAppearance.HideToggler ? null : (
85
+ <Checkbox size='m' className={styles.selectionController} checked={isSelected} disabled={isDisabled} />
86
+ ))}
70
87
  {actionsCell && actionsColumn && (
71
88
  <div className={styles.button}>{flexRender(actionsColumn.column.columnDef.cell, actionsCell.getContext())}</div>
72
89
  )}
@@ -0,0 +1,60 @@
1
+ import { SortingState, Table } from '@tanstack/react-table';
2
+ import { useState } from 'react';
3
+
4
+ import { ArrowDownSVG, ArrowUpSVG, SortSVG } from '@cloud-ru/uikit-product-icons';
5
+ import { MobileDroplist } from '@cloud-ru/uikit-product-mobile-dropdown';
6
+ import { ButtonFunction } from '@snack-uikit/button';
7
+ import { ColumnDefinition } from '@snack-uikit/table';
8
+
9
+ import { useTableSorting } from './useTableSorting';
10
+
11
+ export type TableSortingProps<TData extends object> = {
12
+ table: Table<TData>;
13
+ sorting?: SortingState;
14
+ columnDefinitions: ColumnDefinition<TData>[];
15
+ enabledColumns?: string[];
16
+ areColumnsSettingsEnabled?: boolean;
17
+ };
18
+
19
+ export function TableSorting<TData extends object>({
20
+ table,
21
+ sorting,
22
+ columnDefinitions,
23
+ enabledColumns,
24
+ areColumnsSettingsEnabled = false,
25
+ }: TableSortingProps<TData>) {
26
+ const [open, setOpen] = useState(false);
27
+
28
+ const { items, pinBottom, selection, currentSort, selectedSortId, handleClearSort } = useTableSorting({
29
+ table,
30
+ sorting,
31
+ columnDefinitions,
32
+ enabledColumns,
33
+ areColumnsSettingsEnabled,
34
+ });
35
+
36
+ const handleClear = () => {
37
+ handleClearSort();
38
+ setOpen(false);
39
+ };
40
+
41
+ const clearItem = pinBottom?.[0] ? [{ ...pinBottom[0], onClick: handleClear }] : undefined;
42
+
43
+ let SortIcon = SortSVG;
44
+ if (currentSort) {
45
+ SortIcon = currentSort.desc ? ArrowDownSVG : ArrowUpSVG;
46
+ }
47
+
48
+ return (
49
+ <MobileDroplist
50
+ items={items}
51
+ selection={selection}
52
+ virtualized={items.length > 10}
53
+ pinBottom={clearItem}
54
+ open={open}
55
+ onOpenChange={setOpen}
56
+ >
57
+ <ButtonFunction size='m' icon={<SortIcon />} appearance={selectedSortId ? 'primary' : 'neutral'} />
58
+ </MobileDroplist>
59
+ );
60
+ }
@@ -0,0 +1 @@
1
+ export * from './TableSorting';
@@ -0,0 +1,9 @@
1
+ @use '@sbercloud/figma-tokens-cloud-platform/build/scss/styles-theme-variables' as stv;
2
+
3
+ .clearSortItem {
4
+ &[data-disabled='true'] {
5
+ svg {
6
+ color: stv.$sys-neutral-text-disabled;
7
+ }
8
+ }
9
+ }