@navikt/ds-react 8.10.2 → 8.10.4

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 (200) hide show
  1. package/cjs/action-menu/ActionMenu.js +1 -1
  2. package/cjs/action-menu/ActionMenu.js.map +1 -1
  3. package/cjs/data/stories/Data.test-data.d.ts +24 -0
  4. package/cjs/data/stories/Data.test-data.js +1616 -0
  5. package/cjs/data/stories/Data.test-data.js.map +1 -0
  6. package/cjs/data/table/column-header/DataTableColumnHeader.d.ts +4 -1
  7. package/cjs/data/table/column-header/DataTableColumnHeader.js +4 -2
  8. package/cjs/data/table/column-header/DataTableColumnHeader.js.map +1 -1
  9. package/cjs/data/table/column-header/useTableColumnResize.d.ts +39 -14
  10. package/cjs/data/table/column-header/useTableColumnResize.js +37 -39
  11. package/cjs/data/table/column-header/useTableColumnResize.js.map +1 -1
  12. package/cjs/data/table/details-panel-row/DataTableDetailsPanelRow.d.ts +6 -0
  13. package/cjs/data/table/details-panel-row/DataTableDetailsPanelRow.js +32 -0
  14. package/cjs/data/table/details-panel-row/DataTableDetailsPanelRow.js.map +1 -0
  15. package/cjs/data/table/helpers/collectTableRowEntries.d.ts +13 -5
  16. package/cjs/data/table/helpers/collectTableRowEntries.js +26 -19
  17. package/cjs/data/table/helpers/collectTableRowEntries.js.map +1 -1
  18. package/cjs/data/table/helpers/selection/SelectionSubtreeHelper.d.ts +46 -0
  19. package/cjs/data/table/helpers/selection/SelectionSubtreeHelper.js +112 -0
  20. package/cjs/data/table/helpers/selection/SelectionSubtreeHelper.js.map +1 -0
  21. package/cjs/data/table/helpers/selection/getMultipleSelectProps.d.ts +3 -2
  22. package/cjs/data/table/helpers/selection/getMultipleSelectProps.js +43 -19
  23. package/cjs/data/table/helpers/selection/getMultipleSelectProps.js.map +1 -1
  24. package/cjs/data/table/helpers/selection/selection.types.d.ts +1 -0
  25. package/cjs/data/table/helpers/table-keyboard.d.ts +1 -2
  26. package/cjs/data/table/helpers/table-keyboard.js +1 -2
  27. package/cjs/data/table/helpers/table-keyboard.js.map +1 -1
  28. package/cjs/data/table/hooks/useColumnOptions.js +18 -5
  29. package/cjs/data/table/hooks/useColumnOptions.js.map +1 -1
  30. package/cjs/data/table/hooks/useTableDetailsPanel.d.ts +62 -0
  31. package/cjs/data/table/hooks/{useTableExpansion.js → useTableDetailsPanel.js} +26 -19
  32. package/cjs/data/table/hooks/useTableDetailsPanel.js.map +1 -0
  33. package/cjs/data/table/hooks/useTableItems.d.ts +18 -17
  34. package/cjs/data/table/hooks/useTableItems.js +27 -15
  35. package/cjs/data/table/hooks/useTableItems.js.map +1 -1
  36. package/cjs/data/table/hooks/useTableSelection.d.ts +6 -3
  37. package/cjs/data/table/hooks/useTableSelection.js +10 -4
  38. package/cjs/data/table/hooks/useTableSelection.js.map +1 -1
  39. package/cjs/data/table/index.d.ts +1 -2
  40. package/cjs/data/table/index.js +22 -12
  41. package/cjs/data/table/index.js.map +1 -1
  42. package/cjs/data/table/root/DataTable.types.d.ts +12 -10
  43. package/cjs/data/table/root/DataTableRoot.context.d.ts +5 -1
  44. package/cjs/data/table/root/DataTableRoot.context.js.map +1 -1
  45. package/cjs/data/table/root/DataTableRoot.d.ts +79 -115
  46. package/cjs/data/table/root/DataTableRoot.js +167 -39
  47. package/cjs/data/table/root/DataTableRoot.js.map +1 -1
  48. package/cjs/data/table/root/DataTableRoot.legacy.d.ts +177 -0
  49. package/cjs/data/table/root/DataTableRoot.legacy.js +104 -0
  50. package/cjs/data/table/root/DataTableRoot.legacy.js.map +1 -0
  51. package/cjs/data/table/sub-row-toggle/DataTableSubRowToggle.d.ts +6 -0
  52. package/cjs/data/table/sub-row-toggle/DataTableSubRowToggle.js +21 -0
  53. package/cjs/data/table/sub-row-toggle/DataTableSubRowToggle.js.map +1 -0
  54. package/cjs/data/table/tr/DataTableTr.js +11 -11
  55. package/cjs/data/table/tr/DataTableTr.js.map +1 -1
  56. package/cjs/form/checkbox/Checkbox.js +1 -0
  57. package/cjs/form/checkbox/Checkbox.js.map +1 -1
  58. package/cjs/form/radio/Radio.js +7 -1
  59. package/cjs/form/radio/Radio.js.map +1 -1
  60. package/cjs/modal/types.d.ts +8 -4
  61. package/cjs/utils/components/dismissablelayer/DismissableLayer.js +1 -1
  62. package/cjs/utils/components/dismissablelayer/DismissableLayer.js.map +1 -1
  63. package/cjs/utils/components/floating/Floating.d.ts +16 -1
  64. package/cjs/utils/components/floating/Floating.js +50 -13
  65. package/cjs/utils/components/floating/Floating.js.map +1 -1
  66. package/cjs/utils/components/floating-menu/Menu.js +1 -1
  67. package/cjs/utils/components/floating-menu/Menu.js.map +1 -1
  68. package/cjs/utils/helpers/create-strict-context.js +1 -1
  69. package/cjs/utils/helpers/create-strict-context.js.map +1 -1
  70. package/cjs/utils/hooks/useControllableState.d.ts +5 -5
  71. package/cjs/utils/hooks/useControllableState.js.map +1 -1
  72. package/cjs/utils/hooks/useValueAsRef.js +1 -1
  73. package/cjs/utils/hooks/useValueAsRef.js.map +1 -1
  74. package/cjs/utils-external/hooks/useId.js +1 -1
  75. package/cjs/utils-external/hooks/useId.js.map +1 -1
  76. package/esm/action-menu/ActionMenu.js +1 -1
  77. package/esm/action-menu/ActionMenu.js.map +1 -1
  78. package/esm/data/stories/Data.test-data.d.ts +24 -0
  79. package/esm/data/stories/Data.test-data.js +1607 -0
  80. package/esm/data/stories/Data.test-data.js.map +1 -0
  81. package/esm/data/table/column-header/DataTableColumnHeader.d.ts +4 -1
  82. package/esm/data/table/column-header/DataTableColumnHeader.js +4 -2
  83. package/esm/data/table/column-header/DataTableColumnHeader.js.map +1 -1
  84. package/esm/data/table/column-header/useTableColumnResize.d.ts +39 -14
  85. package/esm/data/table/column-header/useTableColumnResize.js +38 -40
  86. package/esm/data/table/column-header/useTableColumnResize.js.map +1 -1
  87. package/esm/data/table/details-panel-row/DataTableDetailsPanelRow.d.ts +6 -0
  88. package/esm/data/table/details-panel-row/DataTableDetailsPanelRow.js +27 -0
  89. package/esm/data/table/details-panel-row/DataTableDetailsPanelRow.js.map +1 -0
  90. package/esm/data/table/helpers/collectTableRowEntries.d.ts +13 -5
  91. package/esm/data/table/helpers/collectTableRowEntries.js +26 -19
  92. package/esm/data/table/helpers/collectTableRowEntries.js.map +1 -1
  93. package/esm/data/table/helpers/selection/SelectionSubtreeHelper.d.ts +46 -0
  94. package/esm/data/table/helpers/selection/SelectionSubtreeHelper.js +109 -0
  95. package/esm/data/table/helpers/selection/SelectionSubtreeHelper.js.map +1 -0
  96. package/esm/data/table/helpers/selection/getMultipleSelectProps.d.ts +3 -2
  97. package/esm/data/table/helpers/selection/getMultipleSelectProps.js +43 -19
  98. package/esm/data/table/helpers/selection/getMultipleSelectProps.js.map +1 -1
  99. package/esm/data/table/helpers/selection/selection.types.d.ts +1 -0
  100. package/esm/data/table/helpers/table-keyboard.d.ts +1 -2
  101. package/esm/data/table/helpers/table-keyboard.js +1 -2
  102. package/esm/data/table/helpers/table-keyboard.js.map +1 -1
  103. package/esm/data/table/hooks/useColumnOptions.js +18 -5
  104. package/esm/data/table/hooks/useColumnOptions.js.map +1 -1
  105. package/esm/data/table/hooks/useTableDetailsPanel.d.ts +62 -0
  106. package/esm/data/table/hooks/useTableDetailsPanel.js +58 -0
  107. package/esm/data/table/hooks/useTableDetailsPanel.js.map +1 -0
  108. package/esm/data/table/hooks/useTableItems.d.ts +18 -17
  109. package/esm/data/table/hooks/useTableItems.js +27 -15
  110. package/esm/data/table/hooks/useTableItems.js.map +1 -1
  111. package/esm/data/table/hooks/useTableSelection.d.ts +6 -3
  112. package/esm/data/table/hooks/useTableSelection.js +10 -4
  113. package/esm/data/table/hooks/useTableSelection.js.map +1 -1
  114. package/esm/data/table/index.d.ts +1 -2
  115. package/esm/data/table/index.js +21 -1
  116. package/esm/data/table/index.js.map +1 -1
  117. package/esm/data/table/root/DataTable.types.d.ts +12 -10
  118. package/esm/data/table/root/DataTableRoot.context.d.ts +5 -1
  119. package/esm/data/table/root/DataTableRoot.context.js.map +1 -1
  120. package/esm/data/table/root/DataTableRoot.d.ts +79 -115
  121. package/esm/data/table/root/DataTableRoot.js +174 -37
  122. package/esm/data/table/root/DataTableRoot.js.map +1 -1
  123. package/esm/data/table/root/DataTableRoot.legacy.d.ts +177 -0
  124. package/esm/data/table/root/DataTableRoot.legacy.js +59 -0
  125. package/esm/data/table/root/DataTableRoot.legacy.js.map +1 -0
  126. package/esm/data/table/sub-row-toggle/DataTableSubRowToggle.d.ts +6 -0
  127. package/esm/data/table/sub-row-toggle/DataTableSubRowToggle.js +16 -0
  128. package/esm/data/table/sub-row-toggle/DataTableSubRowToggle.js.map +1 -0
  129. package/esm/data/table/tr/DataTableTr.js +11 -11
  130. package/esm/data/table/tr/DataTableTr.js.map +1 -1
  131. package/esm/form/checkbox/Checkbox.js +1 -0
  132. package/esm/form/checkbox/Checkbox.js.map +1 -1
  133. package/esm/form/radio/Radio.js +7 -1
  134. package/esm/form/radio/Radio.js.map +1 -1
  135. package/esm/modal/types.d.ts +8 -4
  136. package/esm/utils/components/dismissablelayer/DismissableLayer.js +1 -1
  137. package/esm/utils/components/dismissablelayer/DismissableLayer.js.map +1 -1
  138. package/esm/utils/components/floating/Floating.d.ts +16 -1
  139. package/esm/utils/components/floating/Floating.js +48 -13
  140. package/esm/utils/components/floating/Floating.js.map +1 -1
  141. package/esm/utils/components/floating-menu/Menu.js +2 -2
  142. package/esm/utils/components/floating-menu/Menu.js.map +1 -1
  143. package/esm/utils/helpers/create-strict-context.js +1 -1
  144. package/esm/utils/helpers/create-strict-context.js.map +1 -1
  145. package/esm/utils/hooks/useControllableState.d.ts +5 -5
  146. package/esm/utils/hooks/useControllableState.js.map +1 -1
  147. package/esm/utils/hooks/useValueAsRef.js +1 -1
  148. package/esm/utils/hooks/useValueAsRef.js.map +1 -1
  149. package/esm/utils-external/hooks/useId.js +1 -1
  150. package/esm/utils-external/hooks/useId.js.map +1 -1
  151. package/package.json +3 -3
  152. package/src/action-menu/ActionMenu.tsx +1 -1
  153. package/src/data/stories/Data.test-data.tsx +1703 -0
  154. package/src/data/table/column-header/DataTableColumnHeader.tsx +11 -7
  155. package/src/data/table/column-header/useTableColumnResize.ts +95 -54
  156. package/src/data/table/details-panel-row/DataTableDetailsPanelRow.tsx +53 -0
  157. package/src/data/table/helpers/collectTableRowEntries.ts +55 -31
  158. package/src/data/table/helpers/selection/SelectionSubtreeHelper.test.ts +66 -0
  159. package/src/data/table/helpers/selection/SelectionSubtreeHelper.ts +162 -0
  160. package/src/data/table/helpers/selection/getMultipleSelectProps.ts +57 -20
  161. package/src/data/table/helpers/selection/selection.types.ts +1 -0
  162. package/src/data/table/helpers/table-keyboard.ts +1 -2
  163. package/src/data/table/hooks/__tests__/useTableItems.test.ts +27 -6
  164. package/src/data/table/hooks/__tests__/useTableSelection.test.ts +182 -58
  165. package/src/data/table/hooks/useColumnOptions.ts +19 -5
  166. package/src/data/table/hooks/useTableDetailsPanel.tsx +182 -0
  167. package/src/data/table/hooks/useTableItems.ts +74 -60
  168. package/src/data/table/hooks/useTableSelection.ts +27 -12
  169. package/src/data/table/index.tsx +5 -3
  170. package/src/data/table/root/DataTable.types.ts +25 -10
  171. package/src/data/table/root/DataTableRoot.context.ts +5 -1
  172. package/src/data/table/root/DataTableRoot.legacy.tsx +297 -0
  173. package/src/data/table/root/DataTableRoot.tsx +483 -219
  174. package/src/data/table/sub-row-toggle/DataTableSubRowToggle.tsx +39 -0
  175. package/src/data/table/tr/DataTableTr.tsx +14 -13
  176. package/src/form/checkbox/Checkbox.tsx +1 -0
  177. package/src/form/radio/Radio.tsx +7 -1
  178. package/src/modal/types.ts +8 -4
  179. package/src/utils/components/dismissablelayer/DismissableLayer.tsx +1 -1
  180. package/src/utils/components/floating/Floating.tsx +56 -13
  181. package/src/utils/components/floating-menu/Menu.tsx +4 -1
  182. package/src/utils/helpers/create-strict-context.tsx +1 -1
  183. package/src/utils/hooks/useControllableState.ts +11 -8
  184. package/src/utils/hooks/useValueAsRef.ts +1 -1
  185. package/src/utils-external/hooks/useId.ts +1 -1
  186. package/cjs/data/table/hooks/useTableExpansion.d.ts +0 -29
  187. package/cjs/data/table/hooks/useTableExpansion.js.map +0 -1
  188. package/cjs/data/table/root/DataTableAuto.d.ts +0 -174
  189. package/cjs/data/table/root/DataTableAuto.js +0 -206
  190. package/cjs/data/table/root/DataTableAuto.js.map +0 -1
  191. package/esm/data/table/hooks/useTableExpansion.d.ts +0 -29
  192. package/esm/data/table/hooks/useTableExpansion.js +0 -51
  193. package/esm/data/table/hooks/useTableExpansion.js.map +0 -1
  194. package/esm/data/table/root/DataTableAuto.d.ts +0 -174
  195. package/esm/data/table/root/DataTableAuto.js +0 -170
  196. package/esm/data/table/root/DataTableAuto.js.map +0 -1
  197. package/src/data/table/hooks/__tests__/useTableExpansion.test.tsx +0 -115
  198. package/src/data/table/hooks/useTableExpansion.tsx +0 -141
  199. package/src/data/table/root/DataTableAuto.test.tsx +0 -118
  200. package/src/data/table/root/DataTableAuto.tsx +0 -603
