@purpurds/table 6.12.5 → 7.1.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/cell-types/body-text-cell.d.ts.map +1 -1
- package/dist/cell-types/link-cell.d.ts.map +1 -1
- package/dist/story-utils/column-def.d.ts.map +1 -1
- package/dist/story-utils/table-data.d.ts +2 -4
- package/dist/story-utils/table-data.d.ts.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/table-action-bar.d.ts.map +1 -1
- package/dist/table-export-drawer.d.ts +3 -2
- package/dist/table-export-drawer.d.ts.map +1 -1
- package/dist/table-row-cell.d.ts.map +1 -1
- package/dist/table-settings-drawer.d.ts +2 -1
- package/dist/table-settings-drawer.d.ts.map +1 -1
- package/dist/table-toolbar.d.ts +6 -4
- package/dist/table-toolbar.d.ts.map +1 -1
- package/dist/table.cjs.js +63 -63
- package/dist/table.cjs.js.map +1 -1
- package/dist/table.d.ts +2 -1
- package/dist/table.d.ts.map +1 -1
- package/dist/table.es.js +4019 -4021
- package/dist/table.es.js.map +1 -1
- package/dist/test-utils/helpers.d.ts +2 -1
- package/dist/test-utils/helpers.d.ts.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/use-truncated-hook.d.ts +3 -5
- package/dist/use-truncated-hook.d.ts.map +1 -1
- package/package.json +23 -23
- package/src/cell-types/body-text-cell.test.tsx +65 -0
- package/src/cell-types/body-text-cell.tsx +8 -9
- package/src/cell-types/lead-text-cell.test.tsx +65 -0
- package/src/cell-types/lead-text-cell.tsx +1 -1
- package/src/cell-types/link-cell.tsx +13 -6
- package/src/story-utils/column-def.ts +2 -0
- package/src/story-utils/table-data.tsx +10 -8
- package/src/table-action-bar.tsx +3 -2
- package/src/table-column-header-cell.tsx +16 -6
- package/src/table-export-drawer.test.tsx +2 -1
- package/src/table-export-drawer.tsx +5 -3
- package/src/table-kitchen-sink.test.tsx +5 -18
- package/src/table-row-cell.tsx +1 -30
- package/src/table-settings-drawer.test.tsx +4 -4
- package/src/table-settings-drawer.tsx +46 -41
- package/src/table-toolbar.test.tsx +3 -0
- package/src/table-toolbar.tsx +12 -7
- package/src/table.module.scss +51 -32
- package/src/table.stories.tsx +10 -9
- package/src/table.tsx +32 -26
- package/src/test-utils/helpers.ts +2 -1
- package/src/types.ts +1 -1
- package/src/use-truncated-hook.tsx +16 -60
package/src/table.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { ReactElement, useEffect, useRef, useState } from "react";
|
|
1
|
+
import React, { ReactElement, useEffect, useId, useRef, useState } from "react";
|
|
2
2
|
import type {
|
|
3
3
|
ColumnDef,
|
|
4
4
|
ColumnFiltersState,
|
|
@@ -70,6 +70,7 @@ export type TableProps<TData extends RowData> = {
|
|
|
70
70
|
columns: CoreOptions<TData>["columns"];
|
|
71
71
|
data: TData[];
|
|
72
72
|
paginationComponent?: ReactElement<PaginationProps>;
|
|
73
|
+
fullWidth?: boolean;
|
|
73
74
|
onRowsCountChange?: (rowsCount: number) => void;
|
|
74
75
|
} & (WithToolbarProps | WithoutToolbarProps) &
|
|
75
76
|
(WithSortingProps | WithoutSortingProps) &
|
|
@@ -94,6 +95,7 @@ export const Table = <TData extends RowData>({
|
|
|
94
95
|
enableToolbar: enableToolbar,
|
|
95
96
|
exportDrawerCopy,
|
|
96
97
|
exportFormats,
|
|
98
|
+
fullWidth = true,
|
|
97
99
|
loading,
|
|
98
100
|
paginationComponent,
|
|
99
101
|
rowSelectionAriaLabels,
|
|
@@ -123,10 +125,11 @@ export const Table = <TData extends RowData>({
|
|
|
123
125
|
);
|
|
124
126
|
const [stickyFirstColumn, setStickyFirstColumn] = useState(true);
|
|
125
127
|
const [stickyHeaders, setStickyHeaders] = useState(true);
|
|
126
|
-
const [rowSelectionEnabled, setRowSelectionEnabled] = useState(true);
|
|
127
128
|
const prevShowOnlySelectedRows = useRef(showOnlySelectedRows);
|
|
128
129
|
const [isScrolled, setIsScrolled] = useState(false);
|
|
129
130
|
const tableContainerRef = useRef<HTMLTableElement>(null);
|
|
131
|
+
const uid = useId();
|
|
132
|
+
const [rowSelectionEnabled, setRowSelectionEnabled] = useState(true);
|
|
130
133
|
|
|
131
134
|
const classes = cx([
|
|
132
135
|
className,
|
|
@@ -252,7 +255,9 @@ export const Table = <TData extends RowData>({
|
|
|
252
255
|
};
|
|
253
256
|
|
|
254
257
|
const getStickyColumn = (index: number) => {
|
|
255
|
-
|
|
258
|
+
// When rowSelectionEnabled is true, the first two columns are sticky
|
|
259
|
+
// Otherwise, only the first column is sticky
|
|
260
|
+
return props.enableRowSelection && rowSelectionEnabled ? index <= 1 : index === 0;
|
|
256
261
|
};
|
|
257
262
|
|
|
258
263
|
const handleResetColumnFilters = () => {
|
|
@@ -275,11 +280,15 @@ export const Table = <TData extends RowData>({
|
|
|
275
280
|
setShowColumnFiltersEnabled(true);
|
|
276
281
|
setStickyFirstColumn(true);
|
|
277
282
|
setStickyHeaders(true);
|
|
278
|
-
setRowSelectionEnabled(true);
|
|
279
283
|
|
|
280
284
|
tanstackTable.resetColumnVisibility();
|
|
281
285
|
};
|
|
282
286
|
|
|
287
|
+
const showBorder = (index: number) => {
|
|
288
|
+
// Only show the border for sticky columns when the table is scrolled
|
|
289
|
+
return isScrolled && stickyFirstColumn && getStickyColumn(index);
|
|
290
|
+
};
|
|
291
|
+
|
|
283
292
|
const tableRows = tanstackTable.getRowModel().rows;
|
|
284
293
|
const emptyTable = tableRows.length === 0 && Boolean(emptyTableCopy);
|
|
285
294
|
|
|
@@ -294,8 +303,8 @@ export const Table = <TData extends RowData>({
|
|
|
294
303
|
getStickyColumn={getStickyColumn}
|
|
295
304
|
stickyFirstColumn={stickyFirstColumn}
|
|
296
305
|
isScrolled={isScrolled}
|
|
297
|
-
rowSelectionEnabled={rowSelectionEnabled}
|
|
298
306
|
cellWidths={getColumnWidths()}
|
|
307
|
+
showBorder={showBorder}
|
|
299
308
|
/>
|
|
300
309
|
) : emptyTable && emptyTableCopy && emptyTableHeadingTag ? (
|
|
301
310
|
<EmptyTable
|
|
@@ -318,11 +327,7 @@ export const Table = <TData extends RowData>({
|
|
|
318
327
|
isLastCell={cellIndex === row.getVisibleCells().length - 1}
|
|
319
328
|
stickyColumn={stickyFirstColumn && getStickyColumn(cellIndex)}
|
|
320
329
|
isScrolled={isScrolled}
|
|
321
|
-
showBorder={
|
|
322
|
-
isScrolled &&
|
|
323
|
-
((props.enableRowSelection && cellIndex === 1) ||
|
|
324
|
-
(!props.enableRowSelection && cellIndex === 0))
|
|
325
|
-
}
|
|
330
|
+
showBorder={showBorder(cellIndex)}
|
|
326
331
|
/>
|
|
327
332
|
))}
|
|
328
333
|
</TableRow>
|
|
@@ -330,9 +335,12 @@ export const Table = <TData extends RowData>({
|
|
|
330
335
|
);
|
|
331
336
|
|
|
332
337
|
return (
|
|
333
|
-
<div id=
|
|
338
|
+
<div id={`${uid}-table`} className={classes}>
|
|
334
339
|
{enableToolbar && (
|
|
335
340
|
<TableToolbar
|
|
341
|
+
aria-controls={`${uid}-table`}
|
|
342
|
+
settingsDrawerAriaControls={`${uid}-settings-drawer`}
|
|
343
|
+
exportDrawerAriaControls={`${uid}-export-drawer`}
|
|
336
344
|
onSetDrawerIsOpen={setSettingsDrawerIsOpen}
|
|
337
345
|
onResetColumnFilters={handleResetColumnFilters}
|
|
338
346
|
onToggleExpand={onToggleExpand}
|
|
@@ -353,7 +361,12 @@ export const Table = <TData extends RowData>({
|
|
|
353
361
|
})}
|
|
354
362
|
ref={tableContainerRef}
|
|
355
363
|
>
|
|
356
|
-
<table
|
|
364
|
+
<table
|
|
365
|
+
className={cx([
|
|
366
|
+
`${rootClassName}__table`,
|
|
367
|
+
{ [`${rootClassName}__table--full-width`]: fullWidth },
|
|
368
|
+
])}
|
|
369
|
+
>
|
|
357
370
|
<TableHeader columnFiltersEnabled={showColumnFiltersEnabled}>
|
|
358
371
|
{tanstackTable.getHeaderGroups().map((headerGroup) => (
|
|
359
372
|
<TableRow key={headerGroup.id}>
|
|
@@ -365,11 +378,7 @@ export const Table = <TData extends RowData>({
|
|
|
365
378
|
stickyColumn={!emptyTable && stickyFirstColumn && getStickyColumn(index)}
|
|
366
379
|
stickyHeaders={!emptyTable && stickyHeaders}
|
|
367
380
|
isScrolled={isScrolled}
|
|
368
|
-
showBorder={
|
|
369
|
-
isScrolled &&
|
|
370
|
-
((props.enableRowSelection && index === 1) ||
|
|
371
|
-
(!props.enableRowSelection && index === 0))
|
|
372
|
-
}
|
|
381
|
+
showBorder={showBorder(index)}
|
|
373
382
|
{...(props.enableSorting && sortingAriaLabels
|
|
374
383
|
? { enableSorting: props.enableSorting, sortingAriaLabels }
|
|
375
384
|
: { enableSorting: false })}
|
|
@@ -396,6 +405,7 @@ export const Table = <TData extends RowData>({
|
|
|
396
405
|
)}
|
|
397
406
|
{enableToolbar && settingsDrawerCopy && (
|
|
398
407
|
<TableSettingsDrawer
|
|
408
|
+
id={`${uid}-settings-drawer`}
|
|
399
409
|
setDrawerIsOpen={setSettingsDrawerIsOpen}
|
|
400
410
|
setShowColumnFiltersEnabled={setShowColumnFiltersEnabled}
|
|
401
411
|
setStickyFirstColumn={setStickyFirstColumn}
|
|
@@ -415,6 +425,7 @@ export const Table = <TData extends RowData>({
|
|
|
415
425
|
)}
|
|
416
426
|
{Array.isArray(exportFormats) && exportDrawerCopy && (
|
|
417
427
|
<TableExportDrawer
|
|
428
|
+
id={`${uid}-export-drawer`}
|
|
418
429
|
isOpen={isExportDrawerOpen}
|
|
419
430
|
setDrawerIsOpen={setExportDrawerIsOpen}
|
|
420
431
|
exportFormats={exportFormats}
|
|
@@ -446,7 +457,7 @@ const EmptyTable = ({ variant, tag, title, description, colSpan, icon }: EmptyTa
|
|
|
446
457
|
`${rootClassName}__empty-section--${variant}`,
|
|
447
458
|
])}
|
|
448
459
|
>
|
|
449
|
-
<div className={cx(`${rootClassName}__empty-section__icon`)}>{icon}</div>
|
|
460
|
+
{icon && <div className={cx(`${rootClassName}__empty-section__icon`)}>{icon}</div>}
|
|
450
461
|
<div className={cx(`${rootClassName}__empty-section__texts`)}>
|
|
451
462
|
<Heading data-testid="purpur-table-empty-table-title" variant="title-100" tag={tag}>
|
|
452
463
|
{title}
|
|
@@ -460,21 +471,20 @@ const EmptyTable = ({ variant, tag, title, description, colSpan, icon }: EmptyTa
|
|
|
460
471
|
|
|
461
472
|
type LoadingTableRowsProps = {
|
|
462
473
|
rowCount: number;
|
|
463
|
-
rowSelectionEnabled: boolean;
|
|
464
474
|
isScrolled: boolean;
|
|
465
475
|
stickyFirstColumn: boolean;
|
|
466
476
|
getStickyColumn: (index: number) => boolean;
|
|
467
477
|
cellWidths: (string | number)[];
|
|
478
|
+
showBorder: (index: number) => boolean;
|
|
468
479
|
};
|
|
469
480
|
|
|
470
481
|
const LoadingTableRows = ({
|
|
471
482
|
rowCount,
|
|
472
|
-
// cellCount,
|
|
473
483
|
getStickyColumn,
|
|
474
484
|
stickyFirstColumn,
|
|
475
485
|
isScrolled,
|
|
476
|
-
rowSelectionEnabled,
|
|
477
486
|
cellWidths,
|
|
487
|
+
showBorder,
|
|
478
488
|
}: LoadingTableRowsProps) => (
|
|
479
489
|
<>
|
|
480
490
|
{Array.from({ length: rowCount }, (_value, index) => index).map((row, rowIndex) => (
|
|
@@ -487,11 +497,7 @@ const LoadingTableRows = ({
|
|
|
487
497
|
isLastCell={cellIndex === cellWidths.length - 1}
|
|
488
498
|
stickyColumn={stickyFirstColumn && getStickyColumn(cellIndex)}
|
|
489
499
|
isScrolled={isScrolled}
|
|
490
|
-
showBorder={
|
|
491
|
-
isScrolled &&
|
|
492
|
-
((rowSelectionEnabled && cellIndex === 1) ||
|
|
493
|
-
(!rowSelectionEnabled && cellIndex === 0))
|
|
494
|
-
}
|
|
500
|
+
showBorder={showBorder(cellIndex)}
|
|
495
501
|
cellWidth={cellWidth}
|
|
496
502
|
/>
|
|
497
503
|
))}
|
|
@@ -145,6 +145,7 @@ export const Selectors = {
|
|
|
145
145
|
PAGINATION: {
|
|
146
146
|
ROOT: "purpur-pagination",
|
|
147
147
|
PAGE_SIZE_SELECT: "purpur-pagination-page-size-selector-select-select",
|
|
148
|
+
PAGE_BUTTON: (pageNumber: number) => `purpur-pagination-pages-page-${pageNumber}-button`,
|
|
148
149
|
},
|
|
149
150
|
SKELETON: "purpur-table-cell-skeleton",
|
|
150
151
|
};
|
|
@@ -164,7 +165,7 @@ export const copy = {
|
|
|
164
165
|
},
|
|
165
166
|
exportDrawer: {
|
|
166
167
|
bodyText: "Choose the format you want to export the table in.",
|
|
167
|
-
|
|
168
|
+
closeButtonAriaLabel: "Close drawer",
|
|
168
169
|
link: "Export as",
|
|
169
170
|
title: "Export table",
|
|
170
171
|
},
|
package/src/types.ts
CHANGED
|
@@ -1,66 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Cell, RowData } from "@tanstack/react-table";
|
|
1
|
+
import { useRef, useState } from "react";
|
|
3
2
|
|
|
4
|
-
const useTruncatedTooltip =
|
|
5
|
-
const divRef = useRef<HTMLParagraphElement>(null);
|
|
6
|
-
const [isTruncated, setIsTruncated] = useState(false);
|
|
7
|
-
const timeoutIdRef = useRef<NodeJS.Timeout | undefined>(undefined);
|
|
3
|
+
const useTruncatedTooltip = () => {
|
|
8
4
|
const [showPopover, setShowPopover] = useState(false);
|
|
9
|
-
|
|
10
|
-
const debounce = (func: (...args: unknown[]) => void, delay: number) => {
|
|
11
|
-
let timeoutId: NodeJS.Timeout;
|
|
12
|
-
const debouncedFunction = (...args: unknown[]) => {
|
|
13
|
-
clearTimeout(timeoutId);
|
|
14
|
-
timeoutId = setTimeout(() => func.apply(this, args), delay);
|
|
15
|
-
};
|
|
16
|
-
return {
|
|
17
|
-
debouncedFunction,
|
|
18
|
-
get timeoutId() {
|
|
19
|
-
return timeoutId;
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
if (!cell) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const { debouncedFunction: checkTruncation, timeoutId } = debounce(() => {
|
|
30
|
-
if (divRef.current && cell) {
|
|
31
|
-
const pEl = divRef.current.querySelector("p");
|
|
32
|
-
if (pEl) {
|
|
33
|
-
setIsTruncated(pEl.scrollWidth > cell.column.getSize());
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}, 100); // Adjust debounce delay as needed
|
|
37
|
-
|
|
38
|
-
checkTruncation();
|
|
39
|
-
timeoutIdRef.current = timeoutId;
|
|
40
|
-
|
|
41
|
-
return () => {
|
|
42
|
-
clearTimeout(timeoutIdRef.current);
|
|
43
|
-
};
|
|
44
|
-
}, [cell]);
|
|
45
|
-
|
|
46
|
-
useEffect(() => {
|
|
47
|
-
if (divRef.current && cell) {
|
|
48
|
-
if (divRef.current.textContent) {
|
|
49
|
-
const pEl = divRef.current.querySelector("p");
|
|
50
|
-
if (pEl) {
|
|
51
|
-
setIsTruncated(pEl.scrollWidth > cell.column.getSize());
|
|
52
|
-
}
|
|
53
|
-
const aEl = divRef.current.querySelector("a");
|
|
54
|
-
if (aEl) {
|
|
55
|
-
setIsTruncated(aEl.scrollWidth > cell.column.getSize());
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}, [divRef, cell, isTruncated]);
|
|
5
|
+
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
60
6
|
|
|
61
7
|
const onMouseEnter = () => {
|
|
62
|
-
if (
|
|
63
|
-
|
|
8
|
+
if (containerRef.current) {
|
|
9
|
+
const contentElement: HTMLLinkElement | HTMLParagraphElement | null =
|
|
10
|
+
containerRef.current.querySelector("a, p"); // Find "a" or "p" tag
|
|
11
|
+
if (contentElement) {
|
|
12
|
+
const containerWidth = containerRef.current.clientWidth;
|
|
13
|
+
const contentWidth =
|
|
14
|
+
contentElement.tagName.toLowerCase() === "a"
|
|
15
|
+
? contentElement.offsetWidth
|
|
16
|
+
: contentElement.scrollWidth;
|
|
17
|
+
|
|
18
|
+
setShowPopover(contentWidth > containerWidth);
|
|
19
|
+
}
|
|
64
20
|
}
|
|
65
21
|
};
|
|
66
22
|
|
|
@@ -68,7 +24,7 @@ const useTruncatedTooltip = <TData extends RowData>(cell: Cell<TData, unknown> |
|
|
|
68
24
|
setShowPopover(false);
|
|
69
25
|
};
|
|
70
26
|
|
|
71
|
-
return {
|
|
27
|
+
return { showPopover, containerRef, onMouseEnter, onMouseLeave };
|
|
72
28
|
};
|
|
73
29
|
|
|
74
30
|
export default useTruncatedTooltip;
|