@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,107 +1,93 @@
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/DataGridTable.types";
6
+ import type { SelectionProps } from "./selection.types";
7
+ import { canSelectTableRow, mutateRowSelection } from "./selection.utils";
8
+
9
+ type GetMultipleSelectPropsArgs<T> = {
10
+ selectedKeysSet: Set<TableRowEntryId>;
11
+ selectedKeys: string[];
12
+ setSelectedKeys: (next: SetStateAction<string[]>) => void;
13
+ tableItems: UseTableItemsReturn<T>;
14
+ isLoading?: boolean;
15
+ } & Pick<SelectionProps<T>, "enableRowSelection">;
16
+
17
+ function getMultipleSelectProps<T>({
14
18
  selectedKeysSet,
15
19
  selectedKeys,
16
20
  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;
21
+ enableRowSelection,
22
+ tableItems,
23
+ isLoading,
24
+ }: GetMultipleSelectPropsArgs<T>) {
25
+ const selectableIdsSet: Set<TableRowEntryId> = new Set();
26
+
27
+ for (const [id, { rowData }] of tableItems.itemDetails) {
28
+ if (canSelectTableRow(enableRowSelection, { row: rowData, id })) {
29
+ selectableIdsSet.add(id);
30
+ }
31
+ }
43
32
 
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
- ];
33
+ let selectedOnPageCount = 0;
34
+ for (const id of selectableIdsSet) {
35
+ selectedKeysSet.has(id) && selectedOnPageCount++;
36
+ }
51
37
 
