@navikt/ds-react 8.6.0 → 8.7.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 (250) hide show
  1. package/cjs/data/drag-and-drop/item/DataDragAndDropItem.d.ts +27 -0
  2. package/cjs/data/drag-and-drop/item/DataDragAndDropItem.js +91 -0
  3. package/cjs/data/drag-and-drop/item/DataDragAndDropItem.js.map +1 -0
  4. package/cjs/data/drag-and-drop/root/DataDragAndDrop.context.d.ts +5 -0
  5. package/cjs/data/drag-and-drop/root/DataDragAndDrop.context.js +6 -0
  6. package/cjs/data/drag-and-drop/root/DataDragAndDrop.context.js.map +1 -0
  7. package/cjs/data/drag-and-drop/root/DataDragAndDropRoot.d.ts +24 -0
  8. package/cjs/data/drag-and-drop/root/DataDragAndDropRoot.js +111 -0
  9. package/cjs/data/drag-and-drop/root/DataDragAndDropRoot.js.map +1 -0
  10. package/cjs/data/table/helpers/table-keyboard.d.ts +1 -0
  11. package/cjs/data/table/helpers/table-keyboard.js +5 -3
  12. package/cjs/data/table/helpers/table-keyboard.js.map +1 -1
  13. package/cjs/data/table/root/DataTableRoot.context.d.ts +8 -0
  14. package/cjs/data/table/root/DataTableRoot.context.js +11 -0
  15. package/cjs/data/table/root/DataTableRoot.context.js.map +1 -0
  16. package/cjs/data/table/root/DataTableRoot.js +5 -3
  17. package/cjs/data/table/root/DataTableRoot.js.map +1 -1
  18. package/cjs/data/table/th/DataTableTh.d.ts +18 -2
  19. package/cjs/data/table/th/DataTableTh.js +45 -20
  20. package/cjs/data/table/th/DataTableTh.js.map +1 -1
  21. package/cjs/data/table/tr/DataTableTr.js +9 -2
  22. package/cjs/data/table/tr/DataTableTr.js.map +1 -1
  23. package/cjs/data/token-filter/AutoSuggest.d.ts +6 -2
  24. package/cjs/data/token-filter/AutoSuggest.js +46 -11
  25. package/cjs/data/token-filter/AutoSuggest.js.map +1 -1
  26. package/cjs/data/token-filter/TokenFilter.d.ts +5 -5
  27. package/cjs/data/token-filter/TokenFilter.js +105 -42
  28. package/cjs/data/token-filter/TokenFilter.js.map +1 -1
  29. package/cjs/data/token-filter/TokenFilter.types.d.ts +51 -33
  30. package/cjs/data/token-filter/helpers/generate-autocomplete-options.d.ts +2 -3
  31. package/cjs/data/token-filter/helpers/generate-autocomplete-options.js +11 -15
  32. package/cjs/data/token-filter/helpers/generate-autocomplete-options.js.map +1 -1
  33. package/cjs/data/token-filter/helpers/operators.d.ts +6 -6
  34. package/cjs/data/token-filter/helpers/operators.js +3 -4
  35. package/cjs/data/token-filter/helpers/operators.js.map +1 -1
  36. package/cjs/data/token-filter/helpers/parse-query-text.d.ts +2 -20
  37. package/cjs/data/token-filter/helpers/parse-query-text.js +1 -1
  38. package/cjs/data/token-filter/helpers/parse-query-text.js.map +1 -1
  39. package/cjs/data/token-filter/helpers/query-builder.d.ts +2 -2
  40. package/cjs/data/token-filter/helpers/query-builder.js.map +1 -1
  41. package/cjs/date/Date.Dialog.d.ts +5 -1
  42. package/cjs/date/Date.Dialog.js +6 -2
  43. package/cjs/date/Date.Dialog.js.map +1 -1
  44. package/cjs/date/datepicker/DatePicker.js +3 -2
  45. package/cjs/date/datepicker/DatePicker.js.map +1 -1
  46. package/cjs/date/datepicker/hooks/useDatepicker.js +5 -2
  47. package/cjs/date/datepicker/hooks/useDatepicker.js.map +1 -1
  48. package/cjs/date/datepicker/hooks/useRangeDatepicker.js +3 -1
  49. package/cjs/date/datepicker/hooks/useRangeDatepicker.js.map +1 -1
  50. package/cjs/date/datepicker/parts/DatePicker.Months.d.ts +2 -1
  51. package/cjs/date/datepicker/parts/DatePicker.Months.js +3 -3
  52. package/cjs/date/datepicker/parts/DatePicker.Months.js.map +1 -1
  53. package/cjs/date/datepicker/parts/DatePicker.RDP.d.ts +5 -1
  54. package/cjs/date/datepicker/parts/DatePicker.RDP.js +2 -2
  55. package/cjs/date/datepicker/parts/DatePicker.RDP.js.map +1 -1
  56. package/cjs/date/monthpicker/MonthPicker.js +3 -2
  57. package/cjs/date/monthpicker/MonthPicker.js.map +1 -1
  58. package/cjs/date/monthpicker/hooks/useMonthPicker.js +3 -1
  59. package/cjs/date/monthpicker/hooks/useMonthPicker.js.map +1 -1
  60. package/cjs/date/monthpicker/parts/MonthPicker.Caption.d.ts +4 -1
  61. package/cjs/date/monthpicker/parts/MonthPicker.Caption.js +3 -2
  62. package/cjs/date/monthpicker/parts/MonthPicker.Caption.js.map +1 -1
  63. package/cjs/dropdown/Toggle.js +5 -12
  64. package/cjs/dropdown/Toggle.js.map +1 -1
  65. package/cjs/form/combobox/Input/Input.js +1 -1
  66. package/cjs/form/combobox/Input/Input.js.map +1 -1
  67. package/cjs/inline-message/root/InlineMessage.js +2 -2
  68. package/cjs/inline-message/root/InlineMessage.js.map +1 -1
  69. package/cjs/provider/Provider.d.ts +2 -2
  70. package/cjs/tooltip/Tooltip.js +1 -3
  71. package/cjs/tooltip/Tooltip.js.map +1 -1
  72. package/cjs/utils/components/HighlightText/HighlightText.d.ts +8 -0
  73. package/cjs/utils/components/HighlightText/HighlightText.js +27 -0
  74. package/cjs/utils/components/HighlightText/HighlightText.js.map +1 -0
  75. package/cjs/utils/components/Listbox/group/ListboxGroup.d.ts +7 -0
  76. package/cjs/utils/components/Listbox/group/ListboxGroup.js +15 -0
  77. package/cjs/utils/components/Listbox/group/ListboxGroup.js.map +1 -0
  78. package/cjs/utils/components/Listbox/input-slot/ListboxInputSlot.d.ts +7 -0
  79. package/cjs/utils/components/Listbox/input-slot/ListboxInputSlot.js +15 -0
  80. package/cjs/utils/components/Listbox/input-slot/ListboxInputSlot.js.map +1 -0
  81. package/cjs/utils/components/Listbox/item/ListboxItem.d.ts +24 -0
  82. package/cjs/utils/components/Listbox/item/ListboxItem.js +33 -0
  83. package/cjs/utils/components/Listbox/item/ListboxItem.js.map +1 -0
  84. package/cjs/utils/components/Listbox/list/ListboxList.d.ts +8 -0
  85. package/cjs/utils/components/Listbox/list/ListboxList.js +32 -0
  86. package/cjs/utils/components/Listbox/list/ListboxList.js.map +1 -0
  87. package/cjs/utils/components/Listbox/root/ListboxRoot.d.ts +20 -0
  88. package/cjs/utils/components/Listbox/root/ListboxRoot.js +84 -0
  89. package/cjs/utils/components/Listbox/root/ListboxRoot.js.map +1 -0
  90. package/cjs/utils/components/Listbox/root/domHelpers.d.ts +3 -0
  91. package/cjs/utils/components/Listbox/root/domHelpers.js +53 -0
  92. package/cjs/utils/components/Listbox/root/domHelpers.js.map +1 -0
  93. package/cjs/utils/components/focus-boundary/FocusBoundary.js +9 -64
  94. package/cjs/utils/components/focus-boundary/FocusBoundary.js.map +1 -1
  95. package/cjs/utils/helpers/focus.d.ts +14 -0
  96. package/cjs/utils/helpers/focus.js +63 -0
  97. package/cjs/utils/helpers/focus.js.map +1 -0
  98. package/cjs/utils/hooks/useDeferredValue.d.ts +1 -0
  99. package/cjs/utils/hooks/useDeferredValue.js +14 -0
  100. package/cjs/utils/hooks/useDeferredValue.js.map +1 -0
  101. package/esm/data/drag-and-drop/item/DataDragAndDropItem.d.ts +27 -0
  102. package/esm/data/drag-and-drop/item/DataDragAndDropItem.js +55 -0
  103. package/esm/data/drag-and-drop/item/DataDragAndDropItem.js.map +1 -0
  104. package/esm/data/drag-and-drop/root/DataDragAndDrop.context.d.ts +5 -0
  105. package/esm/data/drag-and-drop/root/DataDragAndDrop.context.js +3 -0
  106. package/esm/data/drag-and-drop/root/DataDragAndDrop.context.js.map +1 -0
  107. package/esm/data/drag-and-drop/root/DataDragAndDropRoot.d.ts +24 -0
  108. package/esm/data/drag-and-drop/root/DataDragAndDropRoot.js +71 -0
  109. package/esm/data/drag-and-drop/root/DataDragAndDropRoot.js.map +1 -0
  110. package/esm/data/table/helpers/table-keyboard.d.ts +1 -0
  111. package/esm/data/table/helpers/table-keyboard.js +5 -3
  112. package/esm/data/table/helpers/table-keyboard.js.map +1 -1
  113. package/esm/data/table/root/DataTableRoot.context.d.ts +8 -0
  114. package/esm/data/table/root/DataTableRoot.context.js +7 -0
  115. package/esm/data/table/root/DataTableRoot.context.js.map +1 -0
  116. package/esm/data/table/root/DataTableRoot.js +5 -3
  117. package/esm/data/table/root/DataTableRoot.js.map +1 -1
  118. package/esm/data/table/th/DataTableTh.d.ts +18 -2
  119. package/esm/data/table/th/DataTableTh.js +46 -21
  120. package/esm/data/table/th/DataTableTh.js.map +1 -1
  121. package/esm/data/table/tr/DataTableTr.js +9 -2
  122. package/esm/data/table/tr/DataTableTr.js.map +1 -1
  123. package/esm/data/token-filter/AutoSuggest.d.ts +6 -2
  124. package/esm/data/token-filter/AutoSuggest.js +45 -13
  125. package/esm/data/token-filter/AutoSuggest.js.map +1 -1
  126. package/esm/data/token-filter/TokenFilter.d.ts +5 -5
  127. package/esm/data/token-filter/TokenFilter.js +105 -42
  128. package/esm/data/token-filter/TokenFilter.js.map +1 -1
  129. package/esm/data/token-filter/TokenFilter.types.d.ts +51 -33
  130. package/esm/data/token-filter/helpers/generate-autocomplete-options.d.ts +2 -3
  131. package/esm/data/token-filter/helpers/generate-autocomplete-options.js +11 -15
  132. package/esm/data/token-filter/helpers/generate-autocomplete-options.js.map +1 -1
  133. package/esm/data/token-filter/helpers/operators.d.ts +6 -6
  134. package/esm/data/token-filter/helpers/operators.js +3 -4
  135. package/esm/data/token-filter/helpers/operators.js.map +1 -1
  136. package/esm/data/token-filter/helpers/parse-query-text.d.ts +2 -20
  137. package/esm/data/token-filter/helpers/parse-query-text.js +1 -1
  138. package/esm/data/token-filter/helpers/parse-query-text.js.map +1 -1
  139. package/esm/data/token-filter/helpers/query-builder.d.ts +2 -2
  140. package/esm/data/token-filter/helpers/query-builder.js.map +1 -1
  141. package/esm/date/Date.Dialog.d.ts +5 -1
  142. package/esm/date/Date.Dialog.js +6 -2
  143. package/esm/date/Date.Dialog.js.map +1 -1
  144. package/esm/date/datepicker/DatePicker.js +3 -2
  145. package/esm/date/datepicker/DatePicker.js.map +1 -1
  146. package/esm/date/datepicker/hooks/useDatepicker.js +5 -2
  147. package/esm/date/datepicker/hooks/useDatepicker.js.map +1 -1
  148. package/esm/date/datepicker/hooks/useRangeDatepicker.js +3 -1
  149. package/esm/date/datepicker/hooks/useRangeDatepicker.js.map +1 -1
  150. package/esm/date/datepicker/parts/DatePicker.Months.d.ts +2 -1
  151. package/esm/date/datepicker/parts/DatePicker.Months.js +3 -3
  152. package/esm/date/datepicker/parts/DatePicker.Months.js.map +1 -1
  153. package/esm/date/datepicker/parts/DatePicker.RDP.d.ts +5 -1
  154. package/esm/date/datepicker/parts/DatePicker.RDP.js +2 -2
  155. package/esm/date/datepicker/parts/DatePicker.RDP.js.map +1 -1
  156. package/esm/date/monthpicker/MonthPicker.js +3 -2
  157. package/esm/date/monthpicker/MonthPicker.js.map +1 -1
  158. package/esm/date/monthpicker/hooks/useMonthPicker.js +3 -1
  159. package/esm/date/monthpicker/hooks/useMonthPicker.js.map +1 -1
  160. package/esm/date/monthpicker/parts/MonthPicker.Caption.d.ts +4 -1
  161. package/esm/date/monthpicker/parts/MonthPicker.Caption.js +3 -2
  162. package/esm/date/monthpicker/parts/MonthPicker.Caption.js.map +1 -1
  163. package/esm/dropdown/Toggle.js +5 -12
  164. package/esm/dropdown/Toggle.js.map +1 -1
  165. package/esm/form/combobox/Input/Input.js +1 -1
  166. package/esm/form/combobox/Input/Input.js.map +1 -1
  167. package/esm/inline-message/root/InlineMessage.js +3 -3
  168. package/esm/inline-message/root/InlineMessage.js.map +1 -1
  169. package/esm/provider/Provider.d.ts +2 -2
  170. package/esm/tooltip/Tooltip.js +1 -3
  171. package/esm/tooltip/Tooltip.js.map +1 -1
  172. package/esm/utils/components/HighlightText/HighlightText.d.ts +8 -0
  173. package/esm/utils/components/HighlightText/HighlightText.js +21 -0
  174. package/esm/utils/components/HighlightText/HighlightText.js.map +1 -0
  175. package/esm/utils/components/Listbox/group/ListboxGroup.d.ts +7 -0
  176. package/esm/utils/components/Listbox/group/ListboxGroup.js +10 -0
  177. package/esm/utils/components/Listbox/group/ListboxGroup.js.map +1 -0
  178. package/esm/utils/components/Listbox/input-slot/ListboxInputSlot.d.ts +7 -0
  179. package/esm/utils/components/Listbox/input-slot/ListboxInputSlot.js +9 -0
  180. package/esm/utils/components/Listbox/input-slot/ListboxInputSlot.js.map +1 -0
  181. package/esm/utils/components/Listbox/item/ListboxItem.d.ts +24 -0
  182. package/esm/utils/components/Listbox/item/ListboxItem.js +27 -0
  183. package/esm/utils/components/Listbox/item/ListboxItem.js.map +1 -0
  184. package/esm/utils/components/Listbox/list/ListboxList.d.ts +8 -0
  185. package/esm/utils/components/Listbox/list/ListboxList.js +27 -0
  186. package/esm/utils/components/Listbox/list/ListboxList.js.map +1 -0
  187. package/esm/utils/components/Listbox/root/ListboxRoot.d.ts +20 -0
  188. package/esm/utils/components/Listbox/root/ListboxRoot.js +79 -0
  189. package/esm/utils/components/Listbox/root/ListboxRoot.js.map +1 -0
  190. package/esm/utils/components/Listbox/root/domHelpers.d.ts +3 -0
  191. package/esm/utils/components/Listbox/root/domHelpers.js +50 -0
  192. package/esm/utils/components/Listbox/root/domHelpers.js.map +1 -0
  193. package/esm/utils/components/focus-boundary/FocusBoundary.js +8 -63
  194. package/esm/utils/components/focus-boundary/FocusBoundary.js.map +1 -1
  195. package/esm/utils/helpers/focus.d.ts +14 -0
  196. package/esm/utils/helpers/focus.js +60 -0
  197. package/esm/utils/helpers/focus.js.map +1 -0
  198. package/esm/utils/hooks/useDeferredValue.d.ts +1 -0
  199. package/esm/utils/hooks/useDeferredValue.js +7 -0
  200. package/esm/utils/hooks/useDeferredValue.js.map +1 -0
  201. package/package.json +7 -7
  202. package/src/data/drag-and-drop/item/DataDragAndDropItem.tsx +101 -0
  203. package/src/data/drag-and-drop/root/DataDragAndDrop.context.tsx +9 -0
  204. package/src/data/drag-and-drop/root/DataDragAndDropRoot.tsx +98 -0
  205. package/src/data/table/helpers/table-keyboard.ts +7 -3
  206. package/src/data/table/root/DataTableRoot.context.ts +13 -0
  207. package/src/data/table/root/DataTableRoot.tsx +16 -13
  208. package/src/data/table/th/DataTableTh.tsx +110 -54
  209. package/src/data/table/tr/DataTableTr.tsx +13 -2
  210. package/src/data/token-filter/AutoSuggest.tsx +142 -29
  211. package/src/data/token-filter/TokenFilter.tsx +174 -79
  212. package/src/data/token-filter/TokenFilter.types.ts +70 -42
  213. package/src/data/token-filter/helpers/generate-autocomplete-options.test.ts +97 -97
  214. package/src/data/token-filter/helpers/generate-autocomplete-options.ts +31 -38
  215. package/src/data/token-filter/helpers/operators.test.ts +29 -29
  216. package/src/data/token-filter/helpers/operators.ts +16 -16
  217. package/src/data/token-filter/helpers/parse-query-text.test.ts +37 -35
  218. package/src/data/token-filter/helpers/parse-query-text.ts +7 -26
  219. package/src/data/token-filter/helpers/query-builder.ts +2 -2
  220. package/src/date/Date.Dialog.tsx +15 -0
  221. package/src/date/datepicker/DatePicker.tsx +3 -0
  222. package/src/date/datepicker/hooks/useDatepicker.tsx +7 -2
  223. package/src/date/datepicker/hooks/useRangeDatepicker.tsx +5 -1
  224. package/src/date/datepicker/parts/DatePicker.Months.tsx +9 -1
  225. package/src/date/datepicker/parts/DatePicker.RDP.tsx +7 -1
  226. package/src/date/monthpicker/MonthPicker.tsx +3 -1
  227. package/src/date/monthpicker/hooks/useMonthPicker.tsx +5 -1
  228. package/src/date/monthpicker/parts/MonthPicker.Caption.tsx +20 -2
  229. package/src/dropdown/Toggle.tsx +6 -12
  230. package/src/form/combobox/Input/Input.tsx +2 -2
  231. package/src/inline-message/root/InlineMessage.tsx +5 -5
  232. package/src/provider/Provider.tsx +2 -2
  233. package/src/tooltip/Tooltip.tsx +1 -3
  234. package/src/utils/components/HighlightText/HighlightText.tsx +34 -0
  235. package/src/utils/components/Listbox/group/ListboxGroup.tsx +26 -0
  236. package/src/utils/components/Listbox/input-slot/ListboxInputSlot.tsx +22 -0
  237. package/src/utils/components/Listbox/item/ListboxItem.tsx +57 -0
  238. package/src/utils/components/Listbox/list/ListboxList.tsx +38 -0
  239. package/src/utils/components/Listbox/root/ListboxRoot.tsx +104 -0
  240. package/src/utils/components/Listbox/root/domHelpers.ts +59 -0
  241. package/src/utils/components/focus-boundary/FocusBoundary.tsx +8 -78
  242. package/src/utils/helpers/focus.ts +75 -0
  243. package/src/utils/hooks/useDeferredValue.ts +12 -0
  244. package/cjs/data/table/th/DataTableThSortHandle.d.ts +0 -6
  245. package/cjs/data/table/th/DataTableThSortHandle.js +0 -82
  246. package/cjs/data/table/th/DataTableThSortHandle.js.map +0 -1
  247. package/esm/data/table/th/DataTableThSortHandle.d.ts +0 -6
  248. package/esm/data/table/th/DataTableThSortHandle.js +0 -47
  249. package/esm/data/table/th/DataTableThSortHandle.js.map +0 -1
  250. package/src/data/table/th/DataTableThSortHandle.tsx +0 -67
