@navikt/ds-react 8.10.5 → 8.10.6

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 (223) hide show
  1. package/cjs/data/data-grid/index.d.ts +2 -0
  2. package/cjs/data/data-grid/index.js +7 -0
  3. package/cjs/data/data-grid/index.js.map +1 -0
  4. package/cjs/data/data-grid/root/DataGridRoot.context.d.ts +11 -0
  5. package/cjs/data/data-grid/root/DataGridRoot.context.js +11 -0
  6. package/cjs/data/data-grid/root/DataGridRoot.context.js.map +1 -0
  7. package/cjs/data/data-grid/root/DataGridRoot.d.ts +38 -0
  8. package/cjs/data/data-grid/root/DataGridRoot.js +68 -0
  9. package/cjs/data/data-grid/root/DataGridRoot.js.map +1 -0
  10. package/cjs/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js +0 -1
  11. package/cjs/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js.map +1 -1
  12. package/cjs/data/drag-and-drop/root/DragAndDropRoot.d.ts +5 -5
  13. package/cjs/data/drag-and-drop/root/DragAndDropRoot.js +4 -27
  14. package/cjs/data/drag-and-drop/root/DragAndDropRoot.js.map +1 -1
  15. package/cjs/data/stories/Data.test-data.d.ts +2 -5
  16. package/cjs/data/stories/Data.test-data.js +30 -38
  17. package/cjs/data/stories/Data.test-data.js.map +1 -1
  18. package/cjs/data/table/base-cell/DataTableBaseCell.d.ts +15 -15
  19. package/cjs/data/table/base-cell/DataTableBaseCell.js +4 -8
  20. package/cjs/data/table/base-cell/DataTableBaseCell.js.map +1 -1
  21. package/cjs/data/table/column-header/DataTableColumnHeader.d.ts +24 -6
  22. package/cjs/data/table/column-header/DataTableColumnHeader.js +22 -27
  23. package/cjs/data/table/column-header/DataTableColumnHeader.js.map +1 -1
  24. package/cjs/data/table/column-header/useTableColumnResize.d.ts +19 -29
  25. package/cjs/data/table/column-header/useTableColumnResize.js +24 -22
  26. package/cjs/data/table/column-header/useTableColumnResize.js.map +1 -1
  27. package/cjs/data/table/details-panel-row/DataTableDetailsPanelRow.d.ts +1 -1
  28. package/cjs/data/table/details-panel-row/DataTableDetailsPanelRow.js +2 -2
  29. package/cjs/data/table/details-panel-row/DataTableDetailsPanelRow.js.map +1 -1
  30. package/cjs/data/table/helpers/collectTableRowEntries.d.ts +2 -2
  31. package/cjs/data/table/helpers/selection/getMultipleSelectProps.d.ts +13 -11
  32. package/cjs/data/table/helpers/selection/getMultipleSelectProps.js +43 -53
  33. package/cjs/data/table/helpers/selection/getMultipleSelectProps.js.map +1 -1
  34. package/cjs/data/table/helpers/selection/getSingleSelectProps.d.ts +9 -8
  35. package/cjs/data/table/helpers/selection/getSingleSelectProps.js +23 -10
  36. package/cjs/data/table/helpers/selection/getSingleSelectProps.js.map +1 -1
  37. package/cjs/data/table/helpers/selection/selection.types.d.ts +19 -19
  38. package/cjs/data/table/helpers/selection/selection.utils.d.ts +21 -0
  39. package/cjs/data/table/helpers/selection/selection.utils.js +46 -0
  40. package/cjs/data/table/helpers/selection/selection.utils.js.map +1 -0
  41. package/cjs/data/table/hooks/useColumnOptions.d.ts +16 -5
  42. package/cjs/data/table/hooks/useColumnOptions.js +26 -8
  43. package/cjs/data/table/hooks/useColumnOptions.js.map +1 -1
  44. package/cjs/data/table/hooks/useTableDetailsPanel.d.ts +10 -13
  45. package/cjs/data/table/hooks/useTableDetailsPanel.js +6 -5
  46. package/cjs/data/table/hooks/useTableDetailsPanel.js.map +1 -1
  47. package/cjs/data/table/hooks/useTableItems.d.ts +29 -15
  48. package/cjs/data/table/hooks/useTableItems.js +2 -12
  49. package/cjs/data/table/hooks/useTableItems.js.map +1 -1
  50. package/cjs/data/table/hooks/useTableKeyboardNav.d.ts +1 -6
  51. package/cjs/data/table/hooks/useTableKeyboardNav.js +1 -4
  52. package/cjs/data/table/hooks/useTableKeyboardNav.js.map +1 -1
  53. package/cjs/data/table/hooks/useTableSelection.d.ts +6 -6
  54. package/cjs/data/table/hooks/useTableSelection.js +13 -13
  55. package/cjs/data/table/hooks/useTableSelection.js.map +1 -1
  56. package/cjs/data/table/hooks/useTableSort.d.ts +2 -2
  57. package/cjs/data/table/hooks/useTableSort.js +4 -5
  58. package/cjs/data/table/hooks/useTableSort.js.map +1 -1
  59. package/cjs/data/table/root/DataTable.types.d.ts +22 -10
  60. package/cjs/data/table/root/DataTableRoot.context.d.ts +13 -7
  61. package/cjs/data/table/root/DataTableRoot.context.js.map +1 -1
  62. package/cjs/data/table/root/DataTableRoot.d.ts +49 -72
  63. package/cjs/data/table/root/DataTableRoot.js +54 -66
  64. package/cjs/data/table/root/DataTableRoot.js.map +1 -1
  65. package/cjs/data/table/root/DataTableRoot.legacy.d.ts +2 -7
  66. package/cjs/data/table/root/DataTableRoot.legacy.js +17 -3
  67. package/cjs/data/table/root/DataTableRoot.legacy.js.map +1 -1
  68. package/cjs/data/table/sub-row-toggle/DataTableSubRowToggle.js +4 -4
  69. package/cjs/data/table/sub-row-toggle/DataTableSubRowToggle.js.map +1 -1
  70. package/cjs/data/table/tbody/DataTableTbody.js +4 -2
  71. package/cjs/data/table/tbody/DataTableTbody.js.map +1 -1
  72. package/cjs/data/table/tr/DataTableTr.d.ts +5 -3
  73. package/cjs/data/table/tr/DataTableTr.js +36 -23
  74. package/cjs/data/table/tr/DataTableTr.js.map +1 -1
  75. package/cjs/table/ColumnHeader.js +2 -1
  76. package/cjs/table/ColumnHeader.js.map +1 -1
  77. package/esm/data/data-grid/index.d.ts +2 -0
  78. package/esm/data/data-grid/index.js +3 -0
  79. package/esm/data/data-grid/index.js.map +1 -0
  80. package/esm/data/data-grid/root/DataGridRoot.context.d.ts +11 -0
  81. package/esm/data/data-grid/root/DataGridRoot.context.js +7 -0
  82. package/esm/data/data-grid/root/DataGridRoot.context.js.map +1 -0
  83. package/esm/data/data-grid/root/DataGridRoot.d.ts +38 -0
  84. package/esm/data/data-grid/root/DataGridRoot.js +32 -0
  85. package/esm/data/data-grid/root/DataGridRoot.js.map +1 -0
  86. package/esm/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js +0 -1
  87. package/esm/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js.map +1 -1
  88. package/esm/data/drag-and-drop/root/DragAndDropRoot.d.ts +5 -5
  89. package/esm/data/drag-and-drop/root/DragAndDropRoot.js +4 -27
  90. package/esm/data/drag-and-drop/root/DragAndDropRoot.js.map +1 -1
  91. package/esm/data/stories/Data.test-data.d.ts +2 -5
  92. package/esm/data/stories/Data.test-data.js +30 -38
  93. package/esm/data/stories/Data.test-data.js.map +1 -1
  94. package/esm/data/table/base-cell/DataTableBaseCell.d.ts +15 -15
  95. package/esm/data/table/base-cell/DataTableBaseCell.js +4 -8
  96. package/esm/data/table/base-cell/DataTableBaseCell.js.map +1 -1
  97. package/esm/data/table/column-header/DataTableColumnHeader.d.ts +24 -6
  98. package/esm/data/table/column-header/DataTableColumnHeader.js +23 -28
  99. package/esm/data/table/column-header/DataTableColumnHeader.js.map +1 -1
  100. package/esm/data/table/column-header/useTableColumnResize.d.ts +19 -29
  101. package/esm/data/table/column-header/useTableColumnResize.js +24 -22
  102. package/esm/data/table/column-header/useTableColumnResize.js.map +1 -1
  103. package/esm/data/table/details-panel-row/DataTableDetailsPanelRow.d.ts +1 -1
  104. package/esm/data/table/details-panel-row/DataTableDetailsPanelRow.js +2 -2
  105. package/esm/data/table/details-panel-row/DataTableDetailsPanelRow.js.map +1 -1
  106. package/esm/data/table/helpers/collectTableRowEntries.d.ts +2 -2
  107. package/esm/data/table/helpers/selection/getMultipleSelectProps.d.ts +13 -11
  108. package/esm/data/table/helpers/selection/getMultipleSelectProps.js +43 -53
  109. package/esm/data/table/helpers/selection/getMultipleSelectProps.js.map +1 -1
  110. package/esm/data/table/helpers/selection/getSingleSelectProps.d.ts +9 -8
  111. package/esm/data/table/helpers/selection/getSingleSelectProps.js +23 -10
  112. package/esm/data/table/helpers/selection/getSingleSelectProps.js.map +1 -1
  113. package/esm/data/table/helpers/selection/selection.types.d.ts +19 -19
  114. package/esm/data/table/helpers/selection/selection.utils.d.ts +21 -0
  115. package/esm/data/table/helpers/selection/selection.utils.js +43 -0
  116. package/esm/data/table/helpers/selection/selection.utils.js.map +1 -0
  117. package/esm/data/table/hooks/useColumnOptions.d.ts +16 -5
  118. package/esm/data/table/hooks/useColumnOptions.js +26 -8
  119. package/esm/data/table/hooks/useColumnOptions.js.map +1 -1
  120. package/esm/data/table/hooks/useTableDetailsPanel.d.ts +10 -13
  121. package/esm/data/table/hooks/useTableDetailsPanel.js +6 -5
  122. package/esm/data/table/hooks/useTableDetailsPanel.js.map +1 -1
  123. package/esm/data/table/hooks/useTableItems.d.ts +29 -15
  124. package/esm/data/table/hooks/useTableItems.js +3 -10
  125. package/esm/data/table/hooks/useTableItems.js.map +1 -1
  126. package/esm/data/table/hooks/useTableKeyboardNav.d.ts +1 -6
  127. package/esm/data/table/hooks/useTableKeyboardNav.js +1 -4
  128. package/esm/data/table/hooks/useTableKeyboardNav.js.map +1 -1
  129. package/esm/data/table/hooks/useTableSelection.d.ts +6 -6
  130. package/esm/data/table/hooks/useTableSelection.js +13 -13
  131. package/esm/data/table/hooks/useTableSelection.js.map +1 -1
  132. package/esm/data/table/hooks/useTableSort.d.ts +2 -2
  133. package/esm/data/table/hooks/useTableSort.js +4 -5
  134. package/esm/data/table/hooks/useTableSort.js.map +1 -1
  135. package/esm/data/table/root/DataTable.types.d.ts +22 -10
  136. package/esm/data/table/root/DataTableRoot.context.d.ts +13 -7
  137. package/esm/data/table/root/DataTableRoot.context.js.map +1 -1
  138. package/esm/data/table/root/DataTableRoot.d.ts +49 -72
  139. package/esm/data/table/root/DataTableRoot.js +56 -68
  140. package/esm/data/table/root/DataTableRoot.js.map +1 -1
  141. package/esm/data/table/root/DataTableRoot.legacy.d.ts +2 -7
  142. package/esm/data/table/root/DataTableRoot.legacy.js +17 -3
  143. package/esm/data/table/root/DataTableRoot.legacy.js.map +1 -1
  144. package/esm/data/table/sub-row-toggle/DataTableSubRowToggle.js +4 -4
  145. package/esm/data/table/sub-row-toggle/DataTableSubRowToggle.js.map +1 -1
  146. package/esm/data/table/tbody/DataTableTbody.js +4 -2
  147. package/esm/data/table/tbody/DataTableTbody.js.map +1 -1
  148. package/esm/data/table/tr/DataTableTr.d.ts +5 -3
  149. package/esm/data/table/tr/DataTableTr.js +35 -23
  150. package/esm/data/table/tr/DataTableTr.js.map +1 -1
  151. package/esm/table/ColumnHeader.js +2 -1
  152. package/esm/table/ColumnHeader.js.map +1 -1
  153. package/package.json +3 -3
  154. package/src/data/data-grid/index.ts +3 -0
  155. package/src/data/data-grid/root/DataGridRoot.context.ts +16 -0
  156. package/src/data/data-grid/root/DataGridRoot.tsx +71 -0
  157. package/src/data/drag-and-drop/drag-handler/DragAndDropDragHandler.tsx +0 -1
  158. package/src/data/drag-and-drop/root/DragAndDropRoot.tsx +15 -49
  159. package/src/data/stories/Data.test-data.tsx +52 -43
  160. package/src/data/table/agent-component-review.md +175 -0
  161. package/src/data/table/base-cell/DataTableBaseCell.tsx +31 -21
  162. package/src/data/table/column-header/DataTableColumnHeader.tsx +61 -58
  163. package/src/data/table/column-header/useTableColumnResize.ts +55 -71
  164. package/src/data/table/details-panel-row/DataTableDetailsPanelRow.tsx +3 -3
  165. package/src/data/table/helpers/collectTableRowEntries.ts +1 -2
  166. package/src/data/table/helpers/selection/getMultipleSelectProps.ts +65 -85
  167. package/src/data/table/helpers/selection/getSingleSelectProps.ts +35 -17
  168. package/src/data/table/helpers/selection/selection.types.ts +19 -19
  169. package/src/data/table/helpers/selection/selection.utils.test.ts +161 -0
  170. package/src/data/table/helpers/selection/selection.utils.ts +73 -0
  171. package/src/data/table/hooks/__tests__/useTableItems.test.ts +2 -1
  172. package/src/data/table/hooks/useColumnOptions.ts +48 -14
  173. package/src/data/table/hooks/useTableDetailsPanel.tsx +22 -25
  174. package/src/data/table/hooks/useTableItems.ts +32 -24
  175. package/src/data/table/hooks/useTableKeyboardNav.ts +1 -13
  176. package/src/data/table/hooks/useTableSelection.ts +26 -31
  177. package/src/data/table/hooks/useTableSort.ts +10 -9
  178. package/src/data/table/root/DataTable.types.ts +30 -22
  179. package/src/data/table/root/DataTableRoot.context.ts +19 -7
  180. package/src/data/table/root/DataTableRoot.legacy.tsx +22 -14
  181. package/src/data/table/root/DataTableRoot.tsx +244 -293
  182. package/src/data/table/sub-row-toggle/DataTableSubRowToggle.tsx +5 -4
  183. package/src/data/table/tbody/DataTableTbody.tsx +6 -2
  184. package/src/data/table/tr/DataTableTr.tsx +98 -35
  185. package/src/table/ColumnHeader.tsx +2 -1
  186. package/cjs/data/drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.d.ts +0 -22
  187. package/cjs/data/drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.js +0 -35
  188. package/cjs/data/drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.js.map +0 -1
  189. package/cjs/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.d.ts +0 -27
  190. package/cjs/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.js +0 -86
  191. package/cjs/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.js.map +0 -1
  192. package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.d.ts +0 -5
  193. package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.js +0 -6
  194. package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.js.map +0 -1
  195. package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.d.ts +0 -24
  196. package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.js +0 -108
  197. package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.js.map +0 -1
  198. package/cjs/data/table/helpers/selection/SelectionSubtreeHelper.d.ts +0 -46
  199. package/cjs/data/table/helpers/selection/SelectionSubtreeHelper.js +0 -112
  200. package/cjs/data/table/helpers/selection/SelectionSubtreeHelper.js.map +0 -1
  201. package/esm/data/drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.d.ts +0 -22
  202. package/esm/data/drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.js +0 -29
  203. package/esm/data/drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.js.map +0 -1
  204. package/esm/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.d.ts +0 -27
  205. package/esm/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.js +0 -50
  206. package/esm/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.js.map +0 -1
  207. package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.d.ts +0 -5
  208. package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.js +0 -3
  209. package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.js.map +0 -1
  210. package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.d.ts +0 -24
  211. package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.js +0 -68
  212. package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.js.map +0 -1
  213. package/esm/data/table/helpers/selection/SelectionSubtreeHelper.d.ts +0 -46
  214. package/esm/data/table/helpers/selection/SelectionSubtreeHelper.js +0 -109
  215. package/esm/data/table/helpers/selection/SelectionSubtreeHelper.js.map +0 -1
  216. package/src/data/drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.tsx +0 -104
  217. package/src/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.tsx +0 -74
  218. package/src/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.tsx +0 -11
  219. package/src/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.tsx +0 -94
  220. package/src/data/table/helpers/selection/SelectionSubtreeHelper.test.ts +0 -66
  221. package/src/data/table/helpers/selection/SelectionSubtreeHelper.ts +0 -162
  222. package/src/data/table/hooks/__tests__/useTableSelection.test.ts +0 -488
  223. package/src/data/table/root/agent-feature-gap.md +0 -96
