@navikt/ds-react 8.8.0 → 8.9.1

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 (228) hide show
  1. package/cjs/data/drag-and-drop/drag-handler/DragAndDropDragHandler.d.ts +13 -0
  2. package/cjs/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js +59 -0
  3. package/cjs/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js.map +1 -0
  4. package/cjs/data/drag-and-drop/item/DragAndDropItem.d.ts +31 -0
  5. package/cjs/data/drag-and-drop/item/DragAndDropItem.js +48 -0
  6. package/cjs/data/drag-and-drop/item/DragAndDropItem.js.map +1 -0
  7. package/cjs/data/drag-and-drop/root/DragAndDrop.context.d.ts +17 -0
  8. package/cjs/data/drag-and-drop/root/DragAndDrop.context.js +10 -0
  9. package/cjs/data/drag-and-drop/root/DragAndDrop.context.js.map +1 -0
  10. package/cjs/data/drag-and-drop/root/DragAndDropRoot.d.ts +38 -0
  11. package/cjs/data/drag-and-drop/root/DragAndDropRoot.js +219 -0
  12. package/cjs/data/drag-and-drop/root/DragAndDropRoot.js.map +1 -0
  13. package/cjs/data/drag-and-drop/types.d.ts +4 -0
  14. package/cjs/data/drag-and-drop/types.js +3 -0
  15. package/cjs/data/drag-and-drop/types.js.map +1 -0
  16. package/cjs/data/table/helpers/selection/getMultipleSelectProps.d.ts +14 -0
  17. package/cjs/data/table/helpers/selection/getMultipleSelectProps.js +48 -0
  18. package/cjs/data/table/helpers/selection/getMultipleSelectProps.js.map +1 -0
  19. package/cjs/data/table/helpers/selection/getSingleSelectProps.d.ts +10 -0
  20. package/cjs/data/table/helpers/selection/getSingleSelectProps.js +26 -0
  21. package/cjs/data/table/helpers/selection/getSingleSelectProps.js.map +1 -0
  22. package/cjs/data/table/helpers/selection/selection.types.d.ts +42 -0
  23. package/cjs/data/table/helpers/selection/selection.types.js +3 -0
  24. package/cjs/data/table/helpers/selection/selection.types.js.map +1 -0
  25. package/cjs/data/table/{root → hooks}/useTableKeyboardNav.js +1 -1
  26. package/cjs/data/table/hooks/useTableKeyboardNav.js.map +1 -0
  27. package/cjs/data/table/hooks/useTableSelection.d.ts +8 -0
  28. package/cjs/data/table/hooks/useTableSelection.js +49 -0
  29. package/cjs/data/table/hooks/useTableSelection.js.map +1 -0
  30. package/cjs/data/table/root/DataTableAuto.d.ts +4 -4
  31. package/cjs/data/table/root/DataTableAuto.js +23 -11
  32. package/cjs/data/table/root/DataTableAuto.js.map +1 -1
  33. package/cjs/data/table/root/DataTableRoot.d.ts +1 -1
  34. package/cjs/data/table/root/DataTableRoot.js +1 -1
  35. package/cjs/data/table/root/DataTableRoot.js.map +1 -1
  36. package/cjs/data/table/td/DataTableTd.d.ts +4 -0
  37. package/cjs/data/table/td/DataTableTd.js +4 -2
  38. package/cjs/data/table/td/DataTableTd.js.map +1 -1
  39. package/cjs/data/table/th/DataTableTh.d.ts +4 -0
  40. package/cjs/data/table/th/DataTableTh.js +6 -3
  41. package/cjs/data/table/th/DataTableTh.js.map +1 -1
  42. package/cjs/data/token-filter/AutoSuggest.js +37 -4
  43. package/cjs/data/token-filter/AutoSuggest.js.map +1 -1
  44. package/cjs/data/token-filter/FilterChip.d.ts +10 -0
  45. package/cjs/data/token-filter/FilterChip.js +65 -0
  46. package/cjs/data/token-filter/FilterChip.js.map +1 -0
  47. package/cjs/data/token-filter/TokenFilter.d.ts +1 -0
  48. package/cjs/data/token-filter/TokenFilter.js +4 -10
  49. package/cjs/data/token-filter/TokenFilter.js.map +1 -1
  50. package/cjs/data/toolbar/root/DataToolbarRoot.d.ts +6 -23
  51. package/cjs/data/toolbar/root/DataToolbarRoot.js +42 -7
  52. package/cjs/data/toolbar/root/DataToolbarRoot.js.map +1 -1
  53. package/cjs/date/Date.Input.js +8 -9
  54. package/cjs/date/Date.Input.js.map +1 -1
  55. package/cjs/date/datepicker/hooks/useDatepicker.js +4 -3
  56. package/cjs/date/datepicker/hooks/useDatepicker.js.map +1 -1
  57. package/cjs/date/monthpicker/hooks/useMonthPicker.js +3 -2
  58. package/cjs/date/monthpicker/hooks/useMonthPicker.js.map +1 -1
  59. package/cjs/form/checkbox/Checkbox.js +19 -33
  60. package/cjs/form/checkbox/Checkbox.js.map +1 -1
  61. package/cjs/form/checkbox/checkbox-input/CheckboxInput.d.ts +21 -0
  62. package/cjs/form/checkbox/checkbox-input/CheckboxInput.js +65 -0
  63. package/cjs/form/checkbox/checkbox-input/CheckboxInput.js.map +1 -0
  64. package/cjs/form/checkbox/types.d.ts +1 -1
  65. package/cjs/form/fieldset/Fieldset.js +2 -6
  66. package/cjs/form/fieldset/Fieldset.js.map +1 -1
  67. package/cjs/form/radio/Radio.js +9 -7
  68. package/cjs/form/radio/Radio.js.map +1 -1
  69. package/cjs/form/radio/radio-input/RadioInput.d.ts +19 -0
  70. package/cjs/{data/drag-and-drop/root/DataDragAndDropRoot.js → form/radio/radio-input/RadioInput.js} +17 -23
  71. package/cjs/form/radio/radio-input/RadioInput.js.map +1 -0
  72. package/cjs/internal-header/InternalHeaderButton.d.ts +5 -0
  73. package/cjs/internal-header/InternalHeaderButton.js +2 -2
  74. package/cjs/internal-header/InternalHeaderButton.js.map +1 -1
  75. package/cjs/utils/components/Listbox/group/ListboxGroup.js +2 -1
  76. package/cjs/utils/components/Listbox/group/ListboxGroup.js.map +1 -1
  77. package/esm/data/drag-and-drop/drag-handler/DragAndDropDragHandler.d.ts +13 -0
  78. package/esm/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js +53 -0
  79. package/esm/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js.map +1 -0
  80. package/esm/data/drag-and-drop/item/DragAndDropItem.d.ts +31 -0
  81. package/esm/data/drag-and-drop/item/DragAndDropItem.js +42 -0
  82. package/esm/data/drag-and-drop/item/DragAndDropItem.js.map +1 -0
  83. package/esm/data/drag-and-drop/root/DragAndDrop.context.d.ts +17 -0
  84. package/esm/data/drag-and-drop/root/DragAndDrop.context.js +6 -0
  85. package/esm/data/drag-and-drop/root/DragAndDrop.context.js.map +1 -0
  86. package/esm/data/drag-and-drop/root/DragAndDropRoot.d.ts +38 -0
  87. package/esm/data/drag-and-drop/root/DragAndDropRoot.js +179 -0
  88. package/esm/data/drag-and-drop/root/DragAndDropRoot.js.map +1 -0
  89. package/esm/data/drag-and-drop/types.d.ts +4 -0
  90. package/esm/data/drag-and-drop/types.js +2 -0
  91. package/esm/data/drag-and-drop/types.js.map +1 -0
  92. package/esm/data/table/helpers/selection/getMultipleSelectProps.d.ts +14 -0
  93. package/esm/data/table/helpers/selection/getMultipleSelectProps.js +46 -0
  94. package/esm/data/table/helpers/selection/getMultipleSelectProps.js.map +1 -0
  95. package/esm/data/table/helpers/selection/getSingleSelectProps.d.ts +10 -0
  96. package/esm/data/table/helpers/selection/getSingleSelectProps.js +24 -0
  97. package/esm/data/table/helpers/selection/getSingleSelectProps.js.map +1 -0
  98. package/esm/data/table/helpers/selection/selection.types.d.ts +42 -0
  99. package/esm/data/table/helpers/selection/selection.types.js +2 -0
  100. package/esm/data/table/helpers/selection/selection.types.js.map +1 -0
  101. package/esm/data/table/{root → hooks}/useTableKeyboardNav.js +1 -1
  102. package/esm/data/table/hooks/useTableKeyboardNav.js.map +1 -0
  103. package/esm/data/table/hooks/useTableSelection.d.ts +8 -0
  104. package/esm/data/table/hooks/useTableSelection.js +47 -0
  105. package/esm/data/table/hooks/useTableSelection.js.map +1 -0
  106. package/esm/data/table/root/DataTableAuto.d.ts +4 -4
  107. package/esm/data/table/root/DataTableAuto.js +23 -11
  108. package/esm/data/table/root/DataTableAuto.js.map +1 -1
  109. package/esm/data/table/root/DataTableRoot.d.ts +1 -1
  110. package/esm/data/table/root/DataTableRoot.js +1 -1
  111. package/esm/data/table/root/DataTableRoot.js.map +1 -1
  112. package/esm/data/table/td/DataTableTd.d.ts +4 -0
  113. package/esm/data/table/td/DataTableTd.js +4 -2
  114. package/esm/data/table/td/DataTableTd.js.map +1 -1
  115. package/esm/data/table/th/DataTableTh.d.ts +4 -0
  116. package/esm/data/table/th/DataTableTh.js +6 -3
  117. package/esm/data/table/th/DataTableTh.js.map +1 -1
  118. package/esm/data/token-filter/AutoSuggest.js +38 -5
  119. package/esm/data/token-filter/AutoSuggest.js.map +1 -1
  120. package/esm/data/token-filter/FilterChip.d.ts +10 -0
  121. package/esm/data/token-filter/FilterChip.js +30 -0
  122. package/esm/data/token-filter/FilterChip.js.map +1 -0
  123. package/esm/data/token-filter/TokenFilter.d.ts +1 -0
  124. package/esm/data/token-filter/TokenFilter.js +4 -10
  125. package/esm/data/token-filter/TokenFilter.js.map +1 -1
  126. package/esm/data/toolbar/root/DataToolbarRoot.d.ts +6 -23
  127. package/esm/data/toolbar/root/DataToolbarRoot.js +9 -7
  128. package/esm/data/toolbar/root/DataToolbarRoot.js.map +1 -1
  129. package/esm/date/Date.Input.js +9 -10
  130. package/esm/date/Date.Input.js.map +1 -1
  131. package/esm/date/datepicker/hooks/useDatepicker.js +4 -3
  132. package/esm/date/datepicker/hooks/useDatepicker.js.map +1 -1
  133. package/esm/date/monthpicker/hooks/useMonthPicker.js +3 -2
  134. package/esm/date/monthpicker/hooks/useMonthPicker.js.map +1 -1
  135. package/esm/form/checkbox/Checkbox.js +19 -33
  136. package/esm/form/checkbox/Checkbox.js.map +1 -1
  137. package/esm/form/checkbox/checkbox-input/CheckboxInput.d.ts +21 -0
  138. package/esm/form/checkbox/checkbox-input/CheckboxInput.js +29 -0
  139. package/esm/form/checkbox/checkbox-input/CheckboxInput.js.map +1 -0
  140. package/esm/form/checkbox/types.d.ts +1 -1
  141. package/esm/form/fieldset/Fieldset.js +2 -6
  142. package/esm/form/fieldset/Fieldset.js.map +1 -1
  143. package/esm/form/radio/Radio.js +9 -7
  144. package/esm/form/radio/Radio.js.map +1 -1
  145. package/esm/form/radio/radio-input/RadioInput.d.ts +19 -0
  146. package/esm/form/radio/radio-input/RadioInput.js +19 -0
  147. package/esm/form/radio/radio-input/RadioInput.js.map +1 -0
  148. package/esm/internal-header/InternalHeaderButton.d.ts +5 -0
  149. package/esm/internal-header/InternalHeaderButton.js +2 -2
  150. package/esm/internal-header/InternalHeaderButton.js.map +1 -1
  151. package/esm/utils/components/Listbox/group/ListboxGroup.js +2 -1
  152. package/esm/utils/components/Listbox/group/ListboxGroup.js.map +1 -1
  153. package/package.json +4 -4
  154. package/src/data/drag-and-drop/drag-handler/DragAndDropDragHandler.tsx +94 -0
  155. package/src/data/drag-and-drop/item/DragAndDropItem.tsx +75 -0
  156. package/src/data/drag-and-drop/root/DragAndDrop.context.tsx +27 -0
  157. package/src/data/drag-and-drop/root/DragAndDropRoot.tsx +294 -0
  158. package/src/data/drag-and-drop/types.ts +4 -0
  159. package/src/data/table/helpers/selection/getMultipleSelectProps.ts +70 -0
  160. package/src/data/table/helpers/selection/getSingleSelectProps.ts +36 -0
  161. package/src/data/table/helpers/selection/selection.types.ts +56 -0
  162. package/src/data/table/hooks/__tests__/useTableSelection.test.ts +327 -0
  163. package/src/data/table/{root → hooks}/useTableKeyboardNav.ts +1 -1
  164. package/src/data/table/hooks/useTableSelection.ts +78 -0
  165. package/src/data/table/root/DataTableAuto.tsx +58 -25
  166. package/src/data/table/root/DataTableRoot.tsx +2 -2
  167. package/src/data/table/td/DataTableTd.tsx +15 -2
  168. package/src/data/table/th/DataTableTh.tsx +13 -2
  169. package/src/data/token-filter/AutoSuggest.tsx +65 -3
  170. package/src/data/token-filter/FilterChip.tsx +100 -0
  171. package/src/data/token-filter/TokenFilter.tsx +9 -24
  172. package/src/data/toolbar/root/DataToolbarRoot.tsx +29 -32
  173. package/src/date/Date.Input.tsx +17 -16
  174. package/src/date/datepicker/hooks/useDatepicker.tsx +4 -5
  175. package/src/date/monthpicker/hooks/useMonthPicker.tsx +3 -4
  176. package/src/form/checkbox/Checkbox.tsx +37 -64
  177. package/src/form/checkbox/checkbox-input/CheckboxInput.tsx +69 -0
  178. package/src/form/checkbox/types.ts +1 -1
  179. package/src/form/fieldset/Fieldset.tsx +4 -6
  180. package/src/form/radio/Radio.tsx +43 -38
  181. package/src/form/radio/radio-input/RadioInput.tsx +32 -0
  182. package/src/internal-header/InternalHeaderButton.tsx +18 -9
  183. package/src/utils/components/Listbox/group/ListboxGroup.tsx +9 -2
  184. package/cjs/data/action-bar/root/DataActionBarRoot.d.ts +0 -27
  185. package/cjs/data/action-bar/root/DataActionBarRoot.js +0 -49
  186. package/cjs/data/action-bar/root/DataActionBarRoot.js.map +0 -1
  187. package/cjs/data/drag-and-drop/drag-handler/DataDragAndDropDragHandler.d.ts +0 -21
  188. package/cjs/data/drag-and-drop/drag-handler/DataDragAndDropDragHandler.js +0 -24
  189. package/cjs/data/drag-and-drop/drag-handler/DataDragAndDropDragHandler.js.map +0 -1
  190. package/cjs/data/drag-and-drop/item/DataDragAndDropItem.d.ts +0 -27
  191. package/cjs/data/drag-and-drop/item/DataDragAndDropItem.js +0 -41
  192. package/cjs/data/drag-and-drop/item/DataDragAndDropItem.js.map +0 -1
  193. package/cjs/data/drag-and-drop/root/DataDragAndDrop.context.d.ts +0 -8
  194. package/cjs/data/drag-and-drop/root/DataDragAndDrop.context.js +0 -10
  195. package/cjs/data/drag-and-drop/root/DataDragAndDrop.context.js.map +0 -1
  196. package/cjs/data/drag-and-drop/root/DataDragAndDropRoot.d.ts +0 -34
  197. package/cjs/data/drag-and-drop/root/DataDragAndDropRoot.js.map +0 -1
  198. package/cjs/data/table/root/useTableKeyboardNav.js.map +0 -1
  199. package/cjs/data/table/root/useTableSelection.d.ts +0 -55
  200. package/cjs/data/table/root/useTableSelection.js +0 -79
  201. package/cjs/data/table/root/useTableSelection.js.map +0 -1
  202. package/esm/data/action-bar/root/DataActionBarRoot.d.ts +0 -27
  203. package/esm/data/action-bar/root/DataActionBarRoot.js +0 -43
  204. package/esm/data/action-bar/root/DataActionBarRoot.js.map +0 -1
  205. package/esm/data/drag-and-drop/drag-handler/DataDragAndDropDragHandler.d.ts +0 -21
  206. package/esm/data/drag-and-drop/drag-handler/DataDragAndDropDragHandler.js +0 -18
  207. package/esm/data/drag-and-drop/drag-handler/DataDragAndDropDragHandler.js.map +0 -1
  208. package/esm/data/drag-and-drop/item/DataDragAndDropItem.d.ts +0 -27
  209. package/esm/data/drag-and-drop/item/DataDragAndDropItem.js +0 -35
  210. package/esm/data/drag-and-drop/item/DataDragAndDropItem.js.map +0 -1
  211. package/esm/data/drag-and-drop/root/DataDragAndDrop.context.d.ts +0 -8
  212. package/esm/data/drag-and-drop/root/DataDragAndDrop.context.js +0 -6
  213. package/esm/data/drag-and-drop/root/DataDragAndDrop.context.js.map +0 -1
  214. package/esm/data/drag-and-drop/root/DataDragAndDropRoot.d.ts +0 -34
  215. package/esm/data/drag-and-drop/root/DataDragAndDropRoot.js +0 -21
  216. package/esm/data/drag-and-drop/root/DataDragAndDropRoot.js.map +0 -1
  217. package/esm/data/table/root/useTableKeyboardNav.js.map +0 -1
  218. package/esm/data/table/root/useTableSelection.d.ts +0 -55
  219. package/esm/data/table/root/useTableSelection.js +0 -77
  220. package/esm/data/table/root/useTableSelection.js.map +0 -1
  221. package/src/data/action-bar/root/DataActionBarRoot.tsx +0 -59
  222. package/src/data/drag-and-drop/drag-handler/DataDragAndDropDragHandler.tsx +0 -63
  223. package/src/data/drag-and-drop/item/DataDragAndDropItem.tsx +0 -54
  224. package/src/data/drag-and-drop/root/DataDragAndDrop.context.tsx +0 -14
  225. package/src/data/drag-and-drop/root/DataDragAndDropRoot.tsx +0 -54
  226. package/src/data/table/root/useTableSelection.ts +0 -126
  227. /package/cjs/data/table/{root → hooks}/useTableKeyboardNav.d.ts +0 -0
  228. /package/esm/data/table/{root → hooks}/useTableKeyboardNav.d.ts +0 -0
