@navikt/ds-react 8.10.0 → 8.10.2

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 (79) hide show
  1. package/cjs/data/table/column-header/DataTableColumnHeader.d.ts +1 -2
  2. package/cjs/data/table/column-header/DataTableColumnHeader.js +13 -11
  3. package/cjs/data/table/column-header/DataTableColumnHeader.js.map +1 -1
  4. package/cjs/data/table/column-header/useTableColumnResize.d.ts +5 -3
  5. package/cjs/data/table/column-header/useTableColumnResize.js +128 -53
  6. package/cjs/data/table/column-header/useTableColumnResize.js.map +1 -1
  7. package/cjs/data/table/helpers/collectTableRowEntries.d.ts +16 -0
  8. package/cjs/data/table/helpers/collectTableRowEntries.js +27 -0
  9. package/cjs/data/table/helpers/collectTableRowEntries.js.map +1 -0
  10. package/cjs/data/table/helpers/table-keyboard.js +3 -3
  11. package/cjs/data/table/helpers/table-keyboard.js.map +1 -1
  12. package/cjs/data/table/hooks/useTableExpansion.d.ts +9 -6
  13. package/cjs/data/table/hooks/useTableExpansion.js +36 -15
  14. package/cjs/data/table/hooks/useTableExpansion.js.map +1 -1
  15. package/cjs/data/table/hooks/useTableItems.d.ts +29 -0
  16. package/cjs/data/table/hooks/useTableItems.js +63 -0
  17. package/cjs/data/table/hooks/useTableItems.js.map +1 -0
  18. package/cjs/data/table/hooks/useTableKeyboardNav.js +3 -3
  19. package/cjs/data/table/hooks/useTableKeyboardNav.js.map +1 -1
  20. package/cjs/data/table/root/DataTableAuto.d.ts +18 -0
  21. package/cjs/data/table/root/DataTableAuto.js +71 -29
  22. package/cjs/data/table/root/DataTableAuto.js.map +1 -1
  23. package/cjs/data/table/root/DataTableRoot.context.d.ts +5 -3
  24. package/cjs/data/table/root/DataTableRoot.context.js.map +1 -1
  25. package/cjs/data/table/root/DataTableRoot.js +7 -4
  26. package/cjs/data/table/root/DataTableRoot.js.map +1 -1
  27. package/cjs/data/table/tr/DataTableTr.js +30 -32
  28. package/cjs/data/table/tr/DataTableTr.js.map +1 -1
  29. package/cjs/modal/Modal.js +3 -3
  30. package/cjs/modal/Modal.js.map +1 -1
  31. package/cjs/modal/types.d.ts +1 -0
  32. package/esm/data/table/column-header/DataTableColumnHeader.d.ts +1 -2
  33. package/esm/data/table/column-header/DataTableColumnHeader.js +14 -12
  34. package/esm/data/table/column-header/DataTableColumnHeader.js.map +1 -1
  35. package/esm/data/table/column-header/useTableColumnResize.d.ts +5 -3
  36. package/esm/data/table/column-header/useTableColumnResize.js +129 -54
  37. package/esm/data/table/column-header/useTableColumnResize.js.map +1 -1
  38. package/esm/data/table/helpers/collectTableRowEntries.d.ts +16 -0
  39. package/esm/data/table/helpers/collectTableRowEntries.js +25 -0
  40. package/esm/data/table/helpers/collectTableRowEntries.js.map +1 -0
  41. package/esm/data/table/helpers/table-keyboard.js +3 -3
  42. package/esm/data/table/helpers/table-keyboard.js.map +1 -1
  43. package/esm/data/table/hooks/useTableExpansion.d.ts +9 -6
  44. package/esm/data/table/hooks/useTableExpansion.js +36 -16
  45. package/esm/data/table/hooks/useTableExpansion.js.map +1 -1
  46. package/esm/data/table/hooks/useTableItems.d.ts +29 -0
  47. package/esm/data/table/hooks/useTableItems.js +58 -0
  48. package/esm/data/table/hooks/useTableItems.js.map +1 -0
  49. package/esm/data/table/hooks/useTableKeyboardNav.js +3 -3
  50. package/esm/data/table/hooks/useTableKeyboardNav.js.map +1 -1
  51. package/esm/data/table/root/DataTableAuto.d.ts +18 -0
  52. package/esm/data/table/root/DataTableAuto.js +72 -30
  53. package/esm/data/table/root/DataTableAuto.js.map +1 -1
  54. package/esm/data/table/root/DataTableRoot.context.d.ts +5 -3
  55. package/esm/data/table/root/DataTableRoot.context.js.map +1 -1
  56. package/esm/data/table/root/DataTableRoot.js +7 -4
  57. package/esm/data/table/root/DataTableRoot.js.map +1 -1
  58. package/esm/data/table/tr/DataTableTr.js +32 -34
  59. package/esm/data/table/tr/DataTableTr.js.map +1 -1
  60. package/esm/modal/Modal.js +3 -3
  61. package/esm/modal/Modal.js.map +1 -1
  62. package/esm/modal/types.d.ts +1 -0
  63. package/package.json +7 -7
  64. package/src/data/table/column-header/DataTableColumnHeader.tsx +22 -14
  65. package/src/data/table/column-header/useTableColumnResize.ts +152 -79
  66. package/src/data/table/helpers/collectTableRowEntries.ts +58 -0
  67. package/src/data/table/helpers/table-keyboard.ts +4 -4
  68. package/src/data/table/hooks/__tests__/useTableExpansion.test.tsx +115 -0
  69. package/src/data/table/hooks/__tests__/useTableItems.test.ts +131 -0
  70. package/src/data/table/hooks/useTableExpansion.tsx +63 -22
  71. package/src/data/table/hooks/useTableItems.ts +123 -0
  72. package/src/data/table/hooks/useTableKeyboardNav.ts +3 -3
  73. package/src/data/table/root/DataTableAuto.test.tsx +118 -0
  74. package/src/data/table/root/DataTableAuto.tsx +159 -49
  75. package/src/data/table/root/DataTableRoot.context.ts +4 -2
  76. package/src/data/table/root/DataTableRoot.tsx +20 -13
  77. package/src/data/table/tr/DataTableTr.tsx +48 -47
  78. package/src/modal/Modal.tsx +12 -6
  79. package/src/modal/types.ts +1 -0
