@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
@@ -1,4 +1,4 @@
1
- import React, { forwardRef, useRef } from "react";
1
+ import React, { forwardRef, useMemo, useRef } from "react";
2
2
  import {
3
3
  ArrowsUpDownIcon,
4
4
  CaretLeftCircleFillIcon,
@@ -6,40 +6,47 @@ import {
6
6
  SortDownIcon,
7
7
  SortUpIcon,
8
8
  } from "@navikt/aksel-icons";
9
+ import { useDataGridContext } from "../../../data-grid/root/DataGridRoot.context";
9
10
  import { cl } from "../../../utils/helpers";
10
11
  import { useMergeRefs } from "../../../utils/hooks";
11
12
  import {
12
13
  DataTableBaseCell,
13
14
  type DataTableBaseCellProps,
14
15
  } from "../base-cell/DataTableBaseCell";
15
- import type { SortDirection } from "../root/DataTable.types";
16
+ import { useDataTableContext } from "../root/DataTableRoot.context";
16
17
  import { type ResizeProps, useTableColumnResize } from "./useTableColumnResize";
17
18
 
18
- interface DataTableColumnHeaderProps
19
- extends ResizeProps, DataTableBaseCellProps {
19
+ interface DataTableColumnHeaderProps extends DataTableBaseCellProps {
20
+ /**
21
+ * Unique identifier for the column. Used when sorting to identify which column is being sorted.
22
+ */
23
+ id: string;
20
24
  /**
21
25
  * Accessible name of the column.
22
26
  */
23
27
  label: string;
24
28
  /**
25
- * Makes the column header sortable. The entire header cell content becomes
26
- * a clickable button when true.
29
+ * Makes the column sortable by clicking on the header.
30
+ * The entire header cell content becomes a clickable button when true.
27
31
  */
28
32
  sortable?: boolean;
29
33
  /**
30
- * Current sort direction. Only relevant when `sortable` is true.
31
- * Uses values matching the `aria-sort` attribute directly.
32
- * @default "none"
33
- */
34
- sortDirection?: SortDirection;
35
- /**
36
- * Called when the user clicks the sortable header.
37
- * The consumer is responsible for determining and setting the next sort state.
34
+ * Object with props related to column width and resizing. Summary:
35
+ *
36
+ * - `resizable?: boolean` - Whether the column should be resizable by the user.
37
+ * - `autoResizeOnce?: boolean` - Whether the column should automatically resize to fit its content.
38
+ * - `resizeMin?: number` - Minimum width of the column when resizing.
39
+ * - `resizeMax?: number` - Maximum width of the column when resizing.
40
+ * - `value?: number | string` - Controlled width of the column.
41
+ * - `defaultValue?: number | string` - Initial width of the column.
42
+ * - `onChange?: (width: number) => void` - Called when the column width changes.
43
+ *
44
+ * See individual props for details and defaults.
38
45
  */
39
- onSortClick?: (event: React.MouseEvent<HTMLElement>) => void;
46
+ width?: ResizeProps;
40
47
  }
41
48
 
42
- const SORT_ICON: Record<SortDirection, React.ElementType | null> = {
49
+ const SORT_ICON: Record<"asc" | "desc" | "none", React.ElementType> = {
43
50
  asc: SortUpIcon,
44
51
  desc: SortDownIcon,
45
52
  none: ArrowsUpDownIcon,
@@ -56,45 +63,40 @@ const DataTableColumnHeader = forwardRef<
56
63
  >(
57
64
  (
58
65
  {
59
- className,
60
- children,
66
+ id,
61
67
  label,
62
68
  sortable = false,
63
- sortDirection = "none",
64
- onSortClick,
65
- resizable = true,
66
- style,
67
69
  width,
68
- defaultWidth,
69
- autoWidth,
70
- minWidth,
71
- maxWidth,
72
- onWidthChange,
73
- colSpan,
74
- rowSpan,
75
- UNSAFE_isSelection,
70
+ cellType,
71
+ className,
72
+ children,
73
+ style,
76
74
  ...rest
77
75
  },
78
76
  forwardedRef,
79
77
  ) => {
80
- const contentRef = React.useRef<HTMLDivElement>(null);
78
+ const { isLoading } = useDataGridContext();
81
79
  const thRef = useRef<HTMLTableCellElement>(null);
82
80
  const mergedRef = useMergeRefs(forwardedRef, thRef);
81
+ const { sortingState } = useDataTableContext();
82
+ const { onSortClick, sortState } = sortingState;
83
83
 
84
84
  const resizeResult = useTableColumnResize({
85
- resizable,
85
+ ...width,
86
86
  thRef,
87
- width,
88
- defaultWidth,
89
- autoWidth,
90
- minWidth,
91
- maxWidth,
92
- onWidthChange,
93
- style,
94
- colSpan,
87
+ colSpan: rest.colSpan,
95
88
  });
96
89
 
97
- const SortIcon = sortable ? SORT_ICON[sortDirection] : null;
90
+ const sortDirection = useMemo(() => {
91
+ const sortEntry = sortState.find((s) => s.columnId === id);
92
+ return sortEntry?.direction ?? "none";
93
+ }, [id, sortState]);
94
+
95
+ const canSort = sortable && id !== undefined;
96
+
97
+ const SortIcon = canSort ? SORT_ICON[sortDirection] : null;
98
+
99
+ const contentId = `th-content-${id.replace(/\s/g, "-")}`;
98
100
 
99
101
  return (
100
102
  <DataTableBaseCell
@@ -102,20 +104,20 @@ const DataTableColumnHeader = forwardRef<
102
104
  {...rest}
103
105
  ref={mergedRef}
104
106
  className={cl("aksel-data-table__column-header", className)}
105
- data-sortable={sortable}
106
- style={resizeResult.style}
107
- aria-sort={sortable ? getAriaSort(sortDirection) : undefined}
108
- UNSAFE_isSelection={UNSAFE_isSelection}
109
- colSpan={colSpan}
110
- rowSpan={rowSpan}
107
+ data-sortable={canSort}
108
+ style={{ ...style, width: resizeResult.width }}
109
+ aria-sort={canSort ? getAriaSort(sortDirection) : undefined}
110
+ cellType={cellType}
111
+ aria-labelledby={contentId} // Avoids VO announcing "Endre bredde" when navigating horizontally in tbody
111
112
  >
112
- {sortable ? (
113
+ {canSort ? (
113
114
  <button
114
115
  type="button"
115
116
  className="aksel-data-table__th-sort-button"
116
- onClick={onSortClick}
117
+ onClick={(event) => onSortClick(id, event)}
118
+ disabled={isLoading}
117
119
  >
118
- <div ref={contentRef} className="aksel-data-table__th-content">
120
+ <div id={contentId} className="aksel-data-table__th-content">
119
121
  {children}
120
122
  </div>
121
123
  {SortIcon && (
@@ -129,16 +131,16 @@ const DataTableColumnHeader = forwardRef<
129
131
  </button>
130
132
  ) : (
131
133
  <div
132
- ref={contentRef}
134
+ id={contentId}
133
135
  className={cl({
134
- "aksel-data-table__th-content": !UNSAFE_isSelection,
136
+ "aksel-data-table__th-content": cellType !== "action",
135
137
  })}
136
138
  >
137
139
  {children}
138
140
  </div>
139
141
  )}
140
142
 
141
- {resizeResult.enabled && !UNSAFE_isSelection && (
143
+ {resizeResult.enabled && cellType !== "action" && (
142
144
  <button
143
145
  {...resizeResult.resizeHandlerProps}
144
146
  type="button"
@@ -153,23 +155,21 @@ const DataTableColumnHeader = forwardRef<
153
155
  data-block-keyboard-nav
154
156
  role="slider"
155
157
  aria-valuenow={
156
- typeof resizeResult.style.width === "number"
157
- ? resizeResult.style.width
158
- : 0
158
+ typeof resizeResult.width === "number" ? resizeResult.width : 0
159
159
  }
160
160
  aria-valuetext={
161
- typeof resizeResult.style.width === "number" &&
161
+ typeof resizeResult.width === "number" &&
162
162
  resizeResult.isResizingWithKeyboard
163
- ? resizeResult.style.width.toString()
164
- : "" // Needs to be blank when not in keyboard resizing mode to avoid NVDA announcing the value as part of the column heading
163
+ ? resizeResult.width.toString()
164
+ : " " // Needs to be blank when not in keyboard resizing mode to avoid NVDA announcing the value as part of the column heading
165
165
  } // Need either this or aria-valuemax to get SR (at least NVDA) to announce the value
166
166
  >
167
167
  {resizeResult.isResizingWithKeyboard && (
168
168
  <>
169
- <span className="aksel-data-table__th-resize-handle-indicator aksel-data-table__th-resize-handle-indicator--start">
169
+ <span className="aksel-data-table__th-resize-handle-indicator">
170
170
  <CaretLeftCircleFillIcon aria-hidden fontSize="1.5rem" />
171
171
  </span>
172
- <span className="aksel-data-table__th-resize-handle-indicator aksel-data-table__th-resize-handle-indicator--end">
172
+ <span className="aksel-data-table__th-resize-handle-indicator">
173
173
  <CaretRightCircleFillIcon aria-hidden fontSize="1.5rem" />
174
174
  </span>
175
175
  </>
@@ -182,7 +182,7 @@ const DataTableColumnHeader = forwardRef<
182
182
  );
183
183
 
184
184
  function getAriaSort(
185
- sortDirection: SortDirection | undefined,
185
+ sortDirection: "asc" | "desc" | "none" | undefined,
186
186
  ): "ascending" | "descending" | "none" | undefined {
187
187
  if (sortDirection === "asc") return "ascending";
188
188
  if (sortDirection === "desc") return "descending";
@@ -26,61 +26,51 @@ type ResizeProps = {
26
26
  * consider using `layout="auto"` on the root instead for better performance.
27
27
  *
28
28
  * **NB:** This can cause a layout shift. Set a good initial width with `width` or `defaultWidth` to mitigate this.
29
+ *
30
+ * **NB:** Does not work with block content.
29
31
  */
30
- autoWidth?: boolean;
32
+ autoResizeOnce?: boolean;
31
33
  /**
32
- * Minimum width of the column when resizing. Only used when `resizable` or `autoWidth` is enabled.
34
+ * Minimum width of the column when resizing. Only used when `resizable` or `autoResizeOnce` is enabled.
33
35
  * @default 40
34
36
  */
35
- minWidth?: number;
37
+ resizeMin?: number;
36
38
  /**
37
- * Maximum width of the column when resizing. Only used when `resizable` or `autoWidth` is enabled.
39
+ * Maximum width of the column when resizing. Only used when `resizable` or `autoResizeOnce` is enabled.
38
40
  */
39
- maxWidth?: number;
41
+ resizeMax?: number;
40
42
  // TODO: Consider "allowing" %-width on last column, if we find a solution to the overflow issue (width becomes 0px).
41
43
  /**
42
- * Controlled width of the column. Does not respect `minWidth` and `maxWidth`.
44
+ * Controlled width of the column. (Does not respect `resizeMin` and `resizeMax`.)
43
45
  *
44
- * Should only be used to fully control column width state. Otherwise, use `defaultWidth` and let the component handle resizing.
46
+ * Should only be used to fully control column width state. Otherwise, use `default` and let the component handle resizing.
45
47
  *
46
48
  * **NB:** Percentage as initial width does not work well with resizing.
47
49
  */
48
- width?: number | string;
50
+ value?: number | string;
49
51
  /**
50
- * Initial width of the column. Only used when `width` is not set and `resizable` is true.
51
- * Does not respect `minWidth` and `maxWidth`.
52
+ * Initial width of the column. Only used when `value` is not set.
53
+ * (Does not respect `resizeMin` and `resizeMax`.)
52
54
  *
53
55
  * **NB:** Percentage as initial width does not work well with resizing.
54
56
  * @default 140px
55
57
  */
56
- defaultWidth?: number | string;
58
+ defaultValue?: number | string;
57
59
  /**
58
60
  * Called when the column width changes.
59
61
  * @param width New width in pixels.
60
62
  */
61
- onWidthChange?: (width: number) => void;
62
- /**
63
- * Forwarded styles
64
- */
65
- style?: React.CSSProperties;
66
- /**
67
- * Forwarded colSpan
68
- */
69
- colSpan?: number;
63
+ onChange?: (width: number) => void;
70
64
  };
71
65
 
72
- type WithUndefined<T> = {
73
- [K in keyof T]: T[K] | undefined;
74
- };
75
- type Unomittable<T> = WithUndefined<Required<T>>;
76
-
77
- type TableColumnResizeArgs = Unomittable<ResizeProps> & {
66
+ type TableColumnResizeArgs = ResizeProps & {
78
67
  thRef: React.RefObject<HTMLTableCellElement | null>;
68
+ colSpan: number | undefined;
79
69
  };
80
70
 
81
71
  type TableColumnResizeResult =
82
72
  | {
83
- style: React.CSSProperties;
73
+ width: number | string;
84
74
  resizeHandlerProps: {
85
75
  onMouseDown: DOMAttributes<HTMLButtonElement>["onMouseDown"];
86
76
  onTouchStart: DOMAttributes<HTMLButtonElement>["onTouchStart"];
@@ -93,59 +83,53 @@ type TableColumnResizeResult =
93
83
  enabled: true;
94
84
  }
95
85
  | {
96
- style?: React.CSSProperties;
86
+ width?: number | string;
97
87
  enabled: false;
98
88
  };
99
89
 
100
90
  /**
101
91
  * TODO:
102
- * - Do we allow % widths?
103
92
  * - Auto-width mode is hard now since that might cause layout-shifts on mount. But would be preferable to
104
93
  * be able to set "1fr" or similar and have it fill remaining space.
105
94
  */
106
- function useTableColumnResize(
107
- args: TableColumnResizeArgs,
108
- ): TableColumnResizeResult {
109
- const {
110
- resizable,
111
- thRef,
112
- width: userWidth,
113
- defaultWidth,
114
- autoWidth,
115
- onWidthChange,
116
- maxWidth = Infinity,
117
- minWidth = 40,
118
- style,
119
- colSpan,
120
- } = args;
121
-
95
+ function useTableColumnResize({
96
+ resizable = true,
97
+ autoResizeOnce,
98
+ resizeMin = 40,
99
+ resizeMax = Infinity,
100
+ value,
101
+ defaultValue,
102
+ onChange,
103
+ thRef,
104
+ colSpan,
105
+ }: TableColumnResizeArgs): TableColumnResizeResult {
122
106
  const tableContext = useDataTableContext();
123
107
 
124
108
  const [isResizingWithKeyboard, setIsResizingWithKeyboard] = useState(false);
125
109
  const ignoreNextOnClick = useRef(false);
126
110
 
127
111
  const [width, setWidth] = useControllableState({
128
- value: userWidth,
129
- defaultValue: defaultWidth ?? (colSpan ?? 1) * 140,
112
+ value,
113
+ defaultValue: defaultValue ?? (colSpan ?? 1) * 140,
130
114
  /**
131
115
  * TODO:
132
116
  * - Potential optimization: Only call when width as "stopped" changing, e.g. on mouse up or after a debounce when resizing with keyboard.
133
117
  * Otherwise, this could cause excessive calls when resizing quickly.
134
118
  */
135
- onChange: onWidthChange,
119
+ onChange,
136
120
  });
137
121
 
138
122
  const setClampedWidth = useCallback(
139
123
  (newWidth: number) => {
140
- setWidth(Math.min(Math.max(newWidth, minWidth), maxWidth));
124
+ setWidth(Math.min(Math.max(newWidth, resizeMin), resizeMax));
141
125
  },
142
- [minWidth, maxWidth, setWidth],
126
+ [resizeMin, resizeMax, setWidth],
143
127
  );
144
128
 
145
- // biome-ignore lint/correctness/useExhaustiveDependencies: We only want to run this on mount and when autoWidth changes
129
+ // biome-ignore lint/correctness/useExhaustiveDependencies: We only want to run this on mount and when autoResizeOnce changes
146
130
  useEffect(
147
131
  function autoResizeColumn() {
148
- if (!autoWidth) {
132
+ if (!autoResizeOnce) {
149
133
  return;
150
134
  }
151
135
 
@@ -154,20 +138,19 @@ function useTableColumnResize(
154
138
  setClampedWidth(newColumnWidth);
155
139
  }
156
140
  },
157
- [autoWidth], // eslint-disable-line react-hooks/exhaustive-deps
141
+ [autoResizeOnce], // eslint-disable-line react-hooks/exhaustive-deps
158
142
  );
159
143
 
160
144
  const handleOnClick: DOMAttributes<HTMLButtonElement>["onClick"] =
161
145
  useCallback(() => {
162
146
  // We need to use the onClick event in order to support screen readers properly,
163
- // since some of them only send a mouse click when pressing enter/space.
147
+ // since some of them only send a mouse click (no kbd events) when pressing enter/space.
164
148
  // We detect a "screen reader click" by checking if we had a mouseUp event right before.
165
149
 
166
150
  if (ignoreNextOnClick.current) {
167
151
  ignoreNextOnClick.current = false;
168
152
  return;
169
153
  }
170
-
171
154
  setIsResizingWithKeyboard((prev) => !prev);
172
155
  }, []);
173
156
 
@@ -213,11 +196,11 @@ function useTableColumnResize(
213
196
  const currentWidth = thRef.current?.offsetWidth ?? 0;
214
197
  const newWidth = startWidth + (clientX - startX);
215
198
 
216
- if (newWidth > maxWidth) {
199
+ if (newWidth > resizeMax) {
217
200
  setWidth(newWidth < currentWidth ? newWidth : currentWidth);
218
201
  return;
219
202
  }
220
- if (newWidth < minWidth) {
203
+ if (newWidth < resizeMin) {
221
204
  setWidth(newWidth > currentWidth ? newWidth : currentWidth);
222
205
  return;
223
206
  }
@@ -250,7 +233,7 @@ function useTableColumnResize(
250
233
  document.addEventListener("touchend", cleanup, { once: true });
251
234
  document.addEventListener("touchcancel", cleanup, { once: true });
252
235
  },
253
- [maxWidth, minWidth, setWidth, setClampedWidth, thRef],
236
+ [resizeMax, resizeMin, setWidth, setClampedWidth, thRef],
254
237
  );
255
238
 
256
239
  const handleMouseDown: DOMAttributes<HTMLButtonElement>["onMouseDown"] =
@@ -269,7 +252,7 @@ function useTableColumnResize(
269
252
  [startResize],
270
253
  );
271
254
 
272
- // Auto-size column to fit content on double click. NB: Doesn't work with block content!
255
+ // Auto-size column to fit content on double click
273
256
  const handleDoubleClick: DOMAttributes<HTMLButtonElement>["onDoubleClick"] =
274
257
  useCallback(() => {
275
258
  const newColumnWidth = getAutoColumnWidth(thRef);
@@ -280,26 +263,20 @@ function useTableColumnResize(
280
263
 
281
264
  if (tableContext.layout !== "fixed") {
282
265
  return {
283
- style,
284
266
  enabled: false,
285
267
  };
286
268
  }
287
269
 
288
270
  if (!resizable) {
289
271
  return {
290
- style: {
291
- ...style,
292
- width,
293
- },
272
+ width,
273
+
294
274
  enabled: false,
295
275
  };
296
276
  }
297
277
 
298
278
  return {
299
- style: {
300
- ...style,
301
- width,
302
- },
279
+ width,
303
280
  resizeHandlerProps: {
304
281
  onMouseDown: handleMouseDown,
305
282
  onTouchStart: handleTouchStart,
@@ -313,12 +290,16 @@ function useTableColumnResize(
313
290
  };
314
291
  }
315
292
 
293
+ /**
294
+ * Figures out how wide the column needs to be to fit all the content without truncation.
295
+ * NB: Does not work with block content!
296
+ */
316
297
  function getAutoColumnWidth(
317
298
  thRef: React.RefObject<HTMLTableCellElement | null>,
318
299
  ) {
319
300
  const th = thRef.current!;
320
301
  const thContent = th.querySelector(".aksel-data-table__th-content");
321
- const thPaddingEl = th.querySelector("div");
302
+ const thPaddingEl = th.querySelector(".aksel-data-table__cell-content");
322
303
  const rows = th.closest("table")?.querySelectorAll("tbody tr, tfoot tr");
323
304
  if (!thContent || !thPaddingEl || !rows) {
324
305
  return;
@@ -361,17 +342,20 @@ function getAutoColumnWidth(
361
342
  skipRows = cell.rowSpan - 1;
362
343
 
363
344
  // Find needed width
364
- const cellContent = cell.firstChild as HTMLElement;
365
- range.selectNodeContents(cellContent);
366
- const cellContentWidth = range.getBoundingClientRect().width;
367
- const contentElStyle = window.getComputedStyle(cellContent);
368
- const inlinePadding =
369
- parseInt(contentElStyle.paddingLeft, 10) +
370
- parseInt(contentElStyle.paddingRight, 10);
371
- const widthNeededForThisCell =
372
- (cellContentWidth + inlinePadding) / cell.colSpan;
345
+ const cellContent = cell.querySelector(
346
+ ".aksel-data-table__cell-content",
347
+ ) as HTMLElement | null;
348
+
349
+ if (!cellContent) {
350
+ continue;
351
+ }
352
+
353
+ cellContent.style.width = "fit-content";
354
+ const cellContentWidth = cellContent.scrollWidth;
355
+ cellContent.style.removeProperty("width");
356
+ const widthNeededForThisCell = (cellContentWidth + 1) / cell.colSpan;
373
357
  if (widthNeededForThisCell > newColumnWidth) {
374
- newColumnWidth = widthNeededForThisCell;
358
+ newColumnWidth = Math.ceil(widthNeededForThisCell);
375
359
  }
376
360
  }
377
361
 
@@ -9,10 +9,10 @@ function DataTableDetailsPanelRow<T>({
9
9
  rowId,
10
10
  rowData,
11
11
  }: {
12
- rowId: string | number;
12
+ rowId: string;
13
13
  rowData: T;
14
14
  }) {
15
- const { tableId, fullWidthColSpan } = useDataTableContext();
15
+ const { tableId, totalColSpan } = useDataTableContext();
16
16
  const {
17
17
  enableDetailsPanel,
18
18
  isExpanded,
@@ -45,7 +45,7 @@ function DataTableDetailsPanelRow<T>({
45
45
  <tr className="aksel-data-table__details-panel-row">
46
46
  <td
47
47
  id={expansionId}
48
- colSpan={fullWidthColSpan}
48
+ colSpan={totalColSpan}
49
49
  className="aksel-data-table__details-panel-row-cell"
50
50
  >
51
51
  <div style={style}>{content}</div>
@@ -1,4 +1,4 @@
1
- type TableRowEntryId = string | number;
1
+ import type { TableRowEntryId } from "../root/DataGridTable.types";
2
2
 
3
3
  type CollectTableRowEntriesArgs<T> = {
4
4
  items: T[];
@@ -91,6 +91,5 @@ export { collectTableRowEntries };
91
91
  export type {
92
92
  CollectTableRowEntriesArgs,
93
93
  CollectTableRowEntriesReturn,
94
- TableRowEntryId,
95
94
  ItemDetail,
96
95
  };