@snack-uikit/table 0.16.8 → 0.17.1
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 +38 -0
- package/README.md +2 -0
- package/dist/components/Table/Table.d.ts +1 -1
- package/dist/components/Table/Table.js +35 -12
- package/dist/components/Table/hooks/index.d.ts +1 -0
- package/dist/components/Table/hooks/index.js +1 -0
- package/dist/components/Table/utils.d.ts +5 -0
- package/dist/components/Table/utils.js +16 -0
- package/dist/components/types.d.ts +2 -0
- package/dist/constants.js +1 -1
- package/dist/helperComponents/Cells/CopyCell/styles.module.css +3 -0
- package/dist/helperComponents/Cells/HeaderCell/HeaderCell.d.ts +3 -1
- package/dist/helperComponents/Cells/HeaderCell/HeaderCell.js +2 -2
- package/dist/helperComponents/Cells/HeaderCell/ResizeHandle.js +10 -2
- package/dist/helperComponents/Cells/HeaderCell/helpers.d.ts +2 -0
- package/dist/helperComponents/Cells/HeaderCell/helpers.js +3 -0
- package/dist/helperComponents/Cells/HeaderCell/styles.module.css +34 -20
- 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/HeaderRow.js +1 -1
- 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 +4 -2
- package/package.json +5 -6
- package/src/components/Table/Table.tsx +40 -14
- package/src/components/Table/hooks/index.ts +1 -0
- package/src/components/Table/utils.ts +21 -0
- package/src/components/types.ts +3 -0
- package/src/constants.ts +1 -1
- package/src/helperComponents/Cells/CopyCell/styles.module.scss +3 -0
- package/src/helperComponents/Cells/HeaderCell/HeaderCell.tsx +6 -2
- package/src/helperComponents/Cells/HeaderCell/ResizeHandle.tsx +17 -4
- package/src/helperComponents/Cells/HeaderCell/helpers.tsx +5 -0
- package/src/helperComponents/Cells/HeaderCell/styles.module.scss +46 -26
- 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/HeaderRow.tsx +3 -1
- package/src/helperComponents/Rows/styles.module.scss +1 -0
- package/src/helperComponents/contexts.ts +4 -4
- package/src/types.ts +3 -2
|
@@ -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';
|
|
@@ -38,9 +38,9 @@ import {
|
|
|
38
38
|
import { ColumnDefinition } from '../../types';
|
|
39
39
|
import { fuzzyFilter } from '../../utils';
|
|
40
40
|
import { TableProps } from '../types';
|
|
41
|
-
import { useLoadingTable } from './hooks';
|
|
42
|
-
import { useStateControl } from './hooks/useStateControl';
|
|
41
|
+
import { useLoadingTable, useStateControl } from './hooks';
|
|
43
42
|
import styles from './styles.module.scss';
|
|
43
|
+
import { getColumnStyleVars, getCurrentlyConfiguredHeaderWidth } from './utils';
|
|
44
44
|
|
|
45
45
|
/** Компонент таблицы */
|
|
46
46
|
export function Table<TData extends object>({
|
|
@@ -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) {
|
|
@@ -106,6 +112,7 @@ export function Table<TData extends object>({
|
|
|
106
112
|
}
|
|
107
113
|
return cols;
|
|
108
114
|
}, [columnDefinitions, enableSelection]);
|
|
115
|
+
|
|
109
116
|
const columnPinning = useMemo(() => {
|
|
110
117
|
const pinningState: Required<ColumnPinningState> = { left: [], right: [] };
|
|
111
118
|
for (const col of tableColumns) {
|
|
@@ -139,7 +146,7 @@ export function Table<TData extends object>({
|
|
|
139
146
|
manualPagination,
|
|
140
147
|
manualFiltering,
|
|
141
148
|
|
|
142
|
-
globalFilterFn: fuzzyFilter,
|
|
149
|
+
globalFilterFn: enableFuzzySearch ? fuzzyFilter : undefined,
|
|
143
150
|
onGlobalFilterChange,
|
|
144
151
|
|
|
145
152
|
getRowId,
|
|
@@ -154,9 +161,9 @@ export function Table<TData extends object>({
|
|
|
154
161
|
onSortingChange,
|
|
155
162
|
getSortedRowModel: getSortedRowModel(),
|
|
156
163
|
onPaginationChange,
|
|
164
|
+
autoResetPageIndex: false,
|
|
157
165
|
getPaginationRowModel: getPaginationRowModel(),
|
|
158
166
|
getCoreRowModel: getCoreRowModel(),
|
|
159
|
-
|
|
160
167
|
columnResizeMode: 'onEnd',
|
|
161
168
|
});
|
|
162
169
|
|
|
@@ -189,18 +196,20 @@ export function Table<TData extends object>({
|
|
|
189
196
|
}
|
|
190
197
|
}, [loading, rowSelectionProp?.multiRow, table]);
|
|
191
198
|
|
|
192
|
-
|
|
199
|
+
const columnSizeVarsRef = useRef<Record<string, string>>();
|
|
200
|
+
const headers = table.getFlatHeaders();
|
|
193
201
|
|
|
194
202
|
const columnSizeVars = useMemo(() => {
|
|
195
203
|
const originalColumnDefs = table._getColumnDefs();
|
|
196
|
-
const
|
|
197
|
-
const colSizes: { [key: string]: string } = {};
|
|
204
|
+
const colSizes: Record<string, string> = {};
|
|
198
205
|
|
|
199
206
|
for (let i = 0; i < headers.length; i++) {
|
|
200
207
|
const header = headers[i];
|
|
208
|
+
const { sizeKey, flexKey } = getColumnStyleVars(header.id);
|
|
201
209
|
const originalColDef = originalColumnDefs.find(col => getColumnId(header) === col.id);
|
|
202
210
|
const originalColumnDefSize = originalColDef?.size;
|
|
203
211
|
const initSize = originalColumnDefSize ? `${originalColumnDefSize}px` : '100%';
|
|
212
|
+
const prevSize = columnSizeVarsRef.current?.[sizeKey];
|
|
204
213
|
|
|
205
214
|
let size = initSize;
|
|
206
215
|
|
|
@@ -209,17 +218,34 @@ export function Table<TData extends object>({
|
|
|
209
218
|
const colDefSize = header.column.columnDef.size;
|
|
210
219
|
|
|
211
220
|
size = currentSize === colDefSize ? initSize : `${currentSize}px`;
|
|
221
|
+
|
|
222
|
+
if (prevSize === '100%' && currentSize !== colDefSize) {
|
|
223
|
+
const realSize = getCurrentlyConfiguredHeaderWidth(header.id);
|
|
224
|
+
table.setColumnSizing(old => ({ ...old, [header.id]: realSize }));
|
|
225
|
+
|
|
226
|
+
size = `${realSize}px`;
|
|
227
|
+
}
|
|
212
228
|
}
|
|
213
229
|
|
|
214
|
-
colSizes[
|
|
215
|
-
colSizes[
|
|
230
|
+
colSizes[sizeKey] = size;
|
|
231
|
+
colSizes[flexKey] = size === '100%' ? 'unset' : '0';
|
|
216
232
|
}
|
|
217
233
|
|
|
218
234
|
return colSizes;
|
|
219
|
-
/*
|
|
220
|
-
|
|
235
|
+
/*
|
|
236
|
+
effect must be called only on columnSizingInfo.isResizingColumn changes
|
|
237
|
+
to reduce unnecessary recalculations
|
|
238
|
+
|
|
239
|
+
headers ids can also change, so they also should present here
|
|
240
|
+
|
|
241
|
+
table.getTotalSize() will trigger re-render after double-click size reset
|
|
242
|
+
*/
|
|
221
243
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
222
|
-
}, [table.getState().columnSizingInfo.isResizingColumn]);
|
|
244
|
+
}, [table.getState().columnSizingInfo.isResizingColumn, headers, table.getTotalSize()]);
|
|
245
|
+
|
|
246
|
+
useEffect(() => {
|
|
247
|
+
columnSizeVarsRef.current = columnSizeVars;
|
|
248
|
+
}, [columnSizeVars]);
|
|
223
249
|
|
|
224
250
|
const tableRows = table.getRowModel().rows;
|
|
225
251
|
const loadingTableRows = loadingTable.getRowModel().rows;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function getCurrentlyConfiguredHeaderWidth(id: string) {
|
|
2
|
+
const cell = document.querySelector<HTMLDivElement>(`[data-header-id="${id}"]`);
|
|
3
|
+
const resizeHandler = cell?.querySelector<HTMLDivElement>(
|
|
4
|
+
'[data-test-id="table__header-cell-resize-handle-moving-part"]',
|
|
5
|
+
);
|
|
6
|
+
|
|
7
|
+
if (cell && resizeHandler) {
|
|
8
|
+
const { width } = cell.getBoundingClientRect();
|
|
9
|
+
const offset = parseInt(resizeHandler.style.getPropertyValue('--offset'));
|
|
10
|
+
return width + offset;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function getColumnStyleVars(id: string) {
|
|
17
|
+
return {
|
|
18
|
+
sizeKey: `--table-column-${id}-size`,
|
|
19
|
+
flexKey: `--table-column-${id}-flex`,
|
|
20
|
+
};
|
|
21
|
+
}
|
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',
|
|
@@ -5,7 +5,7 @@ import { MouseEvent, useRef } from 'react';
|
|
|
5
5
|
import { TruncateString } from '@snack-uikit/truncate-string';
|
|
6
6
|
|
|
7
7
|
import { TEST_IDS } from '../../../constants';
|
|
8
|
-
import { ColumnDefinition } from '../../../types';
|
|
8
|
+
import { ColumnDefinition, ColumnPinPosition } from '../../../types';
|
|
9
9
|
import { useCellSizes } from '../../hooks';
|
|
10
10
|
import { Cell, CellProps } from '../Cell';
|
|
11
11
|
import { getSortingIcon } from './helpers';
|
|
@@ -14,9 +14,10 @@ import styles from './styles.module.scss';
|
|
|
14
14
|
|
|
15
15
|
type HeaderCellProps<TData> = Omit<CellProps, 'align' | 'children' | 'onClick' | 'style'> & {
|
|
16
16
|
header: Header<TData, unknown>;
|
|
17
|
+
pinPosition?: ColumnPinPosition;
|
|
17
18
|
};
|
|
18
19
|
|
|
19
|
-
export function HeaderCell<TData>({ header, className }: HeaderCellProps<TData>) {
|
|
20
|
+
export function HeaderCell<TData>({ header, pinPosition, className }: HeaderCellProps<TData>) {
|
|
20
21
|
const cellRef = useRef<HTMLDivElement>(null);
|
|
21
22
|
const isSortable = header.column.getCanSort();
|
|
22
23
|
const isResizable = header.column.getCanResize();
|
|
@@ -46,7 +47,10 @@ export function HeaderCell<TData>({ header, className }: HeaderCellProps<TData>)
|
|
|
46
47
|
data-no-padding={columnDef.noHeaderCellPadding || undefined}
|
|
47
48
|
data-no-offset={columnDef.noHeaderCellBorderOffset || undefined}
|
|
48
49
|
data-test-id={TEST_IDS.headerCell}
|
|
50
|
+
data-align={columnDef.headerAlign || undefined}
|
|
51
|
+
data-header-id={header.id}
|
|
49
52
|
data-resizing={isResizing || undefined}
|
|
53
|
+
data-pin-position={pinPosition || undefined}
|
|
50
54
|
role='columnheader'
|
|
51
55
|
className={cn(styles.tableHeaderCell, className, columnDef.headerClassName)}
|
|
52
56
|
ref={cellRef}
|
|
@@ -1,7 +1,8 @@
|
|
|
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
|
+
import { stopEventPropagation } from './helpers';
|
|
5
6
|
import styles from './styles.module.scss';
|
|
6
7
|
|
|
7
8
|
type ResizeHandleProps<TData> = {
|
|
@@ -38,23 +39,35 @@ export function ResizeHandle<TData>({ header, cellRef }: ResizeHandleProps<TData
|
|
|
38
39
|
const isResizing = header.column.getIsResizing();
|
|
39
40
|
const resizeHandler = header.getResizeHandler();
|
|
40
41
|
|
|
42
|
+
const handleMouseDown: MouseEventHandler = event => {
|
|
43
|
+
if (event.detail === 2) {
|
|
44
|
+
header.column.resetSize();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
resizeHandler(event);
|
|
49
|
+
};
|
|
50
|
+
|
|
41
51
|
const offset = isResizing ? getResizeIndicatorOffset({ header, cellRef }) : 0;
|
|
42
52
|
|
|
43
53
|
return (
|
|
44
54
|
<>
|
|
45
|
-
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
|
|
46
55
|
<div
|
|
56
|
+
role='button'
|
|
57
|
+
tabIndex={0}
|
|
47
58
|
className={cn(styles.tableHeaderIcon, styles.tableHeaderResizeHandle)}
|
|
48
59
|
data-resizing={isResizing || undefined}
|
|
49
|
-
onMouseDown={
|
|
60
|
+
onMouseDown={handleMouseDown}
|
|
50
61
|
onTouchStart={resizeHandler}
|
|
62
|
+
onMouseUp={stopEventPropagation}
|
|
51
63
|
/>
|
|
52
64
|
|
|
53
65
|
{isResizing && (
|
|
54
66
|
<div
|
|
67
|
+
data-test-id='table__header-cell-resize-handle-moving-part'
|
|
55
68
|
className={styles.tableHeaderResizeIndicator}
|
|
56
69
|
style={{
|
|
57
|
-
|
|
70
|
+
'--offset': `${offset}px`,
|
|
58
71
|
}}
|
|
59
72
|
/>
|
|
60
73
|
)}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SortDirection } from '@tanstack/react-table';
|
|
2
|
+
import { MouseEventHandler } from 'react';
|
|
2
3
|
|
|
3
4
|
import { ArrowDownSVG, ArrowUpSVG } from '@snack-uikit/icons';
|
|
4
5
|
|
|
@@ -12,3 +13,7 @@ export function getSortingIcon(sort?: SortDirection | false) {
|
|
|
12
13
|
return null;
|
|
13
14
|
}
|
|
14
15
|
}
|
|
16
|
+
|
|
17
|
+
export const stopEventPropagation: MouseEventHandler = e => {
|
|
18
|
+
e.stopPropagation();
|
|
19
|
+
};
|
|
@@ -34,6 +34,33 @@
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
.tableHeaderResizeIndicator {
|
|
38
|
+
cursor: col-resize;
|
|
39
|
+
|
|
40
|
+
position: absolute;
|
|
41
|
+
z-index: 2;
|
|
42
|
+
top: 0;
|
|
43
|
+
right: 0;
|
|
44
|
+
transform: translateX(var(--offset));
|
|
45
|
+
|
|
46
|
+
width: 1px;
|
|
47
|
+
height: 100%;
|
|
48
|
+
|
|
49
|
+
background-color: $sys-neutral-decor-activated;
|
|
50
|
+
|
|
51
|
+
&::after {
|
|
52
|
+
content: '';
|
|
53
|
+
|
|
54
|
+
position: absolute;
|
|
55
|
+
top: 0;
|
|
56
|
+
left: 0;
|
|
57
|
+
transform: translateX(-50%);
|
|
58
|
+
|
|
59
|
+
width: calc(100% + $dimension-4m);
|
|
60
|
+
height: 100%;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
37
64
|
.tableHeaderCell {
|
|
38
65
|
@include composite-var($table-head-column);
|
|
39
66
|
|
|
@@ -92,6 +119,25 @@
|
|
|
92
119
|
&[data-resizing] {
|
|
93
120
|
user-select: none;
|
|
94
121
|
}
|
|
122
|
+
|
|
123
|
+
&[data-align='right'] {
|
|
124
|
+
justify-content: flex-end;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
&[data-pin-position='right'] {
|
|
128
|
+
&:last-child {
|
|
129
|
+
overflow: hidden;
|
|
130
|
+
|
|
131
|
+
.tableHeaderResizeHandle {
|
|
132
|
+
right: 0;
|
|
133
|
+
transform: none;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.tableHeaderResizeIndicator {
|
|
137
|
+
right: calc($dimension-1m / 2);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
95
141
|
}
|
|
96
142
|
|
|
97
143
|
.tableHeaderCellMain {
|
|
@@ -125,29 +171,3 @@
|
|
|
125
171
|
height: simple-var($icon-xs) !important; /* stylelint-disable-line declaration-no-important */
|
|
126
172
|
}
|
|
127
173
|
}
|
|
128
|
-
|
|
129
|
-
.tableHeaderResizeIndicator {
|
|
130
|
-
cursor: col-resize;
|
|
131
|
-
|
|
132
|
-
position: absolute;
|
|
133
|
-
z-index: 2;
|
|
134
|
-
top: 0;
|
|
135
|
-
right: 0;
|
|
136
|
-
|
|
137
|
-
width: 1px;
|
|
138
|
-
height: 100%;
|
|
139
|
-
|
|
140
|
-
background-color: $sys-neutral-decor-activated;
|
|
141
|
-
|
|
142
|
-
&::after {
|
|
143
|
-
content: '';
|
|
144
|
-
|
|
145
|
-
position: absolute;
|
|
146
|
-
top: 0;
|
|
147
|
-
left: 0;
|
|
148
|
-
transform: translateX(-50%);
|
|
149
|
-
|
|
150
|
-
width: calc(100% + $dimension-4m);
|
|
151
|
-
height: 100%;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
@@ -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}
|
|
@@ -26,7 +26,9 @@ export function HeaderRow() {
|
|
|
26
26
|
<PinnedCells position={COLUMN_PIN_POSITION.Right}>
|
|
27
27
|
{rightPinned.map(headerGroup =>
|
|
28
28
|
headerGroup.headers.map(header =>
|
|
29
|
-
header.isPlaceholder ? null :
|
|
29
|
+
header.isPlaceholder ? null : (
|
|
30
|
+
<HeaderCell key={header.id} header={header} pinPosition={COLUMN_PIN_POSITION.Right} />
|
|
31
|
+
),
|
|
30
32
|
),
|
|
31
33
|
)}
|
|
32
34
|
</PinnedCells>
|
|
@@ -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
|
@@ -33,6 +33,8 @@ type BaseColumnDefinition<TData> = Except<
|
|
|
33
33
|
> & {
|
|
34
34
|
/** Заголовок колонки */
|
|
35
35
|
header?: string | ((ctx: HeaderContext<TData, unknown>) => string);
|
|
36
|
+
/** Позиционирование заголовка колонки */
|
|
37
|
+
headerAlign?: ColumnAlign;
|
|
36
38
|
/** Позиционирование контента ячейки в теле таблицы */
|
|
37
39
|
align?: ColumnAlign;
|
|
38
40
|
/** Отключить паддинг у ячейки в теле таблицы */
|
|
@@ -64,8 +66,6 @@ type PinnedColumnDefinition<TData> = BaseColumnDefinition<TData> & {
|
|
|
64
66
|
export type ColumnDefinition<TData> = NormalColumnDefinition<TData> | PinnedColumnDefinition<TData>;
|
|
65
67
|
|
|
66
68
|
export type {
|
|
67
|
-
RowActionInfo,
|
|
68
|
-
RowActionProps,
|
|
69
69
|
RowActionsColumnDefProps,
|
|
70
70
|
StatusColumnDefinitionProps,
|
|
71
71
|
RowInfo,
|
|
@@ -76,6 +76,7 @@ export type {
|
|
|
76
76
|
} from './helperComponents';
|
|
77
77
|
|
|
78
78
|
export type {
|
|
79
|
+
ColumnPinPosition,
|
|
79
80
|
PaginationState,
|
|
80
81
|
SortingState,
|
|
81
82
|
RowSelectionState,
|