@snack-uikit/table 0.33.3 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +5 -3
- package/dist/cjs/components/Table/Table.d.ts +1 -1
- package/dist/cjs/components/Table/Table.js +107 -48
- package/dist/cjs/components/Table/hooks/index.d.ts +1 -0
- package/dist/cjs/components/Table/hooks/index.js +2 -1
- package/dist/cjs/components/Table/hooks/useColumnOrderByDrag.d.ts +8 -0
- package/dist/cjs/components/Table/hooks/useColumnOrderByDrag.js +49 -0
- package/dist/cjs/components/Table/utils.d.ts +13 -0
- package/dist/cjs/components/Table/utils.js +71 -0
- package/dist/cjs/components/types.d.ts +12 -3
- package/dist/cjs/constants.d.ts +1 -0
- package/dist/cjs/constants.js +3 -2
- package/dist/cjs/helperComponents/Cells/BodyCell/BodyCell.d.ts +2 -1
- package/dist/cjs/helperComponents/Cells/BodyCell/BodyCell.js +13 -3
- package/dist/cjs/helperComponents/Cells/HeaderCell/HeaderCell.d.ts +2 -1
- package/dist/cjs/helperComponents/Cells/HeaderCell/HeaderCell.js +41 -17
- package/dist/cjs/helperComponents/Cells/HeaderCell/styles.module.css +10 -0
- package/dist/cjs/helperComponents/ColumnsSettings/ColumnsSettings.d.ts +8 -0
- package/dist/cjs/helperComponents/ColumnsSettings/ColumnsSettings.js +38 -0
- package/dist/cjs/helperComponents/ColumnsSettings/index.d.ts +1 -0
- package/dist/cjs/helperComponents/ColumnsSettings/index.js +25 -0
- package/dist/cjs/helperComponents/ColumnsSettings/styles.module.css +3 -0
- package/dist/cjs/helperComponents/Rows/BodyRow.d.ts +4 -1
- package/dist/cjs/helperComponents/Rows/BodyRow.js +20 -11
- package/dist/cjs/helperComponents/Rows/HeaderRow.d.ts +7 -1
- package/dist/cjs/helperComponents/Rows/HeaderRow.js +13 -5
- package/dist/cjs/helperComponents/hooks.d.ts +9 -9
- package/dist/cjs/helperComponents/hooks.js +39 -11
- package/dist/cjs/helperComponents/index.d.ts +1 -0
- package/dist/cjs/helperComponents/index.js +2 -1
- package/dist/cjs/types.d.ts +11 -3
- package/dist/esm/components/Table/Table.d.ts +1 -1
- package/dist/esm/components/Table/Table.js +40 -12
- package/dist/esm/components/Table/hooks/index.d.ts +1 -0
- package/dist/esm/components/Table/hooks/index.js +1 -0
- package/dist/esm/components/Table/hooks/useColumnOrderByDrag.d.ts +8 -0
- package/dist/esm/components/Table/hooks/useColumnOrderByDrag.js +39 -0
- package/dist/esm/components/Table/utils.d.ts +13 -0
- package/dist/esm/components/Table/utils.js +70 -0
- package/dist/esm/components/types.d.ts +12 -3
- package/dist/esm/constants.d.ts +1 -0
- package/dist/esm/constants.js +1 -0
- package/dist/esm/helperComponents/Cells/BodyCell/BodyCell.d.ts +2 -1
- package/dist/esm/helperComponents/Cells/BodyCell/BodyCell.js +7 -3
- package/dist/esm/helperComponents/Cells/HeaderCell/HeaderCell.d.ts +2 -1
- package/dist/esm/helperComponents/Cells/HeaderCell/HeaderCell.js +14 -4
- package/dist/esm/helperComponents/Cells/HeaderCell/styles.module.css +10 -0
- package/dist/esm/helperComponents/ColumnsSettings/ColumnsSettings.d.ts +8 -0
- package/dist/esm/helperComponents/ColumnsSettings/ColumnsSettings.js +12 -0
- package/dist/esm/helperComponents/ColumnsSettings/index.d.ts +1 -0
- package/dist/esm/helperComponents/ColumnsSettings/index.js +1 -0
- package/dist/esm/helperComponents/ColumnsSettings/styles.module.css +3 -0
- package/dist/esm/helperComponents/Rows/BodyRow.d.ts +4 -1
- package/dist/esm/helperComponents/Rows/BodyRow.js +4 -3
- package/dist/esm/helperComponents/Rows/HeaderRow.d.ts +7 -1
- package/dist/esm/helperComponents/Rows/HeaderRow.js +3 -2
- package/dist/esm/helperComponents/hooks.d.ts +9 -9
- package/dist/esm/helperComponents/hooks.js +32 -11
- package/dist/esm/helperComponents/index.d.ts +1 -0
- package/dist/esm/helperComponents/index.js +1 -0
- package/dist/esm/types.d.ts +11 -3
- package/package.json +9 -5
- package/src/components/Table/Table.tsx +147 -61
- package/src/components/Table/hooks/index.ts +1 -0
- package/src/components/Table/hooks/useColumnOrderByDrag.ts +67 -0
- package/src/components/Table/utils.ts +118 -0
- package/src/components/types.ts +13 -3
- package/src/constants.tsx +1 -0
- package/src/helperComponents/Cells/BodyCell/BodyCell.tsx +9 -2
- package/src/helperComponents/Cells/HeaderCell/HeaderCell.tsx +50 -23
- package/src/helperComponents/Cells/HeaderCell/styles.module.scss +15 -0
- package/src/helperComponents/ColumnsSettings/ColumnsSettings.tsx +28 -0
- package/src/helperComponents/ColumnsSettings/index.ts +1 -0
- package/src/helperComponents/ColumnsSettings/styles.module.scss +5 -0
- package/src/helperComponents/Rows/BodyRow.tsx +30 -8
- package/src/helperComponents/Rows/HeaderRow.tsx +21 -4
- package/src/helperComponents/hooks.ts +41 -11
- package/src/helperComponents/index.ts +1 -0
- package/src/types.ts +21 -3
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import { BaseItemProps, GroupSelectItemProps } from '@snack-uikit/list';
|
|
2
|
+
import { useLocale } from '@snack-uikit/locale';
|
|
1
3
|
import { isBrowser } from '@snack-uikit/utils';
|
|
2
4
|
|
|
5
|
+
import { ColumnDefinition, FilterableColumnDefinition } from '../../types';
|
|
6
|
+
|
|
3
7
|
export function getCurrentlyConfiguredHeaderWidth(id: string): number {
|
|
4
8
|
if (isBrowser()) {
|
|
5
9
|
const cell = document.querySelector<HTMLDivElement>(`[data-header-id="${id}"]`);
|
|
@@ -63,3 +67,117 @@ export function saveStateToLocalStorage({ id, columnId, size }: SaveStateToLocal
|
|
|
63
67
|
|
|
64
68
|
localStorage.setItem(id, JSON.stringify({ ...(savedStateFromStorage || {}), resizeState: newResizeState }));
|
|
65
69
|
}
|
|
70
|
+
|
|
71
|
+
export function isFilterableColumn<TData extends object>(
|
|
72
|
+
colDef: ColumnDefinition<TData>,
|
|
73
|
+
): colDef is FilterableColumnDefinition<TData> {
|
|
74
|
+
return 'id' in colDef && 'headerConfigLabel' in colDef;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function prepareColumnsSettingsMap<TData extends object>(
|
|
78
|
+
columnDefinitions: ColumnDefinition<TData>[],
|
|
79
|
+
): string[] {
|
|
80
|
+
return columnDefinitions.filter(isFilterableColumn).map(colDef => colDef.id);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const sortColumnDefinitions = (columnOrder: string[]) =>
|
|
84
|
+
function sortColDefs<TData extends object>(
|
|
85
|
+
colDefA: FilterableColumnDefinition<TData>,
|
|
86
|
+
colDefB: FilterableColumnDefinition<TData>,
|
|
87
|
+
) {
|
|
88
|
+
const indexItemA = columnOrder.findIndex(columnIndex => columnIndex === colDefA.id);
|
|
89
|
+
const indexItemB = columnOrder.findIndex(columnIndex => columnIndex === colDefB.id);
|
|
90
|
+
|
|
91
|
+
return indexItemA - indexItemB;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
function createColumnsSettingsOption<TData extends object>(
|
|
95
|
+
columnDefinition: FilterableColumnDefinition<TData>,
|
|
96
|
+
): BaseItemProps {
|
|
97
|
+
return {
|
|
98
|
+
id: columnDefinition.id,
|
|
99
|
+
content: {
|
|
100
|
+
option: columnDefinition.headerConfigLabel as string,
|
|
101
|
+
},
|
|
102
|
+
switch: true,
|
|
103
|
+
showSwitchIcon: true,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
type ColumnGroups = {
|
|
108
|
+
pinTop: BaseItemProps[];
|
|
109
|
+
unpinned: BaseItemProps[];
|
|
110
|
+
pinBottom: BaseItemProps[];
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
type PrepareColumnsSettingsProps<TData extends object> = {
|
|
114
|
+
columnDefinitions: ColumnDefinition<TData>[];
|
|
115
|
+
columnOrder: string[];
|
|
116
|
+
areAllColumnsEnabled: boolean;
|
|
117
|
+
columnsSettingsHeader?: string;
|
|
118
|
+
t: ReturnType<typeof useLocale<'Table'>>['t'];
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export function prepareColumnsSettings<TData extends object>({
|
|
122
|
+
columnDefinitions,
|
|
123
|
+
columnOrder,
|
|
124
|
+
columnsSettingsHeader,
|
|
125
|
+
areAllColumnsEnabled,
|
|
126
|
+
t,
|
|
127
|
+
}: PrepareColumnsSettingsProps<TData>): [GroupSelectItemProps] {
|
|
128
|
+
const groupedItems = columnDefinitions
|
|
129
|
+
.filter(isFilterableColumn)
|
|
130
|
+
.sort(sortColumnDefinitions(columnOrder))
|
|
131
|
+
.reduce(
|
|
132
|
+
(accSettings: ColumnGroups, colDef: FilterableColumnDefinition<TData>) => {
|
|
133
|
+
const item = createColumnsSettingsOption(colDef);
|
|
134
|
+
|
|
135
|
+
switch (colDef.pinned) {
|
|
136
|
+
case 'left':
|
|
137
|
+
accSettings.pinTop.push(item);
|
|
138
|
+
break;
|
|
139
|
+
|
|
140
|
+
case 'right':
|
|
141
|
+
accSettings.pinBottom.push(item);
|
|
142
|
+
break;
|
|
143
|
+
|
|
144
|
+
default:
|
|
145
|
+
accSettings.unpinned.push(item);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return accSettings;
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
pinTop: [],
|
|
152
|
+
unpinned: [],
|
|
153
|
+
pinBottom: [],
|
|
154
|
+
},
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
return [
|
|
158
|
+
{
|
|
159
|
+
divider: false,
|
|
160
|
+
items: [
|
|
161
|
+
{
|
|
162
|
+
divider: false,
|
|
163
|
+
items: groupedItems.pinTop,
|
|
164
|
+
type: 'group',
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
divider: true,
|
|
168
|
+
items: groupedItems.unpinned,
|
|
169
|
+
type: 'group',
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
divider: true,
|
|
173
|
+
items: groupedItems.pinBottom,
|
|
174
|
+
type: 'group',
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
selectButtonLabel: areAllColumnsEnabled ? t('groupSelectButton.hide') : t('groupSelectButton.show'),
|
|
178
|
+
label: columnsSettingsHeader || 'Display settings',
|
|
179
|
+
mode: 'primary',
|
|
180
|
+
type: 'group-select',
|
|
181
|
+
},
|
|
182
|
+
];
|
|
183
|
+
}
|
package/src/components/types.ts
CHANGED
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
} from '@tanstack/react-table';
|
|
9
9
|
import { ReactNode, RefObject } from 'react';
|
|
10
10
|
|
|
11
|
-
import {
|
|
12
|
-
import { ToolbarProps } from '@snack-uikit/toolbar';
|
|
11
|
+
import { FiltersState } from '@snack-uikit/chips';
|
|
12
|
+
import { FilterRow, ToolbarProps } from '@snack-uikit/toolbar';
|
|
13
13
|
import { WithSupportProps } from '@snack-uikit/utils';
|
|
14
14
|
|
|
15
15
|
import { EmptyStateProps, ExportButtonProps, RowClickHandler } from '../helperComponents';
|
|
@@ -42,6 +42,16 @@ type BaseTableProps<TData extends object, TFilters extends FiltersState = Record
|
|
|
42
42
|
onChange?(state: SortingState): void;
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
+
/** Параметры отвечают за настройки колонок <br>
|
|
46
|
+
* <strong>enableDrag</strong>: Включение сортировки порядка столбцов вручную перетаскиванием <br>
|
|
47
|
+
* <strong>headerLabel</strong>: Название меню настроек колонок. Наличие включает показ настроек <br>
|
|
48
|
+
* <strong>selectAllButtonLabels</strong>: Значения кнопки включения/отключения всех айтемов ([вкл, выкл]) <br>
|
|
49
|
+
* */
|
|
50
|
+
columnsSettings?: {
|
|
51
|
+
enableDrag?: boolean;
|
|
52
|
+
headerLabel?: string;
|
|
53
|
+
};
|
|
54
|
+
|
|
45
55
|
/** Параметр отвечает за общие настройки раскрывающихся строк*/
|
|
46
56
|
expanding?: {
|
|
47
57
|
/** Метод отвечает за получение дочерних строк*/
|
|
@@ -101,7 +111,7 @@ type BaseTableProps<TData extends object, TFilters extends FiltersState = Record
|
|
|
101
111
|
outline?: boolean;
|
|
102
112
|
|
|
103
113
|
/** Фильтры */
|
|
104
|
-
columnFilters?:
|
|
114
|
+
columnFilters?: FilterRow<TFilters>;
|
|
105
115
|
|
|
106
116
|
/** Флаг, показывающий что данные были отфильтрованы при пустых данных */
|
|
107
117
|
dataFiltered?: boolean;
|
package/src/constants.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useSortable } from '@dnd-kit/sortable';
|
|
1
2
|
import { Cell as TableCell, flexRender } from '@tanstack/react-table';
|
|
2
3
|
import cn from 'classnames';
|
|
3
4
|
|
|
@@ -10,16 +11,22 @@ import styles from './styles.module.scss';
|
|
|
10
11
|
type BodyCellProps<TData> = Omit<CellProps, 'style' | 'children'> & {
|
|
11
12
|
cell: TableCell<TData, unknown>;
|
|
12
13
|
rowAutoHeight?: boolean;
|
|
14
|
+
isDraggable?: boolean;
|
|
13
15
|
};
|
|
14
16
|
|
|
15
|
-
export function BodyCell<TData>({ cell, className, rowAutoHeight, ...props }: BodyCellProps<TData>) {
|
|
17
|
+
export function BodyCell<TData>({ cell, className, rowAutoHeight, isDraggable, ...props }: BodyCellProps<TData>) {
|
|
16
18
|
const columnDef: ColumnDefinition<TData> = cell.column.columnDef;
|
|
17
19
|
|
|
18
|
-
const style = useCellSizes(cell);
|
|
20
|
+
const style = useCellSizes(cell, { isDraggable });
|
|
21
|
+
|
|
22
|
+
const { setNodeRef } = useSortable({
|
|
23
|
+
id: cell.column.id,
|
|
24
|
+
});
|
|
19
25
|
|
|
20
26
|
return (
|
|
21
27
|
<Cell
|
|
22
28
|
{...props}
|
|
29
|
+
ref={setNodeRef}
|
|
23
30
|
style={style}
|
|
24
31
|
className={cn(styles.tableBodyCell, className, columnDef.cellClassName)}
|
|
25
32
|
data-row-auto-height={rowAutoHeight || undefined}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { useSortable } from '@dnd-kit/sortable';
|
|
1
2
|
import { flexRender, Header } from '@tanstack/react-table';
|
|
2
3
|
import cn from 'classnames';
|
|
3
4
|
import { MouseEvent, useRef } from 'react';
|
|
4
5
|
|
|
5
6
|
import { TruncateString } from '@snack-uikit/truncate-string';
|
|
6
7
|
|
|
7
|
-
import { TEST_IDS } from '../../../constants';
|
|
8
|
+
import { DEFAULT_COLUMNS, TEST_IDS } from '../../../constants';
|
|
8
9
|
import { ColumnDefinition, ColumnPinPosition } from '../../../types';
|
|
9
10
|
import { useCellSizes } from '../../hooks';
|
|
10
11
|
import { Cell, CellProps } from '../Cell';
|
|
@@ -16,9 +17,16 @@ type HeaderCellProps<TData> = Omit<CellProps, 'align' | 'children' | 'onClick' |
|
|
|
16
17
|
header: Header<TData, unknown>;
|
|
17
18
|
pinPosition?: ColumnPinPosition;
|
|
18
19
|
rowAutoHeight?: boolean;
|
|
20
|
+
isDraggable?: boolean;
|
|
19
21
|
};
|
|
20
22
|
|
|
21
|
-
export function HeaderCell<TData>({
|
|
23
|
+
export function HeaderCell<TData>({
|
|
24
|
+
header,
|
|
25
|
+
pinPosition,
|
|
26
|
+
className,
|
|
27
|
+
rowAutoHeight,
|
|
28
|
+
isDraggable,
|
|
29
|
+
}: HeaderCellProps<TData>) {
|
|
22
30
|
const cellRef = useRef<HTMLDivElement>(null);
|
|
23
31
|
const isSortable = header.column.getCanSort();
|
|
24
32
|
const isResizable = header.column.getCanResize();
|
|
@@ -32,7 +40,11 @@ export function HeaderCell<TData>({ header, pinPosition, className, rowAutoHeigh
|
|
|
32
40
|
|
|
33
41
|
const columnDef: ColumnDefinition<TData> = header.column.columnDef;
|
|
34
42
|
|
|
35
|
-
const style = useCellSizes(header);
|
|
43
|
+
const style = useCellSizes(header, { isDraggable });
|
|
44
|
+
|
|
45
|
+
const { attributes, listeners, setNodeRef, isDragging } = useSortable({
|
|
46
|
+
id: header.column.id,
|
|
47
|
+
});
|
|
36
48
|
|
|
37
49
|
const sortingHandler = (e: MouseEvent<HTMLDivElement>) => {
|
|
38
50
|
if (isSomeColumnResizing) return;
|
|
@@ -40,11 +52,16 @@ export function HeaderCell<TData>({ header, pinPosition, className, rowAutoHeigh
|
|
|
40
52
|
return header.column.getToggleSortingHandler()?.(e);
|
|
41
53
|
};
|
|
42
54
|
|
|
55
|
+
const isAvailableForDrag = !DEFAULT_COLUMNS.includes(header.column.id);
|
|
56
|
+
const dragAttributes = isAvailableForDrag ? attributes : {};
|
|
57
|
+
const listenersAttributes = isAvailableForDrag ? listeners : {};
|
|
58
|
+
|
|
43
59
|
return (
|
|
44
60
|
<Cell
|
|
45
61
|
style={style}
|
|
46
62
|
onClick={sortingHandler}
|
|
47
63
|
data-sortable={isSortable || undefined}
|
|
64
|
+
data-draggable={isDraggable || undefined}
|
|
48
65
|
data-no-padding={columnDef.noHeaderCellPadding || undefined}
|
|
49
66
|
data-no-offset={columnDef.noHeaderCellBorderOffset || undefined}
|
|
50
67
|
data-test-id={TEST_IDS.headerCell}
|
|
@@ -55,28 +72,38 @@ export function HeaderCell<TData>({ header, pinPosition, className, rowAutoHeigh
|
|
|
55
72
|
data-row-auto-height={rowAutoHeight || undefined}
|
|
56
73
|
role='columnheader'
|
|
57
74
|
className={cn(styles.tableHeaderCell, className, columnDef.headerClassName)}
|
|
58
|
-
ref={
|
|
75
|
+
ref={element => {
|
|
76
|
+
setNodeRef(element);
|
|
77
|
+
return cellRef;
|
|
78
|
+
}}
|
|
59
79
|
>
|
|
60
|
-
<div
|
|
61
|
-
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
80
|
+
<div
|
|
81
|
+
className={styles.tableHeaderCellDragWrapper}
|
|
82
|
+
data-dragging={isDragging || undefined}
|
|
83
|
+
{...dragAttributes}
|
|
84
|
+
{...listenersAttributes}
|
|
85
|
+
>
|
|
86
|
+
<div className={styles.tableHeaderCellMain}>
|
|
87
|
+
{columnDef.header && (
|
|
88
|
+
<div className={styles.tableHeaderCellName}>
|
|
89
|
+
{rowAutoHeight ? (
|
|
90
|
+
flexRender(columnDef.header, header.getContext())
|
|
91
|
+
) : (
|
|
92
|
+
<TruncateString text={flexRender(columnDef.header, header.getContext()) as string} />
|
|
93
|
+
)}
|
|
94
|
+
</div>
|
|
95
|
+
)}
|
|
70
96
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
97
|
+
{Boolean(sortIcon) && (
|
|
98
|
+
<div
|
|
99
|
+
className={styles.tableHeaderIcon}
|
|
100
|
+
data-sort-direction={sortDirection}
|
|
101
|
+
data-test-id={TEST_IDS.headerSortIndicator}
|
|
102
|
+
>
|
|
103
|
+
{sortIcon}
|
|
104
|
+
</div>
|
|
105
|
+
)}
|
|
106
|
+
</div>
|
|
80
107
|
</div>
|
|
81
108
|
|
|
82
109
|
{Boolean(isResizable) && <ResizeHandle header={header} cellRef={cellRef} />}
|
|
@@ -98,6 +98,10 @@
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
&[data-draggable] {
|
|
102
|
+
cursor: grab;
|
|
103
|
+
}
|
|
104
|
+
|
|
101
105
|
&[data-sortable] {
|
|
102
106
|
cursor: pointer;
|
|
103
107
|
}
|
|
@@ -151,6 +155,16 @@
|
|
|
151
155
|
}
|
|
152
156
|
}
|
|
153
157
|
|
|
158
|
+
.tableHeaderCellDragWrapper {
|
|
159
|
+
width: 100%;
|
|
160
|
+
|
|
161
|
+
&[data-dragging] {
|
|
162
|
+
&:active {
|
|
163
|
+
cursor: grabbing;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
154
168
|
.tableHeaderCellMain {
|
|
155
169
|
overflow: auto;
|
|
156
170
|
display: flex;
|
|
@@ -182,3 +196,4 @@
|
|
|
182
196
|
height: styles-tokens-table.simple-var(styles-tokens-element.$icon-xs) !important; /* stylelint-disable-line declaration-no-important */
|
|
183
197
|
}
|
|
184
198
|
}
|
|
199
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ButtonFunction } from '@snack-uikit/button';
|
|
2
|
+
import { FunctionSettingsSVG } from '@snack-uikit/icons';
|
|
3
|
+
import { Droplist, GroupSelectItemProps } from '@snack-uikit/list';
|
|
4
|
+
|
|
5
|
+
import styles from './styles.module.scss';
|
|
6
|
+
|
|
7
|
+
type ColumnsSettingsProps = {
|
|
8
|
+
enabledColumns: string[];
|
|
9
|
+
setEnabledColumns(enabledColumns: string[]): void;
|
|
10
|
+
columnsSettings: [GroupSelectItemProps];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function ColumnsSettings({ columnsSettings, enabledColumns, setEnabledColumns }: ColumnsSettingsProps) {
|
|
14
|
+
return (
|
|
15
|
+
<Droplist
|
|
16
|
+
className={styles.columnsSettings}
|
|
17
|
+
items={columnsSettings}
|
|
18
|
+
selection={{
|
|
19
|
+
value: enabledColumns,
|
|
20
|
+
onChange: setEnabledColumns,
|
|
21
|
+
mode: 'multiple',
|
|
22
|
+
}}
|
|
23
|
+
placement='bottom-end'
|
|
24
|
+
>
|
|
25
|
+
<ButtonFunction size='m' data-test-id='table__column-settings' icon={<FunctionSettingsSVG />} />
|
|
26
|
+
</Droplist>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ColumnsSettings';
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { horizontalListSortingStrategy, SortableContext } from '@dnd-kit/sortable';
|
|
1
2
|
import { Row as TableRow } from '@tanstack/react-table';
|
|
2
3
|
import { MouseEvent, useState } from 'react';
|
|
3
4
|
|
|
4
5
|
import { COLUMN_PIN_POSITION, TEST_IDS } from '../../constants';
|
|
6
|
+
import { ColumnOrder } from '../../types';
|
|
5
7
|
import { BodyCell } from '../Cells';
|
|
6
8
|
import { RowContext } from '../contexts';
|
|
7
9
|
import { useRowCells } from '../hooks';
|
|
@@ -21,10 +23,18 @@ export type RowClickHandler<TData> = (e: MouseEvent<HTMLDivElement>, row: RowInf
|
|
|
21
23
|
export type BodyRowProps<TData> = Pick<RowProps, 'rowAutoHeight'> & {
|
|
22
24
|
row: TableRow<TData>;
|
|
23
25
|
onRowClick?: RowClickHandler<TData>;
|
|
26
|
+
columnOrder: ColumnOrder;
|
|
27
|
+
enableColumnsOrderSortByDrag?: boolean;
|
|
24
28
|
};
|
|
25
29
|
|
|
26
|
-
export function BodyRow<TData>({
|
|
27
|
-
|
|
30
|
+
export function BodyRow<TData>({
|
|
31
|
+
row,
|
|
32
|
+
onRowClick,
|
|
33
|
+
rowAutoHeight,
|
|
34
|
+
columnOrder,
|
|
35
|
+
enableColumnsOrderSortByDrag,
|
|
36
|
+
}: BodyRowProps<TData>) {
|
|
37
|
+
const { leftPinned, rightPinned, unpinned } = useRowCells(row);
|
|
28
38
|
|
|
29
39
|
const [dropListOpened, setDropListOpen] = useState(false);
|
|
30
40
|
|
|
@@ -58,22 +68,34 @@ export function BodyRow<TData>({ row, onRowClick, rowAutoHeight }: BodyRowProps<
|
|
|
58
68
|
className={styles.bodyRow}
|
|
59
69
|
rowAutoHeight={rowAutoHeight}
|
|
60
70
|
>
|
|
61
|
-
{
|
|
71
|
+
{leftPinned && (
|
|
62
72
|
<PinnedCells position={COLUMN_PIN_POSITION.Left}>
|
|
63
|
-
{
|
|
73
|
+
{leftPinned.map(cell => (
|
|
64
74
|
<BodyCell key={cell.id} cell={cell} rowAutoHeight={rowAutoHeight} />
|
|
65
75
|
))}
|
|
66
76
|
</PinnedCells>
|
|
67
77
|
)}
|
|
68
78
|
|
|
69
79
|
{unpinned.map(cell => (
|
|
70
|
-
<
|
|
80
|
+
<SortableContext key={cell.id} items={columnOrder} strategy={horizontalListSortingStrategy}>
|
|
81
|
+
<BodyCell
|
|
82
|
+
key={cell.id}
|
|
83
|
+
cell={cell}
|
|
84
|
+
rowAutoHeight={rowAutoHeight}
|
|
85
|
+
isDraggable={enableColumnsOrderSortByDrag}
|
|
86
|
+
/>
|
|
87
|
+
</SortableContext>
|
|
71
88
|
))}
|
|
72
89
|
|
|
73
|
-
{
|
|
90
|
+
{rightPinned && (
|
|
74
91
|
<PinnedCells position={COLUMN_PIN_POSITION.Right}>
|
|
75
|
-
{
|
|
76
|
-
<BodyCell
|
|
92
|
+
{rightPinned.map(cell => (
|
|
93
|
+
<BodyCell
|
|
94
|
+
key={cell.id}
|
|
95
|
+
cell={cell}
|
|
96
|
+
rowAutoHeight={rowAutoHeight}
|
|
97
|
+
isDraggable={enableColumnsOrderSortByDrag}
|
|
98
|
+
/>
|
|
77
99
|
))}
|
|
78
100
|
</PinnedCells>
|
|
79
101
|
)}
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
+
import { horizontalListSortingStrategy, SortableContext } from '@dnd-kit/sortable';
|
|
2
|
+
|
|
1
3
|
import { COLUMN_PIN_POSITION, TEST_IDS } from '../../constants';
|
|
4
|
+
import { ColumnOrder } from '../../types';
|
|
2
5
|
import { HeaderCell } from '../Cells';
|
|
3
6
|
import { useHeaderGroups } from '../hooks';
|
|
4
7
|
import { PinnedCells } from './PinnedCells';
|
|
5
8
|
import { Row, RowProps } from './Row';
|
|
6
9
|
import styles from './styles.module.scss';
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
type Props = Pick<RowProps, 'rowAutoHeight'> & {
|
|
12
|
+
columnOrder: ColumnOrder;
|
|
13
|
+
enableColumnsOrderSortByDrag?: boolean;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function HeaderRow({ rowAutoHeight, columnOrder, enableColumnsOrderSortByDrag }: Props) {
|
|
9
17
|
const { leftPinned, unpinned, rightPinned } = useHeaderGroups();
|
|
10
18
|
|
|
11
19
|
return (
|
|
@@ -22,9 +30,18 @@ export function HeaderRow({ rowAutoHeight }: Pick<RowProps, 'rowAutoHeight'>) {
|
|
|
22
30
|
</PinnedCells>
|
|
23
31
|
)}
|
|
24
32
|
|
|
25
|
-
{
|
|
26
|
-
|
|
27
|
-
|
|
33
|
+
<SortableContext items={columnOrder} strategy={horizontalListSortingStrategy}>
|
|
34
|
+
{unpinned.map(headerGroup =>
|
|
35
|
+
headerGroup.headers.map(header => (
|
|
36
|
+
<HeaderCell
|
|
37
|
+
key={header.id}
|
|
38
|
+
header={header}
|
|
39
|
+
rowAutoHeight={rowAutoHeight}
|
|
40
|
+
isDraggable={enableColumnsOrderSortByDrag && columnOrder.length > 1}
|
|
41
|
+
/>
|
|
42
|
+
)),
|
|
43
|
+
)}
|
|
44
|
+
</SortableContext>
|
|
28
45
|
|
|
29
46
|
{rightPinned && (
|
|
30
47
|
<PinnedCells position={COLUMN_PIN_POSITION.Right}>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { useSortable } from '@dnd-kit/sortable';
|
|
2
|
+
import { CSS } from '@dnd-kit/utilities';
|
|
1
3
|
import { Cell, Header, HeaderGroup, Row } from '@tanstack/react-table';
|
|
2
|
-
import { useMemo } from 'react';
|
|
4
|
+
import { CSSProperties, useMemo } from 'react';
|
|
3
5
|
|
|
4
6
|
import { useTableContext } from './contexts';
|
|
5
7
|
|
|
@@ -12,6 +14,7 @@ export function useHeaderGroups() {
|
|
|
12
14
|
|
|
13
15
|
const columnDefs = table._getColumnDefs();
|
|
14
16
|
const pinEnabled = table.getIsSomeColumnsPinned();
|
|
17
|
+
const { columnOrder } = table.getState();
|
|
15
18
|
|
|
16
19
|
return useMemo(() => {
|
|
17
20
|
if (!pinEnabled) {
|
|
@@ -30,7 +33,7 @@ export function useHeaderGroups() {
|
|
|
30
33
|
};
|
|
31
34
|
// need to rebuild if columnDefinitions has changed
|
|
32
35
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
33
|
-
}, [table, pinEnabled, columnDefs]);
|
|
36
|
+
}, [table, pinEnabled, columnDefs, columnOrder]);
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
export function useRowCells<TData>(row: Row<TData>) {
|
|
@@ -38,6 +41,7 @@ export function useRowCells<TData>(row: Row<TData>) {
|
|
|
38
41
|
|
|
39
42
|
const pinEnabled = table.getIsSomeColumnsPinned();
|
|
40
43
|
const columnDefs = table._getColumnDefs();
|
|
44
|
+
const { columnOrder } = table.getState();
|
|
41
45
|
|
|
42
46
|
return useMemo(() => {
|
|
43
47
|
if (!pinEnabled) {
|
|
@@ -50,30 +54,56 @@ export function useRowCells<TData>(row: Row<TData>) {
|
|
|
50
54
|
const right = row.getRightVisibleCells();
|
|
51
55
|
|
|
52
56
|
return {
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
leftPinned: left.length ? left : undefined,
|
|
58
|
+
rightPinned: right.length ? right : undefined,
|
|
55
59
|
unpinned: row.getCenterVisibleCells(),
|
|
56
60
|
};
|
|
57
61
|
// need to rebuild if columnDefinitions has changed
|
|
58
62
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
59
|
-
}, [row, pinEnabled, columnDefs]);
|
|
63
|
+
}, [row, pinEnabled, columnDefs, columnOrder]);
|
|
60
64
|
}
|
|
61
65
|
|
|
62
|
-
|
|
66
|
+
type CellSizesOptions = {
|
|
67
|
+
isDraggable?: boolean;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export function useCellSizes<TData>(
|
|
71
|
+
element: Cell<TData, unknown> | Header<TData, unknown>,
|
|
72
|
+
options?: CellSizesOptions,
|
|
73
|
+
) {
|
|
63
74
|
const column = element.column;
|
|
64
75
|
|
|
76
|
+
const { isDragging, transform } = useSortable({
|
|
77
|
+
id: column.id,
|
|
78
|
+
});
|
|
79
|
+
|
|
65
80
|
const minWidth = column.columnDef.minSize;
|
|
66
81
|
const maxWidth = column.columnDef.maxSize;
|
|
67
82
|
const width = `var(--table-column-${column.id}-size)`;
|
|
68
83
|
const flexShrink = `var(--table-column-${column.id}-flex)`;
|
|
69
84
|
|
|
70
|
-
|
|
71
|
-
|
|
85
|
+
const isHeaderCell = 'headerGroup' in element;
|
|
86
|
+
|
|
87
|
+
return useMemo(() => {
|
|
88
|
+
const styles: CSSProperties = {
|
|
72
89
|
minWidth,
|
|
73
90
|
width,
|
|
74
91
|
maxWidth,
|
|
75
92
|
flexShrink,
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
if (options?.isDraggable) {
|
|
96
|
+
styles.opacity = isDragging ? 0.8 : 1;
|
|
97
|
+
styles.position = 'relative';
|
|
98
|
+
styles.transform = CSS.Translate.toString(transform);
|
|
99
|
+
styles.transition = 'width transform 0.2s ease-in-out';
|
|
100
|
+
styles.zIndex = isDragging ? 1 : undefined;
|
|
101
|
+
|
|
102
|
+
if (isHeaderCell) {
|
|
103
|
+
styles.whiteSpace = 'nowrap';
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return styles;
|
|
108
|
+
}, [options?.isDraggable, flexShrink, isDragging, isHeaderCell, maxWidth, minWidth, transform, width]);
|
|
79
109
|
}
|
package/src/types.ts
CHANGED
|
@@ -14,8 +14,7 @@ import { ToolbarProps } from '@snack-uikit/toolbar';
|
|
|
14
14
|
import { ValueOf } from '@snack-uikit/utils';
|
|
15
15
|
|
|
16
16
|
import { COLUMN_ALIGN, COLUMN_PIN_POSITION } from './constants';
|
|
17
|
-
import { Except } from './helperComponents';
|
|
18
|
-
import { EmptyStateProps } from './helperComponents/TableEmptyState';
|
|
17
|
+
import { EmptyStateProps, Except } from './helperComponents';
|
|
19
18
|
|
|
20
19
|
type ColumnAlign = ValueOf<typeof COLUMN_ALIGN>;
|
|
21
20
|
|
|
@@ -64,7 +63,26 @@ type PinnedColumnDefinition<TData> = BaseColumnDefinition<TData> & {
|
|
|
64
63
|
size: number;
|
|
65
64
|
};
|
|
66
65
|
|
|
67
|
-
|
|
66
|
+
type FilterableProps = {
|
|
67
|
+
id: string;
|
|
68
|
+
/** Название колонки в настройках таблицы */
|
|
69
|
+
headerConfigLabel?: string;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
type FilterableNormalColumnDefinition<TData> = NormalColumnDefinition<TData> & FilterableProps;
|
|
73
|
+
|
|
74
|
+
type FilterablePinnedColumnDefinition<TData> = PinnedColumnDefinition<TData> & FilterableProps;
|
|
75
|
+
|
|
76
|
+
export type FilterableColumnDefinition<TData> =
|
|
77
|
+
| FilterableNormalColumnDefinition<TData>
|
|
78
|
+
| FilterablePinnedColumnDefinition<TData>;
|
|
79
|
+
|
|
80
|
+
export type ColumnDefinition<TData> =
|
|
81
|
+
| NormalColumnDefinition<TData>
|
|
82
|
+
| PinnedColumnDefinition<TData>
|
|
83
|
+
| FilterableColumnDefinition<TData>;
|
|
84
|
+
|
|
85
|
+
export type ColumnOrder = string[];
|
|
68
86
|
|
|
69
87
|
export type {
|
|
70
88
|
RowActionsColumnDefProps,
|