@@ -0,0 +1,118 @@
1
+ import { fireEvent, render, screen } from "@testing-library/react";
2
+ import React from "react";
3
+ import { describe, expect, test } from "vitest";
4
+ import { DataTableColumnHeader } from "../column-header/DataTableColumnHeader";
5
+ import type { ColumnDefinitions } from "./DataTable.types";
6
+ import { DataTableAuto } from "./DataTableAuto";
7
+ import { DataTable } from "./DataTableRoot";
8
+
9
+ type TestRow = {
10
+ id: string;
11
+ name: string;
12
+ subRows?: TestRow[];
13
+ };
14
+
15
+ const data: TestRow[] = [
16
+ {
17
+ id: "root",
18
+ name: "Root",
19
+ subRows: [{ id: "child", name: "Child" }],
20
+ },
21
+ ];
22
+
23
+ const fallbackIdData: TestRow[] = [
24
+ {
25
+ id: "unused-root-1",
26
+ name: "Root",
27
+ subRows: [{ id: "unused-child", name: "Child" }],
28
+ },
29
+ {
30
+ id: "unused-root-2",
31
+ name: "Sibling",
32
+ },
33
+ ];
34
+
35
+ const columns: ColumnDefinitions<TestRow> = [
36
+ {
37
+ id: "name",
38
+ label: "Name",
39
+ header: "Name",
40
+ cell: (row) => row.name,
41
+ },
42
+ ];
43
+
44
+ describe("DataTableAuto", () => {
45
+ test("renders expanded child rows and includes them in select-all", () => {
46
+ render(
47
+ <DataTableAuto
48
+ columnDefinitions={columns}
49
+ data={data}
50
+ getRowId={(row) => row.id}
51
+ getSubRows={(row) => row.subRows ?? []}
52
+ selectionMode="multiple"
53
+ />,
54
+ );
55
+
56
+ expect(screen.queryByText("Child")).not.toBeInTheDocument();
57
+
58
+ fireEvent.click(screen.getByRole("button", { name: "Vis under-rader" }));
59
+
60
+ expect(screen.getByText("Child")).toBeInTheDocument();
61
+ expect(screen.getAllByRole("checkbox")).toHaveLength(3);
62
+
63
+ fireEvent.click(
64
+ screen.getByRole("checkbox", { name: "Velg alle synlige rader" }),
65
+ );
66
+
67
+ expect(
68
+ screen
69
+ .getAllByRole("checkbox")
70
+ .every((checkbox) => (checkbox as HTMLInputElement).checked),
71
+ ).toBe(true);
72
+ });
73
+
74
+ test("select-all checks all visible rows when fallback ids are used", () => {
75
+ render(
76
+ <DataTableAuto
77
+ columnDefinitions={columns}
78
+ data={fallbackIdData}
79
+ getSubRows={(row) => row.subRows ?? []}
80
+ defaultExpandedSubRowIds={[0]}
81
+ selectionMode="multiple"
82
+ />,
83
+ );
84
+
85
+ fireEvent.click(
86
+ screen.getByRole("checkbox", { name: "Velg alle synlige rader" }),
87
+ );
88
+
89
+ const rowCheckboxes = screen
90
+ .getAllByRole("checkbox")
91
+ .slice(1) as HTMLInputElement[];
92
+
93
+ expect(rowCheckboxes).toHaveLength(3);
94
+ expect(rowCheckboxes.every((checkbox) => checkbox.checked)).toBe(true);
95
+ });
96
+
97
+ test("does not render expansion controls in the manual table variant", () => {
98
+ render(
99
+ <DataTable>
100
+ <DataTable.Thead>
101
+ <DataTable.Tr>
102
+ <DataTableColumnHeader>Name</DataTableColumnHeader>
103
+ </DataTable.Tr>
104
+ </DataTable.Thead>
105
+ <DataTable.Tbody>
106
+ <DataTable.Tr>
107
+ <DataTable.Td>Root</DataTable.Td>
108
+ </DataTable.Tr>
109
+ </DataTable.Tbody>
110
+ </DataTable>,
111
+ );
112
+
113
+ expect(screen.getByText("Root")).toBeInTheDocument();
114
+ expect(
115
+ screen.queryByRole("button", { name: /vis detaljer|skjul detaljer/i }),
116
+ ).not.toBeInTheDocument();
117
+ });
118
+ });
@@ -1,5 +1,7 @@
1
1
  /** biome-ignore-all lint/correctness/useHookAtTopLevel: False positive because of the way forwardRef() is added */
