@purpurds/table 8.3.0 → 8.4.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.
Files changed (82) hide show
  1. package/dist/LICENSE.txt +205 -35
  2. package/dist/drag-indicator-circle.d.ts +13 -0
  3. package/dist/drag-indicator-circle.d.ts.map +1 -0
  4. package/dist/draggable-table.d.ts +23 -0
  5. package/dist/draggable-table.d.ts.map +1 -0
  6. package/dist/empty-table.d.ts +14 -0
  7. package/dist/empty-table.d.ts.map +1 -0
  8. package/dist/loading-table-rows.d.ts +13 -0
  9. package/dist/loading-table-rows.d.ts.map +1 -0
  10. package/dist/styles.css +1 -1
  11. package/dist/table-body.d.ts +2 -2
  12. package/dist/table-body.d.ts.map +1 -1
  13. package/dist/table-column-header-cell.d.ts +15 -2
  14. package/dist/table-column-header-cell.d.ts.map +1 -1
  15. package/dist/table-content.d.ts +42 -0
  16. package/dist/table-content.d.ts.map +1 -0
  17. package/dist/table-headers.d.ts +28 -0
  18. package/dist/table-headers.d.ts.map +1 -0
  19. package/dist/table-row-cell-skeleton.d.ts +1 -1
  20. package/dist/table-row-cell-skeleton.d.ts.map +1 -1
  21. package/dist/table-row-cell.d.ts +5 -2
  22. package/dist/table-row-cell.d.ts.map +1 -1
  23. package/dist/table-row.d.ts +2 -2
  24. package/dist/table-row.d.ts.map +1 -1
  25. package/dist/table-settings-drawer.d.ts +44 -11
  26. package/dist/table-settings-drawer.d.ts.map +1 -1
  27. package/dist/table.cjs.js +89 -85
  28. package/dist/table.cjs.js.map +1 -1
  29. package/dist/table.d.ts +3 -3
  30. package/dist/table.d.ts.map +1 -1
  31. package/dist/table.es.js +14397 -10195
  32. package/dist/table.es.js.map +1 -1
  33. package/dist/test-utils/helpers.d.ts +1 -0
  34. package/dist/test-utils/helpers.d.ts.map +1 -1
  35. package/dist/types.d.ts +23 -2
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/use-drag-handle.hook.d.ts +15 -0
  38. package/dist/use-drag-handle.hook.d.ts.map +1 -0
  39. package/dist/use-drag-indicator-position.hook.d.ts +19 -0
  40. package/dist/use-drag-indicator-position.hook.d.ts.map +1 -0
  41. package/dist/use-drop-indicator.hook.d.ts +15 -0
  42. package/dist/use-drop-indicator.hook.d.ts.map +1 -0
  43. package/dist/use-element-visibility.hook.d.ts +4 -0
  44. package/dist/use-element-visibility.hook.d.ts.map +1 -0
  45. package/dist/use-table-scroll.hook.d.ts +6 -0
  46. package/dist/use-table-scroll.hook.d.ts.map +1 -0
  47. package/dist/utils/custom-keyboard-coordinates.d.ts +8 -0
  48. package/dist/utils/custom-keyboard-coordinates.d.ts.map +1 -0
  49. package/package.json +27 -23
  50. package/src/drag-indicator-circle.tsx +36 -0
  51. package/src/draggable-table.test.tsx +381 -0
  52. package/src/draggable-table.tsx +191 -0
  53. package/src/empty-table.tsx +54 -0
  54. package/src/loading-table-rows.tsx +41 -0
  55. package/src/table-body.tsx +1 -3
  56. package/src/table-column-header-cell.tsx +135 -64
  57. package/src/table-content-drag.test.tsx +505 -0
  58. package/src/table-content.tsx +165 -0
  59. package/src/table-dnd-integration.test.tsx +425 -0
  60. package/src/table-drag-and-drop.test.tsx +276 -0
  61. package/src/table-headers.tsx +118 -0
  62. package/src/table-row-cell-skeleton.tsx +1 -1
  63. package/src/table-row-cell.test.tsx +2 -1
  64. package/src/table-row-cell.tsx +42 -31
  65. package/src/table-row.tsx +1 -3
  66. package/src/table-settings-drawer.module.scss +165 -2
  67. package/src/table-settings-drawer.test.tsx +0 -99
  68. package/src/table-settings-drawer.tsx +359 -53
  69. package/src/table.module.scss +191 -30
  70. package/src/table.stories.tsx +60 -4
  71. package/src/table.test.tsx +5 -1
  72. package/src/table.tsx +255 -213
  73. package/src/test-utils/helpers.ts +2 -0
  74. package/src/types.ts +25 -2
  75. package/src/use-drag-handle.hook.tsx +60 -0
  76. package/src/use-drag-handle.test.tsx +380 -0
  77. package/src/use-drag-indicator-position.hook.ts +74 -0
  78. package/src/use-drop-indicator.hook.ts +46 -0
  79. package/src/use-element-visibility.hook.ts +28 -0
  80. package/src/use-table-scroll.hook.tsx +30 -0
  81. package/src/utils/custom-keyboard-coordinates.ts +83 -0
  82. package/vitest.setup.ts +1 -1