@@ -3,55 +3,51 @@ import { createStrictContext } from "../../../utils/helpers";
3
3
  import { useControllableState } from "../../../utils/hooks";
4
4
  import {
5
5
  type ItemDetail,
6
+ type TableRowEntryId,
6
7
  collectTableRowEntries,
7
8
  } from "../helpers/collectTableRowEntries";
8
9
 
10
+ type SubRowsProps<T> = {
11
+ getRows?: (rowData: T) => T[];
12
+ expandedRowIds?: (string | number)[];
13
+ defaultExpandedRowIds?: (string | number)[];
14
+ isRowExpandable?: (rowData: T) => boolean;
15
+ onExpandedRowIdsChange?: (ids: (string | number)[]) => void;
16
+ };
17
+
9
18
  type UseTableItemsArgs<T> = {
10
19
  items: T[];
11
- getRowId?: (rowData: T, index: number) => string | number;
12
- /**
13
- * Master - Detail pattern props
14
- */
15
- /* expandedDetailsPanelIds?: (string | number)[];
16
- defaultExpandedDetailsPanelIds?: (string | number)[];
17
- isDetailsPanelExpandable?: (rowData: T) => boolean;
18
- onDetailsPanelChange?: (ids: (string | number)[]) => void;
19
-
20
- getDetailsPanelHeight?: (row: T) => number | "auto";
21
- getDetailsPanelContent?: (row: T) => React.ReactNode; */
22
- /**
23
- * Expanded/Nested rows pattern props
24
- */
25
- getSubRows?: (rowData: T) => T[];
26
- expandedSubRowIds?: (string | number)[];
27
- defaultExpandedSubRowIds?: (string | number)[];
28
- isSubRowExpandable?: (rowData: T) => boolean;
29
- onExpandedSubRowIdsChange?: (ids: (string | number)[]) => void;
20
+ getRowId: (rowData: T, index: number) => TableRowEntryId;
21
+ subRows?: SubRowsProps<T>;
30
22
  };