2
2
  import React, { forwardRef, useMemo } from "react";
3
+ import { ChevronDownIcon, ChevronRightIcon } from "@navikt/aksel-icons";
4
+ import { Button } from "../../../button";
3
5
  import { Skeleton } from "../../../skeleton";
4
6
  import { useId } from "../../../utils-external";
5
7
  import { cl } from "../../../utils/helpers";
@@ -7,12 +9,18 @@ import { useMergeRefs } from "../../../utils/hooks";
7
9
  import { DataTableBaseCell } from "../base-cell/DataTableBaseCell";
8
10
  import { DataTableColumnHeader } from "../column-header/DataTableColumnHeader";
9
11
  import { DataTableEmptyState } from "../empty-state/DataTableEmptyState";
10
- import type { UseColumnOptionsResult } from "../hooks/useColumnOptions";
11
12
  import { useColumnOptions } from "../hooks/useColumnOptions";
12
13
  import {
13
14
  DataTableExpansionProvider,
15
+ getDataTableExpansionId,
14
16
  useDataTableExpansion,
15
17
  } from "../hooks/useTableExpansion";
18
+ import {
19
+ type ItemDetail,
20
+ TableItemsProvider,
21
+ useTableItems,
22
+ useTableItemsContext,
23
+ } from "../hooks/useTableItems";
16
24
  import { useTableKeyboardNav } from "../hooks/useTableKeyboardNav";