@@ -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
+ default?: 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;
70
- };
71
-
72
- type WithUndefined<T> = {
73
- [K in keyof T]: T[K] | undefined;
63
+ onChange?: (width: number) => void;
74
64
  };
75
- type Unomittable<T> = WithUndefined<Required<T>>;
76
65
 
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
+ default: defaultProp,
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: defaultProp ?? (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,15 +342,18 @@ function getAutoColumnWidth(
361
342
  skipRows = cell.rowSpan - 1;
362
343
 
363
344
  // Find needed width
364
- const cellContent = cell.firstChild as HTMLElement;
345
+ const cellContent = cell.querySelector(
346
+ ".aksel-data-table__cell-content",
347
+ ) as HTMLElement;
365
348
  range.selectNodeContents(cellContent);
366
349
  const cellContentWidth = range.getBoundingClientRect().width;
367
350
  const contentElStyle = window.getComputedStyle(cellContent);
368
351
  const inlinePadding =
369
352
  parseInt(contentElStyle.paddingLeft, 10) +
370
353
  parseInt(contentElStyle.paddingRight, 10);
354
+ const marginLeft = parseInt(contentElStyle.marginLeft, 10); // We don't have right margin for now
371
355
  const widthNeededForThisCell =
372
- (cellContentWidth + inlinePadding) / cell.colSpan;
356
+ (cellContentWidth + inlinePadding + marginLeft) / cell.colSpan;
373
357
  if (widthNeededForThisCell > newColumnWidth) {
374
358
  newColumnWidth = widthNeededForThisCell;
375
359
  }
@@ -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/DataTable.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
  };
@@ -1,107 +1,87 @@
1
+ import type { ChangeEventHandler, SetStateAction } from "react";
1
2
  import type { CheckboxInputProps } from "../../../../form/checkbox/checkbox-input/CheckboxInput";
2
- import { SelectionSubtreeHelper } from "./SelectionSubtreeHelper";
3
-
4
- type GetMultipleSelectPropsArgs = {
5
- selectedKeysSet: Set<string | number>;
6
- selectedKeys: (string | number)[];
7
- setSelectedKeys: (keys: (string | number)[]) => void;
8
- disabledKeysSet: Set<string | number>;
9
- visibleRowIds: (string | number)[];
10
- childRowIdsById?: Map<string | number, (string | number)[]>;
11
- };
12
-
13
- function getMultipleSelectProps({
3
+ import { consoleWarning } from "../../../../utils/helpers/consoleWarning";
4
+ import type { UseTableItemsReturn } from "../../hooks/useTableItems";
5
+ import type { TableRowEntryId } from "../../root/DataTable.types";
6
+ import type { SelectedKeysT, SelectionProps } from "./selection.types";
7
+ import { canSelectTableRow, mutateRowSelection } from "./selection.utils";
8
+
9
+ type GetMultipleSelectPropsArgs<T> = {
10
+ selectedKeysSet: Set<TableRowEntryId>;
11
+ selectedKeys: SelectedKeysT;
12
+ setSelectedKeys: (next: SetStateAction<SelectedKeysT>) => void;
13
+ tableItems: UseTableItemsReturn<T>;
14
+ } & Pick<SelectionProps<T>, "enableRowSelection">;
15
+
16
+ function getMultipleSelectProps<T>({
14
17
  selectedKeysSet,
15
18
  selectedKeys,
16
19
  setSelectedKeys,
17
- disabledKeysSet,
18
- visibleRowIds,
19
- childRowIdsById,
20
- }: GetMultipleSelectPropsArgs) {
21
- const subtreeHelper = new SelectionSubtreeHelper({
22
- childRowIdsById,
23
- disabledKeysSet,
24
- selectedKeysSet,
25
- });
26
-
27
- // Header selection traverses the visible roots and skips already visited
28
- // descendants, so expanded trees stay linear in the number of rows.
29
- const headerSelectableKeys = subtreeHelper.getSelectableKeys(visibleRowIds);
30
- const headerSelectableKeysSet = new Set(headerSelectableKeys);
31
-
32
- const selectedSelectableCount = headerSelectableKeys.filter((k) =>
33
- selectedKeysSet.has(k),
34
- ).length;
35
-
36
- const allSelectableSelected =
37
- headerSelectableKeys.length > 0 &&
38
- selectedSelectableCount === headerSelectableKeys.length;
39
-
40
- const indeterminate =
41
- selectedSelectableCount > 0 &&
42
- selectedSelectableCount < headerSelectableKeys.length;
43
-
44
- const selectedKeysNotInView = selectedKeys.filter(
45
- (k) => !headerSelectableKeysSet.has(k),
46
- );
47
- const disabledSelected = selectedKeys.filter((k) => disabledKeysSet.has(k));
48
- const preservedKeys = [
49
- ...new Set([...selectedKeysNotInView, ...disabledSelected]),
50
- ];
20
+ enableRowSelection,
21
+ tableItems,
22
+ }: GetMultipleSelectPropsArgs<T>) {
23
+ const selectableIdsSet: Set<TableRowEntryId> = new Set();
24
+
25
+ for (const [id, { rowData }] of tableItems.itemDetails) {
26
+ if (canSelectTableRow(enableRowSelection, { row: rowData, id })) {
27
+ selectableIdsSet.add(id);
28
+ }
29
+ }
51
30
 
52
- const isGroupFullySelected = (key: string | number) => {
53
- const groupStats = subtreeHelper.getSelectionStats(key);
31
+ let selectedOnPageCount = 0;
32
+ for (const id of selectableIdsSet) {
33
+ selectedKeysSet.has(id) && selectedOnPageCount++;
34
+ }
54
35
 
55
- return (
56
- groupStats.selectableCount > 0 &&
57
- groupStats.selectedCount === groupStats.selectableCount
58
- );
59
- };
36
+ const isAllSelected =
37
+ selectableIdsSet.size > 0 && selectedOnPageCount === selectableIdsSet.size;
38
+ const someSelected = selectedOnPageCount > 0;
60
39
 
61
- const handleToggleAll = () => {
62
- if (allSelectableSelected) {
63
- setSelectedKeys(preservedKeys);
64
- } else {
65
- setSelectedKeys([
66
- ...new Set([...preservedKeys, ...headerSelectableKeys]),
67
- ]);
40
+ const handleToggleRow = (key: TableRowEntryId, row: T) => {
41
+ if (!row) {
42
+ consoleWarning(
43
+ `Row data is undefined for key ${key}. This may cause issues with selection if enableRowSelection is used.`,
44
+ );
68
45
  }
69
- };
70
46
 
71
- const handleToggleRow = (key: string | number) => {
72
- if (disabledKeysSet.has(key)) {
73
- return;
47
+ const checked = !selectedKeysSet.has(key);
48
+ const nextSet = new Set(selectedKeysSet);
49
+ const changed = mutateRowSelection({
50
+ selectedRowIds: nextSet,
51
+ rowId: key,
52
+ checked,
53
+ childRowIdsById: tableItems.childRowIdsById,
54
+ itemDetails: tableItems.itemDetails,
55
+ enableRowSelection,
56
+ });
57
+ if (changed) {
58
+ setSelectedKeys([...nextSet]);
74
59
  }
60
+ };
75
61
 
76
- const groupKeys = subtreeHelper.getSelectableKeys([key]);
77
-
78
- if (isGroupFullySelected(key)) {
79
- const groupKeysSet = new Set(groupKeys);
80
- setSelectedKeys(
81
- selectedKeys.filter((selectedKey) => !groupKeysSet.has(selectedKey)),
82
- );
62
+ const toggleAllRowSelected: ChangeEventHandler<HTMLInputElement> = (
63
+ event,
64
+ ) => {
65
+ if (event.target.checked) {
66
+ const preserved = selectedKeys.filter((k) => !selectableIdsSet.has(k));
67
+ setSelectedKeys([...preserved, ...selectableIdsSet]);
83
68
  } else {
84
- setSelectedKeys([...new Set([...selectedKeys, ...groupKeys])]);
69
+ setSelectedKeys(selectedKeys.filter((k) => !selectableIdsSet.has(k)));
85
70
  }
86
71
  };
87
72
 
88
73
  return {
89
74
  getTheadCheckboxProps: (): CheckboxInputProps => ({
90
- onChange: handleToggleAll,
91
- checked: allSelectableSelected,
92
- indeterminate,
93
- disabled: headerSelectableKeys.length === 0,
75
+ checked: isAllSelected,
76
+ indeterminate: !isAllSelected && someSelected,
77
+ onChange: toggleAllRowSelected,
94
78
  }),
95
- getRowCheckboxProps: (key: string | number): CheckboxInputProps => {
96
- const groupStats = subtreeHelper.getSelectionStats(key);
97
-
79
+ getRowCheckboxProps: (key: TableRowEntryId, row: T): CheckboxInputProps => {
98
80
  return {
99
- onChange: () => handleToggleRow(key),
100
- checked: isGroupFullySelected(key),
101
- indeterminate:
102
- groupStats.selectedCount > 0 &&
103
- groupStats.selectedCount < groupStats.selectableCount,
104
- disabled: disabledKeysSet.has(key),
81
+ onChange: () => handleToggleRow(key, row),
82
+ checked: selectedKeysSet.has(key),
83
+ indeterminate: false,
84
+ disabled: !canSelectTableRow(enableRowSelection, { row, id: key }),
105
85
  };
106
86
  },
107
87
  toggleSelection: handleToggleRow,
@@ -1,33 +1,51 @@
1
1
  import type { RadioInputProps } from "../../../../form/radio/radio-input/RadioInput";
2
+ import { consoleWarning } from "../../../../utils/helpers/consoleWarning";
3
+ import type { TableRowEntryId } from "../../root/DataTable.types";
4
+ import type { SelectedKeysT, SelectionProps } from "./selection.types";
5
+ import { canSelectTableRow } from "./selection.utils";
2
6
 
3
- type GetSingleSelectPropsArgs = {
4
- selectedKeysSet: Set<string | number>;
5
- setSelectedKeys: (keys: (string | number)[]) => void;
6
- disabledKeysSet: Set<string | number>;
7
+ type GetSingleSelectPropsArgs<T> = {
8
+ selectedKeysSet: Set<TableRowEntryId>;
9
+ setSelectedKeys: (keys: SelectedKeysT) => void;
7
10
  name: string;
8
- };
11
+ } & Pick<SelectionProps<T>, "enableRowSelection">;
9
12
 
10
- function getSingleSelectProps({
13
+ function getSingleSelectProps<T>({
11
14
  selectedKeysSet,
12
15
  setSelectedKeys,
13
- disabledKeysSet,
14
16
  name,
15
- }: GetSingleSelectPropsArgs) {
16
- const handleSelectionChange = (key: string | number) => {
17
- if (disabledKeysSet.has(key)) {
17
+ enableRowSelection,
18
+ }: GetSingleSelectPropsArgs<T>) {
19
+ const handleSelectionChange = (key: TableRowEntryId, row: T) => {
20
+ if (!row) {
21
+ consoleWarning(
22
+ `Row data is undefined for key ${key}. This may cause issues with selection if enableRowSelection is used.`,
23
+ );
24
+ }
25
+ if (!canSelectTableRow(enableRowSelection, { row, id: key })) {
18
26
  return;
19
27
  }
28
+
20
29
  setSelectedKeys([key]);
21
30
  };
22
31
 
23
32
  return {
24
- getRowRadioProps: (key: string | number): RadioInputProps => ({
25
- checked: selectedKeysSet.has(key),
26
- onChange: () => handleSelectionChange(key),
27
- disabled: disabledKeysSet.has(key),
28
- value: key,
29
- name,
30
- }),
33
+ getRowRadioProps: (key: TableRowEntryId, row: T): RadioInputProps => {
34
+ const isSelectionDisabled = !canSelectTableRow(enableRowSelection, {
35
+ row,
36
+ id: key,
37
+ });
38
+
39
+ return {
40
+ checked: selectedKeysSet.has(key),
41
+ onChange: isSelectionDisabled
42
+ ? () => null
43
+ : () => handleSelectionChange(key, row),
44
+ disabled: isSelectionDisabled,
45
+ value: key,
46
+ name,
47
+ };
48
+ },
31
49
  toggleSelection: handleSelectionChange,
32
50
  };
33
51
  }
@@ -1,9 +1,11 @@
1
1
  import type { CheckboxInputProps } from "../../../../form/checkbox/checkbox-input/CheckboxInput";
2
2
  import type { RadioInputProps } from "../../../../form/radio/radio-input/RadioInput";
3
+ import type { TableRowEntryId } from "../../root/DataTable.types";
3
4
 
4
- type SelectedKeysT = (string | number)[];
5
+ type SelectedKeysT = TableRowEntryId[];
5
6
 
6
- type SelectionProps = {
7
+ // TODO: Remove `any` if possible
8
+ type SelectionProps<T = any> = {
7
9
  /**
8
10
  * Enables selection of rows.
9
11
  *
@@ -14,7 +16,7 @@ type SelectionProps = {
14
16
  *
15
17
  * @default "none"
16
18
  */
17
- selectionMode?: "none" | "single" | "multiple";
19
+ selectionMode: "none" | "single" | "multiple";
18
20
  /**
19
21
  * Controlled selected keys. Should be used in conjunction with `onSelectionChange`.
20
22
  */
@@ -28,45 +30,43 @@ type SelectionProps = {
28
30
  */
29
31
  onSelectionChange?: (keys: SelectedKeysT) => void;
30
32
  /**
31
- * Keys that should be disabled for selection. These keys will not be selectable and will be styled as disabled.
33
+ * Callback to determine if a row should be enabled for selection.
32
34
  *
33
35
  *
34
- * TODO: Consider making this optionally a callback with (rowData:T) => boolean, to allow for more dynamic disabling of selection based on row data.
36
+ * If set to a boolean, it will enable selection for all rows when true, and disable selection for all rows when false.
35
37
  */
36
- disabledSelectionKeys?: SelectedKeysT;
38
+ enableRowSelection?:
39
+ | (({ row, id }: { row: T; id: TableRowEntryId }) => boolean)
40
+ | boolean;
37
41
  /**
38
- * If true, stops clicking a row from toggling its selection state. This can be used if you want to only allow selection through the checkboxes/radios, and not have the entire row be clickable for selection.
39
- *
40
- * @default false
42
+ * Determines if selection is triggered by clicking the row or the selection control (checkbox/radio).
43
+ * @default "row"
41
44
  */
42
- disableRowSelectionOnClick?: boolean;
45
+ selectionTrigger?: "row" | "control";
43
46
  };
44
47
 
45
48
  type NoneSelection = {
46
49
  selectionMode: "none";
47
50
  selectedKeys: SelectedKeysT;
48
- disabledSelectionKeys: SelectedKeysT;
49
51
  };
50
52
 
51
53
  type SingleSelection = {
52
54
  selectionMode: "single";
53
55
  selectedKeys: SelectedKeysT;
54
- disabledSelectionKeys: SelectedKeysT;
55
- getRowRadioProps: (key: string | number) => RadioInputProps;
56
- toggleSelection: (key: string | number) => void;
56
+ getRowRadioProps: (key: TableRowEntryId, row: any) => RadioInputProps;
57
+ toggleSelection: (key: TableRowEntryId, row: any) => void;
57
58
  };
58
59
 
59
60
  type MultipleSelection = {
60
61
  selectionMode: "multiple";
61
62
  selectedKeys: SelectedKeysT;
62
- disabledSelectionKeys: SelectedKeysT;
63
63
  getTheadCheckboxProps: () => CheckboxInputProps;
64
- getRowCheckboxProps: (key: string | number) => CheckboxInputProps;
65
- toggleSelection: (key: string | number) => void;
64
+ getRowCheckboxProps: (key: TableRowEntryId, row: any) => CheckboxInputProps;
65
+ toggleSelection: (key: TableRowEntryId, row: any) => void;
66
66
  };
67
67
 
68
68
  type TableSelectionBase = {
69
- isRowSelected: (rowId: string | number) => boolean;
69
+ isRowSelected: (rowId: TableRowEntryId) => boolean;
70
70
  };
71
71
 
72
72
  type TableSelection = TableSelectionBase &
@@ -75,8 +75,8 @@ type TableSelection = TableSelectionBase &
75
75
  export type {
76
76
  MultipleSelection,
77
77
  NoneSelection,
78
+ SelectedKeysT,
78
79
  SelectionProps,
79
80
  SingleSelection,
80
81
  TableSelection,
81
- SelectedKeysT,
82
82
  };