52
- const isGroupFullySelected = (key: string | number) => {
53
- const groupStats = subtreeHelper.getSelectionStats(key);
38
+ const isAllSelected =
39
+ selectableIdsSet.size > 0 && selectedOnPageCount === selectableIdsSet.size;
40
+ const someSelected = selectedOnPageCount > 0;
54
41
 
55
- return (
56
- groupStats.selectableCount > 0 &&
57
- groupStats.selectedCount === groupStats.selectableCount
58
- );
59
- };
42
+ const handleToggleRow = (key: TableRowEntryId, row: T) => {
43
+ if (!row) {
44
+ consoleWarning(
45
+ `DataGrid.Table: Row data is undefined for key ${key}. This may cause issues with selection if enableRowSelection is used.`,
46
+ );
47
+ }
60
48
 
61
- const handleToggleAll = () => {
62
- if (allSelectableSelected) {
63
- setSelectedKeys(preservedKeys);
64
- } else {
65
- setSelectedKeys([
66
- ...new Set([...preservedKeys, ...headerSelectableKeys]),
67
- ]);
49
+ const checked = !selectedKeysSet.has(key);
50
+ const nextSet = new Set(selectedKeysSet);
51
+ const changed = mutateRowSelection({
52
+ selectedRowIds: nextSet,
53
+ rowId: key,
54
+ checked,
55
+ childRowIdsById: tableItems.childRowIdsById,
56
+ itemDetails: tableItems.itemDetails,
57
+ enableRowSelection,
58
+ });
59
+ if (changed) {
60
+ setSelectedKeys([...nextSet]);
68
61
  }
69
62
  };
70
63
 
71
- const handleToggleRow = (key: string | number) => {
72
- if (disabledKeysSet.has(key)) {
64
+ const toggleAllRowSelected: ChangeEventHandler<HTMLInputElement> = (
65
+ event,
66
+ ) => {
67
+ if (isLoading) {
73
68
  return;
74
69
  }
75
-
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
- );
70
+ if (event.target.checked) {
71
+ const preserved = selectedKeys.filter((k) => !selectableIdsSet.has(k));
72
+ setSelectedKeys([...preserved, ...selectableIdsSet]);
83
73
  } else {
84
- setSelectedKeys([...new Set([...selectedKeys, ...groupKeys])]);
74
+ setSelectedKeys(selectedKeys.filter((k) => !selectableIdsSet.has(k)));
85
75
  }
86
76
  };
87
77
 
88
78
  return {
89
79
  getTheadCheckboxProps: (): CheckboxInputProps => ({
90
- onChange: handleToggleAll,
91
- checked: allSelectableSelected,
92
- indeterminate,
93
- disabled: headerSelectableKeys.length === 0,
80
+ checked: isAllSelected,
81
+ indeterminate: !isAllSelected && someSelected,
82
+ onChange: toggleAllRowSelected,
83
+ disabled: selectableIdsSet.size === 0 || isLoading,
94
84
  }),
95
- getRowCheckboxProps: (key: string | number): CheckboxInputProps => {
96
- const groupStats = subtreeHelper.getSelectionStats(key);
97
-
85
+ getRowCheckboxProps: (key: TableRowEntryId, row: T): CheckboxInputProps => {
98
86
  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),
87
+ onChange: () => handleToggleRow(key, row),
88
+ checked: selectedKeysSet.has(key),
89
+ indeterminate: false,
90
+ disabled: !canSelectTableRow(enableRowSelection, { row, id: key }),
105
91
  };
106
92
  },
107
93
  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/DataGridTable.types";
4
+ import type { 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: string[]) => 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
+ `DataGrid.Table: 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,8 @@
1
1
  import type { CheckboxInputProps } from "../../../../form/checkbox/checkbox-input/CheckboxInput";
2
2
  import type { RadioInputProps } from "../../../../form/radio/radio-input/RadioInput";
3
3
 
4
- type SelectedKeysT = (string | number)[];
5
-
6
- type SelectionProps = {
4
+ // TODO: Remove `= unknown` if possible
5
+ type SelectionProps<T = unknown> = {
7
6
  /**
8
7
  * Enables selection of rows.
9
8
  *
@@ -14,59 +13,51 @@ type SelectionProps = {
14
13
  *
15
14
  * @default "none"
16
15
  */
17
- selectionMode?: "none" | "single" | "multiple";
16
+ mode: "none" | "single" | "multiple";
18
17
  /**
19
- * Controlled selected keys. Should be used in conjunction with `onSelectionChange`.
18
+ * Controlled selected keys. Should be used in conjunction with `onSelectedRowIdsChange`.
20
19
  */
21
- selectedKeys?: SelectedKeysT;
20
+ selectedRowIds?: string[];
22
21
  /**
23
22
  * Default selected keys when using uncontrolled selection. Should not be used together with `selectedKeys`.
24
23
  */
25
- defaultSelectedKeys?: SelectedKeysT;
24
+ defaultSelectedRowIds?: string[];
26
25
  /**
27
26
  * Callback with array of selected keys.
28
27
  */
29
- onSelectionChange?: (keys: SelectedKeysT) => void;
30
- /**
31
- * Keys that should be disabled for selection. These keys will not be selectable and will be styled as disabled.
32
- *
33
- *
34
- * TODO: Consider making this optionally a callback with (rowData:T) => boolean, to allow for more dynamic disabling of selection based on row data.
35
- */
36
- disabledSelectionKeys?: SelectedKeysT;
28
+ onSelectedRowIdsChange?: (ids: string[]) => void;
37
29
  /**
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.
30
+ * Callback to determine if a row should be enabled for selection.
39
31
  *
40
- * @default false
32
+ * If set to a boolean, it will enable selection for all rows when true, and disable selection for all rows when false.
41
33
  */
42
- disableRowSelectionOnClick?: boolean;
34
+ enableRowSelection?:
35
+ | (({ row, id }: { row: T; id: string }) => boolean)
36
+ | boolean;
43
37
  };
44
38
 
45
39
  type NoneSelection = {
46
- selectionMode: "none";
47
- selectedKeys: SelectedKeysT;
48
- disabledSelectionKeys: SelectedKeysT;
40
+ mode: "none";
41
+ selectedKeys: string[];
49
42
  };
50
43
 
51
44
  type SingleSelection = {
52
- selectionMode: "single";
53
- selectedKeys: SelectedKeysT;
54
- disabledSelectionKeys: SelectedKeysT;
55
- getRowRadioProps: (key: string | number) => RadioInputProps;
56
- toggleSelection: (key: string | number) => void;
45
+ mode: "single";
46
+ selectedKeys: string[];
47
+ getRowRadioProps: (key: string, row: any) => RadioInputProps;
48
+ toggleSelection: (key: string, row: any) => void;
57
49
  };
58
50
 
59
51
  type MultipleSelection = {
60
- selectionMode: "multiple";
61
- selectedKeys: SelectedKeysT;
62
- disabledSelectionKeys: SelectedKeysT;
52
+ mode: "multiple";
53
+ selectedKeys: string[];
63
54
  getTheadCheckboxProps: () => CheckboxInputProps;
64
- getRowCheckboxProps: (key: string | number) => CheckboxInputProps;
65
- toggleSelection: (key: string | number) => void;
55
+ getRowCheckboxProps: (key: string, row: any) => CheckboxInputProps;
56
+ toggleSelection: (key: string, row: any) => void;
66
57
  };
67
58
 
68
59
  type TableSelectionBase = {
69
- isRowSelected: (rowId: string | number) => boolean;
60
+ isRowSelected: (rowId: string) => boolean;
70
61
  };
71
62
 
72
63
  type TableSelection = TableSelectionBase &
@@ -78,5 +69,4 @@ export type {
78
69
  SelectionProps,
79
70
  SingleSelection,
80
71
  TableSelection,
81
- SelectedKeysT,
82
72
  };
@@ -0,0 +1,161 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import type { TableRowEntryId } from "../../root/DataGridTable.types";
3
+ import type { ItemDetail } from "../collectTableRowEntries";
4
+ import { mutateRowSelection } from "./selection.utils";
5
+
6
+ function makeItemDetails<T>(
7
+ entries: { id: TableRowEntryId; rowData: T }[],
8
+ ): Map<TableRowEntryId, ItemDetail<T>> {
9
+ return new Map(
10
+ entries.map(({ id, rowData }) => [
11
+ id,
12
+ { id, rowData, level: 0, parentId: null, children: [] },
13
+ ]),
14
+ );
15
+ }
16
+
17
+ describe("mutateRowSelection", () => {
18
+ test("adds rowId to set when checked", () => {
19
+ const set = new Set<TableRowEntryId>();
20
+ const itemDetails = makeItemDetails([{ id: "a", rowData: {} }]);
21
+ const changed = mutateRowSelection({
22
+ selectedRowIds: set,
23
+ rowId: "a",
24
+ checked: true,
25
+ childRowIdsById: new Map(),
26
+ itemDetails,
27
+ });
28
+ expect(set.has("a")).toBe(true);
29
+ expect(changed).toBe(true);
30
+ });
31
+
32
+ test("removes rowId from set when unchecked", () => {
33
+ const set = new Set<TableRowEntryId>(["a"]);
34
+ const itemDetails = makeItemDetails([{ id: "a", rowData: {} }]);
35
+ const changed = mutateRowSelection({
36
+ selectedRowIds: set,
37
+ rowId: "a",
38
+ checked: false,
39
+ childRowIdsById: new Map(),
40
+ itemDetails,
41
+ });
42
+ expect(set.has("a")).toBe(false);
43
+ expect(changed).toBe(true);
44
+ });
45
+
46
+ test("returns false and does not mutate when row is already in desired state", () => {
47
+ const set = new Set<TableRowEntryId>(["a"]);
48
+ const itemDetails = makeItemDetails([{ id: "a", rowData: {} }]);
49
+ const changed = mutateRowSelection({
50
+ selectedRowIds: set,
51
+ rowId: "a",
52
+ checked: true,
53
+ childRowIdsById: new Map(),
54
+ itemDetails,
55
+ });
56
+ expect(set.size).toBe(1);
57
+ expect(changed).toBe(false);
58
+ });
59
+
60
+ test("recursively selects all children", () => {
61
+ const set = new Set<TableRowEntryId>();
62
+ const itemDetails = makeItemDetails([
63
+ { id: "parent", rowData: {} },
64
+ { id: "child1", rowData: {} },
65
+ { id: "child2", rowData: {} },
66
+ ]);
67
+ const childRowIdsById = new Map<TableRowEntryId, TableRowEntryId[]>([
68
+ ["parent", ["child1", "child2"]],
69
+ ]);
70
+ mutateRowSelection({
71
+ selectedRowIds: set,
72
+ rowId: "parent",
73
+ checked: true,
74
+ childRowIdsById,
75
+ itemDetails,
76
+ });
77
+ expect(set).toEqual(new Set(["parent", "child1", "child2"]));
78
+ });
79
+
80
+ test("recursively deselects all children", () => {
81
+ const set = new Set<TableRowEntryId>(["parent", "child1", "child2"]);
82
+ const itemDetails = makeItemDetails([
83
+ { id: "parent", rowData: {} },
84
+ { id: "child1", rowData: {} },
85
+ { id: "child2", rowData: {} },
86
+ ]);
87
+ const childRowIdsById = new Map<TableRowEntryId, TableRowEntryId[]>([
88
+ ["parent", ["child1", "child2"]],
89
+ ]);
90
+ mutateRowSelection({
91
+ selectedRowIds: set,
92
+ rowId: "parent",
93
+ checked: false,
94
+ childRowIdsById,
95
+ itemDetails,
96
+ });
97
+ expect(set.size).toBe(0);
98
+ });
99
+
100
+ test("handles deeply nested children", () => {
101
+ const set = new Set<TableRowEntryId>();
102
+ const itemDetails = makeItemDetails([
103
+ { id: "a", rowData: {} },
104
+ { id: "a1", rowData: {} },
105
+ { id: "a1a", rowData: {} },
106
+ ]);
107
+ const childRowIdsById = new Map<TableRowEntryId, TableRowEntryId[]>([
108
+ ["a", ["a1"]],
109
+ ["a1", ["a1a"]],
110
+ ]);
111
+ mutateRowSelection({
112
+ selectedRowIds: set,
113
+ rowId: "a",
114
+ checked: true,
115
+ childRowIdsById,
116
+ itemDetails,
117
+ });
118
+ expect(set).toEqual(new Set(["a", "a1", "a1a"]));
119
+ });
120
+
121
+ test("skips disabled rows and their children", () => {
122
+ const set = new Set<TableRowEntryId>();
123
+ const itemDetails = makeItemDetails([
124
+ { id: "parent", rowData: { disabled: false } },
125
+ { id: "child1", rowData: { disabled: true } },
126
+ { id: "child1a", rowData: { disabled: false } },
127
+ { id: "child2", rowData: { disabled: false } },
128
+ ]);
129
+ const childRowIdsById = new Map<TableRowEntryId, TableRowEntryId[]>([
130
+ ["parent", ["child1", "child2"]],
131
+ ["child1", ["child1a"]],
132
+ ]);
133
+ mutateRowSelection({
134
+ selectedRowIds: set,
135
+ rowId: "parent",
136
+ checked: true,
137
+ childRowIdsById,
138
+ itemDetails,
139
+ enableRowSelection: ({ row }) => !row.disabled,
140
+ });
141
+ expect(set.has("parent")).toBe(true);
142
+ expect(set.has("child1")).toBe(false);
143
+ expect(set.has("child1a")).toBe(true);
144
+ expect(set.has("child2")).toBe(true);
145
+ });
146
+
147
+ test("returns false when all matching rows were already disabled", () => {
148
+ const set = new Set<TableRowEntryId>();
149
+ const itemDetails = makeItemDetails([{ id: "a", rowData: {} }]);
150
+ const changed = mutateRowSelection({
151
+ selectedRowIds: set,
152
+ rowId: "a",
153
+ checked: true,
154
+ childRowIdsById: new Map(),
155
+ itemDetails,
156
+ enableRowSelection: false,
157
+ });
158
+ expect(set.size).toBe(0);
159
+ expect(changed).toBe(false);
160
+ });
161
+ });
@@ -0,0 +1,73 @@
1
+ import type { TableRowEntryId } from "../../root/DataGridTable.types";
2
+ import type { ItemDetail } from "../collectTableRowEntries";
3
+ import type { SelectionProps } from "./selection.types";
4
+
5
+ function canSelectTableRow<T>(
6
+ enableRowSelection: SelectionProps<T>["enableRowSelection"],
7
+ args: { row: T; id: TableRowEntryId },
8
+ ): boolean {
9
+ if (typeof enableRowSelection === "function") {
10
+ return enableRowSelection(args);
11
+ }
12
+ return enableRowSelection ?? true;
13
+ }
14
+
15
+ type MutateRowSelectionArgs<T> = {
16
+ selectedRowIds: Set<TableRowEntryId>;
17
+ rowId: TableRowEntryId;
18
+ checked: boolean;
19
+ childRowIdsById: Map<TableRowEntryId, TableRowEntryId[]>;
20
+ itemDetails: Map<TableRowEntryId, ItemDetail<T>>;
21
+ enableRowSelection?: SelectionProps<T>["enableRowSelection"];
22
+ };
23
+
24
+ /**
25
+ * Traverses the row and its children and updates selected-state directly on given selectedRowIds set.
26
+ * Returns true if any changes were made to the set, false otherwise.
27
+ */
28
+ function mutateRowSelection<T>({
29
+ selectedRowIds,
30
+ rowId,
31
+ checked,
32
+ childRowIdsById,
33
+ itemDetails,
34
+ enableRowSelection,
35
+ }: MutateRowSelectionArgs<T>): boolean {
36
+ let changed = false;
37
+ const item = itemDetails.get(rowId);
38
+
39
+ if (
40
+ item &&
41
+ canSelectTableRow(enableRowSelection, { row: item.rowData, id: rowId })
42
+ ) {
43
+ if (checked && !selectedRowIds.has(rowId)) {
44
+ selectedRowIds.add(rowId);
45
+ changed = true;
46
+ } else if (!checked && selectedRowIds.has(rowId)) {
47
+ selectedRowIds.delete(rowId);
48
+ changed = true;
49
+ }
50
+ }
51
+
52
+ const children = childRowIdsById.get(rowId);
53
+ if (children) {
54
+ for (const childId of children) {
55
+ if (
56
+ mutateRowSelection({
57
+ selectedRowIds,
58
+ rowId: childId,
59
+ checked,
60
+ childRowIdsById,
61
+ itemDetails,
62
+ enableRowSelection,
63
+ })
64
+ ) {
65
+ changed = true;
66
+ }
67
+ }
68
+ }
69
+
70
+ return changed;
71
+ }
72
+
73
+ export { canSelectTableRow, mutateRowSelection };
@@ -1,5 +1,6 @@
1
1
  import { renderHook } from "@testing-library/react";
2
2
  import { describe, expect, test } from "vitest";
3
+ import type { TableRowEntryId } from "../../root/DataGridTable.types";
3
4
  import { useTableItems } from "../useTableItems";
4
5
 
5
6
  type TestRow = {
@@ -140,7 +141,7 @@ describe("useTableItems", () => {
140
141
  },
141
142
  }),
142
143
  {
143
- initialProps: { expandedIds: [] as (string | number)[] },
144
+ initialProps: { expandedIds: [] as TableRowEntryId[] },
144
145
  },
145
146
  );
146
147