@navikt/ds-react 8.10.5 → 8.11.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 (266) hide show
  1. package/cjs/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js +0 -1
  2. package/cjs/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js.map +1 -1
  3. package/cjs/data/drag-and-drop/root/DragAndDropRoot.d.ts +6 -6
  4. package/cjs/data/drag-and-drop/root/DragAndDropRoot.js +6 -29
  5. package/cjs/data/drag-and-drop/root/DragAndDropRoot.js.map +1 -1
  6. package/cjs/data/stories/Data.test-data.d.ts +3 -6
  7. package/cjs/data/stories/Data.test-data.js +46 -59
  8. package/cjs/data/stories/Data.test-data.js.map +1 -1
  9. package/cjs/data/table/base-cell/DataTableBaseCell.d.ts +18 -18
  10. package/cjs/data/table/base-cell/DataTableBaseCell.js +4 -8
  11. package/cjs/data/table/base-cell/DataTableBaseCell.js.map +1 -1
  12. package/cjs/data/table/column-header/DataTableColumnHeader.d.ts +19 -13
  13. package/cjs/data/table/column-header/DataTableColumnHeader.js +26 -28
  14. package/cjs/data/table/column-header/DataTableColumnHeader.js.map +1 -1
  15. package/cjs/data/table/column-header/useTableColumnResize.d.ts +19 -29
  16. package/cjs/data/table/column-header/useTableColumnResize.js +30 -28
  17. package/cjs/data/table/column-header/useTableColumnResize.js.map +1 -1
  18. package/cjs/data/table/details-panel-row/DataTableDetailsPanelRow.d.ts +1 -1
  19. package/cjs/data/table/details-panel-row/DataTableDetailsPanelRow.js +2 -2
  20. package/cjs/data/table/details-panel-row/DataTableDetailsPanelRow.js.map +1 -1
  21. package/cjs/data/table/helpers/collectTableRowEntries.d.ts +2 -2
  22. package/cjs/data/table/helpers/selection/getMultipleSelectProps.d.ts +14 -11
  23. package/cjs/data/table/helpers/selection/getMultipleSelectProps.js +45 -51
  24. package/cjs/data/table/helpers/selection/getMultipleSelectProps.js.map +1 -1
  25. package/cjs/data/table/helpers/selection/getSingleSelectProps.d.ts +9 -8
  26. package/cjs/data/table/helpers/selection/getSingleSelectProps.js +23 -10
  27. package/cjs/data/table/helpers/selection/getSingleSelectProps.js.map +1 -1
  28. package/cjs/data/table/helpers/selection/selection.types.d.ts +24 -32
  29. package/cjs/data/table/helpers/selection/selection.utils.d.ts +21 -0
  30. package/cjs/data/table/helpers/selection/selection.utils.js +46 -0
  31. package/cjs/data/table/helpers/selection/selection.utils.js.map +1 -0
  32. package/cjs/data/table/hooks/useColumnOptions.d.ts +17 -6
  33. package/cjs/data/table/hooks/useColumnOptions.js +26 -8
  34. package/cjs/data/table/hooks/useColumnOptions.js.map +1 -1
  35. package/cjs/data/table/hooks/useTableDetailsPanel.d.ts +10 -14
  36. package/cjs/data/table/hooks/useTableDetailsPanel.js +6 -5
  37. package/cjs/data/table/hooks/useTableDetailsPanel.js.map +1 -1
  38. package/cjs/data/table/hooks/useTableItems.d.ts +32 -19
  39. package/cjs/data/table/hooks/useTableItems.js +13 -15
  40. package/cjs/data/table/hooks/useTableItems.js.map +1 -1
  41. package/cjs/data/table/hooks/useTableKeyboardNav.d.ts +1 -6
  42. package/cjs/data/table/hooks/useTableKeyboardNav.js +1 -4
  43. package/cjs/data/table/hooks/useTableKeyboardNav.js.map +1 -1
  44. package/cjs/data/table/hooks/useTableSelection.d.ts +7 -6
  45. package/cjs/data/table/hooks/useTableSelection.js +52 -35
  46. package/cjs/data/table/hooks/useTableSelection.js.map +1 -1
  47. package/cjs/data/table/hooks/useTableSort.d.ts +15 -9
  48. package/cjs/data/table/hooks/useTableSort.js +9 -11
  49. package/cjs/data/table/hooks/useTableSort.js.map +1 -1
  50. package/cjs/data/table/index.d.ts +1 -1
  51. package/cjs/data/table/index.js +3 -23
  52. package/cjs/data/table/index.js.map +1 -1
  53. package/cjs/data/table/root/DataGridTable.types.d.ts +65 -0
  54. package/cjs/data/table/root/DataGridTable.types.js +3 -0
  55. package/cjs/data/table/root/DataGridTable.types.js.map +1 -0
  56. package/cjs/data/table/root/DataGridTableRoot.d.ts +104 -0
  57. package/cjs/data/table/root/DataGridTableRoot.js +237 -0
  58. package/cjs/data/table/root/DataGridTableRoot.js.map +1 -0
  59. package/cjs/data/table/root/DataTableRoot.context.d.ts +17 -7
  60. package/cjs/data/table/root/DataTableRoot.context.js.map +1 -1
  61. package/cjs/data/table/sub-row-toggle/DataTableSubRowToggle.js +4 -4
  62. package/cjs/data/table/sub-row-toggle/DataTableSubRowToggle.js.map +1 -1
  63. package/cjs/data/table/tbody/DataTableTbody.js +4 -2
  64. package/cjs/data/table/tbody/DataTableTbody.js.map +1 -1
  65. package/cjs/data/table/tr/DataTableTr.d.ts +7 -5
  66. package/cjs/data/table/tr/DataTableTr.js +69 -32
  67. package/cjs/data/table/tr/DataTableTr.js.map +1 -1
  68. package/cjs/data/token-filter/TokenFilter.d.ts +0 -6
  69. package/cjs/data/token-filter/TokenFilter.js +1 -1
  70. package/cjs/data-grid/index.d.ts +2 -0
  71. package/cjs/data-grid/index.js +9 -0
  72. package/cjs/data-grid/index.js.map +1 -0
  73. package/cjs/data-grid/root/DataGrid.types.d.ts +35 -0
  74. package/cjs/{data/table/root/DataTable.types.js → data-grid/root/DataGrid.types.js} +1 -1
  75. package/cjs/data-grid/root/DataGrid.types.js.map +1 -0
  76. package/cjs/data-grid/root/DataGridRoot.context.d.ts +16 -0
  77. package/cjs/data-grid/root/DataGridRoot.context.js +11 -0
  78. package/cjs/data-grid/root/DataGridRoot.context.js.map +1 -0
  79. package/cjs/data-grid/root/DataGridRoot.d.ts +89 -0
  80. package/cjs/data-grid/root/DataGridRoot.js +93 -0
  81. package/cjs/data-grid/root/DataGridRoot.js.map +1 -0
  82. package/cjs/preview.d.ts +1 -0
  83. package/cjs/preview.js +7 -0
  84. package/cjs/preview.js.map +1 -0
  85. package/cjs/table/ColumnHeader.js +2 -1
  86. package/cjs/table/ColumnHeader.js.map +1 -1
  87. package/esm/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js +0 -1
  88. package/esm/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js.map +1 -1
  89. package/esm/data/drag-and-drop/root/DragAndDropRoot.d.ts +6 -6
  90. package/esm/data/drag-and-drop/root/DragAndDropRoot.js +6 -29
  91. package/esm/data/drag-and-drop/root/DragAndDropRoot.js.map +1 -1
  92. package/esm/data/stories/Data.test-data.d.ts +3 -6
  93. package/esm/data/stories/Data.test-data.js +46 -59
  94. package/esm/data/stories/Data.test-data.js.map +1 -1
  95. package/esm/data/table/base-cell/DataTableBaseCell.d.ts +18 -18
  96. package/esm/data/table/base-cell/DataTableBaseCell.js +4 -8
  97. package/esm/data/table/base-cell/DataTableBaseCell.js.map +1 -1
  98. package/esm/data/table/column-header/DataTableColumnHeader.d.ts +19 -13
  99. package/esm/data/table/column-header/DataTableColumnHeader.js +27 -29
  100. package/esm/data/table/column-header/DataTableColumnHeader.js.map +1 -1
  101. package/esm/data/table/column-header/useTableColumnResize.d.ts +19 -29
  102. package/esm/data/table/column-header/useTableColumnResize.js +30 -28
  103. package/esm/data/table/column-header/useTableColumnResize.js.map +1 -1
  104. package/esm/data/table/details-panel-row/DataTableDetailsPanelRow.d.ts +1 -1
  105. package/esm/data/table/details-panel-row/DataTableDetailsPanelRow.js +2 -2
  106. package/esm/data/table/details-panel-row/DataTableDetailsPanelRow.js.map +1 -1
  107. package/esm/data/table/helpers/collectTableRowEntries.d.ts +2 -2
  108. package/esm/data/table/helpers/selection/getMultipleSelectProps.d.ts +14 -11
  109. package/esm/data/table/helpers/selection/getMultipleSelectProps.js +45 -51
  110. package/esm/data/table/helpers/selection/getMultipleSelectProps.js.map +1 -1
  111. package/esm/data/table/helpers/selection/getSingleSelectProps.d.ts +9 -8
  112. package/esm/data/table/helpers/selection/getSingleSelectProps.js +23 -10
  113. package/esm/data/table/helpers/selection/getSingleSelectProps.js.map +1 -1
  114. package/esm/data/table/helpers/selection/selection.types.d.ts +24 -32
  115. package/esm/data/table/helpers/selection/selection.utils.d.ts +21 -0
  116. package/esm/data/table/helpers/selection/selection.utils.js +43 -0
  117. package/esm/data/table/helpers/selection/selection.utils.js.map +1 -0
  118. package/esm/data/table/hooks/useColumnOptions.d.ts +17 -6
  119. package/esm/data/table/hooks/useColumnOptions.js +26 -8
  120. package/esm/data/table/hooks/useColumnOptions.js.map +1 -1
  121. package/esm/data/table/hooks/useTableDetailsPanel.d.ts +10 -14
  122. package/esm/data/table/hooks/useTableDetailsPanel.js +6 -5
  123. package/esm/data/table/hooks/useTableDetailsPanel.js.map +1 -1
  124. package/esm/data/table/hooks/useTableItems.d.ts +32 -19
  125. package/esm/data/table/hooks/useTableItems.js +14 -13
  126. package/esm/data/table/hooks/useTableItems.js.map +1 -1
  127. package/esm/data/table/hooks/useTableKeyboardNav.d.ts +1 -6
  128. package/esm/data/table/hooks/useTableKeyboardNav.js +1 -4
  129. package/esm/data/table/hooks/useTableKeyboardNav.js.map +1 -1
  130. package/esm/data/table/hooks/useTableSelection.d.ts +7 -6
  131. package/esm/data/table/hooks/useTableSelection.js +52 -35
  132. package/esm/data/table/hooks/useTableSelection.js.map +1 -1
  133. package/esm/data/table/hooks/useTableSort.d.ts +15 -9
  134. package/esm/data/table/hooks/useTableSort.js +10 -12
  135. package/esm/data/table/hooks/useTableSort.js.map +1 -1
  136. package/esm/data/table/index.d.ts +1 -1
  137. package/esm/data/table/index.js +1 -21
  138. package/esm/data/table/index.js.map +1 -1
  139. package/esm/data/table/root/DataGridTable.types.d.ts +65 -0
  140. package/esm/data/table/root/DataGridTable.types.js +2 -0
  141. package/esm/data/table/root/DataGridTable.types.js.map +1 -0
  142. package/esm/data/table/root/DataGridTableRoot.d.ts +104 -0
  143. package/esm/data/table/root/DataGridTableRoot.js +202 -0
  144. package/esm/data/table/root/DataGridTableRoot.js.map +1 -0
  145. package/esm/data/table/root/DataTableRoot.context.d.ts +17 -7
  146. package/esm/data/table/root/DataTableRoot.context.js.map +1 -1
  147. package/esm/data/table/sub-row-toggle/DataTableSubRowToggle.js +4 -4
  148. package/esm/data/table/sub-row-toggle/DataTableSubRowToggle.js.map +1 -1
  149. package/esm/data/table/tbody/DataTableTbody.js +4 -2
  150. package/esm/data/table/tbody/DataTableTbody.js.map +1 -1
  151. package/esm/data/table/tr/DataTableTr.d.ts +7 -5
  152. package/esm/data/table/tr/DataTableTr.js +68 -32
  153. package/esm/data/table/tr/DataTableTr.js.map +1 -1
  154. package/esm/data/token-filter/TokenFilter.d.ts +0 -6
  155. package/esm/data/token-filter/TokenFilter.js +1 -1
  156. package/esm/data-grid/index.d.ts +2 -0
  157. package/esm/data-grid/index.js +4 -0
  158. package/esm/data-grid/index.js.map +1 -0
  159. package/esm/data-grid/root/DataGrid.types.d.ts +35 -0
  160. package/esm/data-grid/root/DataGrid.types.js +2 -0
  161. package/esm/data-grid/root/DataGrid.types.js.map +1 -0
  162. package/esm/data-grid/root/DataGridRoot.context.d.ts +16 -0
  163. package/esm/data-grid/root/DataGridRoot.context.js +7 -0
  164. package/esm/data-grid/root/DataGridRoot.context.js.map +1 -0
  165. package/esm/data-grid/root/DataGridRoot.d.ts +89 -0
  166. package/esm/data-grid/root/DataGridRoot.js +57 -0
  167. package/esm/data-grid/root/DataGridRoot.js.map +1 -0
  168. package/esm/preview.d.ts +1 -0
  169. package/esm/preview.js +3 -0
  170. package/esm/preview.js.map +1 -0
  171. package/esm/table/ColumnHeader.js +2 -1
  172. package/esm/table/ColumnHeader.js.map +1 -1
  173. package/package.json +23 -3
  174. package/src/data/drag-and-drop/drag-handler/DragAndDropDragHandler.tsx +0 -1
  175. package/src/data/drag-and-drop/root/DragAndDropRoot.tsx +18 -52
  176. package/src/data/stories/Data.test-data.tsx +76 -65
  177. package/src/data/table/base-cell/DataTableBaseCell.tsx +36 -26
  178. package/src/data/table/column-header/DataTableColumnHeader.tsx +62 -62
  179. package/src/data/table/column-header/useTableColumnResize.ts +63 -79
  180. package/src/data/table/details-panel-row/DataTableDetailsPanelRow.tsx +3 -3
  181. package/src/data/table/helpers/collectTableRowEntries.ts +1 -2
  182. package/src/data/table/helpers/selection/getMultipleSelectProps.ts +69 -83
  183. package/src/data/table/helpers/selection/getSingleSelectProps.ts +35 -17
  184. package/src/data/table/helpers/selection/selection.types.ts +23 -33
  185. package/src/data/table/helpers/selection/selection.utils.test.ts +161 -0
  186. package/src/data/table/helpers/selection/selection.utils.ts +73 -0
  187. package/src/data/table/hooks/__tests__/useTableItems.test.ts +2 -1
  188. package/src/data/table/hooks/useColumnOptions.ts +49 -15
  189. package/src/data/table/hooks/useTableDetailsPanel.tsx +21 -28
  190. package/src/data/table/hooks/useTableItems.ts +60 -38
  191. package/src/data/table/hooks/useTableKeyboardNav.ts +1 -13
  192. package/src/data/table/hooks/useTableSelection.ts +80 -68
  193. package/src/data/table/hooks/useTableSort.ts +36 -23
  194. package/src/data/table/index.tsx +4 -21
  195. package/src/data/table/root/DataGridTable.types.ts +82 -0
  196. package/src/data/table/root/DataGridTableRoot.tsx +566 -0
  197. package/src/data/table/root/DataTableRoot.context.ts +24 -10
  198. package/src/data/table/sub-row-toggle/DataTableSubRowToggle.tsx +6 -5
  199. package/src/data/table/tbody/DataTableTbody.tsx +6 -2
  200. package/src/data/table/tr/DataTableTr.tsx +145 -47
  201. package/src/data/token-filter/TokenFilter.tsx +1 -1
  202. package/src/data-grid/index.ts +3 -0
  203. package/src/data-grid/root/DataGrid.types.ts +36 -0
  204. package/src/data-grid/root/DataGridRoot.context.ts +21 -0
  205. package/src/data-grid/root/DataGridRoot.tsx +152 -0
  206. package/src/preview.ts +2 -0
  207. package/src/table/ColumnHeader.tsx +3 -1
  208. package/cjs/data/drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.d.ts +0 -22
  209. package/cjs/data/drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.js +0 -35
  210. package/cjs/data/drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.js.map +0 -1
  211. package/cjs/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.d.ts +0 -27
  212. package/cjs/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.js +0 -86
  213. package/cjs/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.js.map +0 -1
  214. package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.d.ts +0 -5
  215. package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.js +0 -6
  216. package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.js.map +0 -1
  217. package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.d.ts +0 -24
  218. package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.js +0 -108
  219. package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.js.map +0 -1
  220. package/cjs/data/table/helpers/selection/SelectionSubtreeHelper.d.ts +0 -46
  221. package/cjs/data/table/helpers/selection/SelectionSubtreeHelper.js +0 -112
  222. package/cjs/data/table/helpers/selection/SelectionSubtreeHelper.js.map +0 -1
  223. package/cjs/data/table/root/DataTable.types.d.ts +0 -63
  224. package/cjs/data/table/root/DataTable.types.js.map +0 -1
  225. package/cjs/data/table/root/DataTableRoot.d.ts +0 -141
  226. package/cjs/data/table/root/DataTableRoot.js +0 -229
  227. package/cjs/data/table/root/DataTableRoot.js.map +0 -1
  228. package/cjs/data/table/root/DataTableRoot.legacy.d.ts +0 -177
  229. package/cjs/data/table/root/DataTableRoot.legacy.js +0 -104
  230. package/cjs/data/table/root/DataTableRoot.legacy.js.map +0 -1
  231. package/esm/data/drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.d.ts +0 -22
  232. package/esm/data/drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.js +0 -29
  233. package/esm/data/drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.js.map +0 -1
  234. package/esm/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.d.ts +0 -27
  235. package/esm/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.js +0 -50
  236. package/esm/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.js.map +0 -1
  237. package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.d.ts +0 -5
  238. package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.js +0 -3
  239. package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.js.map +0 -1
  240. package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.d.ts +0 -24
  241. package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.js +0 -68
  242. package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.js.map +0 -1
  243. package/esm/data/table/helpers/selection/SelectionSubtreeHelper.d.ts +0 -46
  244. package/esm/data/table/helpers/selection/SelectionSubtreeHelper.js +0 -109
  245. package/esm/data/table/helpers/selection/SelectionSubtreeHelper.js.map +0 -1
  246. package/esm/data/table/root/DataTable.types.d.ts +0 -63
  247. package/esm/data/table/root/DataTable.types.js +0 -2
  248. package/esm/data/table/root/DataTable.types.js.map +0 -1
  249. package/esm/data/table/root/DataTableRoot.d.ts +0 -141
  250. package/esm/data/table/root/DataTableRoot.js +0 -193
  251. package/esm/data/table/root/DataTableRoot.js.map +0 -1
  252. package/esm/data/table/root/DataTableRoot.legacy.d.ts +0 -177
  253. package/esm/data/table/root/DataTableRoot.legacy.js +0 -59
  254. package/esm/data/table/root/DataTableRoot.legacy.js.map +0 -1
  255. package/src/data/drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.tsx +0 -104
  256. package/src/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.tsx +0 -74
  257. package/src/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.tsx +0 -11
  258. package/src/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.tsx +0 -94
  259. package/src/data/table/Readme.md +0 -11
  260. package/src/data/table/helpers/selection/SelectionSubtreeHelper.test.ts +0 -66
  261. package/src/data/table/helpers/selection/SelectionSubtreeHelper.ts +0 -162
  262. package/src/data/table/hooks/__tests__/useTableSelection.test.ts +0 -488
  263. package/src/data/table/root/DataTable.types.ts +0 -87
  264. package/src/data/table/root/DataTableRoot.legacy.tsx +0 -297
  265. package/src/data/table/root/DataTableRoot.tsx +0 -562
  266. package/src/data/table/root/agent-feature-gap.md +0 -96
