@snack-uikit/table 0.29.0 → 0.30.1-preview-9a03a1c9.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 +11 -0
- package/README.md +2 -0
- package/dist/cjs/components/Table/Table.d.ts +1 -1
- package/dist/cjs/components/Table/Table.js +141 -104
- 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 +9 -0
- package/dist/cjs/components/Table/hooks/useColumnOrderByDrag.js +76 -0
- package/dist/cjs/components/Table/utils.js +6 -3
- package/dist/cjs/components/types.d.ts +2 -0
- 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/DragHandle.d.ts +6 -0
- package/dist/cjs/helperComponents/Cells/HeaderCell/DragHandle.js +27 -0
- package/dist/cjs/helperComponents/Cells/HeaderCell/HeaderCell.d.ts +2 -1
- package/dist/cjs/helperComponents/Cells/HeaderCell/HeaderCell.js +22 -2
- package/dist/cjs/helperComponents/Cells/HeaderCell/styles.module.css +11 -0
- package/dist/cjs/helperComponents/Rows/BodyRow.d.ts +4 -1
- package/dist/cjs/helperComponents/Rows/BodyRow.js +30 -12
- package/dist/cjs/helperComponents/Rows/HeaderRow.d.ts +7 -1
- package/dist/cjs/helperComponents/Rows/HeaderRow.js +33 -13
- package/dist/cjs/helperComponents/hooks.d.ts +22 -13
- package/dist/cjs/helperComponents/hooks.js +63 -15
- package/dist/cjs/types.d.ts +5 -0
- package/dist/esm/components/Table/Table.d.ts +1 -1
- package/dist/esm/components/Table/Table.js +34 -25
- 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 +9 -0
- package/dist/esm/components/Table/hooks/useColumnOrderByDrag.js +66 -0
- package/dist/esm/components/Table/utils.js +6 -3
- package/dist/esm/components/types.d.ts +2 -0
- 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/DragHandle.d.ts +6 -0
- package/dist/esm/helperComponents/Cells/HeaderCell/DragHandle.js +6 -0
- package/dist/esm/helperComponents/Cells/HeaderCell/HeaderCell.d.ts +2 -1
- package/dist/esm/helperComponents/Cells/HeaderCell/HeaderCell.js +13 -4
- package/dist/esm/helperComponents/Cells/HeaderCell/styles.module.css +11 -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 +4 -3
- package/dist/esm/helperComponents/hooks.d.ts +22 -13
- package/dist/esm/helperComponents/hooks.js +58 -15
- package/dist/esm/types.d.ts +5 -0
- package/package.json +6 -2
- package/src/components/Table/Table.tsx +151 -117
- package/src/components/Table/hooks/index.ts +1 -0
- package/src/components/Table/hooks/useColumnOrderByDrag.ts +100 -0
- package/src/components/Table/utils.ts +8 -3
- package/src/components/types.ts +3 -0
- package/src/constants.tsx +2 -0
- package/src/helperComponents/Cells/BodyCell/BodyCell.tsx +9 -2
- package/src/helperComponents/Cells/HeaderCell/DragHandle.tsx +18 -0
- package/src/helperComponents/Cells/HeaderCell/HeaderCell.tsx +19 -4
- package/src/helperComponents/Cells/HeaderCell/styles.module.scss +15 -4
- package/src/helperComponents/Rows/BodyRow.tsx +36 -9
- package/src/helperComponents/Rows/HeaderRow.tsx +51 -18
- package/src/helperComponents/Rows/styles.module.scss +2 -2
- package/src/helperComponents/hooks.ts +78 -15
- package/src/types.ts +6 -0
|
@@ -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 { GroupedColumnOrderState } from '../../types';
|
|
5
7
|
import { BodyCell } from '../Cells';
|
|
6
8
|
import { RowContext } from '../contexts';
|
|
7
9
|
import { useRowCells } from '../hooks';
|
|
@@ -21,10 +23,17 @@ export type RowClickHandler<TData> = (e: MouseEvent<HTMLDivElement>, row: RowInf
|
|
|
21
23
|
export type BodyRowProps<TData> = {
|
|
22
24
|
row: TableRow<TData>;
|
|
23
25
|
onRowClick?: RowClickHandler<TData>;
|
|
26
|
+
groupedColumnOrderState: GroupedColumnOrderState;
|
|
27
|
+
enableColumnsOrderSortByDrag?: boolean;
|
|
24
28
|
};
|
|
25
29
|
|
|
26
|
-
export function BodyRow<TData>({
|
|
27
|
-
|
|
30
|
+
export function BodyRow<TData>({
|
|
31
|
+
row,
|
|
32
|
+
onRowClick,
|
|
33
|
+
groupedColumnOrderState,
|
|
34
|
+
enableColumnsOrderSortByDrag,
|
|
35
|
+
}: BodyRowProps<TData>) {
|
|
36
|
+
const { leftPinned, rightPinned, unpinned } = useRowCells(row, groupedColumnOrderState);
|
|
28
37
|
|
|
29
38
|
const [dropListOpened, setDropListOpen] = useState(false);
|
|
30
39
|
|
|
@@ -57,22 +66,40 @@ export function BodyRow<TData>({ row, onRowClick }: BodyRowProps<TData>) {
|
|
|
57
66
|
data-row-id={row.id}
|
|
58
67
|
className={styles.bodyRow}
|
|
59
68
|
>
|
|
60
|
-
{
|
|
69
|
+
{leftPinned && (
|
|
61
70
|
<PinnedCells position={COLUMN_PIN_POSITION.Left}>
|
|
62
|
-
{
|
|
63
|
-
<
|
|
71
|
+
{leftPinned.map(cell => (
|
|
72
|
+
<SortableContext
|
|
73
|
+
key={cell.id}
|
|
74
|
+
items={groupedColumnOrderState.leftPinned}
|
|
75
|
+
strategy={horizontalListSortingStrategy}
|
|
76
|
+
>
|
|
77
|
+
<BodyCell key={cell.id} cell={cell} isDraggable={enableColumnsOrderSortByDrag} />
|
|
78
|
+
</SortableContext>
|
|
64
79
|
))}
|
|
65
80
|
</PinnedCells>
|
|
66
81
|
)}
|
|
67
82
|
|
|
68
83
|
{unpinned.map(cell => (
|
|
69
|
-
<
|
|
84
|
+
<SortableContext
|
|
85
|
+
key={cell.id}
|
|
86
|
+
items={groupedColumnOrderState.unpinned}
|
|
87
|
+
strategy={horizontalListSortingStrategy}
|
|
88
|
+
>
|
|
89
|
+
<BodyCell key={cell.id} cell={cell} isDraggable={enableColumnsOrderSortByDrag} />
|
|
90
|
+
</SortableContext>
|
|
70
91
|
))}
|
|
71
92
|
|
|
72
|
-
{
|
|
93
|
+
{rightPinned && (
|
|
73
94
|
<PinnedCells position={COLUMN_PIN_POSITION.Right}>
|
|
74
|
-
{
|
|
75
|
-
<
|
|
95
|
+
{rightPinned.map(cell => (
|
|
96
|
+
<SortableContext
|
|
97
|
+
key={cell.id}
|
|
98
|
+
items={groupedColumnOrderState.rightPinned}
|
|
99
|
+
strategy={horizontalListSortingStrategy}
|
|
100
|
+
>
|
|
101
|
+
<BodyCell key={cell.id} cell={cell} isDraggable={enableColumnsOrderSortByDrag} />
|
|
102
|
+
</SortableContext>
|
|
76
103
|
))}
|
|
77
104
|
</PinnedCells>
|
|
78
105
|
)}
|
|
@@ -1,37 +1,70 @@
|
|
|
1
|
+
import { horizontalListSortingStrategy, SortableContext } from '@dnd-kit/sortable';
|
|
2
|
+
|
|
1
3
|
import { COLUMN_PIN_POSITION, TEST_IDS } from '../../constants';
|
|
4
|
+
import { GroupedColumnOrderState } from '../../types';
|
|
2
5
|
import { HeaderCell } from '../Cells';
|
|
3
6
|
import { useHeaderGroups } from '../hooks';
|
|
4
7
|
import { PinnedCells } from './PinnedCells';
|
|
5
8
|
import { Row } from './Row';
|
|
6
9
|
import styles from './styles.module.scss';
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
type Props = {
|
|
12
|
+
groupedColumnOrderState: GroupedColumnOrderState;
|
|
13
|
+
enableColumnsOrderSortByDrag?: boolean;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function HeaderRow({ groupedColumnOrderState, enableColumnsOrderSortByDrag }: Props) {
|
|
17
|
+
const { leftPinned, unpinned, rightPinned } = useHeaderGroups(groupedColumnOrderState);
|
|
10
18
|
|
|
11
19
|
return (
|
|
12
20
|
<Row className={styles.tableHeader} data-test-id={TEST_IDS.headerRow}>
|
|
13
21
|
{leftPinned && (
|
|
14
|
-
<
|
|
15
|
-
{
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
<SortableContext items={groupedColumnOrderState.leftPinned} strategy={horizontalListSortingStrategy}>
|
|
23
|
+
<PinnedCells position={COLUMN_PIN_POSITION.Left}>
|
|
24
|
+
{leftPinned.map(headerGroup =>
|
|
25
|
+
headerGroup.headers.map(header =>
|
|
26
|
+
header.isPlaceholder ? null : (
|
|
27
|
+
<HeaderCell
|
|
28
|
+
key={header.id}
|
|
29
|
+
header={header}
|
|
30
|
+
isDraggable={enableColumnsOrderSortByDrag && groupedColumnOrderState.leftPinned.length > 1}
|
|
31
|
+
/>
|
|
32
|
+
),
|
|
33
|
+
),
|
|
34
|
+
)}
|
|
35
|
+
</PinnedCells>
|
|
36
|
+
</SortableContext>
|
|
21
37
|
)}
|
|
22
38
|
|
|
23
|
-
|
|
39
|
+
<SortableContext items={groupedColumnOrderState.unpinned} strategy={horizontalListSortingStrategy}>
|
|
40
|
+
{unpinned.map(headerGroup =>
|
|
41
|
+
headerGroup.headers.map(header => (
|
|
42
|
+
<HeaderCell
|
|
43
|
+
key={header.id}
|
|
44
|
+
header={header}
|
|
45
|
+
isDraggable={enableColumnsOrderSortByDrag && groupedColumnOrderState.unpinned.length > 1}
|
|
46
|
+
/>
|
|
47
|
+
)),
|
|
48
|
+
)}
|
|
49
|
+
</SortableContext>
|
|
24
50
|
|
|
25
51
|
{rightPinned && (
|
|
26
|
-
<
|
|
27
|
-
{
|
|
28
|
-
|
|
29
|
-
header
|
|
30
|
-
|
|
52
|
+
<SortableContext items={groupedColumnOrderState.rightPinned} strategy={horizontalListSortingStrategy}>
|
|
53
|
+
<PinnedCells position={COLUMN_PIN_POSITION.Right}>
|
|
54
|
+
{rightPinned.map(headerGroup =>
|
|
55
|
+
headerGroup.headers.map(header =>
|
|
56
|
+
header.isPlaceholder ? null : (
|
|
57
|
+
<HeaderCell
|
|
58
|
+
key={header.id}
|
|
59
|
+
header={header}
|
|
60
|
+
pinPosition={COLUMN_PIN_POSITION.Right}
|
|
61
|
+
isDraggable={enableColumnsOrderSortByDrag && groupedColumnOrderState.rightPinned.length > 1}
|
|
62
|
+
/>
|
|
63
|
+
),
|
|
31
64
|
),
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
</
|
|
65
|
+
)}
|
|
66
|
+
</PinnedCells>
|
|
67
|
+
</SortableContext>
|
|
35
68
|
)}
|
|
36
69
|
</Row>
|
|
37
70
|
);
|
|
@@ -42,8 +42,8 @@ $snack-ui-table-row-background: var(--snack-ui-table-row-background);
|
|
|
42
42
|
content: '';
|
|
43
43
|
|
|
44
44
|
position: absolute;
|
|
45
|
-
top: calc(0px - styles-tokens-table.$border-width-table);
|
|
46
|
-
bottom: calc(0px - styles-tokens-table.$border-width-table);
|
|
45
|
+
top: calc(0px - #{styles-tokens-table.$border-width-table});
|
|
46
|
+
bottom: calc(0px - #{styles-tokens-table.$border-width-table});
|
|
47
47
|
|
|
48
48
|
box-sizing: border-box;
|
|
49
49
|
width: styles-tokens-table.$border-width-table;
|
|
@@ -1,17 +1,36 @@
|
|
|
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
|
|
|
6
|
+
import { GroupedColumnOrderState } from '../types';
|
|
4
7
|
import { useTableContext } from './contexts';
|
|
5
8
|
|
|
6
9
|
function hasHeaders<TData>(groups: HeaderGroup<TData>[]) {
|
|
7
10
|
return groups.some(group => group.headers.length);
|
|
8
11
|
}
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
const sortHeaderGroup = (groups: HeaderGroup<unknown>[], groupOrder: string[]) =>
|
|
14
|
+
groups.map(group => ({
|
|
15
|
+
...group,
|
|
16
|
+
headers: group.headers.sort((a, b) => {
|
|
17
|
+
const indexA = groupOrder.findIndex(columnId => columnId === a.id);
|
|
18
|
+
const indexB = groupOrder.findIndex(columnId => columnId === b.id);
|
|
19
|
+
|
|
20
|
+
if (indexA > -1 && indexB > -1) {
|
|
21
|
+
return indexA - indexB;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return 0;
|
|
25
|
+
}),
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
export function useHeaderGroups(groupedColumnOrderState: GroupedColumnOrderState) {
|
|
11
29
|
const { table } = useTableContext();
|
|
12
30
|
|
|
13
31
|
const columnDefs = table._getColumnDefs();
|
|
14
32
|
const pinEnabled = table.getIsSomeColumnsPinned();
|
|
33
|
+
const { columnOrder } = table.getState();
|
|
15
34
|
|
|
16
35
|
return useMemo(() => {
|
|
17
36
|
if (!pinEnabled) {
|
|
@@ -24,20 +43,34 @@ export function useHeaderGroups() {
|
|
|
24
43
|
const right = table.getRightHeaderGroups();
|
|
25
44
|
|
|
26
45
|
return {
|
|
27
|
-
leftPinned: hasHeaders(left) ? left : undefined,
|
|
28
|
-
rightPinned: hasHeaders(right) ? right : undefined,
|
|
46
|
+
leftPinned: hasHeaders(left) ? sortHeaderGroup(left, groupedColumnOrderState.leftPinned) : undefined,
|
|
47
|
+
rightPinned: hasHeaders(right) ? sortHeaderGroup(right, groupedColumnOrderState.rightPinned) : undefined,
|
|
29
48
|
unpinned: table.getCenterHeaderGroups(),
|
|
30
49
|
};
|
|
31
50
|
// need to rebuild if columnDefinitions has changed
|
|
32
51
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
33
|
-
}, [table, pinEnabled, columnDefs]);
|
|
52
|
+
}, [table, pinEnabled, columnDefs, columnOrder, groupedColumnOrderState]);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function sortPinnedColumnsByOrderState<TData>(groupOrder: string[]) {
|
|
56
|
+
return (a: Cell<TData, unknown>, b: Cell<TData, unknown>) => {
|
|
57
|
+
const indexA = groupOrder.findIndex(columnId => columnId === a.column.id);
|
|
58
|
+
const indexB = groupOrder.findIndex(columnId => columnId === b.column.id);
|
|
59
|
+
|
|
60
|
+
if (indexA > -1 && indexB > -1) {
|
|
61
|
+
return indexA - indexB;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return 0;
|
|
65
|
+
};
|
|
34
66
|
}
|
|
35
67
|
|
|
36
|
-
export function useRowCells<TData>(row: Row<TData
|
|
68
|
+
export function useRowCells<TData>(row: Row<TData>, groupedColumnOrderState: GroupedColumnOrderState) {
|
|
37
69
|
const { table } = useTableContext();
|
|
38
70
|
|
|
39
71
|
const pinEnabled = table.getIsSomeColumnsPinned();
|
|
40
72
|
const columnDefs = table._getColumnDefs();
|
|
73
|
+
const { columnOrder } = table.getState();
|
|
41
74
|
|
|
42
75
|
return useMemo(() => {
|
|
43
76
|
if (!pinEnabled) {
|
|
@@ -50,30 +83,60 @@ export function useRowCells<TData>(row: Row<TData>) {
|
|
|
50
83
|
const right = row.getRightVisibleCells();
|
|
51
84
|
|
|
52
85
|
return {
|
|
53
|
-
|
|
54
|
-
|
|
86
|
+
leftPinned: left.length
|
|
87
|
+
? left.slice().sort(sortPinnedColumnsByOrderState(groupedColumnOrderState.leftPinned))
|
|
88
|
+
: undefined,
|
|
89
|
+
rightPinned: right.length
|
|
90
|
+
? right.slice().sort(sortPinnedColumnsByOrderState(groupedColumnOrderState.rightPinned))
|
|
91
|
+
: undefined,
|
|
55
92
|
unpinned: row.getCenterVisibleCells(),
|
|
56
93
|
};
|
|
57
94
|
// need to rebuild if columnDefinitions has changed
|
|
58
95
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
59
|
-
}, [row, pinEnabled, columnDefs]);
|
|
96
|
+
}, [row, pinEnabled, columnDefs, columnOrder, groupedColumnOrderState]);
|
|
60
97
|
}
|
|
61
98
|
|
|
62
|
-
|
|
99
|
+
type CellSizesOptions = {
|
|
100
|
+
isDraggable?: boolean;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export function useCellSizes<TData>(
|
|
104
|
+
element: Cell<TData, unknown> | Header<TData, unknown>,
|
|
105
|
+
options?: CellSizesOptions,
|
|
106
|
+
) {
|
|
63
107
|
const column = element.column;
|
|
64
108
|
|
|
109
|
+
const { isDragging, transform } = useSortable({
|
|
110
|
+
id: column.id,
|
|
111
|
+
});
|
|
112
|
+
|
|
65
113
|
const minWidth = column.columnDef.minSize;
|
|
66
114
|
const maxWidth = column.columnDef.maxSize;
|
|
67
115
|
const width = `var(--table-column-${column.id}-size)`;
|
|
68
116
|
const flexShrink = `var(--table-column-${column.id}-flex)`;
|
|
69
117
|
|
|
70
|
-
|
|
71
|
-
|
|
118
|
+
const isHeaderCell = 'headerGroup' in element;
|
|
119
|
+
|
|
120
|
+
return useMemo(() => {
|
|
121
|
+
const styles: CSSProperties = {
|
|
72
122
|
minWidth,
|
|
73
123
|
width,
|
|
74
124
|
maxWidth,
|
|
75
125
|
flexShrink,
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
if (options?.isDraggable) {
|
|
129
|
+
styles.opacity = isDragging ? 0.8 : 1;
|
|
130
|
+
styles.position = 'relative';
|
|
131
|
+
styles.transform = CSS.Translate.toString(transform);
|
|
132
|
+
styles.transition = 'width transform 0.2s ease-in-out';
|
|
133
|
+
styles.zIndex = isDragging ? 1 : 0;
|
|
134
|
+
|
|
135
|
+
if (isHeaderCell) {
|
|
136
|
+
styles.whiteSpace = 'nowrap';
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return styles;
|
|
141
|
+
}, [options?.isDraggable, flexShrink, isDragging, isHeaderCell, maxWidth, minWidth, transform, width]);
|
|
79
142
|
}
|
package/src/types.ts
CHANGED
|
@@ -66,6 +66,12 @@ type PinnedColumnDefinition<TData> = BaseColumnDefinition<TData> & {
|
|
|
66
66
|
|
|
67
67
|
export type ColumnDefinition<TData> = NormalColumnDefinition<TData> | PinnedColumnDefinition<TData>;
|
|
68
68
|
|
|
69
|
+
export type GroupedColumnOrderState = {
|
|
70
|
+
leftPinned: string[];
|
|
71
|
+
rightPinned: string[];
|
|
72
|
+
unpinned: string[];
|
|
73
|
+
};
|
|
74
|
+
|
|
69
75
|
export type {
|
|
70
76
|
RowActionsColumnDefProps,
|
|
71
77
|
StatusColumnDefinitionProps,
|