@navikt/ds-react 8.10.3 → 8.10.5

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 (242) 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/drag-and-drop/drag-handler/DragAndDropDragHandler.js +11 -12
  4. package/cjs/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js.map +1 -1
  5. package/cjs/data/drag-and-drop/root/DragAndDrop.context.d.ts +4 -2
  6. package/cjs/data/drag-and-drop/root/DragAndDrop.context.js.map +1 -1
  7. package/cjs/data/drag-and-drop/root/DragAndDropRoot.d.ts +5 -5
  8. package/cjs/data/drag-and-drop/root/DragAndDropRoot.js +49 -28
  9. package/cjs/data/drag-and-drop/root/DragAndDropRoot.js.map +1 -1
  10. package/cjs/data/drag-and-drop/types.d.ts +0 -4
  11. package/cjs/data/{drag-and-drop-old/drag-handler/DataDragAndDropDragHandler.d.ts → drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.d.ts} +3 -3
  12. package/cjs/data/{drag-and-drop-old/drag-handler/DataDragAndDropDragHandler.js → drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.js} +5 -5
  13. package/cjs/data/drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.js.map +1 -0
  14. package/cjs/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.d.ts +27 -0
  15. package/cjs/data/{drag-and-drop-old/item/DataDragAndDropItem.js → drag-and-drop-legacy/item/DragAndDropItemLegacy.js} +12 -12
  16. package/cjs/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.js.map +1 -0
  17. package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.d.ts +5 -0
  18. package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.js +6 -0
  19. package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.js.map +1 -0
  20. package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.d.ts +24 -0
  21. package/cjs/data/{drag-and-drop-old/root/DataDragAndDropRoot.js → drag-and-drop-legacy/root/DragAndDropLegacyRoot.js} +10 -10
  22. package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.js.map +1 -0
  23. package/cjs/data/stories/Data.test-data.d.ts +24 -0
  24. package/cjs/data/stories/Data.test-data.js +1615 -0
  25. package/cjs/data/stories/Data.test-data.js.map +1 -0
  26. package/cjs/data/table/column-header/DataTableColumnHeader.d.ts +4 -1
  27. package/cjs/data/table/column-header/DataTableColumnHeader.js +4 -4
  28. package/cjs/data/table/column-header/DataTableColumnHeader.js.map +1 -1
  29. package/cjs/data/table/column-header/useTableColumnResize.d.ts +21 -18
  30. package/cjs/data/table/column-header/useTableColumnResize.js +7 -25
  31. package/cjs/data/table/column-header/useTableColumnResize.js.map +1 -1
  32. package/cjs/data/table/details-panel-row/DataTableDetailsPanelRow.d.ts +6 -0
  33. package/cjs/data/table/details-panel-row/DataTableDetailsPanelRow.js +32 -0
  34. package/cjs/data/table/details-panel-row/DataTableDetailsPanelRow.js.map +1 -0
  35. package/cjs/data/table/helpers/collectTableRowEntries.d.ts +9 -7
  36. package/cjs/data/table/helpers/collectTableRowEntries.js +21 -14
  37. package/cjs/data/table/helpers/collectTableRowEntries.js.map +1 -1
  38. package/cjs/data/table/helpers/table-focus.d.ts +0 -3
  39. package/cjs/data/table/helpers/table-focus.js +38 -8
  40. package/cjs/data/table/helpers/table-focus.js.map +1 -1
  41. package/cjs/data/table/hooks/useColumnOptions.js +18 -5
  42. package/cjs/data/table/hooks/useColumnOptions.js.map +1 -1
  43. package/cjs/data/table/hooks/useGridCache.js +2 -2
  44. package/cjs/data/table/hooks/useGridCache.js.map +1 -1
  45. package/cjs/data/table/hooks/useTableDetailsPanel.d.ts +62 -0
  46. package/cjs/data/table/hooks/{useTableExpansion.js → useTableDetailsPanel.js} +21 -20
  47. package/cjs/data/table/hooks/useTableDetailsPanel.js.map +1 -0
  48. package/cjs/data/table/hooks/useTableItems.d.ts +14 -17
  49. package/cjs/data/table/hooks/useTableItems.js +17 -16
  50. package/cjs/data/table/hooks/useTableItems.js.map +1 -1
  51. package/cjs/data/table/hooks/useTableKeyboardNav.js +5 -1
  52. package/cjs/data/table/hooks/useTableKeyboardNav.js.map +1 -1
  53. package/cjs/data/table/hooks/useTableSelection.d.ts +4 -2
  54. package/cjs/data/table/hooks/useTableSelection.js +6 -1
  55. package/cjs/data/table/hooks/useTableSelection.js.map +1 -1
  56. package/cjs/data/table/index.d.ts +1 -2
  57. package/cjs/data/table/index.js +22 -12
  58. package/cjs/data/table/index.js.map +1 -1
  59. package/cjs/data/table/root/DataTable.types.d.ts +7 -9
  60. package/cjs/data/table/root/DataTableRoot.context.d.ts +5 -1
  61. package/cjs/data/table/root/DataTableRoot.context.js.map +1 -1
  62. package/cjs/data/table/root/DataTableRoot.d.ts +79 -115
  63. package/cjs/data/table/root/DataTableRoot.js +163 -38
  64. package/cjs/data/table/root/DataTableRoot.js.map +1 -1
  65. package/cjs/data/table/root/DataTableRoot.legacy.d.ts +177 -0
  66. package/cjs/data/table/root/DataTableRoot.legacy.js +104 -0
  67. package/cjs/data/table/root/DataTableRoot.legacy.js.map +1 -0
  68. package/cjs/data/table/sub-row-toggle/DataTableSubRowToggle.d.ts +6 -0
  69. package/cjs/data/table/sub-row-toggle/DataTableSubRowToggle.js +21 -0
  70. package/cjs/data/table/sub-row-toggle/DataTableSubRowToggle.js.map +1 -0
  71. package/cjs/data/table/tr/DataTableTr.js +11 -11
  72. package/cjs/data/table/tr/DataTableTr.js.map +1 -1
  73. package/cjs/utils/components/dismissablelayer/DismissableLayer.js +1 -1
  74. package/cjs/utils/components/dismissablelayer/DismissableLayer.js.map +1 -1
  75. package/cjs/utils/components/floating/Floating.d.ts +16 -1
  76. package/cjs/utils/components/floating/Floating.js +50 -13
  77. package/cjs/utils/components/floating/Floating.js.map +1 -1
  78. package/cjs/utils/components/floating-menu/Menu.js +1 -1
  79. package/cjs/utils/components/floating-menu/Menu.js.map +1 -1
  80. package/cjs/utils/helpers/create-strict-context.js +1 -1
  81. package/cjs/utils/helpers/create-strict-context.js.map +1 -1
  82. package/cjs/utils/hooks/useControllableState.d.ts +5 -5
  83. package/cjs/utils/hooks/useControllableState.js.map +1 -1
  84. package/cjs/utils/hooks/useValueAsRef.js +1 -1
  85. package/cjs/utils/hooks/useValueAsRef.js.map +1 -1
  86. package/cjs/utils-external/hooks/useId.js +1 -1
  87. package/cjs/utils-external/hooks/useId.js.map +1 -1
  88. package/esm/action-menu/ActionMenu.js +1 -1
  89. package/esm/action-menu/ActionMenu.js.map +1 -1
  90. package/esm/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js +11 -12
  91. package/esm/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js.map +1 -1
  92. package/esm/data/drag-and-drop/root/DragAndDrop.context.d.ts +4 -2
  93. package/esm/data/drag-and-drop/root/DragAndDrop.context.js.map +1 -1
  94. package/esm/data/drag-and-drop/root/DragAndDropRoot.d.ts +5 -5
  95. package/esm/data/drag-and-drop/root/DragAndDropRoot.js +49 -28
  96. package/esm/data/drag-and-drop/root/DragAndDropRoot.js.map +1 -1
  97. package/esm/data/drag-and-drop/types.d.ts +0 -4
  98. package/esm/data/{drag-and-drop-old/drag-handler/DataDragAndDropDragHandler.d.ts → drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.d.ts} +3 -3
  99. package/esm/data/{drag-and-drop-old/drag-handler/DataDragAndDropDragHandler.js → drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.js} +4 -4
  100. package/esm/data/drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.js.map +1 -0
  101. package/esm/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.d.ts +27 -0
  102. package/esm/data/{drag-and-drop-old/item/DataDragAndDropItem.js → drag-and-drop-legacy/item/DragAndDropItemLegacy.js} +11 -11
  103. package/esm/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.js.map +1 -0
  104. package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.d.ts +5 -0
  105. package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.js +3 -0
  106. package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.js.map +1 -0
  107. package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.d.ts +24 -0
  108. package/esm/data/{drag-and-drop-old/root/DataDragAndDropRoot.js → drag-and-drop-legacy/root/DragAndDropLegacyRoot.js} +8 -8
  109. package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.js.map +1 -0
  110. package/esm/data/stories/Data.test-data.d.ts +24 -0
  111. package/esm/data/stories/Data.test-data.js +1606 -0
  112. package/esm/data/stories/Data.test-data.js.map +1 -0
  113. package/esm/data/table/column-header/DataTableColumnHeader.d.ts +4 -1
  114. package/esm/data/table/column-header/DataTableColumnHeader.js +4 -4
  115. package/esm/data/table/column-header/DataTableColumnHeader.js.map +1 -1
  116. package/esm/data/table/column-header/useTableColumnResize.d.ts +21 -18
  117. package/esm/data/table/column-header/useTableColumnResize.js +7 -25
  118. package/esm/data/table/column-header/useTableColumnResize.js.map +1 -1
  119. package/esm/data/table/details-panel-row/DataTableDetailsPanelRow.d.ts +6 -0
  120. package/esm/data/table/details-panel-row/DataTableDetailsPanelRow.js +27 -0
  121. package/esm/data/table/details-panel-row/DataTableDetailsPanelRow.js.map +1 -0
  122. package/esm/data/table/helpers/collectTableRowEntries.d.ts +9 -7
  123. package/esm/data/table/helpers/collectTableRowEntries.js +21 -14
  124. package/esm/data/table/helpers/collectTableRowEntries.js.map +1 -1
  125. package/esm/data/table/helpers/table-focus.d.ts +0 -3
  126. package/esm/data/table/helpers/table-focus.js +38 -8
  127. package/esm/data/table/helpers/table-focus.js.map +1 -1
  128. package/esm/data/table/hooks/useColumnOptions.js +18 -5
  129. package/esm/data/table/hooks/useColumnOptions.js.map +1 -1
  130. package/esm/data/table/hooks/useGridCache.js +2 -2
  131. package/esm/data/table/hooks/useGridCache.js.map +1 -1
  132. package/esm/data/table/hooks/useTableDetailsPanel.d.ts +62 -0
  133. package/esm/data/table/hooks/{useTableExpansion.js → useTableDetailsPanel.js} +18 -17
  134. package/esm/data/table/hooks/useTableDetailsPanel.js.map +1 -0
  135. package/esm/data/table/hooks/useTableItems.d.ts +14 -17
  136. package/esm/data/table/hooks/useTableItems.js +17 -16
  137. package/esm/data/table/hooks/useTableItems.js.map +1 -1
  138. package/esm/data/table/hooks/useTableKeyboardNav.js +6 -2
  139. package/esm/data/table/hooks/useTableKeyboardNav.js.map +1 -1
  140. package/esm/data/table/hooks/useTableSelection.d.ts +4 -2
  141. package/esm/data/table/hooks/useTableSelection.js +6 -1
  142. package/esm/data/table/hooks/useTableSelection.js.map +1 -1
  143. package/esm/data/table/index.d.ts +1 -2
  144. package/esm/data/table/index.js +21 -1
  145. package/esm/data/table/index.js.map +1 -1
  146. package/esm/data/table/root/DataTable.types.d.ts +7 -9
  147. package/esm/data/table/root/DataTableRoot.context.d.ts +5 -1
  148. package/esm/data/table/root/DataTableRoot.context.js.map +1 -1
  149. package/esm/data/table/root/DataTableRoot.d.ts +79 -115
  150. package/esm/data/table/root/DataTableRoot.js +170 -36
  151. package/esm/data/table/root/DataTableRoot.js.map +1 -1
  152. package/esm/data/table/root/DataTableRoot.legacy.d.ts +177 -0
  153. package/esm/data/table/root/DataTableRoot.legacy.js +59 -0
  154. package/esm/data/table/root/DataTableRoot.legacy.js.map +1 -0
  155. package/esm/data/table/sub-row-toggle/DataTableSubRowToggle.d.ts +6 -0
  156. package/esm/data/table/sub-row-toggle/DataTableSubRowToggle.js +16 -0
  157. package/esm/data/table/sub-row-toggle/DataTableSubRowToggle.js.map +1 -0
  158. package/esm/data/table/tr/DataTableTr.js +11 -11
  159. package/esm/data/table/tr/DataTableTr.js.map +1 -1
  160. package/esm/utils/components/dismissablelayer/DismissableLayer.js +1 -1
  161. package/esm/utils/components/dismissablelayer/DismissableLayer.js.map +1 -1
  162. package/esm/utils/components/floating/Floating.d.ts +16 -1
  163. package/esm/utils/components/floating/Floating.js +48 -13
  164. package/esm/utils/components/floating/Floating.js.map +1 -1
  165. package/esm/utils/components/floating-menu/Menu.js +2 -2
  166. package/esm/utils/components/floating-menu/Menu.js.map +1 -1
  167. package/esm/utils/helpers/create-strict-context.js +1 -1
  168. package/esm/utils/helpers/create-strict-context.js.map +1 -1
  169. package/esm/utils/hooks/useControllableState.d.ts +5 -5
  170. package/esm/utils/hooks/useControllableState.js.map +1 -1
  171. package/esm/utils/hooks/useValueAsRef.js +1 -1
  172. package/esm/utils/hooks/useValueAsRef.js.map +1 -1
  173. package/esm/utils-external/hooks/useId.js +1 -1
  174. package/esm/utils-external/hooks/useId.js.map +1 -1
  175. package/package.json +8 -7
  176. package/src/action-menu/ActionMenu.tsx +1 -1
  177. package/src/data/drag-and-drop/drag-handler/DragAndDropDragHandler.tsx +11 -16
  178. package/src/data/drag-and-drop/root/DragAndDrop.context.tsx +4 -2
  179. package/src/data/drag-and-drop/root/DragAndDropRoot.tsx +85 -40
  180. package/src/data/drag-and-drop/types.ts +0 -5
  181. package/src/data/{drag-and-drop-old/drag-handler/DataDragAndDropDragHandler.tsx → drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.tsx} +5 -5
  182. package/src/data/{drag-and-drop-old/item/DataDragAndDropItem.tsx → drag-and-drop-legacy/item/DragAndDropItemLegacy.tsx} +13 -13
  183. package/src/data/{drag-and-drop-old/root/DataDragAndDrop.context.tsx → drag-and-drop-legacy/root/DragAndDropLegacy.context.tsx} +3 -3
  184. package/src/data/{drag-and-drop-old/root/DataDragAndDropRoot.tsx → drag-and-drop-legacy/root/DragAndDropLegacyRoot.tsx} +19 -21
  185. package/src/data/stories/Data.test-data.tsx +1702 -0
  186. package/src/data/table/column-header/DataTableColumnHeader.tsx +8 -6
  187. package/src/data/table/column-header/useTableColumnResize.ts +29 -44
  188. package/src/data/table/details-panel-row/DataTableDetailsPanelRow.tsx +57 -0
  189. package/src/data/table/helpers/collectTableRowEntries.ts +36 -30
  190. package/src/data/table/helpers/table-focus.ts +63 -9
  191. package/src/data/table/hooks/__tests__/useTableItems.test.ts +58 -12
  192. package/src/data/table/hooks/__tests__/useTableSelection.test.ts +57 -44
  193. package/src/data/table/hooks/useColumnOptions.ts +19 -5
  194. package/src/data/table/hooks/useGridCache.ts +3 -2
  195. package/src/data/table/hooks/useTableDetailsPanel.tsx +185 -0
  196. package/src/data/table/hooks/useTableItems.ts +44 -52
  197. package/src/data/table/hooks/useTableKeyboardNav.ts +6 -2
  198. package/src/data/table/hooks/useTableSelection.ts +17 -6
  199. package/src/data/table/index.tsx +5 -3
  200. package/src/data/table/root/DataTable.types.ts +20 -9
  201. package/src/data/table/root/DataTableRoot.context.ts +5 -1
  202. package/src/data/table/root/DataTableRoot.legacy.tsx +297 -0
  203. package/src/data/table/root/DataTableRoot.tsx +484 -219
  204. package/src/data/table/root/agent-feature-gap.md +96 -0
  205. package/src/data/table/sub-row-toggle/DataTableSubRowToggle.tsx +39 -0
  206. package/src/data/table/tr/DataTableTr.tsx +14 -13
  207. package/src/utils/components/dismissablelayer/DismissableLayer.tsx +1 -1
  208. package/src/utils/components/floating/Floating.tsx +56 -13
  209. package/src/utils/components/floating-menu/Menu.tsx +4 -1
  210. package/src/utils/helpers/create-strict-context.tsx +1 -1
  211. package/src/utils/hooks/useControllableState.ts +11 -8
  212. package/src/utils/hooks/useValueAsRef.ts +1 -1
  213. package/src/utils-external/hooks/useId.ts +1 -1
  214. package/cjs/data/drag-and-drop-old/drag-handler/DataDragAndDropDragHandler.js.map +0 -1
  215. package/cjs/data/drag-and-drop-old/item/DataDragAndDropItem.d.ts +0 -27
  216. package/cjs/data/drag-and-drop-old/item/DataDragAndDropItem.js.map +0 -1
  217. package/cjs/data/drag-and-drop-old/root/DataDragAndDrop.context.d.ts +0 -5
  218. package/cjs/data/drag-and-drop-old/root/DataDragAndDrop.context.js +0 -6
  219. package/cjs/data/drag-and-drop-old/root/DataDragAndDrop.context.js.map +0 -1
  220. package/cjs/data/drag-and-drop-old/root/DataDragAndDropRoot.d.ts +0 -24
  221. package/cjs/data/drag-and-drop-old/root/DataDragAndDropRoot.js.map +0 -1
  222. package/cjs/data/table/hooks/useTableExpansion.d.ts +0 -27
  223. package/cjs/data/table/hooks/useTableExpansion.js.map +0 -1
  224. package/cjs/data/table/root/DataTableAuto.d.ts +0 -182
  225. package/cjs/data/table/root/DataTableAuto.js +0 -206
  226. package/cjs/data/table/root/DataTableAuto.js.map +0 -1
  227. package/esm/data/drag-and-drop-old/drag-handler/DataDragAndDropDragHandler.js.map +0 -1
  228. package/esm/data/drag-and-drop-old/item/DataDragAndDropItem.d.ts +0 -27
  229. package/esm/data/drag-and-drop-old/item/DataDragAndDropItem.js.map +0 -1
  230. package/esm/data/drag-and-drop-old/root/DataDragAndDrop.context.d.ts +0 -5
  231. package/esm/data/drag-and-drop-old/root/DataDragAndDrop.context.js +0 -3
  232. package/esm/data/drag-and-drop-old/root/DataDragAndDrop.context.js.map +0 -1
  233. package/esm/data/drag-and-drop-old/root/DataDragAndDropRoot.d.ts +0 -24
  234. package/esm/data/drag-and-drop-old/root/DataDragAndDropRoot.js.map +0 -1
  235. package/esm/data/table/hooks/useTableExpansion.d.ts +0 -27
  236. package/esm/data/table/hooks/useTableExpansion.js.map +0 -1
  237. package/esm/data/table/root/DataTableAuto.d.ts +0 -182
  238. package/esm/data/table/root/DataTableAuto.js +0 -170
  239. package/esm/data/table/root/DataTableAuto.js.map +0 -1
  240. package/src/data/table/hooks/useTableExpansion.tsx +0 -146
  241. package/src/data/table/root/DataTableAuto.test.tsx +0 -244
  242. package/src/data/table/root/DataTableAuto.tsx +0 -612
