@purpurds/table 0.0.1

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.
Files changed (142) hide show
  1. package/dist/LICENSE.txt +213 -0
  2. package/dist/cell-types/badge-cell.d.ts +8 -0
  3. package/dist/cell-types/badge-cell.d.ts.map +1 -0
  4. package/dist/cell-types/body-text-cell.d.ts +8 -0
  5. package/dist/cell-types/body-text-cell.d.ts.map +1 -0
  6. package/dist/cell-types/button-cell.d.ts +8 -0
  7. package/dist/cell-types/button-cell.d.ts.map +1 -0
  8. package/dist/cell-types/button-group-cell.d.ts +16 -0
  9. package/dist/cell-types/button-group-cell.d.ts.map +1 -0
  10. package/dist/cell-types/cta-link-cell.d.ts +8 -0
  11. package/dist/cell-types/cta-link-cell.d.ts.map +1 -0
  12. package/dist/cell-types/date-cell.d.ts +8 -0
  13. package/dist/cell-types/date-cell.d.ts.map +1 -0
  14. package/dist/cell-types/empty-cell.d.ts +4 -0
  15. package/dist/cell-types/empty-cell.d.ts.map +1 -0
  16. package/dist/cell-types/error-message-cell.d.ts +8 -0
  17. package/dist/cell-types/error-message-cell.d.ts.map +1 -0
  18. package/dist/cell-types/icon-text-cell.d.ts +8 -0
  19. package/dist/cell-types/icon-text-cell.d.ts.map +1 -0
  20. package/dist/cell-types/lead-text-cell.d.ts +8 -0
  21. package/dist/cell-types/lead-text-cell.d.ts.map +1 -0
  22. package/dist/cell-types/link-cell.d.ts +8 -0
  23. package/dist/cell-types/link-cell.d.ts.map +1 -0
  24. package/dist/cell-types/number-cell.d.ts +8 -0
  25. package/dist/cell-types/number-cell.d.ts.map +1 -0
  26. package/dist/cell-types/row-selection-cell.d.ts +8 -0
  27. package/dist/cell-types/row-selection-cell.d.ts.map +1 -0
  28. package/dist/cell-types/row-toggle-cell.d.ts +8 -0
  29. package/dist/cell-types/row-toggle-cell.d.ts.map +1 -0
  30. package/dist/cell-types/toggle-cell.d.ts +8 -0
  31. package/dist/cell-types/toggle-cell.d.ts.map +1 -0
  32. package/dist/cell-types/warning-message-cell.d.ts +8 -0
  33. package/dist/cell-types/warning-message-cell.d.ts.map +1 -0
  34. package/dist/metadata.js +17 -0
  35. package/dist/story-utils/column-def.d.ts +5 -0
  36. package/dist/story-utils/column-def.d.ts.map +1 -0
  37. package/dist/story-utils/table-data.d.ts +35 -0
  38. package/dist/story-utils/table-data.d.ts.map +1 -0
  39. package/dist/story-utils/use-fetch-table-data-hook.d.ts +11 -0
  40. package/dist/story-utils/use-fetch-table-data-hook.d.ts.map +1 -0
  41. package/dist/styles.css +1 -0
  42. package/dist/table-action-bar.d.ts +26 -0
  43. package/dist/table-action-bar.d.ts.map +1 -0
  44. package/dist/table-body.d.ts +10 -0
  45. package/dist/table-body.d.ts.map +1 -0
  46. package/dist/table-column-header-cell.d.ts +28 -0
  47. package/dist/table-column-header-cell.d.ts.map +1 -0
  48. package/dist/table-export-drawer.d.ts +17 -0
  49. package/dist/table-export-drawer.d.ts.map +1 -0
  50. package/dist/table-header.d.ts +11 -0
  51. package/dist/table-header.d.ts.map +1 -0
  52. package/dist/table-row-cell-skeleton.d.ts +14 -0
  53. package/dist/table-row-cell-skeleton.d.ts.map +1 -0
  54. package/dist/table-row-cell.d.ts +25 -0
  55. package/dist/table-row-cell.d.ts.map +1 -0
  56. package/dist/table-row.d.ts +11 -0
  57. package/dist/table-row.d.ts.map +1 -0
  58. package/dist/table-settings-drawer.d.ts +41 -0
  59. package/dist/table-settings-drawer.d.ts.map +1 -0
  60. package/dist/table-toolbar.d.ts +37 -0
  61. package/dist/table-toolbar.d.ts.map +1 -0
  62. package/dist/table.cjs.js +259 -0
  63. package/dist/table.cjs.js.map +1 -0
  64. package/dist/table.d.ts +20 -0
  65. package/dist/table.d.ts.map +1 -0
  66. package/dist/table.es.js +13585 -0
  67. package/dist/table.es.js.map +1 -0
  68. package/dist/test-utils/column-def.d.ts +6 -0
  69. package/dist/test-utils/column-def.d.ts.map +1 -0
  70. package/dist/test-utils/helpers.d.ts +138 -0
  71. package/dist/test-utils/helpers.d.ts.map +1 -0
  72. package/dist/test-utils/table-data.d.ts +33 -0
  73. package/dist/test-utils/table-data.d.ts.map +1 -0
  74. package/dist/types.d.ts +420 -0
  75. package/dist/types.d.ts.map +1 -0
  76. package/dist/use-screen-size.hook.d.ts +7 -0
  77. package/dist/use-screen-size.hook.d.ts.map +1 -0
  78. package/dist/use-truncated-hook.d.ts +10 -0
  79. package/dist/use-truncated-hook.d.ts.map +1 -0
  80. package/dist/utils/custom-functions.d.ts +9 -0
  81. package/dist/utils/custom-functions.d.ts.map +1 -0
  82. package/dist/utils/unit-conversions.d.ts +19 -0
  83. package/dist/utils/unit-conversions.d.ts.map +1 -0
  84. package/dist/utils/unit-conversions.spec.d.ts +2 -0
  85. package/dist/utils/unit-conversions.spec.d.ts.map +1 -0
  86. package/eslint.config.mjs +2 -0
  87. package/package.json +82 -0
  88. package/src/cell-types/badge-cell.tsx +25 -0
  89. package/src/cell-types/body-text-cell.tsx +54 -0
  90. package/src/cell-types/button-cell.tsx +26 -0
  91. package/src/cell-types/button-group-cell.tsx +54 -0
  92. package/src/cell-types/cta-link-cell.tsx +25 -0
  93. package/src/cell-types/date-cell.tsx +33 -0
  94. package/src/cell-types/empty-cell.tsx +6 -0
  95. package/src/cell-types/error-message-cell.tsx +30 -0
  96. package/src/cell-types/icon-text-cell.tsx +30 -0
  97. package/src/cell-types/lead-text-cell.tsx +19 -0
  98. package/src/cell-types/link-cell.tsx +58 -0
  99. package/src/cell-types/number-cell.tsx +27 -0
  100. package/src/cell-types/row-selection-cell.tsx +22 -0
  101. package/src/cell-types/row-toggle-cell.tsx +23 -0
  102. package/src/cell-types/toggle-cell.tsx +19 -0
  103. package/src/cell-types/warning-message-cell.tsx +30 -0
  104. package/src/global.d.ts +4 -0
  105. package/src/story-utils/column-def.ts +148 -0
  106. package/src/story-utils/table-data.tsx +262 -0
  107. package/src/story-utils/use-fetch-table-data-hook.tsx +30 -0
  108. package/src/table-action-bar.module.scss +106 -0
  109. package/src/table-action-bar.test.tsx +111 -0
  110. package/src/table-action-bar.tsx +104 -0
  111. package/src/table-body.tsx +25 -0
  112. package/src/table-column-header-cell.tsx +305 -0
  113. package/src/table-export-drawer.module.scss +9 -0
  114. package/src/table-export-drawer.test.tsx +75 -0
  115. package/src/table-export-drawer.tsx +59 -0
  116. package/src/table-header.tsx +35 -0
  117. package/src/table-kitchen-sink.test.tsx +1196 -0
  118. package/src/table-row-cell-skeleton.tsx +61 -0
  119. package/src/table-row-cell.test.tsx +360 -0
  120. package/src/table-row-cell.tsx +188 -0
  121. package/src/table-row.tsx +30 -0
  122. package/src/table-settings-drawer.module.scss +25 -0
  123. package/src/table-settings-drawer.test.tsx +350 -0
  124. package/src/table-settings-drawer.tsx +254 -0
  125. package/src/table-toolbar.module.scss +17 -0
  126. package/src/table-toolbar.test.tsx +95 -0
  127. package/src/table-toolbar.tsx +136 -0
  128. package/src/table.module.scss +367 -0
  129. package/src/table.stories.tsx +1246 -0
  130. package/src/table.story.css +11 -0
  131. package/src/table.test.tsx +318 -0
  132. package/src/table.tsx +501 -0
  133. package/src/test-utils/column-def.ts +152 -0
  134. package/src/test-utils/helpers.ts +234 -0
  135. package/src/test-utils/table-data.tsx +318 -0
  136. package/src/types.ts +496 -0
  137. package/src/use-screen-size.hook.ts +23 -0
  138. package/src/use-truncated-hook.tsx +74 -0
  139. package/src/utils/custom-functions.ts +52 -0
  140. package/src/utils/unit-conversions.spec.ts +92 -0
  141. package/src/utils/unit-conversions.ts +30 -0
  142. package/vitest.setup.ts +60 -0