@@ -2,20 +2,22 @@ import React, { forwardRef } from "react";
2
2
  import { BodyShort } from "../../typography/index.js";
3
3
  import { omit, useId } from "../../utils-external/index.js";
4
4
  import { cl } from "../../utils/helpers/index.js";
5
+ import { RadioInput } from "./radio-input/RadioInput.js";
5
6
  import { useRadio } from "./useRadio.js";
6
- export const Radio = forwardRef((props, ref) => {
7
+ export const Radio = forwardRef((props, forwardedRef) => {
7
8
  const { inputProps, size, hasError, readOnly } = useRadio(props);
8
9
  const descriptionId = useId();
9
- return (React.createElement("div", { className: cl(props.className, "aksel-radio", `aksel-radio--${size}`, {
10
+ const { className, description, children } = props;
11
+ return (React.createElement("div", { className: cl(className, "aksel-radio", `aksel-radio--${size}`, {
10
12
  "aksel-radio--error": hasError,
11
13
  "aksel-radio--disabled": inputProps.disabled,
12
14
  "aksel-radio--readonly": readOnly,
13
15
  }), "data-color": hasError ? "danger" : props["data-color"] },
14
- React.createElement("input", Object.assign({}, omit(props, ["children", "size", "description", "readOnly"]), omit(inputProps, ["aria-invalid", "aria-describedby"]), { "aria-describedby": cl(inputProps["aria-describedby"], {
15
- [descriptionId]: props.description,
16
- }) || undefined, className: "aksel-radio__input", ref: ref })),
17
- React.createElement(BodyShort, { as: "label", htmlFor: inputProps.id, className: "aksel-radio__label", size: size }, props.children),
18
- props.description && (React.createElement(BodyShort, { id: descriptionId, size: size, className: "aksel-form-field__subdescription aksel-radio__description" }, props.description))));
16
+ React.createElement(RadioInput, Object.assign({ ref: forwardedRef }, omit(props, ["children", "size", "description", "readOnly"]), omit(inputProps, ["aria-invalid", "aria-describedby"]), { "aria-describedby": cl(inputProps["aria-describedby"], {
17
+ [descriptionId]: description,
18
+ }) || undefined, standalone: false })),
19
+ React.createElement(BodyShort, { as: "label", htmlFor: inputProps.id, className: "aksel-radio__label", size: size }, children),
20
+ description && (React.createElement(BodyShort, { id: descriptionId, size: size, className: "aksel-form-field__subdescription aksel-radio__description" }, description))));
19
21
  });
20
22
  export default Radio;
21
23
  //# sourceMappingURL=Radio.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Radio.js","sourceRoot":"","sources":["../../../src/form/radio/Radio.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAA+B,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IAC3E,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACjE,MAAM,aAAa,GAAG,KAAK,EAAE,CAAC;IAE9B,OAAO,CACL,6BACE,SAAS,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,aAAa,EAAE,gBAAgB,IAAI,EAAE,EAAE;YACpE,oBAAoB,EAAE,QAAQ;YAC9B,uBAAuB,EAAE,UAAU,CAAC,QAAQ;YAC5C,uBAAuB,EAAE,QAAQ;SAClC,CAAC,gBACU,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC;QAErD,+CACM,IAAI,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC,EAC5D,IAAI,CAAC,UAAU,EAAE,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC,wBAExD,EAAE,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE;gBACjC,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC,WAAW;aACnC,CAAC,IAAI,SAAS,EAEjB,SAAS,EAAC,oBAAoB,EAC9B,GAAG,EAAE,GAAG,IACR;QACF,oBAAC,SAAS,IACR,EAAE,EAAC,OAAO,EACV,OAAO,EAAE,UAAU,CAAC,EAAE,EACtB,SAAS,EAAC,oBAAoB,EAC9B,IAAI,EAAE,IAAI,IAET,KAAK,CAAC,QAAQ,CACL;QACX,KAAK,CAAC,WAAW,IAAI,CACpB,oBAAC,SAAS,IACR,EAAE,EAAE,aAAa,EACjB,IAAI,EAAE,IAAI,EACV,SAAS,EAAC,2DAA2D,IAEpE,KAAK,CAAC,WAAW,CACR,CACb,CACG,CACP,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"Radio.js","sourceRoot":"","sources":["../../../src/form/radio/Radio.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAC7B,CAAC,KAAiB,EAAE,YAAY,EAAE,EAAE;IAClC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACjE,MAAM,aAAa,GAAG,KAAK,EAAE,CAAC;IAE9B,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAEnD,OAAO,CACL,6BACE,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,aAAa,EAAE,gBAAgB,IAAI,EAAE,EAAE;YAC9D,oBAAoB,EAAE,QAAQ;YAC9B,uBAAuB,EAAE,UAAU,CAAC,QAAQ;YAC5C,uBAAuB,EAAE,QAAQ;SAClC,CAAC,gBACU,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC;QAErD,oBAAC,UAAU,kBACT,GAAG,EAAE,YAAY,IACb,IAAI,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC,EAC5D,IAAI,CAAC,UAAU,EAAE,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC,wBAExD,EAAE,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE;gBACjC,CAAC,aAAa,CAAC,EAAE,WAAW;aAC7B,CAAC,IAAI,SAAS,EAEjB,UAAU,EAAE,KAAK,IACjB;QACF,oBAAC,SAAS,IACR,EAAE,EAAC,OAAO,EACV,OAAO,EAAE,UAAU,CAAC,EAAE,EACtB,SAAS,EAAC,oBAAoB,EAC9B,IAAI,EAAE,IAAI,IAET,QAAQ,CACC;QACX,WAAW,IAAI,CACd,oBAAC,SAAS,IACR,EAAE,EAAE,aAAa,EACjB,IAAI,EAAE,IAAI,EACV,SAAS,EAAC,2DAA2D,IAEpE,WAAW,CACF,CACb,CACG,CACP,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,eAAe,KAAK,CAAC"}
@@ -0,0 +1,19 @@
1
+ import React from "react";
2
+ type RadioInputProps = React.InputHTMLAttributes<HTMLInputElement> & {
3
+ children?: never;
4
+ standalone?: boolean;
5
+ /**
6
+ * Reduces pseudo-element target-size.
7
+ */
8
+ compact?: boolean;
9
+ };
10
+ declare const RadioInput: React.ForwardRefExoticComponent<React.InputHTMLAttributes<HTMLInputElement> & {
11
+ children?: never;
12
+ standalone?: boolean;
13
+ /**
14
+ * Reduces pseudo-element target-size.
15
+ */
16
+ compact?: boolean;
17
+ } & React.RefAttributes<HTMLInputElement>>;
18
+ export { RadioInput };
19
+ export type { RadioInputProps };
@@ -0,0 +1,19 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import React, { forwardRef } from "react";
13
+ import { cl } from "../../../utils/helpers/index.js";
14
+ const RadioInput = forwardRef((_a, forwardedRef) => {
15
+ var { className, standalone = true, compact } = _a, rest = __rest(_a, ["className", "standalone", "compact"]);
16
+ return (React.createElement("input", Object.assign({}, rest, { ref: forwardedRef, className: cl("aksel-radio__input", className), "data-standalone": standalone, "data-compact": compact, type: "radio" })));
17
+ });
18
+ export { RadioInput };
19
+ //# sourceMappingURL=RadioInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadioInput.js","sourceRoot":"","sources":["../../../../src/form/radio/radio-input/RadioInput.tsx"],"names":[],"mappings":";;;;;;;;;;;AAAA,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAC;AAW5C,MAAM,UAAU,GAAG,UAAU,CAC3B,CACE,EAAmE,EACnE,YAAY,EACZ,EAAE;QAFF,EAAE,SAAS,EAAE,UAAU,GAAG,IAAI,EAAE,OAAO,OAA4B,EAAvB,IAAI,cAAhD,sCAAkD,CAAF;IAGhD,OAAO,CACL,+CACM,IAAI,IACR,GAAG,EAAE,YAAY,EACjB,SAAS,EAAE,EAAE,CAAC,oBAAoB,EAAE,SAAS,CAAC,qBAC7B,UAAU,kBACb,OAAO,EACrB,IAAI,EAAC,OAAO,IACZ,CACH,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,OAAO,EAAE,UAAU,EAAE,CAAC"}
@@ -5,6 +5,11 @@ export interface InternalHeaderButtonProps extends React.ButtonHTMLAttributes<HT
5
5
  * Application Button
6
6
  */
7
7
  children: React.ReactNode;
8
+ /**
9
+ * Active state for element.
10
+ * @default false
11
+ */
12
+ isActive?: boolean;
8
13
  }
9
14
  export declare const InternalHeaderButton: OverridableComponent<InternalHeaderButtonProps, HTMLButtonElement>;
10
15
  export default InternalHeaderButton;
@@ -12,8 +12,8 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import React, { forwardRef } from "react";
13
13
  import { cl } from "../utils/helpers/index.js";
14
14
  export const InternalHeaderButton = forwardRef((_a, ref) => {
15
- var { as: Component = "button", className } = _a, rest = __rest(_a, ["as", "className"]);
16
- return (React.createElement(Component, Object.assign({}, rest, { ref: ref, className: cl("aksel-internalheader__button", className) })));
15
+ var { as: Component = "button", className, isActive = false } = _a, rest = __rest(_a, ["as", "className", "isActive"]);
16
+ return (React.createElement(Component, Object.assign({ "aria-current": isActive || undefined }, rest, { ref: ref, className: cl("aksel-internalheader__button", className), "data-active": isActive })));
17
17
  });
18
18
  export default InternalHeaderButton;
19
19
  //# sourceMappingURL=InternalHeaderButton.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"InternalHeaderButton.js","sourceRoot":"","sources":["../../src/internal-header/InternalHeaderButton.tsx"],"names":[],"mappings":";;;;;;;;;;;AAAA,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAE1C,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAQtC,MAAM,CAAC,MAAM,oBAAoB,GAG7B,UAAU,CAAC,CAAC,EAAgD,EAAE,GAAG,EAAE,EAAE;QAAzD,EAAE,EAAE,EAAE,SAAS,GAAG,QAAQ,EAAE,SAAS,OAAW,EAAN,IAAI,cAA9C,mBAAgD,CAAF;IAC5D,OAAO,CACL,oBAAC,SAAS,oBACJ,IAAI,IACR,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,EAAE,CAAC,8BAA8B,EAAE,SAAS,CAAC,IACxD,CACH,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"InternalHeaderButton.js","sourceRoot":"","sources":["../../src/internal-header/InternalHeaderButton.tsx"],"names":[],"mappings":";;;;;;;;;;;AAAA,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAE1C,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAatC,MAAM,CAAC,MAAM,oBAAoB,GAG7B,UAAU,CACZ,CAAC,EAAkE,EAAE,GAAG,EAAE,EAAE;QAA3E,EAAE,EAAE,EAAE,SAAS,GAAG,QAAQ,EAAE,SAAS,EAAE,QAAQ,GAAG,KAAK,OAAW,EAAN,IAAI,cAAhE,+BAAkE,CAAF;IAC/D,OAAO,CACL,oBAAC,SAAS,kCACM,QAAQ,IAAI,SAAS,IAC/B,IAAI,IACR,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,EAAE,CAAC,8BAA8B,EAAE,SAAS,CAAC,iBAC3C,QAAQ,IACrB,CACH,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -1,9 +1,10 @@
1
1
  import React from "react";
2
+ import { Label } from "../../../../typography/index.js";
2
3
  import { useId } from "../../../../utils-external/index.js";
3
4
  function ListboxGroup({ label, children }) {
4
5
  const labelId = useId();
5
6
  return (React.createElement("div", { role: "group", className: "aksel-listbox__group", "aria-labelledby": labelId },
6
- React.createElement("div", { id: labelId, "aria-hidden": true }, label),
7
+ React.createElement(Label, { as: "div", size: "small", id: labelId, "aria-hidden": true, className: "aksel-listbox__group-label" }, label),
7
8
  children));
8
9
  }
9
10
  export { ListboxGroup };
@@ -1 +1 @@
1
- {"version":3,"file":"ListboxGroup.js","sourceRoot":"","sources":["../../../../../src/utils/components/Listbox/group/ListboxGroup.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AAOnD,SAAS,YAAY,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAqB;IAC1D,MAAM,OAAO,GAAG,KAAK,EAAE,CAAC;IAExB,OAAO,CACL,6BACE,IAAI,EAAC,OAAO,EACZ,SAAS,EAAC,sBAAsB,qBACf,OAAO;QAExB,6BAAK,EAAE,EAAE,OAAO,yBACb,KAAK,CACF;QACL,QAAQ,CACL,CACP,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"ListboxGroup.js","sourceRoot":"","sources":["../../../../../src/utils/components/Listbox/group/ListboxGroup.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AAOnD,SAAS,YAAY,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAqB;IAC1D,MAAM,OAAO,GAAG,KAAK,EAAE,CAAC;IAExB,OAAO,CACL,6BACE,IAAI,EAAC,OAAO,EACZ,SAAS,EAAC,sBAAsB,qBACf,OAAO;QAExB,oBAAC,KAAK,IACJ,EAAE,EAAC,KAAK,EACR,IAAI,EAAC,OAAO,EACZ,EAAE,EAAE,OAAO,uBAEX,SAAS,EAAC,4BAA4B,IAErC,KAAK,CACA;QACP,QAAQ,CACL,CACP,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@navikt/ds-react",
3
- "version": "8.8.0",
3
+ "version": "8.9.1",
4
4
  "description": "React components from the Norwegian Labour and Welfare Administration.",
5
5
  "author": "Aksel, a team part of the Norwegian Labour and Welfare Administration.",
6
6
  "license": "MIT",
@@ -705,8 +705,8 @@
705
705
  "dependencies": {
706
706
  "@floating-ui/react": "0.27.8",
707
707
  "@floating-ui/react-dom": "^2.1.8",
708
- "@navikt/aksel-icons": "^8.8.0",
709
- "@navikt/ds-tokens": "^8.8.0",
708
+ "@navikt/aksel-icons": "^8.9.1",
709
+ "@navikt/ds-tokens": "^8.9.1",
710
710
  "date-fns": "^4.0.0",
711
711
  "react-day-picker": "9.7.0"
712
712
  },
@@ -732,7 +732,7 @@
732
732
  "tsc-alias": "1.8.16",
733
733
  "tsx": "^4.20.6",
734
734
  "typescript": "5.9.3",
735
- "vitest": "4.0.18"
735
+ "vitest": "4.1.0"
736
736
  },
737
737
  "peerDependencies": {
738
738
  "@types/react": "^17.0.30 || ^18 || ^19",
@@ -0,0 +1,94 @@
1
+ import React from "react";
2
+ import {
3
+ CaretDownCircleFillIcon,
4
+ CaretUpCircleFillIcon,
5
+ DragVerticalIcon,
6
+ } from "@navikt/aksel-icons";
7
+ import { useDragAndDropContext } from "../root/DragAndDrop.context";
8
+ import { DragAndDropElement } from "../types";
9
+
10
+ export interface DragAndDropDragHandlerProps {
11
+ item: DragAndDropElement;
12
+ itemRef?: React.RefObject<HTMLDivElement | null>;
13
+ }
14
+
15
+ /**
16
+ * DragAndDropDragHandler
17
+ *
18
+ * A button component that serves as a drag handle for drag and drop operations.
19
+ * Can be used to initiate dragging of elements in a data table or list.
20
+ */
21
+ export const DragAndDropDragHandler = React.forwardRef<
22
+ HTMLDivElement,
23
+ DragAndDropDragHandlerProps
24
+ >(({ item, itemRef }, forwardedRef) => {
25
+ const context = useDragAndDropContext();
26
+ const active =
27
+ context?.dragHandlerActive &&
28
+ item &&
29
+ context?.dragHandlerActive?.id === item.id;
30
+
31
+ return (
32
+ <div className="aksel-data-drag-and-drop__drag-handler" ref={forwardedRef}>
33
+ {active && (
34
+ <span
35
+ className="aksel-data-drag-and-drop__drag-handler__arrow"
36
+ data-direction="up"
37
+ >
38
+ <CaretUpCircleFillIcon aria-hidden fontSize="1.2rem" />
39
+ </span>
40
+ )}
41
+ <button
42
+ aria-label="Dra for å flytte"
43
+ className="aksel-data-drag-and-drop__drag-handler__button"
44
+ data-drag-handler-active={active}
45
+ onPointerDown={(event) => {
46
+ event.stopPropagation();
47
+ context?.startPendingDragStart(event, item, itemRef?.current || null);
48
+ }}
49
+ onClick={() => context?.setDragHandlerActive(item)}
50
+ onKeyDown={(event) => {
51
+ if (
52
+ (event.key === "Enter" || event.key === " ") &&
53
+ context?.dragHandlerActive
54
+ ) {
55
+ // Enter or space, currently active item - end keyboard dragging
56
+ event.preventDefault();
57
+ context?.setDragHandlerActive(null);
58
+ } else if (
59
+ (event.key === "Enter" || event.key === " ") &&
60
+ !context?.dragHandlerActive
61
+ ) {
62
+ // Enter or space, not currently active item - start keyboard dragging
63
+ event.preventDefault();
64
+ context?.setDragHandlerActive(item);
65
+ } else if (event.key === "Escape") {
66
+ // Cancel dragging
67
+ // TODO Handle reset
68
+ context?.setDragHandlerActive(null);
69
+ } else if (event.key === "ArrowUp") {
70
+ // Move item up
71
+ context?.onKeyboardDragEnd(-1);
72
+ } else if (event.key === "ArrowDown") {
73
+ // Move item down
74
+ context?.onKeyboardDragEnd(1);
75
+ }
76
+ }}
77
+ >
78
+ <DragVerticalIcon
79
+ aria-hidden
80
+ title="Dra for å flytte"
81
+ fontSize="1.5rem"
82
+ />
83
+ </button>
84
+ {active && (
85
+ <span
86
+ className="aksel-data-drag-and-drop__drag-handler__arrow"
87
+ data-direction="down"
88
+ >
89
+ <CaretDownCircleFillIcon aria-hidden fontSize="1.2rem" />
90
+ </span>
91
+ )}
92
+ </div>
93
+ );
94
+ });
@@ -0,0 +1,75 @@
1
+ import React from "react";
2
+ import { HStack } from "../../../primitives/stack";
3
+ import { cl } from "../../../utils/helpers";
4
+ import { DragAndDropDragHandler } from "../drag-handler/DragAndDropDragHandler";
5
+ import { useDragAndDropContext } from "../root/DragAndDrop.context";
6
+
7
+ interface DragAndDropItemProps extends React.HTMLAttributes<HTMLDivElement> {
8
+ children: React.ReactNode;
9
+ /**
10
+ * Unique id
11
+ */
12
+ id: string;
13
+ /**
14
+ * Index of the item being dragged
15
+ */
16
+ index: number;
17
+ /**
18
+ * Indicates if the item is an overlay
19
+ */
20
+ isOverlay?: boolean;
21
+ }
22
+
23
+ /**
24
+ * TODO
25
+ *
26
+ * @see 🏷️ {@link DragAndDropItemProps}
27
+ * @example
28
+ * ```tsx
29
+ * <DragAndDrop.Item numOfSelectedRows={selectedRows.length} onClear={handleClear}>
30
+ * TODO
31
+ * </DragAndDrop.Item>
32
+ * ```
33
+ */
34
+ const DragAndDropItem = React.forwardRef<HTMLDivElement, DragAndDropItemProps>(
35
+ (
36
+ { children, id, index, className, isOverlay = false, ...rest },
37
+ forwardedRef,
38
+ ) => {
39
+ const ref = React.useRef<HTMLDivElement>(null);
40
+ const context = useDragAndDropContext();
41
+ const item = { id, index };
42
+ const isDropTarget = context?.dropTarget?.id === id;
43
+
44
+ return (
45
+ <HStack
46
+ gap="space-8"
47
+ align="center"
48
+ wrap={false}
49
+ asChild
50
+ ref={forwardedRef}
51
+ padding="space-4"
52
+ >
53
+ {/* TODO Should this be a <li>? */}
54
+ <div
55
+ id={isOverlay ? undefined : id}
56
+ ref={ref}
57
+ {...rest}
58
+ data-dnd-id={isOverlay ? undefined : id}
59
+ data-dnd-index={isOverlay ? undefined : index}
60
+ className={cl("aksel-data-table__drag-and-drop-item", className)}
61
+ data-drop-target={isOverlay ? undefined : isDropTarget}
62
+ data-overlay={isOverlay}
63
+ tabIndex={isOverlay ? undefined : -1}
64
+ >
65
+ <DragAndDropDragHandler item={item} itemRef={ref} />
66
+ <div>{children}</div>
67
+ </div>
68
+ </HStack>
69
+ );
70
+ },
71
+ );
72
+
73
+ export default DragAndDropItem;
74
+ export { DragAndDropItem };
75
+ export type { DragAndDropItemProps };
@@ -0,0 +1,27 @@
1
+ import { createStrictContext } from "../../../utils/helpers";
2
+ import { DragAndDropElement } from "../types";
3
+
4
+ interface DragAndDropContextType {
5
+ activeItem: DragAndDropElement | null;
6
+ setActiveItem: (id: DragAndDropElement | null) => void;
7
+ dropTarget: DragAndDropElement | null;
8
+ setDropTarget: (id: DragAndDropElement | null) => void;
9
+ dragHandlerActive: DragAndDropElement | null;
10
+ setDragHandlerActive: (active: DragAndDropElement | null) => void;
11
+ onKeyboardDragEnd: (diff: number) => void;
12
+ startPendingDragStart: (
13
+ event: React.PointerEvent,
14
+ item: DragAndDropElement,
15
+ element?: HTMLElement | null,
16
+ ) => void;
17
+ cancelDragStart: () => void;
18
+ }
19
+
20
+ export const {
21
+ Provider: DragAndDropProvider,
22
+ useContext: useDragAndDropContext,
23
+ } = createStrictContext<DragAndDropContextType | undefined>({
24
+ errorMessage:
25
+ "useDragAndDropContext must be used within a DragAndDropProvider",
26
+ name: "DragAndDropContext",
27
+ });
@@ -0,0 +1,294 @@
1
+ import React, { forwardRef, useEffect } from "react";
2
+ import { Floating } from "../../../utils/components/floating/Floating";
3
+ import DragAndDropItem, { DragAndDropItemProps } from "../item/DragAndDropItem";
4
+ import { DragAndDropElement } from "../types";
5
+ import { DragAndDropProvider } from "./DragAndDrop.context";
6
+
7
+ interface DragAndDropProps extends React.HTMLAttributes<HTMLDivElement> {
8
+ children: React.ReactElement<DragAndDropItemProps>[];
9
+ setItems: React.Dispatch<React.SetStateAction<any[]>>;
10
+ }
11
+
12
+ interface DataDragAndDropRootComponent extends React.ForwardRefExoticComponent<
13
+ DragAndDropProps & React.RefAttributes<HTMLDivElement>
14
+ > {
15
+ /**
16
+ * @see 🏷️ {@link DragAndDropItemProps}
17
+ * * @example
18
+ * ```jsx
19
+ * <DragAndDrop>
20
+ * <DragAndDrop.Item id="1" index={0}>
21
+ * ...
22
+ * </DragAndDrop.Item>
23
+ * </DragAndDrop>
24
+ * ```
25
+ */
26
+ Item: typeof DragAndDropItem;
27
+ }
28
+
29
+ /**
30
+ * TODO
31
+ * [x] setItems on root
32
+ * [x] state : active element
33
+ * [x] pointer over listener / state, onPointerEnter, onPointerLeave
34
+ * [x] Overlay - Use floating component
35
+ * [x] Keyboard navigation
36
+ * [ ] UU - announce on drag start, item moved, drag end
37
+ * [x] Make overlay same width as the OG item, currently jumps to content width
38
+ * [ ] Look into adding a cancel listener event
39
+ * [ ] Make onClick work on drag handler button, currently blocked by pointer down/up listeners
40
+ * [ ] Talk to design about what should happen on ESC key press, currently just cancels dragging, should it also reset position?
41
+ * [ ] Make arrow icons into buttons that react to keyboard events, currently just decorative
42
+ */
43
+
44
+ const DragAndDrop = forwardRef<HTMLDivElement, DragAndDropProps>(
45
+ ({ setItems, children }, forwardedRef) => {
46
+ const DRAG_THRESHOLD = 4; // Minimum movement in pixels to start dragging
47
+
48
+ const [activeItem, setActiveItem] =
49
+ React.useState<DragAndDropElement | null>(null);
50
+ const [dropTarget, setDropTarget] =
51
+ React.useState<DragAndDropElement | null>(null);
52
+ const [dragHandlerActive, setDragHandlerActive] =
53
+ React.useState<DragAndDropElement | null>(null);
54
+ const [overlayWidth, setOverlayWidth] = React.useState<number | null>(null);
55
+
56
+ const activeItemRef = React.useRef<DragAndDropElement | null>(null);
57
+ const dropTargetRef = React.useRef<DragAndDropElement | null>(null);
58
+ const activeChild = children.find(
59
+ (child) => child.props.id === activeItem?.id,
60
+ );
61
+
62
+ const [virtualRef, setVirtualRef] = React.useState({
63
+ getBoundingClientRect: () =>
64
+ DOMRect.fromRect({ width: 0, height: 0, x: 0, y: 0 }),
65
+ });
66
+
67
+ const pendingDragStartRef = React.useRef<{
68
+ item: DragAndDropElement;
69
+ element: HTMLElement | null;
70
+ pointerId: number;
71
+ startX: number;
72
+ startY: number;
73
+ } | null>(null);
74
+
75
+ const startPendingDragStart = (
76
+ event: React.PointerEvent,
77
+ item: DragAndDropElement,
78
+ element?: HTMLElement | null,
79
+ ) => {
80
+ pendingDragStartRef.current = {
81
+ item,
82
+ element: element || null,
83
+ pointerId: event.pointerId,
84
+ startX: event.clientX,
85
+ startY: event.clientY,
86
+ };
87
+ };
88
+
89
+ const cancelDragStart = () => {
90
+ pendingDragStartRef.current = null;
91
+ };
92
+
93
+ const setCombinedActiveItem = React.useCallback(
94
+ (item: DragAndDropElement | null) => {
95
+ activeItemRef.current = item;
96
+ setActiveItem(item);
97
+ },
98
+ [],
99
+ );
100
+
101
+ const setCombinedDropTarget = React.useCallback(
102
+ (item: DragAndDropElement | null) => {
103
+ dropTargetRef.current = item;
104
+ setDropTarget(item);
105
+ },
106
+ [],
107
+ );
108
+
109
+ useEffect(() => {
110
+ /* This useEffect is used to toggle a class on the html element when dragging,
111
+ to prevent cursor issues when dragging over interactive elements,
112
+ and to prevent text selection during dragging. */
113
+
114
+ if (activeItem) {
115
+ document.documentElement.setAttribute("data-dragging-cursor", "true");
116
+ document.body.style.userSelect = "none";
117
+ } else {
118
+ document.documentElement.removeAttribute("data-dragging-cursor");
119
+ document.body.style.userSelect = "";
120
+ }
121
+
122
+ return () => {
123
+ document.documentElement.removeAttribute("data-dragging-cursor");
124
+ document.body.style.userSelect = "";
125
+ };
126
+ }, [activeItem]);
127
+
128
+ useEffect(() => {
129
+ const handlePointerMove = (event: PointerEvent) => {
130
+ const pendingStart = pendingDragStartRef.current;
131
+ const activeRef = activeItemRef.current;
132
+ const element = pendingStart?.element;
133
+
134
+ if (!activeRef && pendingStart) {
135
+ const deltaX = Math.abs(event.clientX - pendingStart.startX);
136
+ const deltaY = Math.abs(event.clientY - pendingStart.startY);
137
+
138
+ if (deltaX > DRAG_THRESHOLD || deltaY > DRAG_THRESHOLD) {
139
+ if (element) {
140
+ element.setPointerCapture(pendingStart.pointerId);
141
+ }
142
+
143
+ setOverlayWidth(element?.getBoundingClientRect().width ?? null);
144
+ setCombinedActiveItem(pendingStart.item);
145
+ setCombinedDropTarget(pendingStart.item);
146
+ pendingDragStartRef.current = null;
147
+ }
148
+ return;
149
+ }
150
+
151
+ const active = activeItemRef.current;
152
+ if (!active) return;
153
+
154
+ setVirtualRef({
155
+ getBoundingClientRect: () =>
156
+ DOMRect.fromRect({
157
+ width: 0,
158
+ height: 0,
159
+ x: event.clientX,
160
+ y: event.clientY,
161
+ }),
162
+ });
163
+
164
+ const elements = document.elementsFromPoint(
165
+ event.clientX,
166
+ event.clientY,
167
+ );
168
+
169
+ const matchingElements = elements.filter(
170
+ (el) =>
171
+ el instanceof HTMLElement && Boolean(el.closest("[data-dnd-id]")),
172
+ ) as HTMLElement[];
173
+
174
+ const itemElements = matchingElements
175
+ .map((el) => el.closest("[data-dnd-id]") as HTMLElement)
176
+ .filter((el) => el instanceof HTMLElement);
177
+
178
+ const uniqueItemElements = Array.from(new Set(itemElements));
179
+
180
+ const targetElement =
181
+ uniqueItemElements.find((el) => el.dataset.dndId !== active.id) ??
182
+ uniqueItemElements.find((el) => el.dataset.dndId === active.id) ??
183
+ null;
184
+
185
+ if (!targetElement) {
186
+ setCombinedDropTarget(null);
187
+ return;
188
+ }
189
+
190
+ const hoveredId = targetElement.dataset.dndId;
191
+ const hoveredIndex = Number(targetElement.dataset.dndIndex);
192
+
193
+ if (!hoveredId || Number.isNaN(hoveredIndex)) {
194
+ setCombinedDropTarget(null);
195
+ return;
196
+ }
197
+
198
+ setCombinedDropTarget({ id: hoveredId, index: hoveredIndex });
199
+ };
200
+
201
+ const handlePointerUp = () => {
202
+ if (!activeItemRef.current) {
203
+ pendingDragStartRef.current = null;
204
+ return;
205
+ }
206
+
207
+ const active = activeItemRef.current;
208
+ const target = dropTargetRef.current;
209
+
210
+ if (active && target && active.id !== target.id) {
211
+ setItems((items) => {
212
+ const newItems = [...items];
213
+ const [movedItem] = newItems.splice(active.index, 1);
214
+ newItems.splice(target.index, 0, movedItem);
215
+ return newItems;
216
+ });
217
+ }
218
+ setOverlayWidth(null);
219
+ setDragHandlerActive(null);
220
+ setCombinedActiveItem(null);
221
+ setCombinedDropTarget(null);
222
+ pendingDragStartRef.current = null;
223
+ };
224
+
225
+ // TODO - Look into adding a cancel listener event
226
+ window.addEventListener("pointermove", handlePointerMove);
227
+ window.addEventListener("pointerup", handlePointerUp);
228
+
229
+ return () => {
230
+ window.removeEventListener("pointermove", handlePointerMove);
231
+ window.removeEventListener("pointerup", handlePointerUp);
232
+ };
233
+ }, [setCombinedDropTarget, setCombinedActiveItem, setItems]);
234
+
235
+ const onKeyboardDragEnd = (diff: number) => {
236
+ if (!dragHandlerActive) return;
237
+
238
+ const targetIndex = dragHandlerActive.index + diff;
239
+ if (targetIndex < 0 || targetIndex >= children.length) {
240
+ return;
241
+ }
242
+
243
+ setItems((items) => {
244
+ const newItems = [...items];
245
+ const [movedItem] = newItems.splice(dragHandlerActive.index, 1);
246
+ newItems.splice(targetIndex, 0, movedItem);
247
+ return newItems;
248
+ });
249
+ setDragHandlerActive({ ...dragHandlerActive, index: targetIndex });
250
+ };
251
+
252
+ return (
253
+ <DragAndDropProvider
254
+ activeItem={activeItem}
255
+ setActiveItem={setCombinedActiveItem}
256
+ dropTarget={dropTarget}
257
+ setDropTarget={setCombinedDropTarget}
258
+ dragHandlerActive={dragHandlerActive}
259
+ setDragHandlerActive={setDragHandlerActive}
260
+ onKeyboardDragEnd={onKeyboardDragEnd}
261
+ startPendingDragStart={startPendingDragStart}
262
+ cancelDragStart={cancelDragStart}
263
+ >
264
+ <div ref={forwardedRef}>{children}</div>
265
+ {activeItem && activeChild && (
266
+ <Floating>
267
+ <Floating.Anchor virtualRef={virtualRef}>
268
+ <span />
269
+ </Floating.Anchor>
270
+ <Floating.Content
271
+ align="start"
272
+ updatePositionStrategy="always"
273
+ style={{
274
+ pointerEvents: "none",
275
+ boxSizing: "border-box",
276
+ width: overlayWidth ? `${overlayWidth}px` : "fit-content",
277
+ }}
278
+ >
279
+ {React.cloneElement(activeChild, {
280
+ isOverlay: true,
281
+ })}
282
+ </Floating.Content>
283
+ </Floating>
284
+ )}
285
+ </DragAndDropProvider>
286
+ );
287
+ },
288
+ ) as DataDragAndDropRootComponent;
289
+
290
+ DragAndDrop.Item = DragAndDropItem;
291
+
292
+ export { DragAndDrop, DragAndDropItem };
293
+ export default DragAndDrop;
294
+ export type { DragAndDropItemProps, DragAndDropProps };
@@ -0,0 +1,4 @@
1
+ export interface DragAndDropElement {
2
+ id: string;
3
+ index: number;
4
+ }