@purpurds/table 8.6.0 → 8.8.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/dist/LICENSE.txt +16 -16
- package/dist/styles.css +1 -1
- package/dist/table-column-header-cell.d.ts.map +1 -1
- package/dist/table-content.d.ts +16 -27
- package/dist/table-content.d.ts.map +1 -1
- package/dist/table.cjs.js +65 -65
- package/dist/table.cjs.js.map +1 -1
- package/dist/table.d.ts.map +1 -1
- package/dist/table.es.js +4191 -4249
- package/dist/table.es.js.map +1 -1
- package/dist/use-drag-handle.hook.d.ts +2 -6
- package/dist/use-drag-handle.hook.d.ts.map +1 -1
- package/dist/utils/custom-keyboard-coordinates.d.ts +3 -2
- package/dist/utils/custom-keyboard-coordinates.d.ts.map +1 -1
- package/package.json +25 -25
- package/src/cell-types/date-cell.tsx +1 -1
- package/src/table-column-header-cell.tsx +9 -5
- package/src/table-content-drag.test.tsx +43 -430
- package/src/table-content.tsx +62 -118
- package/src/table-settings-drawer.tsx +1 -1
- package/src/table.stories.tsx +11 -0
- package/src/table.tsx +100 -139
- package/src/use-drag-handle.hook.tsx +7 -26
- package/src/use-drag-handle.test.tsx +21 -174
- package/src/utils/custom-keyboard-coordinates.ts +27 -66
package/src/table-content.tsx
CHANGED
|
@@ -9,137 +9,53 @@ import { EmptyTable } from "./empty-table";
|
|
|
9
9
|
import { LoadingTableRows } from "./loading-table-rows";
|
|
10
10
|
import styles from "./table.module.scss";
|
|
11
11
|
import { TableBody } from "./table-body";
|
|
12
|
-
import { TableHeader } from "./table-header";
|
|
13
12
|
import { TableRow } from "./table-row";
|
|
14
13
|
import { TableRowCell } from "./table-row-cell";
|
|
15
14
|
|
|
16
15
|
const cx = c.bind(styles);
|
|
17
16
|
const rootClassName = "purpur-table";
|
|
18
17
|
|
|
19
|
-
type
|
|
18
|
+
type TableContentProps<TData extends RowData> = {
|
|
20
19
|
tanstackTable: Table<TData>;
|
|
21
20
|
tableRows: Row<TData>[];
|
|
22
|
-
showColumnFiltersEnabled: boolean;
|
|
23
21
|
fullWidth: boolean;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
stickyFirstColumn
|
|
29
|
-
getStickyColumn
|
|
30
|
-
isScrolled
|
|
31
|
-
showBorder
|
|
32
|
-
enableColumnDrag
|
|
33
|
-
activeId
|
|
22
|
+
tableHeader: React.ReactNode;
|
|
23
|
+
loading?: boolean;
|
|
24
|
+
skeletonRows?: number;
|
|
25
|
+
isEmptyTable?: boolean;
|
|
26
|
+
stickyFirstColumn?: boolean;
|
|
27
|
+
getStickyColumn?: (index: number) => boolean;
|
|
28
|
+
isScrolled?: boolean;
|
|
29
|
+
showBorder?: (index: number) => boolean;
|
|
30
|
+
enableColumnDrag?: boolean;
|
|
31
|
+
activeId?: UniqueIdentifier | null;
|
|
32
|
+
getColumnWidths?: () => (string | number)[];
|
|
33
|
+
variant?: "primary" | "secondary";
|
|
34
|
+
emptyTableHeadingTag?: HeadingTagType;
|
|
35
|
+
emptyTableCopy?: { title: string; description: string };
|
|
36
|
+
emptyTableIcon?: React.ReactNode;
|
|
34
37
|
};
|
|
35
38
|
|
|
36
|
-
export function
|
|
39
|
+
export function TableContent<TData extends RowData>({
|
|
40
|
+
tanstackTable,
|
|
37
41
|
tableRows,
|
|
38
|
-
showColumnFiltersEnabled,
|
|
39
42
|
fullWidth,
|
|
40
|
-
|
|
43
|
+
tableHeader,
|
|
44
|
+
loading,
|
|
45
|
+
skeletonRows,
|
|
46
|
+
isEmptyTable,
|
|
41
47
|
stickyFirstColumn,
|
|
42
48
|
getStickyColumn,
|
|
43
49
|
isScrolled,
|
|
44
50
|
showBorder,
|
|
45
51
|
enableColumnDrag,
|
|
46
52
|
activeId,
|
|
47
|
-
}: NormalTableContentProps<TData>) {
|
|
48
|
-
return (
|
|
49
|
-
<table
|
|
50
|
-
className={cx([
|
|
51
|
-
`${rootClassName}__table`,
|
|
52
|
-
{ [`${rootClassName}__table--full-width`]: fullWidth },
|
|
53
|
-
])}
|
|
54
|
-
>
|
|
55
|
-
<TableHeader columnFiltersEnabled={showColumnFiltersEnabled}>
|
|
56
|
-
{renderTableHeaders()}
|
|
57
|
-
</TableHeader>
|
|
58
|
-
<TableBody>
|
|
59
|
-
{tableRows.map((row, rowIndex) => (
|
|
60
|
-
<TableRow key={row.id} isSelected={row.getIsSelected()}>
|
|
61
|
-
{row.getVisibleCells().map((cell, cellIndex) => (
|
|
62
|
-
<TableRowCell
|
|
63
|
-
key={cell.id}
|
|
64
|
-
cell={cell}
|
|
65
|
-
isLastRow={rowIndex === tableRows.length - 1}
|
|
66
|
-
isFirstCell={cellIndex === 0}
|
|
67
|
-
isLastCell={cellIndex === row.getVisibleCells().length - 1}
|
|
68
|
-
stickyColumn={stickyFirstColumn && getStickyColumn(cellIndex)}
|
|
69
|
-
isScrolled={isScrolled}
|
|
70
|
-
showBorder={showBorder(cellIndex)}
|
|
71
|
-
enableColumnDrag={enableColumnDrag || false}
|
|
72
|
-
draggingActive={activeId === cell.column.id}
|
|
73
|
-
/>
|
|
74
|
-
))}
|
|
75
|
-
</TableRow>
|
|
76
|
-
))}
|
|
77
|
-
</TableBody>
|
|
78
|
-
</table>
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
type LoadingTableContentProps<TData extends RowData> = BaseTableContentProps<TData> & {
|
|
83
|
-
skeletonRows: number;
|
|
84
|
-
getStickyColumn: (index: number) => boolean;
|
|
85
|
-
stickyFirstColumn: boolean;
|
|
86
|
-
isScrolled: boolean;
|
|
87
|
-
showBorder: (index: number) => boolean;
|
|
88
|
-
getColumnWidths: () => (string | number)[];
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
export function LoadingTableContent<TData extends RowData>({
|
|
92
|
-
showColumnFiltersEnabled,
|
|
93
|
-
fullWidth,
|
|
94
|
-
renderTableHeaders,
|
|
95
|
-
skeletonRows,
|
|
96
|
-
getStickyColumn,
|
|
97
|
-
stickyFirstColumn,
|
|
98
|
-
isScrolled,
|
|
99
|
-
showBorder,
|
|
100
53
|
getColumnWidths,
|
|
101
|
-
}: LoadingTableContentProps<TData>) {
|
|
102
|
-
return (
|
|
103
|
-
<table
|
|
104
|
-
className={cx([
|
|
105
|
-
`${rootClassName}__table`,
|
|
106
|
-
{ [`${rootClassName}__table--full-width`]: fullWidth },
|
|
107
|
-
])}
|
|
108
|
-
>
|
|
109
|
-
<TableHeader columnFiltersEnabled={showColumnFiltersEnabled}>
|
|
110
|
-
{renderTableHeaders()}
|
|
111
|
-
</TableHeader>
|
|
112
|
-
<TableBody>
|
|
113
|
-
<LoadingTableRows
|
|
114
|
-
rowCount={skeletonRows}
|
|
115
|
-
getStickyColumn={getStickyColumn}
|
|
116
|
-
stickyFirstColumn={stickyFirstColumn}
|
|
117
|
-
isScrolled={isScrolled}
|
|
118
|
-
cellWidths={getColumnWidths()}
|
|
119
|
-
showBorder={showBorder}
|
|
120
|
-
/>
|
|
121
|
-
</TableBody>
|
|
122
|
-
</table>
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
type EmptyTableContentProps<TData extends RowData> = BaseTableContentProps<TData> & {
|
|
127
|
-
variant: "primary" | "secondary";
|
|
128
|
-
emptyTableHeadingTag: HeadingTagType;
|
|
129
|
-
emptyTableCopy: { title: string; description: string };
|
|
130
|
-
emptyTableIcon?: React.ReactNode;
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
export function EmptyTableContent<TData extends RowData>({
|
|
134
|
-
tanstackTable,
|
|
135
|
-
showColumnFiltersEnabled,
|
|
136
|
-
fullWidth,
|
|
137
|
-
renderTableHeaders,
|
|
138
54
|
variant,
|
|
139
55
|
emptyTableHeadingTag,
|
|
140
56
|
emptyTableCopy,
|
|
141
57
|
emptyTableIcon,
|
|
142
|
-
}:
|
|
58
|
+
}: TableContentProps<TData>) {
|
|
143
59
|
return (
|
|
144
60
|
<table
|
|
145
61
|
className={cx([
|
|
@@ -147,18 +63,46 @@ export function EmptyTableContent<TData extends RowData>({
|
|
|
147
63
|
{ [`${rootClassName}__table--full-width`]: fullWidth },
|
|
148
64
|
])}
|
|
149
65
|
>
|
|
150
|
-
|
|
151
|
-
{renderTableHeaders()}
|
|
152
|
-
</TableHeader>
|
|
66
|
+
{tableHeader}
|
|
153
67
|
<TableBody>
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
68
|
+
{loading && skeletonRows ? (
|
|
69
|
+
<LoadingTableRows
|
|
70
|
+
rowCount={skeletonRows}
|
|
71
|
+
getStickyColumn={getStickyColumn!}
|
|
72
|
+
stickyFirstColumn={stickyFirstColumn!}
|
|
73
|
+
isScrolled={isScrolled!}
|
|
74
|
+
cellWidths={getColumnWidths!()}
|
|
75
|
+
showBorder={showBorder!}
|
|
76
|
+
/>
|
|
77
|
+
) : isEmptyTable && emptyTableCopy && emptyTableHeadingTag ? (
|
|
78
|
+
<EmptyTable
|
|
79
|
+
variant={variant!}
|
|
80
|
+
tag={emptyTableHeadingTag}
|
|
81
|
+
title={emptyTableCopy.title}
|
|
82
|
+
description={emptyTableCopy.description}
|
|
83
|
+
colSpan={tanstackTable.getVisibleLeafColumns().length}
|
|
84
|
+
icon={emptyTableIcon}
|
|
85
|
+
/>
|
|
86
|
+
) : (
|
|
87
|
+
tableRows.map((row, rowIndex) => (
|
|
88
|
+
<TableRow key={row.id} isSelected={row.getIsSelected()}>
|
|
89
|
+
{row.getVisibleCells().map((cell, cellIndex) => (
|
|
90
|
+
<TableRowCell
|
|
91
|
+
key={cell.id}
|
|
92
|
+
cell={cell}
|
|
93
|
+
isLastRow={rowIndex === tableRows.length - 1}
|
|
94
|
+
isFirstCell={cellIndex === 0}
|
|
95
|
+
isLastCell={cellIndex === row.getVisibleCells().length - 1}
|
|
96
|
+
stickyColumn={stickyFirstColumn && getStickyColumn!(cellIndex)}
|
|
97
|
+
isScrolled={isScrolled!}
|
|
98
|
+
showBorder={showBorder!(cellIndex)}
|
|
99
|
+
enableColumnDrag={enableColumnDrag || false}
|
|
100
|
+
draggingActive={activeId === cell.column.id}
|
|
101
|
+
/>
|
|
102
|
+
))}
|
|
103
|
+
</TableRow>
|
|
104
|
+
))
|
|
105
|
+
)}
|
|
162
106
|
</TableBody>
|
|
163
107
|
</table>
|
|
164
108
|
);
|
|
@@ -489,7 +489,7 @@ const DraggableColumnItem = ({
|
|
|
489
489
|
>
|
|
490
490
|
<IconDragVertical className={cx(`${rootClassName}__draggable-handle-icon`)} size="sm" />
|
|
491
491
|
</div>
|
|
492
|
-
<
|
|
492
|
+
<Paragraph>{label}</Paragraph>
|
|
493
493
|
<VisuallyHidden id={`drag-instructions-${id}`}>
|
|
494
494
|
{copy.visibleColumns.ariaLabels.dragHandle.instructions}
|
|
495
495
|
</VisuallyHidden>
|
package/src/table.stories.tsx
CHANGED
|
@@ -403,6 +403,14 @@ manages filtering, sorting and pagination internally.
|
|
|
403
403
|
stepNumberPrefix: "Go to page",
|
|
404
404
|
};
|
|
405
405
|
|
|
406
|
+
const emptyTableProps = {
|
|
407
|
+
emptyTableCopy: {
|
|
408
|
+
title: args.emptyTableCopy?.title || "No data found",
|
|
409
|
+
description: args.emptyTableCopy?.description || "There are no items to display.",
|
|
410
|
+
},
|
|
411
|
+
emptyTableHeadingTag: args.emptyTableHeadingTag || "h2",
|
|
412
|
+
};
|
|
413
|
+
|
|
406
414
|
return renderTableContainer(
|
|
407
415
|
{ ...args, isExpanded: tableExpanded },
|
|
408
416
|
/* @ts-expect-error Props are incompatible. Storybook issue after adding argTypes. */
|
|
@@ -446,6 +454,9 @@ manages filtering, sorting and pagination internally.
|
|
|
446
454
|
stickyHeaders={args.stickyHeaders}
|
|
447
455
|
enableColumnDrag={args.enableColumnDrag}
|
|
448
456
|
columnDragAriaLabelsCopy={commonColumnDragAriaLabels}
|
|
457
|
+
emptyTableCopy={emptyTableProps.emptyTableCopy}
|
|
458
|
+
emptyTableHeadingTag={emptyTableProps.emptyTableHeadingTag}
|
|
459
|
+
emptyTableIcon={<IllustrativeIconTableQuestionDuocolorStatic />}
|
|
449
460
|
/>
|
|
450
461
|
);
|
|
451
462
|
},
|
package/src/table.tsx
CHANGED
|
@@ -38,8 +38,9 @@ export type {
|
|
|
38
38
|
|
|
39
39
|
import styles from "./table.module.scss";
|
|
40
40
|
import { TableActionBar } from "./table-action-bar";
|
|
41
|
-
import {
|
|
41
|
+
import { TableContent } from "./table-content";
|
|
42
42
|
import { TableExportDrawer } from "./table-export-drawer";
|
|
43
|
+
import { TableHeader } from "./table-header";
|
|
43
44
|
import { SortableTableHeaders, StandardTableHeaders } from "./table-headers";
|
|
44
45
|
import { TableSettingsDrawer, type TableSettingsDrawerCopyProps } from "./table-settings-drawer";
|
|
45
46
|
import { TableToolbar } from "./table-toolbar";
|
|
@@ -140,12 +141,12 @@ export const Table = <TData extends RowData>({
|
|
|
140
141
|
const [activeId, setActiveId] = useState<UniqueIdentifier | null>(null);
|
|
141
142
|
|
|
142
143
|
const classes = cx([
|
|
143
|
-
className,
|
|
144
144
|
rootClassName,
|
|
145
145
|
{
|
|
146
146
|
[`${rootClassName}--${variant}`]: variant,
|
|
147
147
|
[`${rootClassName}--without-toolbar`]: !enableToolbar || !settingsDrawerCopy,
|
|
148
148
|
},
|
|
149
|
+
className,
|
|
149
150
|
]);
|
|
150
151
|
|
|
151
152
|
// Only add row selection columns when enableRowSelection is true
|
|
@@ -204,7 +205,7 @@ export const Table = <TData extends RowData>({
|
|
|
204
205
|
...restProps,
|
|
205
206
|
});
|
|
206
207
|
|
|
207
|
-
const rowCount =
|
|
208
|
+
const rowCount = tanstackTable.getRowCount();
|
|
208
209
|
|
|
209
210
|
useEffect(() => {
|
|
210
211
|
if (onRowsCountChange) {
|
|
@@ -315,141 +316,101 @@ export const Table = <TData extends RowData>({
|
|
|
315
316
|
const tableRows = tanstackTable.getRowModel().rows;
|
|
316
317
|
const emptyTable = tableRows.length === 0 && Boolean(emptyTableCopy);
|
|
317
318
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
tanstackTable={tanstackTable}
|
|
387
|
-
tableRows={tableRows}
|
|
388
|
-
showColumnFiltersEnabled={showColumnFiltersEnabled}
|
|
389
|
-
fullWidth={fullWidth}
|
|
390
|
-
renderTableHeaders={renderTableHeaders}
|
|
391
|
-
skeletonRows={skeletonRows}
|
|
392
|
-
getStickyColumn={getStickyColumn}
|
|
393
|
-
stickyFirstColumn={stickyFirstColumn}
|
|
394
|
-
isScrolled={isScrolled}
|
|
395
|
-
showBorder={showBorder}
|
|
396
|
-
getColumnWidths={memoizedGetColumnWidths}
|
|
397
|
-
/>
|
|
398
|
-
);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
const isEmptyTable = tableRows.length === 0 && Boolean(emptyTableCopy);
|
|
402
|
-
if (isEmptyTable && emptyTableCopy && emptyTableHeadingTag) {
|
|
403
|
-
return (
|
|
404
|
-
<EmptyTableContent
|
|
405
|
-
tanstackTable={tanstackTable}
|
|
406
|
-
tableRows={tableRows}
|
|
407
|
-
showColumnFiltersEnabled={showColumnFiltersEnabled}
|
|
408
|
-
fullWidth={fullWidth}
|
|
409
|
-
renderTableHeaders={renderTableHeaders}
|
|
410
|
-
variant={variant}
|
|
411
|
-
emptyTableHeadingTag={emptyTableHeadingTag}
|
|
412
|
-
emptyTableCopy={emptyTableCopy}
|
|
413
|
-
emptyTableIcon={emptyTableIcon}
|
|
414
|
-
/>
|
|
415
|
-
);
|
|
416
|
-
}
|
|
319
|
+
// Extract header groups to avoid complex expression in dependency array
|
|
320
|
+
const headerGroups = tanstackTable.getHeaderGroups();
|
|
321
|
+
|
|
322
|
+
// Memoized table header to prevent re-renders and maintain filter focus
|
|
323
|
+
const tableHeader = React.useMemo(
|
|
324
|
+
() => (
|
|
325
|
+
<TableHeader columnFiltersEnabled={showColumnFiltersEnabled}>
|
|
326
|
+
{headerGroups.map((headerGroup) => {
|
|
327
|
+
if (enableColumnDrag && state?.columnOrder) {
|
|
328
|
+
return (
|
|
329
|
+
<SortableTableHeaders
|
|
330
|
+
key={headerGroup.id}
|
|
331
|
+
headerGroup={headerGroup}
|
|
332
|
+
tanstackTable={tanstackTable}
|
|
333
|
+
tableHasFilters={showColumnFiltersEnabled}
|
|
334
|
+
emptyTable={emptyTable}
|
|
335
|
+
stickyFirstColumn={stickyFirstColumn}
|
|
336
|
+
stickyHeaders={stickyHeaders}
|
|
337
|
+
isScrolled={isScrolled}
|
|
338
|
+
getStickyColumn={getStickyColumn}
|
|
339
|
+
showBorder={showBorder}
|
|
340
|
+
enableSorting={props.enableSorting || false}
|
|
341
|
+
sortingAriaLabels={sortingAriaLabels}
|
|
342
|
+
columnOrder={state.columnOrder}
|
|
343
|
+
activeId={activeId}
|
|
344
|
+
enableColumnDrag={enableColumnDrag}
|
|
345
|
+
columnDragAriaLabelsCopy={columnDragAriaLabelsCopy}
|
|
346
|
+
/>
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return (
|
|
351
|
+
<StandardTableHeaders
|
|
352
|
+
key={headerGroup.id}
|
|
353
|
+
headerGroup={headerGroup}
|
|
354
|
+
tanstackTable={tanstackTable}
|
|
355
|
+
tableHasFilters={showColumnFiltersEnabled}
|
|
356
|
+
emptyTable={emptyTable}
|
|
357
|
+
stickyFirstColumn={stickyFirstColumn}
|
|
358
|
+
stickyHeaders={stickyHeaders}
|
|
359
|
+
isScrolled={isScrolled}
|
|
360
|
+
getStickyColumn={getStickyColumn}
|
|
361
|
+
showBorder={showBorder}
|
|
362
|
+
enableSorting={props.enableSorting || false}
|
|
363
|
+
sortingAriaLabels={sortingAriaLabels}
|
|
364
|
+
/>
|
|
365
|
+
);
|
|
366
|
+
})}
|
|
367
|
+
</TableHeader>
|
|
368
|
+
),
|
|
369
|
+
[
|
|
370
|
+
showColumnFiltersEnabled,
|
|
371
|
+
headerGroups,
|
|
372
|
+
enableColumnDrag,
|
|
373
|
+
state?.columnOrder,
|
|
374
|
+
props.enableSorting,
|
|
375
|
+
sortingAriaLabels,
|
|
376
|
+
columnDragAriaLabelsCopy,
|
|
377
|
+
tanstackTable,
|
|
378
|
+
emptyTable,
|
|
379
|
+
stickyFirstColumn,
|
|
380
|
+
stickyHeaders,
|
|
381
|
+
isScrolled,
|
|
382
|
+
getStickyColumn,
|
|
383
|
+
showBorder,
|
|
384
|
+
activeId,
|
|
385
|
+
]
|
|
386
|
+
);
|
|
417
387
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
renderTableHeaders,
|
|
445
|
-
showBorder,
|
|
446
|
-
showColumnFiltersEnabled,
|
|
447
|
-
skeletonRows,
|
|
448
|
-
stickyFirstColumn,
|
|
449
|
-
tableRows,
|
|
450
|
-
tanstackTable,
|
|
451
|
-
variant,
|
|
452
|
-
]);
|
|
388
|
+
const isEmptyTable = tableRows.length === 0 && Boolean(emptyTableCopy);
|
|
389
|
+
|
|
390
|
+
const tableContent = (
|
|
391
|
+
<TableContent
|
|
392
|
+
tanstackTable={tanstackTable}
|
|
393
|
+
tableRows={tableRows}
|
|
394
|
+
fullWidth={fullWidth}
|
|
395
|
+
tableHeader={tableHeader}
|
|
396
|
+
loading={loading}
|
|
397
|
+
skeletonRows={skeletonRows}
|
|
398
|
+
isEmptyTable={isEmptyTable}
|
|
399
|
+
stickyFirstColumn={stickyFirstColumn}
|
|
400
|
+
getStickyColumn={getStickyColumn}
|
|
401
|
+
isScrolled={isScrolled}
|
|
402
|
+
showBorder={showBorder}
|
|
403
|
+
enableColumnDrag={enableColumnDrag}
|
|
404
|
+
activeId={activeId}
|
|
405
|
+
getColumnWidths={() =>
|
|
406
|
+
tanstackTable.getVisibleLeafColumns().map((column) => column.getSize() || "100%")
|
|
407
|
+
}
|
|
408
|
+
variant={variant}
|
|
409
|
+
emptyTableHeadingTag={emptyTableHeadingTag}
|
|
410
|
+
emptyTableCopy={emptyTableCopy}
|
|
411
|
+
emptyTableIcon={emptyTableIcon}
|
|
412
|
+
/>
|
|
413
|
+
);
|
|
453
414
|
|
|
454
415
|
return (
|
|
455
416
|
<div id={`${uid}-table`} className={classes}>
|
|
@@ -491,10 +452,10 @@ export const Table = <TData extends RowData>({
|
|
|
491
452
|
columnDragAriaLabelsCopy={columnDragAriaLabelsCopy}
|
|
492
453
|
rootClassName={rootClassName}
|
|
493
454
|
>
|
|
494
|
-
{
|
|
455
|
+
{tableContent}
|
|
495
456
|
</DraggableTable>
|
|
496
457
|
) : (
|
|
497
|
-
|
|
458
|
+
tableContent
|
|
498
459
|
)}
|
|
499
460
|
</div>
|
|
500
461
|
{paginationComponent}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from "react";
|
|
2
2
|
import { IconDragHorizontal } from "@purpurds/icon/drag-horizontal";
|
|
3
3
|
import c from "classnames/bind";
|
|
4
4
|
|
|
@@ -7,52 +7,33 @@ import styles from "./table.module.scss";
|
|
|
7
7
|
const cx = c.bind(styles);
|
|
8
8
|
const rootClassName = "purpur-table-column-header-cell";
|
|
9
9
|
|
|
10
|
-
export function useDragHandle() {
|
|
11
|
-
const [mouseDownActive, setMouseDownActive] = useState(false);
|
|
12
|
-
|
|
13
|
-
const handleMouseDown = () => {
|
|
14
|
-
setMouseDownActive(true);
|
|
15
|
-
window.addEventListener("mouseup", handleMouseUp, { once: true });
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const handleMouseUp = () => {
|
|
19
|
-
setMouseDownActive(false);
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
return { mouseDownActive, handleMouseDown };
|
|
23
|
-
}
|
|
24
|
-
|
|
25
10
|
export type TableColumnDragHandleProps = {
|
|
26
|
-
onMouseDown: () => void;
|
|
27
11
|
overlayActive?: boolean;
|
|
28
12
|
isFirstColumn: boolean;
|
|
29
13
|
isLastColumn: boolean;
|
|
30
14
|
columnDragAriaLabel: string;
|
|
15
|
+
// Add any additional props from listeners
|
|
16
|
+
[key: string]: unknown;
|
|
31
17
|
};
|
|
32
18
|
|
|
33
19
|
export function TableColumnDragHandle({
|
|
34
|
-
onMouseDown,
|
|
35
20
|
overlayActive,
|
|
36
21
|
isFirstColumn,
|
|
37
22
|
isLastColumn,
|
|
38
23
|
columnDragAriaLabel,
|
|
24
|
+
...dragListeners // Capture the listeners from useSortable
|
|
39
25
|
}: TableColumnDragHandleProps) {
|
|
40
26
|
return (
|
|
41
27
|
<div
|
|
28
|
+
role="button"
|
|
29
|
+
tabIndex={0}
|
|
42
30
|
className={cx(`${rootClassName}__drag-handle`, {
|
|
43
31
|
[`${rootClassName}__border-radius-first-cell`]: isFirstColumn && !overlayActive,
|
|
44
32
|
[`${rootClassName}__border-radius-last-cell`]: isLastColumn && !overlayActive,
|
|
45
33
|
[`${rootClassName}__drag-handle--active`]: overlayActive,
|
|
46
34
|
})}
|
|
47
|
-
role="button"
|
|
48
|
-
tabIndex={0}
|
|
49
35
|
aria-label={columnDragAriaLabel}
|
|
50
|
-
|
|
51
|
-
onKeyDown={(e) => {
|
|
52
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
53
|
-
onMouseDown();
|
|
54
|
-
}
|
|
55
|
-
}}
|
|
36
|
+
{...dragListeners}
|
|
56
37
|
>
|
|
57
38
|
<IconDragHorizontal className={cx(`${rootClassName}__drag-handle-icon`)} size="sm" />
|
|
58
39
|
</div>
|