@@ -0,0 +1,104 @@
1
+ /* eslint-disable jsx-a11y/no-static-element-interactions */
2
+ /** biome-ignore-all lint/a11y/noStaticElementInteractions: We know what we are doing */
3
+ import React from "react";
4
+ import { ListboxGroup } from "../group/ListboxGroup";
5
+ import { ListboxInputSlot } from "../input-slot/ListboxInputSlot";
6
+ import { ListboxItem } from "../item/ListboxItem";
7
+ import { ListboxList } from "../list/ListboxList";
8
+ import { findNextItem, findPrevItem } from "./domHelpers";
9
+
10
+ export interface ListboxProps {
11
+ children: React.ReactNode;
12
+ setVirtuallyFocusedItemId: (value: string) => void;
13
+ }
14
+
15
+ /**
16
+ * Low level component for displaying a list of selectable items with optional grouping.
17
+ * Keyboard navigation is implemented with virtual focus so that real focus can remain on an input field.
18
+ */
19
+ function Listbox({ children, setVirtuallyFocusedItemId }: ListboxProps) {
20
+ const virtuallyFocusItem = (element: HTMLElement | null) => {
21
+ setVirtuallyFocusedItemId(element?.dataset.id || "");
22
+ element?.scrollIntoView({ block: "nearest" });
23
+ };
24
+
25
+ return (
26
+ <div
27
+ onKeyDown={(event) => {
28
+ const listbox =
29
+ event.currentTarget.querySelector<HTMLElement>('[role="listbox"]');
30
+ if (!listbox) {
31
+ return;
32
+ }
33
+
34
+ // Helper functions
35
+ const getFirstItem = (suffix: string = "") =>
36
+ listbox.querySelector<HTMLElement>(`[role="option"]${suffix}`);
37
+ const getLastItem = () => {
38
+ const allItems =
39
+ listbox.querySelectorAll<HTMLElement>('[role="option"]');
40
+ return allItems[allItems.length - 1];
41
+ };
42
+
43
+ const focusedItemElm = getFirstItem('[data-virtual-focus="true"]');
44
+
45
+ // Doesn't make sense to have real focus on one item and virtual focus on another at the same time.
46
+ // Not sure if it matters, though 🤔
47
+ const itemElmWithRealFocus = getFirstItem(":focus");
48
+ if (itemElmWithRealFocus) {
49
+ listbox.focus();
50
+ }
51
+
52
+ const virtuallyFocusWithFallback = (
53
+ getNextElement: (currentItem: HTMLElement) => HTMLElement | null,
54
+ getFallback: () => HTMLElement | null,
55
+ ) => {
56
+ event.preventDefault();
57
+ if (!focusedItemElm) {
58
+ virtuallyFocusItem(getFallback());
59
+ return;
60
+ }
61
+ const nextItem = getNextElement(focusedItemElm);
62
+ if (!nextItem) {
63
+ virtuallyFocusItem(getFallback());
64
+ return;
65
+ }
66
+ virtuallyFocusItem(nextItem);
67
+ };
68
+
69
+ switch (event.key) {
70
+ case "ArrowDown":
71
+ virtuallyFocusWithFallback(findNextItem, getFirstItem);
72
+ break;
73
+ case "ArrowUp":
74
+ virtuallyFocusWithFallback(findPrevItem, getLastItem);
75
+ break;
76
+ case "Home":
77
+ event.preventDefault();
78
+ virtuallyFocusItem(getFirstItem());
79
+ break;
80
+ case "End":
81
+ event.preventDefault();
82
+ virtuallyFocusItem(getLastItem());
83
+ break;
84
+ case "Enter":
85
+ case "Accept":
86
+ if (focusedItemElm) {
87
+ focusedItemElm.click();
88
+ }
89
+ break;
90
+ // TODO: Consider implementing PageUp/PageDown too
91
+ }
92
+ }}
93
+ >
94
+ {children}
95
+ </div>
96
+ );
97
+ }
98
+
99
+ Listbox.InputSlot = ListboxInputSlot;
100
+ Listbox.List = ListboxList;
101
+ Listbox.Item = ListboxItem;
102
+ Listbox.Group = ListboxGroup;
103
+
104
+ export default Listbox;
@@ -0,0 +1,59 @@
1
+ function findNextItem(currentItem: HTMLElement) {
2
+ const nextElement = currentItem.nextElementSibling as HTMLElement | null;
3
+ if (nextElement) {
4
+ if (nextElement.role === "group") {
5
+ return nextElement.querySelector<HTMLElement>('[role="option"]');
6
+ }
7
+ if (nextElement.role === "option") {
8
+ return nextElement;
9
+ }
10
+ }
11
+
12
+ // No next element: Current element might be inside a group.
13
+ // Check if the parent has a next sibling
14
+ const parentNextElement = currentItem.parentElement
15
+ ?.nextElementSibling as HTMLElement | null;
16
+ if (parentNextElement) {
17
+ if (parentNextElement.role === "group") {
18
+ return parentNextElement.querySelector<HTMLElement>('[role="option"]');
19
+ }
20
+ if (parentNextElement.role === "option") {
21
+ return parentNextElement;
22
+ }
23
+ }
24
+
25
+ return null;
26
+ }
27
+
28
+ function findPrevItem(currentItem: HTMLElement) {
29
+ const prevElement = currentItem.previousElementSibling as HTMLElement | null;
30
+ if (prevElement) {
31
+ if (prevElement.role === "group") {
32
+ return prevElement.querySelector<HTMLElement>(
33
+ '[role="option"]:last-of-type',
34
+ );
35
+ }
36
+ if (prevElement.role === "option") {
37
+ return prevElement;
38
+ }
39
+ }
40
+
41
+ // No previous element: Current element might be inside a group.
42
+ // Check if the parent has a previous sibling.
43
+ const parentPrevElement = currentItem.parentElement
44
+ ?.previousElementSibling as HTMLElement | null;
45
+ if (parentPrevElement) {
46
+ if (parentPrevElement.role === "group") {
47
+ return parentPrevElement.querySelector<HTMLElement>(
48
+ '[role="option"]:last-of-type',
49
+ );
50
+ }
51
+ if (parentPrevElement.role === "option") {
52
+ return parentPrevElement;
53
+ }
54
+ }
55
+
56
+ return null;
57
+ }
58
+
59
+ export { findNextItem, findPrevItem };
@@ -11,6 +11,7 @@ import {
11
11
  ownerDocument,
12
12
  resolveRef,
13
13
  } from "../../helpers";