@@ -0,0 +1,566 @@
1
+ import React, {
2
+ forwardRef,
3
+ memo,
4
+ useCallback,
5
+ useEffect,
6
+ useRef,
7
+ useState,
8
+ } from "react";
9
+ import { useDataGridContext } from "../../../data-grid/root/DataGridRoot.context";
10
+ import { Skeleton } from "../../../skeleton";
11
+ import { useId } from "../../../utils-external";
12
+ import { Slot } from "../../../utils/components/slot/Slot";
13
+ import { cl } from "../../../utils/helpers";
14
+ import { useMergeRefs } from "../../../utils/hooks";
15
+ import { DataTableBaseCell } from "../base-cell/DataTableBaseCell";
16
+ import { DataTableColumnHeader } from "../column-header/DataTableColumnHeader";
17
+ import { DataTableDetailsPanelRow } from "../details-panel-row/DataTableDetailsPanelRow";
18
+ import { DataTableEmptyState } from "../empty-state/DataTableEmptyState";
19
+ import type { ItemDetail } from "../helpers/collectTableRowEntries";
20
+ import { useColumnOptions } from "../hooks/useColumnOptions";
21
+ import {
22
+ DataTableDetailsPanelProvider,
23
+ type DetailsPanelProps,
24
+ } from "../hooks/useTableDetailsPanel";
25
+ import { type SubRowsProps, useTableItems } from "../hooks/useTableItems";
26
+ import { useTableKeyboardNav } from "../hooks/useTableKeyboardNav";
27
+ import { useTableSelection } from "../hooks/useTableSelection";
28
+ import { type TableSortOptions, useTableSort } from "../hooks/useTableSort";
29
+ import { DataTableLoadingState } from "../loading-state/DataTableLoadingState";
30
+ import { DataTableSubRowToggle } from "../sub-row-toggle/DataTableSubRowToggle";
31
+ import { DataTableTbody } from "../tbody/DataTableTbody";
32
+ import { DataTableThead } from "../thead/DataTableThead";
33
+ import { DataTableTr } from "../tr/DataTableTr";
34
+ import type { DataTableLoadingConfig } from "./DataGridTable.types";
35
+ import {
36
+ DataTableContextProvider,
37
+ useDataTableContext,
38
+ } from "./DataTableRoot.context";
39
+
40
+ /*
41
+ * TODO: For consideration:
42
+ * - Use namespacing for types. There will be a lot of standalone types connected to this component,
43
+ * it could make sense to access them under DataTable.X instead of separate imports.
44
+ * - Consider having a "Wrapper" component that only handles context and logic like,
45
+ * "DataTableRoot" or "DataGrid" or something, and then have the main "DataTable" component only handle rendering of table itself.
46
+ * This would make props more focused and discoverable since its not mixed with htmltable-props.
47
+ */
48
+
49
+ /*
50
+ * TODO:
51
+ * - Test `onColumnDefinitionChange` callback that is called when resize, sort, order etc changes
52
+ */
53
+ interface DataGridTableProps<T> extends React.HTMLAttributes<HTMLTableElement> {
54
+ children?: never;
55
+ /**
56
+ * Controls table layout.
57
+ *
58
+ * ### fixed
59
+ * Gives you full control of column widths. This is required for resizable columns.
60
+ *
61
+ * ### auto
62
+ * Makes the columns resize automatically based on the content.
63
+ * The table will take up at least 100% of available width.
64
+ *
65
+ * **NB:** When using this with `truncateContent`, you have to manually
66
+ * set a `contentMaxWidth` on cells that should be truncated.
67
+ * @default "fixed"
68
+ */
69
+ layout?: "fixed" | "auto";
70
+ /**
71
+ * Whether the header should be sticky.
72
+ * For this to work, you have to put the component in a flex container with a height restriction.
73
+ *
74
+ * @example
75
+ * <VStack height="100vh">
76
+ * <div>Content before DataGrid</div>
77
+ * <DataGrid>
78
+ * <DataGrid.Table />
79
+ * </DataGrid>
80
+ * <div>Content after DataGrid</div>
81
+ * </VStack>
82
+ *
83
+ * @example
84
+ * <div style={{ display: "flex", maxHeight: "500px" }}>
85
+ * <DataGrid>
86
+ * <DataGrid.Table />
87
+ * </DataGrid>
88
+ * </div>
89
+ *
90
+ * @default true
91
+ */
92
+ stickyHeader?: boolean;
93
+ /**
94
+ * Callback invoked when a row in the table body is clicked.
95
+ *
96
+ * Call `event.preventDefault()` inside the callback to prevent the default row click behavior, such as selection.
97
+ */
98
+ onRowAction?: ({
99
+ row,
100
+ id,
101
+ event,
102
+ }: {
103
+ row: T;
104
+ id: string;
105
+ event: React.MouseEvent<HTMLTableRowElement>;
106
+ }) => void;
107
+ /**
108
+ * Content to render when `data` is empty.
109
+ * Rendered inside a row spanning all columns.
110
+ */
111
+ emptyContent?: React.ReactNode;
112
+ /**
113
+ * Configures how the table behaves during loading.
114
+ *
115
+ * Use `variant` to select the loading strategy:
116
+ * - `"content"` — renders custom content inside a full-width row.
117
+ * - `"skeleton"` — renders skeleton placeholder rows.
118
+ * - `"overlay"` — keeps existing data visible with a loading overlay.
119
+ *
120
+ * @default { variant: "skeleton", rows: 5 }
121
+ */
122
+ loadingContent?: DataTableLoadingConfig;
123
+ /**
124
+ * Object with props related to nested rows (sub-rows).
125
+ */
126
+ subRows?: SubRowsProps<T>; // TODO: Table might need to be implemented with role="treegrid" for a11y when having nested rows.
127
+ /**
128
+ * Object with props related to details panel.
129
+ * This is a panel that can be expanded below each row to show arbitrary content.
130
+ */
131
+ detailsPanel?: DetailsPanelProps<T>;
132
+ /**
133
+ * Object with props related to sorting.
134
+ */
135
+ sorting?: TableSortOptions;
136
+ /**
137
+ * Determines if selection is triggered by clicking the row or the selection control (checkbox/radio).
138
+ * @default "row"
139
+ */
140
+ selectionTrigger?: "row" | "control";
141
+ }
142
+
143
+ const DataGridTableInternal = forwardRef<
144
+ HTMLTableElement,
145
+ DataGridTableProps<any>
146
+ >(
147
+ (
148
+ {
149
+ className,
150
+ id,
151
+ layout = "fixed",
152
+ stickyHeader = true,
153
+ onRowAction,
154
+ emptyContent,
155
+ loadingContent = {
156
+ variant: "skeleton",
157
+ rows: 5,
158
+ label: "Laster innhold",
159
+ }, // TODO translate label
160
+ detailsPanel,
161
+ subRows,
162
+ sorting,
163
+ selectionTrigger = "row",
164
+ ...rest
165
+ }: DataGridTableProps<unknown>,
166
+ forwardedRef,
167
+ ) => {
168
+ const {
169
+ columnDefinitions,
170
+ data,
171
+ getRowId,
172
+ selection,
173
+ isLoading,
174
+ tableSettings,
175
+ } = useDataGridContext();
176
+
177
+ const sortingState = useTableSort(sorting);
178
+
179
+ const tableItems = useTableItems({
180
+ items: data,
181
+ getRowId,
182
+ subRows,
183
+ });
184
+
185
+ const tableSelectionState = useTableSelection({
186
+ selection,
187
+ selectionTrigger,
188
+ tableItems,
189
+ });
190
+
191
+ const { columns, stickyStart, totalColSpan } = useColumnOptions(
192
+ columnDefinitions,
193
+ {
194
+ stickyColumns: tableSettings?.stickyColumns,
195
+ hasSelection: tableSelectionState.selection.mode !== "none",
196
+ hasDetailsPanel: !!detailsPanel?.getContent,
197
+ layout,
198
+ },
199
+ );
200
+
201
+ const tableId = useId(id);
202
+
203
+ const truncateContent = tableSettings?.truncateContent ?? layout !== "auto";
204
+
205
+ return (
206
+ <DataTableContextProvider
207
+ layout={layout}
208
+ withKeyboardNav={true}
209
+ selectionState={tableSelectionState}
210
+ stickyStart={stickyStart}
211
+ stickyHeader={stickyHeader}
212
+ tableId={tableId}
213
+ loading={loadingContent}
214
+ onRowAction={onRowAction}
215
+ columns={columns}
216
+ totalColSpan={totalColSpan}
217
+ tableItems={tableItems}
218
+ sortingState={sortingState}
219
+ >
220
+ <TableElementWrapper
221
+ enabled={true}
222
+ hasStickyColumns={
223
+ !!(
224
+ tableSettings?.stickyColumns?.start ||
225
+ tableSettings?.stickyColumns?.end
226
+ )
227
+ }
228
+ >
229
+ <table
230
+ {...rest}
231
+ ref={forwardedRef}
232
+ className={cl("aksel-data-table", className)}
233
+ data-zebra-stripes={tableSettings?.zebraStripes}
234
+ data-truncate-content={truncateContent}
235
+ data-density={tableSettings?.rowDensity}
236
+ data-text-size={tableSettings?.textSize}
237
+ data-layout={layout}
238
+ data-loading={isLoading || undefined}
239
+ aria-busy={isLoading || undefined}
240
+ >
241
+ <DataTableDetailsPanelProvider detailsPanel={detailsPanel}>
242
+ <DataTableThead>
243
+ <DataTableTr>
244
+ {columns.map(
245
+ ({ isSticky, isStickyLast, stickyLeftOffset, colDef }) => {
246
+ return (
247
+ <DataTableColumnHeader
248
+ id={colDef.id}
249
+ width={colDef.width}
250
+ align={colDef.align ?? "left"}
251
+ key={colDef.id}
252
+ isSticky={isSticky}
253
+ sortable={colDef.isSortable}
254
+ label={colDef.header}
255
+ style={
256
+ stickyLeftOffset
257
+ ? { left: stickyLeftOffset }
258
+ : undefined
259
+ }
260
+ data-sticky-last={isStickyLast || undefined}
261
+ >
262
+ {colDef.headerCell ?? colDef.header}
263
+ </DataTableColumnHeader>
264
+ );
265
+ },
266
+ )}
267
+ </DataTableTr>
268
+ </DataTableThead>
269
+
270
+ <DataTableTbody>
271
+ <DataTableTBodyContent emptyContent={emptyContent} />
272
+ </DataTableTbody>
273
+ </DataTableDetailsPanelProvider>
274
+ </table>
275
+ </TableElementWrapper>
276
+ </DataTableContextProvider>
277
+ );
278
+ },
279
+ );
280
+
281
+ /**
282
+ * Temp optimization to avoid re-renders on every keyboard-move, selection change etc
283
+ */
284
+ function TableElementWrapper({
285
+ children,
286
+ enabled,
287
+ hasStickyColumns,
288
+ }: {
289
+ children: React.ReactNode;
290
+ enabled: boolean;
291
+ hasStickyColumns: boolean;
292
+ }) {
293
+ const [applyStickyStyles, setApplyStickyStyles] = useState<boolean>(false);
294
+
295
+ const tableWrapperRef = useRef<HTMLDivElement>(null);
296
+ const tableRef = useRef<HTMLTableElement>(null);
297
+ const rafRef = useRef<number | null>(null);
298
+ const { tabIndex, setTableRef } = useTableKeyboardNav({
299
+ enabled,
300
+ });
301
+
302
+ const mergedTableRefs = useMergeRefs(tableRef, setTableRef);
303
+
304
+ const updateStickyStyles = useCallback(() => {
305
+ if (!tableWrapperRef.current) {
306
+ return;
307
+ }
308
+
309
+ const doesWrapperHasScroll =
310
+ tableWrapperRef.current.scrollWidth > tableWrapperRef.current.clientWidth;
311
+
312
+ setApplyStickyStyles(doesWrapperHasScroll);
313
+ }, []);
314
+
315
+ const scheduleStickyStylesUpdate = useCallback(() => {
316
+ if (rafRef.current !== null) {
317
+ return;
318
+ }
319
+
320
+ rafRef.current = requestAnimationFrame(() => {
321
+ rafRef.current = null;
322
+ updateStickyStyles();
323
+ });
324
+ }, [updateStickyStyles]);
325
+
326
+ useEffect(
327
+ function observeAndUpdateStickyStyles() {
328
+ if (!hasStickyColumns) {
329
+ return;
330
+ }
331
+
332
+ const tableWrapperElement = tableWrapperRef.current;
333
+
334
+ if (!tableWrapperElement) {
335
+ return;
336
+ }
337
+
338
+ const handleResize = () => scheduleStickyStylesUpdate();
339
+
340
+ window.addEventListener("resize", handleResize);
341
+
342
+ let resizeObserver: ResizeObserver | undefined;
343
+ if (typeof ResizeObserver !== "undefined") {
344
+ resizeObserver = new ResizeObserver(handleResize);
345
+ resizeObserver.observe(tableWrapperElement);
346
+ if (tableRef.current) {
347
+ resizeObserver.observe(tableRef.current);
348
+ }
349
+ }
350
+
351
+ scheduleStickyStylesUpdate();
352
+
353
+ return () => {
354
+ window.removeEventListener("resize", handleResize);
355
+ resizeObserver?.disconnect();
356
+ if (rafRef.current !== null) {
357
+ cancelAnimationFrame(rafRef.current);
358
+ rafRef.current = null;
359
+ }
360
+ };
361
+ },
362
+ [scheduleStickyStylesUpdate, hasStickyColumns],
363
+ );
364
+
365
+ return (
366
+ <div className="aksel-data-table__border-wrapper">
367
+ <div ref={tableWrapperRef} className="aksel-data-table__scroll-wrapper">
368
+ <Slot
369
+ tabIndex={tabIndex}
370
+ /* @ts-expect-error Ref is not typed correctly to handle this case */
371
+ ref={mergedTableRefs}
372
+ data-scroll={applyStickyStyles ? "true" : undefined}
373
+ >
374
+ {children}
375
+ </Slot>
376
+ </div>
377
+ </div>
378
+ );
379
+ }
380
+
381
+ interface DataTableTBodyContentProps {
382
+ emptyContent: React.ReactNode;
383
+ }
384
+
385
+ function DataTableTBodyContent({ emptyContent }: DataTableTBodyContentProps) {
386
+ const { columns, loading, totalColSpan, tableItems } = useDataTableContext();
387
+ const { isLoading } = useDataGridContext();
388
+
389
+ if (isLoading && loading?.variant === "content") {
390
+ return (
391
+ <DataTableLoadingState colSpan={totalColSpan}>
392
+ {loading.content}
393
+ </DataTableLoadingState>
394
+ );
395
+ }
396
+
397
+ if (isLoading && loading?.variant === "skeleton") {
398
+ const rows = loading.rows ?? 5;
399
+ const label = loading.label ?? "Laster innhold"; // TODO translate
400
+ return (
401
+ <>
402
+ <tr>
403
+ <td colSpan={totalColSpan} className="aksel-sr-only">
404
+ {label}
405
+ </td>
406
+ </tr>
407
+ {Array.from({ length: rows }, (_, rowIndex) => (
408
+ <DataTableTr key={`skeleton-row-${rowIndex}`} aria-hidden>
409
+ {columns.map(
410
+ (
411
+ { isSticky, isStickyLast, stickyLeftOffset, colDef },
412
+ colDefIndex,
413
+ ) => (
414
+ <DataTableBaseCell
415
+ align={colDef.align ?? "left"}
416
+ key={colDef.id || colDefIndex}
417
+ as={colDef.isRowHeader ? "th" : "td"}
418
+ isSticky={isSticky}
419
+ style={
420
+ stickyLeftOffset ? { left: stickyLeftOffset } : undefined
421
+ }
422
+ data-sticky-last={isStickyLast || undefined}
423
+ >
424
+ <Skeleton variant="text" />
425
+ </DataTableBaseCell>
426
+ ),
427
+ )}
428
+ </DataTableTr>
429
+ ))}
430
+ </>
431
+ );
432
+ }
433
+
434
+ if (tableItems.items.length === 0 && emptyContent !== undefined) {
435
+ return (
436
+ <DataTableEmptyState colSpan={totalColSpan}>
437
+ {emptyContent}
438
+ </DataTableEmptyState>
439
+ );
440
+ }
441
+
442
+ const renderLoadingAnnouncement = isLoading && loading?.variant === "overlay";
443
+
444
+ const overlayLabel =
445
+ loading?.variant === "overlay"
446
+ ? (loading.label ?? "Laster innhold") // TODO translate
447
+ : "Laster innhold";
448
+
449
+ return (
450
+ <>
451
+ {renderLoadingAnnouncement && (
452
+ <tr>
453
+ <td colSpan={totalColSpan} className="aksel-sr-only">
454
+ {overlayLabel}
455
+ </td>
456
+ </tr>
457
+ )}
458
+ {tableItems.items.map((rowData, rowIndex) => {
459
+ const rowId = tableItems.visibleRowIds[rowIndex];
460
+ const details =
461
+ rowId != null ? tableItems.itemDetails.get(rowId) : undefined;
462
+
463
+ /* Should in theory be impossible. Look about typing this? */
464
+ if (!details) {
465
+ return null;
466
+ }
467
+
468
+ return (
469
+ <DataTableDataRow
470
+ key={details.id}
471
+ rowData={rowData}
472
+ details={details}
473
+ columns={columns}
474
+ />
475
+ );
476
+ })}
477
+ </>
478
+ );
479
+ }
480
+
481
+ interface DataTableDataRowProps {
482
+ rowData: any;
483
+ details: ItemDetail<any>;
484
+ columns: ReturnType<typeof useColumnOptions>["columns"];
485
+ }
486
+
487
+ const DataTableDataRow = memo(
488
+ function DataTableDataRow({
489
+ rowData,
490
+ details,
491
+ columns,
492
+ }: DataTableDataRowProps) {
493
+ const hasSubRows = details.children.length > 0;
494
+
495
+ return (
496
+ <>
497
+ <DataTableTr rowId={details.id}>
498
+ {columns.map(
499
+ (
500
+ { isSticky, isStickyLast, stickyLeftOffset, colDef },
501
+ colDefIndex,
502
+ ) => {
503
+ const renderNestedToggle = colDefIndex === 0 && hasSubRows;
504
+ const renderNestedIndent =
505
+ colDefIndex === 0 && (details.level > 0 || hasSubRows);
506
+
507
+ const style: React.CSSProperties = {
508
+ "--__axc-data-table-nested-depth": details.level,
509
+ ...(stickyLeftOffset ? { left: stickyLeftOffset } : {}),
510
+ };
511
+
512
+ return (
513
+ <DataTableBaseCell
514
+ align={colDef.align ?? "left"}
515
+ key={colDef.id || colDefIndex}
516
+ as={colDef.isRowHeader ? "th" : "td"}
517
+ isSticky={isSticky}
518
+ data-nested={renderNestedIndent || undefined}
519
+ data-sticky-last={isStickyLast || undefined}
520
+ style={style}
521
+ beforeContent={
522
+ renderNestedToggle ? (
523
+ <DataTableSubRowToggle details={details} />
524
+ ) : undefined
525
+ }
526
+ >
527
+ {colDef.bodyCell(rowData)}
528
+ </DataTableBaseCell>
529
+ );
530
+ },
531
+ )}
532
+ </DataTableTr>
533
+ <DataTableDetailsPanelRow rowId={details.id} rowData={rowData} />
534
+ </>
535
+ );
536
+ },
537
+ /* TODO: Might be some better metrics we could use to optimize this */
538
+ (prev, next) =>
539
+ prev.rowData === next.rowData &&
540
+ prev.columns === next.columns &&
541
+ prev.details.id === next.details.id &&
542
+ prev.details.level === next.details.level &&
543
+ prev.details.children.length === next.details.children.length,
544
+ );
545
+
546
+ const DataGridTable = DataGridTableInternal as <RowT>(
547
+ props: DataGridTableProps<RowT> & React.RefAttributes<HTMLTableElement>,
548
+ ) => React.ReactElement | null;
549
+
550
+ // eslint-disable-next-line @typescript-eslint/no-namespace, import/export
551
+ export namespace DataGridTable {
552
+ export type Props<T = unknown> = DataGridTableProps<T>;
553
+ export type Sorting = TableSortOptions;
554
+ export type SortEntry = import("./DataGridTable.types").SortEntry;
555
+ export type SortChangeDetail =
556
+ import("./DataGridTable.types").SortChangeDetail;
557
+ export type LoadingContent = DataTableLoadingConfig;
558
+ export type SubRows<T = unknown> = SubRowsProps<T>;
559
+ export type DetailsPanel<T = unknown> = DetailsPanelProps<T>;
560
+ }
561
+
562
+ // docgen doesn't work well with type params, so we let it use DataGridTableInternal instead
563
+ // eslint-disable-next-line import/export
564
+ export { DataGridTable, DataGridTableInternal };
565
+ export type { DataGridTableProps };
566
+ export default DataGridTable;
@@ -1,27 +1,41 @@
1
1
  import { createStrictContext } from "../../../utils/helpers";