@@ -17,11 +17,10 @@ import { type ResizeProps, useTableColumnResize } from "./useTableColumnResize";
17
17
 
18
18
  interface DataTableColumnHeaderProps
19
19
  extends ResizeProps, DataTableBaseCellProps {
20
- resizeHandler?: (
21
- event:
22
- | React.MouseEvent<HTMLButtonElement>
23
- | React.TouchEvent<HTMLButtonElement>,
24
- ) => void;
20
+ /**
21
+ * Accessible name of the column.
22
+ */
23
+ label: string;
25
24
  /**
26
25
  * Makes the column header sortable. The entire header cell content becomes
27
26
  * a clickable button when true.
@@ -59,6 +58,7 @@ const DataTableColumnHeader = forwardRef<
59
58
  {
60
59
  className,
61
60
  children,
61
+ label,
62
62
  sortable = false,
63
63
  sortDirection = "none",
64
64
  onSortClick,
@@ -111,6 +111,7 @@ const DataTableColumnHeader = forwardRef<
111
111
  >
112
112
  {sortable ? (
113
113
  <button
114
+ type="button"
114
115
  className="aksel-data-table__th-sort-button"
115
116
  onClick={onSortClick}
116
117
  >
@@ -140,11 +141,12 @@ const DataTableColumnHeader = forwardRef<
140
141
  {resizeResult.enabled && !UNSAFE_isSelection && (
141
142
  <button
142
143
  {...resizeResult.resizeHandlerProps}
144
+ type="button"
143
145
  className="aksel-data-table__th-resize-handle"
144
146
  aria-label={
145
147
  resizeResult.isResizingWithKeyboard
146
148
  ? "Bruk pil venstre/høyre"
147
- : "Endre bredde"
149
+ : `Endre bredde ${label}`
148
150
  } // TODO Translate
149
151
  data-active={resizeResult.isResizingWithKeyboard}
150
152
  data-disable-keyboard-nav={resizeResult.isResizingWithKeyboard}
@@ -8,9 +8,8 @@ import {
8
8
  import { useControllableState } from "../../../utils/hooks";
9
9
  import { useDataTableContext } from "../root/DataTableRoot.context";
10
10
 
11
- type ColumnWidth = number | string;
12
-
13
11
  type ResizeProps = {
12
+ // If/when we add support for composition, consider mentioning that resizing only works on first row in thead.
14
13
  /**
15
14
  * Whether the column should be resizable by the user.
16
15
  *
@@ -18,16 +17,6 @@ type ResizeProps = {
18
17
  * @default true
19
18
  */
20
19
  resizable?: boolean;
21
- /**
22
- * Controlled width of the column.
23
- *
24
- * Should only be used to fully control column width state. Otherwise, use `defaultWidth` and let the component handle resizing.
25
- */
26
- width?: ColumnWidth;
27
- /**
28
- * Initial width of the column. Only used when `width` is not set and `resizable` is true.
29
- */
30
- defaultWidth?: ColumnWidth;
31
20
  /**
32
21
  * Whether the column should automatically resize to fit its content. **Runs only once.**
33
22
  *
@@ -40,21 +29,36 @@ type ResizeProps = {
40
29
  */
41
30
  autoWidth?: boolean;
42
31
  /**
43
- * Minimum width of the column.
32
+ * Minimum width of the column when resizing. Only used when `resizable` or `autoWidth` is enabled.
33
+ * @default 40
34
+ */
35
+ minWidth?: number;
36
+ /**
37
+ * Maximum width of the column when resizing. Only used when `resizable` or `autoWidth` is enabled.
38
+ */
39
+ maxWidth?: number;
40
+ // TODO: Consider "allowing" %-width on last column, if we find a solution to the overflow issue (width becomes 0px).
41
+ /**
42
+ * Controlled width of the column. Does not respect `minWidth` and `maxWidth`.
44
43
  *
45
- * Should be used in conjunction with `width` or `defaultWidth` to set limits when resizing.
44
+ * Should only be used to fully control column width state. Otherwise, use `defaultWidth` and let the component handle resizing.
45
+ *
46
+ * **NB:** Percentage as initial width does not work well with resizing.
46
47
  */
47
- minWidth?: ColumnWidth;
48
+ width?: number | string;
48
49
  /**
49
- * Maximum width of the column.
50
+ * Initial width of the column. Only used when `width` is not set and `resizable` is true.
51
+ * Does not respect `minWidth` and `maxWidth`.
50
52
  *
51
- * Should be used in conjunction with `width` or `defaultWidth` to set limits when resizing.
53
+ * **NB:** Percentage as initial width does not work well with resizing.
54
+ * @default 140px
52
55
  */
53
- maxWidth?: ColumnWidth;
56
+ defaultWidth?: number | string;
54
57
  /**
55
58
  * Called when the column width changes.
59
+ * @param width New width in pixels.
56
60
  */
57
- onWidthChange?: (width: ColumnWidth) => void;
61
+ onWidthChange?: (width: number) => void;
58
62
  /**
59
63
  * Forwarded styles
60
64
  */
@@ -133,10 +137,7 @@ function useTableColumnResize(
133
137
 
134
138
  const setClampedWidth = useCallback(
135
139
  (newWidth: number) => {
136
- const min = parseWidth(minWidth) ?? 0;
137
- const max = parseWidth(maxWidth) ?? Infinity;
138
- const clamped = Math.min(Math.max(newWidth, min), max);
139
- setWidth(clamped);
140
+ setWidth(Math.min(Math.max(newWidth, minWidth), maxWidth));
140
141
  },
141
142
  [minWidth, maxWidth, setWidth],
142
143
  );
@@ -212,14 +213,11 @@ function useTableColumnResize(
212
213
  const currentWidth = thRef.current?.offsetWidth ?? 0;
213
214
  const newWidth = startWidth + (clientX - startX);
214
215
 
215
- const min = parseWidth(minWidth) ?? 0;
216
- const max = parseWidth(maxWidth) ?? Infinity;
217
-
218
- if (newWidth > max) {
216
+ if (newWidth > maxWidth) {
219
217
  setWidth(newWidth < currentWidth ? newWidth : currentWidth);
220
218
  return;
221
219
  }
222
- if (newWidth < min) {
220
+ if (newWidth < minWidth) {
223
221
  setWidth(newWidth > currentWidth ? newWidth : currentWidth);
224
222
  return;
225
223
  }
@@ -315,20 +313,6 @@ function useTableColumnResize(
315
313
  };
316
314
  }
317
315
 
318
- function parseWidth(width: ColumnWidth | undefined): number | undefined {
319
- if (width == null) {
320
- return undefined;
321
- }
322
- if (typeof width === "number") {
323
- return width;
324
- }
325
- if (typeof width === "string") {
326
- const parsed = parseInt(width, 10);
327
- return Number.isNaN(parsed) ? undefined : parsed;
328
- }
329
- return undefined;
330
- }
331
-
332
316
  function getAutoColumnWidth(
333
317
  thRef: React.RefObject<HTMLTableCellElement | null>,
334
318
  ) {
@@ -341,7 +325,9 @@ function getAutoColumnWidth(
341
325
  }
342
326
 
343
327
  // Find needed width for header cell
344
- const contentWidth = thContent.scrollWidth;
328
+ const range = document.createRange();
329
+ range.selectNodeContents(thContent);
330
+ const contentWidth = range.getBoundingClientRect().width;
345
331
  const paddingElStyle = window.getComputedStyle(thPaddingEl);
346
332
  const thInlinePadding =
347
333
  parseInt(paddingElStyle.paddingLeft, 10) +
@@ -357,7 +343,6 @@ function getAutoColumnWidth(
357
343
  }
358
344
 
359
345
  // Find needed width for each cell in column in tbody and tfoot
360
- const range = document.createRange();
361
346
  let skipRows = 0;
362
347
  for (const row of rows) {
363
348
  // Skip rows where the cell in this column is covered by a rowspan from a previous row
@@ -0,0 +1,57 @@
1
+ import React from "react";
2
+ import {
3
+ getDataTableDetailsPanelId,
4
+ useDataTableDetailsPanel,
5
+ } from "../hooks/useTableDetailsPanel";
6
+ import { useDataTableContext } from "../root/DataTableRoot.context";
7
+
8
+ function DataTableDetailsPanelRow<T>({
9
+ rowId,
10
+ rowData,
11
+ }: {
12
+ rowId: string | number;
13
+ rowData: T;
14
+ }) {
15
+ const { tableId, fullWidthColSpan } = useDataTableContext();
16
+ const {
17
+ enableDetailsPanel,
18
+ isExpanded,
19
+ getDetailsPanelContent,
20
+ getDetailsPanelHeight,
21
+ } = useDataTableDetailsPanel();
22
+
23
+ if (!enableDetailsPanel) {
24
+ return null;
25
+ }
26
+
27
+ if (!isExpanded(rowId)) {
28
+ return null;
29
+ }
30
+
31
+ const content = getDetailsPanelContent?.(rowData);
32
+ const expansionId = getDataTableDetailsPanelId(tableId, rowId);
33
+
34
+ if (!content) {
35
+ return null;
36
+ }
37
+
38
+ const panelHeight = getDetailsPanelHeight?.(rowData);
39
+
40
+ const style: React.CSSProperties = panelHeight
41
+ ? { height: panelHeight, overflow: "auto" }
42
+ : { height: "auto" };
43
+
44
+ return (
45
+ <tr className="aksel-data-table__details-panel-row">
46
+ <td
47
+ id={expansionId}
48
+ colSpan={fullWidthColSpan}
49
+ className="aksel-data-table__details-panel-row-cell"
50
+ >
51
+ <div style={style}>{content}</div>
52
+ </td>
53
+ </tr>
54
+ );
55
+ }
56
+
57
+ export { DataTableDetailsPanelRow };
@@ -3,19 +3,21 @@ type TableRowEntryId = string | number;
3
3
  type CollectTableRowEntriesArgs<T> = {
4
4
  items: T[];
5
5
  getRowId?: (rowData: T, index: number) => TableRowEntryId;
6
- getSubRows?: (rowData: T) => T[];
7
- isSubRowExpandable?: (rowData: T) => boolean;
6
+ getRows?: (rowData: T) => T[];
7
+ isRowExpandable?: (rowData: T) => boolean;
8
8
  };
9
9
 
10
10
  interface ItemDetail<T> {
11
- id: string | number;
11
+ id: TableRowEntryId;
12
+ rowData: T;
12
13
  level: number;
13
- parent: null | T;
14
- children: readonly T[];
14
+ parentId: TableRowEntryId | null;
15
+ children: readonly TableRowEntryId[];
15
16
  }
16
17
 
17
18
  type CollectTableRowEntriesReturn<T> = {
18
- itemDetails: Map<T, ItemDetail<T>>;
19
+ itemDetails: Map<TableRowEntryId, ItemDetail<T>>;
20
+ rootRowIds: TableRowEntryId[];
19
21
  /**
20
22
  * Direct child ids for each row, used to traverse nested selection groups
21
23
  * without storing every descendant list on each ancestor.
@@ -26,61 +28,65 @@ type CollectTableRowEntriesReturn<T> = {
26
28
  function collectTableRowEntries<T>({
27
29
  items,
28
30
  getRowId,
29
- getSubRows,
30
- isSubRowExpandable,
31
+ getRows,
32
+ isRowExpandable,
31
33
  }: CollectTableRowEntriesArgs<T>): CollectTableRowEntriesReturn<T> {
32
- const itemDetailsMap = new Map<T, ItemDetail<T>>();
34
+ const itemDetailsMap = new Map<TableRowEntryId, ItemDetail<T>>();
33
35
  const childRowIdsById = new Map<TableRowEntryId, TableRowEntryId[]>();
36
+ const rootRowIds: TableRowEntryId[] = [];
34
37
 
35
38
  const traverseRow = (
36
39
  rowData: T,
37
40
  rowIndex: number,
38
41
  level: number,
39
- parent: T | null,
40
- parentId?: TableRowEntryId,
42
+ parentRowId: TableRowEntryId | null,
41
43
  ): TableRowEntryId => {
42
- const rowId =
43
- getRowId?.(rowData, rowIndex) ??
44
- (parentId == null ? rowIndex : `${parentId}-${rowIndex}`);
45
- const isRowExpandable = isSubRowExpandable?.(rowData) ?? true;
46
- const children = (isRowExpandable ? getSubRows?.(rowData) : []) ?? [];
44
+ const rowId = getRowId
45
+ ? getRowId(rowData, rowIndex)
46
+ : getFallbackTableRowId(rowIndex, parentRowId);
47
47
 
48
- itemDetailsMap.set(rowData, {
49
- id: rowId,
50
- level,
51
- parent,
52
- children,
53
- });
48
+ const children =
49
+ ((isRowExpandable?.(rowData) ?? true) ? getRows?.(rowData) : []) ?? [];
54
50
 
55
51
  const childRowIds: TableRowEntryId[] = [];
56
52
 
57
53
  for (let childIndex = 0; childIndex < children.length; childIndex++) {
58
54
  const childRow = children[childIndex];
59
- const childRowId = traverseRow(
60
- childRow,
61
- childIndex,
62
- level + 1,
63
- rowData,
64
- rowId,
65
- );
55
+ const childRowId = traverseRow(childRow, childIndex, level + 1, rowId);
66
56
  childRowIds.push(childRowId);
67
57
  }
68
58
 
59
+ itemDetailsMap.set(rowId, {
60
+ id: rowId,
61
+ rowData,
62
+ level,
63
+ parentId: parentRowId,
64
+ children: childRowIds,
65
+ });
66
+
69
67
  childRowIdsById.set(rowId, childRowIds);
70
68
 
71
69
  return rowId;
72
70
  };
73
71
 
74
72
  for (let rowIndex = 0; rowIndex < items.length; rowIndex++) {
75
- traverseRow(items[rowIndex], rowIndex, 0, null);
73
+ rootRowIds.push(traverseRow(items[rowIndex], rowIndex, 0, null));
76
74
  }
77
75
 
78
76
  return {
79
77
  itemDetails: itemDetailsMap,
78
+ rootRowIds,
80
79
  childRowIdsById,
81
80
  };
82
81
  }
83
82
 
83
+ function getFallbackTableRowId(
84
+ rowIndex: number,
85
+ parentRowId: TableRowEntryId | null,
86
+ ): string {
87
+ return parentRowId == null ? String(rowIndex) : `${parentRowId}.${rowIndex}`;
88
+ }
89
+
84
90
  export { collectTableRowEntries };
85
91
  export type {
86
92
  CollectTableRowEntriesArgs,
@@ -121,16 +121,70 @@ function prepareCellFocus(cell: Element): HTMLElement | null {
121
121
  /**
122
122
  * Applies focus and scroll to an element.
123
123
  */
124
+ function getStickyOffsets(element: HTMLElement): {
125
+ stickyOffsetStart: number;
126
+ stickyOffsetEnd: number;
127
+ stickyHeaderHeight: number;
128
+ } {
129
+ const table = element.closest(".aksel-data-table");
130
+
131
+ if (!table) {
132
+ return {
133
+ stickyOffsetStart: 0,
134
+ stickyOffsetEnd: 0,
135
+ stickyHeaderHeight: 0,
136
+ };
137
+ }
138
+
139
+ const stickyHeader = table.querySelector<HTMLElement>(
140
+ `.aksel-data-table__tr[data-sticky="true"]`,
141
+ );
142
+
143
+ const stickyNodesStart = table.querySelectorAll<HTMLElement>(
144
+ `.aksel-data-table__column-header[data-sticky="start"]`,
145
+ );
146
+
147
+ const stickyNodesEnd = table.querySelectorAll<HTMLElement>(
148
+ `.aksel-data-table__column-header[data-sticky="end"]`,
149
+ );
150
+
151
+ return {
152
+ stickyOffsetStart: Array.from(stickyNodesStart).reduce(
153
+ (offset, node) => offset + node.getBoundingClientRect().width,
154
+ 0,
155
+ ),
156
+ stickyOffsetEnd: Array.from(stickyNodesEnd).reduce(
157
+ (offset, node) => offset + node.getBoundingClientRect().width,
158
+ 0,
159
+ ),
160
+ stickyHeaderHeight: stickyHeader?.getBoundingClientRect().height ?? 0,
161
+ };
162
+ }
163
+
124
164
  function applyFocusAndScroll(element: HTMLElement): void {
125
- element.focus({
126
- preventScroll: true,
127
- });
128
-
129
- element.scrollIntoView({
130
- behavior: "smooth",
131
- block: "nearest",
132
- inline: "nearest",
133
- });
165
+ const { stickyOffsetStart, stickyOffsetEnd, stickyHeaderHeight } =
166
+ getStickyOffsets(element);
167
+
168
+ const originalScrollMarginInline = element.style.scrollMarginInline;
169
+ const originalScrollMarginBlockStart = element.style.scrollMarginBlockStart;
170
+
171
+ element.style.scrollMarginInline = `${stickyOffsetStart}px ${stickyOffsetEnd}px`;
172
+ element.style.scrollMarginBlockStart = `${stickyHeaderHeight}px`;
173
+
174
+ try {
175
+ element.focus({
176
+ preventScroll: true,
177
+ });
178
+
179
+ element.scrollIntoView({
180
+ behavior: "auto",
181
+ block: "nearest",
182
+ inline: "nearest",
183
+ });
184
+ } finally {
185
+ element.style.scrollMarginBlockStart = originalScrollMarginBlockStart;
186
+ element.style.scrollMarginInline = originalScrollMarginInline;
187
+ }
134
188
  }
135
189
 
136
190
  /**
@@ -45,6 +45,12 @@ const fallbackRows: FallbackTestRow[] = [
45
45
  },
46
46
  ];
47
47
 
48
+ const duplicatedRowObject: TestRow = {
49
+ id: "shared",
50
+ name: "Shared",
51
+ subRows: [{ id: "shared-child", name: "Child" }],
52
+ };
53
+
48
54
  const getSubRows = (row: TestRow) => row.subRows ?? [];
49
55
 
50
56
  const getVisibleIds = (rows: TestRow[]) => rows.map((row) => row.id);
@@ -59,16 +65,18 @@ describe("useTableItems", () => {
59
65
  );
60
66
 
61
67
  expect(getVisibleIds(result.current.items)).toEqual(["a", "b"]);
62
- expect(result.current.itemDetails.get(plainRows[0])).toMatchObject({
68
+ expect(result.current.itemDetails.get("a")).toMatchObject({
63
69
  id: "a",
70
+ rowData: plainRows[0],
64
71
  level: 0,
65
- parent: null,
72
+ parentId: null,
66
73
  children: [],
67
74
  });
68
- expect(result.current.itemDetails.get(plainRows[1])).toMatchObject({
75
+ expect(result.current.itemDetails.get("b")).toMatchObject({
69
76
  id: "b",
77
+ rowData: plainRows[1],
70
78
  level: 0,
71
- parent: null,
79
+ parentId: null,
72
80
  children: [],
73
81
  });
74
82
  });
@@ -78,8 +86,10 @@ describe("useTableItems", () => {
78
86
  useTableItems({
79
87
  items: nestedRows,
80
88
  getRowId: (row) => row.id,
81
- getSubRows,
82
- defaultExpandedSubRowIds: ["a"],
89
+ subRows: {
90
+ getRows: getSubRows,
91
+ defaultExpandedRowIds: ["a"],
92
+ },
83
93
  }),
84
94
  );
85
95
 
@@ -91,7 +101,7 @@ describe("useTableItems", () => {
91
101
  useTableItems({
92
102
  items: nestedRows,
93
103
  getRowId: (row) => row.id,
94
- getSubRows,
104
+ subRows: { getRows: getSubRows },
95
105
  }),
96
106
  );
97
107
 
@@ -100,12 +110,14 @@ describe("useTableItems", () => {
100
110
  expect(result.current.childRowIdsById.get("b")).toEqual(["b1"]);
101
111
  });
102
112
 
103
- test("uses the same fallback root id to reveal child rows when getRowId is omitted", () => {
113
+ test("uses unique fallback ids to reveal child rows when getRowId is omitted", () => {
104
114
  const { result } = renderHook(() =>
105
115
  useTableItems({
106
116
  items: fallbackRows,
107
- getSubRows: (row) => row.subRows ?? [],
108
- defaultExpandedSubRowIds: [0],
117
+ subRows: {
118
+ getRows: (row: any) => row.subRows ?? [],
119
+ defaultExpandedRowIds: ["0"],
120
+ },
109
121
  }),
110
122
  );
111
123
 
@@ -113,6 +125,7 @@ describe("useTableItems", () => {
113
125
  "Parent",
114
126
  "Child",
115
127
  ]);
128
+ expect(result.current.childRowIdsById.get("0")).toEqual(["0.0"]);
116
129
  });
117
130
 
118
131
  test("updates visible rows in depth-first order for controlled expanded ids", () => {
@@ -121,8 +134,10 @@ describe("useTableItems", () => {
121
134
  useTableItems({
122
135
  items: nestedRows,
123
136
  getRowId: (row) => row.id,
124
- getSubRows,
125
- expandedSubRowIds: expandedIds,
137
+ subRows: {
138
+ getRows: getSubRows,
139
+ expandedRowIds: expandedIds,
140
+ },
126
141
  }),
127
142
  {
128
143
  initialProps: { expandedIds: [] as (string | number)[] },
@@ -142,4 +157,35 @@ describe("useTableItems", () => {
142
157
  "b1",
143
158
  ]);
144
159
  });
160
+
161
+ test("tracks duplicated row objects by row id instead of object identity", () => {
162
+ const { result } = renderHook(() =>
163
+ useTableItems({
164
+ items: [duplicatedRowObject, duplicatedRowObject],
165
+ subRows: {
166
+ getRows: getSubRows,
167
+ defaultExpandedRowIds: ["0"],
168
+ },
169
+ }),
170
+ );
171
+
172
+ expect(result.current.visibleRowIds).toEqual(["0", "0.0", "1"]);
173
+ expect(getVisibleIds(result.current.items)).toEqual([
174
+ "shared",
175
+ "shared-child",
176
+ "shared",
177
+ ]);
178
+ expect(result.current.itemDetails.get("0")).toMatchObject({
179
+ id: "0",
180
+ rowData: duplicatedRowObject,
181
+ parentId: null,
182
+ children: ["0.0"],
183
+ });
184
+ expect(result.current.itemDetails.get("1")).toMatchObject({
185
+ id: "1",
186
+ rowData: duplicatedRowObject,
187
+ parentId: null,
188
+ children: ["1.0"],
189
+ });
190
+ });
145
191
  });