17
25
  import {
18
26
  type SelectionProps,
@@ -157,6 +165,11 @@ interface DataTableProps<T>
157
165
  * When provided, an expand toggle column is added automatically.
158
166
  */
159
167
  getDetailsPanelContent?: (rowData: T) => React.ReactNode;
168
+ /**
169
+ * Determines whether a row can be expanded to show details panel content.
170
+ * @default () => true
171
+ */
172
+ isDetailsPanelExpandable?: (rowData: T) => boolean;
160
173
  /**
161
174
  * Controlled list of expanded row IDs.
162
175
  * Use with `onDetailsPanelChange` for controlled usage, or `defaultDetailsPanelRowIds` for uncontrolled.
@@ -169,6 +182,10 @@ interface DataTableProps<T>
169
182
  defaultDetailsPanelRowIds?: (string | number)[];
170
183
  /**
171
184
  * Called when the list of expanded row IDs changes.
185
+ *
186
+ *
187
+ * TODO:
188
+ * - Docs: This pattern is called "Master / Detail" in general terms
172
189
  */
173
190
  onDetailsPanelChange?: (ids: (string | number)[]) => void;
174
191
  /**
@@ -182,6 +199,15 @@ interface DataTableProps<T>
182
199
  * @default false
183
200
  */
184
201
  showExpandAll?: boolean;
202
+ /**
203
+ * Function to get sub-rows for a given row, used for nested rows.
204
+ * When provided, an expand toggle column is added automatically.
205
+ */
206
+ getSubRows?: (rowData: T) => T[];
207
+ expandedSubRowIds?: (string | number)[];
208
+ defaultExpandedSubRowIds?: (string | number)[];
209
+ isSubRowExpandable?: (rowData: T) => boolean;
210
+ onExpandedSubRowIdsChange?: (ids: (string | number)[]) => void;
185
211
  }
186
212
 
187
213
  function DataTableAutoInner<T>(
@@ -215,11 +241,17 @@ function DataTableAutoInner<T>(
215
241
  loadingLabel = "Laster innhold",
216
242
  disableRowSelectionOnClick = false,
217
243
  getDetailsPanelContent,
244
+ isDetailsPanelExpandable,
218
245
  getDetailsPanelHeight,
219
246
  showExpandAll = false,
220
247
  detailsPanelRowIds,
221
248
  defaultDetailsPanelRowIds,
222
249
  onDetailsPanelChange,
250
+ getSubRows,
251
+ expandedSubRowIds,
252
+ defaultExpandedSubRowIds,
253
+ isSubRowExpandable,
254
+ onExpandedSubRowIdsChange,
223
255
  ...rest
224
256
  }: DataTableProps<T>,
225
257
  forwardedRef: React.ForwardedRef<HTMLTableElement>,
@@ -237,12 +269,25 @@ function DataTableAutoInner<T>(
237
269
 
238
270
  const mergedRef = useMergeRefs(forwardedRef, setTableRef);
239
271
 
272
+ const tableItems = useTableItems({
273
+ items: data,
274
+ getRowId,
275
+ getSubRows,
276
+ expandedSubRowIds,
277
+ defaultExpandedSubRowIds,
278
+ isSubRowExpandable,
279
+ onExpandedSubRowIdsChange,
280
+ });
281
+
240
282
  const allRowKeys = useMemo(() => {
241
- const resolvedGetRowId = (item: T, index: number): string | number =>
242
- getRowId?.(item, index) ?? index;
283
+ const rowKeys: (string | number)[] = [];
284
+
285
+ for (const details of tableItems.itemDetails.values()) {
286
+ rowKeys.push(details.id);
287
+ }
243
288
 
244
- return data.map((item, index) => resolvedGetRowId(item, index));
245
- }, [data, getRowId]);
289
+ return rowKeys;
290
+ }, [tableItems.itemDetails]);
246
291
 
