@navikt/ds-react 7.2.0 → 7.3.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 (294) hide show
  1. package/cjs/accordion/AccordionHeader.js +1 -1
  2. package/cjs/accordion/AccordionHeader.js.map +1 -1
  3. package/cjs/alert/Alert.d.ts +0 -3
  4. package/cjs/alert/Alert.js +11 -17
  5. package/cjs/alert/Alert.js.map +1 -1
  6. package/cjs/chips/Removable.d.ts +5 -5
  7. package/cjs/chips/Removable.js +4 -2
  8. package/cjs/chips/Removable.js.map +1 -1
  9. package/cjs/collapsible/Collapsible.context.d.ts +1 -1
  10. package/cjs/date/datepicker/DatePicker.d.ts +2 -2
  11. package/cjs/date/monthpicker/MonthPicker.d.ts +2 -2
  12. package/cjs/dropdown/Menu/index.js +1 -1
  13. package/cjs/dropdown/Menu/index.js.map +1 -1
  14. package/cjs/form/checkbox/useCheckbox.js +3 -2
  15. package/cjs/form/checkbox/useCheckbox.js.map +1 -1
  16. package/cjs/form/combobox/ComboboxProvider.js +4 -1
  17. package/cjs/form/combobox/ComboboxProvider.js.map +1 -1
  18. package/cjs/form/combobox/FilteredOptions/filteredOptionsContext.js +1 -1
  19. package/cjs/form/combobox/FilteredOptions/filteredOptionsContext.js.map +1 -1
  20. package/cjs/form/combobox/FilteredOptions/useVirtualFocus.d.ts +3 -0
  21. package/cjs/form/combobox/FilteredOptions/useVirtualFocus.js +33 -10
  22. package/cjs/form/combobox/FilteredOptions/useVirtualFocus.js.map +1 -1
  23. package/cjs/form/combobox/Input/Input.js +23 -10
  24. package/cjs/form/combobox/Input/Input.js.map +1 -1
  25. package/cjs/form/file-upload/FileUpload.context.d.ts +1 -1
  26. package/cjs/form/radio/useRadio.js +3 -2
  27. package/cjs/form/radio/useRadio.js.map +1 -1
  28. package/cjs/form/search/Search.js +1 -1
  29. package/cjs/form/search/Search.js.map +1 -1
  30. package/cjs/form/switch/Switch.js +2 -1
  31. package/cjs/form/switch/Switch.js.map +1 -1
  32. package/cjs/index.d.ts +1 -0
  33. package/cjs/index.js +4 -2
  34. package/cjs/index.js.map +1 -1
  35. package/cjs/layout/base/BasePrimitive.d.ts +3 -0
  36. package/cjs/layout/base/BasePrimitive.js.map +1 -1
  37. package/cjs/layout/box/Box.d.ts +2 -2
  38. package/cjs/layout/box/Box.js.map +1 -1
  39. package/cjs/layout/grid/HGrid.d.ts +2 -2
  40. package/cjs/layout/grid/HGrid.js.map +1 -1
  41. package/cjs/layout/stack/Stack.d.ts +2 -2
  42. package/cjs/layout/stack/Stack.js.map +1 -1
  43. package/cjs/modal/ModalHeader.js +6 -1
  44. package/cjs/modal/ModalHeader.js.map +1 -1
  45. package/cjs/modal/dialog-polyfill.js +2 -2
  46. package/cjs/modal/dialog-polyfill.js.map +1 -1
  47. package/cjs/overlays/action-menu/ActionMenu.d.ts +310 -0
  48. package/cjs/overlays/action-menu/ActionMenu.js +227 -0
  49. package/cjs/overlays/action-menu/ActionMenu.js.map +1 -0
  50. package/cjs/overlays/action-menu/index.d.ts +1 -0
  51. package/cjs/overlays/action-menu/index.js +19 -0
  52. package/cjs/overlays/action-menu/index.js.map +1 -0
  53. package/cjs/overlays/floating/Floating.js +9 -10
  54. package/cjs/overlays/floating/Floating.js.map +1 -1
  55. package/cjs/overlays/floating/Floating.utils.d.ts +3 -5
  56. package/cjs/overlays/floating/Floating.utils.js +0 -2
  57. package/cjs/overlays/floating/Floating.utils.js.map +1 -1
  58. package/cjs/overlays/floating-menu/Menu.d.ts +15 -21
  59. package/cjs/overlays/floating-menu/Menu.js +119 -230
  60. package/cjs/overlays/floating-menu/Menu.js.map +1 -1
  61. package/cjs/overlays/floating-menu/parts/RovingFocus.d.ts +1 -1
  62. package/cjs/overlays/floating-menu/parts/RovingFocus.js +4 -4
  63. package/cjs/overlays/floating-menu/parts/RovingFocus.js.map +1 -1
  64. package/cjs/pagination/Pagination.d.ts +1 -6
  65. package/cjs/pagination/Pagination.js.map +1 -1
  66. package/cjs/provider/i18n/LanguageProvider.d.ts +3 -3
  67. package/cjs/stepper/context.d.ts +1 -1
  68. package/cjs/table/Body.d.ts +2 -4
  69. package/cjs/table/Body.js.map +1 -1
  70. package/cjs/table/ColumnHeader.d.ts +1 -2
  71. package/cjs/table/ColumnHeader.js.map +1 -1
  72. package/cjs/table/ExpandableRow.d.ts +1 -2
  73. package/cjs/table/ExpandableRow.js.map +1 -1
  74. package/cjs/table/Header.d.ts +2 -4
  75. package/cjs/table/Header.js.map +1 -1
  76. package/cjs/table/HeaderCell.d.ts +1 -2
  77. package/cjs/table/HeaderCell.js.map +1 -1
  78. package/cjs/table/Row.d.ts +1 -2
  79. package/cjs/table/Row.js.map +1 -1
  80. package/cjs/tabs/Tabs.context.d.ts +1 -1
  81. package/cjs/tabs/parts/tablist/useScrollButtons.js +1 -1
  82. package/cjs/tabs/parts/tablist/useScrollButtons.js.map +1 -1
  83. package/cjs/tabs/parts/tablist/useTabList.js +4 -4
  84. package/cjs/tabs/parts/tablist/useTabList.js.map +1 -1
  85. package/cjs/timeline/TimelineRow.js +9 -10
  86. package/cjs/timeline/TimelineRow.js.map +1 -1
  87. package/cjs/toggle-group/ToggleGroup.context.d.ts +1 -1
  88. package/cjs/toggle-group/parts/useToggleItem.js +4 -4
  89. package/cjs/toggle-group/parts/useToggleItem.js.map +1 -1
  90. package/cjs/util/TextareaAutoSize.js +2 -2
  91. package/cjs/util/TextareaAutoSize.js.map +1 -1
  92. package/cjs/util/hooks/descendants/descendant.js +1 -1
  93. package/cjs/util/hooks/descendants/descendant.js.map +1 -1
  94. package/cjs/util/hooks/descendants/useDescendant.js +1 -1
  95. package/cjs/util/hooks/descendants/useDescendant.js.map +1 -1
  96. package/cjs/util/i18n/get.d.ts +2 -2
  97. package/cjs/util/i18n/get.js.map +1 -1
  98. package/cjs/util/i18n/i18n.context.d.ts +2 -3
  99. package/cjs/util/i18n/i18n.context.js.map +1 -1
  100. package/cjs/util/i18n/i18n.types.d.ts +5 -9
  101. package/cjs/util/i18n/locales/en.d.ts +39 -0
  102. package/cjs/util/i18n/locales/en.js +41 -0
  103. package/cjs/util/i18n/locales/en.js.map +1 -0
  104. package/cjs/util/i18n/locales/nb.d.ts +14 -0
  105. package/cjs/util/i18n/locales/nb.js +14 -0
  106. package/cjs/util/i18n/locales/nb.js.map +1 -1
  107. package/cjs/util/i18n/locales/nn.d.ts +39 -0
  108. package/cjs/util/i18n/locales/nn.js +41 -0
  109. package/cjs/util/i18n/locales/nn.js.map +1 -0
  110. package/cjs/util/requireReactElement.d.ts +2 -0
  111. package/cjs/util/requireReactElement.js +22 -0
  112. package/cjs/util/requireReactElement.js.map +1 -0
  113. package/cjs/util/virtualfocus/Context.d.ts +1 -1
  114. package/cjs/util/virtualfocus/parts/VirtualFocusContent.d.ts +1 -2
  115. package/cjs/util/virtualfocus/parts/VirtualFocusContent.js.map +1 -1
  116. package/esm/accordion/AccordionHeader.js +1 -1
  117. package/esm/accordion/AccordionHeader.js.map +1 -1
  118. package/esm/alert/Alert.d.ts +0 -3
  119. package/esm/alert/Alert.js +11 -17
  120. package/esm/alert/Alert.js.map +1 -1
  121. package/esm/chips/Removable.d.ts +5 -5
  122. package/esm/chips/Removable.js +4 -2
  123. package/esm/chips/Removable.js.map +1 -1
  124. package/esm/collapsible/Collapsible.context.d.ts +1 -1
  125. package/esm/date/datepicker/DatePicker.d.ts +2 -2
  126. package/esm/date/monthpicker/MonthPicker.d.ts +2 -2
  127. package/esm/dropdown/Menu/index.js +1 -1
  128. package/esm/dropdown/Menu/index.js.map +1 -1
  129. package/esm/form/checkbox/useCheckbox.js +3 -2
  130. package/esm/form/checkbox/useCheckbox.js.map +1 -1
  131. package/esm/form/combobox/ComboboxProvider.js +4 -1
  132. package/esm/form/combobox/ComboboxProvider.js.map +1 -1
  133. package/esm/form/combobox/FilteredOptions/filteredOptionsContext.js +1 -1
  134. package/esm/form/combobox/FilteredOptions/filteredOptionsContext.js.map +1 -1
  135. package/esm/form/combobox/FilteredOptions/useVirtualFocus.d.ts +3 -0
  136. package/esm/form/combobox/FilteredOptions/useVirtualFocus.js +34 -11
  137. package/esm/form/combobox/FilteredOptions/useVirtualFocus.js.map +1 -1
  138. package/esm/form/combobox/Input/Input.js +23 -10
  139. package/esm/form/combobox/Input/Input.js.map +1 -1
  140. package/esm/form/file-upload/FileUpload.context.d.ts +1 -1
  141. package/esm/form/radio/useRadio.js +3 -2
  142. package/esm/form/radio/useRadio.js.map +1 -1
  143. package/esm/form/search/Search.js +1 -1
  144. package/esm/form/search/Search.js.map +1 -1
  145. package/esm/form/switch/Switch.js +2 -1
  146. package/esm/form/switch/Switch.js.map +1 -1
  147. package/esm/index.d.ts +1 -0
  148. package/esm/index.js +1 -0
  149. package/esm/index.js.map +1 -1
  150. package/esm/layout/base/BasePrimitive.d.ts +3 -0
  151. package/esm/layout/base/BasePrimitive.js.map +1 -1
  152. package/esm/layout/box/Box.d.ts +2 -2
  153. package/esm/layout/box/Box.js.map +1 -1
  154. package/esm/layout/grid/HGrid.d.ts +2 -2
  155. package/esm/layout/grid/HGrid.js.map +1 -1
  156. package/esm/layout/stack/Stack.d.ts +2 -2
  157. package/esm/layout/stack/Stack.js.map +1 -1
  158. package/esm/modal/ModalHeader.js +6 -1
  159. package/esm/modal/ModalHeader.js.map +1 -1
  160. package/esm/modal/dialog-polyfill.js +2 -2
  161. package/esm/modal/dialog-polyfill.js.map +1 -1
  162. package/esm/overlays/action-menu/ActionMenu.d.ts +310 -0
  163. package/esm/overlays/action-menu/ActionMenu.js +197 -0
  164. package/esm/overlays/action-menu/ActionMenu.js.map +1 -0
  165. package/esm/overlays/action-menu/index.d.ts +1 -0
  166. package/esm/overlays/action-menu/index.js +3 -0
  167. package/esm/overlays/action-menu/index.js.map +1 -0
  168. package/esm/overlays/floating/Floating.js +9 -10
  169. package/esm/overlays/floating/Floating.js.map +1 -1
  170. package/esm/overlays/floating/Floating.utils.d.ts +3 -5
  171. package/esm/overlays/floating/Floating.utils.js +0 -2
  172. package/esm/overlays/floating/Floating.utils.js.map +1 -1
  173. package/esm/overlays/floating-menu/Menu.d.ts +15 -21
  174. package/esm/overlays/floating-menu/Menu.js +119 -230
  175. package/esm/overlays/floating-menu/Menu.js.map +1 -1
  176. package/esm/overlays/floating-menu/parts/RovingFocus.d.ts +1 -1
  177. package/esm/overlays/floating-menu/parts/RovingFocus.js +4 -4
  178. package/esm/overlays/floating-menu/parts/RovingFocus.js.map +1 -1
  179. package/esm/pagination/Pagination.d.ts +1 -6
  180. package/esm/pagination/Pagination.js.map +1 -1
  181. package/esm/provider/i18n/LanguageProvider.d.ts +3 -3
  182. package/esm/stepper/context.d.ts +1 -1
  183. package/esm/table/Body.d.ts +2 -4
  184. package/esm/table/Body.js.map +1 -1
  185. package/esm/table/ColumnHeader.d.ts +1 -2
  186. package/esm/table/ColumnHeader.js.map +1 -1
  187. package/esm/table/ExpandableRow.d.ts +1 -2
  188. package/esm/table/ExpandableRow.js.map +1 -1
  189. package/esm/table/Header.d.ts +2 -4
  190. package/esm/table/Header.js.map +1 -1
  191. package/esm/table/HeaderCell.d.ts +1 -2
  192. package/esm/table/HeaderCell.js.map +1 -1
  193. package/esm/table/Row.d.ts +1 -2
  194. package/esm/table/Row.js.map +1 -1
  195. package/esm/tabs/Tabs.context.d.ts +1 -1
  196. package/esm/tabs/parts/tablist/useScrollButtons.js +1 -1
  197. package/esm/tabs/parts/tablist/useScrollButtons.js.map +1 -1
  198. package/esm/tabs/parts/tablist/useTabList.js +4 -4
  199. package/esm/tabs/parts/tablist/useTabList.js.map +1 -1
  200. package/esm/timeline/TimelineRow.js +9 -10
  201. package/esm/timeline/TimelineRow.js.map +1 -1
  202. package/esm/toggle-group/ToggleGroup.context.d.ts +1 -1
  203. package/esm/toggle-group/parts/useToggleItem.js +4 -4
  204. package/esm/toggle-group/parts/useToggleItem.js.map +1 -1
  205. package/esm/util/TextareaAutoSize.js +2 -2
  206. package/esm/util/TextareaAutoSize.js.map +1 -1
  207. package/esm/util/hooks/descendants/descendant.js +1 -1
  208. package/esm/util/hooks/descendants/descendant.js.map +1 -1
  209. package/esm/util/hooks/descendants/useDescendant.js +1 -1
  210. package/esm/util/hooks/descendants/useDescendant.js.map +1 -1
  211. package/esm/util/i18n/get.d.ts +2 -2
  212. package/esm/util/i18n/get.js.map +1 -1
  213. package/esm/util/i18n/i18n.context.d.ts +2 -3
  214. package/esm/util/i18n/i18n.context.js.map +1 -1
  215. package/esm/util/i18n/i18n.types.d.ts +5 -9
  216. package/esm/util/i18n/locales/en.d.ts +39 -0
  217. package/esm/util/i18n/locales/en.js +39 -0
  218. package/esm/util/i18n/locales/en.js.map +1 -0
  219. package/esm/util/i18n/locales/nb.d.ts +14 -0
  220. package/esm/util/i18n/locales/nb.js +14 -0
  221. package/esm/util/i18n/locales/nb.js.map +1 -1
  222. package/esm/util/i18n/locales/nn.d.ts +39 -0
  223. package/esm/util/i18n/locales/nn.js +39 -0
  224. package/esm/util/i18n/locales/nn.js.map +1 -0
  225. package/esm/util/requireReactElement.d.ts +2 -0
  226. package/esm/util/requireReactElement.js +15 -0
  227. package/esm/util/requireReactElement.js.map +1 -0
  228. package/esm/util/virtualfocus/Context.d.ts +1 -1
  229. package/esm/util/virtualfocus/parts/VirtualFocusContent.d.ts +1 -2
  230. package/esm/util/virtualfocus/parts/VirtualFocusContent.js.map +1 -1
  231. package/package.json +15 -7
  232. package/src/accordion/AccordionHeader.tsx +0 -1
  233. package/src/alert/Alert.tsx +11 -20
  234. package/src/chips/Removable.tsx +13 -9
  235. package/src/date/datepicker/DatePicker.tsx +2 -2
  236. package/src/date/monthpicker/MonthPicker.tsx +2 -2
  237. package/src/dropdown/Menu/index.tsx +1 -1
  238. package/src/form/checkbox/Checkbox.test.tsx +2 -3
  239. package/src/form/checkbox/useCheckbox.ts +2 -2
  240. package/src/form/combobox/ComboboxProvider.tsx +9 -1
  241. package/src/form/combobox/FilteredOptions/filteredOptionsContext.tsx +1 -1
  242. package/src/form/combobox/FilteredOptions/useVirtualFocus.ts +42 -11
  243. package/src/form/combobox/Input/Input.tsx +19 -10
  244. package/src/form/combobox/__tests__/combobox.test.tsx +36 -0
  245. package/src/form/confirmation-panel/ConfirmationPanel.test.tsx +1 -2
  246. package/src/form/radio/Radio.test.tsx +4 -5
  247. package/src/form/radio/useRadio.ts +2 -2
  248. package/src/form/search/Search.tsx +1 -1
  249. package/src/form/switch/Switch.tsx +1 -1
  250. package/src/index.ts +1 -0
  251. package/src/layout/base/BasePrimitive.tsx +3 -0
  252. package/src/layout/box/Box.tsx +35 -36
  253. package/src/layout/grid/HGrid.tsx +26 -27
  254. package/src/layout/stack/Stack.tsx +53 -54
  255. package/src/modal/ModalHeader.tsx +6 -0
  256. package/src/modal/dialog-polyfill.ts +2 -2
  257. package/src/overlays/action-menu/ActionMenu.tsx +971 -0
  258. package/src/overlays/action-menu/index.ts +29 -0
  259. package/src/overlays/floating/Floating.tsx +6 -12
  260. package/src/overlays/floating/Floating.utils.ts +2 -5
  261. package/src/overlays/floating-menu/Menu.tsx +183 -332
  262. package/src/overlays/floating-menu/parts/RovingFocus.tsx +7 -7
  263. package/src/pagination/Pagination.tsx +4 -1
  264. package/src/pagination/steps.test.ts +15 -16
  265. package/src/provider/i18n/LanguageProvider.tsx +3 -3
  266. package/src/table/Body.tsx +4 -6
  267. package/src/table/ColumnHeader.tsx +3 -4
  268. package/src/table/ExpandableRow.tsx +3 -4
  269. package/src/table/Header.tsx +4 -6
  270. package/src/table/HeaderCell.tsx +3 -4
  271. package/src/table/Row.tsx +3 -4
  272. package/src/tabs/parts/tablist/useScrollButtons.ts +1 -1
  273. package/src/tabs/parts/tablist/useTabList.ts +4 -4
  274. package/src/timeline/TimelineRow.tsx +20 -21
  275. package/src/toggle-group/parts/useToggleItem.ts +4 -4
  276. package/src/util/TextareaAutoSize.tsx +2 -2
  277. package/src/util/hooks/descendants/descendant.ts +1 -1
  278. package/src/util/hooks/descendants/useDescendant.tsx +1 -1
  279. package/src/util/i18n/get.ts +3 -3
  280. package/src/util/i18n/i18n.context.ts +2 -3
  281. package/src/util/i18n/i18n.types.ts +7 -11
  282. package/src/util/i18n/locales/en.ts +40 -0
  283. package/src/util/i18n/locales/nb.ts +23 -1
  284. package/src/util/i18n/locales/nn.ts +40 -0
  285. package/src/util/i18n/locales.test.tsx +23 -0
  286. package/src/util/requireReactElement.ts +25 -0
  287. package/src/util/virtualfocus/parts/VirtualFocusContent.tsx +4 -2
  288. package/cjs/util/i18n/merge.d.ts +0 -2
  289. package/cjs/util/i18n/merge.js +0 -28
  290. package/cjs/util/i18n/merge.js.map +0 -1
  291. package/esm/util/i18n/merge.d.ts +0 -2
  292. package/esm/util/i18n/merge.js +0 -25
  293. package/esm/util/i18n/merge.js.map +0 -1
  294. package/src/util/i18n/merge.ts +0 -35