14
+ import { focusElement, getTabbableCandidates } from "../../helpers/focus";
14
15
  import { useMergeRefs } from "../../hooks";
15
16
  import { useValueAsRef } from "../../hooks/useValueAsRef";
16
17
  import { Slot } from "../slot/Slot";
@@ -118,7 +119,7 @@ const FocusBoundary = forwardRef<HTMLDivElement, FocusBoundaryProps>(
118
119
  if (container.contains(target)) {
119
120
  lastFocusedElementRef.current = target;
120
121
  } else {
121
- focus(lastFocusedElementRef.current, { select: true });
122
+ focusElement(lastFocusedElementRef.current, { select: true });
122
123
  }
123
124
  }
124
125
 
@@ -150,7 +151,7 @@ const FocusBoundary = forwardRef<HTMLDivElement, FocusBoundaryProps>(
150
151
  * when they are not supposed to (like when clicking on elements outside the container
151
152
  */
152
153
  if (!container.contains(relatedTarget)) {
153
- focus(lastFocusedElementRef.current, { select: true });
154
+ focusElement(lastFocusedElementRef.current, { select: true });
154
155
  }
155
156
  }
156
157
 
@@ -165,7 +166,7 @@ const FocusBoundary = forwardRef<HTMLDivElement, FocusBoundaryProps>(
165
166
  }
166
167
 
167
168
  if (mutations.some((mutation) => mutation.removedNodes.length > 0)) {
168
- focus(container);
169
+ focusElement(container);
169
170
  }
170
171
  };