247
292
  const tableSelectionState = useTableSelection({
248
293
  selectionMode: selectionModeProp,
@@ -258,6 +303,12 @@ function DataTableAutoInner<T>(
258
303
  selectionMode: tableSelectionState.selection.selectionMode,
259
304
  });
260
305
 
306
+ const fullWidthColSpan =
307
+ columns.length +
308
+ (layout === "fixed" ? 1 : 0) +
309
+ (tableSelectionState.selection.selectionMode !== "none" ? 1 : 0) +
310
+ (getDetailsPanelContent ? 1 : 0);
311
+
261
312
  const tableId = useId(id);
262
313
 
263
314
  return (
@@ -273,13 +324,15 @@ function DataTableAutoInner<T>(
273
324
  disableRowSelectionOnClick={disableRowSelectionOnClick}
274
325
  isLoading={isLoading}
275
326
  showLoadingOverlay={isLoading && !loadingState && !loadingRows}
327
+ columns={columns}
276
328
  >
277
329
  <DataTableExpansionProvider
278
330
  detailsPanelRowIds={detailsPanelRowIds}
279
331
  defaultDetailsPanelRowIds={defaultDetailsPanelRowIds}
280
332
  onDetailsPanelChange={onDetailsPanelChange}
281
- allRowKeys={allRowKeys}
333
+ itemDetails={tableItems.itemDetails}
282
334
  getDetailsPanelContent={getDetailsPanelContent}
335
+ isDetailsPanelExpandable={isDetailsPanelExpandable}
283
336
  getDetailsPanelHeight={getDetailsPanelHeight}
284
337
  showExpandAll={showExpandAll}
285
338
  >
@@ -323,17 +376,22 @@ function DataTableAutoInner<T>(
323
376
  })}
324
377
  </DataTableTr>
325
378
  </DataTableThead>
326
- <DataTableTbody>
327
- <DataTableAutoTBodyContent
328
- columns={columns}
329
- data={data}
330
- allRowKeys={allRowKeys}
331
- loadingState={loadingState}
332
- loadingRows={loadingRows}
333
- loadingLabel={loadingLabel}
334
- emptyState={emptyState}
335
- />
336
- </DataTableTbody>
379
+ <TableItemsProvider
380
+ itemDetails={tableItems.itemDetails}
381
+ items={tableItems.items}
382
+ onExpandedSubRowIdsChange={tableItems.onExpandedSubRowIdsChange}
383
+ isSubRowExpanded={tableItems.isSubRowExpanded}
384
+ >
385
+ <DataTableTbody>
386
+ <DataTableAutoTBodyContent
387
+ loadingState={loadingState}
388
+ loadingRows={loadingRows}
389
+ loadingLabel={loadingLabel}
390
+ emptyState={emptyState}
391
+ fullWidthColSpan={fullWidthColSpan}
392
+ />
393
+ </DataTableTbody>
394
+ </TableItemsProvider>
337
395
  </table>
338
396
  </div>
339
397
  </div>
@@ -342,30 +400,27 @@ function DataTableAutoInner<T>(
342
400
  );
343
401
  }
344
402
 
