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