@purpurds/table 8.3.1 → 8.5.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 +205 -35
- package/dist/drag-indicator-circle.d.ts +13 -0
- package/dist/drag-indicator-circle.d.ts.map +1 -0
- package/dist/draggable-table.d.ts +23 -0
- package/dist/draggable-table.d.ts.map +1 -0
- package/dist/empty-table.d.ts +14 -0
- package/dist/empty-table.d.ts.map +1 -0
- package/dist/loading-table-rows.d.ts +13 -0
- package/dist/loading-table-rows.d.ts.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/table-body.d.ts +2 -2
- package/dist/table-body.d.ts.map +1 -1
- package/dist/table-column-header-cell.d.ts +15 -2
- package/dist/table-column-header-cell.d.ts.map +1 -1
- package/dist/table-content.d.ts +42 -0
- package/dist/table-content.d.ts.map +1 -0
- package/dist/table-headers.d.ts +28 -0
- package/dist/table-headers.d.ts.map +1 -0
- package/dist/table-row-cell-skeleton.d.ts +1 -1
- package/dist/table-row-cell-skeleton.d.ts.map +1 -1
- package/dist/table-row-cell.d.ts +5 -2
- package/dist/table-row-cell.d.ts.map +1 -1
- package/dist/table-row.d.ts +2 -2
- package/dist/table-row.d.ts.map +1 -1
- package/dist/table-settings-drawer.d.ts +44 -11
- package/dist/table-settings-drawer.d.ts.map +1 -1
- package/dist/table.cjs.js +89 -85
- package/dist/table.cjs.js.map +1 -1
- package/dist/table.d.ts +3 -3
- package/dist/table.d.ts.map +1 -1
- package/dist/table.es.js +14040 -9810
- package/dist/table.es.js.map +1 -1
- package/dist/test-utils/helpers.d.ts +1 -0
- package/dist/test-utils/helpers.d.ts.map +1 -1
- package/dist/types.d.ts +23 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/use-drag-handle.hook.d.ts +15 -0
- package/dist/use-drag-handle.hook.d.ts.map +1 -0
- package/dist/use-drag-indicator-position.hook.d.ts +19 -0
- package/dist/use-drag-indicator-position.hook.d.ts.map +1 -0
- package/dist/use-drop-indicator.hook.d.ts +15 -0
- package/dist/use-drop-indicator.hook.d.ts.map +1 -0
- package/dist/use-element-visibility.hook.d.ts +4 -0
- package/dist/use-element-visibility.hook.d.ts.map +1 -0
- package/dist/use-table-scroll.hook.d.ts +6 -0
- package/dist/use-table-scroll.hook.d.ts.map +1 -0
- package/dist/utils/custom-keyboard-coordinates.d.ts +8 -0
- package/dist/utils/custom-keyboard-coordinates.d.ts.map +1 -0
- package/package.json +27 -23
- package/src/drag-indicator-circle.tsx +36 -0
- package/src/draggable-table.test.tsx +381 -0
- package/src/draggable-table.tsx +191 -0
- package/src/empty-table.tsx +54 -0
- package/src/loading-table-rows.tsx +41 -0
- package/src/table-body.tsx +1 -3
- package/src/table-column-header-cell.tsx +135 -64
- package/src/table-content-drag.test.tsx +505 -0
- package/src/table-content.tsx +165 -0
- package/src/table-dnd-integration.test.tsx +425 -0
- package/src/table-drag-and-drop.test.tsx +276 -0
- package/src/table-headers.tsx +118 -0
- package/src/table-row-cell-skeleton.tsx +1 -1
- package/src/table-row-cell.test.tsx +2 -1
- package/src/table-row-cell.tsx +42 -31
- package/src/table-row.tsx +1 -3
- package/src/table-settings-drawer.module.scss +165 -2
- package/src/table-settings-drawer.test.tsx +0 -99
- package/src/table-settings-drawer.tsx +359 -53
- package/src/table.module.scss +191 -30
- package/src/table.stories.tsx +60 -4
- package/src/table.test.tsx +5 -1
- package/src/table.tsx +255 -213
- package/src/test-utils/helpers.ts +2 -0
- package/src/types.ts +25 -2
- package/src/use-drag-handle.hook.tsx +60 -0
- package/src/use-drag-handle.test.tsx +380 -0
- package/src/use-drag-indicator-position.hook.ts +74 -0
- package/src/use-drop-indicator.hook.ts +46 -0
- package/src/use-element-visibility.hook.ts +28 -0
- package/src/use-table-scroll.hook.tsx +30 -0
- package/src/utils/custom-keyboard-coordinates.ts +83 -0
- package/vitest.setup.ts +1 -1
package/src/table.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import React, { type ReactElement, useEffect, useId, useRef, useState } from "react";
|
|
1
|
+
import React, { type ReactElement, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
2
|
+
import type { DragEndEvent, UniqueIdentifier } from "@dnd-kit/core";
|
|
2
3
|
import type {
|
|
3
4
|
ColumnDef,
|
|
4
5
|
ColumnFiltersState,
|
|
@@ -18,11 +19,11 @@ import {
|
|
|
18
19
|
useReactTable,
|
|
19
20
|
} from "@tanstack/react-table";
|
|
20
21
|
export { createColumnHelper } from "@tanstack/react-table";
|
|
21
|
-
import { Heading, type HeadingTagType } from "@purpurds/heading";
|
|
22
22
|
import { type PaginationProps } from "@purpurds/pagination";
|
|
23
|
-
import { Paragraph } from "@purpurds/paragraph";
|
|
24
23
|
import c from "classnames/bind";
|
|
25
24
|
|
|
25
|
+
import { DraggableTable } from "./draggable-table";
|
|
26
|
+
|
|
26
27
|
export type {
|
|
27
28
|
ColumnDef,
|
|
28
29
|
ColumnFiltersState,
|
|
@@ -37,29 +38,28 @@ export type {
|
|
|
37
38
|
|
|
38
39
|
import styles from "./table.module.scss";
|
|
39
40
|
import { TableActionBar } from "./table-action-bar";
|
|
40
|
-
import
|
|
41
|
-
import { TableColumnHeaderCell } from "./table-column-header-cell";
|
|
41
|
+
import { EmptyTableContent, LoadingTableContent, NormalTableContent } from "./table-content";
|
|
42
42
|
import { TableExportDrawer } from "./table-export-drawer";
|
|
43
|
-
import {
|
|
44
|
-
import
|
|
45
|
-
import TableRowCell from "./table-row-cell";
|
|
46
|
-
import TableRowCellSkeleton from "./table-row-cell-skeleton";
|
|
47
|
-
import { TableSettingsDrawer } from "./table-settings-drawer";
|
|
43
|
+
import { SortableTableHeaders, StandardTableHeaders } from "./table-headers";
|
|
44
|
+
import { TableSettingsDrawer, type TableSettingsDrawerCopyProps } from "./table-settings-drawer";
|
|
48
45
|
import { TableToolbar } from "./table-toolbar";
|
|
49
|
-
import {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
46
|
+
import type {
|
|
47
|
+
WithActionBarProps,
|
|
48
|
+
WithColumnDragProps,
|
|
49
|
+
WithEmptyTableProps,
|
|
50
|
+
WithLoadingProps,
|
|
51
|
+
WithoutActionBarProps,
|
|
52
|
+
WithoutColumnDragProps,
|
|
53
|
+
WithoutEmptyTableProps,
|
|
54
|
+
WithoutLoadingProps,
|
|
55
|
+
WithoutRowSelectionProps,
|
|
56
|
+
WithoutSortingProps,
|
|
57
|
+
WithoutToolbarProps,
|
|
58
|
+
WithRowSelectionProps,
|
|
59
|
+
WithSortingProps,
|
|
60
|
+
WithToolbarProps,
|
|
62
61
|
} from "./types";
|
|
62
|
+
import { useTableScroll } from "./use-table-scroll.hook";
|
|
63
63
|
import { filterOnFilterKey, sortOnBadgeValue, sortOnBadgeVariant } from "./utils/custom-functions";
|
|
64
64
|
|
|
65
65
|
const cx = c.bind(styles);
|
|
@@ -81,6 +81,7 @@ export type TableProps<TData extends RowData> = {
|
|
|
81
81
|
(WithEmptyTableProps | WithoutEmptyTableProps) &
|
|
82
82
|
(WithoutLoadingProps | WithLoadingProps) &
|
|
83
83
|
(WithoutRowSelectionProps | WithRowSelectionProps<TData>) &
|
|
84
|
+
(WithColumnDragProps | WithoutColumnDragProps) &
|
|
84
85
|
Partial<TableOptions<TData>>;
|
|
85
86
|
|
|
86
87
|
const rootClassName = "purpur-table";
|
|
@@ -120,10 +121,10 @@ export const Table = <TData extends RowData>({
|
|
|
120
121
|
onSecondaryButtonClick,
|
|
121
122
|
setShowOnlySelectedRows,
|
|
122
123
|
drawerZIndex = 6,
|
|
124
|
+
enableColumnDrag,
|
|
125
|
+
columnDragAriaLabelsCopy,
|
|
123
126
|
...props
|
|
124
127
|
}: TableProps<TData>) => {
|
|
125
|
-
const [selectedRowsCount, setSelectedRowsCount] = useState(0);
|
|
126
|
-
const [actionBarVisible, setActionBarVisible] = useState(false);
|
|
127
128
|
const [isSettingsDrawerOpen, setSettingsDrawerIsOpen] = useState(false);
|
|
128
129
|
const [isExportDrawerOpen, setExportDrawerIsOpen] = useState(false);
|
|
129
130
|
const [showColumnFiltersEnabled, setShowColumnFiltersEnabled] = useState(
|
|
@@ -132,10 +133,11 @@ export const Table = <TData extends RowData>({
|
|
|
132
133
|
const [stickyFirstColumn, setStickyFirstColumn] = useState(stickyFirstColumnProp);
|
|
133
134
|
const [stickyHeaders, setStickyHeaders] = useState(stickyHeadersProp);
|
|
134
135
|
const prevShowOnlySelectedRows = useRef(showOnlySelectedRows);
|
|
135
|
-
const [isScrolled, setIsScrolled] = useState(false);
|
|
136
136
|
const tableContainerRef = useRef<HTMLTableElement>(null);
|
|
137
137
|
const uid = useId();
|
|
138
|
-
const
|
|
138
|
+
const isScrolled = useTableScroll(tableContainerRef);
|
|
139
|
+
|
|
140
|
+
const [activeId, setActiveId] = useState<UniqueIdentifier | null>(null);
|
|
139
141
|
|
|
140
142
|
const classes = cx([
|
|
141
143
|
className,
|
|
@@ -146,13 +148,13 @@ export const Table = <TData extends RowData>({
|
|
|
146
148
|
},
|
|
147
149
|
]);
|
|
148
150
|
|
|
149
|
-
// Only add row selection columns when
|
|
150
|
-
if (props.enableRowSelection
|
|
151
|
+
// Only add row selection columns when enableRowSelection is true
|
|
152
|
+
if (props.enableRowSelection) {
|
|
151
153
|
columns = props.enableMultiRowSelection
|
|
152
154
|
? [
|
|
153
155
|
{
|
|
154
156
|
id: "row-selection",
|
|
155
|
-
header:
|
|
157
|
+
header: rowSelectionAriaLabels?.header,
|
|
156
158
|
size: 25,
|
|
157
159
|
meta: {
|
|
158
160
|
cellType: "rowSelection",
|
|
@@ -164,7 +166,7 @@ export const Table = <TData extends RowData>({
|
|
|
164
166
|
: [
|
|
165
167
|
{
|
|
166
168
|
id: "row-toggle",
|
|
167
|
-
header:
|
|
169
|
+
header: rowSelectionAriaLabels?.header,
|
|
168
170
|
size: 25,
|
|
169
171
|
meta: {
|
|
170
172
|
cellType: "rowToggle",
|
|
@@ -202,54 +204,62 @@ export const Table = <TData extends RowData>({
|
|
|
202
204
|
...restProps,
|
|
203
205
|
});
|
|
204
206
|
|
|
207
|
+
const rowCount = useMemo(() => tanstackTable.getRowCount(), [tanstackTable]);
|
|
208
|
+
|
|
205
209
|
useEffect(() => {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
};
|
|
210
|
+
if (onRowsCountChange) {
|
|
211
|
+
onRowsCountChange(rowCount);
|
|
212
|
+
}
|
|
213
|
+
}, [rowCount, onRowsCountChange]);
|
|
212
214
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
215
|
+
// Handle drag end - Only used when DnD is enabled
|
|
216
|
+
const handleDragEnd = (event: DragEndEvent) => {
|
|
217
|
+
const { active, over } = event;
|
|
218
|
+
|
|
219
|
+
// Don't allow moving row selection columns
|
|
220
|
+
if (active.id === "row-selection" || active.id === "row-toggle") {
|
|
221
|
+
setActiveId(null);
|
|
222
|
+
return;
|
|
216
223
|
}
|
|
217
224
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
}, []);
|
|
225
|
+
// Don't allow dropping over row selection columns
|
|
226
|
+
if (over && (over.id === "row-selection" || over.id === "row-toggle")) {
|
|
227
|
+
setActiveId(null);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
224
230
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
231
|
+
if (over && active.id !== over.id) {
|
|
232
|
+
const currentOrder = tanstackTable.getAllLeafColumns().map((column) => column.id);
|
|
233
|
+
const oldIndex = currentOrder.indexOf(String(active.id));
|
|
234
|
+
const newIndex = currentOrder.indexOf(String(over.id));
|
|
235
|
+
|
|
236
|
+
if (oldIndex !== -1 && newIndex !== -1) {
|
|
237
|
+
const newOrder = [...currentOrder];
|
|
238
|
+
const [removed] = newOrder.splice(oldIndex, 1);
|
|
239
|
+
newOrder.splice(newIndex, 0, removed);
|
|
240
|
+
tanstackTable.setColumnOrder(newOrder);
|
|
234
241
|
}
|
|
235
|
-
prevShowOnlySelectedRows.current = showOnlySelectedRows;
|
|
236
242
|
}
|
|
237
|
-
}, [showOnlySelectedRows, tanstackTable]);
|
|
238
243
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
onRowsCountChange(tanstackTable.getRowCount());
|
|
242
|
-
}
|
|
243
|
-
}, [state, onRowsCountChange, tanstackTable]);
|
|
244
|
+
setActiveId(null);
|
|
245
|
+
};
|
|
244
246
|
|
|
245
247
|
useEffect(() => {
|
|
246
|
-
if (
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
setActionBarVisible(newLength > 0);
|
|
248
|
+
if (showOnlySelectedRows !== prevShowOnlySelectedRows.current) {
|
|
249
|
+
tanstackTable.setPageIndex(0);
|
|
250
|
+
prevShowOnlySelectedRows.current = showOnlySelectedRows;
|
|
250
251
|
}
|
|
252
|
+
}, [showOnlySelectedRows, tanstackTable]);
|
|
253
|
+
|
|
254
|
+
const selectedRowsData = useMemo(() => {
|
|
255
|
+
if (!state?.rowSelection) return { count: 0, visible: false };
|
|
256
|
+
const count = Object.keys(state.rowSelection).length;
|
|
257
|
+
return { count, visible: count > 0 };
|
|
251
258
|
}, [state?.rowSelection]);
|
|
252
259
|
|
|
260
|
+
const selectedRowsCount = selectedRowsData.count;
|
|
261
|
+
const actionBarVisible = selectedRowsData.visible;
|
|
262
|
+
|
|
253
263
|
const handleCancelSelection = () => {
|
|
254
264
|
tanstackTable.resetRowSelection();
|
|
255
265
|
setShowOnlySelectedRows?.(false);
|
|
@@ -261,11 +271,14 @@ export const Table = <TData extends RowData>({
|
|
|
261
271
|
}
|
|
262
272
|
};
|
|
263
273
|
|
|
264
|
-
const getStickyColumn = (
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
274
|
+
const getStickyColumn = React.useCallback(
|
|
275
|
+
(index: number) => {
|
|
276
|
+
// When rowSelectionEnabled is true, the first two columns are sticky
|
|
277
|
+
// Otherwise, only the first column is sticky
|
|
278
|
+
return props.enableRowSelection ? index <= 1 : index === 0;
|
|
279
|
+
},
|
|
280
|
+
[props.enableRowSelection]
|
|
281
|
+
);
|
|
269
282
|
|
|
270
283
|
const handleResetColumnFilters = () => {
|
|
271
284
|
tanstackTable.resetColumnFilters();
|
|
@@ -284,62 +297,159 @@ export const Table = <TData extends RowData>({
|
|
|
284
297
|
};
|
|
285
298
|
|
|
286
299
|
const handleResetSettings = () => {
|
|
287
|
-
setShowColumnFiltersEnabled(
|
|
288
|
-
setStickyFirstColumn(
|
|
289
|
-
setStickyHeaders(
|
|
290
|
-
|
|
300
|
+
setShowColumnFiltersEnabled(Boolean(props.enableFilters));
|
|
301
|
+
setStickyFirstColumn(stickyFirstColumnProp);
|
|
302
|
+
setStickyHeaders(stickyHeadersProp);
|
|
303
|
+
tanstackTable.resetColumnOrder();
|
|
291
304
|
tanstackTable.resetColumnVisibility();
|
|
292
305
|
};
|
|
293
306
|
|
|
294
|
-
const showBorder = (
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
307
|
+
const showBorder = React.useCallback(
|
|
308
|
+
(index: number) => {
|
|
309
|
+
// Only show the border for sticky columns when the table is scrolled
|
|
310
|
+
return isScrolled && stickyFirstColumn && getStickyColumn(index);
|
|
311
|
+
},
|
|
312
|
+
[isScrolled, stickyFirstColumn, getStickyColumn]
|
|
313
|
+
);
|
|
298
314
|
|
|
299
315
|
const tableRows = tanstackTable.getRowModel().rows;
|
|
300
316
|
const emptyTable = tableRows.length === 0 && Boolean(emptyTableCopy);
|
|
301
317
|
|
|
302
|
-
const
|
|
318
|
+
const memoizedGetColumnWidths = React.useCallback(() => {
|
|
303
319
|
return tanstackTable.getAllColumns().map((column) => column.getSize() || "100%");
|
|
304
|
-
};
|
|
320
|
+
}, [tanstackTable]);
|
|
321
|
+
|
|
322
|
+
// Render table headers with or without drag functionality
|
|
323
|
+
const renderTableHeaders = React.useCallback(() => {
|
|
324
|
+
return tanstackTable.getHeaderGroups().map((headerGroup) => {
|
|
325
|
+
if (enableColumnDrag && state?.columnOrder) {
|
|
326
|
+
return (
|
|
327
|
+
<SortableTableHeaders
|
|
328
|
+
key={headerGroup.id}
|
|
329
|
+
headerGroup={headerGroup}
|
|
330
|
+
tanstackTable={tanstackTable}
|
|
331
|
+
tableHasFilters={showColumnFiltersEnabled}
|
|
332
|
+
emptyTable={emptyTable}
|
|
333
|
+
stickyFirstColumn={stickyFirstColumn}
|
|
334
|
+
stickyHeaders={stickyHeaders}
|
|
335
|
+
isScrolled={isScrolled}
|
|
336
|
+
getStickyColumn={getStickyColumn}
|
|
337
|
+
showBorder={showBorder}
|
|
338
|
+
enableSorting={props.enableSorting || false}
|
|
339
|
+
sortingAriaLabels={sortingAriaLabels}
|
|
340
|
+
columnOrder={state.columnOrder}
|
|
341
|
+
activeId={activeId}
|
|
342
|
+
enableColumnDrag={enableColumnDrag}
|
|
343
|
+
columnDragAriaLabelsCopy={columnDragAriaLabelsCopy}
|
|
344
|
+
/>
|
|
345
|
+
);
|
|
346
|
+
}
|
|
305
347
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
348
|
+
return (
|
|
349
|
+
<StandardTableHeaders
|
|
350
|
+
key={headerGroup.id}
|
|
351
|
+
headerGroup={headerGroup}
|
|
352
|
+
tanstackTable={tanstackTable}
|
|
353
|
+
tableHasFilters={showColumnFiltersEnabled}
|
|
354
|
+
emptyTable={emptyTable}
|
|
355
|
+
stickyFirstColumn={stickyFirstColumn}
|
|
356
|
+
stickyHeaders={stickyHeaders}
|
|
357
|
+
isScrolled={isScrolled}
|
|
358
|
+
getStickyColumn={getStickyColumn}
|
|
359
|
+
showBorder={showBorder}
|
|
360
|
+
enableSorting={props.enableSorting || false}
|
|
361
|
+
sortingAriaLabels={sortingAriaLabels}
|
|
362
|
+
/>
|
|
363
|
+
);
|
|
364
|
+
});
|
|
365
|
+
}, [
|
|
366
|
+
activeId,
|
|
367
|
+
columnDragAriaLabelsCopy,
|
|
368
|
+
emptyTable,
|
|
369
|
+
enableColumnDrag,
|
|
370
|
+
getStickyColumn,
|
|
371
|
+
isScrolled,
|
|
372
|
+
props.enableSorting,
|
|
373
|
+
showBorder,
|
|
374
|
+
showColumnFiltersEnabled,
|
|
375
|
+
sortingAriaLabels,
|
|
376
|
+
state?.columnOrder,
|
|
377
|
+
stickyFirstColumn,
|
|
378
|
+
stickyHeaders,
|
|
379
|
+
tanstackTable,
|
|
380
|
+
]);
|
|
381
|
+
|
|
382
|
+
const renderTableContent = React.useCallback(() => {
|
|
383
|
+
if (loading && skeletonRows) {
|
|
384
|
+
return (
|
|
385
|
+
<LoadingTableContent
|
|
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
|
+
}
|
|
417
|
+
|
|
418
|
+
return (
|
|
419
|
+
<NormalTableContent
|
|
420
|
+
tanstackTable={tanstackTable}
|
|
421
|
+
tableRows={tableRows}
|
|
422
|
+
showColumnFiltersEnabled={showColumnFiltersEnabled}
|
|
423
|
+
fullWidth={fullWidth}
|
|
424
|
+
renderTableHeaders={renderTableHeaders}
|
|
311
425
|
stickyFirstColumn={stickyFirstColumn}
|
|
426
|
+
getStickyColumn={getStickyColumn}
|
|
312
427
|
isScrolled={isScrolled}
|
|
313
|
-
cellWidths={getColumnWidths()}
|
|
314
428
|
showBorder={showBorder}
|
|
429
|
+
enableColumnDrag={enableColumnDrag || false}
|
|
430
|
+
activeId={activeId}
|
|
315
431
|
/>
|
|
316
|
-
) : emptyTable && emptyTableCopy && emptyTableHeadingTag ? (
|
|
317
|
-
<EmptyTable
|
|
318
|
-
variant={variant}
|
|
319
|
-
tag={emptyTableHeadingTag}
|
|
320
|
-
title={emptyTableCopy.title}
|
|
321
|
-
description={emptyTableCopy.description}
|
|
322
|
-
colSpan={tanstackTable.getVisibleLeafColumns().length}
|
|
323
|
-
icon={emptyTableIcon}
|
|
324
|
-
/>
|
|
325
|
-
) : (
|
|
326
|
-
tableRows.map((row, rowIndex) => (
|
|
327
|
-
<TableRow key={row.id} isSelected={row.getIsSelected()}>
|
|
328
|
-
{row.getVisibleCells().map((cell, cellIndex) => (
|
|
329
|
-
<TableRowCell
|
|
330
|
-
key={cell.id}
|
|
331
|
-
cell={cell}
|
|
332
|
-
isLastRow={rowIndex === tableRows.length - 1}
|
|
333
|
-
isFirstCell={cellIndex === 0}
|
|
334
|
-
isLastCell={cellIndex === row.getVisibleCells().length - 1}
|
|
335
|
-
stickyColumn={stickyFirstColumn && getStickyColumn(cellIndex)}
|
|
336
|
-
isScrolled={isScrolled}
|
|
337
|
-
showBorder={showBorder(cellIndex)}
|
|
338
|
-
/>
|
|
339
|
-
))}
|
|
340
|
-
</TableRow>
|
|
341
|
-
))
|
|
342
432
|
);
|
|
433
|
+
}, [
|
|
434
|
+
activeId,
|
|
435
|
+
emptyTableCopy,
|
|
436
|
+
emptyTableHeadingTag,
|
|
437
|
+
emptyTableIcon,
|
|
438
|
+
enableColumnDrag,
|
|
439
|
+
fullWidth,
|
|
440
|
+
getStickyColumn,
|
|
441
|
+
isScrolled,
|
|
442
|
+
loading,
|
|
443
|
+
memoizedGetColumnWidths,
|
|
444
|
+
renderTableHeaders,
|
|
445
|
+
showBorder,
|
|
446
|
+
showColumnFiltersEnabled,
|
|
447
|
+
skeletonRows,
|
|
448
|
+
stickyFirstColumn,
|
|
449
|
+
tableRows,
|
|
450
|
+
tanstackTable,
|
|
451
|
+
variant,
|
|
452
|
+
]);
|
|
343
453
|
|
|
344
454
|
return (
|
|
345
455
|
<div id={`${uid}-table`} className={classes}>
|
|
@@ -368,34 +478,24 @@ export const Table = <TData extends RowData>({
|
|
|
368
478
|
})}
|
|
369
479
|
ref={tableContainerRef}
|
|
370
480
|
>
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
{
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
{
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
{...(props.enableSorting && sortingAriaLabels
|
|
390
|
-
? { enableSorting: props.enableSorting, sortingAriaLabels }
|
|
391
|
-
: { enableSorting: false })}
|
|
392
|
-
/>
|
|
393
|
-
))}
|
|
394
|
-
</TableRow>
|
|
395
|
-
))}
|
|
396
|
-
</TableHeader>
|
|
397
|
-
<TableBody>{tableBodyContent}</TableBody>
|
|
398
|
-
</table>
|
|
481
|
+
{enableColumnDrag && columnDragAriaLabelsCopy ? (
|
|
482
|
+
<DraggableTable
|
|
483
|
+
activeId={activeId}
|
|
484
|
+
setActiveId={setActiveId}
|
|
485
|
+
handleDragEnd={handleDragEnd}
|
|
486
|
+
tableRows={tableRows}
|
|
487
|
+
tanstackTable={tanstackTable}
|
|
488
|
+
variant={variant}
|
|
489
|
+
fullWidth={fullWidth}
|
|
490
|
+
showColumnFiltersEnabled={showColumnFiltersEnabled}
|
|
491
|
+
columnDragAriaLabelsCopy={columnDragAriaLabelsCopy}
|
|
492
|
+
rootClassName={rootClassName}
|
|
493
|
+
>
|
|
494
|
+
{renderTableContent()}
|
|
495
|
+
</DraggableTable>
|
|
496
|
+
) : (
|
|
497
|
+
renderTableContent()
|
|
498
|
+
)}
|
|
399
499
|
</div>
|
|
400
500
|
{paginationComponent}
|
|
401
501
|
{enableActionBar && actionBarTotalRowCount && actionbarCopy && onPrimaryButtonClick && (
|
|
@@ -417,18 +517,27 @@ export const Table = <TData extends RowData>({
|
|
|
417
517
|
setShowColumnFiltersEnabled={setShowColumnFiltersEnabled}
|
|
418
518
|
setStickyFirstColumn={setStickyFirstColumn}
|
|
419
519
|
setStickyHeaders={setStickyHeaders}
|
|
420
|
-
getAllColumns={tanstackTable.
|
|
520
|
+
getAllColumns={tanstackTable.getAllLeafColumns}
|
|
421
521
|
isDrawerOpen={isSettingsDrawerOpen}
|
|
422
522
|
showColumnFilters={showColumnFiltersEnabled}
|
|
423
523
|
stickyFirstColumn={stickyFirstColumn}
|
|
424
524
|
stickyHeaders={stickyHeaders}
|
|
425
|
-
copy={settingsDrawerCopy}
|
|
426
525
|
onResetSettings={handleResetSettings}
|
|
427
526
|
columnFiltersEnabled={Boolean(props.enableFilters)}
|
|
428
|
-
enableRowSelection={Boolean(props.enableRowSelection)}
|
|
429
|
-
rowSelectionEnabled={rowSelectionEnabled}
|
|
430
|
-
setRowSelectionEnabled={setRowSelectionEnabled}
|
|
431
527
|
zIndex={drawerZIndex}
|
|
528
|
+
{...(enableColumnDrag && state?.columnOrder
|
|
529
|
+
? {
|
|
530
|
+
enableColumnDrag: true,
|
|
531
|
+
copy: settingsDrawerCopy as TableSettingsDrawerCopyProps<true>,
|
|
532
|
+
columnOrder: state.columnOrder,
|
|
533
|
+
onColumnOrderChange: (newOrder) => {
|
|
534
|
+
tanstackTable.setColumnOrder(newOrder);
|
|
535
|
+
},
|
|
536
|
+
}
|
|
537
|
+
: {
|
|
538
|
+
enableColumnDrag: false,
|
|
539
|
+
copy: settingsDrawerCopy as TableSettingsDrawerCopyProps<false>,
|
|
540
|
+
})}
|
|
432
541
|
/>
|
|
433
542
|
)}
|
|
434
543
|
{Array.isArray(exportFormats) && exportDrawerCopy && (
|
|
@@ -447,70 +556,3 @@ export const Table = <TData extends RowData>({
|
|
|
447
556
|
};
|
|
448
557
|
|
|
449
558
|
Table.displayName = "Table";
|
|
450
|
-
|
|
451
|
-
type EmptyTableProps = {
|
|
452
|
-
variant: "primary" | "secondary";
|
|
453
|
-
tag: HeadingTagType;
|
|
454
|
-
title: string;
|
|
455
|
-
description: string;
|
|
456
|
-
colSpan: number;
|
|
457
|
-
icon: React.ReactNode;
|
|
458
|
-
};
|
|
459
|
-
|
|
460
|
-
const EmptyTable = ({ variant, tag, title, description, colSpan, icon }: EmptyTableProps) => (
|
|
461
|
-
<TableRow>
|
|
462
|
-
<TableRowCell colSpan={colSpan} isLastRow={true} isFirstCell={true} isLastCell={true}>
|
|
463
|
-
<div
|
|
464
|
-
className={cx([
|
|
465
|
-
`${rootClassName}__empty-section`,
|
|
466
|
-
`${rootClassName}__empty-section--${variant}`,
|
|
467
|
-
])}
|
|
468
|
-
>
|
|
469
|
-
{icon && <div className={cx(`${rootClassName}__empty-section__icon`)}>{icon}</div>}
|
|
470
|
-
<div className={cx(`${rootClassName}__empty-section__texts`)}>
|
|
471
|
-
<Heading data-testid="purpur-table-empty-table-title" variant="title-100" tag={tag}>
|
|
472
|
-
{title}
|
|
473
|
-
</Heading>
|
|
474
|
-
<Paragraph data-testid="purpur-table-empty-table-description">{description}</Paragraph>
|
|
475
|
-
</div>
|
|
476
|
-
</div>
|
|
477
|
-
</TableRowCell>
|
|
478
|
-
</TableRow>
|
|
479
|
-
);
|
|
480
|
-
|
|
481
|
-
type LoadingTableRowsProps = {
|
|
482
|
-
rowCount: number;
|
|
483
|
-
isScrolled: boolean;
|
|
484
|
-
stickyFirstColumn: boolean;
|
|
485
|
-
getStickyColumn: (index: number) => boolean;
|
|
486
|
-
cellWidths: (string | number)[];
|
|
487
|
-
showBorder: (index: number) => boolean;
|
|
488
|
-
};
|
|
489
|
-
|
|
490
|
-
const LoadingTableRows = ({
|
|
491
|
-
rowCount,
|
|
492
|
-
getStickyColumn,
|
|
493
|
-
stickyFirstColumn,
|
|
494
|
-
isScrolled,
|
|
495
|
-
cellWidths,
|
|
496
|
-
showBorder,
|
|
497
|
-
}: LoadingTableRowsProps) => (
|
|
498
|
-
<>
|
|
499
|
-
{Array.from({ length: rowCount }, (_value, index) => index).map((row, rowIndex) => (
|
|
500
|
-
<TableRow key={`skeleton-row-${row}`}>
|
|
501
|
-
{cellWidths.map((cellWidth, cellIndex) => (
|
|
502
|
-
<TableRowCellSkeleton
|
|
503
|
-
key={`skeleton-cell-${cellIndex}`}
|
|
504
|
-
isLastRow={rowIndex === rowCount - 1}
|
|
505
|
-
isFirstCell={cellIndex === 0}
|
|
506
|
-
isLastCell={cellIndex === cellWidths.length - 1}
|
|
507
|
-
stickyColumn={stickyFirstColumn && getStickyColumn(cellIndex)}
|
|
508
|
-
isScrolled={isScrolled}
|
|
509
|
-
showBorder={showBorder(cellIndex)}
|
|
510
|
-
cellWidth={cellWidth}
|
|
511
|
-
/>
|
|
512
|
-
))}
|
|
513
|
-
</TableRow>
|
|
514
|
-
))}
|
|
515
|
-
</>
|
|
516
|
-
);
|
|
@@ -186,6 +186,7 @@ export const copy = {
|
|
|
186
186
|
},
|
|
187
187
|
generalSettings: {
|
|
188
188
|
header: "General settings",
|
|
189
|
+
|
|
189
190
|
toggles: {
|
|
190
191
|
lockFirstcolumn: "Lock first column",
|
|
191
192
|
showFilters: "Show Filters",
|
|
@@ -195,6 +196,7 @@ export const copy = {
|
|
|
195
196
|
title: "Table settings",
|
|
196
197
|
visibleColumns: {
|
|
197
198
|
header: "Visible columns",
|
|
199
|
+
description: "Change general table settings",
|
|
198
200
|
},
|
|
199
201
|
},
|
|
200
202
|
sortingAriaLabels: {
|
package/src/types.ts
CHANGED
|
@@ -320,6 +320,7 @@ export type WithoutToolbarProps = {
|
|
|
320
320
|
toolbarCopy?: never;
|
|
321
321
|
toolbarTotalRowCount?: never;
|
|
322
322
|
exportDrawerCopy?: never;
|
|
323
|
+
enableColumnDrag?: boolean;
|
|
323
324
|
};
|
|
324
325
|
|
|
325
326
|
type WithFiltersProps = {
|
|
@@ -440,7 +441,6 @@ type WithSettingsDrawerProps = {
|
|
|
440
441
|
/**
|
|
441
442
|
* Optional properties for customizing the settings drawer copy.
|
|
442
443
|
*/
|
|
443
|
-
settingsDrawerCopy: TableSettingsDrawerCopyProps;
|
|
444
444
|
toolbarCopy: {
|
|
445
445
|
buttons: {
|
|
446
446
|
settings: string;
|
|
@@ -449,7 +449,10 @@ type WithSettingsDrawerProps = {
|
|
|
449
449
|
settings: string;
|
|
450
450
|
};
|
|
451
451
|
};
|
|
452
|
-
}
|
|
452
|
+
} & (
|
|
453
|
+
| (WithColumnDragProps & { settingsDrawerCopy: TableSettingsDrawerCopyProps<true> })
|
|
454
|
+
| (WithoutColumnDragProps & { settingsDrawerCopy?: TableSettingsDrawerCopyProps<false> })
|
|
455
|
+
);
|
|
453
456
|
|
|
454
457
|
/**
|
|
455
458
|
* Props for enabling a single export format in a data table component.
|
|
@@ -494,4 +497,24 @@ type WithoutSettingsDrawerProps = {
|
|
|
494
497
|
settings?: undefined;
|
|
495
498
|
};
|
|
496
499
|
};
|
|
500
|
+
} & WithoutColumnDragProps;
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Props for column drag feature
|
|
504
|
+
*/
|
|
505
|
+
export type WithColumnDragProps = {
|
|
506
|
+
enableColumnDrag: true;
|
|
507
|
+
onColumnOrderChange: (newColumnOrder: string[]) => void;
|
|
508
|
+
columnDragAriaLabelsCopy: ColumnDragAriaLabelsCopy;
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
export type WithoutColumnDragProps = {
|
|
512
|
+
enableColumnDrag?: false | undefined;
|
|
513
|
+
onColumnOrderChange?: never;
|
|
514
|
+
columnDragAriaLabelsCopy?: never;
|
|
515
|
+
};
|
|
516
|
+
|
|
517
|
+
type ColumnDragAriaLabelsCopy = {
|
|
518
|
+
grab: string;
|
|
519
|
+
grabbing: string;
|
|
497
520
|
};
|