package/src/table.tsx ADDED
@@ -0,0 +1,501 @@
1
+ import React, { ReactElement, useEffect, useRef, useState } from "react";
2
+ import type {
3
+ ColumnDef,
4
+ ColumnFiltersState,
5
+ CoreOptions,
6
+ PaginationState,
7
+ RowData,
8
+ RowSelectionState,
9
+ SortingState,
10
+ TableOptions,
11
+ VisibilityState,
12
+ } from "@tanstack/react-table";
13
+ import {
14
+ getCoreRowModel,
15
+ getFilteredRowModel,
16
+ getPaginationRowModel,
17
+ getSortedRowModel,
18
+ useReactTable,
19
+ } from "@tanstack/react-table";
20
+ export { createColumnHelper } from "@tanstack/react-table";
21
+ import { Heading, HeadingTagType } from "@purpurds/heading";
22
+ import { PaginationProps } from "@purpurds/pagination";
23
+ import { Paragraph } from "@purpurds/paragraph";
24
+ import c from "classnames/bind";
25
+
26
+ export type {
27
+ ColumnDef,
28
+ ColumnFiltersState,
29
+ CoreOptions,
30
+ PaginationState,
31
+ RowData,
32
+ RowSelectionState,
33
+ SortingState,
34
+ TableOptions,
35
+ VisibilityState,
36
+ };
37
+
38
+ import styles from "./table.module.scss";
39
+ import { TableActionBar } from "./table-action-bar";
40
+ import TableBody from "./table-body";
41
+ import { TableColumnHeaderCell } from "./table-column-header-cell";
42
+ import { TableExportDrawer } from "./table-export-drawer";
43
+ import { TableHeader } from "./table-header";
44
+ import TableRow from "./table-row";
45
+ import TableRowCell from "./table-row-cell";
46
+ import TableRowCellSkeleton from "./table-row-cell-skeleton";
47
+ import { TableSettingsDrawer } from "./table-settings-drawer";
48
+ import { TableToolbar } from "./table-toolbar";
49
+ import {
50
+ WithActionBarProps,
51
+ WithEmptyTableProps,
52
+ WithLoadingProps,
53
+ WithoutActionBarProps,
54
+ WithoutEmptyTableProps,
55
+ WithoutLoadingProps,
56
+ WithoutRowSelectionProps,
57
+ WithoutSortingProps,
58
+ WithoutToolbarProps,
59
+ WithRowSelectionProps,
60
+ WithSortingProps,
61
+ WithToolbarProps,
62
+ } from "./types";
63
+ import { filterOnFilterKey, sortOnBadgeValue, sortOnBadgeVariant } from "./utils/custom-functions";
64
+
65
+ const cx = c.bind(styles);
66
+
67
+ export type TableProps<TData extends RowData> = {
68
+ className?: string;
69
+ variant?: "primary" | "secondary";
70
+ columns: CoreOptions<TData>["columns"];
71
+ data: TData[];
72
+ paginationComponent?: ReactElement<PaginationProps>;
73
+ onRowsCountChange?: (rowsCount: number) => void;
74
+ } & (WithToolbarProps | WithoutToolbarProps) &
75
+ (WithSortingProps | WithoutSortingProps) &
76
+ (WithActionBarProps | WithoutActionBarProps) &
77
+ (WithEmptyTableProps | WithoutEmptyTableProps) &
78
+ (WithoutLoadingProps | WithLoadingProps) &
79
+ (WithoutRowSelectionProps | WithRowSelectionProps<TData>) &
80
+ Partial<TableOptions<TData>>;
81
+
82
+ const rootClassName = "purpur-table";
83
+
84
+ export const Table = <TData extends RowData>({
85
+ actionbarCopy,
86
+ actionBarTotalRowCount,
87
+ className,
88
+ columns,
89
+ data,
90
+ emptyTableCopy,
91
+ emptyTableHeadingTag,
92
+ emptyTableIcon,
93
+ enableActionBar,
94
+ enableToolbar: enableToolbar,
95
+ exportDrawerCopy,
96
+ exportFormats,
97
+ loading,
98
+ paginationComponent,
99
+ rowSelectionAriaLabels,
100
+ settingsDrawerCopy,
101
+ showOnlySelectedRows,
102
+ skeletonRows,
103
+ sortingAriaLabels,
104
+ state,
105
+ toolbarCopy,
106
+ toolbarTotalRowCount,
107
+ variant = "primary",
108
+ getRowId,
109
+ onExportData,
110
+ onRowsCountChange,
111
+ onToggleExpand,
112
+ onPrimaryButtonClick,
113
+ onSecondaryButtonClick,
114
+ setShowOnlySelectedRows,
115
+ ...props
116
+ }: TableProps<TData>) => {
117
+ const [selectedRowsCount, setSelectedRowsCount] = useState(0);
118
+ const [actionBarVisible, setActionBarVisible] = useState(false);
119
+ const [isSettingsDrawerOpen, setSettingsDrawerIsOpen] = useState(false);
120
+ const [isExportDrawerOpen, setExportDrawerIsOpen] = useState(false);
121
+ const [showColumnFiltersEnabled, setShowColumnFiltersEnabled] = useState(
122
+ Boolean(props.enableFilters)
123
+ );
124
+ const [stickyFirstColumn, setStickyFirstColumn] = useState(true);
125
+ const [stickyHeaders, setStickyHeaders] = useState(true);
126
+ const [rowSelectionEnabled, setRowSelectionEnabled] = useState(true);
127
+ const prevShowOnlySelectedRows = useRef(showOnlySelectedRows);
128
+ const [isScrolled, setIsScrolled] = useState(false);
129
+ const tableContainerRef = useRef<HTMLTableElement>(null);
130
+
131
+ const classes = cx([
132
+ className,
133
+ rootClassName,
134
+ {
135
+ [`${rootClassName}--${variant}`]: variant,
136
+ },
137
+ ]);
138
+
139
+ // Only add row selection columns when both enableRowSelection is true and rowSelectionEnabled is true
140
+ if (props.enableRowSelection && rowSelectionEnabled) {
141
+ columns = props.enableMultiRowSelection
142
+ ? [
143
+ {
144
+ id: "row-selection",
145
+ header: "Row selection",
146
+ size: 25,
147
+ meta: {
148
+ cellType: "rowSelection",
149
+ rowSelectionAriaLabels,
150
+ },
151
+ },
152
+ ...columns,
153
+ ]
154
+ : [
155
+ {
156
+ id: "row-toggle",
157
+ header: "Row toggle",
158
+ size: 25,
159
+ meta: {
160
+ cellType: "rowToggle",
161
+ rowSelectionAriaLabels,
162
+ },
163
+ },
164
+ ...columns,
165
+ ];
166
+ }
167
+
168
+ const { filterFns, sortingFns, ...restProps } = props;
169
+
170
+ const tanstackTable = useReactTable({
171
+ columns,
172
+ data,
173
+ state,
174
+ enableColumnFilters: showColumnFiltersEnabled,
175
+ getRowId,
176
+ filterFns: {
177
+ ...filterFns,
178
+ filterOnFilterKey: filterOnFilterKey<TData>,
179
+ },
180
+ sortingFns: {
181
+ ...sortingFns,
182
+ sortOnBadgeVariant: sortOnBadgeVariant<TData>,
183
+ sortOnBadgeValue: sortOnBadgeValue<TData>,
184
+ },
185
+ getCoreRowModel: getCoreRowModel(),
186
+ getSortedRowModel:
187
+ props.enableSorting && !props.manualSorting ? getSortedRowModel() : undefined,
188
+ getFilteredRowModel:
189
+ props.enableFilters && !props.manualFiltering ? getFilteredRowModel() : undefined,
190
+ getPaginationRowModel:
191
+ paginationComponent && !props.manualPagination ? getPaginationRowModel() : undefined,
192
+ ...restProps,
193
+ });
194
+
195
+ useEffect(() => {
196
+ const handleScroll = () => {
197
+ if (tableContainerRef.current) {
198
+ const scrollLeft = tableContainerRef.current.scrollLeft;
199
+ setIsScrolled(scrollLeft > 0);
200
+ }
201
+ };
202
+
203
+ const container = tableContainerRef.current;
204
+ if (container) {
205
+ container.addEventListener("scroll", handleScroll);
206
+ }
207
+
208
+ return () => {
209
+ if (container) {
210
+ container.removeEventListener("scroll", handleScroll);
211
+ }
212
+ };
213
+ }, []);
214
+
215
+ useEffect(() => {
216
+ if (showOnlySelectedRows) {
217
+ if (!prevShowOnlySelectedRows.current) {
218
+ tanstackTable.setPageIndex(0);
219
+ }
220
+ prevShowOnlySelectedRows.current = showOnlySelectedRows;
221
+ } else {
222
+ if (prevShowOnlySelectedRows.current) {
223
+ tanstackTable.setPageIndex(0);
224
+ }
225
+ prevShowOnlySelectedRows.current = showOnlySelectedRows;
226
+ }
227
+ }, [showOnlySelectedRows, tanstackTable]);
228
+
229
+ useEffect(() => {
230
+ if (onRowsCountChange) {
231
+ onRowsCountChange(tanstackTable.getRowCount());
232
+ }
233
+ }, [state, onRowsCountChange, tanstackTable]);
234
+
235
+ useEffect(() => {
236
+ if (state?.rowSelection) {
237
+ const newLength = Object.keys(state.rowSelection).length;
238
+ setSelectedRowsCount(newLength);
239
+ setActionBarVisible(newLength > 0);
240
+ }
241
+ }, [state?.rowSelection]);
242
+
243
+ const handleCancelSelection = () => {
244
+ tanstackTable.resetRowSelection();
245
+ setShowOnlySelectedRows?.(false);
246
+ };
247
+
248
+ const handleToggleSelected = () => {
249
+ if (setShowOnlySelectedRows) {
250
+ setShowOnlySelectedRows((prev) => !prev);
251
+ }
252
+ };
253
+
254
+ const getStickyColumn = (index: number) => {
255
+ return props.enableRowSelection ? index <= 1 : index === 0;
256
+ };
257
+
258
+ const handleResetColumnFilters = () => {
259
+ tanstackTable.resetColumnFilters();
260
+ };
261
+
262
+ const handleExportButton = () => {
263
+ if (typeof exportFormats === "string") {
264
+ handleExportData(exportFormats);
265
+ } else {
266
+ setExportDrawerIsOpen((prev) => !prev);
267
+ }
268
+ };
269
+
270
+ const handleExportData = (format: string) => {
271
+ onExportData?.(format);
272
+ };
273
+
274
+ const handleResetSettings = () => {
275
+ setShowColumnFiltersEnabled(true);
276
+ setStickyFirstColumn(true);
277
+ setStickyHeaders(true);
278
+ setRowSelectionEnabled(true);
279
+
280
+ tanstackTable.resetColumnVisibility();
281
+ };
282
+
283
+ const tableRows = tanstackTable.getRowModel().rows;
284
+ const emptyTable = tableRows.length === 0 && Boolean(emptyTableCopy);
285
+
286
+ const getColumnWidths = (): (string | number)[] => {
287
+ return tanstackTable.getAllColumns().map((column) => column.getSize() || "100%");
288
+ };
289
+
290
+ const tableBodyContent =
291
+ loading && skeletonRows ? (
292
+ <LoadingTableRows
293
+ rowCount={skeletonRows}
294
+ getStickyColumn={getStickyColumn}
295
+ stickyFirstColumn={stickyFirstColumn}
296
+ isScrolled={isScrolled}
297
+ rowSelectionEnabled={rowSelectionEnabled}
298
+ cellWidths={getColumnWidths()}
299
+ />
300
+ ) : emptyTable && emptyTableCopy && emptyTableHeadingTag ? (
301
+ <EmptyTable
302
+ variant={variant}
303
+ tag={emptyTableHeadingTag}
304
+ title={emptyTableCopy.title}
305
+ description={emptyTableCopy.description}
306
+ colSpan={tanstackTable.getVisibleLeafColumns().length}
307
+ icon={emptyTableIcon}
308
+ />
309
+ ) : (
310
+ tableRows.map((row, rowIndex) => (
311
+ <TableRow key={row.id} isSelected={row.getIsSelected()}>
312
+ {row.getVisibleCells().map((cell, cellIndex) => (
313
+ <TableRowCell
314
+ key={cell.id}
315
+ cell={cell}
316
+ isLastRow={rowIndex === tableRows.length - 1}
317
+ isFirstCell={cellIndex === 0}
318
+ isLastCell={cellIndex === row.getVisibleCells().length - 1}
319
+ stickyColumn={stickyFirstColumn && getStickyColumn(cellIndex)}
320
+ isScrolled={isScrolled}
321
+ showBorder={
322
+ isScrolled &&
323
+ ((props.enableRowSelection && cellIndex === 1) ||
324
+ (!props.enableRowSelection && cellIndex === 0))
325
+ }
326
+ />
327
+ ))}
328
+ </TableRow>
329
+ ))
330
+ );
331
+
332
+ return (
333
+ <div id="purpur-table" className={classes}>
334
+ {enableToolbar && (
335
+ <TableToolbar
336
+ onSetDrawerIsOpen={setSettingsDrawerIsOpen}
337
+ onResetColumnFilters={handleResetColumnFilters}
338
+ onToggleExpand={onToggleExpand}
339
+ onExportData={handleExportButton}
340
+ totalRowCount={toolbarTotalRowCount ?? tanstackTable.getRowCount()}
341
+ visibleRowCount={tanstackTable.getRowModel().rows.length}
342
+ toolbarCopy={toolbarCopy}
343
+ isSettingsDrawerOpen={isSettingsDrawerOpen}
344
+ hasExportsDrawer={Array.isArray(exportFormats)}
345
+ isExportDrawerOpen={isExportDrawerOpen}
346
+ showFilters={showColumnFiltersEnabled}
347
+ disableClearFilters={tanstackTable.getState().columnFilters.length === 0}
348
+ />
349
+ )}
350
+ <div
351
+ className={cx(`${rootClassName}__container`, {
352
+ [`${rootClassName}__container--scrolled`]: isScrolled,
353
+ })}
354
+ ref={tableContainerRef}
355
+ >
356
+ <table className={cx(`${rootClassName}__table`)}>
357
+ <TableHeader columnFiltersEnabled={showColumnFiltersEnabled}>
358
+ {tanstackTable.getHeaderGroups().map((headerGroup) => (
359
+ <TableRow key={headerGroup.id}>
360
+ {headerGroup.headers.map((header, index) => (
361
+ <TableColumnHeaderCell
362
+ key={header.id}
363
+ header={header}
364
+ tanstackTable={tanstackTable}
365
+ stickyColumn={!emptyTable && stickyFirstColumn && getStickyColumn(index)}
366
+ stickyHeaders={!emptyTable && stickyHeaders}
367
+ isScrolled={isScrolled}
368
+ showBorder={
369
+ isScrolled &&
370
+ ((props.enableRowSelection && index === 1) ||
371
+ (!props.enableRowSelection && index === 0))
372
+ }
373
+ {...(props.enableSorting && sortingAriaLabels
374
+ ? { enableSorting: props.enableSorting, sortingAriaLabels }
375
+ : { enableSorting: false })}
376
+ />
377
+ ))}
378
+ </TableRow>
379
+ ))}
380
+ </TableHeader>
381
+ <TableBody>{tableBodyContent}</TableBody>
382
+ </table>
383
+ </div>
384
+ {paginationComponent}
385
+ {enableActionBar && actionBarTotalRowCount && actionbarCopy && onPrimaryButtonClick && (
386
+ <TableActionBar
387
+ rowCount={actionBarTotalRowCount}
388
+ selectedRowsCount={selectedRowsCount}
389
+ copy={actionbarCopy}
390
+ isVisible={actionBarVisible}
391
+ onCancelSelection={handleCancelSelection}
392
+ onToggleSelected={handleToggleSelected}
393
+ onPrimaryButtonClick={onPrimaryButtonClick}
394
+ onSecondaryButtonClick={onSecondaryButtonClick}
395
+ />
396
+ )}
397
+ {enableToolbar && settingsDrawerCopy && (
398
+ <TableSettingsDrawer
399
+ setDrawerIsOpen={setSettingsDrawerIsOpen}
400
+ setShowColumnFiltersEnabled={setShowColumnFiltersEnabled}
401
+ setStickyFirstColumn={setStickyFirstColumn}
402
+ setStickyHeaders={setStickyHeaders}
403
+ getAllColumns={tanstackTable.getAllColumns}
404
+ isDrawerOpen={isSettingsDrawerOpen}
405
+ showColumnFilters={showColumnFiltersEnabled}
406
+ stickyFirstColumn={stickyFirstColumn}
407
+ stickyHeaders={stickyHeaders}
408
+ copy={settingsDrawerCopy}
409
+ onResetSettings={handleResetSettings}
410
+ columnFiltersEnabled={Boolean(props.enableFilters)}
411
+ enableRowSelection={Boolean(props.enableRowSelection)}
412
+ rowSelectionEnabled={rowSelectionEnabled}
413
+ setRowSelectionEnabled={setRowSelectionEnabled}
414
+ />
415
+ )}
416
+ {Array.isArray(exportFormats) && exportDrawerCopy && (
417
+ <TableExportDrawer
418
+ isOpen={isExportDrawerOpen}
419
+ setDrawerIsOpen={setExportDrawerIsOpen}
420
+ exportFormats={exportFormats}
421
+ copy={exportDrawerCopy}
422
+ onExportData={handleExportData}
423
+ />
424
+ )}
425
+ </div>
426
+ );
427
+ };
428
+
429
+ Table.displayName = "Table";
430
+
431
+ type EmptyTableProps = {
432
+ variant: "primary" | "secondary";
433
+ tag: HeadingTagType;
434
+ title: string;
435
+ description: string;
436
+ colSpan: number;
437
+ icon: React.ReactNode;
438
+ };
439
+
440
+ const EmptyTable = ({ variant, tag, title, description, colSpan, icon }: EmptyTableProps) => (
441
+ <TableRow>
442
+ <TableRowCell colSpan={colSpan} isLastRow={true} isFirstCell={true} isLastCell={true}>
443
+ <div
444
+ className={cx([
445
+ `${rootClassName}__empty-section`,
446
+ `${rootClassName}__empty-section--${variant}`,
447
+ ])}
448
+ >
449
+ <div className={cx(`${rootClassName}__empty-section__icon`)}>{icon}</div>
450
+ <div className={cx(`${rootClassName}__empty-section__texts`)}>
451
+ <Heading data-testid="purpur-table-empty-table-title" variant="title-100" tag={tag}>
452
+ {title}
453
+ </Heading>
454
+ <Paragraph data-testid="purpur-table-empty-table-description">{description}</Paragraph>
455
+ </div>
456
+ </div>
457
+ </TableRowCell>
458
+ </TableRow>
459
+ );
460
+
461
+ type LoadingTableRowsProps = {
462
+ rowCount: number;
463
+ rowSelectionEnabled: boolean;
464
+ isScrolled: boolean;
465
+ stickyFirstColumn: boolean;
466
+ getStickyColumn: (index: number) => boolean;
467
+ cellWidths: (string | number)[];
468
+ };
469
+
470
+ const LoadingTableRows = ({
471
+ rowCount,
472
+ // cellCount,
473
+ getStickyColumn,
474
+ stickyFirstColumn,
475
+ isScrolled,
476
+ rowSelectionEnabled,
477
+ cellWidths,
478
+ }: LoadingTableRowsProps) => (
479
+ <>
480
+ {Array.from({ length: rowCount }, (_value, index) => index).map((row, rowIndex) => (
481
+ <TableRow key={`skeleton-row-${row}`}>
482
+ {cellWidths.map((cellWidth, cellIndex) => (
483
+ <TableRowCellSkeleton
484
+ key={`skeleton-cell-${cellIndex}`}
485
+ isLastRow={rowIndex === rowCount - 1}
486
+ isFirstCell={cellIndex === 0}
487
+ isLastCell={cellIndex === cellWidths.length - 1}
488
+ stickyColumn={stickyFirstColumn && getStickyColumn(cellIndex)}
489
+ isScrolled={isScrolled}
490
+ showBorder={
491
+ isScrolled &&
492
+ ((rowSelectionEnabled && cellIndex === 1) ||
493
+ (!rowSelectionEnabled && cellIndex === 0))
494
+ }
495
+ cellWidth={cellWidth}
496
+ />
497
+ ))}
498
+ </TableRow>
499
+ ))}
500
+ </>
501
+ );
@@ -0,0 +1,152 @@
1
+ import { ColumnDef } from "@tanstack/react-table";
2
+
3
+ import { TableDataLarge, TableDataSmall } from "./table-data";
4
+
5
+ export const createColumnDefKitchenSink = (
6
+ clickCellButton: () => void,
7
+ clickButtonGroupCellButton: () => void
8
+ ): ColumnDef<TableDataLarge>[] => [
9
+ {
10
+ accessorKey: "id",
11
+ header: "ID",
12
+ meta: {
13
+ cellType: "leadText",
14
+ filterVariant: "string",
15
+ filterPlaceholder: "Search by id",
16
+ filterAriaLabel: "Search by id",
17
+ },
18
+ },
19
+ {
20
+ accessorKey: "name",
21
+ header: "Name",
22
+ meta: {
23
+ cellType: "bodyText",
24
+ filterVariant: "string",
25
+ filterPlaceholder: "Search by name",
26
+ filterAriaLabel: "Search by name",
27
+ },
28
+ },
29
+ {
30
+ accessorKey: "link",
31
+ header: "Link",
32
+ enableColumnFilter: false,
33
+ meta: {
34
+ cellType: "link",
35
+ },
36
+ },
37
+ {
38
+ accessorKey: "age",
39
+ header: "Age",
40
+ filterFn: "includesString",
41
+ meta: {
42
+ cellType: "number",
43
+ filterVariant: "string",
44
+ filterPlaceholder: "Search by age",
45
+ filterAriaLabel: "Search by age",
46
+ },
47
+ },
48
+ {
49
+ accessorKey: "badge",
50
+ header: "Badge",
51
+ filterFn: "filterOnFilterKey",
52
+ meta: {
53
+ cellType: "badge",
54
+ filterVariant: "select",
55
+ filterKey: "variant",
56
+ selectProps: {
57
+ value: "",
58
+ options: [
59
+ {
60
+ value: "",
61
+ label: "Default",
62
+ },
63
+ {
64
+ value: "information",
65
+ label: "Information",
66
+ },
67
+ {
68
+ value: "success",
69
+ label: "Success",
70
+ },
71
+ {
72
+ value: "warning",
73
+ label: "Warning",
74
+ },
75
+ {
76
+ value: "special",
77
+ label: "Special",
78
+ },
79
+ ],
80
+ "aria-label": "Select badge variant",
81
+ },
82
+ },
83
+ },
84
+ {
85
+ accessorKey: "position",
86
+ header: "Position",
87
+ filterFn: "includesString",
88
+ meta: {
89
+ cellType: "number",
90
+ filterVariant: "string",
91
+ numberCellAlignment: "right",
92
+ filterAriaLabel: "Filter on position",
93
+ },
94
+ },
95
+ {
96
+ id: "button",
97
+ header: "Action",
98
+ meta: {
99
+ cellType: "button",
100
+ onClick: clickCellButton,
101
+ },
102
+ },
103
+ {
104
+ accessorKey: "date",
105
+ header: "Date",
106
+ enableColumnFilter: false,
107
+ enableSorting: false,
108
+ meta: {
109
+ cellType: "date",
110
+ showTime: true,
111
+ },
112
+ },
113
+ {
114
+ id: "buttonGroup",
115
+ header: "Buttons",
116
+ meta: {
117
+ cellType: "buttonGroup",
118
+ onClick: clickButtonGroupCellButton,
119
+ },
120
+ },
121
+ ];
122
+
123
+ export const createColumnDefSmall = (): ColumnDef<TableDataSmall>[] => [
124
+ {
125
+ accessorKey: "id",
126
+ header: "ID",
127
+ meta: {
128
+ cellType: "leadText",
129
+ },
130
+ },
131
+ {
132
+ accessorKey: "name",
133
+ header: "Name",
134
+ meta: {
135
+ cellType: "bodyText",
136
+ },
137
+ },
138
+ {
139
+ accessorKey: "link",
140
+ header: "Link",
141
+ meta: {
142
+ cellType: "link",
143
+ },
144
+ },
145
+ {
146
+ accessorKey: "age",
147
+ header: "Age",
148
+ meta: {
149
+ cellType: "number",
150
+ },
151
+ },
152
+ ];