31
23
 
32
24
  type useTableItemsReturn<T> = {
33
25
  items: T[];
34
26
  itemDetails: Map<T, ItemDetail<T>>;
35
- onExpandedSubRowIdsChange: (id: string | number) => void;
27
+ /** Row ids for the rows currently rendered in the table body. */
28
+ visibleRowIds: TableRowEntryId[];
29
+ /** Direct child ids for each row, used to traverse selection groups lazily. */
30
+ childRowIdsById: Map<TableRowEntryId, TableRowEntryId[]>;
31
+ onExpandedRowIdsChange: (id: string | number) => void;
36
32
  isSubRowExpanded: (id: string | number) => boolean;
37
33
  };
38
34
 
39
35
  function useTableItems<T>(args: UseTableItemsArgs<T>): useTableItemsReturn<T> {
36
+ const { items, subRows = {}, getRowId } = args;
37
+
40
38
  const {
41
- items,
42
- expandedSubRowIds,
43
- defaultExpandedSubRowIds,
44
- getSubRows,
45
- getRowId,
46
- onExpandedSubRowIdsChange,
47
- isSubRowExpandable,
48
- } = args;
39
+ expandedRowIds,
40
+ defaultExpandedRowIds,
41
+ getRows,
42
+ onExpandedRowIdsChange,
43
+ isRowExpandable,
44
+ } = subRows;
49
45
 
