@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.
- package/CHANGELOG.md +22 -0
- package/dist/cjs/components/MobileTable.d.ts +2 -2
- package/dist/cjs/components/MobileTable.js +82 -6
- package/dist/cjs/components/index.d.ts +1 -0
- package/dist/cjs/components/index.js +1 -0
- package/dist/cjs/helperComponents/ColumnsSettings/ColumnsSettings.d.ts +7 -0
- package/dist/cjs/helperComponents/ColumnsSettings/ColumnsSettings.js +18 -0
- package/dist/cjs/helperComponents/ColumnsSettings/index.d.ts +1 -0
- package/dist/cjs/helperComponents/ColumnsSettings/index.js +17 -0
- package/dist/cjs/helperComponents/ColumnsSettings/styles.module.css +3 -0
- package/dist/cjs/helperComponents/TableCard/TableCard.d.ts +3 -1
- package/dist/cjs/helperComponents/TableCard/TableCard.js +10 -3
- package/dist/cjs/helperComponents/TableSorting/TableSorting.d.ts +10 -0
- package/dist/cjs/helperComponents/TableSorting/TableSorting.js +29 -0
- package/dist/cjs/helperComponents/TableSorting/index.d.ts +1 -0
- package/dist/cjs/helperComponents/TableSorting/index.js +17 -0
- package/dist/cjs/helperComponents/TableSorting/styles.module.css +3 -0
- package/dist/cjs/helperComponents/TableSorting/useTableSorting.d.ts +23 -0
- package/dist/cjs/helperComponents/TableSorting/useTableSorting.js +189 -0
- package/dist/cjs/helperComponents/TableSorting/utils.d.ts +9 -0
- package/dist/cjs/helperComponents/TableSorting/utils.js +75 -0
- package/dist/cjs/helperComponents/index.d.ts +3 -1
- package/dist/cjs/helperComponents/index.js +3 -1
- package/dist/esm/components/MobileTable.d.ts +2 -2
- package/dist/esm/components/MobileTable.js +84 -8
- package/dist/esm/components/index.d.ts +1 -0
- package/dist/esm/components/index.js +1 -0
- package/dist/esm/helperComponents/ColumnsSettings/ColumnsSettings.d.ts +7 -0
- package/dist/esm/helperComponents/ColumnsSettings/ColumnsSettings.js +12 -0
- package/dist/esm/helperComponents/ColumnsSettings/index.d.ts +1 -0
- package/dist/esm/helperComponents/ColumnsSettings/index.js +1 -0
- package/dist/esm/helperComponents/ColumnsSettings/styles.module.css +3 -0
- package/dist/esm/helperComponents/TableCard/TableCard.d.ts +3 -1
- package/dist/esm/helperComponents/TableCard/TableCard.js +10 -3
- package/dist/esm/helperComponents/TableSorting/TableSorting.d.ts +10 -0
- package/dist/esm/helperComponents/TableSorting/TableSorting.js +26 -0
- package/dist/esm/helperComponents/TableSorting/index.d.ts +1 -0
- package/dist/esm/helperComponents/TableSorting/index.js +1 -0
- package/dist/esm/helperComponents/TableSorting/styles.module.css +3 -0
- package/dist/esm/helperComponents/TableSorting/useTableSorting.d.ts +23 -0
- package/dist/esm/helperComponents/TableSorting/useTableSorting.js +183 -0
- package/dist/esm/helperComponents/TableSorting/utils.d.ts +9 -0
- package/dist/esm/helperComponents/TableSorting/utils.js +70 -0
- package/dist/esm/helperComponents/index.d.ts +3 -1
- package/dist/esm/helperComponents/index.js +3 -1
- package/package.json +6 -3
- package/src/components/MobileTable.tsx +144 -9
- package/src/components/index.ts +1 -0
- package/src/helperComponents/ColumnsSettings/ColumnsSettings.tsx +28 -0
- package/src/helperComponents/ColumnsSettings/index.ts +1 -0
- package/src/helperComponents/ColumnsSettings/styles.module.scss +5 -0
- package/src/helperComponents/TableCard/TableCard.tsx +21 -4
- package/src/helperComponents/TableSorting/TableSorting.tsx +60 -0
- package/src/helperComponents/TableSorting/index.ts +1 -0
- package/src/helperComponents/TableSorting/styles.module.scss +9 -0
- package/src/helperComponents/TableSorting/useTableSorting.tsx +248 -0
- package/src/helperComponents/TableSorting/utils.ts +89 -0
- 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.
|
|
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.
|
|
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": "
|
|
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 {
|
|
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:
|
|
217
|
+
columns: enabledTableColumns,
|
|
132
218
|
getCoreRowModel: getCoreRowModel(),
|
|
133
219
|
getPaginationRowModel: getPaginationRowModel(),
|
|
134
220
|
getFilteredRowModel: getFilteredRowModel(),
|
|
135
221
|
getSortedRowModel: getSortedRowModel(),
|
|
136
222
|
|
|
137
|
-
state: {
|
|
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={
|
|
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
|
))}
|
package/src/components/index.ts
CHANGED
|
@@ -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';
|
|
@@ -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>({
|
|
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' &&
|
|
69
|
-
|
|
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';
|