2
- import type { UseColumnOptionsResult } from "../hooks/useColumnOptions";
2
+ import type {
3
+ StickyStartState,
4
+ UseColumnOptionsResult,
5
+ } from "../hooks/useColumnOptions";
6
+ import type { UseTableItemsReturn } from "../hooks/useTableItems";
3
7
  import type { UseTableSelectionReturn } from "../hooks/useTableSelection";
8
+ import type { UseTableSortResults } from "../hooks/useTableSort";
9
+ import type { DataTableLoadingConfig } from "./DataGridTable.types";
4
10
 
5
11
  type DataTableContextProps<T> = {
6
12
  layout: "fixed" | "auto";
7
13
  withKeyboardNav: boolean;
8
14
  selectionState: UseTableSelectionReturn;
9
- stickySelection: boolean;
15
+ stickyStart: StickyStartState;
10
16
  stickyHeader: boolean;
11
17
  tableId: string;
12
- showLoadingSkeletons: boolean;
13
- onRowClick?: (
14
- rowId: string | number,
15
- event: React.MouseEvent<HTMLTableRowElement>,
16
- ) => void;
17
- isLoading?: boolean;
18
- showLoadingOverlay: boolean;
18
+ loading: DataTableLoadingConfig | undefined;
19
+ onRowAction?: ({
20
+ row,
21
+ id,
22
+ event,
23
+ }: {
24
+ row: T;
25
+ id: string;
26
+ event: React.MouseEvent<HTMLTableRowElement>;
27
+ }) => void;
19
28
  columns: UseColumnOptionsResult<T>["columns"];
20
29
  /**
21
30
  * Used to set exact colspan for detailsPanel, loadingState and emptyState.
22
31
  * This is necessary to ensure that these components span the entire width of the table.
23
32
  */
24
- fullWidthColSpan: number;
33
+ totalColSpan: number;
34
+ /**
35
+ * The current items and related metadata.
36
+ */
37
+ tableItems: UseTableItemsReturn<T>;
38
+ sortingState: UseTableSortResults;
25
39
  };
