@tamagui/create-menu 2.0.0-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 (162) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/MenuPredefined.cjs +182 -0
  3. package/dist/cjs/MenuPredefined.js +162 -0
  4. package/dist/cjs/MenuPredefined.js.map +6 -0
  5. package/dist/cjs/MenuPredefined.native.js +185 -0
  6. package/dist/cjs/MenuPredefined.native.js.map +1 -0
  7. package/dist/cjs/createBaseMenu.cjs +927 -0
  8. package/dist/cjs/createBaseMenu.js +724 -0
  9. package/dist/cjs/createBaseMenu.js.map +6 -0
  10. package/dist/cjs/createBaseMenu.native.js +1105 -0
  11. package/dist/cjs/createBaseMenu.native.js.map +1 -0
  12. package/dist/cjs/createNativeMenu/createNativeMenu.cjs +224 -0
  13. package/dist/cjs/createNativeMenu/createNativeMenu.js +172 -0
  14. package/dist/cjs/createNativeMenu/createNativeMenu.js.map +6 -0
  15. package/dist/cjs/createNativeMenu/createNativeMenu.native.js +287 -0
  16. package/dist/cjs/createNativeMenu/createNativeMenu.native.js.map +1 -0
  17. package/dist/cjs/createNativeMenu/createNativeMenuTypes.cjs +16 -0
  18. package/dist/cjs/createNativeMenu/createNativeMenuTypes.js +14 -0
  19. package/dist/cjs/createNativeMenu/createNativeMenuTypes.js.map +6 -0
  20. package/dist/cjs/createNativeMenu/createNativeMenuTypes.native.js +19 -0
  21. package/dist/cjs/createNativeMenu/createNativeMenuTypes.native.js.map +1 -0
  22. package/dist/cjs/createNativeMenu/index.cjs +19 -0
  23. package/dist/cjs/createNativeMenu/index.js +16 -0
  24. package/dist/cjs/createNativeMenu/index.js.map +6 -0
  25. package/dist/cjs/createNativeMenu/index.native.js +22 -0
  26. package/dist/cjs/createNativeMenu/index.native.js.map +1 -0
  27. package/dist/cjs/createNativeMenu/utils.cjs +68 -0
  28. package/dist/cjs/createNativeMenu/utils.js +66 -0
  29. package/dist/cjs/createNativeMenu/utils.js.map +6 -0
  30. package/dist/cjs/createNativeMenu/utils.native.js +94 -0
  31. package/dist/cjs/createNativeMenu/utils.native.js.map +1 -0
  32. package/dist/cjs/createNativeMenu/withNativeMenu.cjs +37 -0
  33. package/dist/cjs/createNativeMenu/withNativeMenu.js +30 -0
  34. package/dist/cjs/createNativeMenu/withNativeMenu.js.map +6 -0
  35. package/dist/cjs/createNativeMenu/withNativeMenu.native.js +43 -0
  36. package/dist/cjs/createNativeMenu/withNativeMenu.native.js.map +1 -0
  37. package/dist/cjs/index.cjs +30 -0
  38. package/dist/cjs/index.js +24 -0
  39. package/dist/cjs/index.js.map +6 -0
  40. package/dist/cjs/index.native.js +33 -0
  41. package/dist/cjs/index.native.js.map +1 -0
  42. package/dist/esm/MenuPredefined.js +147 -0
  43. package/dist/esm/MenuPredefined.js.map +6 -0
  44. package/dist/esm/MenuPredefined.mjs +159 -0
  45. package/dist/esm/MenuPredefined.mjs.map +1 -0
  46. package/dist/esm/MenuPredefined.native.js +159 -0
  47. package/dist/esm/MenuPredefined.native.js.map +1 -0
  48. package/dist/esm/createBaseMenu.js +729 -0
  49. package/dist/esm/createBaseMenu.js.map +6 -0
  50. package/dist/esm/createBaseMenu.mjs +893 -0
  51. package/dist/esm/createBaseMenu.mjs.map +1 -0
  52. package/dist/esm/createBaseMenu.native.js +1068 -0
  53. package/dist/esm/createBaseMenu.native.js.map +1 -0
  54. package/dist/esm/createNativeMenu/createNativeMenu.js +150 -0
  55. package/dist/esm/createNativeMenu/createNativeMenu.js.map +6 -0
  56. package/dist/esm/createNativeMenu/createNativeMenu.mjs +190 -0
  57. package/dist/esm/createNativeMenu/createNativeMenu.mjs.map +1 -0
  58. package/dist/esm/createNativeMenu/createNativeMenu.native.js +250 -0
  59. package/dist/esm/createNativeMenu/createNativeMenu.native.js.map +1 -0
  60. package/dist/esm/createNativeMenu/createNativeMenuTypes.js +1 -0
  61. package/dist/esm/createNativeMenu/createNativeMenuTypes.js.map +6 -0
  62. package/dist/esm/createNativeMenu/createNativeMenuTypes.mjs +2 -0
  63. package/dist/esm/createNativeMenu/createNativeMenuTypes.mjs.map +1 -0
  64. package/dist/esm/createNativeMenu/createNativeMenuTypes.native.js +2 -0
  65. package/dist/esm/createNativeMenu/createNativeMenuTypes.native.js.map +1 -0
  66. package/dist/esm/createNativeMenu/index.js +3 -0
  67. package/dist/esm/createNativeMenu/index.js.map +6 -0
  68. package/dist/esm/createNativeMenu/index.mjs +3 -0
  69. package/dist/esm/createNativeMenu/index.mjs.map +1 -0
  70. package/dist/esm/createNativeMenu/index.native.js +3 -0
  71. package/dist/esm/createNativeMenu/index.native.js.map +1 -0
  72. package/dist/esm/createNativeMenu/utils.js +47 -0
  73. package/dist/esm/createNativeMenu/utils.js.map +6 -0
  74. package/dist/esm/createNativeMenu/utils.mjs +29 -0
  75. package/dist/esm/createNativeMenu/utils.mjs.map +1 -0
  76. package/dist/esm/createNativeMenu/utils.native.js +52 -0
  77. package/dist/esm/createNativeMenu/utils.native.js.map +1 -0
  78. package/dist/esm/createNativeMenu/withNativeMenu.js +15 -0
  79. package/dist/esm/createNativeMenu/withNativeMenu.js.map +6 -0
  80. package/dist/esm/createNativeMenu/withNativeMenu.mjs +14 -0
  81. package/dist/esm/createNativeMenu/withNativeMenu.mjs.map +1 -0
  82. package/dist/esm/createNativeMenu/withNativeMenu.native.js +17 -0
  83. package/dist/esm/createNativeMenu/withNativeMenu.native.js.map +1 -0
  84. package/dist/esm/index.js +8 -0
  85. package/dist/esm/index.js.map +6 -0
  86. package/dist/esm/index.mjs +6 -0
  87. package/dist/esm/index.mjs.map +1 -0
  88. package/dist/esm/index.native.js +6 -0
  89. package/dist/esm/index.native.js.map +1 -0
  90. package/dist/jsx/MenuPredefined.js +147 -0
  91. package/dist/jsx/MenuPredefined.js.map +6 -0
  92. package/dist/jsx/MenuPredefined.mjs +159 -0
  93. package/dist/jsx/MenuPredefined.mjs.map +1 -0
  94. package/dist/jsx/MenuPredefined.native.js +185 -0
  95. package/dist/jsx/MenuPredefined.native.js.map +1 -0
  96. package/dist/jsx/createBaseMenu.js +729 -0
  97. package/dist/jsx/createBaseMenu.js.map +6 -0
  98. package/dist/jsx/createBaseMenu.mjs +893 -0
  99. package/dist/jsx/createBaseMenu.mjs.map +1 -0
  100. package/dist/jsx/createBaseMenu.native.js +1105 -0
  101. package/dist/jsx/createBaseMenu.native.js.map +1 -0
  102. package/dist/jsx/createNativeMenu/createNativeMenu.js +150 -0
  103. package/dist/jsx/createNativeMenu/createNativeMenu.js.map +6 -0
  104. package/dist/jsx/createNativeMenu/createNativeMenu.mjs +190 -0
  105. package/dist/jsx/createNativeMenu/createNativeMenu.mjs.map +1 -0
  106. package/dist/jsx/createNativeMenu/createNativeMenu.native.js +287 -0
  107. package/dist/jsx/createNativeMenu/createNativeMenu.native.js.map +1 -0
  108. package/dist/jsx/createNativeMenu/createNativeMenuTypes.js +1 -0
  109. package/dist/jsx/createNativeMenu/createNativeMenuTypes.js.map +6 -0
  110. package/dist/jsx/createNativeMenu/createNativeMenuTypes.mjs +2 -0
  111. package/dist/jsx/createNativeMenu/createNativeMenuTypes.mjs.map +1 -0
  112. package/dist/jsx/createNativeMenu/createNativeMenuTypes.native.js +19 -0
  113. package/dist/jsx/createNativeMenu/createNativeMenuTypes.native.js.map +1 -0
  114. package/dist/jsx/createNativeMenu/index.js +3 -0
  115. package/dist/jsx/createNativeMenu/index.js.map +6 -0
  116. package/dist/jsx/createNativeMenu/index.mjs +3 -0
  117. package/dist/jsx/createNativeMenu/index.mjs.map +1 -0
  118. package/dist/jsx/createNativeMenu/index.native.js +22 -0
  119. package/dist/jsx/createNativeMenu/index.native.js.map +1 -0
  120. package/dist/jsx/createNativeMenu/utils.js +47 -0
  121. package/dist/jsx/createNativeMenu/utils.js.map +6 -0
  122. package/dist/jsx/createNativeMenu/utils.mjs +29 -0
  123. package/dist/jsx/createNativeMenu/utils.mjs.map +1 -0
  124. package/dist/jsx/createNativeMenu/utils.native.js +94 -0
  125. package/dist/jsx/createNativeMenu/utils.native.js.map +1 -0
  126. package/dist/jsx/createNativeMenu/withNativeMenu.js +15 -0
  127. package/dist/jsx/createNativeMenu/withNativeMenu.js.map +6 -0
  128. package/dist/jsx/createNativeMenu/withNativeMenu.mjs +14 -0
  129. package/dist/jsx/createNativeMenu/withNativeMenu.mjs.map +1 -0
  130. package/dist/jsx/createNativeMenu/withNativeMenu.native.js +43 -0
  131. package/dist/jsx/createNativeMenu/withNativeMenu.native.js.map +1 -0
  132. package/dist/jsx/index.js +8 -0
  133. package/dist/jsx/index.js.map +6 -0
  134. package/dist/jsx/index.mjs +6 -0
  135. package/dist/jsx/index.mjs.map +1 -0
  136. package/dist/jsx/index.native.js +33 -0
  137. package/dist/jsx/index.native.js.map +1 -0
  138. package/package.json +80 -0
  139. package/src/MenuPredefined.tsx +195 -0
  140. package/src/createBaseMenu.tsx +1703 -0
  141. package/src/createNativeMenu/createNativeMenu.tsx +372 -0
  142. package/src/createNativeMenu/createNativeMenuTypes.ts +214 -0
  143. package/src/createNativeMenu/index.tsx +7 -0
  144. package/src/createNativeMenu/utils.tsx +150 -0
  145. package/src/createNativeMenu/withNativeMenu.tsx +38 -0
  146. package/src/index.tsx +9 -0
  147. package/types/MenuPredefined.d.ts +28 -0
  148. package/types/MenuPredefined.d.ts.map +1 -0
  149. package/types/createBaseMenu.d.ts +207 -0
  150. package/types/createBaseMenu.d.ts.map +1 -0
  151. package/types/createNativeMenu/createNativeMenu.d.ts +42 -0
  152. package/types/createNativeMenu/createNativeMenu.d.ts.map +1 -0
  153. package/types/createNativeMenu/createNativeMenuTypes.d.ts +188 -0
  154. package/types/createNativeMenu/createNativeMenuTypes.d.ts.map +1 -0
  155. package/types/createNativeMenu/index.d.ts +4 -0
  156. package/types/createNativeMenu/index.d.ts.map +1 -0
  157. package/types/createNativeMenu/utils.d.ts +38 -0
  158. package/types/createNativeMenu/utils.d.ts.map +1 -0
  159. package/types/createNativeMenu/withNativeMenu.d.ts +9 -0
  160. package/types/createNativeMenu/withNativeMenu.d.ts.map +1 -0
  161. package/types/index.d.ts +6 -0
  162. package/types/index.d.ts.map +1 -0