345
- interface DataTableAutoTBodyContentProps<T> {
346
- columns: UseColumnOptionsResult<T>["columns"];
347
- data: T[];
348
- allRowKeys: (string | number)[];
403
+ interface DataTableAutoTBodyContentProps {
349
404
  loadingState: React.ReactNode;
350
405
  loadingLabel: string;
351
406
  loadingRows?: number;
352
407
  emptyState: React.ReactNode;
408
+ fullWidthColSpan: number;
353
409
  }
354
410
 
355
- function DataTableAutoTBodyContent<T>({
356
- columns,
357
- data,
358
- allRowKeys,
411
+ function DataTableAutoTBodyContent({
359
412
  loadingState,
360
413
  loadingRows,
361
414
  loadingLabel,
362
415
  emptyState,
363
- }: DataTableAutoTBodyContentProps<T>) {
364
- const { isLoading } = useDataTableContext();
416
+ fullWidthColSpan,
417
+ }: DataTableAutoTBodyContentProps) {
418
+ const { items, itemDetails } = useTableItemsContext();
419
+ const { columns, isLoading } = useDataTableContext();
365
420
 
366
421
  if (isLoading && loadingState != null) {
367
422
  return (
368
- <DataTableLoadingState colSpan={columns.length}>
423
+ <DataTableLoadingState colSpan={fullWidthColSpan}>
369
424
  {loadingState}
370
425
  </DataTableLoadingState>
371
426
  );
@@ -375,7 +430,7 @@ function DataTableAutoTBodyContent<T>({
375
430
  return (
376
431
  <>
377
432
  <tr>
378
- <td colSpan={columns.length} className="aksel-sr-only">
433
+ <td colSpan={fullWidthColSpan} className="aksel-sr-only">
379
434
  {loadingLabel}
380
435
  </td>
381
436
  </tr>
@@ -397,29 +452,45 @@ function DataTableAutoTBodyContent<T>({
397
452
  );
398
453
  }
399
454
 
400
- if (data.length === 0 && emptyState !== undefined) {
455
+ if (items.length === 0 && emptyState !== undefined) {
401
456
  return (
402
- <DataTableEmptyState colSpan={columns.length}>
457
+ <DataTableEmptyState colSpan={fullWidthColSpan}>
403
458
  {emptyState}
404
459
  </DataTableEmptyState>
405
460
  );
406
461
  }
407
462
 
408
- const renderLoadingAnnoucement = isLoading && !loadingState && !loadingRows;
463
+ const renderLoadingAnnouncement = isLoading && !loadingState && !loadingRows;
464
+
465
+ return items.map((rowData) => {
466
+ const details = itemDetails.get(rowData);
467
+
468
+ /* Should in theory be impossible. Look about typing this? */
469
+ if (!details) {
470
+ return null;
471
+ }
472
+
473
+ const hasSubRows = details.children.length > 0;
409
474
 
410
- return data.map((rowData, rowIndex) => {
411
- const rowId = allRowKeys[rowIndex];
412
475
  return (
413
- <React.Fragment key={rowId}>
414
- {renderLoadingAnnoucement && (
476
+ <React.Fragment key={details.id}>
477
+ {renderLoadingAnnouncement && (
415
478
  <tr>
416
- <td colSpan={columns.length} className="aksel-sr-only">
479
+ <td colSpan={fullWidthColSpan} className="aksel-sr-only">
417
480
  {loadingLabel}
418
481
  </td>
419
482
  </tr>
420
483
  )}
421
- <DataTableTr rowId={rowId}>
484
+ <DataTableTr rowId={details.id}>
422
485
  {columns.map(({ isSticky, colDef }, colDefIndex) => {
486
+ const renderNestedToggle = colDefIndex === 0 && hasSubRows;
487
+ const renderNestedIndent =
488
+ colDefIndex === 0 && (details.level > 0 || hasSubRows);
489
+
490
+ const style: React.CSSProperties = {
491
+ "--__axc-data-table-nested-depth": details.level,
492
+ };
493
+
423
494
  return (
424
495
  <DataTableBaseCell
425
496
  /* TODO: Make this configurable */
@@ -427,47 +498,86 @@ function DataTableAutoTBodyContent<T>({
427
498
  key={colDef.id || colDefIndex}
428
499
  as={colDef.isRowHeader ? "th" : "td"}
429
500
  isSticky={isSticky}
501
+ data-nested={renderNestedIndent || undefined}
502
+ style={style}
430
503
  >
504
+ {renderNestedToggle && <NestedRowToggle details={details} />}
431
505
  {colDef.cell(rowData)}
432
506
  </DataTableBaseCell>
433
507
  );
434
508
  })}
435
509
  </DataTableTr>
436
510
  <DataTableExpandedRow
437
- rowId={rowId}
511
+ rowId={details.id}
438
512
  rowData={rowData}
439
- columnCount={columns.length}
513
+ fullWidthColSpan={fullWidthColSpan}
440
514
  />
441
515
  </React.Fragment>
442
516
  );
443
517
  });
444
518
  }
445
519
 
520
+ function NestedRowToggle({ details }: { details: ItemDetail<any> }) {
521
+ const { isSubRowExpanded, onExpandedSubRowIdsChange } =
522
+ useTableItemsContext();
523
+
524
+ const subRows = details.children;
525
+ const hasSubRows = subRows && subRows.length > 0;
526
+ const isRowExpanded = isSubRowExpanded(details.id);
527
+
528
+ return (
529
+ <div className="aksel-data-table__nested-toggle">
530
+ {hasSubRows && (
531
+ <Button
532
+ variant="tertiary"
533
+ data-color="neutral"
534
+ size="small"
535
+ onClick={(e) => {
536
+ e.stopPropagation();
537
+ onExpandedSubRowIdsChange(details.id);
538
+ }}
539
+ aria-expanded={isRowExpanded}
540
+ aria-label={isRowExpanded ? "Skjul under-rader" : "Vis under-rader"}
541
+ icon={
542
+ isRowExpanded ? (
543
+ <ChevronDownIcon aria-hidden />
544
+ ) : (
545
+ <ChevronRightIcon aria-hidden />
546
+ )
547
+ }
548
+ />
549
+ )}
550
+ </div>
551
+ );
552
+ }
553
+
446
554
  function DataTableExpandedRow<T>({
447
555
  rowId,
448
556
  rowData,
449
- columnCount,
557
+ fullWidthColSpan,
450
558
  }: {
451
559
  rowId: string | number;
452
560
  rowData: T;
453
- columnCount: number;
561
+ fullWidthColSpan: number;
454
562
  }) {
455
563
  const { tableId } = useDataTableContext();
456
- const expansionContext = useDataTableExpansion(false);
564
+ const {
565
+ enableDetailsPanel,
566
+ isExpanded,
567
+ getDetailsPanelContent,
568
+ getDetailsPanelHeight,
569
+ } = useDataTableExpansion();
457
570
 
458
- /* TODO: Is this the way we want to opt out? Might just be temp until auto and root is merged so they use same context */
459
- if (!expansionContext) {
571
+ if (!enableDetailsPanel) {
460
572
  return null;
461
573
  }
462
574
 
463
- const { isExpanded, getDetailsPanelContent, getDetailsPanelHeight } =
464
- expansionContext;
465
-
466
575
  if (!isExpanded(rowId)) {
467
576
  return null;
468
577
  }
469
578
 
470
579
  const content = getDetailsPanelContent?.(rowData);
580
+ const expansionId = getDataTableExpansionId(tableId, rowId);
471
581
 
472
582
  if (!content) {
473
583
  return null;
@@ -475,7 +585,7 @@ function DataTableExpandedRow<T>({
475
585
 
476
586
  return (
477
587
  <tr>
478
- <td id={`${tableId}-expansion-${rowId}`} colSpan={columnCount}>
588
+ <td id={expansionId} colSpan={fullWidthColSpan}>
479
589
  <div style={{ height: getDetailsPanelHeight?.(rowData) }}>
480
590
  {content}
481
591
  </div>
@@ -1,7 +1,8 @@
1
1
  import { createStrictContext } from "../../../utils/helpers";
2
+ import type { UseColumnOptionsResult } from "../hooks/useColumnOptions";
2
3
  import type { UseTableSelectionReturn } from "../hooks/useTableSelection";
3
4
 
4
- type DataTableContextProps = {
5
+ type DataTableContextProps<T> = {
5
6
  layout: "fixed" | "auto";
6
7
  withKeyboardNav: boolean;
7
8
  selectionState: UseTableSelectionReturn;
@@ -16,10 +17,11 @@ type DataTableContextProps = {
16
17
  disableRowSelectionOnClick: boolean;
17
18
  isLoading?: boolean;
18
19
  showLoadingOverlay: boolean;
20
+ columns: UseColumnOptionsResult<T>["columns"];
19
21
  };
20
22
 
21
23
  const { Provider: DataTableContextProvider, useContext: useDataTableContext } =
22
- createStrictContext<DataTableContextProps>({
24
+ createStrictContext<DataTableContextProps<any>>({
23
25
  name: "DataTableContext",
24
26
  errorMessage: "useDataTableContext must be used within DataTable",
25
27
  });
@@ -10,6 +10,8 @@ import {
10
10
  DataTableEmptyState,
11
11
  type DataTableEmptyStateProps,
12
12
  } from "../empty-state/DataTableEmptyState";
13
+ import { DataTableExpansionProvider } from "../hooks/useTableExpansion";
14
+ import type { ItemDetail } from "../hooks/useTableItems";
13
15
  import { useTableKeyboardNav } from "../hooks/useTableKeyboardNav";
14
16
  import { type SelectionProps } from "../hooks/useTableSelection";
15
17
  import { noSelectionState } from "../hooks/useTableSelection";
@@ -34,6 +36,8 @@ import {
34
36
  import { DataTableTr, type DataTableTrProps } from "../tr/DataTableTr";
35
37
  import { DataTableContextProvider } from "./DataTableRoot.context";
36
38
 
39
+ const EMPTY_ITEM_DETAILS = new Map<never, ItemDetail<never>>();
40
+
37
41
  interface DataTableProps
38
42
  extends React.HTMLAttributes<HTMLTableElement>, SelectionProps {
39
43
  children: React.ReactNode;
@@ -234,21 +238,24 @@ const DataTable = forwardRef<HTMLTableElement, DataTableProps>(
234
238
  onRowClick={undefined}
235
239
  disableRowSelectionOnClick={false}
236
240
  showLoadingOverlay={false}
241
+ columns={[]}
237
242
  >
238
- <div className="aksel-data-table__border-wrapper">
239
- <div className="aksel-data-table__scroll-wrapper">
240
- <table
241
- {...rest}
242
- ref={mergedRef}
243
- className={cl("aksel-data-table", className)}
244
- data-zebra-stripes={zebraStripes}
245
- data-truncate-content={truncateContent}
246
- data-density={rowDensity}
247
- data-layout={layout}
248
- tabIndex={tabIndex}
249
- />
243
+ <DataTableExpansionProvider itemDetails={EMPTY_ITEM_DETAILS}>
244
+ <div className="aksel-data-table__border-wrapper">
245
+ <div className="aksel-data-table__scroll-wrapper">
246
+ <table
247
+ {...rest}
248
+ ref={mergedRef}
249
+ className={cl("aksel-data-table", className)}
250
+ data-zebra-stripes={zebraStripes}
251
+ data-truncate-content={truncateContent}
252
+ data-density={rowDensity}
253
+ data-layout={layout}
254
+ tabIndex={tabIndex}
255
+ />
256
+ </div>
250
257
  </div>
251
- </div>
258
+ </DataTableExpansionProvider>
252
259
  </DataTableContextProvider>
253
260
  );
254
261
  },