26
40
 
27
41
  const { Provider: DataTableContextProvider, useContext: useDataTableContext } =
@@ -1,14 +1,15 @@
1
1
  import React from "react";
2
2
  import { ChevronDownIcon, ChevronRightIcon } from "@navikt/aksel-icons";
3
3
  import { Button } from "../../../button";
4
- import { type ItemDetail, useTableItemsContext } from "../hooks/useTableItems";
4
+ import { type ItemDetail } from "../hooks/useTableItems";
5
+ import { useDataTableContext } from "../root/DataTableRoot.context";
5
6
 
6
7
  function DataTableSubRowToggle({ details }: { details: ItemDetail<any> }) {
7
- const { isSubRowExpanded, onExpandedRowIdsChange } = useTableItemsContext();
8
+ const { tableItems } = useDataTableContext();
8
9
 
9
10
  const subRows = details.children;
10
11
  const hasSubRows = subRows && subRows.length > 0;
11
- const isRowExpanded = isSubRowExpanded(details.id);
12
+ const isRowExpanded = tableItems.isSubRowExpanded(details.id);
12
13
 
13
14
  return (
14
15
  <div className="aksel-data-table__nested-toggle">
@@ -19,10 +20,10 @@ function DataTableSubRowToggle({ details }: { details: ItemDetail<any> }) {
19
20
  size="small"
20
21
  onClick={(e) => {
21
22
  e.stopPropagation();
22
- onExpandedRowIdsChange(details.id);
23
+ tableItems.onExpandedRowIdsChange(details.id);
23
24
  }}
24
25
  aria-expanded={isRowExpanded}
25
- aria-label={isRowExpanded ? "Skjul under-rader" : "Vis under-rader"}
26
+ aria-label={isRowExpanded ? "Skjul under-rader" : "Vis under-rader"} // TODO translate
26
27
  icon={
27
28
  isRowExpanded ? (
28
29
  <ChevronDownIcon aria-hidden />
@@ -1,4 +1,5 @@
1
1
  import React, { forwardRef, version } from "react";
2
+ import { useDataGridContext } from "../../../data-grid/root/DataGridRoot.context";
2
3
  import { cl } from "../../../utils/helpers";
3
4
  import {
4
5
  DataTableLocationProvider,
@@ -11,7 +12,8 @@ const inertValue = parseInt(version.split(".")[0], 10) > 18 ? true : ""; // Supp
11
12
 
12
13
  const DataTableTbody = forwardRef<HTMLTableSectionElement, DataTableTbodyProps>(
13
14
  ({ className, ...rest }, forwardedRef) => {
14
- const { showLoadingOverlay } = useDataTableContext();
15
+ const { isLoading } = useDataGridContext();
16
+ const { loading } = useDataTableContext();
15
17
  return (
16
18
  <DataTableLocationProvider location="tbody">
17
19
  <tbody
@@ -19,7 +21,9 @@ const DataTableTbody = forwardRef<HTMLTableSectionElement, DataTableTbodyProps>(
19
21
  ref={forwardedRef}
20
22
  className={cl("aksel-data-table__tbody", className)}
21
23
  // @ts-expect-error - inert is not yet recognized by React's type definitions, but we want to use it for better accessibility when showing the loading overlay.
22
- inert={showLoadingOverlay ? inertValue : false}
24
+ inert={
25
+ isLoading && loading?.variant === "overlay" ? inertValue : false
26
+ }
23
27
  />
24
28
  </DataTableLocationProvider>
25
29
  );