@@ -0,0 +1,729 @@
1
+ import { Animate } from "@tamagui/animate";
2
+ import { AnimatePresence as Presence } from "@tamagui/animate-presence";
3
+ import { createCollection } from "@tamagui/collection";
4
+ import {
5
+ Dismissable as DismissableLayer,
6
+ dispatchDiscreteCustomEvent
7
+ } from "@tamagui/dismissable";
8
+ import { useFocusGuards } from "@tamagui/focus-guard";
9
+ import { FocusScope } from "@tamagui/focus-scope";
10
+ import * as PopperPrimitive from "@tamagui/popper";
11
+ import { Portal as PortalPrimitive } from "@tamagui/portal";
12
+ import { RemoveScroll } from "@tamagui/remove-scroll";
13
+ import { RovingFocusGroup } from "@tamagui/roving-focus";
14
+ import { useCallbackRef } from "@tamagui/use-callback-ref";
15
+ import { useDirection } from "@tamagui/use-direction";
16
+ import {
17
+ Text,
18
+ View,
19
+ composeEventHandlers,
20
+ composeRefs,
21
+ createStyledContext,
22
+ isAndroid,
23
+ isWeb,
24
+ useComposedRefs,
25
+ withStaticProperties
26
+ } from "@tamagui/web";
27
+ import * as React from "react";
28
+ import { useId } from "react";
29
+ import { MenuPredefined } from "./MenuPredefined";
30
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
31
+ function whenMouse(handler) {
32
+ return (event) => event.pointerType === "mouse" ? handler(event) : void 0;
33
+ }
34
+ const SELECTION_KEYS = ["Enter", " "], FIRST_KEYS = ["ArrowDown", "PageUp", "Home"], LAST_KEYS = ["ArrowUp", "PageDown", "End"], FIRST_LAST_KEYS = [...FIRST_KEYS, ...LAST_KEYS], SUB_OPEN_KEYS = {
35
+ ltr: [...SELECTION_KEYS, "ArrowRight"],
36
+ rtl: [...SELECTION_KEYS, "ArrowLeft"]
37
+ }, SUB_CLOSE_KEYS = {
38
+ ltr: ["ArrowLeft"],
39
+ rtl: ["ArrowRight"]
40
+ }, MENU_NAME = "Menu", [Collection, useCollection] = createCollection(MENU_NAME), { Provider: MenuProvider, useStyledContext: useMenuContext } = createStyledContext(), { Provider: MenuRootProvider, useStyledContext: useMenuRootContext } = createStyledContext(), MENU_CONTEXT = "MenuContext";
41
+ function createBaseMenu({
42
+ Item: _Item = MenuPredefined.MenuItem,
43
+ Title: _Title = MenuPredefined.Title,
44
+ SubTitle: _SubTitle = MenuPredefined.SubTitle,
45
+ Image: _Image = MenuPredefined.MenuImage,
46
+ Icon: _Icon = MenuPredefined.MenuIcon,
47
+ Indicator: _Indicator = MenuPredefined.MenuIndicator,
48
+ Separator: _Separator = MenuPredefined.MenuSeparator,
49
+ MenuGroup: _MenuGroup = MenuPredefined.MenuGroup,
50
+ Label: _Label = MenuPredefined.MenuLabel
51
+ }) {
52
+ const MenuComp = (props) => {
53
+ const {
54
+ scope = MENU_CONTEXT,
55
+ open = !1,
56
+ children,
57
+ dir,
58
+ onOpenChange,
59
+ modal = !0,
60
+ ...rest
61
+ } = props, [content, setContent] = React.useState(null), isUsingKeyboardRef = React.useRef(!1), handleOpenChange = useCallbackRef(onOpenChange), direction = useDirection(dir);
62
+ return isWeb && React.useEffect(() => {
63
+ const handleKeyDown = () => {
64
+ isUsingKeyboardRef.current = !0, document.addEventListener("pointerdown", handlePointer, {
65
+ capture: !0,
66
+ once: !0
67
+ }), document.addEventListener("pointermove", handlePointer, {
68
+ capture: !0,
69
+ once: !0
70
+ });
71
+ }, handlePointer = () => isUsingKeyboardRef.current = !1;
72
+ return document.addEventListener("keydown", handleKeyDown, { capture: !0 }), () => {
73
+ document.removeEventListener("keydown", handleKeyDown, { capture: !0 }), document.removeEventListener("pointerdown", handlePointer, { capture: !0 }), document.removeEventListener("pointermove", handlePointer, { capture: !0 });
74
+ };
75
+ }, []), /* @__PURE__ */ jsx(PopperPrimitive.Popper, { scope, ...rest, children: /* @__PURE__ */ jsx(
76
+ MenuProvider,
77
+ {
78
+ scope,
79
+ open,
80
+ onOpenChange: handleOpenChange,
81
+ content,
82
+ onContentChange: setContent,
83
+ children: /* @__PURE__ */ jsx(
84
+ MenuRootProvider,
85
+ {
86
+ scope,
87
+ onClose: React.useCallback(() => handleOpenChange(!1), [handleOpenChange]),
88
+ isUsingKeyboardRef,
89
+ dir: direction,
90
+ modal,
91
+ children: /* @__PURE__ */ jsx(MenuSubProvider, { scope, children })
92
+ }
93
+ )
94
+ }
95
+ ) });
96
+ }, RepropagateMenuAndMenuRootProvider = (props) => {
97
+ const {
98
+ scope = MENU_CONTEXT,
99
+ menuContext,
100
+ rootContext,
101
+ popperContext,
102
+ menuSubContext,
103
+ children
104
+ } = props;
105
+ return /* @__PURE__ */ jsx(PopperPrimitive.PopperProvider, { ...popperContext, scope, children: /* @__PURE__ */ jsx(MenuProvider, { scope, ...menuContext, children: /* @__PURE__ */ jsx(MenuRootProvider, { scope, ...rootContext, children: menuSubContext ? /* @__PURE__ */ jsx(MenuSubProvider, { scope, ...menuSubContext, children }) : children }) }) });
106
+ };
107
+ MenuComp.displayName = MENU_NAME;
108
+ const ANCHOR_NAME = "MenuAnchor", MenuAnchor = (props) => /* @__PURE__ */ jsx(PopperPrimitive.PopperAnchor, { scope: MENU_CONTEXT, ...props });
109
+ MenuAnchor.displayName = ANCHOR_NAME;
110
+ const PORTAL_NAME = "MenuPortal", { Provider: PortalProvider, useStyledContext: usePortalContext } = createStyledContext(void 0, "Portal"), MenuPortal = (props) => {
111
+ const { scope = MENU_CONTEXT, forceMount, zIndex, children } = props, menuContext = useMenuContext(scope), rootContext = useMenuRootContext(scope), popperContext = PopperPrimitive.usePopperContext(scope), menuSubContext = useMenuSubContext(scope), content = isAndroid ? /* @__PURE__ */ jsx(
112
+ RepropagateMenuAndMenuRootProvider,
113
+ {
114
+ menuContext,
115
+ rootContext,
116
+ popperContext,
117
+ menuSubContext,
118
+ scope,
119
+ children
120
+ }
121
+ ) : children;
122
+ return /* @__PURE__ */ jsx(Animate, { type: "presence", present: forceMount || menuContext.open, children: /* @__PURE__ */ jsx(PortalPrimitive, { children: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(PortalProvider, { scope, forceMount, children: /* @__PURE__ */ jsxs(View, { zIndex: zIndex || 100, inset: 0, position: "absolute", children: [
123
+ !!menuContext.open && !isWeb && /* @__PURE__ */ jsx(
124
+ View,
125
+ {
126
+ inset: 0,
127
+ position: "absolute",
128
+ onPress: () => menuContext.onOpenChange(!menuContext.open)
129
+ }
130
+ ),
131
+ content
132
+ ] }) }) }) }) });
133
+ };
134
+ MenuPortal.displayName = PORTAL_NAME;
135
+ const CONTENT_NAME = "MenuContent", { Provider: MenuContentProvider, useStyledContext: useMenuContentContext } = createStyledContext(), MenuContent = React.forwardRef(
136
+ (props, forwardedRef) => {
137
+ const scope = props.scope || MENU_CONTEXT, portalContext = usePortalContext(scope), { forceMount = portalContext.forceMount, ...contentProps } = props, rootContext = useMenuRootContext(scope);
138
+ return /* @__PURE__ */ jsx(Collection.Provider, { scope, children: /* @__PURE__ */ jsx(Collection.Slot, { scope, children: rootContext.modal ? /* @__PURE__ */ jsx(MenuRootContentModal, { ...contentProps, ref: forwardedRef }) : /* @__PURE__ */ jsx(MenuRootContentNonModal, { ...contentProps, ref: forwardedRef }) }) });
139
+ }
140
+ ), MenuRootContentModal = React.forwardRef((props, forwardedRef) => {
141
+ const scope = props.scope || MENU_CONTEXT, context = useMenuContext(scope), ref = React.useRef(null), composedRefs = useComposedRefs(forwardedRef, ref);
142
+ return /* @__PURE__ */ jsx(
143
+ MenuContentImpl,
144
+ {
145
+ ...props,
146
+ scope,
147
+ ref: composedRefs,
148
+ trapFocus: context.open,
149
+ disableOutsidePointerEvents: context.open,
150
+ disableOutsideScroll: !0,
151
+ onFocusOutside: composeEventHandlers(
152
+ props.onFocusOutside,
153
+ (event) => event.preventDefault(),
154
+ { checkDefaultPrevented: !1 }
155
+ ),
156
+ onDismiss: () => context.onOpenChange(!1)
157
+ }
158
+ );
159
+ }), MenuRootContentNonModal = React.forwardRef((props, forwardedRef) => {
160
+ const scope = props.scope || MENU_CONTEXT, context = useMenuContext(scope);
161
+ return /* @__PURE__ */ jsx(
162
+ MenuContentImpl,
163
+ {
164
+ ...props,
165
+ scope,
166
+ ref: forwardedRef,
167
+ trapFocus: !1,
168
+ disableOutsidePointerEvents: !1,
169
+ disableOutsideScroll: !1,
170
+ onDismiss: () => context.onOpenChange(!1)
171
+ }
172
+ );
173
+ }), MenuContentImpl = React.forwardRef((props, forwardedRef) => {
174
+ const {
175
+ scope = MENU_CONTEXT,
176
+ loop = !1,
177
+ trapFocus,
178
+ onOpenAutoFocus,
179
+ onCloseAutoFocus,
180
+ disableOutsidePointerEvents,
181
+ onEntryFocus,
182
+ onEscapeKeyDown,
183
+ onPointerDownOutside,
184
+ onFocusOutside,
185
+ onInteractOutside,
186
+ onDismiss,
187
+ disableOutsideScroll,
188
+ unstyled = process.env.TAMAGUI_HEADLESS === "1",
189
+ ...contentProps
190
+ } = props, context = useMenuContext(scope), rootContext = useMenuRootContext(scope), getItems = useCollection(scope), [currentItemId, setCurrentItemId] = React.useState(null), contentRef = React.useRef(null), composedRefs = useComposedRefs(
191
+ forwardedRef,
192
+ contentRef,
193
+ context.onContentChange
194
+ ), timerRef = React.useRef(0), searchRef = React.useRef(""), pointerGraceTimerRef = React.useRef(0), pointerGraceIntentRef = React.useRef(null), pointerDirRef = React.useRef("right"), lastPointerXRef = React.useRef(0), handleTypeaheadSearch = (key) => {
195
+ const search = searchRef.current + key, items = getItems().filter((item) => !item.disabled), currentItem = document.activeElement, currentMatch = items.find(
196
+ (item) => item.ref.current === currentItem
197
+ )?.textValue, values = items.map((item) => item.textValue), nextMatch = getNextMatch(values, search, currentMatch), newItem = items.find((item) => item.textValue === nextMatch)?.ref.current;
198
+ (function updateSearch(value) {
199
+ searchRef.current = value, clearTimeout(timerRef.current), value !== "" && (timerRef.current = setTimeout(() => updateSearch(""), 1e3));
200
+ })(search), newItem && setTimeout(() => newItem.focus());
201
+ };
202
+ React.useEffect(() => () => clearTimeout(timerRef.current), []), isWeb && useFocusGuards();
203
+ const isPointerMovingToSubmenu = React.useCallback((event) => pointerDirRef.current === pointerGraceIntentRef.current?.side && isPointerInGraceArea(event, pointerGraceIntentRef.current?.area), []), content = /* @__PURE__ */ jsx(
204
+ PopperPrimitive.PopperContent,
205
+ {
206
+ role: "menu",
207
+ ...!unstyled && {
208
+ elevation: 30,
209
+ paddingVertical: "$2",
210
+ backgroundColor: "$background",
211
+ borderColor: "$borderColor",
212
+ outlineWidth: 0
213
+ },
214
+ "aria-orientation": "vertical",
215
+ "data-state": getOpenState(context.open),
216
+ "data-tamagui-menu-content": "",
217
+ dir: rootContext.dir,
218
+ scope: scope || MENU_CONTEXT,
219
+ ...contentProps,
220
+ ref: composedRefs,
221
+ className: contentProps.animation ? void 0 : contentProps.className,
222
+ ...isWeb ? {
223
+ onKeyDown: composeEventHandlers(contentProps.onKeyDown, (event) => {
224
+ const isKeyDownInside = event.target.closest("[data-tamagui-menu-content]") === event.currentTarget, isModifierKey = event.ctrlKey || event.altKey || event.metaKey, isCharacterKey = event.key.length === 1;
225
+ isKeyDownInside && (event.key === "Tab" && event.preventDefault(), !isModifierKey && isCharacterKey && handleTypeaheadSearch(event.key));
226
+ const content2 = contentRef.current;
227
+ if (event.target !== content2 || !FIRST_LAST_KEYS.includes(event.key)) return;
228
+ event.preventDefault();
229
+ const candidateNodes = getItems().filter((item) => !item.disabled).map((item) => item.ref.current);
230
+ LAST_KEYS.includes(event.key) && candidateNodes.reverse(), focusFirst(candidateNodes);
231
+ }),
232
+ // TODO
233
+ // @ts-ignore
234
+ onBlur: composeEventHandlers(props.onBlur, (event) => {
235
+ event.currentTarget?.contains(event.target) || (clearTimeout(timerRef.current), searchRef.current = "");
236
+ }),
237
+ // TODO
238
+ onPointerMove: composeEventHandlers(props.onPointerMove, (event) => {
239
+ if (event.pointerType !== "mouse") return;
240
+ const target = event.target, pointerXHasChanged = lastPointerXRef.current !== event.clientX;
241
+ if (event.currentTarget?.contains(target) && pointerXHasChanged) {
242
+ const newDir = event.clientX > lastPointerXRef.current ? "right" : "left";
243
+ pointerDirRef.current = newDir, lastPointerXRef.current = event.clientX;
244
+ }
245
+ })
246
+ } : {}
247
+ }
248
+ );
249
+ return /* @__PURE__ */ jsx(
250
+ MenuContentProvider,
251
+ {
252
+ scope,
253
+ searchRef,
254
+ onItemEnter: React.useCallback(
255
+ (event) => {
256
+ isPointerMovingToSubmenu(event) && event.preventDefault();
257
+ },
258
+ [isPointerMovingToSubmenu]
259
+ ),
260
+ onItemLeave: React.useCallback(
261
+ (event) => {
262
+ isPointerMovingToSubmenu(event) || (contentRef.current?.focus(), setCurrentItemId(null));
263
+ },
264
+ [isPointerMovingToSubmenu]
265
+ ),
266
+ onTriggerLeave: React.useCallback(
267
+ (event) => {
268
+ isPointerMovingToSubmenu(event) && event.preventDefault();
269
+ },
270
+ [isPointerMovingToSubmenu]
271
+ ),
272
+ pointerGraceTimerRef,
273
+ onPointerGraceIntentChange: React.useCallback((intent) => {
274
+ pointerGraceIntentRef.current = intent;
275
+ }, []),
276
+ children: /* @__PURE__ */ jsx(RemoveScroll, { enabled: disableOutsideScroll, children: /* @__PURE__ */ jsx(
277
+ FocusScope,
278
+ {
279
+ asChild: !1,
280
+ trapped: trapFocus,
281
+ onMountAutoFocus: composeEventHandlers(onOpenAutoFocus, (event) => {
282
+ event.preventDefault(), contentRef.current?.focus();
283
+ }),
284
+ onUnmountAutoFocus: onCloseAutoFocus,
285
+ children: /* @__PURE__ */ jsx(
286
+ DismissableLayer,
287
+ {
288
+ disableOutsidePointerEvents,
289
+ onEscapeKeyDown,
290
+ onPointerDownOutside,
291
+ onFocusOutside,
292
+ onInteractOutside,
293
+ onDismiss,
294
+ asChild: !0,
295
+ children: /* @__PURE__ */ jsx(
296
+ RovingFocusGroup,
297
+ {
298
+ asChild: !0,
299
+ __scopeRovingFocusGroup: scope || MENU_CONTEXT,
300
+ dir: rootContext.dir,
301
+ orientation: "vertical",
302
+ loop,
303
+ currentTabStopId: currentItemId,
304
+ onCurrentTabStopIdChange: setCurrentItemId,
305
+ onEntryFocus: composeEventHandlers(onEntryFocus, (event) => {
306
+ rootContext.isUsingKeyboardRef.current || event.preventDefault();
307
+ }),
308
+ children: content
309
+ }
310
+ )
311
+ }
312
+ )
313
+ }
314
+ ) })
315
+ }
316
+ );
317
+ });
318
+ MenuContent.displayName = CONTENT_NAME;
319
+ const ITEM_NAME = "MenuItem", ITEM_SELECT = "menu.itemSelect", MenuItem = React.forwardRef(
320
+ (props, forwardedRef) => {
321
+ const {
322
+ disabled = !1,
323
+ onSelect,
324
+ children,
325
+ scope = MENU_CONTEXT,
326
+ ...itemProps
327
+ } = props, ref = React.useRef(null), rootContext = useMenuRootContext(scope), contentContext = useMenuContentContext(scope), composedRefs = useComposedRefs(forwardedRef, ref), isPointerDownRef = React.useRef(!1), handleSelect = () => {
328
+ const menuItem = ref.current;
329
+ if (!disabled && menuItem)
330
+ if (isWeb) {
331
+ const itemSelectEvent = new CustomEvent(ITEM_SELECT, {
332
+ bubbles: !0,
333
+ cancelable: !0
334
+ });
335
+ menuItem.addEventListener(ITEM_SELECT, (event) => onSelect?.(event), {
336
+ once: !0
337
+ }), dispatchDiscreteCustomEvent(menuItem, itemSelectEvent), itemSelectEvent.defaultPrevented ? isPointerDownRef.current = !1 : rootContext.onClose();
338
+ } else
339
+ onSelect?.({ target: menuItem }), isPointerDownRef.current = !1, rootContext.onClose();
340
+ }, content = typeof children == "string" ? /* @__PURE__ */ jsx(Text, { children }) : children;
341
+ return /* @__PURE__ */ jsx(
342
+ MenuItemImpl,
343
+ {
344
+ outlineStyle: "none",
345
+ ...itemProps,
346
+ scope,
347
+ ref: composedRefs,
348
+ disabled,
349
+ onPress: composeEventHandlers(props.onPress, handleSelect),
350
+ onPointerDown: (event) => {
351
+ props.onPointerDown?.(event), isPointerDownRef.current = !0;
352
+ },
353
+ onPointerUp: composeEventHandlers(props.onPointerUp, (event) => {
354
+ isWeb && (isPointerDownRef.current || event.currentTarget?.click());
355
+ }),
356
+ ...isWeb ? {
357
+ onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {
358
+ const isTypingAhead = contentContext.searchRef.current !== "";
359
+ disabled || isTypingAhead && event.key === " " || SELECTION_KEYS.includes(event.key) && (event.currentTarget?.click(), event.preventDefault());
360
+ })
361
+ } : {},
362
+ children: content
363
+ }
364
+ );
365
+ }
366
+ ), MenuItemImpl = React.forwardRef((props, forwardedRef) => {
367
+ const {
368
+ scope = MENU_CONTEXT,
369
+ disabled = !1,
370
+ textValue,
371
+ unstyled = process.env.TAMAGUI_HEADLESS === "1",
372
+ ...itemProps
373
+ } = props, contentContext = useMenuContentContext(scope), ref = React.useRef(null), composedRefs = useComposedRefs(forwardedRef, ref), [isFocused, setIsFocused] = React.useState(!1), [textContent, setTextContent] = React.useState("");
374
+ return isWeb && React.useEffect(() => {
375
+ const menuItem = ref.current;
376
+ menuItem && setTextContent((menuItem.textContent ?? "").trim());
377
+ }, [itemProps.children]), /* @__PURE__ */ jsx(
378
+ Collection.ItemSlot,
379
+ {
380
+ scope,
381
+ disabled,
382
+ textValue: textValue ?? textContent,
383
+ children: /* @__PURE__ */ jsx(
384
+ RovingFocusGroup.Item,
385
+ {
386
+ asChild: !0,
387
+ __scopeRovingFocusGroup: scope,
388
+ focusable: !disabled,
389
+ ...!unstyled && {
390
+ flexDirection: "row",
391
+ alignItems: "center"
392
+ },
393
+ ...itemProps,
394
+ children: /* @__PURE__ */ jsx(
395
+ _Item,
396
+ {
397
+ ...!unstyled && {
398
+ hoverTheme: !0,
399
+ pressTheme: !0,
400
+ focusTheme: !0,
401
+ paddingVertical: "$2",
402
+ paddingHorizontal: "$4",
403
+ width: "100%"
404
+ },
405
+ componentName: ITEM_NAME,
406
+ role: "menuitem",
407
+ "data-highlighted": isFocused ? "" : void 0,
408
+ "aria-disabled": disabled || void 0,
409
+ "data-disabled": disabled ? "" : void 0,
410
+ ...itemProps,
411
+ ref: composedRefs,
412
+ onPointerMove: composeEventHandlers(props.onPointerMove, (event) => {
413
+ event.pointerType === "mouse" && (disabled ? contentContext.onItemLeave(event) : (contentContext.onItemEnter(event), event.defaultPrevented || event.currentTarget.focus()));
414
+ }),
415
+ onPointerLeave: composeEventHandlers(props.onPointerLeave, (event) => {
416
+ contentContext.onItemLeave(event);
417
+ }),
418
+ onFocus: composeEventHandlers(props.onFocus, () => setIsFocused(!0)),
419
+ onBlur: composeEventHandlers(props.onBlur, () => setIsFocused(!1))
420
+ }
421
+ )
422
+ }
423
+ )
424
+ }
425
+ );
426
+ });
427
+ MenuItem.displayName = ITEM_NAME;
428
+ const ITEM_TITLE_NAME = "MenuItemTitle", MenuItemTitle = _Title.styleable((props, forwardedRef) => /* @__PURE__ */ jsx(_Title, { ...props, ref: forwardedRef }));
429
+ MenuItemTitle.displayName = ITEM_TITLE_NAME;
430
+ const ITEM_SUB_TITLE_NAME = "MenuItemSubTitle", MenuItemSubTitle = _SubTitle.styleable((props, forwardedRef) => /* @__PURE__ */ jsx(_SubTitle, { ...props, ref: forwardedRef }));
431
+ MenuItemSubTitle.displayName = ITEM_SUB_TITLE_NAME;
432
+ const ITEM_IMAGE = "MenuItemImage", MenuItemImage = React.forwardRef((props, forwardedRef) => /* @__PURE__ */ jsx(_Image, { ...props, ref: forwardedRef }));
433
+ MenuItemImage.displayName = ITEM_IMAGE;
434
+ const ITEM_ICON = "MenuItemIcon", MenuItemIcon = _Icon;
435
+ MenuItemIcon.displayName = ITEM_ICON;
436
+ const CHECKBOX_ITEM_NAME = "MenuCheckboxItem", MenuCheckboxItem = React.forwardRef((props, forwardedRef) => {
437
+ const {
438
+ checked = !1,
439
+ onCheckedChange,
440
+ scope = MENU_CONTEXT,
441
+ ...checkboxItemProps
442
+ } = props;
443
+ return /* @__PURE__ */ jsx(ItemIndicatorProvider, { scope, checked, children: /* @__PURE__ */ jsx(
444
+ MenuItem,
445
+ {
446
+ componentName: CHECKBOX_ITEM_NAME,
447
+ role: isWeb ? "menuitemcheckbox" : "menuitem",
448
+ "aria-checked": isIndeterminate(checked) ? "mixed" : checked,
449
+ ...checkboxItemProps,
450
+ scope,
451
+ ref: forwardedRef,
452
+ "data-state": getCheckedState(checked),
453
+ onSelect: composeEventHandlers(
454
+ checkboxItemProps.onSelect,
455
+ () => onCheckedChange?.(isIndeterminate(checked) ? !0 : !checked),
456
+ { checkDefaultPrevented: !1 }
457
+ )
458
+ }
459
+ ) });
460
+ });
461
+ MenuCheckboxItem.displayName = CHECKBOX_ITEM_NAME;
462
+ const RADIO_GROUP_NAME = "MenuRadioGroup", { Provider: RadioGroupProvider, useStyledContext: useRadioGroupContext } = createStyledContext(), MenuRadioGroup = _MenuGroup.styleable(
463
+ (props, forwardedRef) => {
464
+ const { value, onValueChange, scope = MENU_CONTEXT, ...groupProps } = props, handleValueChange = useCallbackRef(onValueChange);
465
+ return /* @__PURE__ */ jsx(RadioGroupProvider, { scope, value, onValueChange: handleValueChange, children: /* @__PURE__ */ jsx(
466
+ _MenuGroup,
467
+ {
468
+ componentName: RADIO_GROUP_NAME,
469
+ ...groupProps,
470
+ ref: forwardedRef
471
+ }
472
+ ) });
473
+ }
474
+ );
475
+ MenuRadioGroup.displayName = RADIO_GROUP_NAME;
476
+ const RADIO_ITEM_NAME = "MenuRadioItem", MenuRadioItem = React.forwardRef(
477
+ (props, forwardedRef) => {
478
+ const { value, scope = MENU_CONTEXT, ...radioItemProps } = props, context = useRadioGroupContext(scope), checked = value === context.value;
479
+ return /* @__PURE__ */ jsx(ItemIndicatorProvider, { scope, checked, children: /* @__PURE__ */ jsx(
480
+ MenuItem,
481
+ {
482
+ componentName: RADIO_ITEM_NAME,
483
+ ...radioItemProps,
484
+ scope,
485
+ "aria-checked": checked,
486
+ ref: forwardedRef,
487
+ role: isWeb ? "menuitemradio" : "menuitem",
488
+ "data-state": getCheckedState(checked),
489
+ onSelect: composeEventHandlers(
490
+ radioItemProps.onSelect,
491
+ () => context.onValueChange?.(value),
492
+ { checkDefaultPrevented: !1 }
493
+ )
494
+ }
495
+ ) });
496
+ }
497
+ );
498
+ MenuRadioItem.displayName = RADIO_ITEM_NAME;
499
+ const ITEM_INDICATOR_NAME = "MenuItemIndicator", { Provider: ItemIndicatorProvider, useStyledContext: useItemIndicatorContext } = createStyledContext(), MenuItemIndicator = _Indicator.styleable(
500
+ (props, forwardedRef) => {
501
+ const { scope = MENU_CONTEXT, forceMount, ...itemIndicatorProps } = props, indicatorContext = useItemIndicatorContext(scope);
502
+ return /* @__PURE__ */ jsx(Presence, { children: forceMount || isIndeterminate(indicatorContext.checked) || indicatorContext.checked === !0 ? /* @__PURE__ */ jsx(
503
+ _Indicator,
504
+ {
505
+ componentName: ITEM_INDICATOR_NAME,
506
+ tag: "span",
507
+ ...itemIndicatorProps,
508
+ ref: forwardedRef,
509
+ "data-state": getCheckedState(indicatorContext.checked)
510
+ }
511
+ ) : null });
512
+ }
513
+ );
514
+ MenuItemIndicator.displayName = ITEM_INDICATOR_NAME;
515
+ const MenuArrow = React.forwardRef(
516
+ function(props, forwardedRef) {
517
+ const {
518
+ scope = MENU_CONTEXT,
519
+ unstyled = process.env.TAMAGUI_HEADLESS === "1",
520
+ ...rest
521
+ } = props;
522
+ return /* @__PURE__ */ jsx(
523
+ PopperPrimitive.PopperArrow,
524
+ {
525
+ scope,
526
+ componentName: "PopperArrow",
527
+ ...!unstyled && {
528
+ backgroundColor: "$background"
529
+ },
530
+ ...rest,
531
+ ref: forwardedRef
532
+ }
533
+ );
534
+ }
535
+ ), SUB_NAME = "MenuSub", { Provider: MenuSubProvider, useStyledContext: useMenuSubContext } = createStyledContext(), MenuSub = (props) => {
536
+ const { scope = MENU_CONTEXT, children, open = !1, onOpenChange, ...rest } = props, parentMenuContext = useMenuContext(scope), [trigger, setTrigger] = React.useState(null), [content, setContent] = React.useState(null), handleOpenChange = useCallbackRef(onOpenChange);
537
+ return React.useEffect(() => (parentMenuContext.open === !1 && handleOpenChange(!1), () => handleOpenChange(!1)), [parentMenuContext.open, handleOpenChange]), /* @__PURE__ */ jsx(PopperPrimitive.Popper, { ...rest, scope, children: /* @__PURE__ */ jsx(
538
+ MenuProvider,
539
+ {
540
+ scope,
541
+ open,
542
+ onOpenChange: handleOpenChange,
543
+ content,
544
+ onContentChange: setContent,
545
+ children: /* @__PURE__ */ jsx(
546
+ MenuSubProvider,
547
+ {
548
+ scope,
549
+ contentId: useId(),
550
+ triggerId: useId(),
551
+ trigger,
552
+ onTriggerChange: setTrigger,
553
+ children
554
+ }
555
+ )
556
+ }
557
+ ) });
558
+ };
559
+ MenuSub.displayName = SUB_NAME;
560
+ const SUB_TRIGGER_NAME = "MenuSubTrigger", MenuSubTrigger = React.forwardRef((props, forwardedRef) => {
561
+ const scope = props.scope || MENU_CONTEXT, context = useMenuContext(scope), rootContext = useMenuRootContext(scope), subContext = useMenuSubContext(scope), contentContext = useMenuContentContext(scope), openTimerRef = React.useRef(null), { pointerGraceTimerRef, onPointerGraceIntentChange } = contentContext, clearOpenTimer = React.useCallback(() => {
562
+ openTimerRef.current && window.clearTimeout(openTimerRef.current), openTimerRef.current = null;
563
+ }, []);
564
+ return React.useEffect(() => clearOpenTimer, [clearOpenTimer]), React.useEffect(() => {
565
+ const pointerGraceTimer = pointerGraceTimerRef.current;
566
+ return () => {
567
+ window.clearTimeout(pointerGraceTimer), onPointerGraceIntentChange(null);
568
+ };
569
+ }, [pointerGraceTimerRef, onPointerGraceIntentChange]), /* @__PURE__ */ jsx(MenuAnchor, { componentName: SUB_TRIGGER_NAME, asChild: !0, scope, children: /* @__PURE__ */ jsx(
570
+ MenuItemImpl,
571
+ {
572
+ id: subContext.triggerId,
573
+ "aria-haspopup": "menu",
574
+ "aria-expanded": context.open,
575
+ "aria-controls": subContext.contentId,
576
+ "data-state": getOpenState(context.open),
577
+ outlineStyle: "none",
578
+ ...props,
579
+ ref: composeRefs(forwardedRef, subContext.onTriggerChange),
580
+ onPress: (event) => {
581
+ props.onPress?.(event), !(props.disabled || event.defaultPrevented) && (isWeb && event.currentTarget.focus(), context.open || context.onOpenChange(!0));
582
+ },
583
+ onPointerMove: composeEventHandlers(
584
+ props.onPointerMove,
585
+ // @ts-ignore
586
+ whenMouse((event) => {
587
+ contentContext.onItemEnter(event), !event.defaultPrevented && !props.disabled && !context.open && !openTimerRef.current && (contentContext.onPointerGraceIntentChange(null), openTimerRef.current = window.setTimeout(() => {
588
+ context.onOpenChange(!0), clearOpenTimer();
589
+ }, 100));
590
+ })
591
+ ),
592
+ onPointerLeave: composeEventHandlers(props.onPointerLeave, (eventIn) => {
593
+ const event = eventIn;
594
+ clearOpenTimer();
595
+ const contentRect = context.content?.getBoundingClientRect();
596
+ if (contentRect) {
597
+ const side = context.content?.dataset.side, rightSide = side === "right", bleed = rightSide ? -5 : 5, contentNearEdge = contentRect[rightSide ? "left" : "right"], contentFarEdge = contentRect[rightSide ? "right" : "left"];
598
+ contentContext.onPointerGraceIntentChange({
599
+ area: [
600
+ // Apply a bleed on clientX to ensure that our exit point is
601
+ // consistently within polygon bounds
602
+ { x: event.clientX + bleed, y: event.clientY },
603
+ { x: contentNearEdge, y: contentRect.top },
604
+ { x: contentFarEdge, y: contentRect.top },
605
+ { x: contentFarEdge, y: contentRect.bottom },
606
+ { x: contentNearEdge, y: contentRect.bottom }
607
+ ],
608
+ side
609
+ }), window.clearTimeout(pointerGraceTimerRef.current), pointerGraceTimerRef.current = window.setTimeout(
610
+ () => contentContext.onPointerGraceIntentChange(null),
611
+ 300
612
+ );
613
+ } else {
614
+ if (contentContext.onTriggerLeave(event), event.defaultPrevented) return;
615
+ contentContext.onPointerGraceIntentChange(null);
616
+ }
617
+ }),
618
+ ...isWeb ? {
619
+ onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {
620
+ const isTypingAhead = contentContext.searchRef.current !== "";
621
+ props.disabled || isTypingAhead && event.key === " " || SUB_OPEN_KEYS[rootContext.dir].includes(event.key) && (context.onOpenChange(!0), context.content?.focus(), event.preventDefault());
622
+ })
623
+ } : null
624
+ }
625
+ ) });
626
+ });
627
+ MenuSubTrigger.displayName = SUB_TRIGGER_NAME;
628
+ const SUB_CONTENT_NAME = "MenuSubContent", MenuSubContent = React.forwardRef((props, forwardedRef) => {
629
+ const scope = props.scope || MENU_CONTEXT, portalContext = usePortalContext(scope), { forceMount = portalContext.forceMount, ...subContentProps } = props, context = useMenuContext(scope), rootContext = useMenuRootContext(scope), subContext = useMenuSubContext(scope), ref = React.useRef(null), composedRefs = useComposedRefs(forwardedRef, ref);
630
+ return /* @__PURE__ */ jsx(Collection.Provider, { scope, children: /* @__PURE__ */ jsx(Collection.Slot, { scope, children: /* @__PURE__ */ jsx(
631
+ MenuContentImpl,
632
+ {
633
+ id: subContext.contentId,
634
+ "aria-labelledby": subContext.triggerId,
635
+ ...subContentProps,
636
+ ref: composedRefs,
637
+ "data-side": rootContext.dir === "rtl" ? "left" : "right",
638
+ disableOutsidePointerEvents: !1,
639
+ disableOutsideScroll: !1,
640
+ trapFocus: !1,
641
+ onOpenAutoFocus: (event) => {
642
+ rootContext.isUsingKeyboardRef.current && ref.current?.focus(), event.preventDefault();
643
+ },
644
+ onCloseAutoFocus: (event) => event.preventDefault(),
645
+ onFocusOutside: composeEventHandlers(props.onFocusOutside, (event) => {
646
+ event.target !== subContext.trigger && context.onOpenChange(!1);
647
+ }),
648
+ onEscapeKeyDown: composeEventHandlers(props.onEscapeKeyDown, (event) => {
649
+ rootContext.onClose(), event.preventDefault();
650
+ }),
651
+ ...isWeb ? {
652
+ onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {
653
+ const isKeyDownInside = event.currentTarget.contains(
654
+ event.target
655
+ ), isCloseKey = SUB_CLOSE_KEYS[rootContext.dir].includes(event.key);
656
+ isKeyDownInside && isCloseKey && (context.onOpenChange(!1), subContext.trigger?.focus(), event.preventDefault());
657
+ })
658
+ } : null
659
+ }
660
+ ) }) });
661
+ });
662
+ return MenuSubContent.displayName = SUB_CONTENT_NAME, {
663
+ Menu: withStaticProperties(MenuComp, {
664
+ Anchor: MenuAnchor,
665
+ Portal: MenuPortal,
666
+ Content: MenuContent,
667
+ Group: _MenuGroup,
668
+ Label: _Label,
669
+ Item: MenuItem,
670
+ CheckboxItem: MenuCheckboxItem,
671
+ RadioGroup: MenuRadioGroup,
672
+ RadioItem: MenuRadioItem,
673
+ ItemIndicator: MenuItemIndicator,
674
+ Separator: _Separator,
675
+ Arrow: MenuArrow,
676
+ Sub: MenuSub,
677
+ SubTrigger: MenuSubTrigger,
678
+ SubContent: MenuSubContent,
679
+ ItemTitle: MenuItemTitle,
680
+ ItemSubtitle: MenuItemSubTitle,
681
+ ItemImage: MenuItemImage,
682
+ ItemIcon: MenuItemIcon
683
+ })
684
+ };
685
+ }
686
+ function getOpenState(open) {
687
+ return open ? "open" : "closed";
688
+ }
689
+ function isIndeterminate(checked) {
690
+ return checked === "indeterminate";
691
+ }
692
+ function getCheckedState(checked) {
693
+ return isIndeterminate(checked) ? "indeterminate" : checked ? "checked" : "unchecked";
694
+ }
695
+ function focusFirst(candidates) {
696
+ const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;
697
+ for (const candidate of candidates)
698
+ if (candidate === PREVIOUSLY_FOCUSED_ELEMENT || (candidate.focus(), document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT)) return;
699
+ }
700
+ function wrapArray(array, startIndex) {
701
+ return array.map((_, index) => array[(startIndex + index) % array.length]);
702
+ }
703
+ function getNextMatch(values, search, currentMatch) {
704
+ const normalizedSearch = search.length > 1 && Array.from(search).every((char) => char === search[0]) ? search[0] : search, currentMatchIndex = currentMatch ? values.indexOf(currentMatch) : -1;
705
+ let wrappedValues = wrapArray(values, Math.max(currentMatchIndex, 0));
706
+ normalizedSearch.length === 1 && (wrappedValues = wrappedValues.filter((v) => v !== currentMatch));
707
+ const nextMatch = wrappedValues.find(
708
+ (value) => value.toLowerCase().startsWith(normalizedSearch.toLowerCase())
709
+ );
710
+ return nextMatch !== currentMatch ? nextMatch : void 0;
711
+ }
712
+ function isPointInPolygon(point, polygon) {
713
+ const { x, y } = point;
714
+ let inside = !1;
715
+ for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
716
+ const xi = polygon[i].x, yi = polygon[i].y, xj = polygon[j].x, yj = polygon[j].y;
717
+ yi > y != yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi && (inside = !inside);
718
+ }
719
+ return inside;
720
+ }
721
+ function isPointerInGraceArea(event, area) {
722
+ if (!area) return !1;
723
+ const cursorPos = { x: event.clientX, y: event.clientY };
724
+ return isPointInPolygon(cursorPos, area);
725
+ }
726
+ export {
727
+ createBaseMenu
728
+ };
729
+ //# sourceMappingURL=createBaseMenu.js.map