@snack-uikit/table 0.14.7-preview-da21d728.0 → 0.14.7
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 +10 -0
- package/dist/components/ServerTable/ServerTable.js +1 -1
- package/dist/components/ServerTable/utils.d.ts +1 -1
- package/dist/components/ServerTable/utils.js +5 -3
- package/dist/components/Table/Table.d.ts +1 -1
- package/dist/components/Table/Table.js +19 -73
- package/dist/components/Table/hooks/index.d.ts +1 -0
- package/dist/components/Table/hooks/index.js +1 -0
- package/dist/components/Table/hooks/useTable.d.ts +10 -0
- package/dist/components/Table/hooks/useTable.js +75 -0
- package/package.json +6 -6
- package/src/components/ServerTable/ServerTable.tsx +1 -1
- package/src/components/ServerTable/utils.ts +5 -3
- package/src/components/Table/Table.tsx +23 -104
- package/src/components/Table/hooks/index.ts +1 -0
- package/src/components/Table/hooks/useTable.tsx +132 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
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.14.7 (2024-02-27)
|
|
7
|
+
|
|
8
|
+
### Only dependencies have been changed
|
|
9
|
+
* [@snack-uikit/list@0.5.0](https://github.com/cloud-ru-tech/snack-uikit/blob/master/packages/list/CHANGELOG.md)
|
|
10
|
+
* [@snack-uikit/toolbar@0.7.15](https://github.com/cloud-ru-tech/snack-uikit/blob/master/packages/toolbar/CHANGELOG.md)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
6
16
|
## 0.14.6 (2024-02-26)
|
|
7
17
|
|
|
8
18
|
|
|
@@ -23,7 +23,7 @@ export function ServerTable(_a) {
|
|
|
23
23
|
const [tempSearch, setTempSearch] = useState(search || '');
|
|
24
24
|
const handleSearch = useCallback((newValue) => {
|
|
25
25
|
setTempSearch(newValue);
|
|
26
|
-
onSearchDebounced(newValue.trim(), setSearch);
|
|
26
|
+
onSearchDebounced()(newValue.trim(), setSearch);
|
|
27
27
|
}, [setSearch]);
|
|
28
28
|
const handlePageChange = useCallback(({ pageSize, pageIndex }) => onChangePage(pageIndex * pageSize, pageSize), [onChangePage]);
|
|
29
29
|
const pageIndex = useMemo(() => Math.floor(offset / limit), [limit, offset]);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/// <reference types="lodash" />
|
|
2
|
-
export declare
|
|
2
|
+
export declare function onSearchDebounced(): import("lodash").DebouncedFunc<(newValue: string, onChange: (newValue: string) => void) => void>;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import debounce from 'lodash.debounce';
|
|
2
2
|
import { SEARCH_DELAY } from './constants';
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
export function onSearchDebounced() {
|
|
4
|
+
return debounce((newValue, onChange) => {
|
|
5
|
+
onChange(newValue);
|
|
6
|
+
}, SEARCH_DELAY);
|
|
7
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TableProps } from '../types';
|
|
2
2
|
/** Компонент таблицы */
|
|
3
|
-
export declare function Table<TData extends object>({ data, columnDefinitions, rowSelection
|
|
3
|
+
export declare function Table<TData extends object>({ 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, ...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: {
|
|
@@ -10,87 +10,31 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
-
import { getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from '@tanstack/react-table';
|
|
14
13
|
import cn from 'classnames';
|
|
15
14
|
import { useCallback, useEffect, useMemo } from 'react';
|
|
16
15
|
import { useLocale } from '@snack-uikit/locale';
|
|
17
16
|
import { Scroll } from '@snack-uikit/scroll';
|
|
18
17
|
import { SkeletonContextProvider } from '@snack-uikit/skeleton';
|
|
19
18
|
import { Toolbar } from '@snack-uikit/toolbar';
|
|
20
|
-
import { TruncateString } from '@snack-uikit/truncate-string';
|
|
21
19
|
import { extractSupportProps } from '@snack-uikit/utils';
|
|
22
20
|
import { DEFAULT_PAGE_SIZE } from '../../constants';
|
|
23
|
-
import { BodyRow, ExportButton, getColumnId, getRowActionsColumnDef,
|
|
24
|
-
import {
|
|
25
|
-
import { useLoadingTable } from './hooks';
|
|
26
|
-
import { useStateControl } from './hooks/useStateControl';
|
|
21
|
+
import { BodyRow, ExportButton, getColumnId, getRowActionsColumnDef, getStatusColumnDef, HeaderRow, STATUS_APPEARANCE, TableContext, TableEmptyState, TablePagination, useEmptyState, } from '../../helperComponents';
|
|
22
|
+
import { useLoadingTable, useTable } from './hooks';
|
|
27
23
|
import styles from './styles.module.css';
|
|
28
24
|
/** Компонент таблицы */
|
|
29
25
|
export function Table(_a) {
|
|
30
|
-
var { data, columnDefinitions, rowSelection
|
|
31
|
-
const {
|
|
32
|
-
const { state: rowSelection, onStateChange: onRowSelectionChange } = useStateControl(rowSelectionProp, {});
|
|
33
|
-
const defaultPaginationState = useMemo(() => ({
|
|
34
|
-
pageIndex: 0,
|
|
35
|
-
pageSize,
|
|
36
|
-
}), [pageSize]);
|
|
37
|
-
const { state: sorting, onStateChange: onSortingChange } = useStateControl(sortingProp, []);
|
|
38
|
-
const { state: pagination, onStateChange: onPaginationChange } = useStateControl(paginationProp, defaultPaginationState);
|
|
39
|
-
const enableSelection = Boolean(rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.enable);
|
|
40
|
-
const tableColumns = useMemo(() => {
|
|
41
|
-
let cols = columnDefinitions;
|
|
42
|
-
if (enableSelection) {
|
|
43
|
-
cols = [getSelectionCellColumnDef(), ...cols];
|
|
44
|
-
}
|
|
45
|
-
return cols;
|
|
46
|
-
}, [columnDefinitions, enableSelection]);
|
|
47
|
-
const columnPinning = useMemo(() => {
|
|
48
|
-
var _a;
|
|
49
|
-
const pinningState = { left: [], right: [] };
|
|
50
|
-
for (const col of tableColumns) {
|
|
51
|
-
const id = getColumnId(col);
|
|
52
|
-
if (col.pinned && id) {
|
|
53
|
-
(_a = pinningState[col.pinned]) === null || _a === void 0 ? void 0 : _a.push(id);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return pinningState;
|
|
57
|
-
}, [tableColumns]);
|
|
58
|
-
const table = useReactTable({
|
|
26
|
+
var { data, columnDefinitions, rowSelection, search, sorting, columnFilters, pagination, 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 } = _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"]);
|
|
27
|
+
const { table, tableColumns, columnPinning } = useTable({
|
|
59
28
|
data,
|
|
60
|
-
|
|
61
|
-
state: {
|
|
62
|
-
columnPinning,
|
|
63
|
-
globalFilter,
|
|
64
|
-
rowSelection,
|
|
65
|
-
sorting,
|
|
66
|
-
pagination,
|
|
67
|
-
},
|
|
68
|
-
pageCount,
|
|
69
|
-
defaultColumn: {
|
|
70
|
-
enableSorting: false,
|
|
71
|
-
enableResizing: false,
|
|
72
|
-
minSize: 40,
|
|
73
|
-
cell: (cell) => _jsx(TruncateString, { text: String(cell.getValue()), maxLines: 1 }),
|
|
74
|
-
},
|
|
75
|
-
manualSorting,
|
|
76
|
-
manualPagination,
|
|
29
|
+
sorting,
|
|
77
30
|
manualFiltering,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
enableColumnResizing: true,
|
|
86
|
-
enableSorting: true,
|
|
87
|
-
enableMultiSort: true,
|
|
88
|
-
onSortingChange,
|
|
89
|
-
getSortedRowModel: getSortedRowModel(),
|
|
90
|
-
onPaginationChange,
|
|
91
|
-
getPaginationRowModel: getPaginationRowModel(),
|
|
92
|
-
getCoreRowModel: getCoreRowModel(),
|
|
93
|
-
columnResizeMode: 'onEnd',
|
|
31
|
+
manualPagination,
|
|
32
|
+
manualSorting,
|
|
33
|
+
columnDefinitions,
|
|
34
|
+
rowSelection,
|
|
35
|
+
pagination,
|
|
36
|
+
pageCount,
|
|
37
|
+
pageSize,
|
|
94
38
|
});
|
|
95
39
|
const { loadingTable } = useLoadingTable({ pageSize, columnDefinitions: tableColumns, columnPinning });
|
|
96
40
|
const handleOnRefresh = useCallback(() => {
|
|
@@ -106,7 +50,7 @@ export function Table(_a) {
|
|
|
106
50
|
}
|
|
107
51
|
}, [loading, onDelete, table]);
|
|
108
52
|
const handleOnCheck = useCallback(() => {
|
|
109
|
-
if (!loading && (
|
|
53
|
+
if (!loading && (rowSelection === null || rowSelection === void 0 ? void 0 : rowSelection.multiRow)) {
|
|
110
54
|
table.toggleAllPageRowsSelected();
|
|
111
55
|
return;
|
|
112
56
|
}
|
|
@@ -114,7 +58,7 @@ export function Table(_a) {
|
|
|
114
58
|
table.resetRowSelection();
|
|
115
59
|
return;
|
|
116
60
|
}
|
|
117
|
-
}, [loading,
|
|
61
|
+
}, [loading, rowSelection === null || rowSelection === void 0 ? void 0 : rowSelection.multiRow, table]);
|
|
118
62
|
useEffect(() => { }, []);
|
|
119
63
|
const columnSizeVars = useMemo(() => {
|
|
120
64
|
const originalColumnDefs = table._getColumnDefs();
|
|
@@ -148,14 +92,16 @@ export function Table(_a) {
|
|
|
148
92
|
const tempPageSize = !suppressPagination ? tablePagination === null || tablePagination === void 0 ? void 0 : tablePagination.pageSize : pageSize;
|
|
149
93
|
return !tableRows.length ? Math.min(Math.max(tempPageSize, 5), DEFAULT_PAGE_SIZE) : tempPageSize;
|
|
150
94
|
}, [pageSize, suppressPagination, tablePagination === null || tablePagination === void 0 ? void 0 : tablePagination.pageSize, tableRows.length]);
|
|
95
|
+
const enableSelection = Boolean(rowSelection === null || rowSelection === void 0 ? void 0 : rowSelection.enable);
|
|
151
96
|
return (_jsx(_Fragment, { children: _jsxs("div", Object.assign({ style: {
|
|
152
97
|
'--page-size': cssPageSize,
|
|
98
|
+
// width: table.getTotalSize(),
|
|
153
99
|
}, className: cn(styles.wrapper, className) }, extractSupportProps(rest), { children: [!suppressToolbar && (_jsxs("div", { className: styles.header, children: [_jsx(Toolbar, { search: {
|
|
154
|
-
value: globalFilter,
|
|
155
|
-
onChange:
|
|
100
|
+
value: table.getState().globalFilter,
|
|
101
|
+
onChange: table.setGlobalFilter,
|
|
156
102
|
loading: search === null || search === void 0 ? void 0 : search.loading,
|
|
157
103
|
placeholder: (search === null || search === void 0 ? void 0 : search.placeholder) || t('searchPlaceholder'),
|
|
158
|
-
}, 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: (
|
|
104
|
+
}, 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: (rowSelection === null || rowSelection === void 0 ? void 0 : rowSelection.multiRow) ? 'multiple' : 'single', before: toolbarBefore, after: _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: pagination === null || pagination === void 0 ? void 0 : pagination.options, optionsLabel: pagination === null || pagination === void 0 ? void 0 : pagination.optionsLabel, pageCount: pageCount }))] })) }));
|
|
159
105
|
}
|
|
160
106
|
Table.getStatusColumnDef = getStatusColumnDef;
|
|
161
107
|
Table.statusAppearances = STATUS_APPEARANCE;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ColumnPinningState } from '@tanstack/react-table';
|
|
2
|
+
import { ColumnDefinition } from '../../../types';
|
|
3
|
+
import { TableProps } from '../../types';
|
|
4
|
+
type UseTableProps<TData extends object> = Pick<TableProps<TData>, 'search' | 'rowSelection' | 'sorting' | 'pagination' | 'pageSize' | 'columnDefinitions' | 'data' | 'manualFiltering' | 'manualSorting' | 'manualPagination' | 'pageCount'>;
|
|
5
|
+
export declare function useTable<TData extends object>({ search, pageSize, pagination: paginationProp, rowSelection: rowSelectionProp, sorting: sortingProp, columnDefinitions, manualFiltering, manualPagination, manualSorting, pageCount, data, }: UseTableProps<TData>): {
|
|
6
|
+
table: import("@tanstack/react-table").Table<TData>;
|
|
7
|
+
tableColumns: ColumnDefinition<TData>[];
|
|
8
|
+
columnPinning: Required<ColumnPinningState>;
|
|
9
|
+
};
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from '@tanstack/react-table';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import { TruncateString } from '@snack-uikit/truncate-string';
|
|
5
|
+
import { DEFAULT_PAGE_SIZE } from '../../../constants';
|
|
6
|
+
import { getColumnId, getSelectionCellColumnDef } from '../../../helperComponents';
|
|
7
|
+
import { fuzzyFilter } from '../../../utils';
|
|
8
|
+
import { useStateControl } from './useStateControl';
|
|
9
|
+
export function useTable({ search, pageSize = DEFAULT_PAGE_SIZE, pagination: paginationProp, rowSelection: rowSelectionProp, sorting: sortingProp, columnDefinitions, manualFiltering, manualPagination, manualSorting, pageCount, data, }) {
|
|
10
|
+
const { state: globalFilter, onStateChange: onGlobalFilterChange } = useStateControl(search, '');
|
|
11
|
+
const { state: rowSelection, onStateChange: onRowSelectionChange } = useStateControl(rowSelectionProp, {});
|
|
12
|
+
const defaultPaginationState = useMemo(() => ({
|
|
13
|
+
pageIndex: 0,
|
|
14
|
+
pageSize,
|
|
15
|
+
}), [pageSize]);
|
|
16
|
+
const { state: sorting, onStateChange: onSortingChange } = useStateControl(sortingProp, []);
|
|
17
|
+
const { state: pagination, onStateChange: onPaginationChange } = useStateControl(paginationProp, defaultPaginationState);
|
|
18
|
+
const enableSelection = Boolean(rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.enable);
|
|
19
|
+
const tableColumns = useMemo(() => {
|
|
20
|
+
let cols = columnDefinitions;
|
|
21
|
+
if (enableSelection) {
|
|
22
|
+
cols = [getSelectionCellColumnDef(), ...cols];
|
|
23
|
+
}
|
|
24
|
+
return cols;
|
|
25
|
+
}, [columnDefinitions, enableSelection]);
|
|
26
|
+
const columnPinning = useMemo(() => {
|
|
27
|
+
var _a;
|
|
28
|
+
const pinningState = { left: [], right: [] };
|
|
29
|
+
for (const col of tableColumns) {
|
|
30
|
+
const id = getColumnId(col);
|
|
31
|
+
if (col.pinned && id) {
|
|
32
|
+
(_a = pinningState[col.pinned]) === null || _a === void 0 ? void 0 : _a.push(id);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return pinningState;
|
|
36
|
+
}, [tableColumns]);
|
|
37
|
+
const table = useReactTable({
|
|
38
|
+
data,
|
|
39
|
+
columns: tableColumns,
|
|
40
|
+
state: {
|
|
41
|
+
columnPinning,
|
|
42
|
+
globalFilter,
|
|
43
|
+
rowSelection,
|
|
44
|
+
sorting,
|
|
45
|
+
pagination,
|
|
46
|
+
},
|
|
47
|
+
pageCount,
|
|
48
|
+
defaultColumn: {
|
|
49
|
+
enableSorting: true,
|
|
50
|
+
enableResizing: true,
|
|
51
|
+
minSize: 40,
|
|
52
|
+
cell: (cell) => _jsx(TruncateString, { text: String(cell.getValue()), maxLines: 1 }),
|
|
53
|
+
},
|
|
54
|
+
manualSorting,
|
|
55
|
+
manualPagination,
|
|
56
|
+
manualFiltering,
|
|
57
|
+
globalFilterFn: fuzzyFilter,
|
|
58
|
+
onGlobalFilterChange,
|
|
59
|
+
onRowSelectionChange,
|
|
60
|
+
enableRowSelection: rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.enable,
|
|
61
|
+
enableMultiRowSelection: rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.multiRow,
|
|
62
|
+
enableFilters: true,
|
|
63
|
+
getFilteredRowModel: getFilteredRowModel(),
|
|
64
|
+
enableColumnResizing: true,
|
|
65
|
+
enableSorting: true,
|
|
66
|
+
enableMultiSort: true,
|
|
67
|
+
onSortingChange,
|
|
68
|
+
getSortedRowModel: getSortedRowModel(),
|
|
69
|
+
onPaginationChange,
|
|
70
|
+
getPaginationRowModel: getPaginationRowModel(),
|
|
71
|
+
getCoreRowModel: getCoreRowModel(),
|
|
72
|
+
columnResizeMode: 'onEnd',
|
|
73
|
+
});
|
|
74
|
+
return { table, tableColumns, columnPinning };
|
|
75
|
+
}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
6
|
"title": "Table",
|
|
7
|
-
"version": "0.14.7
|
|
7
|
+
"version": "0.14.7",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -33,17 +33,17 @@
|
|
|
33
33
|
"scripts": {},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@snack-uikit/button": "0.16.1",
|
|
36
|
-
"@snack-uikit/chips": "0.12.
|
|
36
|
+
"@snack-uikit/chips": "0.12.0",
|
|
37
37
|
"@snack-uikit/icon-predefined": "0.4.2",
|
|
38
38
|
"@snack-uikit/icons": "0.20.1",
|
|
39
39
|
"@snack-uikit/info-block": "0.3.0",
|
|
40
|
-
"@snack-uikit/list": "0.
|
|
40
|
+
"@snack-uikit/list": "0.5.0",
|
|
41
41
|
"@snack-uikit/pagination": "0.6.4",
|
|
42
42
|
"@snack-uikit/scroll": "0.5.2",
|
|
43
43
|
"@snack-uikit/skeleton": "0.3.3",
|
|
44
|
-
"@snack-uikit/tag": "0.8.
|
|
44
|
+
"@snack-uikit/tag": "0.8.0",
|
|
45
45
|
"@snack-uikit/toggles": "0.9.6",
|
|
46
|
-
"@snack-uikit/toolbar": "0.7.15
|
|
46
|
+
"@snack-uikit/toolbar": "0.7.15",
|
|
47
47
|
"@snack-uikit/truncate-string": "0.4.9",
|
|
48
48
|
"@snack-uikit/typography": "0.6.1",
|
|
49
49
|
"@snack-uikit/utils": "3.2.0",
|
|
@@ -58,5 +58,5 @@
|
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"@snack-uikit/locale": "*"
|
|
60
60
|
},
|
|
61
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "bfdd4a8e3c077eab0d45e177172a62b6dcbda06b"
|
|
62
62
|
}
|
|
@@ -31,7 +31,7 @@ export function ServerTable<TData extends object>({
|
|
|
31
31
|
const handleSearch = useCallback(
|
|
32
32
|
(newValue: string) => {
|
|
33
33
|
setTempSearch(newValue);
|
|
34
|
-
onSearchDebounced(newValue.trim(), setSearch);
|
|
34
|
+
onSearchDebounced()(newValue.trim(), setSearch);
|
|
35
35
|
},
|
|
36
36
|
|
|
37
37
|
[setSearch],
|
|
@@ -2,6 +2,8 @@ import debounce from 'lodash.debounce';
|
|
|
2
2
|
|
|
3
3
|
import { SEARCH_DELAY } from './constants';
|
|
4
4
|
|
|
5
|
-
export
|
|
6
|
-
onChange(newValue)
|
|
7
|
-
|
|
5
|
+
export function onSearchDebounced() {
|
|
6
|
+
return debounce((newValue: string, onChange: (newValue: string) => void) => {
|
|
7
|
+
onChange(newValue);
|
|
8
|
+
}, SEARCH_DELAY);
|
|
9
|
+
}
|
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CellContext,
|
|
3
|
-
ColumnPinningState,
|
|
4
|
-
getCoreRowModel,
|
|
5
|
-
getFilteredRowModel,
|
|
6
|
-
getPaginationRowModel,
|
|
7
|
-
getSortedRowModel,
|
|
8
|
-
PaginationState,
|
|
9
|
-
RowSelectionState,
|
|
10
|
-
SortingState,
|
|
11
|
-
useReactTable,
|
|
12
|
-
} from '@tanstack/react-table';
|
|
13
1
|
import cn from 'classnames';
|
|
14
2
|
import { RefObject, useCallback, useEffect, useMemo } from 'react';
|
|
15
3
|
|
|
@@ -17,7 +5,6 @@ import { useLocale } from '@snack-uikit/locale';
|
|
|
17
5
|
import { Scroll } from '@snack-uikit/scroll';
|
|
18
6
|
import { SkeletonContextProvider } from '@snack-uikit/skeleton';
|
|
19
7
|
import { Toolbar } from '@snack-uikit/toolbar';
|
|
20
|
-
import { TruncateString } from '@snack-uikit/truncate-string';
|
|
21
8
|
import { extractSupportProps } from '@snack-uikit/utils';
|
|
22
9
|
|
|
23
10
|
import { DEFAULT_PAGE_SIZE } from '../../constants';
|
|
@@ -26,7 +13,6 @@ import {
|
|
|
26
13
|
ExportButton,
|
|
27
14
|
getColumnId,
|
|
28
15
|
getRowActionsColumnDef,
|
|
29
|
-
getSelectionCellColumnDef,
|
|
30
16
|
getStatusColumnDef,
|
|
31
17
|
HeaderRow,
|
|
32
18
|
STATUS_APPEARANCE,
|
|
@@ -35,22 +21,19 @@ import {
|
|
|
35
21
|
TablePagination,
|
|
36
22
|
useEmptyState,
|
|
37
23
|
} from '../../helperComponents';
|
|
38
|
-
import { ColumnDefinition } from '../../types';
|
|
39
|
-
import { fuzzyFilter } from '../../utils';
|
|
40
24
|
import { TableProps } from '../types';
|
|
41
|
-
import { useLoadingTable } from './hooks';
|
|
42
|
-
import { useStateControl } from './hooks/useStateControl';
|
|
25
|
+
import { useLoadingTable, useTable } from './hooks';
|
|
43
26
|
import styles from './styles.module.scss';
|
|
44
27
|
|
|
45
28
|
/** Компонент таблицы */
|
|
46
29
|
export function Table<TData extends object>({
|
|
47
30
|
data,
|
|
48
31
|
columnDefinitions,
|
|
49
|
-
rowSelection
|
|
32
|
+
rowSelection,
|
|
50
33
|
search,
|
|
51
|
-
sorting
|
|
34
|
+
sorting,
|
|
52
35
|
columnFilters,
|
|
53
|
-
pagination
|
|
36
|
+
pagination,
|
|
54
37
|
className,
|
|
55
38
|
onRowClick,
|
|
56
39
|
onRefresh,
|
|
@@ -78,84 +61,17 @@ export function Table<TData extends object>({
|
|
|
78
61
|
|
|
79
62
|
...rest
|
|
80
63
|
}: TableProps<TData>) {
|
|
81
|
-
const {
|
|
82
|
-
const { state: rowSelection, onStateChange: onRowSelectionChange } = useStateControl<RowSelectionState>(
|
|
83
|
-
rowSelectionProp,
|
|
84
|
-
{},
|
|
85
|
-
);
|
|
86
|
-
const defaultPaginationState = useMemo(
|
|
87
|
-
() => ({
|
|
88
|
-
pageIndex: 0,
|
|
89
|
-
pageSize,
|
|
90
|
-
}),
|
|
91
|
-
[pageSize],
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
const { state: sorting, onStateChange: onSortingChange } = useStateControl<SortingState>(sortingProp, []);
|
|
95
|
-
const { state: pagination, onStateChange: onPaginationChange } = useStateControl<PaginationState>(
|
|
96
|
-
paginationProp,
|
|
97
|
-
defaultPaginationState,
|
|
98
|
-
);
|
|
99
|
-
const enableSelection = Boolean(rowSelectionProp?.enable);
|
|
100
|
-
|
|
101
|
-
const tableColumns: ColumnDefinition<TData>[] = useMemo(() => {
|
|
102
|
-
let cols: ColumnDefinition<TData>[] = columnDefinitions;
|
|
103
|
-
if (enableSelection) {
|
|
104
|
-
cols = [getSelectionCellColumnDef(), ...cols];
|
|
105
|
-
}
|
|
106
|
-
return cols;
|
|
107
|
-
}, [columnDefinitions, enableSelection]);
|
|
108
|
-
const columnPinning = useMemo(() => {
|
|
109
|
-
const pinningState: Required<ColumnPinningState> = { left: [], right: [] };
|
|
110
|
-
for (const col of tableColumns) {
|
|
111
|
-
const id = getColumnId(col);
|
|
112
|
-
if (col.pinned && id) {
|
|
113
|
-
pinningState[col.pinned]?.push(id);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
return pinningState;
|
|
117
|
-
}, [tableColumns]);
|
|
118
|
-
|
|
119
|
-
const table = useReactTable<TData>({
|
|
64
|
+
const { table, tableColumns, columnPinning } = useTable<TData>({
|
|
120
65
|
data,
|
|
121
|
-
|
|
122
|
-
state: {
|
|
123
|
-
columnPinning,
|
|
124
|
-
globalFilter,
|
|
125
|
-
rowSelection,
|
|
126
|
-
sorting,
|
|
127
|
-
pagination,
|
|
128
|
-
},
|
|
129
|
-
pageCount,
|
|
130
|
-
defaultColumn: {
|
|
131
|
-
enableSorting: false,
|
|
132
|
-
enableResizing: false,
|
|
133
|
-
minSize: 40,
|
|
134
|
-
cell: (cell: CellContext<TData, unknown>) => <TruncateString text={String(cell.getValue())} maxLines={1} />,
|
|
135
|
-
},
|
|
136
|
-
|
|
137
|
-
manualSorting,
|
|
138
|
-
manualPagination,
|
|
66
|
+
sorting,
|
|
139
67
|
manualFiltering,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
enableFilters: true,
|
|
148
|
-
getFilteredRowModel: getFilteredRowModel(),
|
|
149
|
-
enableColumnResizing: true,
|
|
150
|
-
enableSorting: true,
|
|
151
|
-
enableMultiSort: true,
|
|
152
|
-
onSortingChange,
|
|
153
|
-
getSortedRowModel: getSortedRowModel(),
|
|
154
|
-
onPaginationChange,
|
|
155
|
-
getPaginationRowModel: getPaginationRowModel(),
|
|
156
|
-
getCoreRowModel: getCoreRowModel(),
|
|
157
|
-
|
|
158
|
-
columnResizeMode: 'onEnd',
|
|
68
|
+
manualPagination,
|
|
69
|
+
manualSorting,
|
|
70
|
+
columnDefinitions,
|
|
71
|
+
rowSelection,
|
|
72
|
+
pagination,
|
|
73
|
+
pageCount,
|
|
74
|
+
pageSize,
|
|
159
75
|
});
|
|
160
76
|
|
|
161
77
|
const { loadingTable } = useLoadingTable({ pageSize, columnDefinitions: tableColumns, columnPinning });
|
|
@@ -176,7 +92,7 @@ export function Table<TData extends object>({
|
|
|
176
92
|
}, [loading, onDelete, table]);
|
|
177
93
|
|
|
178
94
|
const handleOnCheck = useCallback(() => {
|
|
179
|
-
if (!loading &&
|
|
95
|
+
if (!loading && rowSelection?.multiRow) {
|
|
180
96
|
table.toggleAllPageRowsSelected();
|
|
181
97
|
return;
|
|
182
98
|
}
|
|
@@ -185,7 +101,7 @@ export function Table<TData extends object>({
|
|
|
185
101
|
table.resetRowSelection();
|
|
186
102
|
return;
|
|
187
103
|
}
|
|
188
|
-
}, [loading,
|
|
104
|
+
}, [loading, rowSelection?.multiRow, table]);
|
|
189
105
|
|
|
190
106
|
useEffect(() => {}, []);
|
|
191
107
|
|
|
@@ -232,11 +148,14 @@ export function Table<TData extends object>({
|
|
|
232
148
|
return !tableRows.length ? Math.min(Math.max(tempPageSize, 5), DEFAULT_PAGE_SIZE) : tempPageSize;
|
|
233
149
|
}, [pageSize, suppressPagination, tablePagination?.pageSize, tableRows.length]);
|
|
234
150
|
|
|
151
|
+
const enableSelection = Boolean(rowSelection?.enable);
|
|
152
|
+
|
|
235
153
|
return (
|
|
236
154
|
<>
|
|
237
155
|
<div
|
|
238
156
|
style={{
|
|
239
157
|
'--page-size': cssPageSize,
|
|
158
|
+
// width: table.getTotalSize(),
|
|
240
159
|
}}
|
|
241
160
|
className={cn(styles.wrapper, className)}
|
|
242
161
|
{...extractSupportProps(rest)}
|
|
@@ -245,8 +164,8 @@ export function Table<TData extends object>({
|
|
|
245
164
|
<div className={styles.header}>
|
|
246
165
|
<Toolbar
|
|
247
166
|
search={{
|
|
248
|
-
value: globalFilter,
|
|
249
|
-
onChange:
|
|
167
|
+
value: table.getState().globalFilter,
|
|
168
|
+
onChange: table.setGlobalFilter,
|
|
250
169
|
loading: search?.loading,
|
|
251
170
|
placeholder: search?.placeholder || t('searchPlaceholder'),
|
|
252
171
|
}}
|
|
@@ -257,7 +176,7 @@ export function Table<TData extends object>({
|
|
|
257
176
|
onDelete={enableSelection && onDelete ? handleOnDelete : undefined}
|
|
258
177
|
onCheck={enableSelection ? handleOnCheck : undefined}
|
|
259
178
|
outline={outline}
|
|
260
|
-
selectionMode={
|
|
179
|
+
selectionMode={rowSelection?.multiRow ? 'multiple' : 'single'}
|
|
261
180
|
before={toolbarBefore}
|
|
262
181
|
after={
|
|
263
182
|
<>
|
|
@@ -309,8 +228,8 @@ export function Table<TData extends object>({
|
|
|
309
228
|
{!suppressPagination && (
|
|
310
229
|
<TablePagination
|
|
311
230
|
table={table}
|
|
312
|
-
options={
|
|
313
|
-
optionsLabel={
|
|
231
|
+
options={pagination?.options}
|
|
232
|
+
optionsLabel={pagination?.optionsLabel}
|
|
314
233
|
pageCount={pageCount}
|
|
315
234
|
/>
|
|
316
235
|
)}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CellContext,
|
|
3
|
+
ColumnPinningState,
|
|
4
|
+
getCoreRowModel,
|
|
5
|
+
getFilteredRowModel,
|
|
6
|
+
getPaginationRowModel,
|
|
7
|
+
getSortedRowModel,
|
|
8
|
+
PaginationState,
|
|
9
|
+
RowSelectionState,
|
|
10
|
+
SortingState,
|
|
11
|
+
useReactTable,
|
|
12
|
+
} from '@tanstack/react-table';
|
|
13
|
+
import { useMemo } from 'react';
|
|
14
|
+
|
|
15
|
+
import { TruncateString } from '@snack-uikit/truncate-string';
|
|
16
|
+
|
|
17
|
+
import { DEFAULT_PAGE_SIZE } from '../../../constants';
|
|
18
|
+
import { getColumnId, getSelectionCellColumnDef } from '../../../helperComponents';
|
|
19
|
+
import { ColumnDefinition } from '../../../types';
|
|
20
|
+
import { fuzzyFilter } from '../../../utils';
|
|
21
|
+
import { TableProps } from '../../types';
|
|
22
|
+
import { useStateControl } from './useStateControl';
|
|
23
|
+
|
|
24
|
+
type UseTableProps<TData extends object> = Pick<
|
|
25
|
+
TableProps<TData>,
|
|
26
|
+
| 'search'
|
|
27
|
+
| 'rowSelection'
|
|
28
|
+
| 'sorting'
|
|
29
|
+
| 'pagination'
|
|
30
|
+
| 'pageSize'
|
|
31
|
+
| 'columnDefinitions'
|
|
32
|
+
| 'data'
|
|
33
|
+
| 'manualFiltering'
|
|
34
|
+
| 'manualSorting'
|
|
35
|
+
| 'manualPagination'
|
|
36
|
+
| 'pageCount'
|
|
37
|
+
>;
|
|
38
|
+
|
|
39
|
+
export function useTable<TData extends object>({
|
|
40
|
+
search,
|
|
41
|
+
pageSize = DEFAULT_PAGE_SIZE,
|
|
42
|
+
pagination: paginationProp,
|
|
43
|
+
rowSelection: rowSelectionProp,
|
|
44
|
+
sorting: sortingProp,
|
|
45
|
+
columnDefinitions,
|
|
46
|
+
manualFiltering,
|
|
47
|
+
manualPagination,
|
|
48
|
+
manualSorting,
|
|
49
|
+
pageCount,
|
|
50
|
+
data,
|
|
51
|
+
}: UseTableProps<TData>) {
|
|
52
|
+
const { state: globalFilter, onStateChange: onGlobalFilterChange } = useStateControl<string>(search, '');
|
|
53
|
+
const { state: rowSelection, onStateChange: onRowSelectionChange } = useStateControl<RowSelectionState>(
|
|
54
|
+
rowSelectionProp,
|
|
55
|
+
{},
|
|
56
|
+
);
|
|
57
|
+
const defaultPaginationState = useMemo(
|
|
58
|
+
() => ({
|
|
59
|
+
pageIndex: 0,
|
|
60
|
+
pageSize,
|
|
61
|
+
}),
|
|
62
|
+
[pageSize],
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const { state: sorting, onStateChange: onSortingChange } = useStateControl<SortingState>(sortingProp, []);
|
|
66
|
+
const { state: pagination, onStateChange: onPaginationChange } = useStateControl<PaginationState>(
|
|
67
|
+
paginationProp,
|
|
68
|
+
defaultPaginationState,
|
|
69
|
+
);
|
|
70
|
+
const enableSelection = Boolean(rowSelectionProp?.enable);
|
|
71
|
+
const tableColumns: ColumnDefinition<TData>[] = useMemo(() => {
|
|
72
|
+
let cols: ColumnDefinition<TData>[] = columnDefinitions;
|
|
73
|
+
if (enableSelection) {
|
|
74
|
+
cols = [getSelectionCellColumnDef(), ...cols];
|
|
75
|
+
}
|
|
76
|
+
return cols;
|
|
77
|
+
}, [columnDefinitions, enableSelection]);
|
|
78
|
+
const columnPinning = useMemo(() => {
|
|
79
|
+
const pinningState: Required<ColumnPinningState> = { left: [], right: [] };
|
|
80
|
+
for (const col of tableColumns) {
|
|
81
|
+
const id = getColumnId(col);
|
|
82
|
+
if (col.pinned && id) {
|
|
83
|
+
pinningState[col.pinned]?.push(id);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return pinningState;
|
|
87
|
+
}, [tableColumns]);
|
|
88
|
+
|
|
89
|
+
const table = useReactTable<TData>({
|
|
90
|
+
data,
|
|
91
|
+
columns: tableColumns,
|
|
92
|
+
state: {
|
|
93
|
+
columnPinning,
|
|
94
|
+
globalFilter,
|
|
95
|
+
rowSelection,
|
|
96
|
+
sorting,
|
|
97
|
+
pagination,
|
|
98
|
+
},
|
|
99
|
+
pageCount,
|
|
100
|
+
defaultColumn: {
|
|
101
|
+
enableSorting: true,
|
|
102
|
+
enableResizing: true,
|
|
103
|
+
minSize: 40,
|
|
104
|
+
cell: (cell: CellContext<TData, unknown>) => <TruncateString text={String(cell.getValue())} maxLines={1} />,
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
manualSorting,
|
|
108
|
+
manualPagination,
|
|
109
|
+
manualFiltering,
|
|
110
|
+
|
|
111
|
+
globalFilterFn: fuzzyFilter,
|
|
112
|
+
onGlobalFilterChange,
|
|
113
|
+
|
|
114
|
+
onRowSelectionChange,
|
|
115
|
+
enableRowSelection: rowSelectionProp?.enable,
|
|
116
|
+
enableMultiRowSelection: rowSelectionProp?.multiRow,
|
|
117
|
+
enableFilters: true,
|
|
118
|
+
getFilteredRowModel: getFilteredRowModel(),
|
|
119
|
+
enableColumnResizing: true,
|
|
120
|
+
enableSorting: true,
|
|
121
|
+
enableMultiSort: true,
|
|
122
|
+
onSortingChange,
|
|
123
|
+
getSortedRowModel: getSortedRowModel(),
|
|
124
|
+
onPaginationChange,
|
|
125
|
+
getPaginationRowModel: getPaginationRowModel(),
|
|
126
|
+
getCoreRowModel: getCoreRowModel(),
|
|
127
|
+
|
|
128
|
+
columnResizeMode: 'onEnd',
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
return { table, tableColumns, columnPinning };
|
|
132
|
+
}
|