@@ -0,0 +1,505 @@
1
+ import React from "react";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { axe } from "vitest-axe";
4
+
5
+ import { EmptyTableContent, LoadingTableContent, NormalTableContent } from "./table-content";
6
+
7
+ // Mock tanstack table
8
+ const mockTanstackTable = {
9
+ getVisibleLeafColumns: vi.fn(() => [{ id: "col1" }, { id: "col2" }]),
10
+ } as unknown as Parameters<typeof NormalTableContent>[0]["tanstackTable"];
11
+
12
+ // Mock row data
13
+ const mockTableRows = [
14
+ {
15
+ id: "row1",
16
+ getIsSelected: () => false,
17
+ getVisibleCells: () => [
18
+ {
19
+ id: "cell1",
20
+ column: {
21
+ id: "col1",
22
+ getIsFirstColumn: () => true,
23
+ getIsLastColumn: () => false,
24
+ columnDef: { meta: { cellType: "default" } },
25
+ },
26
+ getValue: () => "Value 1",
27
+ getContext: () => ({ getValue: () => "Value 1" }),
28
+ },
29
+ {
30
+ id: "cell2",
31
+ column: {
32
+ id: "col2",
33
+ getIsFirstColumn: () => false,
34
+ getIsLastColumn: () => true,
35
+ columnDef: { meta: { cellType: "default" } },
36
+ },
37
+ getValue: () => "Value 2",
38
+ getContext: () => ({ getValue: () => "Value 2" }),
39
+ },
40
+ ],
41
+ },
42
+ {
43
+ id: "row2",
44
+ getIsSelected: () => true,
45
+ getVisibleCells: () => [
46
+ {
47
+ id: "cell3",
48
+ column: {
49
+ id: "col1",
50
+ getIsFirstColumn: () => true,
51
+ getIsLastColumn: () => false,
52
+ columnDef: { meta: { cellType: "default" } },
53
+ },
54
+ getValue: () => "Value 3",
55
+ getContext: () => ({ getValue: () => "Value 3" }),
56
+ },
57
+ {
58
+ id: "cell4",
59
+ column: {
60
+ id: "col2",
61
+ getIsFirstColumn: () => false,
62
+ getIsLastColumn: () => true,
63
+ columnDef: { meta: { cellType: "default" } },
64
+ },
65
+ getValue: () => "Value 4",
66
+ getContext: () => ({ getValue: () => "Value 4" }),
67
+ },
68
+ ],
69
+ },
70
+ ] as unknown as Parameters<typeof NormalTableContent>[0]["tableRows"];
71
+
72
+ const mockRenderTableHeaders = () => (
73
+ <tr>
74
+ <th>Header 1</th>
75
+ <th>Header 2</th>
76
+ </tr>
77
+ );
78
+
79
+ describe("Table Content Components with Drag and Drop", () => {
80
+ describe("NormalTableContent", () => {
81
+ const defaultProps = {
82
+ tanstackTable: mockTanstackTable,
83
+ tableRows: mockTableRows,
84
+ showColumnFiltersEnabled: false,
85
+ fullWidth: false,
86
+ renderTableHeaders: mockRenderTableHeaders,
87
+ stickyFirstColumn: false,
88
+ getStickyColumn: () => false,
89
+ isScrolled: false,
90
+ showBorder: () => false,
91
+ enableColumnDrag: false,
92
+ activeId: null,
93
+ };
94
+
95
+ it("should render table with drag disabled by default", () => {
96
+ render(<NormalTableContent {...defaultProps} />);
97
+
98
+ const table = screen.getByRole("table");
99
+ expect(table).toBeInTheDocument();
100
+ expect(table.className).toContain("purpur-table__table");
101
+ });
102
+
103
+ it("should render table with drag enabled", () => {
104
+ render(<NormalTableContent {...defaultProps} enableColumnDrag={true} />);
105
+
106
+ const table = screen.getByRole("table");
107
+ expect(table).toBeInTheDocument();
108
+ });
109
+
110
+ it("should apply full width class when fullWidth is true", () => {
111
+ render(<NormalTableContent {...defaultProps} fullWidth={true} />);
112
+
113
+ const table = screen.getByRole("table");
114
+ expect(table.className).toContain("purpur-table__table--full-width");
115
+ });
116
+
117
+ it("should render correct number of rows", () => {
118
+ render(<NormalTableContent {...defaultProps} />);
119
+
120
+ const rows = screen.getAllByRole("row");
121
+ // Should have header row + data rows
122
+ expect(rows.length).toBeGreaterThan(mockTableRows.length);
123
+ });
124
+
125
+ it("should pass enableColumnDrag prop to table cells", () => {
126
+ render(<NormalTableContent {...defaultProps} enableColumnDrag={true} />);
127
+
128
+ // All cells should receive the enableColumnDrag prop
129
+ const table = screen.getByRole("table");
130
+ expect(table).toBeInTheDocument();
131
+ });
132
+
133
+ it("should pass draggingActive prop to cells when activeId matches", () => {
134
+ render(<NormalTableContent {...defaultProps} enableColumnDrag={true} activeId="col1" />);
135
+
136
+ const table = screen.getByRole("table");
137
+ expect(table).toBeInTheDocument();
138
+ });
139
+
140
+ it("should handle sticky columns with drag enabled", () => {
141
+ render(
142
+ <NormalTableContent
143
+ {...defaultProps}
144
+ stickyFirstColumn={true}
145
+ getStickyColumn={(index) => index === 0}
146
+ enableColumnDrag={true}
147
+ />
148
+ );
149
+
150
+ const table = screen.getByRole("table");
151
+ expect(table).toBeInTheDocument();
152
+ });
153
+
154
+ it("should handle scrolled state with drag enabled", () => {
155
+ render(<NormalTableContent {...defaultProps} isScrolled={true} enableColumnDrag={true} />);
156
+
157
+ const table = screen.getByRole("table");
158
+ expect(table).toBeInTheDocument();
159
+ });
160
+
161
+ it("should handle border showing with drag enabled", () => {
162
+ render(
163
+ <NormalTableContent
164
+ {...defaultProps}
165
+ showBorder={(index) => index === 0}
166
+ enableColumnDrag={true}
167
+ />
168
+ );
169
+
170
+ const table = screen.getByRole("table");
171
+ expect(table).toBeInTheDocument();
172
+ });
173
+
174
+ it("should be accessible with drag enabled", async () => {
175
+ const { container } = render(
176
+ <NormalTableContent {...defaultProps} enableColumnDrag={true} />
177
+ );
178
+
179
+ const results = await axe(container);
180
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
181
+ // @ts-ignore
182
+ expect(results).toHaveNoViolations();
183
+ });
184
+
185
+ it("should handle empty table rows", () => {
186
+ render(<NormalTableContent {...defaultProps} tableRows={[]} enableColumnDrag={true} />);
187
+
188
+ const table = screen.getByRole("table");
189
+ expect(table).toBeInTheDocument();
190
+ });
191
+
192
+ it("should handle selected rows with drag enabled", () => {
193
+ const selectedRows = mockTableRows.map(
194
+ (row: Parameters<typeof NormalTableContent>[0]["tableRows"][0]) => ({
195
+ ...row,
196
+ getIsSelected: () => true,
197
+ })
198
+ );
199
+
200
+ render(
201
+ <NormalTableContent {...defaultProps} tableRows={selectedRows} enableColumnDrag={true} />
202
+ );
203
+
204
+ const table = screen.getByRole("table");
205
+ expect(table).toBeInTheDocument();
206
+ });
207
+ });
208
+
209
+ describe("LoadingTableContent", () => {
210
+ const defaultProps = {
211
+ tanstackTable: mockTanstackTable,
212
+ tableRows: [],
213
+ showColumnFiltersEnabled: false,
214
+ fullWidth: false,
215
+ renderTableHeaders: mockRenderTableHeaders,
216
+ skeletonRows: 5,
217
+ getStickyColumn: () => false,
218
+ stickyFirstColumn: false,
219
+ isScrolled: false,
220
+ showBorder: () => false,
221
+ getColumnWidths: () => ["100px", "150px"],
222
+ };
223
+
224
+ it("should render loading table with drag context support", () => {
225
+ render(<LoadingTableContent {...defaultProps} />);
226
+
227
+ const table = screen.getByRole("table");
228
+ expect(table).toBeInTheDocument();
229
+ expect(table.className).toContain("purpur-table__table");
230
+ });
231
+
232
+ it("should apply full width class when fullWidth is true", () => {
233
+ render(<LoadingTableContent {...defaultProps} fullWidth={true} />);
234
+
235
+ const table = screen.getByRole("table");
236
+ expect(table.className).toContain("purpur-table__table--full-width");
237
+ });
238
+
239
+ it("should render with column filters enabled", () => {
240
+ render(<LoadingTableContent {...defaultProps} showColumnFiltersEnabled={true} />);
241
+
242
+ const table = screen.getByRole("table");
243
+ expect(table).toBeInTheDocument();
244
+ });
245
+
246
+ it("should handle sticky columns in loading state", () => {
247
+ render(
248
+ <LoadingTableContent
249
+ {...defaultProps}
250
+ stickyFirstColumn={true}
251
+ getStickyColumn={(index) => index === 0}
252
+ />
253
+ );
254
+
255
+ const table = screen.getByRole("table");
256
+ expect(table).toBeInTheDocument();
257
+ });
258
+
259
+ it("should handle scrolled state in loading", () => {
260
+ render(<LoadingTableContent {...defaultProps} isScrolled={true} />);
261
+
262
+ const table = screen.getByRole("table");
263
+ expect(table).toBeInTheDocument();
264
+ });
265
+
266
+ it("should pass correct skeleton row count", () => {
267
+ const skeletonRows = 3;
268
+ render(<LoadingTableContent {...defaultProps} skeletonRows={skeletonRows} />);
269
+
270
+ const table = screen.getByRole("table");
271
+ expect(table).toBeInTheDocument();
272
+ });
273
+
274
+ it("should pass column widths to loading rows", () => {
275
+ const columnWidths = ["120px", "180px", "200px"];
276
+ render(<LoadingTableContent {...defaultProps} getColumnWidths={() => columnWidths} />);
277
+
278
+ const table = screen.getByRole("table");
279
+ expect(table).toBeInTheDocument();
280
+ });
281
+
282
+ it("should be accessible in loading state", async () => {
283
+ const { container } = render(<LoadingTableContent {...defaultProps} />);
284
+
285
+ const results = await axe(container);
286
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
287
+ // @ts-ignore
288
+ expect(results).toHaveNoViolations();
289
+ });
290
+ });
291
+
292
+ describe("EmptyTableContent", () => {
293
+ const defaultProps = {
294
+ tanstackTable: mockTanstackTable,
295
+ tableRows: [],
296
+ showColumnFiltersEnabled: false,
297
+ fullWidth: false,
298
+ renderTableHeaders: mockRenderTableHeaders,
299
+ variant: "primary" as const,
300
+ emptyTableHeadingTag: "h2" as const,
301
+ emptyTableCopy: {
302
+ title: "No data available",
303
+ description: "There are no items to display in this table.",
304
+ },
305
+ emptyTableIcon: <div data-testid="empty-icon">Empty Icon</div>,
306
+ };
307
+
308
+ it("should render empty table with drag context support", () => {
309
+ render(<EmptyTableContent {...defaultProps} />);
310
+
311
+ const table = screen.getByRole("table");
312
+ expect(table).toBeInTheDocument();
313
+ expect(table.className).toContain("purpur-table__table");
314
+ });
315
+
316
+ it("should apply full width class when fullWidth is true", () => {
317
+ render(<EmptyTableContent {...defaultProps} fullWidth={true} />);
318
+
319
+ const table = screen.getByRole("table");
320
+ expect(table.className).toContain("purpur-table__table--full-width");
321
+ });
322
+
323
+ it("should render with column filters enabled", () => {
324
+ render(<EmptyTableContent {...defaultProps} showColumnFiltersEnabled={true} />);
325
+
326
+ const table = screen.getByRole("table");
327
+ expect(table).toBeInTheDocument();
328
+ });
329
+
330
+ it("should display empty table content", () => {
331
+ render(<EmptyTableContent {...defaultProps} />);
332
+
333
+ expect(screen.getByText(defaultProps.emptyTableCopy.title)).toBeInTheDocument();
334
+ expect(screen.getByText(defaultProps.emptyTableCopy.description)).toBeInTheDocument();
335
+ expect(screen.getByTestId("empty-icon")).toBeInTheDocument();
336
+ });
337
+
338
+ it("should handle different variants", () => {
339
+ const variants = ["primary", "secondary"] as const;
340
+
341
+ variants.forEach((variant) => {
342
+ const { unmount } = render(<EmptyTableContent {...defaultProps} variant={variant} />);
343
+
344
+ const table = screen.getByRole("table");
345
+ expect(table).toBeInTheDocument();
346
+
347
+ unmount();
348
+ });
349
+ });
350
+
351
+ it("should handle different heading tags", () => {
352
+ const headingTags = ["h1", "h2", "h3", "h4", "h5", "h6"] as const;
353
+
354
+ headingTags.forEach((tag) => {
355
+ const { unmount } = render(
356
+ <EmptyTableContent {...defaultProps} emptyTableHeadingTag={tag} />
357
+ );
358
+
359
+ const table = screen.getByRole("table");
360
+ expect(table).toBeInTheDocument();
361
+
362
+ unmount();
363
+ });
364
+ });
365
+
366
+ it("should handle missing icon", () => {
367
+ render(<EmptyTableContent {...defaultProps} emptyTableIcon={undefined} />);
368
+
369
+ const table = screen.getByRole("table");
370
+ expect(table).toBeInTheDocument();
371
+ expect(screen.queryByTestId("empty-icon")).not.toBeInTheDocument();
372
+ });
373
+
374
+ it("should calculate correct colSpan from tanstack table", () => {
375
+ const mockTableWithMoreColumns = {
376
+ getVisibleLeafColumns: vi.fn(() => [
377
+ { id: "col1" },
378
+ { id: "col2" },
379
+ { id: "col3" },
380
+ { id: "col4" },
381
+ ]),
382
+ } as unknown as Parameters<typeof EmptyTableContent>[0]["tanstackTable"];
383
+
384
+ render(<EmptyTableContent {...defaultProps} tanstackTable={mockTableWithMoreColumns} />);
385
+
386
+ const table = screen.getByRole("table");
387
+ expect(table).toBeInTheDocument();
388
+ });
389
+
390
+ it("should be accessible in empty state", async () => {
391
+ const { container } = render(<EmptyTableContent {...defaultProps} />);
392
+
393
+ const results = await axe(container);
394
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
395
+ // @ts-ignore
396
+ expect(results).toHaveNoViolations();
397
+ });
398
+
399
+ it("should handle empty copy strings", () => {
400
+ render(
401
+ <EmptyTableContent
402
+ {...defaultProps}
403
+ emptyTableCopy={{
404
+ title: "",
405
+ description: "",
406
+ }}
407
+ />
408
+ );
409
+
410
+ const table = screen.getByRole("table");
411
+ expect(table).toBeInTheDocument();
412
+ });
413
+ });
414
+
415
+ describe("Integration between content types", () => {
416
+ it("should maintain consistent table structure across all content types", () => {
417
+ const baseProps = {
418
+ tanstackTable: mockTanstackTable,
419
+ showColumnFiltersEnabled: false,
420
+ fullWidth: true,
421
+ renderTableHeaders: mockRenderTableHeaders,
422
+ };
423
+
424
+ // Normal content
425
+ const { container: normalContainer, unmount: unmountNormal } = render(
426
+ <NormalTableContent
427
+ {...baseProps}
428
+ tableRows={mockTableRows}
429
+ stickyFirstColumn={false}
430
+ getStickyColumn={() => false}
431
+ isScrolled={false}
432
+ showBorder={() => false}
433
+ enableColumnDrag={false}
434
+ activeId={null}
435
+ />
436
+ );
437
+
438
+ const normalTable = normalContainer.querySelector("table");
439
+ expect(normalTable?.className).toContain("purpur-table__table");
440
+ expect(normalTable?.className).toContain("purpur-table__table--full-width");
441
+ unmountNormal();
442
+
443
+ // Loading content
444
+ const { container: loadingContainer, unmount: unmountLoading } = render(
445
+ <LoadingTableContent
446
+ {...baseProps}
447
+ tableRows={[]}
448
+ skeletonRows={5}
449
+ getStickyColumn={() => false}
450
+ stickyFirstColumn={false}
451
+ isScrolled={false}
452
+ showBorder={() => false}
453
+ getColumnWidths={() => []}
454
+ />
455
+ );
456
+
457
+ const loadingTable = loadingContainer.querySelector("table");
458
+ expect(loadingTable?.className).toContain("purpur-table__table");
459
+ expect(loadingTable?.className).toContain("purpur-table__table--full-width");
460
+ unmountLoading();
461
+
462
+ // Empty content
463
+ const { container: emptyContainer, unmount: unmountEmpty } = render(
464
+ <EmptyTableContent
465
+ {...baseProps}
466
+ tableRows={[]}
467
+ variant="primary"
468
+ emptyTableHeadingTag="h2"
469
+ emptyTableCopy={{
470
+ title: "Empty",
471
+ description: "No data",
472
+ }}
473
+ />
474
+ );
475
+
476
+ const emptyTable = emptyContainer.querySelector("table");
477
+ expect(emptyTable?.className).toContain("purpur-table__table");
478
+ expect(emptyTable?.className).toContain("purpur-table__table--full-width");
479
+ unmountEmpty();
480
+ });
481
+
482
+ it("should handle drag and drop props consistently", () => {
483
+ // Test that drag-related props don't break any content type
484
+ expect(() => {
485
+ render(
486
+ <div>
487
+ <NormalTableContent
488
+ tanstackTable={mockTanstackTable}
489
+ tableRows={mockTableRows}
490
+ showColumnFiltersEnabled={false}
491
+ fullWidth={false}
492
+ renderTableHeaders={mockRenderTableHeaders}
493
+ stickyFirstColumn={false}
494
+ getStickyColumn={() => false}
495
+ isScrolled={false}
496
+ showBorder={() => false}
497
+ enableColumnDrag={true}
498
+ activeId="col1"
499
+ />
500
+ </div>
501
+ );
502
+ }).not.toThrow();
503
+ });
504
+ });
505
+ });
@@ -0,0 +1,165 @@
1
+ import React from "react";
2
+ import type { UniqueIdentifier } from "@dnd-kit/core";
3
+ import { type HeadingTagType } from "@purpurds/heading";
4
+ import type { Row, Table } from "@tanstack/react-table";
5
+ import type { RowData } from "@tanstack/react-table";
6
+ import c from "classnames/bind";
7
+
8
+ import { EmptyTable } from "./empty-table";
9
+ import { LoadingTableRows } from "./loading-table-rows";
10
+ import styles from "./table.module.scss";
11
+ import { TableBody } from "./table-body";
12
+ import { TableHeader } from "./table-header";
13
+ import { TableRow } from "./table-row";
14
+ import { TableRowCell } from "./table-row-cell";
15
+
16
+ const cx = c.bind(styles);
17
+ const rootClassName = "purpur-table";
18
+
19
+ type BaseTableContentProps<TData extends RowData> = {
20
+ tanstackTable: Table<TData>;
21
+ tableRows: Row<TData>[];
22
+ showColumnFiltersEnabled: boolean;
23
+ fullWidth: boolean;
24
+ renderTableHeaders: () => React.ReactNode;
25
+ };
26
+
27
+ type NormalTableContentProps<TData extends RowData> = BaseTableContentProps<TData> & {
28
+ stickyFirstColumn: boolean;
29
+ getStickyColumn: (index: number) => boolean;
30
+ isScrolled: boolean;
31
+ showBorder: (index: number) => boolean;
32
+ enableColumnDrag: boolean;
33
+ activeId: UniqueIdentifier | null;
34
+ };
35
+
36
+ export function NormalTableContent<TData extends RowData>({
37
+ tableRows,
38
+ showColumnFiltersEnabled,
39
+ fullWidth,
40
+ renderTableHeaders,
41
+ stickyFirstColumn,
42
+ getStickyColumn,
43
+ isScrolled,
44
+ showBorder,
45
+ enableColumnDrag,
46
+ 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
+ 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
+ variant,
139
+ emptyTableHeadingTag,
140
+ emptyTableCopy,
141
+ emptyTableIcon,
142
+ }: EmptyTableContentProps<TData>) {
143
+ return (
144
+ <table
145
+ className={cx([
146
+ `${rootClassName}__table`,
147
+ { [`${rootClassName}__table--full-width`]: fullWidth },
148
+ ])}
149
+ >
150
+ <TableHeader columnFiltersEnabled={showColumnFiltersEnabled}>
151
+ {renderTableHeaders()}
152
+ </TableHeader>
153
+ <TableBody>
154
+ <EmptyTable
155
+ variant={variant}
156
+ tag={emptyTableHeadingTag}
157
+ title={emptyTableCopy.title}
158
+ description={emptyTableCopy.description}
159
+ colSpan={tanstackTable.getVisibleLeafColumns().length}
160
+ icon={emptyTableIcon}
161
+ />
162
+ </TableBody>
163
+ </table>
164
+ );
165
+ }