@@ -0,0 +1,971 @@
1
+ import cl from "clsx";
2
+ import React, { forwardRef, useRef } from "react";
3
+ import { ChevronRightIcon } from "@navikt/aksel-icons";
4
+ import { useModalContext } from "../../modal/Modal.context";
5
+ import { Slot } from "../../slot/Slot";
6
+ import { OverridableComponent, useId } from "../../util";
7
+ import { composeEventHandlers } from "../../util/composeEventHandlers";
8
+ import { createContext } from "../../util/create-context";
9
+ import { useMergeRefs } from "../../util/hooks";
10
+ import { useControllableState } from "../../util/hooks/useControllableState";
11
+ import { requireReactElement } from "../../util/requireReactElement";
12
+ import { Menu, MenuPortalProps } from "../floating-menu/Menu";
13
+
14
+ /* -------------------------------------------------------------------------- */
15
+ /* ActionMenu */
16
+ /* -------------------------------------------------------------------------- */
17
+ type ActionMenuContextValue = {
18
+ triggerId: string;
19
+ triggerRef: React.RefObject<HTMLButtonElement>;
20
+ contentId: string;
21
+ open: boolean;
22
+ onOpenChange: (open: boolean) => void;
23
+ onOpenToggle: () => void;
24
+ rootElement: MenuPortalProps["rootElement"];
25
+ };
26
+
27
+ const [ActionMenuProvider, useActionMenuContext] =
28
+ createContext<ActionMenuContextValue>({
29
+ name: "ActionMenuContext",
30
+ errorMessage:
31
+ "ActionMenu sub-components cannot be rendered outside the ActionMenu component.",
32
+ });
33
+
34
+ type ActionMenuProps = {
35
+ children?: React.ReactNode;
36
+ /**
37
+ * Whether the menu is open or not.
38
+ * Only needed if you want manually control state.
39
+ */
40
+ open?: boolean;
41
+ /**
42
+ * Callback for when the menu is opened or closed.
43
+ */
44
+ onOpenChange?: (open: boolean) => void;
45
+ } & Pick<MenuPortalProps, "rootElement">;
46
+
47
+ interface ActionMenuComponent extends React.FC<ActionMenuProps> {
48
+ /**
49
+ * Acts as a trigger and anchor for the menu.
50
+ * Must be wrapped around a button. If you use your own component, make sure to forward ref and props.
51
+ * @example
52
+ * ```jsx
53
+ * <ActionMenu.Trigger>
54
+ * <button>Open Menu</button>
55
+ * </ActionMenu.Trigger>
56
+ * ```
57
+ */
58
+ Trigger: typeof ActionMenuTrigger;
59
+ /**
60
+ * The menu content, containing all the items.
61
+ * @example
62
+ * ```jsx
63
+ * <ActionMenu.Content>
64
+ * <ActionMenu.Item>
65
+ * Item 1
66
+ * </ActionMenu.Item>
67
+ * <ActionMenu.Item>
68
+ * Item 2
69
+ * </ActionMenu.Item>
70
+ * </ActionMenu.Content>
71
+ * ```
72
+ */
73
+ Content: typeof ActionMenuContent;
74
+ /**
75
+ * Semantically and visually groups items together with a label.
76
+ * This is the prefered way to group items, as it provides better accessibility
77
+ * rather than using a standalone `ActionMenu.Label`.
78
+ *
79
+ * It is required to use either `label` or `aria-label` to provide an accessible name for the group.
80
+ * @example
81
+ * ```jsx
82
+ * <ActionMenu.Content>
83
+ * <ActionMenu.Group label="Group 1">
84
+ * <ActionMenu.Item>
85
+ * Item 1
86
+ * </ActionMenu.Item>
87
+ * <ActionMenu.Item>
88
+ * Item 2
89
+ * </ActionMenu.Item>
90
+ * </ActionMenu.Group>
91
+ * <ActionMenu.Group label="Group 2">
92
+ * <ActionMenu.Item>
93
+ * Item 3
94
+ * </ActionMenu.Item>
95
+ * <ActionMenu.Item>
96
+ * Item 4
97
+ * </ActionMenu.Item>
98
+ * </ActionMenu.Group>
99
+ * </ActionMenu.Content>
100
+ * ```
101
+ */
102
+ Group: typeof ActionMenuGroup;
103
+ /**
104
+ * Separate labeling option for the menu.
105
+ * This is not for grouping items, but rather for adding a label to the menu at the top. For grouping items, use `ActionMenu.Group`.
106
+ * @example
107
+ * ```jsx
108
+ * <ActionMenu.Content>
109
+ * <ActionMenu.Label>
110
+ * Label
111
+ * </ActionMenu.Label>
112
+ * <ActionMenu.Divider />
113
+ * </ActionMenu.Content
114
+ * ```
115
+ */
116
+ Label: typeof ActionMenuLabel;
117
+ /**
118
+ * A single item in the menu. Can be used standalone or grouped with other items.
119
+ * Use `onSelect` to handle the action when the item is selected, like navigating to a new page or performing an action.
120
+ * @example
121
+ * ```jsx
122
+ * <ActionMenu.Content>
123
+ * // Grouped
124
+ * <ActionMenu.Group label="Group 1">
125
+ * <ActionMenu.Item onSelect={navigate}>
126
+ * Item 1
127
+ * </ActionMenu.Item>
128
+ * <ActionMenu.Item onSelect={navigate}>
129
+ * Item 2
130
+ * </ActionMenu.Item>
131
+ * </ActionMenu.Group>
132
+ * <ActionMenu.Divider />
133
+ * // Standalone
134
+ * <ActionMenu.Item onSelect={updateState}>
135
+ * Item 3
136
+ * </ActionMenu.Item>
137
+ * </ActionMenu.Content>
138
+ * ```
139
+ * @example As link
140
+ * ```jsx
141
+ * <ActionMenu.Item as="a" href="#">
142
+ * Item
143
+ * </ActionMenu.Item>
144
+ * ```
145
+ */
146
+ Item: typeof ActionMenuItem;
147
+ /**
148
+ * A checkbox item in the menu. Can be used standalone or grouped with other items.
149
+ * @example
150
+ * ```jsx
151
+ * <ActionMenu.CheckboxItem
152
+ * checked={isChecked}
153
+ * onCheckedChange={handleChange}
154
+ * >
155
+ * Checkbox 1
156
+ * </ActionMenu.CheckboxItem>
157
+ * ```
158
+ */
159
+ CheckboxItem: typeof ActionMenuCheckboxItem;
160
+ /**
161
+ * A radio group in the menu.
162
+ *
163
+ * It is required to use either `label` or `aria-label` to provide an accessible name for the group.
164
+ * @example
165
+ * ```jsx
166
+ * <ActionMenu.RadioGroup
167
+ * onValueChange={handleValueChange}
168
+ * value={radioValue}
169
+ * label="Radio group"
170
+ * >
171
+ * <ActionMenu.RadioItem value="1">Radio 1</ActionMenu.RadioItem>
172
+ * <ActionMenu.RadioItem value="2">Radio 2</ActionMenu.RadioItem>
173
+ * </ActionMenu.RadioGroup>
174
+ * ```
175
+ */
176
+ RadioGroup: typeof ActionMenuRadioGroup;
177
+ /**
178
+ * A radio item in the menu. Should always be grouped with an `ActionMenu.RadioGroup`.
179
+ * @example
180
+ * ```jsx
181
+ * <ActionMenu.RadioGroup
182
+ * onValueChange={handleValueChange}
183
+ * value={radioValue}
184
+ * label="Radio group"
185
+ * >
186
+ * <ActionMenu.RadioItem value="1">Radio 1</ActionMenu.RadioItem>
187
+ * <ActionMenu.RadioItem value="2">Radio 2</ActionMenu.RadioItem>
188
+ * </ActionMenu.RadioGroup>
189
+ * ```
190
+ */
191
+ RadioItem: typeof ActionMenuRadioItem;
192
+ /**
193
+ * A simple divider to separate items in the menu.
194
+ */
195
+ Divider: typeof ActionMenuDivider;
196
+ /**
197
+ * A sub-menu that can be nested inside the menu.
198
+ * The sub-menu can be nested inside other sub-menus allowing for multiple levels of nesting.
199
+ * @example
200
+ * ```jsx
201
+ * <ActionMenu.Sub>
202
+ * <ActionMenu.SubTrigger>Submenu 1</ActionMenu.SubTrigger>
203
+ * <ActionMenu.SubContent>
204
+ * <ActionMenu.Item>
205
+ * Subitem 1
206
+ * </ActionMenu.Item>
207
+ * <ActionMenu.Item>
208
+ * Subitem 2
209
+ * </ActionMenu.Item>
210
+ * </ActionMenu.SubContent>
211
+ * </ActionMenu.Sub>
212
+ * ```
213
+ */
214
+ Sub: typeof ActionMenuSub;
215
+ /**
216
+ * Acts as a trigger for a sub-menu.
217
+ * In contrast to `ActionMenu.Trigger`, this trigger is a standalone component and should not be wrapped around a React.ReactNode.
218
+ * @example
219
+ * ```jsx
220
+ * <ActionMenu.Sub>
221
+ * <ActionMenu.SubTrigger>Submenu 1</ActionMenu.SubTrigger>
222
+ * </ActionMenu.Sub>
223
+ * ```
224
+ */
225
+ SubTrigger: typeof ActionMenuSubTrigger;
226
+ /**
227
+ * The content of a sub-menu.
228
+ * @example
229
+ * ```jsx
230
+ * <ActionMenu.Sub>
231
+ * <ActionMenu.SubContent>
232
+ * <ActionMenu.Item>
233
+ * Subitem 1
234
+ * </ActionMenu.Item>
235
+ * <ActionMenu.Item>
236
+ * Subitem 2
237
+ * </ActionMenu.Item>
238
+ * </ActionMenu.SubContent>
239
+ * </ActionMenu.Sub>
240
+ * ```
241
+ */
242
+ SubContent: typeof ActionMenuSubContent;
243
+ }
244
+
245
+ const ActionMenuRoot = ({
246
+ children,
247
+ open: openProp,
248
+ onOpenChange,
249
+ rootElement: rootElementProp,
250
+ }: ActionMenuProps) => {
251
+ const triggerRef = useRef<HTMLButtonElement>(null);
252
+
253
+ const modalContext = useModalContext(false);
254
+ const rootElement = modalContext ? modalContext.ref.current : rootElementProp;
255
+
256
+ const [open = false, setOpen] = useControllableState({
257
+ value: openProp,
258
+ defaultValue: false,
259
+ onChange: onOpenChange,
260
+ });
261
+
262
+ return (
263
+ <ActionMenuProvider
264
+ triggerId={useId()}
265
+ triggerRef={triggerRef}
266
+ contentId={useId()}
267
+ open={open}
268
+ onOpenChange={setOpen}
269
+ onOpenToggle={() => setOpen((prevOpen) => !prevOpen)}
270
+ rootElement={rootElement}
271
+ >
272
+ <Menu open={open} onOpenChange={setOpen} modal>
273
+ {children}
274
+ </Menu>
275
+ </ActionMenuProvider>
276
+ );
277
+ };
278
+
279
+ export const ActionMenu = ActionMenuRoot as ActionMenuComponent;
280
+
281
+ /* -------------------------------------------------------------------------- */
282
+ /* ActionMenuTrigger */
283
+ /* -------------------------------------------------------------------------- */
284
+ interface ActionMenuTriggerProps
285
+ extends React.ButtonHTMLAttributes<HTMLButtonElement> {
286
+ children: React.ReactElement;
287
+ }
288
+
289
+ export const ActionMenuTrigger = forwardRef<
290
+ HTMLButtonElement,
291
+ ActionMenuTriggerProps
292
+ >(
293
+ (
294
+ { children, onKeyDown, style, onClick, ...rest }: ActionMenuTriggerProps,
295
+ ref,
296
+ ) => {
297
+ const context = useActionMenuContext();
298
+
299
+ const mergedRefs = useMergeRefs(ref, context.triggerRef);
300
+
301
+ return (
302
+ <Menu.Anchor asChild>
303
+ <Slot
304
+ type="button"
305
+ id={context.triggerId}
306
+ aria-haspopup="menu"
307
+ aria-expanded={context.open}
308
+ aria-controls={context.open ? context.contentId : undefined}
309
+ data-state={context.open ? "open" : "closed"}
310
+ ref={mergedRefs}
311
+ {...rest}
312
+ style={{ ...style, pointerEvents: context.open ? "auto" : undefined }}
313
+ onClick={composeEventHandlers(onClick, context.onOpenToggle)}
314
+ onKeyDown={composeEventHandlers(onKeyDown, (event) => {
315
+ if (event.key === "ArrowDown") {
316
+ context.onOpenChange(true);
317
+ /* Stop keydown from scrolling window */
318
+ event.preventDefault();
319
+ }
320
+ })}
321
+ >
322
+ {requireReactElement(children)}
323
+ </Slot>
324
+ </Menu.Anchor>
325
+ );
326
+ },
327
+ );
328
+
329
+ /* -------------------------------------------------------------------------- */
330
+ /* ActionMenuContent */
331
+ /* -------------------------------------------------------------------------- */
332
+ interface ActionMenuContentProps
333
+ extends Omit<React.HTMLAttributes<HTMLDivElement>, "id"> {
334
+ children?: React.ReactNode;
335
+ }
336
+
337
+ export const ActionMenuContent = forwardRef<
338
+ HTMLDivElement,
339
+ ActionMenuContentProps
340
+ >(({ children, className, style, ...rest }: ActionMenuContentProps, ref) => {
341
+ const context = useActionMenuContext();
342
+
343
+ return (
344
+ <Menu.Portal rootElement={context.rootElement} asChild>
345
+ <Menu.Content
346
+ ref={ref}
347
+ id={context.contentId}
348
+ aria-labelledby={context.triggerId}
349
+ className={cl("navds-action-menu__content", className)}
350
+ {...rest}
351
+ align="start"
352
+ sideOffset={4}
353
+ collisionPadding={10}
354
+ onCloseAutoFocus={() => {
355
+ context.triggerRef.current?.focus();
356
+ }}
357
+ safeZone={{ anchor: context.triggerRef.current }}
358
+ style={{
359
+ ...style,
360
+ ...{
361
+ "--__ac-action-menu-content-transform-origin":
362
+ "var(--ac-floating-transform-origin)",
363
+ "--__ac-action-menu-content-available-height":
364
+ "var(--ac-floating-available-height)",
365
+ },
366
+ }}
367
+ >
368
+ <div className="navds-action-menu__content-inner">{children}</div>
369
+ </Menu.Content>
370
+ </Menu.Portal>
371
+ );
372
+ });
373
+
374
+ /* -------------------------------------------------------------------------- */
375
+ /* ActionMenuLabel */
376
+ /* -------------------------------------------------------------------------- */
377
+ interface ActionMenuLabelProps extends React.HTMLAttributes<HTMLDivElement> {
378
+ children: React.ReactNode;
379
+ }
380
+
381
+ export const ActionMenuLabel = forwardRef<HTMLDivElement, ActionMenuLabelProps>(
382
+ ({ children, className, ...rest }: ActionMenuLabelProps, ref) => {
383
+ return (
384
+ <div
385
+ ref={ref}
386
+ {...rest}
387
+ className={cl("navds-action-menu__label", className)}
388
+ >
389
+ {children}
390
+ </div>
391
+ );
392
+ },
393
+ );
394
+
395
+ /* -------------------------------------------------------------------------- */
396
+ /* ActionMenuGroup */
397
+ /* -------------------------------------------------------------------------- */
398
+ type ActionMenuGroupElement = React.ElementRef<typeof Menu.Group>;
399
+ type MenuGroupProps = React.ComponentPropsWithoutRef<typeof Menu.Group>;
400
+
401
+ type ActionMenuGroupLabelingProps =
402
+ | {
403
+ /**
404
+ * Adds a visual and accessible label to the group.
405
+ */
406
+ label: string;
407
+ /**
408
+ * Adds an aria-label to the group.
409
+ */
410
+ "aria-label"?: never;
411
+ }
412
+ | {
413
+ /**
414
+ * Adds an aria-label to the group.
415
+ */
416
+ "aria-label": string;
417
+ /**
418
+ * Adds a visual and accessible label to the group.
419
+ */
420
+ label?: never;
421
+ };
422
+
423
+ type ActionMenuGroupProps = Omit<MenuGroupProps, "asChild"> &
424
+ ActionMenuGroupLabelingProps;
425
+
426
+ export const ActionMenuGroup = forwardRef<
427
+ ActionMenuGroupElement,
428
+ ActionMenuGroupProps
429
+ >(({ children, className, label, ...rest }: ActionMenuGroupProps, ref) => {
430
+ const labelId = useId();
431
+
432
+ return (
433
+ <Menu.Group
434
+ ref={ref}
435
+ {...rest}
436
+ className={cl("navds-action-menu__group", className)}
437
+ asChild={false}
438
+ aria-labelledby={label ? labelId : undefined}
439
+ >
440
+ {label && (
441
+ <ActionMenu.Label id={labelId} aria-hidden>
442
+ {label}
443
+ </ActionMenu.Label>
444
+ )}
445
+ {children}
446
+ </Menu.Group>
447
+ );
448
+ });
449
+
450
+ /* -------------------------------------------------------------------------- */
451
+ /* Utility components */
452
+ /* -------------------------------------------------------------------------- */
453
+ type MarkerProps = {
454
+ children: React.ReactNode;
455
+ className?: string;
456
+ placement: "left" | "right";
457
+ };
458
+
459
+ const Marker = ({ children, className, placement }: MarkerProps) => {
460
+ return (
461
+ <div
462
+ aria-hidden
463
+ className={cl(
464
+ className,
465
+ "navds-action-menu__marker",
466
+ `navds-action-menu__marker--${placement}`,
467
+ )}
468
+ >
469
+ {children}
470
+ </div>
471
+ );
472
+ };
473
+
474
+ type ShortcutProps = {
475
+ children: string;
476
+ };
477
+
478
+ const Shortcut = ({ children }: ShortcutProps) => {
479
+ /**
480
+ * Assumes the user will input either a single keyboard key
481
+ * or keys separated by "+"
482
+ */
483
+ const parsed = children.split("+").filter((str) => str !== "");
484
+
485
+ return (
486
+ <Marker placement="right">
487
+ {parsed.map((char, index) => (
488
+ <span key={char + index} className="navds-action-menu__shortcut">
489
+ {char}
490
+ </span>
491
+ ))}
492
+ </Marker>
493
+ );
494
+ };
495
+
496
+ /* -------------------------------------------------------------------------- */
497
+ /* ActionMenuItem */
498
+ /* -------------------------------------------------------------------------- */
499
+ type ActionMenuItemElement = React.ElementRef<typeof Menu.Item>;
500
+ type MenuItemProps = React.ComponentPropsWithoutRef<typeof Menu.Item>;
501
+
502
+ interface ActionMenuItemProps extends Omit<MenuItemProps, "asChild"> {
503
+ /**
504
+ * Shows connected shortcut-keys for the item.
505
+ * This is only a visual representation, you will have to implement the actual shortcut yourself.
506
+ */
507
+ shortcut?: string;
508
+ /**
509
+ * Styles the item as a destructive action.
510
+ */
511
+ variant?: "danger";
512
+ /**
513
+ * Adds an icon on the left side. The icon will always have aria-hidden.
514
+ */
515
+ icon?: React.ReactNode;
516
+ }
517
+
518
+ export const ActionMenuItem: OverridableComponent<
519
+ ActionMenuItemProps,
520
+ ActionMenuItemElement
521
+ > = forwardRef(
522
+ (
523
+ {
524
+ children,
525
+ as: Component = "div",
526
+ className,
527
+ icon,
528
+ shortcut,
529
+ variant,
530
+ ...rest
531
+ },
532
+ ref,
533
+ ) => {
534
+ return (
535
+ <Menu.Item
536
+ {...rest}
537
+ className={cl("navds-action-menu__item", className, {
538
+ "navds-action-menu__item--danger": variant === "danger",
539
+ "navds-action-menu__item--has-icon": icon,
540
+ })}
541
+ aria-keyshortcuts={shortcut ?? undefined}
542
+ asChild
543
+ >
544
+ <Component ref={ref}>
545
+ {children}
546
+ {icon && (
547
+ <Marker placement="left" className="navds-action-menu__marker-icon">
548
+ {icon}
549
+ </Marker>
550
+ )}
551
+ {shortcut && <Shortcut>{shortcut}</Shortcut>}
552
+ </Component>
553
+ </Menu.Item>
554
+ );
555
+ },
556
+ );
557
+
558
+ /* -------------------------------------------------------------------------- */
559
+ /* ActionMenuCheckboxItem */
560
+ /* -------------------------------------------------------------------------- */
561
+ type ActionMenuCheckboxItemElement = React.ElementRef<typeof Menu.CheckboxItem>;
562
+ type MenuCheckboxItemProps = React.ComponentPropsWithoutRef<
563
+ typeof Menu.CheckboxItem
564
+ >;
565
+
566
+ interface ActionMenuCheckboxItemProps
567
+ extends Omit<MenuCheckboxItemProps, "asChild"> {
568
+ children: React.ReactNode;
569
+ /**
570
+ * Shows connected shortcut-keys for the item.
571
+ * This is only a visual representation, you will have to implement the actual shortcut yourself.
572
+ */
573
+ shortcut?: string;
574
+ }
575
+
576
+ export const ActionMenuCheckboxItem = forwardRef<
577
+ ActionMenuCheckboxItemElement,
578
+ ActionMenuCheckboxItemProps
579
+ >(
580
+ (
581
+ {
582
+ children,
583
+ className,
584
+ shortcut,
585
+ onSelect,
586
+ ...rest
587
+ }: ActionMenuCheckboxItemProps,
588
+ ref,
589
+ ) => {
590
+ return (
591
+ <Menu.CheckboxItem
592
+ ref={ref}
593
+ {...rest}
594
+ onSelect={composeEventHandlers(onSelect, (event) => {
595
+ /**
596
+ * Prevent default to avoid the menu from closing when clicking the checkbox
597
+ */
598
+ event.preventDefault();
599
+ })}
600
+ asChild={false}
601
+ className={cl(
602
+ "navds-action-menu__item navds-action-menu__item--has-icon",
603
+ className,
604
+ )}
605
+ aria-keyshortcuts={shortcut}
606
+ >
607
+ {children}
608
+ <Marker placement="left">
609
+ <Menu.ItemIndicator className="navds-action-menu__indicator">
610
+ <svg
611
+ width="1em"
612
+ height="1em"
613
+ viewBox="0 0 24 24"
614
+ fill="none"
615
+ xmlns="http://www.w3.org/2000/svg"
616
+ className="navds-action-menu__indicator-icon"
617
+ aria-hidden
618
+ >
619
+ <g className="navds-action-menu__indicator-icon--unchecked">
620
+ <rect
621
+ width="24"
622
+ height="24"
623
+ rx="4"
624
+ fill="var(--a-border-default)"
625
+ />
626
+ <rect
627
+ x="1"
628
+ y="1"
629
+ width="22"
630
+ height="22"
631
+ rx="3"
632
+ fill="var(--a-surface-default)"
633
+ strokeWidth="2"
634
+ />
635
+ </g>
636
+ <g className="navds-action-menu__indicator-icon--indeterminate">
637
+ <rect
638
+ width="24"
639
+ height="24"
640
+ rx="4"
641
+ fill="var(--a-surface-action-selected)"
642
+ />
643
+ <rect
644
+ x="6"
645
+ y="10"
646
+ width="12"
647
+ height="4"
648
+ rx="1"
649
+ fill="var(--a-surface-default)"
650
+ />
651
+ </g>
652
+ <g className="navds-action-menu__indicator-icon--checked">
653
+ <rect
654
+ width="24"
655
+ height="24"
656
+ rx="4"
657
+ fill="var(--a-surface-action-selected)"
658
+ />
659
+ <path
660
+ d="M10.0352 13.4148L16.4752 7.40467C17.0792 6.83965 18.029 6.86933 18.5955 7.47478C19.162 8.08027 19.1296 9.03007 18.5245 9.59621L11.0211 16.5993C10.741 16.859 10.3756 17 10.0002 17C9.60651 17 9.22717 16.8462 8.93914 16.5611L6.43914 14.0611C5.85362 13.4756 5.85362 12.5254 6.43914 11.9399C7.02467 11.3544 7.97483 11.3544 8.56036 11.9399L10.0352 13.4148Z"
661
+ fill="var(--a-surface-default)"
662
+ />
663
+ </g>
664
+ </svg>
665
+ </Menu.ItemIndicator>
666
+ </Marker>
667
+
668
+ {shortcut && <Shortcut>{shortcut}</Shortcut>}
669
+ </Menu.CheckboxItem>
670
+ );
671
+ },
672
+ );
673
+
674
+ /* -------------------------------------------------------------------------- */
675
+ /* ActionMenuRadioGroup */
676
+ /* -------------------------------------------------------------------------- */
677
+ type ActionMenuRadioGroupElement = React.ElementRef<typeof Menu.RadioGroup>;
678
+ type MenuRadioGroupProps = React.ComponentPropsWithoutRef<
679
+ typeof Menu.RadioGroup
680
+ >;
681
+ type ActionMenuRadioGroupProps = ActionMenuGroupLabelingProps &
682
+ Omit<MenuRadioGroupProps, "asChild"> & {
683
+ children: React.ReactNode;
684
+ };
685
+
686
+ export const ActionMenuRadioGroup = forwardRef<
687
+ ActionMenuRadioGroupElement,
688
+ ActionMenuRadioGroupProps
689
+ >(({ children, label, ...rest }: ActionMenuRadioGroupProps, ref) => {
690
+ const labelId = useId();
691
+
692
+ return (
693
+ <Menu.RadioGroup
694
+ ref={ref}
695
+ {...rest}
696
+ asChild={false}
697
+ aria-labelledby={label ? labelId : undefined}
698
+ >
699
+ {label && (
700
+ <ActionMenu.Label id={labelId} aria-hidden>
701
+ {label}
702
+ </ActionMenu.Label>
703
+ )}
704
+ {children}
705
+ </Menu.RadioGroup>
706
+ );
707
+ });
708
+
709
+ /* -------------------------------------------------------------------------- */
710
+ /* ActionMenuRadioItem */
711
+ /* -------------------------------------------------------------------------- */
712
+ type ActionMenuRadioItemElement = React.ElementRef<typeof Menu.RadioItem>;
713
+ type MenuRadioItemProps = React.ComponentPropsWithoutRef<typeof Menu.RadioItem>;
714
+ interface ActionMenuRadioItemProps extends Omit<MenuRadioItemProps, "asChild"> {
715
+ children: React.ReactNode;
716
+ }
717
+
718
+ export const ActionMenuRadioItem = forwardRef<
719
+ ActionMenuRadioItemElement,
720
+ ActionMenuRadioItemProps
721
+ >(
722
+ (
723
+ { children, className, onSelect, ...rest }: ActionMenuRadioItemProps,
724
+ ref,
725
+ ) => {
726
+ return (
727
+ <Menu.RadioItem
728
+ ref={ref}
729
+ {...rest}
730
+ onSelect={composeEventHandlers(onSelect, (event) => {
731
+ /**
732
+ * Prevent default to avoid the menu from closing when clicking the radio
733
+ */
734
+ event.preventDefault();
735
+ })}
736
+ asChild={false}
737
+ className={cl(
738
+ "navds-action-menu__item navds-action-menu__item--has-icon",
739
+ className,
740
+ )}
741
+ >
742
+ {children}
743
+ <Marker placement="left">
744
+ <Menu.ItemIndicator className="navds-action-menu__indicator">
745
+ <svg
746
+ width="1em"
747
+ height="1em"
748
+ viewBox="0 0 24 24"
749
+ fill="none"
750
+ xmlns="http://www.w3.org/2000/svg"
751
+ className="navds-action-menu__indicator-icon"
752
+ aria-hidden
753
+ >
754
+ <g className="navds-action-menu__indicator-icon--unchecked">
755
+ <rect
756
+ width="24"
757
+ height="24"
758
+ rx="12"
759
+ fill="var(--a-border-default)"
760
+ />
761
+ <rect
762
+ x="1"
763
+ y="1"
764
+ width="22"
765
+ height="22"
766
+ rx="11"
767
+ strokeWidth="2"
768
+ fill="var(--a-surface-default)"
769
+ />
770
+ </g>
771
+ <g className="navds-action-menu__indicator-icon--checked">
772
+ <rect
773
+ x="1"
774
+ y="1"
775
+ width="22"
776
+ height="22"
777
+ rx="11"
778
+ fill="var(--a-surface-default)"
779
+ />
780
+ <rect
781
+ x="1"
782
+ y="1"
783
+ width="22"
784
+ height="22"
785
+ rx="11"
786
+ stroke="var(--a-surface-action-selected)"
787
+ strokeWidth="2"
788
+ />
789
+ <path
790
+ d="M20 12C20 16.4178 16.4178 20 12 20C7.58222 20 4 16.4178 4 12C4 7.58222 7.58222 4 12 4C16.4178 4 20 7.58222 20 12Z"
791
+ fill="var(--a-surface-action-selected)"
792
+ />
793
+ </g>
794
+ </svg>
795
+ </Menu.ItemIndicator>
796
+ </Marker>
797
+ </Menu.RadioItem>
798
+ );
799
+ },
800
+ );
801
+
802
+ /* -------------------------------------------------------------------------- */
803
+ /* ActionMenuDivider */
804
+ /* -------------------------------------------------------------------------- */
805
+ type ActionMenuDividerElement = React.ElementRef<typeof Menu.Divider>;
806
+ type MenuDividerProps = React.ComponentPropsWithoutRef<typeof Menu.Divider>;
807
+ type ActionMenuDividerProps = Omit<MenuDividerProps, "asChild">;
808
+
809
+ export const ActionMenuDivider = forwardRef<
810
+ ActionMenuDividerElement,
811
+ ActionMenuDividerProps
812
+ >(({ className, ...rest }: ActionMenuDividerProps, ref) => {
813
+ return (
814
+ <Menu.Divider
815
+ ref={ref}
816
+ asChild={false}
817
+ {...rest}
818
+ className={cl("navds-action-menu__divider", className)}
819
+ />
820
+ );
821
+ });
822
+
823
+ /* -------------------------------------------------------------------------- */
824
+ /* ActionMenuSub */
825
+ /* -------------------------------------------------------------------------- */
826
+ interface ActionMenuSubProps {
827
+ children?: React.ReactNode;
828
+ /**
829
+ * Whether the sub-menu is open or not. Only needed if you want to manually control state.
830
+ */
831
+ open?: boolean;
832
+ /**
833
+ * Callback for when the sub-menu is opened or closed.
834
+ */
835
+ onOpenChange?: (open: boolean) => void;
836
+ }
837
+
838
+ export const ActionMenuSub = (props: ActionMenuSubProps) => {
839
+ const { children, open: openProp, onOpenChange } = props;
840
+
841
+ const [open = false, setOpen] = useControllableState({
842
+ value: openProp,
843
+ defaultValue: false,
844
+ onChange: onOpenChange,
845
+ });
846
+
847
+ return (
848
+ <Menu.Sub open={open} onOpenChange={setOpen}>
849
+ {children}
850
+ </Menu.Sub>
851
+ );
852
+ };
853
+
854
+ /* -------------------------------------------------------------------------- */
855
+ /* ActionMenuSubTrigger */
856
+ /* -------------------------------------------------------------------------- */
857
+ type ActionMenuSubTriggerElement = React.ElementRef<typeof Menu.SubTrigger>;
858
+ type MenuSubTriggerProps = React.ComponentPropsWithoutRef<
859
+ typeof Menu.SubTrigger
860
+ >;
861
+ interface ActionMenuSubTriggerProps
862
+ extends Omit<MenuSubTriggerProps, "asChild"> {
863
+ icon?: React.ReactNode;
864
+ }
865
+
866
+ export const ActionMenuSubTrigger = forwardRef<
867
+ ActionMenuSubTriggerElement,
868
+ ActionMenuSubTriggerProps
869
+ >(({ children, className, icon, ...rest }: ActionMenuSubTriggerProps, ref) => {
870
+ return (
871
+ <Menu.SubTrigger
872
+ ref={ref}
873
+ {...rest}
874
+ asChild={false}
875
+ className={cl(
876
+ "navds-action-menu__item navds-action-menu__sub-trigger",
877
+ className,
878
+ { "navds-action-menu__item--has-icon": icon },
879
+ )}
880
+ >
881
+ {children}
882
+ {icon && (
883
+ <Marker placement="left" className="navds-action-menu__marker-icon">
884
+ {icon}
885
+ </Marker>
886
+ )}
887
+ <Marker placement="right" className="navds-action-menu__marker-icon">
888
+ <ChevronRightIcon aria-hidden />
889
+ </Marker>
890
+ </Menu.SubTrigger>
891
+ );
892
+ });
893
+
894
+ /* -------------------------------------------------------------------------- */
895
+ /* ActionMenuSubContent */
896
+ /* -------------------------------------------------------------------------- */
897
+ type ActionMenuSubContentElement = React.ElementRef<typeof Menu.Content>;
898
+
899
+ interface ActionMenuSubContentProps
900
+ extends React.HTMLAttributes<HTMLDivElement> {
901
+ children: React.ReactNode;
902
+ }
903
+
904
+ export const ActionMenuSubContent = forwardRef<
905
+ ActionMenuSubContentElement,
906
+ ActionMenuSubContentProps
907
+ >(({ children, className, style, ...rest }: ActionMenuSubContentProps, ref) => {
908
+ const context = useActionMenuContext();
909
+
910
+ return (
911
+ <Menu.Portal rootElement={context.rootElement}>
912
+ <Menu.SubContent
913
+ ref={ref}
914
+ alignOffset={-4}
915
+ sideOffset={1}
916
+ collisionPadding={10}
917
+ {...rest}
918
+ className={cl(
919
+ "navds-action-menu__content navds-action-menu__sub-content",
920
+ className,
921
+ )}
922
+ style={{
923
+ ...style,
924
+ ...{
925
+ "--ac-action-menu-content-transform-origin":
926
+ "var(--ac-floating-transform-origin)",
927
+ "--ac-action-menu-content-available-width":
928
+ "var(--ac-floating-available-width)",
929
+ "--ac-action-menu-content-available-height":
930
+ "var(--ac-floating-available-height)",
931
+ "--ac-action-menu-trigger-width": "var(--ac-floating-anchor-width)",
932
+ "--ac-action-menu-trigger-height":
933
+ "var(--ac-floating-anchor-height)",
934
+ },
935
+ }}
936
+ >
937
+ <div className="navds-action-menu__content-inner">{children}</div>
938
+ </Menu.SubContent>
939
+ </Menu.Portal>
940
+ );
941
+ });
942
+
943
+ /* -------------------------------------------------------------------------- */
944
+ ActionMenu.Trigger = ActionMenuTrigger;
945
+ ActionMenu.Content = ActionMenuContent;
946
+ ActionMenu.Group = ActionMenuGroup;
947
+ ActionMenu.Label = ActionMenuLabel;
948
+ ActionMenu.Item = ActionMenuItem;
949
+ ActionMenu.CheckboxItem = ActionMenuCheckboxItem;
950
+ ActionMenu.RadioGroup = ActionMenuRadioGroup;
951
+ ActionMenu.RadioItem = ActionMenuRadioItem;
952
+ ActionMenu.Divider = ActionMenuDivider;
953
+ ActionMenu.Sub = ActionMenuSub;
954
+ ActionMenu.SubTrigger = ActionMenuSubTrigger;
955
+ ActionMenu.SubContent = ActionMenuSubContent;
956
+
957
+ export type {
958
+ ActionMenuItemProps,
959
+ ActionMenuCheckboxItemProps,
960
+ ActionMenuContentProps,
961
+ ActionMenuDividerProps,
962
+ ActionMenuGroupProps,
963
+ ActionMenuLabelProps,
964
+ ActionMenuProps,
965
+ ActionMenuRadioGroupProps,
966
+ ActionMenuRadioItemProps,
967
+ ActionMenuSubContentProps,
968
+ ActionMenuSubProps,
969
+ ActionMenuSubTriggerProps,
970
+ ActionMenuTriggerProps,
971
+ };