50
46
  const [nestedSubRowsExpandedIds, setNestedSubRowsExpandedIds] =
51
47
  useControllableState({
52
- value: expandedSubRowIds,
53
- defaultValue: defaultExpandedSubRowIds ?? [],
54
- onChange: onExpandedSubRowIdsChange,
48
+ value: expandedRowIds,
49
+ defaultValue: defaultExpandedRowIds ?? [],
50
+ onChange: onExpandedRowIdsChange,
55
51
  });
56
52
 
57
53
  const expandedIdsSet = useMemo(
@@ -59,38 +55,52 @@ function useTableItems<T>(args: UseTableItemsArgs<T>): useTableItemsReturn<T> {
59
55
  [nestedSubRowsExpandedIds],
60
56
  );
61
57
 
62
- const { itemDetails, visibleItems } = useMemo(() => {
63
- const rowEntriesMap = collectTableRowEntries({
64
- items,
65
- getRowId,
66
- getSubRows,
67
- isSubRowExpandable,
68
- });
58
+ const { itemDetails, visibleItems, visibleRowIds, childRowIdsById } =
59
+ useMemo(() => {
60
+ const { itemDetails: rowEntriesMap, childRowIdsById: _childRowIdsById } =
61
+ collectTableRowEntries({
62
+ items,
63
+ getRowId,
64
+ getRows,
65
+ isRowExpandable,
66
+ });
69
67
 
70
- const localVisibleItems: T[] = [];
71
- const addVisibleRows = (rowData: T) => {
72
- localVisibleItems.push(rowData);
68
+ const localVisibleItems: T[] = [];
69
+ const localVisibleRowIds: TableRowEntryId[] = [];
73
70
 
74
- const details = rowEntriesMap.get(rowData);
71
+ const addVisibleRows = (rowData: T): TableRowEntryId[] => {
72
+ const details = rowEntriesMap.get(rowData);
75
73
 
76
- if (!details || !expandedIdsSet.has(details.id)) {
77
- return;
78
- }
74
+ if (!details) {
75
+ return [];
76
+ }
79
77
 
80
- for (const childRow of details.children) {
81
- addVisibleRows(childRow);
82
- }
83
- };
78
+ localVisibleItems.push(rowData);
79
+ localVisibleRowIds.push(details.id);
80
+
81
+ const visibleDescendantRowIds: TableRowEntryId[] = [];
82
+
83
+ if (expandedIdsSet.has(details.id)) {
84
+ for (const childRow of details.children) {
85
+ const childVisibleRowIds = addVisibleRows(childRow);
86
+ visibleDescendantRowIds.push(...childVisibleRowIds);
87
+ }
88
+ }
84
89
 
85
- for (const rowData of items) {
86
- addVisibleRows(rowData);
87
- }
90
+ return [details.id, ...visibleDescendantRowIds];
91
+ };
92
+
93
+ for (const rowData of items) {
94
+ addVisibleRows(rowData);
95
+ }
88
96
 
89
- return {
90
- visibleItems: localVisibleItems,
91
- itemDetails: rowEntriesMap,
92
- };
93
- }, [getSubRows, items, getRowId, isSubRowExpandable, expandedIdsSet]);
97
+ return {
98
+ visibleItems: localVisibleItems,
99
+ visibleRowIds: localVisibleRowIds,
100
+ childRowIdsById: _childRowIdsById,
101
+ itemDetails: rowEntriesMap,
102
+ };
103
+ }, [getRows, items, getRowId, isRowExpandable, expandedIdsSet]);
94
104
 
95
105
  const handleExpandedSubRowIdChange = useCallback(
96
106
  (id: string | number) => {
@@ -106,18 +116,22 @@ function useTableItems<T>(args: UseTableItemsArgs<T>): useTableItemsReturn<T> {
106
116
  return {
107
117
  items: visibleItems,
108
118
  itemDetails,
109
- onExpandedSubRowIdsChange: handleExpandedSubRowIdChange,
119
+ visibleRowIds,
120
+ childRowIdsById,
121
+ onExpandedRowIdsChange: handleExpandedSubRowIdChange,
110
122
  isSubRowExpanded: (id: string | number) => expandedIdsSet.has(id),
111
123
  };
112
124
  }
113
125
 
114
126
  const { Provider: TableItemsProvider, useContext: useTableItemsContext } =
115
127
  /* TODO: Can we type this better? */
116
- createStrictContext<useTableItemsReturn<any>>({
128
+ createStrictContext<
129
+ Omit<useTableItemsReturn<any>, "visibleRowIds" | "childRowIdsById">
130
+ >({
117
131
  name: "TableItemsContext",
118
132
  errorMessage:
119
133
  "useTableItemsContext must be used within a TableItemsProvider",
120
134
  });
121
135
 
122
136
  export { useTableItems, TableItemsProvider, useTableItemsContext };
123
- export type { ItemDetail };
137
+ export type { ItemDetail, SubRowsProps };
@@ -9,24 +9,34 @@ import type {
9
9
  TableSelection,
10
10
  } from "../helpers/selection/selection.types";
11
11
 
12
- type UseTableSelectionArgs = SelectionProps & {
13
- /* This is needed for multiple selection to know which keys to select when "select all" is used */
14
- allRowKeys: (string | number)[];
12
+ type UseTableSelectionArgs = {
13
+ selection?: SelectionProps;
14
+ /* Visible rows manage the header checkbox state and render selection cells. */
15
+ visibleRowIds: (string | number)[];
16
+ /* Direct child ids let selection walk nested rows lazily. */
17
+ childRowIdsById?: Map<string | number, (string | number)[]>;
15
18
  };
16
19
 
17
20
  type UseTableSelectionReturn = {
18
21
  selection: TableSelection;
19
22
  renderSelection: boolean;
23
+ disableRowSelectionOnClick: boolean;
20
24
  };
21
25
 
22
26
  function useTableSelection({
23
- selectionMode = "none",
24
- defaultSelectedKeys,
25
- selectedKeys: selectedKeysProp,
26
- onSelectionChange,
27
- disabledSelectionKeys = [],
28
- allRowKeys,
27
+ selection = {},
28
+ visibleRowIds = [],
29
+ childRowIdsById,
29
30
  }: UseTableSelectionArgs): UseTableSelectionReturn {
31
+ const {
32
+ selectionMode = "none",
33
+ defaultSelectedKeys,
34
+ selectedKeys: selectedKeysProp,
35
+ onSelectionChange,
36
+ disabledSelectionKeys = [],
37
+ disableRowSelectionOnClick = false,
38
+ } = selection;
39
+
30
40
  const radioGroupName = useId();
31
41
 
32
42
  const [selectedKeys, setSelectedKeys] = useControllableState<SelectedKeysT>({
@@ -56,6 +66,7 @@ function useTableSelection({
56
66
  ...baseSelection,
57
67
  selectedKeys: [],
58
68
  },
69
+ disableRowSelectionOnClick,
59
70
  renderSelection: false,
60
71
  };
61
72
  }
@@ -72,7 +83,8 @@ function useTableSelection({
72
83
  name: radioGroupName,
73
84
  }),
74
85
  },
75
- renderSelection: allRowKeys.length !== 0,
86
+ disableRowSelectionOnClick,
87
+ renderSelection: visibleRowIds.length !== 0,
76
88
  };
77
89
  }
78
90
 
@@ -85,10 +97,12 @@ function useTableSelection({
85
97
  selectedKeys,
86
98
  setSelectedKeys,
87
99
  disabledKeysSet,
88
- allRowKeys,
100
+ visibleRowIds,
101
+ childRowIdsById,
89
102
  }),
90
103
  },
91
- renderSelection: allRowKeys.length !== 0,
104
+ disableRowSelectionOnClick,
105
+ renderSelection: visibleRowIds.length !== 0,
92
106
  };
93
107
  }
94
108
 
@@ -102,6 +116,7 @@ const noSelectionState: UseTableSelectionReturn = {
102
116
  disabledSelectionKeys: [],
103
117
  isRowSelected: () => false,
104
118
  },
119
+ disableRowSelectionOnClick: false,
105
120
  renderSelection: false,
106
121
  };
107
122
 
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- export {
2
+ /* export {
3
3
  default as DataTable,
4
4
  DataTableCaption,
5
5
  DataTableThead,
@@ -8,7 +8,7 @@ export {
8
8
  DataTableTh,
9
9
  DataTableTd,
10
10
  DataTableTfoot,
11
- } from "./root/DataTableRoot";
11
+ } from "./root/DataTableRoot.legacy";
12
12
  export type {
13
13
  DataTableProps,
14
14
  DataTableCaptionProps,
@@ -18,4 +18,6 @@ export type {
18
18
  DataTableThProps,
19
19
  DataTableTdProps,
20
20
  DataTableTfootProps,
21
- } from "./root/DataTableRoot";
21
+ } from "./root/DataTableRoot.legacy"; */
22
+
23
+ export { DataTable, type DataTableProps } from "./root/DataTableRoot";
@@ -1,3 +1,5 @@
1
+ import type { ResizeProps } from "../column-header/useTableColumnResize";
2
+
1
3
  type SortDirection = "asc" | "desc" | "none";
2
4
 
3
5
  /**
@@ -5,18 +7,24 @@ type SortDirection = "asc" | "desc" | "none";
5
7
  * - Consider "accessorKey" or similar to allow simple column definitions without a cell function.
6
8
  * - Add "align" property for better control over text alignment in cells.
7
9
  */
8
- type ColumnDefinition<T> = {
10
+ type ColumnDefinition<T, DetailsT = Record<string, any>> = Pick<
11
+ ResizeProps,
12
+ | "resizable"
13
+ | "width"
14
+ | "defaultWidth"
15
+ | "autoWidth"
16
+ | "minWidth"
17
+ | "maxWidth"
18
+ | "onWidthChange"
19
+ > & {
9
20
  id: string;
10
- width?: number | string;
11
- defaultWidth?: number | string;
12
- minWidth?: number | string;
13
- maxWidth?: number | string;
14
21
  /**
15
- * Currently only handles cell alignment.
16
- * TODO: Should this include centering?
17
- * type "icon" or something to avoid ellipsis on actions, tags etc
22
+ * Text alignment for cells in this column.
23
+ *
24
+ *
25
+ * @default "left"
18
26
  */
19
- type?: "string" | "number";
27
+ align?: "left" | "right" | "center";
20
28
  /**
21
29
  * Assigned to the cell's `th` element instead of `td` if true.
22
30
  *
@@ -43,9 +51,16 @@ type ColumnDefinition<T> = {
43
51
  * Use `sort` and `onSortChange` on the root component to control sort state.
44
52
  */
45
53
  sortable?: boolean;
54
+ /**
55
+ * Additional metadata that can be used for filtering or other purposes. Not used by the table itself.
56
+ */
57
+ details?: DetailsT;
46
58
  };
47
59
 
48
- type ColumnDefinitions<T> = ColumnDefinition<T>[];
60
+ type ColumnDefinitions<T, DetailsT = Record<string, any>> = ColumnDefinition<
61
+ T,
62
+ DetailsT
63
+ >[];
49
64
 
50
65
  /**
51
66
  * A single sort entry representing a column's current sort state.
@@ -14,10 +14,14 @@ type DataTableContextProps<T> = {
14
14
  rowId: string | number,
15
15
  event: React.MouseEvent<HTMLTableRowElement>,
16
16
  ) => void;
17
- disableRowSelectionOnClick: boolean;
18
17
  isLoading?: boolean;
19
18
  showLoadingOverlay: boolean;
20
19
  columns: UseColumnOptionsResult<T>["columns"];
20
+ /**
21
+ * Used to set exact colspan for detailsPanel, loadingState and emptyState.
22
+ * This is necessary to ensure that these components span the entire width of the table.
23
+ */
24
+ fullWidthColSpan: number;
21
25
  };
22
26
 
23
27
  const { Provider: DataTableContextProvider, useContext: useDataTableContext } =
@@ -0,0 +1,297 @@
1
+ import React, { forwardRef } from "react";
2
+ import { useId } from "../../../utils-external";
3
+ import { cl } from "../../../utils/helpers";
4
+ import { useMergeRefs } from "../../../utils/hooks";
5
+ import {
6
+ DataTableCaption,
7
+ type DataTableCaptionProps,
8
+ } from "../caption/DataTableCaption";
9
+ import {
10
+ DataTableEmptyState,
11
+ type DataTableEmptyStateProps,
12
+ } from "../empty-state/DataTableEmptyState";
13
+ import { DataTableDetailsPanelProvider } from "../hooks/useTableDetailsPanel";
14
+ import { useTableKeyboardNav } from "../hooks/useTableKeyboardNav";
15
+ import {
16
+ type SelectionProps,
17
+ noSelectionState,
18
+ } from "../hooks/useTableSelection";
19
+ import {
20
+ DataTableLoadingState,
21
+ type DataTableLoadingStateProps,
22
+ } from "../loading-state/DataTableLoadingState";
23
+ import {
24
+ DataTableTbody,
25
+ type DataTableTbodyProps,
26
+ } from "../tbody/DataTableTbody";
27
+ import { DataTableTd, type DataTableTdProps } from "../td/DataTableTd";
28
+ import {
29
+ DataTableTfoot,
30
+ type DataTableTfootProps,
31
+ } from "../tfoot/DataTableTfoot";
32
+ import { DataTableTh, type DataTableThProps } from "../th/DataTableTh";
33
+ import {
34
+ DataTableThead,
35
+ type DataTableTheadProps,
36
+ } from "../thead/DataTableThead";
37
+ import { DataTableTr, type DataTableTrProps } from "../tr/DataTableTr";
38
+ import { DataTableContextProvider } from "./DataTableRoot.context";
39
+
40
+ interface DataTableProps
41
+ extends React.HTMLAttributes<HTMLTableElement>, SelectionProps {
42
+ children: React.ReactNode;
43
+ /**
44
+ * Controls vertical cell padding.
45
+ * @default "normal"
46
+ */
47
+ rowDensity?: "condensed" | "normal" | "spacious";
48
+ /**
49
+ * Zebra striped table
50
+ * @default false
51
+ */
52
+ zebraStripes?: boolean;
53
+ /**
54
+ * Truncate content in cells and show ellipsis for overflowed text.
55
+ *
56
+ * **NB:** When using `layout="auto"`, you have to manually set a `maxWidth` on columns that should be truncated.
57
+ * @default true
58
+ */
59
+ truncateContent?: boolean; // TODO: Consider making this default false when layout=auto, and maybe disallow it but add a wrap prop on the td-comp.
60
+ /**
61
+ * Enables keyboard navigation for table rows and cells.
62
+ * @default false
63
+ */
64
+ withKeyboardNav?: boolean;
65
+ /**
66
+ * Custom callback to determine if navigation should be blocked.
67
+ * Called before default blocking logic.
68
+ * Requires `withKeyboardNav` to be `true`.
69
+ */
70
+ shouldBlockNavigation?: (event: KeyboardEvent) => boolean;
71
+ /**
72
+ * Controls table layout.
73
+ *
74
+ * ### fixed
75
+ * Gives you full control of column widths. This is required for resizable columns.
76
+ *
77
+ * ### auto
78
+ * Makes the columns resize automatically based on the content.
79
+ * The table will take up at least 100% of available width.
80
+ *
81
+ * **NB:** When using this with `truncateContent`, you have to manually
82
+ * set a `contentMaxWidth` on cells that should be truncated.
83
+ * @default "fixed"
84
+ */
85
+ layout?: "fixed" | "auto";
86
+ }
87
+
88
+ interface DataTableRootComponent extends React.ForwardRefExoticComponent<
89
+ DataTableProps & React.RefAttributes<HTMLTableElement>
90
+ > {
91
+ /**
92
+ * @see 🏷️ {@link DataTableCaptionProps}
93
+ * @example
94
+ * ```jsx
95
+ * <DataTable>
96
+ * <DataTable.Caption>
97
+ * Lorem ipsum
98
+ * </DataTable.Caption
99
+ * </DataTable>
100
+ * ```
101
+ */
102
+ Caption: typeof DataTableCaption;
103
+ /**
104
+ * @see 🏷️ {@link DataTableTheadProps}
105
+ * @example
106
+ * ```jsx
107
+ * <DataTable>
108
+ * <DataTable.Thead>
109
+ * ... TODO
110
+ * </DataTable.Thead>
111
+ * </DataTable>
112
+ * ```
113
+ */
114
+ Thead: typeof DataTableThead;
115
+ /**
116
+ * @see 🏷️ {@link DataTableTbodyProps}
117
+ * @example
118
+ * ```jsx
119
+ * <DataTable>
120
+ * <DataTable.Tbody>
121
+ * ... TODO
122
+ * </DataTable.Tbody>
123
+ * </DataTable>
124
+ * ```
125
+ */
126
+ Tbody: typeof DataTableTbody;
127
+ /**
128
+ * @see 🏷️ {@link DataTableTrProps}
129
+ * @example
130
+ * ```jsx
131
+ * <DataTable>
132
+ * <DataTable.Tr>
133
+ * ... TODO
134
+ * </DataTable.Tr
135
+ * </DataTable>
136
+ * ```
137
+ */
138
+ Tr: typeof DataTableTr;
139
+ /**
140
+ * @see 🏷️ {@link DataTableThProps}
141
+ * @example
142
+ * ```jsx
143
+ * ```
144
+ */
145
+ Th: typeof DataTableTh;
146
+ /**
147
+ * @see 🏷️ {@link DataTableTdProps}
148
+ * @example
149
+ * ```jsx
150
+ * <DataTable>
151
+ * <DataTable.Tbody>
152
+ * <DataTable.Td>
153
+ * Lorem ipsum
154
+ * </DataTable.Td>
155
+ * <DataTable.Td>
156
+ * Dolor sit amet
157
+ * </DataTable.Td>
158
+ * </DataTable.Tbody>
159
+ * </DataTable>
160
+ * ```
161
+ */
162
+ Td: typeof DataTableTd;
163
+ /**
164
+ * @see 🏷️ {@link DataTableTfootProps}
165
+ * @example
166
+ * ```jsx
167
+ * <DataTable>
168
+ * <DataTable.Tfoot>
169
+ * ...
170
+ * </DataTable.Tfoot>
171
+ * </DataTable>
172
+ * ```
173
+ */
174
+ Tfoot: typeof DataTableTfoot;
175
+ /**
176
+ * @see 🏷️ {@link DataTableEmptyStateProps}
177
+ * @example
178
+ * ```jsx
179
+ * <DataTable>
180
+ * <DataTable.TBody>
181
+ * <DataTable.EmptyState />
182
+ * </DataTable.TBody>
183
+ * </DataTable>
184
+ * ```
185
+ */
186
+ EmptyState: typeof DataTableEmptyState;
187
+ /**
188
+ * @see 🏷️ {@link DataTableEmptyStateProps}
189
+ * @example
190
+ * ```jsx
191
+ * <DataTable>
192
+ * <DataTable.TBody>
193
+ * <DataTable.LoadingState />
194
+ * </DataTable.TBody>
195
+ * </DataTable>
196
+ * ```
197
+ */
198
+ LoadingState: typeof DataTableLoadingState;
199
+ }
200
+
201
+ /**
202
+ * TODO Component description etc.
203
+ *
204
+ * **NB:** To get sticky headers, you have to set a height restriction on the table container. You can use VStack for this:
205
+ * TODO example
206
+ */
207
+ const DataTable = forwardRef<HTMLTableElement, DataTableProps>(
208
+ (
209
+ {
210
+ className,
211
+ rowDensity = "normal",
212
+ withKeyboardNav = false,
213
+ zebraStripes = false,
214
+ truncateContent = true,
215
+ shouldBlockNavigation,
216
+ layout = "fixed",
217
+ ...rest
218
+ },
219
+ forwardedRef,
220
+ ) => {
221
+ const { tabIndex, setTableRef } = useTableKeyboardNav({
222
+ enabled: withKeyboardNav,
223
+ shouldBlockNavigation,
224
+ });
225
+
226
+ const mergedRef = useMergeRefs(forwardedRef, setTableRef);
227
+
228
+ return (
229
+ <DataTableContextProvider
230
+ layout={layout}
231
+ withKeyboardNav={withKeyboardNav}
232
+ selectionState={noSelectionState}
233
+ stickySelection={false}
234
+ stickyHeader={true}
235
+ tableId={useId()}
236
+ showLoadingSkeletons={false}
237
+ onRowClick={undefined}
238
+ showLoadingOverlay={false}
239
+ columns={[]}
240
+ fullWidthColSpan={9999}
241
+ >
242
+ <DataTableDetailsPanelProvider>
243
+ <div className="aksel-data-table__border-wrapper">
244
+ <div className="aksel-data-table__scroll-wrapper">
245
+ <table
246
+ {...rest}
247
+ ref={mergedRef}
248
+ className={cl("aksel-data-table", className)}
249
+ data-zebra-stripes={zebraStripes}
250
+ data-truncate-content={truncateContent}
251
+ data-density={rowDensity}
252
+ data-layout={layout}
253
+ tabIndex={tabIndex}
254
+ />
255
+ </div>
256
+ </div>
257
+ </DataTableDetailsPanelProvider>
258
+ </DataTableContextProvider>
259
+ );
260
+ },
261
+ ) as DataTableRootComponent;
262
+
263
+ DataTable.Caption = DataTableCaption;
264
+ DataTable.Thead = DataTableThead;
265
+ DataTable.Tbody = DataTableTbody;
266
+ DataTable.Th = DataTableTh;
267
+ DataTable.Tr = DataTableTr;
268
+ DataTable.Td = DataTableTd;
269
+ DataTable.Tfoot = DataTableTfoot;
270
+ DataTable.EmptyState = DataTableEmptyState;
271
+ DataTable.LoadingState = DataTableLoadingState;
272
+
273
+ export {
274
+ DataTable,
275
+ DataTableCaption,
276
+ DataTableEmptyState,
277
+ DataTableLoadingState,
278
+ DataTableTbody,
279
+ DataTableTd,
280
+ DataTableTfoot,
281
+ DataTableTh,
282
+ DataTableThead,
283
+ DataTableTr,
284
+ };
285
+ export default DataTable;
286
+ export type {
287
+ DataTableCaptionProps,
288
+ DataTableEmptyStateProps,
289
+ DataTableLoadingStateProps,
290
+ DataTableProps,
291
+ DataTableTbodyProps,
292
+ DataTableTdProps,
293
+ DataTableTfootProps,
294
+ DataTableTheadProps,
295
+ DataTableThProps,
296
+ DataTableTrProps,
297
+ };