171
172
 
@@ -230,7 +231,7 @@ const FocusBoundary = forwardRef<HTMLDivElement, FocusBoundaryProps>(
230
231
  const previouslyFocusedElement = ownerDoc.activeElement;
231
232
 
232
233
  queueMicrotask(() => {
233
- const focusableElements = removeLinks(getTabbableCandidates(container));
234
+ const focusableElements = getTabbableCandidates(container);
234
235
  const initialFocusValueOrFn = initialFocusRef.current;
235
236
  const resolvedInitialFocus =
236
237
  typeof initialFocusValueOrFn === "function"
@@ -262,7 +263,7 @@ const FocusBoundary = forwardRef<HTMLDivElement, FocusBoundaryProps>(
262
263
  return;
263
264
  }
264
265
 
265
- focus(elToFocus, {
266
+ focusElement(elToFocus, {
266
267
  preventScroll: elToFocus === container,
267
268
  sync: false,
268
269
  });
@@ -361,12 +362,12 @@ const FocusBoundary = forwardRef<HTMLDivElement, FocusBoundaryProps>(
361
362
  if (!event.shiftKey && focusedElement === last) {
362
363
  event.preventDefault();
363
364
  if (loop) {
364
- focus(first, { select: true });
365
+ focusElement(first, { select: true });
365
366
  }
366
367
  } else if (event.shiftKey && focusedElement === first) {
367
368
  event.preventDefault();
368
369
  if (loop) {
369
- focus(last, { select: true });
370
+ focusElement(last, { select: true });
370
371
  }
371
372
  }
372
373
  }
@@ -398,40 +399,6 @@ function getTabbableEdges(container: HTMLElement) {
398
399
  ] as const;
399
400
  }
400
401
 
401
- /**
402
- * Returns a list of potential tabbable candidates.
403
- * We do not take into account tabindex values.
404
- *
405
- * See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker
406
- * Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1
407
- */
408
- function getTabbableCandidates(container: HTMLElement) {
409
- const nodes: HTMLElement[] = [];
410
- const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
411
- acceptNode: (node: any) => {
412
- const isHiddenInput = node.tagName === "INPUT" && node.type === "hidden";
413
- if (node.disabled || node.hidden || isHiddenInput) {
414
- return NodeFilter.FILTER_SKIP;
415
- }
416
-
417
- /**
418
- * `.tabIndex` is not the same as the `tabindex` attribute. It works on the
419
- * runtime's understanding of tabbability, so this automatically accounts
420
- * for any kind of element that could be tabbed to.
421
- */
422
- return node.tabIndex >= 0
423
- ? NodeFilter.FILTER_ACCEPT
424
- : NodeFilter.FILTER_SKIP;
425
- },
426
- });
427
-
428
- while (walker.nextNode()) {
429
- nodes.push(walker.currentNode as HTMLElement);
430
- }
431
-
432
- return nodes;
433
- }
434
-
435
402
  /**
436
403
  * Returns the first visible element in a list.
437
404
  * NOTE: Only checks visibility up to the `container`.
@@ -462,39 +429,6 @@ function isHidden(node: HTMLElement, { upTo }: { upTo?: HTMLElement }) {
462
429
  return false;
463
430
  }
464
431
 
465
- let rafId = 0;
466
- function focus(
467
- element?: HTMLElement | null,
468
- { select = false, preventScroll = true, sync = true } = {},
469
- ) {
470
- if (!element?.focus) {
471
- return;
472
- }
473
-
474
- const previouslyFocusedElement = document.activeElement;
475
-
476
- cancelAnimationFrame(rafId);
477
- const exec = () => element.focus({ preventScroll });
478
-
479
- if (sync) {
480
- exec();
481
- } else {
482
- rafId = requestAnimationFrame(exec);
483
- }
484
-
485
- if (!select) {
486
- return;
487
- }
488
-
489
- /* By default, inputs that gets focus should select its contents */
490
- if (
491
- element !== previouslyFocusedElement &&
492
- element instanceof HTMLInputElement &&
493
- "select" in element
494
- )
495
- element.select();
496
- }
497
-
498
432
  /* ---------------------------- FocusBoundary stack ---------------------------- */
499
433
  type FocusBoundaryAPI = { paused: boolean; pause(): void; resume(): void };
500
434
  const focusBoundarysStack = createFocusBoundarysStack();
@@ -531,10 +465,6 @@ function arrayRemove<T>(array: T[], item: T) {
531
465
  return updatedArray;
532
466
  }
533
467
 
534
- function removeLinks(items: HTMLElement[]) {
535
- return items.filter((item) => item.tagName !== "A");
536
- }
537
-
538
468
  const LIST_LIMIT = 10;
539
469
  let previouslyFocusedElements: Element[] = [];
540
470
  const focusedElementsByContainer = new WeakMap<Element, Element[]>();
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Returns a list of potential tabbable candidates.
3
+ * We do not take into account tabindex values.
4
+ *
5
+ * See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker
6
+ * Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1
7
+ */
8
+ function getTabbableCandidates(container: HTMLElement) {
9
+ const nodes: HTMLElement[] = [];
10
+ const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
11
+ acceptNode: (node: any) => {
12
+ const isHiddenInput = node.tagName === "INPUT" && node.type === "hidden";
13
+ if (node.disabled || node.hidden || isHiddenInput) {
14
+ return NodeFilter.FILTER_SKIP;
15
+ }
16
+
17
+ /**
18
+ * `.tabIndex` is not the same as the `tabindex` attribute. It works on the
19
+ * runtime's understanding of tabbability, so this automatically accounts
20
+ * for any kind of element that could be tabbed to.
21
+ */
22
+ return node.tabIndex >= 0
23
+ ? NodeFilter.FILTER_ACCEPT
24
+ : NodeFilter.FILTER_SKIP;
25
+ },
26
+ });
27
+
28
+ while (walker.nextNode()) {
29
+ nodes.push(walker.currentNode as HTMLElement);
30
+ }
31
+
32
+ return removeLinks(nodes);
33
+ }
34
+
35
+ function removeLinks(items: HTMLElement[]) {
36
+ return items.filter((item) => item.tagName !== "A");
37
+ }
38
+
39
+ let rafId = 0;
40
+
41
+ function focusElement(
42
+ element?: HTMLElement | null,
43
+ { select = false, preventScroll = true, sync = true } = {},
44
+ ) {
45
+ if (!element?.focus) {
46
+ return;
47
+ }
48
+
49
+ const previouslyFocusedElement = document.activeElement;
50
+
51
+ cancelAnimationFrame(rafId);
52
+ const exec = () => {
53
+ element.focus({ preventScroll });
54
+ };
55
+
56
+ if (sync) {
57
+ exec();
58
+ } else {
59
+ rafId = requestAnimationFrame(exec);
60
+ }
61
+
62
+ if (!select) {
63
+ return;
64
+ }
65
+
66
+ /* By default, inputs that gets focus should select its contents */
67
+ if (
68
+ element !== previouslyFocusedElement &&
69
+ element instanceof HTMLInputElement &&
70
+ "select" in element
71
+ )
72
+ element.select();
73
+ }
74
+
75
+ export { getTabbableCandidates, focusElement };
@@ -0,0 +1,12 @@
1
+ import React from "react";
2
+
3
+ const maybeReactUseDeferredValue: undefined | ((string: string) => string) = (
4
+ React as any
5
+ )[
6
+ "useDeferredValue" + "" // Workaround for https://github.com/webpack/webpack/issues/14814
7
+ ];
8
+
9
+ export const useDeferredValue = (value: string): string =>
10
+ maybeReactUseDeferredValue !== undefined
11
+ ? maybeReactUseDeferredValue(value)
12
+ : value;
@@ -1,6 +0,0 @@
1
- import React from "react";
2
- declare function DataTableThSortHandle({ sortDirection, onSortChange, }: {
3
- sortDirection?: "asc" | "desc" | "none" | false;
4
- onSortChange?: (direction: "asc" | "desc" | "none", event: Event) => void;
5
- }): React.JSX.Element | null;
6
- export { DataTableThSortHandle };
@@ -1,82 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.DataTableThSortHandle = DataTableThSortHandle;
37
- const react_1 = __importStar(require("react"));
38
- const aksel_icons_1 = require("@navikt/aksel-icons");
39
- const button_1 = require("../../../button");
40
- const ICON_CONFIG = {
41
- desc: {
42
- icon: aksel_icons_1.SortDownIcon,
43
- title: "Sorter stigende",
44
- },
45
- asc: {
46
- icon: aksel_icons_1.SortUpIcon,
47
- title: "Ingen sortering",
48
- },
49
- none: {
50
- icon: aksel_icons_1.ArrowsUpDownIcon,
51
- title: "Sorter synkende",
52
- },
53
- };
54
- function DataTableThSortHandle({ sortDirection = false, onSortChange, }) {
55
- const IconConfig = (0, react_1.useMemo)(() => {
56
- if (!sortDirection) {
57
- return null;
58
- }
59
- return ICON_CONFIG[sortDirection];
60
- }, [sortDirection]);
61
- if (!sortDirection || !IconConfig) {
62
- return null;
63
- }
64
- return (react_1.default.createElement(button_1.Button, { "data-color": "neutral", variant: "tertiary", size: "small", icon: react_1.default.createElement(IconConfig.icon, { title: IconConfig.title }), onClick: (event) => {
65
- if (!onSortChange)
66
- return;
67
- /* TODO: This configuration is not a given */
68
- let newDirection;
69
- if (sortDirection === "none") {
70
- newDirection = "asc";
71
- }
72
- else if (sortDirection === "asc") {
73
- newDirection = "desc";
74
- }
75
- else {
76
- newDirection = "none";
77
- }
78
- /* TODO: Handle types better */
79
- onSortChange(newDirection, event);
80
- } }));
81
- }
82
- //# sourceMappingURL=DataTableThSortHandle.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DataTableThSortHandle.js","sourceRoot":"","sources":["../../../../src/data/table/th/DataTableThSortHandle.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkES,sDAAqB;AAlE9B,+CAAuC;AACvC,qDAI6B;AAC7B,4CAAyC;AAEzC,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE;QACJ,IAAI,EAAE,0BAAY;QAClB,KAAK,EAAE,iBAAiB;KACzB;IACD,GAAG,EAAE;QACH,IAAI,EAAE,wBAAU;QAChB,KAAK,EAAE,iBAAiB;KACzB;IACD,IAAI,EAAE;QACJ,IAAI,EAAE,8BAAgB;QACtB,KAAK,EAAE,iBAAiB;KACzB;CACF,CAAC;AAEF,SAAS,qBAAqB,CAAC,EAC7B,aAAa,GAAG,KAAK,EACrB,YAAY,GAIb;IACC,MAAM,UAAU,GAAG,IAAA,eAAO,EAAC,GAAG,EAAE;QAC9B,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,WAAW,CAAC,aAAa,CAAC,CAAC;IACpC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC;IAEpB,IAAI,CAAC,aAAa,IAAI,CAAC,UAAU,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CACL,8BAAC,eAAM,kBACM,SAAS,EACpB,OAAO,EAAC,UAAU,EAClB,IAAI,EAAC,OAAO,EACZ,IAAI,EAAE,8BAAC,UAAU,CAAC,IAAI,IAAC,KAAK,EAAE,UAAU,CAAC,KAAK,GAAI,EAClD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YACjB,IAAI,CAAC,YAAY;gBAAE,OAAO;YAE1B,6CAA6C;YAC7C,IAAI,YAAqC,CAAC;YAC1C,IAAI,aAAa,KAAK,MAAM,EAAE,CAAC;gBAC7B,YAAY,GAAG,KAAK,CAAC;YACvB,CAAC;iBAAM,IAAI,aAAa,KAAK,KAAK,EAAE,CAAC;gBACnC,YAAY,GAAG,MAAM,CAAC;YACxB,CAAC;iBAAM,CAAC;gBACN,YAAY,GAAG,MAAM,CAAC;YACxB,CAAC;YACD,+BAA+B;YAC/B,YAAY,CAAC,YAAY,EAAE,KAAyB,CAAC,CAAC;QACxD,CAAC,GACD,CACH,CAAC;AACJ,CAAC"}
@@ -1,6 +0,0 @@
1
- import React from "react";
2
- declare function DataTableThSortHandle({ sortDirection, onSortChange, }: {
3
- sortDirection?: "asc" | "desc" | "none" | false;
4
- onSortChange?: (direction: "asc" | "desc" | "none", event: Event) => void;
5
- }): React.JSX.Element | null;
6
- export { DataTableThSortHandle };
@@ -1,47 +0,0 @@
1
- import React, { useMemo } from "react";
2
- import { ArrowsUpDownIcon, SortDownIcon, SortUpIcon, } from "@navikt/aksel-icons";
3
- import { Button } from "../../../button/index.js";
4
- const ICON_CONFIG = {
5
- desc: {
6
- icon: SortDownIcon,
7
- title: "Sorter stigende",
8
- },
9
- asc: {
10
- icon: SortUpIcon,
11
- title: "Ingen sortering",
12
- },
13
- none: {
14
- icon: ArrowsUpDownIcon,
15
- title: "Sorter synkende",
16
- },
17
- };
18
- function DataTableThSortHandle({ sortDirection = false, onSortChange, }) {
19
- const IconConfig = useMemo(() => {
20
- if (!sortDirection) {
21
- return null;
22
- }
23
- return ICON_CONFIG[sortDirection];
24
- }, [sortDirection]);
25
- if (!sortDirection || !IconConfig) {
26
- return null;
27
- }
28
- return (React.createElement(Button, { "data-color": "neutral", variant: "tertiary", size: "small", icon: React.createElement(IconConfig.icon, { title: IconConfig.title }), onClick: (event) => {
29
- if (!onSortChange)
30
- return;
31
- /* TODO: This configuration is not a given */
32
- let newDirection;
33
- if (sortDirection === "none") {
34
- newDirection = "asc";
35
- }
36
- else if (sortDirection === "asc") {
37
- newDirection = "desc";
38
- }
39
- else {
40
- newDirection = "none";
41
- }
42
- /* TODO: Handle types better */
43
- onSortChange(newDirection, event);
44
- } }));
45
- }
46
- export { DataTableThSortHandle };
47
- //# sourceMappingURL=DataTableThSortHandle.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DataTableThSortHandle.js","sourceRoot":"","sources":["../../../../src/data/table/th/DataTableThSortHandle.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,UAAU,GACX,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,iBAAiB;KACzB;IACD,GAAG,EAAE;QACH,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,iBAAiB;KACzB;IACD,IAAI,EAAE;QACJ,IAAI,EAAE,gBAAgB;QACtB,KAAK,EAAE,iBAAiB;KACzB;CACF,CAAC;AAEF,SAAS,qBAAqB,CAAC,EAC7B,aAAa,GAAG,KAAK,EACrB,YAAY,GAIb;IACC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE;QAC9B,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,WAAW,CAAC,aAAa,CAAC,CAAC;IACpC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC;IAEpB,IAAI,CAAC,aAAa,IAAI,CAAC,UAAU,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CACL,oBAAC,MAAM,kBACM,SAAS,EACpB,OAAO,EAAC,UAAU,EAClB,IAAI,EAAC,OAAO,EACZ,IAAI,EAAE,oBAAC,UAAU,CAAC,IAAI,IAAC,KAAK,EAAE,UAAU,CAAC,KAAK,GAAI,EAClD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YACjB,IAAI,CAAC,YAAY;gBAAE,OAAO;YAE1B,6CAA6C;YAC7C,IAAI,YAAqC,CAAC;YAC1C,IAAI,aAAa,KAAK,MAAM,EAAE,CAAC;gBAC7B,YAAY,GAAG,KAAK,CAAC;YACvB,CAAC;iBAAM,IAAI,aAAa,KAAK,KAAK,EAAE,CAAC;gBACnC,YAAY,GAAG,MAAM,CAAC;YACxB,CAAC;iBAAM,CAAC;gBACN,YAAY,GAAG,MAAM,CAAC;YACxB,CAAC;YACD,+BAA+B;YAC/B,YAAY,CAAC,YAAY,EAAE,KAAyB,CAAC,CAAC;QACxD,CAAC,GACD,CACH,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
@@ -1,67 +0,0 @@
1
- import React, { useMemo } from "react";
2
- import {
3
- ArrowsUpDownIcon,
4
- SortDownIcon,
5
- SortUpIcon,
6
- } from "@navikt/aksel-icons";
7
- import { Button } from "../../../button";
8
-
9
- const ICON_CONFIG = {
10
- desc: {
11
- icon: SortDownIcon,
12
- title: "Sorter stigende",
13
- },
14
- asc: {
15
- icon: SortUpIcon,
16
- title: "Ingen sortering",
17
- },
18
- none: {
19
- icon: ArrowsUpDownIcon,
20
- title: "Sorter synkende",
21
- },
22
- };
23
-
24
- function DataTableThSortHandle({
25
- sortDirection = false,
26
- onSortChange,
27
- }: {
28
- sortDirection?: "asc" | "desc" | "none" | false;
29
- onSortChange?: (direction: "asc" | "desc" | "none", event: Event) => void;
30
- }) {
31
- const IconConfig = useMemo(() => {
32
- if (!sortDirection) {
33
- return null;
34
- }
35
- return ICON_CONFIG[sortDirection];
36
- }, [sortDirection]);
37
-
38
- if (!sortDirection || !IconConfig) {
39
- return null;
40
- }
41
-
42
- return (
43
- <Button
44
- data-color="neutral"
45
- variant="tertiary"
46
- size="small"
47
- icon={<IconConfig.icon title={IconConfig.title} />}
48
- onClick={(event) => {
49
- if (!onSortChange) return;
50
-
51
- /* TODO: This configuration is not a given */
52
- let newDirection: "asc" | "desc" | "none";
53
- if (sortDirection === "none") {
54
- newDirection = "asc";
55
- } else if (sortDirection === "asc") {
56
- newDirection = "desc";
57
- } else {
58
- newDirection = "none";
59
- }
60
- /* TODO: Handle types better */
61
- onSortChange(newDirection, event as unknown as Event);
62
- }}
63
- />
64
- );
65
- }
66
-
67
- export { DataTableThSortHandle };