@snack-uikit/table 0.16.7 → 0.16.8-preview-e82f86de.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/README.md +2 -0
- package/dist/components/Table/Table.d.ts +1 -1
- package/dist/components/Table/Table.js +34 -6
- package/dist/components/types.d.ts +2 -0
- package/dist/constants.js +1 -1
- package/dist/helperComponents/Cells/HeaderCell/HeaderCell.js +1 -1
- package/dist/helperComponents/Cells/HeaderCell/ResizeHandle.js +9 -2
- package/dist/helperComponents/Cells/HeaderCell/styles.module.css +1 -0
- package/dist/helperComponents/Cells/RowActionsCell/RowActionsCell.d.ts +2 -15
- package/dist/helperComponents/Cells/RowActionsCell/RowActionsCell.js +15 -23
- package/dist/helperComponents/Cells/RowActionsCell/styles.module.css +2 -8
- package/dist/helperComponents/Rows/BodyRow.js +2 -2
- package/dist/helperComponents/Rows/styles.module.css +1 -0
- package/dist/helperComponents/contexts.d.ts +2 -2
- package/dist/helperComponents/contexts.js +2 -2
- package/dist/types.d.ts +1 -1
- package/package.json +5 -6
- package/src/components/Table/Table.tsx +44 -8
- package/src/components/types.ts +3 -0
- package/src/constants.ts +1 -1
- package/src/helperComponents/Cells/HeaderCell/HeaderCell.tsx +1 -0
- package/src/helperComponents/Cells/HeaderCell/ResizeHandle.tsx +14 -4
- package/src/helperComponents/Cells/HeaderCell/styles.module.scss +1 -0
- package/src/helperComponents/Cells/RowActionsCell/RowActionsCell.tsx +28 -51
- package/src/helperComponents/Cells/RowActionsCell/styles.module.scss +2 -11
- package/src/helperComponents/Rows/BodyRow.tsx +3 -3
- package/src/helperComponents/Rows/styles.module.scss +1 -0
- package/src/helperComponents/contexts.ts +4 -4
- package/src/types.ts +0 -2
package/README.md
CHANGED
|
@@ -114,6 +114,7 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
|
|
|
114
114
|
| sorting | `{ initialState?: SortingState; state?: SortingState; onChange?(state: SortingState): void; }` | - | Параметры отвечают за возможность сортировки, их стоит использовать если нужно отслеживать состояние <br> <strong>initialState</strong>: Начальное состояние сортировки <br> <strong>state</strong>: Состояние сортировки, жестко устанавливаемое снаружи <br> <strong>onChange</strong>: Колбэк на изменение сортировки |
|
|
115
115
|
| 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
116
|
| search | `{ initialValue?: 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 строки поиска |
|
|
117
|
+
| enableFuzzySearch | `boolean` | - | Включить нечеткий поиск |
|
|
117
118
|
| pageSize | `number` | 10 | Максимальное кол-во строк на страницу |
|
|
118
119
|
| pagination | `{ state?: PaginationState; options?: number[]; optionsLabel?: string; onChange?(state: PaginationState): void; }` | 'Rows volume: ' <br> <strong>onChange</strong>: Колбэк на изменение пагинации | Параметры отвечают за пагинацию в таблице <br> <strong>state</strong>: Состояние строки поиска, жестко устанавливаемое снаружи <br> <strong>options</strong>: Варианты в выпадающем селекторе для установки кол-ва строк на страницу <br> <strong>optionsLabel</strong>: Текст для селектора кол-ва строк на страницу |
|
|
119
120
|
| pageCount | `number` | - | Кол-во страниц (используется для внешнего управления) |
|
|
@@ -169,6 +170,7 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
|
|
|
169
170
|
| loading | `boolean` | - | Состояние загрузки |
|
|
170
171
|
| sorting | `{ initialState?: SortingState; state?: SortingState; onChange?(state: SortingState): void; }` | - | Параметры отвечают за возможность сортировки, их стоит использовать если нужно отслеживать состояние <br> <strong>initialState</strong>: Начальное состояние сортировки <br> <strong>state</strong>: Состояние сортировки, жестко устанавливаемое снаружи <br> <strong>onChange</strong>: Колбэк на изменение сортировки |
|
|
171
172
|
| 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
|
+
| enableFuzzySearch | `boolean` | - | Включить нечеткий поиск |
|
|
172
174
|
| onRowClick | `RowClickHandler<TData>` | - | Колбэк клика по строке |
|
|
173
175
|
| className | `string` | - | CSS-класс |
|
|
174
176
|
| onRefresh | `() => void` | - | Колбек обновления данных |
|
|
@@ -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, ...rest }: TableProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
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;
|
|
4
4
|
export declare namespace Table {
|
|
5
5
|
var getStatusColumnDef: typeof import("../../helperComponents").getStatusColumnDef;
|
|
6
6
|
var statusAppearances: {
|
|
@@ -12,7 +12,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
12
12
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
13
|
import { getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from '@tanstack/react-table';
|
|
14
14
|
import cn from 'classnames';
|
|
15
|
-
import { useCallback, useEffect, useMemo } from 'react';
|
|
15
|
+
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
16
16
|
import { useLocale } from '@snack-uikit/locale';
|
|
17
17
|
import { Scroll } from '@snack-uikit/scroll';
|
|
18
18
|
import { SkeletonContextProvider } from '@snack-uikit/skeleton';
|
|
@@ -27,7 +27,7 @@ import { useStateControl } from './hooks/useStateControl';
|
|
|
27
27
|
import styles from './styles.module.css';
|
|
28
28
|
/** Компонент таблицы */
|
|
29
29
|
export function Table(_a) {
|
|
30
|
-
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 } = _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"]);
|
|
30
|
+
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
31
|
const { state: globalFilter, onStateChange: onGlobalFilterChange } = useStateControl(search, '');
|
|
32
32
|
const { state: rowSelection, onStateChange: onRowSelectionChange } = useStateControl(rowSelectionProp, {});
|
|
33
33
|
const defaultPaginationState = useMemo(() => ({
|
|
@@ -37,6 +37,11 @@ export function Table(_a) {
|
|
|
37
37
|
const { state: sorting, onStateChange: onSortingChange } = useStateControl(sortingProp, []);
|
|
38
38
|
const { state: pagination, onStateChange: onPaginationChange } = useStateControl(paginationProp, defaultPaginationState);
|
|
39
39
|
const enableSelection = Boolean(rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.enable);
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (pagination.pageIndex >= data.length / pagination.pageSize) {
|
|
42
|
+
onPaginationChange(Object.assign(Object.assign({}, pagination), { pageIndex: 0 }));
|
|
43
|
+
}
|
|
44
|
+
}, [data.length, onPaginationChange, pagination]);
|
|
40
45
|
const tableColumns = useMemo(() => {
|
|
41
46
|
let cols = columnDefinitions;
|
|
42
47
|
if (enableSelection) {
|
|
@@ -75,7 +80,7 @@ export function Table(_a) {
|
|
|
75
80
|
manualSorting,
|
|
76
81
|
manualPagination,
|
|
77
82
|
manualFiltering,
|
|
78
|
-
globalFilterFn: fuzzyFilter,
|
|
83
|
+
globalFilterFn: enableFuzzySearch ? fuzzyFilter : undefined,
|
|
79
84
|
onGlobalFilterChange,
|
|
80
85
|
getRowId,
|
|
81
86
|
onRowSelectionChange,
|
|
@@ -89,6 +94,7 @@ export function Table(_a) {
|
|
|
89
94
|
onSortingChange,
|
|
90
95
|
getSortedRowModel: getSortedRowModel(),
|
|
91
96
|
onPaginationChange,
|
|
97
|
+
autoResetPageIndex: false,
|
|
92
98
|
getPaginationRowModel: getPaginationRowModel(),
|
|
93
99
|
getCoreRowModel: getCoreRowModel(),
|
|
94
100
|
columnResizeMode: 'onEnd',
|
|
@@ -116,8 +122,21 @@ export function Table(_a) {
|
|
|
116
122
|
return;
|
|
117
123
|
}
|
|
118
124
|
}, [loading, rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.multiRow, table]);
|
|
119
|
-
|
|
125
|
+
const columnSizeVarsRef = useRef();
|
|
120
126
|
const columnSizeVars = useMemo(() => {
|
|
127
|
+
var _a;
|
|
128
|
+
const sizeKey = (id) => `--table-column-${id}-size`;
|
|
129
|
+
const flexKey = (id) => `--table-column-${id}-flex`;
|
|
130
|
+
const getCurrentlyConfiguredHeaderWidth = (id) => {
|
|
131
|
+
const cell = document.querySelector(`[data-header-id="${id}"]`);
|
|
132
|
+
const resizeHandler = cell === null || cell === void 0 ? void 0 : cell.querySelector('[data-test-id="table__header-cell-resize-handle-moving-part"]');
|
|
133
|
+
if (cell && resizeHandler) {
|
|
134
|
+
const { width } = cell.getBoundingClientRect();
|
|
135
|
+
const offset = parseInt(resizeHandler.style.getPropertyValue('--offset'));
|
|
136
|
+
return width + offset;
|
|
137
|
+
}
|
|
138
|
+
return 0;
|
|
139
|
+
};
|
|
121
140
|
const originalColumnDefs = table._getColumnDefs();
|
|
122
141
|
const headers = table.getFlatHeaders();
|
|
123
142
|
const colSizes = {};
|
|
@@ -126,20 +145,29 @@ export function Table(_a) {
|
|
|
126
145
|
const originalColDef = originalColumnDefs.find(col => getColumnId(header) === col.id);
|
|
127
146
|
const originalColumnDefSize = originalColDef === null || originalColDef === void 0 ? void 0 : originalColDef.size;
|
|
128
147
|
const initSize = originalColumnDefSize ? `${originalColumnDefSize}px` : '100%';
|
|
148
|
+
const prevSize = (_a = columnSizeVarsRef.current) === null || _a === void 0 ? void 0 : _a[sizeKey(header.id)];
|
|
129
149
|
let size = initSize;
|
|
130
150
|
if (header.column.getCanResize()) {
|
|
131
151
|
const currentSize = header.getSize();
|
|
132
152
|
const colDefSize = header.column.columnDef.size;
|
|
133
153
|
size = currentSize === colDefSize ? initSize : `${currentSize}px`;
|
|
154
|
+
if (prevSize === '100%' && currentSize !== colDefSize) {
|
|
155
|
+
const realSize = getCurrentlyConfiguredHeaderWidth(header.id);
|
|
156
|
+
table.setColumnSizing(old => (Object.assign(Object.assign({}, old), { [header.id]: realSize })));
|
|
157
|
+
size = `${realSize}px`;
|
|
158
|
+
}
|
|
134
159
|
}
|
|
135
|
-
colSizes[
|
|
136
|
-
colSizes[
|
|
160
|
+
colSizes[sizeKey(header.id)] = size;
|
|
161
|
+
colSizes[flexKey(header.id)] = size === '100%' ? 'unset' : '0';
|
|
137
162
|
}
|
|
138
163
|
return colSizes;
|
|
139
164
|
/* effect must be called only on columnSizingInfo.isResizingColumn changes
|
|
140
165
|
to reduce unnecessary recalculations */
|
|
141
166
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
142
167
|
}, [table.getState().columnSizingInfo.isResizingColumn]);
|
|
168
|
+
useEffect(() => {
|
|
169
|
+
columnSizeVarsRef.current = columnSizeVars;
|
|
170
|
+
}, [columnSizeVars]);
|
|
143
171
|
const tableRows = table.getRowModel().rows;
|
|
144
172
|
const loadingTableRows = loadingTable.getRowModel().rows;
|
|
145
173
|
const tablePagination = table.getState().pagination;
|
|
@@ -48,6 +48,8 @@ export type TableProps<TData extends object> = WithSupportProps<{
|
|
|
48
48
|
loading?: boolean;
|
|
49
49
|
onChange?(value: string): void;
|
|
50
50
|
};
|
|
51
|
+
/** Включить нечеткий поиск */
|
|
52
|
+
enableFuzzySearch?: boolean;
|
|
51
53
|
/** Максимальное кол-во строк на страницу @default 10 */
|
|
52
54
|
pageSize?: number;
|
|
53
55
|
/** Параметры отвечают за пагинацию в таблице <br>
|
package/dist/constants.js
CHANGED
|
@@ -17,7 +17,7 @@ export const TEST_IDS = {
|
|
|
17
17
|
rowActions: {
|
|
18
18
|
droplistTrigger: 'table__body-row__droplistTrigger',
|
|
19
19
|
droplist: 'table__body-row__actions-droplist',
|
|
20
|
-
option: '
|
|
20
|
+
option: 'list__base-item-option',
|
|
21
21
|
},
|
|
22
22
|
statusIndicator: 'table__status-indicator',
|
|
23
23
|
statusLabel: 'table__status-label',
|
|
@@ -26,5 +26,5 @@ export function HeaderCell({ header, className }) {
|
|
|
26
26
|
return;
|
|
27
27
|
return (_a = header.column.getToggleSortingHandler()) === null || _a === void 0 ? void 0 : _a(e);
|
|
28
28
|
};
|
|
29
|
-
return (_jsxs(Cell, { style: style, onMouseUp: sortingHandler, "data-sortable": isSortable || undefined, "data-no-padding": columnDef.noHeaderCellPadding || undefined, "data-no-offset": columnDef.noHeaderCellBorderOffset || undefined, "data-test-id": TEST_IDS.headerCell, "data-resizing": isResizing || undefined, role: 'columnheader', className: cn(styles.tableHeaderCell, className, columnDef.headerClassName), ref: cellRef, children: [_jsxs("div", { className: styles.tableHeaderCellMain, children: [columnDef.header && (_jsx("div", { className: styles.tableHeaderCellName, children: _jsx(TruncateString, { text: flexRender(columnDef.header, header.getContext()) }) })), Boolean(sortIcon) && (_jsx("div", { className: styles.tableHeaderIcon, "data-sort-direction": sortDirection, "data-test-id": TEST_IDS.headerSortIndicator, children: sortIcon }))] }), Boolean(isResizable) && _jsx(ResizeHandle, { header: header, cellRef: cellRef })] }));
|
|
29
|
+
return (_jsxs(Cell, { style: style, onMouseUp: sortingHandler, "data-sortable": isSortable || undefined, "data-no-padding": columnDef.noHeaderCellPadding || undefined, "data-no-offset": columnDef.noHeaderCellBorderOffset || undefined, "data-test-id": TEST_IDS.headerCell, "data-header-id": header.id, "data-resizing": isResizing || undefined, role: 'columnheader', className: cn(styles.tableHeaderCell, className, columnDef.headerClassName), ref: cellRef, children: [_jsxs("div", { className: styles.tableHeaderCellMain, children: [columnDef.header && (_jsx("div", { className: styles.tableHeaderCellName, children: _jsx(TruncateString, { text: flexRender(columnDef.header, header.getContext()) }) })), Boolean(sortIcon) && (_jsx("div", { className: styles.tableHeaderIcon, "data-sort-direction": sortDirection, "data-test-id": TEST_IDS.headerSortIndicator, children: sortIcon }))] }), Boolean(isResizable) && _jsx(ResizeHandle, { header: header, cellRef: cellRef })] }));
|
|
30
30
|
}
|
|
@@ -22,8 +22,15 @@ function getResizeIndicatorOffset({ header, cellRef }) {
|
|
|
22
22
|
export function ResizeHandle({ header, cellRef }) {
|
|
23
23
|
const isResizing = header.column.getIsResizing();
|
|
24
24
|
const resizeHandler = header.getResizeHandler();
|
|
25
|
+
const handleMouseDown = event => {
|
|
26
|
+
if (event.detail === 2) {
|
|
27
|
+
header.column.resetSize();
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
resizeHandler(event);
|
|
31
|
+
};
|
|
25
32
|
const offset = isResizing ? getResizeIndicatorOffset({ header, cellRef }) : 0;
|
|
26
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { className: cn(styles.tableHeaderIcon, styles.tableHeaderResizeHandle), "data-resizing": isResizing || undefined, onMouseDown:
|
|
27
|
-
|
|
33
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { role: 'button', tabIndex: 0, className: cn(styles.tableHeaderIcon, styles.tableHeaderResizeHandle), "data-resizing": isResizing || undefined, onMouseDown: handleMouseDown, onTouchStart: resizeHandler }), isResizing && (_jsx("div", { "data-test-id": 'table__header-cell-resize-handle-moving-part', className: styles.tableHeaderResizeIndicator, style: {
|
|
34
|
+
'--offset': `${offset}px`,
|
|
28
35
|
} }))] }));
|
|
29
36
|
}
|
|
@@ -1,20 +1,7 @@
|
|
|
1
1
|
import { CellContext } from '@tanstack/react-table';
|
|
2
|
-
import {
|
|
3
|
-
import { BaseItemProps } from '@snack-uikit/list';
|
|
2
|
+
import { DroplistProps } from '@snack-uikit/list';
|
|
4
3
|
import { ColumnDefinition } from '../../../types';
|
|
5
|
-
export type
|
|
6
|
-
rowId: string;
|
|
7
|
-
data: TData;
|
|
8
|
-
itemId?: string;
|
|
9
|
-
};
|
|
10
|
-
export type RowActionProps<TData> = Pick<BaseItemProps, 'content' | 'disabled' | 'data-test-id'> & {
|
|
11
|
-
icon?: ReactElement;
|
|
12
|
-
tagLabel?: string;
|
|
13
|
-
id?: string;
|
|
14
|
-
hidden?: boolean;
|
|
15
|
-
onClick(row: RowActionInfo<TData>, e: MouseEvent<HTMLElement>): void;
|
|
16
|
-
};
|
|
17
|
-
export type ActionsGenerator<TData> = (cell: CellContext<TData, unknown>) => RowActionProps<TData>[];
|
|
4
|
+
export type ActionsGenerator<TData> = (cell: CellContext<TData, unknown>) => DroplistProps['items'];
|
|
18
5
|
export type RowActionsColumnDefProps<TData> = {
|
|
19
6
|
/** Действия для строки */
|
|
20
7
|
actionsGenerator: ActionsGenerator<TData>;
|
|
@@ -1,39 +1,31 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useCallback, useMemo } from 'react';
|
|
3
3
|
import { ButtonFunction } from '@snack-uikit/button';
|
|
4
4
|
import { MoreSVG } from '@snack-uikit/icons';
|
|
5
|
-
import { Droplist } from '@snack-uikit/list';
|
|
6
|
-
import { Tag } from '@snack-uikit/tag';
|
|
5
|
+
import { Droplist, isBaseItemProps } from '@snack-uikit/list';
|
|
7
6
|
import { COLUMN_PIN_POSITION, TEST_IDS } from '../../../constants';
|
|
8
7
|
import { useRowContext } from '../../contexts';
|
|
9
8
|
import styles from './styles.module.css';
|
|
10
9
|
function RowActionsCell({ row, actions }) {
|
|
11
|
-
const {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
const { dropListOpened, setDropListOpen } = useRowContext();
|
|
11
|
+
const patchItem = useCallback((item, cb) => {
|
|
12
|
+
if (isBaseItemProps(item)) {
|
|
13
|
+
return Object.assign(Object.assign({}, item), { onClick(e) {
|
|
14
|
+
var _a;
|
|
15
|
+
(_a = item.onClick) === null || _a === void 0 ? void 0 : _a.call(item, e);
|
|
16
|
+
cb(e);
|
|
17
|
+
} });
|
|
18
|
+
}
|
|
19
|
+
return Object.assign(Object.assign({}, item), { items: item.items.map(i => patchItem(i, cb)) });
|
|
20
|
+
}, []);
|
|
16
21
|
const disabled = !row.getCanSelect();
|
|
17
22
|
const stopPropagationClick = (e) => {
|
|
18
23
|
e.stopPropagation();
|
|
19
24
|
};
|
|
20
|
-
const
|
|
25
|
+
const patchedItems = useMemo(() => actions.map(item => patchItem(item, () => setDropListOpen(false))), [actions, patchItem, setDropListOpen]);
|
|
21
26
|
return (
|
|
22
27
|
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
23
|
-
_jsx("div", { onClick: stopPropagationClick, className: styles.rowActionsCellWrap, "data-open":
|
|
24
|
-
.filter(item => !(item === null || item === void 0 ? void 0 : item.hidden))
|
|
25
|
-
.map(item => ({
|
|
26
|
-
id: item.id,
|
|
27
|
-
onClick: e => {
|
|
28
|
-
handleItemClick(item)(e);
|
|
29
|
-
setDroplistOpen(false);
|
|
30
|
-
},
|
|
31
|
-
disabled: item.disabled,
|
|
32
|
-
content: item.content,
|
|
33
|
-
beforeContent: item.icon,
|
|
34
|
-
afterContent: item.tagLabel ? _jsx(Tag, { label: item.tagLabel }) : undefined,
|
|
35
|
-
'data-test-id': item['data-test-id'] || TEST_IDS.rowActions.option,
|
|
36
|
-
})), children: _jsx("span", { className: styles.rowActionsCellTrigger, children: _jsx(ButtonFunction, { icon: _jsx(MoreSVG, { size: 24 }), "data-test-id": TEST_IDS.rowActions.droplistTrigger, ref: triggerRef }) }) })) }));
|
|
28
|
+
_jsx("div", { onClick: stopPropagationClick, className: styles.rowActionsCellWrap, "data-open": dropListOpened || undefined, children: !disabled && Boolean(actions.length) && (_jsx(Droplist, { trigger: 'clickAndFocusVisible', open: dropListOpened, onOpenChange: setDropListOpen, placement: 'bottom-end', size: 'm', "data-test-id": TEST_IDS.rowActions.droplist, items: patchedItems, children: _jsx(ButtonFunction, { icon: _jsx(MoreSVG, { size: 24 }), "data-test-id": TEST_IDS.rowActions.droplistTrigger }) })) }));
|
|
37
29
|
}
|
|
38
30
|
/** Вспомогательная функция для создания ячейки с дополнительными действиями у строки */
|
|
39
31
|
export function getRowActionsColumnDef({ actionsGenerator, pinned, }) {
|
|
@@ -16,20 +16,14 @@
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
.rowActionsCellWrap{
|
|
19
|
+
--offset:0px;
|
|
20
|
+
cursor:pointer;
|
|
19
21
|
box-sizing:border-box;
|
|
20
22
|
width:100%;
|
|
21
23
|
height:100%;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
.rowActionsCellTrigger{
|
|
25
|
-
--offset:0px;
|
|
26
24
|
padding-left:var(--space-table-cell-action-padding, 4px);
|
|
27
25
|
padding-right:var(--space-table-cell-action-padding, 4px);
|
|
28
|
-
cursor:pointer;
|
|
29
26
|
display:flex;
|
|
30
27
|
align-items:center;
|
|
31
28
|
justify-content:center;
|
|
32
|
-
box-sizing:border-box;
|
|
33
|
-
width:100%;
|
|
34
|
-
height:100%;
|
|
35
29
|
}
|
|
@@ -9,7 +9,7 @@ import { Row } from './Row';
|
|
|
9
9
|
import styles from './styles.module.css';
|
|
10
10
|
export function BodyRow({ row, onRowClick }) {
|
|
11
11
|
const { pinnedLeft, pinnedRight, unpinned } = useRowCells(row);
|
|
12
|
-
const [
|
|
12
|
+
const [dropListOpened, setDropListOpen] = useState(false);
|
|
13
13
|
const disabled = !row.getCanSelect();
|
|
14
14
|
const handleRowClick = (e) => {
|
|
15
15
|
if (disabled)
|
|
@@ -21,5 +21,5 @@ export function BodyRow({ row, onRowClick }) {
|
|
|
21
21
|
toggleSelected: row.toggleSelected,
|
|
22
22
|
});
|
|
23
23
|
};
|
|
24
|
-
return (_jsx(RowContext.Provider, { value: {
|
|
24
|
+
return (_jsx(RowContext.Provider, { value: { dropListOpened, setDropListOpen }, children: _jsxs(Row, { onClick: handleRowClick, "data-clickable": Boolean(onRowClick) || undefined, "data-disabled": disabled || undefined, "data-selected": row.getIsSelected() || undefined, "data-actions-opened": dropListOpened || undefined, "data-test-id": TEST_IDS.bodyRow, "data-row-id": row.id, className: styles.bodyRow, children: [pinnedLeft && (_jsx(PinnedCells, { position: COLUMN_PIN_POSITION.Left, children: pinnedLeft.map(cell => (_jsx(BodyCell, { cell: cell }, cell.id))) })), unpinned.map(cell => (_jsx(BodyCell, { cell: cell }, cell.id))), pinnedRight && (_jsx(PinnedCells, { position: COLUMN_PIN_POSITION.Right, children: pinnedRight.map(cell => (_jsx(BodyCell, { cell: cell }, cell.id))) }))] }) }));
|
|
25
25
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Table } from '@tanstack/react-table';
|
|
2
2
|
import { Dispatch, SetStateAction } from 'react';
|
|
3
3
|
type RowContext = {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
dropListOpened: boolean;
|
|
5
|
+
setDropListOpen: Dispatch<SetStateAction<boolean>>;
|
|
6
6
|
};
|
|
7
7
|
export declare const RowContext: import("react").Context<RowContext>;
|
|
8
8
|
export declare const useRowContext: () => RowContext;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createContext, useContext } from 'react';
|
|
2
2
|
export const RowContext = createContext({
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
dropListOpened: false,
|
|
4
|
+
setDropListOpen() { },
|
|
5
5
|
});
|
|
6
6
|
export const useRowContext = () => useContext(RowContext);
|
|
7
7
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
package/dist/types.d.ts
CHANGED
|
@@ -37,5 +37,5 @@ type PinnedColumnDefinition<TData> = BaseColumnDefinition<TData> & {
|
|
|
37
37
|
size: number;
|
|
38
38
|
};
|
|
39
39
|
export type ColumnDefinition<TData> = NormalColumnDefinition<TData> | PinnedColumnDefinition<TData>;
|
|
40
|
-
export type {
|
|
40
|
+
export type { RowActionsColumnDefProps, StatusColumnDefinitionProps, RowInfo, RowClickHandler, ActionsGenerator, CopyCellProps, MapStatusToAppearanceFnType, } from './helperComponents';
|
|
41
41
|
export type { PaginationState, SortingState, RowSelectionState, RowSelectionOptions, EmptyStateProps, ToolbarProps, HeaderContext, CellContext, };
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
6
|
"title": "Table",
|
|
7
|
-
"version": "0.16.
|
|
7
|
+
"version": "0.16.8-preview-e82f86de.0",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -33,17 +33,16 @@
|
|
|
33
33
|
"scripts": {},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@snack-uikit/button": "0.17.1",
|
|
36
|
-
"@snack-uikit/chips": "0.13.
|
|
36
|
+
"@snack-uikit/chips": "0.13.4-preview-e82f86de.0",
|
|
37
37
|
"@snack-uikit/icon-predefined": "0.5.1",
|
|
38
38
|
"@snack-uikit/icons": "0.20.1",
|
|
39
39
|
"@snack-uikit/info-block": "0.3.4",
|
|
40
|
-
"@snack-uikit/list": "0.11.
|
|
40
|
+
"@snack-uikit/list": "0.11.5-preview-e82f86de.0",
|
|
41
41
|
"@snack-uikit/pagination": "0.6.7",
|
|
42
42
|
"@snack-uikit/scroll": "0.5.3",
|
|
43
43
|
"@snack-uikit/skeleton": "0.3.4",
|
|
44
|
-
"@snack-uikit/tag": "0.9.1",
|
|
45
44
|
"@snack-uikit/toggles": "0.9.8",
|
|
46
|
-
"@snack-uikit/toolbar": "0.7.
|
|
45
|
+
"@snack-uikit/toolbar": "0.7.33-preview-e82f86de.0",
|
|
47
46
|
"@snack-uikit/truncate-string": "0.4.13",
|
|
48
47
|
"@snack-uikit/typography": "0.6.2",
|
|
49
48
|
"@snack-uikit/utils": "3.3.0",
|
|
@@ -58,5 +57,5 @@
|
|
|
58
57
|
"peerDependencies": {
|
|
59
58
|
"@snack-uikit/locale": "*"
|
|
60
59
|
},
|
|
61
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "31a8e5230a8829ad3222c4bb9acb9b20e5345f4d"
|
|
62
61
|
}
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
useReactTable,
|
|
12
12
|
} from '@tanstack/react-table';
|
|
13
13
|
import cn from 'classnames';
|
|
14
|
-
import { RefObject, useCallback, useEffect, useMemo } from 'react';
|
|
14
|
+
import { RefObject, useCallback, useEffect, useMemo, useRef } from 'react';
|
|
15
15
|
|
|
16
16
|
import { useLocale } from '@snack-uikit/locale';
|
|
17
17
|
import { Scroll } from '@snack-uikit/scroll';
|
|
@@ -76,7 +76,7 @@ export function Table<TData extends object>({
|
|
|
76
76
|
scrollRef,
|
|
77
77
|
scrollContainerRef,
|
|
78
78
|
getRowId,
|
|
79
|
-
|
|
79
|
+
enableFuzzySearch,
|
|
80
80
|
...rest
|
|
81
81
|
}: TableProps<TData>) {
|
|
82
82
|
const { state: globalFilter, onStateChange: onGlobalFilterChange } = useStateControl<string>(search, '');
|
|
@@ -99,6 +99,12 @@ export function Table<TData extends object>({
|
|
|
99
99
|
);
|
|
100
100
|
const enableSelection = Boolean(rowSelectionProp?.enable);
|
|
101
101
|
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (pagination.pageIndex >= data.length / pagination.pageSize) {
|
|
104
|
+
onPaginationChange({ ...pagination, pageIndex: 0 });
|
|
105
|
+
}
|
|
106
|
+
}, [data.length, onPaginationChange, pagination]);
|
|
107
|
+
|
|
102
108
|
const tableColumns: ColumnDefinition<TData>[] = useMemo(() => {
|
|
103
109
|
let cols: ColumnDefinition<TData>[] = columnDefinitions;
|
|
104
110
|
if (enableSelection) {
|
|
@@ -139,7 +145,7 @@ export function Table<TData extends object>({
|
|
|
139
145
|
manualPagination,
|
|
140
146
|
manualFiltering,
|
|
141
147
|
|
|
142
|
-
globalFilterFn: fuzzyFilter,
|
|
148
|
+
globalFilterFn: enableFuzzySearch ? fuzzyFilter : undefined,
|
|
143
149
|
onGlobalFilterChange,
|
|
144
150
|
|
|
145
151
|
getRowId,
|
|
@@ -154,9 +160,9 @@ export function Table<TData extends object>({
|
|
|
154
160
|
onSortingChange,
|
|
155
161
|
getSortedRowModel: getSortedRowModel(),
|
|
156
162
|
onPaginationChange,
|
|
163
|
+
autoResetPageIndex: false,
|
|
157
164
|
getPaginationRowModel: getPaginationRowModel(),
|
|
158
165
|
getCoreRowModel: getCoreRowModel(),
|
|
159
|
-
|
|
160
166
|
columnResizeMode: 'onEnd',
|
|
161
167
|
});
|
|
162
168
|
|
|
@@ -189,18 +195,37 @@ export function Table<TData extends object>({
|
|
|
189
195
|
}
|
|
190
196
|
}, [loading, rowSelectionProp?.multiRow, table]);
|
|
191
197
|
|
|
192
|
-
|
|
198
|
+
const columnSizeVarsRef = useRef<Record<string, string>>();
|
|
193
199
|
|
|
194
200
|
const columnSizeVars = useMemo(() => {
|
|
201
|
+
const sizeKey = (id: string) => `--table-column-${id}-size`;
|
|
202
|
+
const flexKey = (id: string) => `--table-column-${id}-flex`;
|
|
203
|
+
|
|
204
|
+
const getCurrentlyConfiguredHeaderWidth = (id: string) => {
|
|
205
|
+
const cell = document.querySelector<HTMLDivElement>(`[data-header-id="${id}"]`);
|
|
206
|
+
const resizeHandler = cell?.querySelector<HTMLDivElement>(
|
|
207
|
+
'[data-test-id="table__header-cell-resize-handle-moving-part"]',
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
if (cell && resizeHandler) {
|
|
211
|
+
const { width } = cell.getBoundingClientRect();
|
|
212
|
+
const offset = parseInt(resizeHandler.style.getPropertyValue('--offset'));
|
|
213
|
+
return width + offset;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return 0;
|
|
217
|
+
};
|
|
218
|
+
|
|
195
219
|
const originalColumnDefs = table._getColumnDefs();
|
|
196
220
|
const headers = table.getFlatHeaders();
|
|
197
|
-
const colSizes:
|
|
221
|
+
const colSizes: Record<string, string> = {};
|
|
198
222
|
|
|
199
223
|
for (let i = 0; i < headers.length; i++) {
|
|
200
224
|
const header = headers[i];
|
|
201
225
|
const originalColDef = originalColumnDefs.find(col => getColumnId(header) === col.id);
|
|
202
226
|
const originalColumnDefSize = originalColDef?.size;
|
|
203
227
|
const initSize = originalColumnDefSize ? `${originalColumnDefSize}px` : '100%';
|
|
228
|
+
const prevSize = columnSizeVarsRef.current?.[sizeKey(header.id)];
|
|
204
229
|
|
|
205
230
|
let size = initSize;
|
|
206
231
|
|
|
@@ -209,10 +234,17 @@ export function Table<TData extends object>({
|
|
|
209
234
|
const colDefSize = header.column.columnDef.size;
|
|
210
235
|
|
|
211
236
|
size = currentSize === colDefSize ? initSize : `${currentSize}px`;
|
|
237
|
+
|
|
238
|
+
if (prevSize === '100%' && currentSize !== colDefSize) {
|
|
239
|
+
const realSize = getCurrentlyConfiguredHeaderWidth(header.id);
|
|
240
|
+
table.setColumnSizing(old => ({ ...old, [header.id]: realSize }));
|
|
241
|
+
|
|
242
|
+
size = `${realSize}px`;
|
|
243
|
+
}
|
|
212
244
|
}
|
|
213
245
|
|
|
214
|
-
colSizes[
|
|
215
|
-
colSizes[
|
|
246
|
+
colSizes[sizeKey(header.id)] = size;
|
|
247
|
+
colSizes[flexKey(header.id)] = size === '100%' ? 'unset' : '0';
|
|
216
248
|
}
|
|
217
249
|
|
|
218
250
|
return colSizes;
|
|
@@ -221,6 +253,10 @@ export function Table<TData extends object>({
|
|
|
221
253
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
222
254
|
}, [table.getState().columnSizingInfo.isResizingColumn]);
|
|
223
255
|
|
|
256
|
+
useEffect(() => {
|
|
257
|
+
columnSizeVarsRef.current = columnSizeVars;
|
|
258
|
+
}, [columnSizeVars]);
|
|
259
|
+
|
|
224
260
|
const tableRows = table.getRowModel().rows;
|
|
225
261
|
const loadingTableRows = loadingTable.getRowModel().rows;
|
|
226
262
|
const tablePagination = table.getState().pagination;
|
package/src/components/types.ts
CHANGED
|
@@ -52,6 +52,9 @@ export type TableProps<TData extends object> = WithSupportProps<{
|
|
|
52
52
|
onChange?(value: string): void;
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
+
/** Включить нечеткий поиск */
|
|
56
|
+
enableFuzzySearch?: boolean;
|
|
57
|
+
|
|
55
58
|
/** Максимальное кол-во строк на страницу @default 10 */
|
|
56
59
|
pageSize?: number;
|
|
57
60
|
|
package/src/constants.ts
CHANGED
|
@@ -19,7 +19,7 @@ export const TEST_IDS = {
|
|
|
19
19
|
rowActions: {
|
|
20
20
|
droplistTrigger: 'table__body-row__droplistTrigger',
|
|
21
21
|
droplist: 'table__body-row__actions-droplist',
|
|
22
|
-
option: '
|
|
22
|
+
option: 'list__base-item-option',
|
|
23
23
|
},
|
|
24
24
|
statusIndicator: 'table__status-indicator',
|
|
25
25
|
statusLabel: 'table__status-label',
|
|
@@ -46,6 +46,7 @@ export function HeaderCell<TData>({ header, className }: HeaderCellProps<TData>)
|
|
|
46
46
|
data-no-padding={columnDef.noHeaderCellPadding || undefined}
|
|
47
47
|
data-no-offset={columnDef.noHeaderCellBorderOffset || undefined}
|
|
48
48
|
data-test-id={TEST_IDS.headerCell}
|
|
49
|
+
data-header-id={header.id}
|
|
49
50
|
data-resizing={isResizing || undefined}
|
|
50
51
|
role='columnheader'
|
|
51
52
|
className={cn(styles.tableHeaderCell, className, columnDef.headerClassName)}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Header } from '@tanstack/react-table';
|
|
2
2
|
import cn from 'classnames';
|
|
3
|
-
import { RefObject } from 'react';
|
|
3
|
+
import { MouseEventHandler, RefObject } from 'react';
|
|
4
4
|
|
|
5
5
|
import styles from './styles.module.scss';
|
|
6
6
|
|
|
@@ -37,24 +37,34 @@ function getResizeIndicatorOffset<TData>({ header, cellRef }: ResizeHandleProps<
|
|
|
37
37
|
export function ResizeHandle<TData>({ header, cellRef }: ResizeHandleProps<TData>) {
|
|
38
38
|
const isResizing = header.column.getIsResizing();
|
|
39
39
|
const resizeHandler = header.getResizeHandler();
|
|
40
|
+
const handleMouseDown: MouseEventHandler = event => {
|
|
41
|
+
if (event.detail === 2) {
|
|
42
|
+
header.column.resetSize();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
resizeHandler(event);
|
|
47
|
+
};
|
|
40
48
|
|
|
41
49
|
const offset = isResizing ? getResizeIndicatorOffset({ header, cellRef }) : 0;
|
|
42
50
|
|
|
43
51
|
return (
|
|
44
52
|
<>
|
|
45
|
-
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
|
|
46
53
|
<div
|
|
54
|
+
role='button'
|
|
55
|
+
tabIndex={0}
|
|
47
56
|
className={cn(styles.tableHeaderIcon, styles.tableHeaderResizeHandle)}
|
|
48
57
|
data-resizing={isResizing || undefined}
|
|
49
|
-
onMouseDown={
|
|
58
|
+
onMouseDown={handleMouseDown}
|
|
50
59
|
onTouchStart={resizeHandler}
|
|
51
60
|
/>
|
|
52
61
|
|
|
53
62
|
{isResizing && (
|
|
54
63
|
<div
|
|
64
|
+
data-test-id='table__header-cell-resize-handle-moving-part'
|
|
55
65
|
className={styles.tableHeaderResizeIndicator}
|
|
56
66
|
style={{
|
|
57
|
-
|
|
67
|
+
'--offset': `${offset}px`,
|
|
58
68
|
}}
|
|
59
69
|
/>
|
|
60
70
|
)}
|
|
@@ -1,42 +1,36 @@
|
|
|
1
1
|
import { CellContext, Row } from '@tanstack/react-table';
|
|
2
|
-
import { MouseEvent,
|
|
2
|
+
import { MouseEvent, MouseEventHandler, useCallback, useMemo } from 'react';
|
|
3
3
|
|
|
4
4
|
import { ButtonFunction } from '@snack-uikit/button';
|
|
5
5
|
import { MoreSVG } from '@snack-uikit/icons';
|
|
6
|
-
import {
|
|
7
|
-
import { Tag } from '@snack-uikit/tag';
|
|
6
|
+
import { Droplist, DroplistProps, isBaseItemProps, ItemProps } from '@snack-uikit/list';
|
|
8
7
|
|
|
9
8
|
import { COLUMN_PIN_POSITION, TEST_IDS } from '../../../constants';
|
|
10
9
|
import { ColumnDefinition } from '../../../types';
|
|
11
10
|
import { useRowContext } from '../../contexts';
|
|
12
11
|
import styles from './styles.module.scss';
|
|
13
12
|
|
|
14
|
-
export type RowActionInfo<TData> = {
|
|
15
|
-
rowId: string;
|
|
16
|
-
data: TData;
|
|
17
|
-
itemId?: string;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export type RowActionProps<TData> = Pick<BaseItemProps, 'content' | 'disabled' | 'data-test-id'> & {
|
|
21
|
-
icon?: ReactElement;
|
|
22
|
-
tagLabel?: string;
|
|
23
|
-
id?: string;
|
|
24
|
-
hidden?: boolean;
|
|
25
|
-
onClick(row: RowActionInfo<TData>, e: MouseEvent<HTMLElement>): void;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
13
|
type RowActionsCellProps<TData> = {
|
|
29
|
-
actions:
|
|
14
|
+
actions: DroplistProps['items'];
|
|
30
15
|
row: Row<TData>;
|
|
31
16
|
};
|
|
32
17
|
|
|
33
18
|
function RowActionsCell<TData>({ row, actions }: RowActionsCellProps<TData>) {
|
|
34
|
-
const {
|
|
35
|
-
const triggerRef = useRef(null);
|
|
19
|
+
const { dropListOpened, setDropListOpen } = useRowContext();
|
|
36
20
|
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
21
|
+
const patchItem = useCallback((item: ItemProps, cb: MouseEventHandler): ItemProps => {
|
|
22
|
+
if (isBaseItemProps(item)) {
|
|
23
|
+
return {
|
|
24
|
+
...item,
|
|
25
|
+
onClick(e) {
|
|
26
|
+
item.onClick?.(e);
|
|
27
|
+
cb(e);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return { ...item, items: item.items.map(i => patchItem(i, cb)) };
|
|
33
|
+
}, []);
|
|
40
34
|
|
|
41
35
|
const disabled = !row.getCanSelect();
|
|
42
36
|
|
|
@@ -44,49 +38,32 @@ function RowActionsCell<TData>({ row, actions }: RowActionsCellProps<TData>) {
|
|
|
44
38
|
e.stopPropagation();
|
|
45
39
|
};
|
|
46
40
|
|
|
47
|
-
const
|
|
41
|
+
const patchedItems = useMemo(
|
|
42
|
+
() => actions.map(item => patchItem(item, () => setDropListOpen(false))),
|
|
43
|
+
[actions, patchItem, setDropListOpen],
|
|
44
|
+
);
|
|
48
45
|
|
|
49
46
|
return (
|
|
50
47
|
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
51
|
-
<div onClick={stopPropagationClick} className={styles.rowActionsCellWrap} data-open={
|
|
52
|
-
{!disabled && Boolean(
|
|
48
|
+
<div onClick={stopPropagationClick} className={styles.rowActionsCellWrap} data-open={dropListOpened || undefined}>
|
|
49
|
+
{!disabled && Boolean(actions.length) && (
|
|
53
50
|
<Droplist
|
|
54
51
|
trigger='clickAndFocusVisible'
|
|
55
|
-
open={
|
|
56
|
-
onOpenChange={
|
|
52
|
+
open={dropListOpened}
|
|
53
|
+
onOpenChange={setDropListOpen}
|
|
57
54
|
placement='bottom-end'
|
|
58
55
|
size='m'
|
|
59
56
|
data-test-id={TEST_IDS.rowActions.droplist}
|
|
60
|
-
|
|
61
|
-
items={actions
|
|
62
|
-
.filter(item => !item?.hidden)
|
|
63
|
-
.map(item => ({
|
|
64
|
-
id: item.id,
|
|
65
|
-
onClick: e => {
|
|
66
|
-
handleItemClick(item)(e);
|
|
67
|
-
setDroplistOpen(false);
|
|
68
|
-
},
|
|
69
|
-
disabled: item.disabled,
|
|
70
|
-
content: item.content,
|
|
71
|
-
beforeContent: item.icon,
|
|
72
|
-
afterContent: item.tagLabel ? <Tag label={item.tagLabel} /> : undefined,
|
|
73
|
-
'data-test-id': item['data-test-id'] || TEST_IDS.rowActions.option,
|
|
74
|
-
}))}
|
|
57
|
+
items={patchedItems}
|
|
75
58
|
>
|
|
76
|
-
<
|
|
77
|
-
<ButtonFunction
|
|
78
|
-
icon={<MoreSVG size={24} />}
|
|
79
|
-
data-test-id={TEST_IDS.rowActions.droplistTrigger}
|
|
80
|
-
ref={triggerRef}
|
|
81
|
-
/>
|
|
82
|
-
</span>
|
|
59
|
+
<ButtonFunction icon={<MoreSVG size={24} />} data-test-id={TEST_IDS.rowActions.droplistTrigger} />
|
|
83
60
|
</Droplist>
|
|
84
61
|
)}
|
|
85
62
|
</div>
|
|
86
63
|
);
|
|
87
64
|
}
|
|
88
65
|
|
|
89
|
-
export type ActionsGenerator<TData> = (cell: CellContext<TData, unknown>) =>
|
|
66
|
+
export type ActionsGenerator<TData> = (cell: CellContext<TData, unknown>) => DroplistProps['items'];
|
|
90
67
|
|
|
91
68
|
export type RowActionsColumnDefProps<TData> = {
|
|
92
69
|
/** Действия для строки */
|
|
@@ -24,24 +24,15 @@
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
.rowActionsCellWrap {
|
|
27
|
+
--offset: 0px;
|
|
28
|
+
cursor: pointer;
|
|
27
29
|
box-sizing: border-box;
|
|
28
30
|
width: 100%;
|
|
29
31
|
height: 100%;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
.rowActionsCellTrigger {
|
|
33
|
-
--offset: 0px;
|
|
34
32
|
|
|
35
33
|
@include composite-var($table-cells-action);
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
cursor: pointer;
|
|
39
34
|
|
|
40
35
|
display: flex;
|
|
41
36
|
align-items: center;
|
|
42
37
|
justify-content: center;
|
|
43
|
-
|
|
44
|
-
box-sizing: border-box;
|
|
45
|
-
width: 100%;
|
|
46
|
-
height: 100%;
|
|
47
38
|
}
|
|
@@ -26,7 +26,7 @@ type BodyRowProps<TData> = {
|
|
|
26
26
|
export function BodyRow<TData>({ row, onRowClick }: BodyRowProps<TData>) {
|
|
27
27
|
const { pinnedLeft, pinnedRight, unpinned } = useRowCells(row);
|
|
28
28
|
|
|
29
|
-
const [
|
|
29
|
+
const [dropListOpened, setDropListOpen] = useState(false);
|
|
30
30
|
|
|
31
31
|
const disabled = !row.getCanSelect();
|
|
32
32
|
|
|
@@ -42,13 +42,13 @@ export function BodyRow<TData>({ row, onRowClick }: BodyRowProps<TData>) {
|
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
return (
|
|
45
|
-
<RowContext.Provider value={{
|
|
45
|
+
<RowContext.Provider value={{ dropListOpened, setDropListOpen }}>
|
|
46
46
|
<Row
|
|
47
47
|
onClick={handleRowClick}
|
|
48
48
|
data-clickable={Boolean(onRowClick) || undefined}
|
|
49
49
|
data-disabled={disabled || undefined}
|
|
50
50
|
data-selected={row.getIsSelected() || undefined}
|
|
51
|
-
data-actions-opened={
|
|
51
|
+
data-actions-opened={dropListOpened || undefined}
|
|
52
52
|
data-test-id={TEST_IDS.bodyRow}
|
|
53
53
|
data-row-id={row.id}
|
|
54
54
|
className={styles.bodyRow}
|
|
@@ -2,13 +2,13 @@ import { Table } from '@tanstack/react-table';
|
|
|
2
2
|
import { createContext, Dispatch, SetStateAction, useContext } from 'react';
|
|
3
3
|
|
|
4
4
|
type RowContext = {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
dropListOpened: boolean;
|
|
6
|
+
setDropListOpen: Dispatch<SetStateAction<boolean>>;
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
export const RowContext = createContext<RowContext>({
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
dropListOpened: false,
|
|
11
|
+
setDropListOpen() {},
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
export const useRowContext = () => useContext(RowContext);
|
package/src/types.ts
CHANGED
|
@@ -64,8 +64,6 @@ type PinnedColumnDefinition<TData> = BaseColumnDefinition<TData> & {
|
|
|
64
64
|
export type ColumnDefinition<TData> = NormalColumnDefinition<TData> | PinnedColumnDefinition<TData>;
|
|
65
65
|
|
|
66
66
|
export type {
|
|
67
|
-
RowActionInfo,
|
|
68
|
-
RowActionProps,
|
|
69
67
|
RowActionsColumnDefProps,
|
|
70
68
|
StatusColumnDefinitionProps,
|
|
71
69
|
RowInfo,
|