@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,1068 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Animate } from "@tamagui/animate";
3
+ import { AnimatePresence as Presence } from "@tamagui/animate-presence";
4
+ import { createCollection } from "@tamagui/collection";
5
+ import { Dismissable as DismissableLayer, dispatchDiscreteCustomEvent } from "@tamagui/dismissable";
6
+ import { useFocusGuards } from "@tamagui/focus-guard";
7
+ import { FocusScope } from "@tamagui/focus-scope";
8
+ import * as PopperPrimitive from "@tamagui/popper";
9
+ import { Portal as PortalPrimitive } from "@tamagui/portal";
10
+ import { RemoveScroll } from "@tamagui/remove-scroll";
11
+ import { RovingFocusGroup } from "@tamagui/roving-focus";
12
+ import { useCallbackRef } from "@tamagui/use-callback-ref";
13
+ import { useDirection } from "@tamagui/use-direction";
14
+ import { Text, View, composeEventHandlers, composeRefs, createStyledContext, isAndroid, isWeb, useComposedRefs, withStaticProperties } from "@tamagui/web";
15
+ import * as React from "react";
16
+ import { useId } from "react";
17
+ import { MenuPredefined } from "./MenuPredefined.native.js";
18
+ function whenMouse(handler) {
19
+ return function (event) {
20
+ return event.pointerType === "mouse" ? handler(event) : void 0;
21
+ };
22
+ }
23
+ var SELECTION_KEYS = ["Enter", " "],
24
+ FIRST_KEYS = ["ArrowDown", "PageUp", "Home"],
25
+ LAST_KEYS = ["ArrowUp", "PageDown", "End"],
26
+ FIRST_LAST_KEYS = [...FIRST_KEYS, ...LAST_KEYS],
27
+ SUB_OPEN_KEYS = {
28
+ ltr: [...SELECTION_KEYS, "ArrowRight"],
29
+ rtl: [...SELECTION_KEYS, "ArrowLeft"]
30
+ },
31
+ SUB_CLOSE_KEYS = {
32
+ ltr: ["ArrowLeft"],
33
+ rtl: ["ArrowRight"]
34
+ },
35
+ MENU_NAME = "Menu",
36
+ [Collection, useCollection] = createCollection(MENU_NAME),
37
+ {
38
+ Provider: MenuProvider,
39
+ useStyledContext: useMenuContext
40
+ } = createStyledContext(),
41
+ {
42
+ Provider: MenuRootProvider,
43
+ useStyledContext: useMenuRootContext
44
+ } = createStyledContext(),
45
+ MENU_CONTEXT = "MenuContext";
46
+ function createBaseMenu(param) {
47
+ var {
48
+ Item: _Item = MenuPredefined.MenuItem,
49
+ Title: _Title = MenuPredefined.Title,
50
+ SubTitle: _SubTitle = MenuPredefined.SubTitle,
51
+ Image: _Image = MenuPredefined.MenuImage,
52
+ Icon: _Icon = MenuPredefined.MenuIcon,
53
+ Indicator: _Indicator = MenuPredefined.MenuIndicator,
54
+ Separator: _Separator = MenuPredefined.MenuSeparator,
55
+ MenuGroup: _MenuGroup = MenuPredefined.MenuGroup,
56
+ Label: _Label = MenuPredefined.MenuLabel
57
+ } = param,
58
+ MenuComp = function (props) {
59
+ var {
60
+ scope = MENU_CONTEXT,
61
+ open = !1,
62
+ children,
63
+ dir,
64
+ onOpenChange,
65
+ modal = !0,
66
+ ...rest
67
+ } = props,
68
+ [content, setContent] = React.useState(null),
69
+ isUsingKeyboardRef = React.useRef(!1),
70
+ handleOpenChange = useCallbackRef(onOpenChange),
71
+ direction = useDirection(dir);
72
+ return isWeb && React.useEffect(function () {
73
+ var handleKeyDown = function () {
74
+ isUsingKeyboardRef.current = !0, document.addEventListener("pointerdown", handlePointer, {
75
+ capture: !0,
76
+ once: !0
77
+ }), document.addEventListener("pointermove", handlePointer, {
78
+ capture: !0,
79
+ once: !0
80
+ });
81
+ },
82
+ handlePointer = function () {
83
+ return isUsingKeyboardRef.current = !1;
84
+ };
85
+ return document.addEventListener("keydown", handleKeyDown, {
86
+ capture: !0
87
+ }), function () {
88
+ document.removeEventListener("keydown", handleKeyDown, {
89
+ capture: !0
90
+ }), document.removeEventListener("pointerdown", handlePointer, {
91
+ capture: !0
92
+ }), document.removeEventListener("pointermove", handlePointer, {
93
+ capture: !0
94
+ });
95
+ };
96
+ }, []), /* @__PURE__ */_jsx(PopperPrimitive.Popper, {
97
+ scope,
98
+ ...rest,
99
+ children: /* @__PURE__ */_jsx(MenuProvider, {
100
+ scope,
101
+ open,
102
+ onOpenChange: handleOpenChange,
103
+ content,
104
+ onContentChange: setContent,
105
+ children: /* @__PURE__ */_jsx(MenuRootProvider, {
106
+ scope,
107
+ onClose: React.useCallback(function () {
108
+ return handleOpenChange(!1);
109
+ }, [handleOpenChange]),
110
+ isUsingKeyboardRef,
111
+ dir: direction,
112
+ modal,
113
+ children: (/** this provider is just to avoid crashing when using useSubMenuContext() inside MenuPortal */
114
+ /* @__PURE__ */_jsx(MenuSubProvider, {
115
+ scope,
116
+ children
117
+ }))
118
+ })
119
+ })
120
+ });
121
+ },
122
+ RepropagateMenuAndMenuRootProvider = function (props) {
123
+ var {
124
+ scope = MENU_CONTEXT,
125
+ menuContext,
126
+ rootContext,
127
+ popperContext,
128
+ menuSubContext,
129
+ children
130
+ } = props;
131
+ return /* @__PURE__ */_jsx(PopperPrimitive.PopperProvider, {
132
+ ...popperContext,
133
+ scope,
134
+ children: /* @__PURE__ */_jsx(MenuProvider, {
135
+ scope,
136
+ ...menuContext,
137
+ children: /* @__PURE__ */_jsx(MenuRootProvider, {
138
+ scope,
139
+ ...rootContext,
140
+ children: menuSubContext ? /* @__PURE__ */_jsx(MenuSubProvider, {
141
+ scope,
142
+ ...menuSubContext,
143
+ children
144
+ }) : children
145
+ })
146
+ })
147
+ });
148
+ };
149
+ MenuComp.displayName = MENU_NAME;
150
+ var ANCHOR_NAME = "MenuAnchor",
151
+ MenuAnchor = function (props) {
152
+ return /* @__PURE__ */_jsx(PopperPrimitive.PopperAnchor, {
153
+ scope: MENU_CONTEXT,
154
+ ...props
155
+ });
156
+ };
157
+ MenuAnchor.displayName = ANCHOR_NAME;
158
+ var PORTAL_NAME = "MenuPortal",
159
+ {
160
+ Provider: PortalProvider,
161
+ useStyledContext: usePortalContext
162
+ } = createStyledContext(void 0, "Portal"),
163
+ MenuPortal = function (props) {
164
+ var {
165
+ scope = MENU_CONTEXT,
166
+ forceMount,
167
+ zIndex,
168
+ children
169
+ } = props,
170
+ menuContext = useMenuContext(scope),
171
+ rootContext = useMenuRootContext(scope),
172
+ popperContext = PopperPrimitive.usePopperContext(scope),
173
+ menuSubContext = useMenuSubContext(scope),
174
+ content = isAndroid ? /* @__PURE__ */_jsx(RepropagateMenuAndMenuRootProvider, {
175
+ menuContext,
176
+ rootContext,
177
+ popperContext,
178
+ menuSubContext,
179
+ scope,
180
+ children
181
+ }) : children;
182
+ return /* @__PURE__ */_jsx(Animate, {
183
+ type: "presence",
184
+ present: forceMount || menuContext.open,
185
+ children: /* @__PURE__ */_jsx(PortalPrimitive, {
186
+ children: /* @__PURE__ */_jsx(_Fragment, {
187
+ children: /* @__PURE__ */_jsx(PortalProvider, {
188
+ scope,
189
+ forceMount,
190
+ children: /* @__PURE__ */_jsxs(View, {
191
+ zIndex: zIndex || 100,
192
+ inset: 0,
193
+ position: "absolute",
194
+ children: [!!menuContext.open && !isWeb && /* @__PURE__ */_jsx(View, {
195
+ inset: 0,
196
+ position: "absolute",
197
+ onPress: function () {
198
+ return menuContext.onOpenChange(!menuContext.open);
199
+ }
200
+ }), content]
201
+ })
202
+ })
203
+ })
204
+ })
205
+ });
206
+ };
207
+ MenuPortal.displayName = PORTAL_NAME;
208
+ var CONTENT_NAME = "MenuContent",
209
+ {
210
+ Provider: MenuContentProvider,
211
+ useStyledContext: useMenuContentContext
212
+ } = createStyledContext(),
213
+ MenuContent = /* @__PURE__ */React.forwardRef(function (props, forwardedRef) {
214
+ var scope = props.scope || MENU_CONTEXT,
215
+ portalContext = usePortalContext(scope),
216
+ {
217
+ forceMount = portalContext.forceMount,
218
+ ...contentProps
219
+ } = props,
220
+ rootContext = useMenuRootContext(scope);
221
+ return /* @__PURE__ */_jsx(Collection.Provider, {
222
+ scope,
223
+ children: /* @__PURE__ */_jsx(Collection.Slot, {
224
+ scope,
225
+ children: rootContext.modal ? /* @__PURE__ */_jsx(MenuRootContentModal, {
226
+ ...contentProps,
227
+ ref: forwardedRef
228
+ }) : /* @__PURE__ */_jsx(MenuRootContentNonModal, {
229
+ ...contentProps,
230
+ ref: forwardedRef
231
+ })
232
+ })
233
+ });
234
+ }),
235
+ MenuRootContentModal = /* @__PURE__ */React.forwardRef(function (props, forwardedRef) {
236
+ var scope = props.scope || MENU_CONTEXT,
237
+ context = useMenuContext(scope),
238
+ ref = React.useRef(null),
239
+ composedRefs = useComposedRefs(forwardedRef, ref);
240
+ return /* @__PURE__ */_jsx(MenuContentImpl, {
241
+ ...props,
242
+ scope,
243
+ ref: composedRefs,
244
+ // we make sure we're not trapping once it's been closed
245
+ // (closed !== unmounted when animating out)
246
+ trapFocus: context.open,
247
+ // make sure to only disable pointer events when open
248
+ // this avoids blocking interactions while animating out
249
+ disableOutsidePointerEvents: context.open,
250
+ disableOutsideScroll: !0,
251
+ // When focus is trapped, a `focusout` event may still happen.
252
+ // We make sure we don't trigger our `onDismiss` in such case.
253
+ onFocusOutside: composeEventHandlers(props.onFocusOutside, function (event) {
254
+ return event.preventDefault();
255
+ }, {
256
+ checkDefaultPrevented: !1
257
+ }),
258
+ onDismiss: function () {
259
+ return context.onOpenChange(!1);
260
+ }
261
+ });
262
+ }),
263
+ MenuRootContentNonModal = /* @__PURE__ */React.forwardRef(function (props, forwardedRef) {
264
+ var scope = props.scope || MENU_CONTEXT,
265
+ context = useMenuContext(scope);
266
+ return /* @__PURE__ */_jsx(MenuContentImpl, {
267
+ ...props,
268
+ scope,
269
+ ref: forwardedRef,
270
+ trapFocus: !1,
271
+ disableOutsidePointerEvents: !1,
272
+ disableOutsideScroll: !1,
273
+ onDismiss: function () {
274
+ return context.onOpenChange(!1);
275
+ }
276
+ });
277
+ }),
278
+ MenuContentImpl = /* @__PURE__ */React.forwardRef(function (props, forwardedRef) {
279
+ var {
280
+ scope = MENU_CONTEXT,
281
+ loop = !1,
282
+ trapFocus,
283
+ onOpenAutoFocus,
284
+ onCloseAutoFocus,
285
+ disableOutsidePointerEvents,
286
+ onEntryFocus,
287
+ onEscapeKeyDown,
288
+ onPointerDownOutside,
289
+ onFocusOutside,
290
+ onInteractOutside,
291
+ onDismiss,
292
+ disableOutsideScroll,
293
+ unstyled = process.env.TAMAGUI_HEADLESS === "1",
294
+ ...contentProps
295
+ } = props,
296
+ context = useMenuContext(scope),
297
+ rootContext = useMenuRootContext(scope),
298
+ getItems = useCollection(scope),
299
+ [currentItemId, setCurrentItemId] = React.useState(null),
300
+ contentRef = React.useRef(null),
301
+ composedRefs = useComposedRefs(forwardedRef, contentRef, context.onContentChange),
302
+ timerRef = React.useRef(0),
303
+ searchRef = React.useRef(""),
304
+ pointerGraceTimerRef = React.useRef(0),
305
+ pointerGraceIntentRef = React.useRef(null),
306
+ pointerDirRef = React.useRef("right"),
307
+ lastPointerXRef = React.useRef(0),
308
+ handleTypeaheadSearch = function (key) {
309
+ var _items_find,
310
+ _items_find1,
311
+ search = searchRef.current + key,
312
+ items = getItems().filter(function (item) {
313
+ return !item.disabled;
314
+ }),
315
+ currentItem = document.activeElement,
316
+ currentMatch = (_items_find = items.find(function (item) {
317
+ return item.ref.current === currentItem;
318
+ })) === null || _items_find === void 0 ? void 0 : _items_find.textValue,
319
+ values = items.map(function (item) {
320
+ return item.textValue;
321
+ }),
322
+ nextMatch = getNextMatch(values, search, currentMatch),
323
+ newItem = (_items_find1 = items.find(function (item) {
324
+ return item.textValue === nextMatch;
325
+ })) === null || _items_find1 === void 0 ? void 0 : _items_find1.ref.current;
326
+ (function updateSearch(value) {
327
+ searchRef.current = value, clearTimeout(timerRef.current), value !== "" && (timerRef.current = setTimeout(function () {
328
+ return updateSearch("");
329
+ }, 1e3));
330
+ })(search), newItem && setTimeout(function () {
331
+ return newItem.focus();
332
+ });
333
+ };
334
+ React.useEffect(function () {
335
+ return function () {
336
+ return clearTimeout(timerRef.current);
337
+ };
338
+ }, []), isWeb && useFocusGuards();
339
+ var isPointerMovingToSubmenu = React.useCallback(function (event) {
340
+ var _pointerGraceIntentRef_current,
341
+ _pointerGraceIntentRef_current1,
342
+ isMovingTowards = pointerDirRef.current === ((_pointerGraceIntentRef_current = pointerGraceIntentRef.current) === null || _pointerGraceIntentRef_current === void 0 ? void 0 : _pointerGraceIntentRef_current.side);
343
+ return isMovingTowards && isPointerInGraceArea(event, (_pointerGraceIntentRef_current1 = pointerGraceIntentRef.current) === null || _pointerGraceIntentRef_current1 === void 0 ? void 0 : _pointerGraceIntentRef_current1.area);
344
+ }, []),
345
+ content = /* @__PURE__ */_jsx(PopperPrimitive.PopperContent, {
346
+ role: "menu",
347
+ ...(!unstyled && {
348
+ elevation: 30,
349
+ paddingVertical: "$2",
350
+ backgroundColor: "$background",
351
+ borderColor: "$borderColor",
352
+ outlineWidth: 0
353
+ }),
354
+ "aria-orientation": "vertical",
355
+ "data-state": getOpenState(context.open),
356
+ "data-tamagui-menu-content": "",
357
+ // TODO
358
+ // @ts-ignore
359
+ dir: rootContext.dir,
360
+ scope: scope || MENU_CONTEXT,
361
+ ...contentProps,
362
+ ref: composedRefs,
363
+ className: contentProps.animation ? void 0 : contentProps.className,
364
+ ...(isWeb ? {
365
+ onKeyDown: composeEventHandlers(contentProps.onKeyDown, function (event) {
366
+ var target = event.target,
367
+ isKeyDownInside = target.closest("[data-tamagui-menu-content]") === event.currentTarget,
368
+ isModifierKey = event.ctrlKey || event.altKey || event.metaKey,
369
+ isCharacterKey = event.key.length === 1;
370
+ isKeyDownInside && (event.key === "Tab" && event.preventDefault(), !isModifierKey && isCharacterKey && handleTypeaheadSearch(event.key));
371
+ var content2 = contentRef.current;
372
+ if (event.target === content2 && FIRST_LAST_KEYS.includes(event.key)) {
373
+ event.preventDefault();
374
+ var items = getItems().filter(function (item) {
375
+ return !item.disabled;
376
+ }),
377
+ candidateNodes = items.map(function (item) {
378
+ return item.ref.current;
379
+ });
380
+ LAST_KEYS.includes(event.key) && candidateNodes.reverse(), focusFirst(candidateNodes);
381
+ }
382
+ }),
383
+ // TODO
384
+ // @ts-ignore
385
+ onBlur: composeEventHandlers(props.onBlur, function (event) {
386
+ var _event_currentTarget;
387
+ !((_event_currentTarget = event.currentTarget) === null || _event_currentTarget === void 0) && _event_currentTarget.contains(event.target) || (clearTimeout(timerRef.current), searchRef.current = "");
388
+ }),
389
+ // TODO
390
+ onPointerMove: composeEventHandlers(props.onPointerMove, function (event) {
391
+ var _event_currentTarget;
392
+ if (event.pointerType === "mouse") {
393
+ var target = event.target,
394
+ pointerXHasChanged = lastPointerXRef.current !== event.clientX;
395
+ if (!((_event_currentTarget = event.currentTarget) === null || _event_currentTarget === void 0) && _event_currentTarget.contains(target) && pointerXHasChanged) {
396
+ var newDir = event.clientX > lastPointerXRef.current ? "right" : "left";
397
+ pointerDirRef.current = newDir, lastPointerXRef.current = event.clientX;
398
+ }
399
+ }
400
+ })
401
+ } : {})
402
+ });
403
+ return /* @__PURE__ */_jsx(MenuContentProvider, {
404
+ scope,
405
+ searchRef,
406
+ onItemEnter: React.useCallback(function (event) {
407
+ isPointerMovingToSubmenu(event) && event.preventDefault();
408
+ }, [isPointerMovingToSubmenu]),
409
+ onItemLeave: React.useCallback(function (event) {
410
+ var _contentRef_current;
411
+ isPointerMovingToSubmenu(event) || ((_contentRef_current = contentRef.current) === null || _contentRef_current === void 0 || _contentRef_current.focus(), setCurrentItemId(null));
412
+ }, [isPointerMovingToSubmenu]),
413
+ onTriggerLeave: React.useCallback(function (event) {
414
+ isPointerMovingToSubmenu(event) && event.preventDefault();
415
+ }, [isPointerMovingToSubmenu]),
416
+ pointerGraceTimerRef,
417
+ onPointerGraceIntentChange: React.useCallback(function (intent) {
418
+ pointerGraceIntentRef.current = intent;
419
+ }, []),
420
+ children: /* @__PURE__ */_jsx(RemoveScroll, {
421
+ enabled: disableOutsideScroll,
422
+ children: /* @__PURE__ */_jsx(FocusScope, {
423
+ asChild: !1,
424
+ trapped: trapFocus,
425
+ onMountAutoFocus: composeEventHandlers(onOpenAutoFocus, function (event) {
426
+ var _contentRef_current;
427
+ event.preventDefault(), (_contentRef_current = contentRef.current) === null || _contentRef_current === void 0 || _contentRef_current.focus();
428
+ }),
429
+ onUnmountAutoFocus: onCloseAutoFocus,
430
+ children: /* @__PURE__ */_jsx(DismissableLayer, {
431
+ disableOutsidePointerEvents,
432
+ onEscapeKeyDown,
433
+ onPointerDownOutside,
434
+ onFocusOutside,
435
+ onInteractOutside,
436
+ onDismiss,
437
+ asChild: !0,
438
+ children: /* @__PURE__ */_jsx(RovingFocusGroup, {
439
+ asChild: !0,
440
+ __scopeRovingFocusGroup: scope || MENU_CONTEXT,
441
+ dir: rootContext.dir,
442
+ orientation: "vertical",
443
+ loop,
444
+ currentTabStopId: currentItemId,
445
+ onCurrentTabStopIdChange: setCurrentItemId,
446
+ onEntryFocus: composeEventHandlers(onEntryFocus, function (event) {
447
+ rootContext.isUsingKeyboardRef.current || event.preventDefault();
448
+ }),
449
+ children: content
450
+ })
451
+ })
452
+ })
453
+ })
454
+ });
455
+ });
456
+ MenuContent.displayName = CONTENT_NAME;
457
+ var ITEM_NAME = "MenuItem",
458
+ ITEM_SELECT = "menu.itemSelect",
459
+ MenuItem = /* @__PURE__ */React.forwardRef(function (props, forwardedRef) {
460
+ var {
461
+ disabled = !1,
462
+ onSelect,
463
+ children,
464
+ scope = MENU_CONTEXT,
465
+ ...itemProps
466
+ } = props,
467
+ ref = React.useRef(null),
468
+ rootContext = useMenuRootContext(scope),
469
+ contentContext = useMenuContentContext(scope),
470
+ composedRefs = useComposedRefs(forwardedRef, ref),
471
+ isPointerDownRef = React.useRef(!1),
472
+ handleSelect = function () {
473
+ var menuItem = ref.current;
474
+ if (!disabled && menuItem) if (isWeb) {
475
+ var itemSelectEvent = new CustomEvent(ITEM_SELECT, {
476
+ bubbles: !0,
477
+ cancelable: !0
478
+ });
479
+ menuItem.addEventListener(ITEM_SELECT, function (event) {
480
+ return onSelect?.(event);
481
+ }, {
482
+ once: !0
483
+ }), dispatchDiscreteCustomEvent(menuItem, itemSelectEvent), itemSelectEvent.defaultPrevented ? isPointerDownRef.current = !1 : rootContext.onClose();
484
+ } else onSelect?.({
485
+ target: menuItem
486
+ }), isPointerDownRef.current = !1, rootContext.onClose();
487
+ },
488
+ content = typeof children == "string" ? /* @__PURE__ */_jsx(Text, {
489
+ children
490
+ }) : children;
491
+ return /* @__PURE__ */_jsx(MenuItemImpl, {
492
+ outlineStyle: "none",
493
+ ...itemProps,
494
+ scope,
495
+ // @ts-ignore
496
+ ref: composedRefs,
497
+ disabled,
498
+ onPress: composeEventHandlers(props.onPress, handleSelect),
499
+ onPointerDown: function (event) {
500
+ var _props_onPointerDown;
501
+ (_props_onPointerDown = props.onPointerDown) === null || _props_onPointerDown === void 0 || _props_onPointerDown.call(props, event), isPointerDownRef.current = !0;
502
+ },
503
+ onPointerUp: composeEventHandlers(props.onPointerUp, function (event) {
504
+ if (isWeb) {
505
+ var _event_currentTarget;
506
+ isPointerDownRef.current || (_event_currentTarget = event.currentTarget) === null || _event_currentTarget === void 0 || _event_currentTarget.click();
507
+ }
508
+ }),
509
+ ...(isWeb ? {
510
+ onKeyDown: composeEventHandlers(props.onKeyDown, function (event) {
511
+ var isTypingAhead = contentContext.searchRef.current !== "";
512
+ if (!(disabled || isTypingAhead && event.key === " ") && SELECTION_KEYS.includes(event.key)) {
513
+ var _event_currentTarget;
514
+ (_event_currentTarget = event.currentTarget) === null || _event_currentTarget === void 0 || _event_currentTarget.click(), event.preventDefault();
515
+ }
516
+ })
517
+ } : {}),
518
+ children: content
519
+ });
520
+ }),
521
+ MenuItemImpl = /* @__PURE__ */React.forwardRef(function (props, forwardedRef) {
522
+ var {
523
+ scope = MENU_CONTEXT,
524
+ disabled = !1,
525
+ textValue,
526
+ unstyled = process.env.TAMAGUI_HEADLESS === "1",
527
+ ...itemProps
528
+ } = props,
529
+ contentContext = useMenuContentContext(scope),
530
+ ref = React.useRef(null),
531
+ composedRefs = useComposedRefs(forwardedRef, ref),
532
+ [isFocused, setIsFocused] = React.useState(!1),
533
+ [textContent, setTextContent] = React.useState("");
534
+ return isWeb && React.useEffect(function () {
535
+ var menuItem = ref.current;
536
+ if (menuItem) {
537
+ var _menuItem_textContent;
538
+ setTextContent(((_menuItem_textContent = menuItem.textContent) !== null && _menuItem_textContent !== void 0 ? _menuItem_textContent : "").trim());
539
+ }
540
+ }, [itemProps.children]), /* @__PURE__ */_jsx(Collection.ItemSlot, {
541
+ scope,
542
+ disabled,
543
+ textValue: textValue ?? textContent,
544
+ children: /* @__PURE__ */_jsx(RovingFocusGroup.Item, {
545
+ asChild: !0,
546
+ __scopeRovingFocusGroup: scope,
547
+ focusable: !disabled,
548
+ ...(!unstyled && {
549
+ flexDirection: "row",
550
+ alignItems: "center"
551
+ }),
552
+ ...itemProps,
553
+ children: /* @__PURE__ */_jsx(_Item, {
554
+ ...(!unstyled && {
555
+ hoverTheme: !0,
556
+ pressTheme: !0,
557
+ focusTheme: !0,
558
+ paddingVertical: "$2",
559
+ paddingHorizontal: "$4",
560
+ width: "100%"
561
+ }),
562
+ componentName: ITEM_NAME,
563
+ role: "menuitem",
564
+ "data-highlighted": isFocused ? "" : void 0,
565
+ "aria-disabled": disabled || void 0,
566
+ "data-disabled": disabled ? "" : void 0,
567
+ ...itemProps,
568
+ ref: composedRefs,
569
+ /**
570
+ * We focus items on `pointerMove` to achieve the following:
571
+ *
572
+ * - Mouse over an item (it focuses)
573
+ * - Leave mouse where it is and use keyboard to focus a different item
574
+ * - Wiggle mouse without it leaving previously focused item
575
+ * - Previously focused item should re-focus
576
+ *
577
+ * If we used `mouseOver`/`mouseEnter` it would not re-focus when the mouse
578
+ * wiggles. This is to match native menu implementation.
579
+ */
580
+ onPointerMove: composeEventHandlers(props.onPointerMove, function (event) {
581
+ if (event.pointerType === "mouse") {
582
+ if (disabled) contentContext.onItemLeave(event);else if (contentContext.onItemEnter(event), !event.defaultPrevented) {
583
+ var item = event.currentTarget;
584
+ item.focus();
585
+ }
586
+ }
587
+ }),
588
+ onPointerLeave: composeEventHandlers(props.onPointerLeave, function (event) {
589
+ contentContext.onItemLeave(event);
590
+ }),
591
+ onFocus: composeEventHandlers(props.onFocus, function () {
592
+ return setIsFocused(!0);
593
+ }),
594
+ onBlur: composeEventHandlers(props.onBlur, function () {
595
+ return setIsFocused(!1);
596
+ })
597
+ })
598
+ })
599
+ });
600
+ });
601
+ MenuItem.displayName = ITEM_NAME;
602
+ var ITEM_TITLE_NAME = "MenuItemTitle",
603
+ MenuItemTitle = _Title.styleable(function (props, forwardedRef) {
604
+ return /* @__PURE__ */_jsx(_Title, {
605
+ ...props,
606
+ ref: forwardedRef
607
+ });
608
+ });
609
+ MenuItemTitle.displayName = ITEM_TITLE_NAME;
610
+ var ITEM_SUB_TITLE_NAME = "MenuItemSubTitle",
611
+ MenuItemSubTitle = _SubTitle.styleable(function (props, forwardedRef) {
612
+ return /* @__PURE__ */_jsx(_SubTitle, {
613
+ ...props,
614
+ ref: forwardedRef
615
+ });
616
+ });
617
+ MenuItemSubTitle.displayName = ITEM_SUB_TITLE_NAME;
618
+ var ITEM_IMAGE = "MenuItemImage",
619
+ MenuItemImage = /* @__PURE__ */React.forwardRef(function (props, forwardedRef) {
620
+ return /* @__PURE__ */_jsx(_Image, {
621
+ ...props,
622
+ ref: forwardedRef
623
+ });
624
+ });
625
+ MenuItemImage.displayName = ITEM_IMAGE;
626
+ var ITEM_ICON = "MenuItemIcon",
627
+ MenuItemIcon = _Icon;
628
+ MenuItemIcon.displayName = ITEM_ICON;
629
+ var CHECKBOX_ITEM_NAME = "MenuCheckboxItem",
630
+ MenuCheckboxItem = /* @__PURE__ */React.forwardRef(function (props, forwardedRef) {
631
+ var {
632
+ checked = !1,
633
+ onCheckedChange,
634
+ scope = MENU_CONTEXT,
635
+ ...checkboxItemProps
636
+ } = props;
637
+ return /* @__PURE__ */_jsx(ItemIndicatorProvider, {
638
+ scope,
639
+ checked,
640
+ children: /* @__PURE__ */_jsx(MenuItem, {
641
+ componentName: CHECKBOX_ITEM_NAME,
642
+ role: isWeb ? "menuitemcheckbox" : "menuitem",
643
+ "aria-checked": isIndeterminate(checked) ? "mixed" : checked,
644
+ ...checkboxItemProps,
645
+ scope,
646
+ ref: forwardedRef,
647
+ "data-state": getCheckedState(checked),
648
+ onSelect: composeEventHandlers(checkboxItemProps.onSelect, function () {
649
+ return onCheckedChange?.(isIndeterminate(checked) ? !0 : !checked);
650
+ }, {
651
+ checkDefaultPrevented: !1
652
+ })
653
+ })
654
+ });
655
+ });
656
+ MenuCheckboxItem.displayName = CHECKBOX_ITEM_NAME;
657
+ var RADIO_GROUP_NAME = "MenuRadioGroup",
658
+ {
659
+ Provider: RadioGroupProvider,
660
+ useStyledContext: useRadioGroupContext
661
+ } = createStyledContext(),
662
+ MenuRadioGroup = _MenuGroup.styleable(function (props, forwardedRef) {
663
+ var {
664
+ value,
665
+ onValueChange,
666
+ scope = MENU_CONTEXT,
667
+ ...groupProps
668
+ } = props,
669
+ handleValueChange = useCallbackRef(onValueChange);
670
+ return /* @__PURE__ */_jsx(RadioGroupProvider, {
671
+ scope,
672
+ value,
673
+ onValueChange: handleValueChange,
674
+ children: /* @__PURE__ */_jsx(_MenuGroup, {
675
+ componentName: RADIO_GROUP_NAME,
676
+ ...groupProps,
677
+ ref: forwardedRef
678
+ })
679
+ });
680
+ });
681
+ MenuRadioGroup.displayName = RADIO_GROUP_NAME;
682
+ var RADIO_ITEM_NAME = "MenuRadioItem",
683
+ MenuRadioItem = /* @__PURE__ */React.forwardRef(function (props, forwardedRef) {
684
+ var {
685
+ value,
686
+ scope = MENU_CONTEXT,
687
+ ...radioItemProps
688
+ } = props,
689
+ context = useRadioGroupContext(scope),
690
+ checked = value === context.value;
691
+ return /* @__PURE__ */_jsx(ItemIndicatorProvider, {
692
+ scope,
693
+ checked,
694
+ children: /* @__PURE__ */_jsx(MenuItem, {
695
+ componentName: RADIO_ITEM_NAME,
696
+ ...radioItemProps,
697
+ scope,
698
+ "aria-checked": checked,
699
+ ref: forwardedRef,
700
+ role: isWeb ? "menuitemradio" : "menuitem",
701
+ "data-state": getCheckedState(checked),
702
+ onSelect: composeEventHandlers(radioItemProps.onSelect, function () {
703
+ var _context_onValueChange;
704
+ return (_context_onValueChange = context.onValueChange) === null || _context_onValueChange === void 0 ? void 0 : _context_onValueChange.call(context, value);
705
+ }, {
706
+ checkDefaultPrevented: !1
707
+ })
708
+ })
709
+ });
710
+ });
711
+ MenuRadioItem.displayName = RADIO_ITEM_NAME;
712
+ var ITEM_INDICATOR_NAME = "MenuItemIndicator",
713
+ {
714
+ Provider: ItemIndicatorProvider,
715
+ useStyledContext: useItemIndicatorContext
716
+ } = createStyledContext(),
717
+ MenuItemIndicator = _Indicator.styleable(function (props, forwardedRef) {
718
+ var {
719
+ scope = MENU_CONTEXT,
720
+ forceMount,
721
+ ...itemIndicatorProps
722
+ } = props,
723
+ indicatorContext = useItemIndicatorContext(scope);
724
+ return /* @__PURE__ */_jsx(Presence, {
725
+ children: forceMount || isIndeterminate(indicatorContext.checked) || indicatorContext.checked === !0 ? /* @__PURE__ */_jsx(_Indicator, {
726
+ componentName: ITEM_INDICATOR_NAME,
727
+ tag: "span",
728
+ ...itemIndicatorProps,
729
+ ref: forwardedRef,
730
+ "data-state": getCheckedState(indicatorContext.checked)
731
+ }) : null
732
+ });
733
+ });
734
+ MenuItemIndicator.displayName = ITEM_INDICATOR_NAME;
735
+ var MenuArrow = /* @__PURE__ */React.forwardRef(function (props, forwardedRef) {
736
+ var {
737
+ scope = MENU_CONTEXT,
738
+ unstyled = process.env.TAMAGUI_HEADLESS === "1",
739
+ ...rest
740
+ } = props;
741
+ return /* @__PURE__ */_jsx(PopperPrimitive.PopperArrow, {
742
+ scope,
743
+ componentName: "PopperArrow",
744
+ ...(!unstyled && {
745
+ backgroundColor: "$background"
746
+ }),
747
+ ...rest,
748
+ ref: forwardedRef
749
+ });
750
+ }),
751
+ SUB_NAME = "MenuSub",
752
+ {
753
+ Provider: MenuSubProvider,
754
+ useStyledContext: useMenuSubContext
755
+ } = createStyledContext(),
756
+ MenuSub = function (props) {
757
+ var {
758
+ scope = MENU_CONTEXT,
759
+ children,
760
+ open = !1,
761
+ onOpenChange,
762
+ ...rest
763
+ } = props,
764
+ parentMenuContext = useMenuContext(scope),
765
+ [trigger, setTrigger] = React.useState(null),
766
+ [content, setContent] = React.useState(null),
767
+ handleOpenChange = useCallbackRef(onOpenChange);
768
+ return React.useEffect(function () {
769
+ return parentMenuContext.open === !1 && handleOpenChange(!1), function () {
770
+ return handleOpenChange(!1);
771
+ };
772
+ }, [parentMenuContext.open, handleOpenChange]), /* @__PURE__ */_jsx(PopperPrimitive.Popper, {
773
+ ...rest,
774
+ scope,
775
+ children: /* @__PURE__ */_jsx(MenuProvider, {
776
+ scope,
777
+ open,
778
+ onOpenChange: handleOpenChange,
779
+ content,
780
+ onContentChange: setContent,
781
+ children: /* @__PURE__ */_jsx(MenuSubProvider, {
782
+ scope,
783
+ contentId: useId(),
784
+ triggerId: useId(),
785
+ trigger,
786
+ onTriggerChange: setTrigger,
787
+ children
788
+ })
789
+ })
790
+ });
791
+ };
792
+ MenuSub.displayName = SUB_NAME;
793
+ var SUB_TRIGGER_NAME = "MenuSubTrigger",
794
+ MenuSubTrigger = /* @__PURE__ */React.forwardRef(function (props, forwardedRef) {
795
+ var scope = props.scope || MENU_CONTEXT,
796
+ context = useMenuContext(scope),
797
+ rootContext = useMenuRootContext(scope),
798
+ subContext = useMenuSubContext(scope),
799
+ contentContext = useMenuContentContext(scope),
800
+ openTimerRef = React.useRef(null),
801
+ {
802
+ pointerGraceTimerRef,
803
+ onPointerGraceIntentChange
804
+ } = contentContext,
805
+ clearOpenTimer = React.useCallback(function () {
806
+ openTimerRef.current && window.clearTimeout(openTimerRef.current), openTimerRef.current = null;
807
+ }, []);
808
+ return React.useEffect(function () {
809
+ return clearOpenTimer;
810
+ }, [clearOpenTimer]), React.useEffect(function () {
811
+ var pointerGraceTimer = pointerGraceTimerRef.current;
812
+ return function () {
813
+ window.clearTimeout(pointerGraceTimer), onPointerGraceIntentChange(null);
814
+ };
815
+ }, [pointerGraceTimerRef, onPointerGraceIntentChange]), /* @__PURE__ */_jsx(MenuAnchor, {
816
+ componentName: SUB_TRIGGER_NAME,
817
+ asChild: !0,
818
+ scope,
819
+ children: /* @__PURE__ */_jsx(MenuItemImpl, {
820
+ id: subContext.triggerId,
821
+ "aria-haspopup": "menu",
822
+ "aria-expanded": context.open,
823
+ "aria-controls": subContext.contentId,
824
+ "data-state": getOpenState(context.open),
825
+ outlineStyle: "none",
826
+ ...props,
827
+ ref: composeRefs(forwardedRef, subContext.onTriggerChange),
828
+ // This is redundant for mouse users but we cannot determine pointer type from
829
+ // click event and we cannot use pointerup event (see git history for reasons why)
830
+ onPress: function (event) {
831
+ var _props_onPress;
832
+ (_props_onPress = props.onPress) === null || _props_onPress === void 0 || _props_onPress.call(props, event), !(props.disabled || event.defaultPrevented) && (isWeb && event.currentTarget.focus(), context.open || context.onOpenChange(!0));
833
+ },
834
+ onPointerMove: composeEventHandlers(props.onPointerMove,
835
+ // @ts-ignore
836
+ whenMouse(function (event) {
837
+ contentContext.onItemEnter(event), !event.defaultPrevented && !props.disabled && !context.open && !openTimerRef.current && (contentContext.onPointerGraceIntentChange(null), openTimerRef.current = window.setTimeout(function () {
838
+ context.onOpenChange(!0), clearOpenTimer();
839
+ }, 100));
840
+ })),
841
+ onPointerLeave: composeEventHandlers(props.onPointerLeave, function (eventIn) {
842
+ var _context_content,
843
+ event = eventIn;
844
+ clearOpenTimer();
845
+ var contentRect = (_context_content = context.content) === null || _context_content === void 0 ? void 0 : _context_content.getBoundingClientRect();
846
+ if (contentRect) {
847
+ var _context_content1,
848
+ side = (_context_content1 = context.content) === null || _context_content1 === void 0 ? void 0 : _context_content1.dataset.side,
849
+ rightSide = side === "right",
850
+ bleed = rightSide ? -5 : 5,
851
+ contentNearEdge = contentRect[rightSide ? "left" : "right"],
852
+ contentFarEdge = contentRect[rightSide ? "right" : "left"];
853
+ contentContext.onPointerGraceIntentChange({
854
+ area: [
855
+ // Apply a bleed on clientX to ensure that our exit point is
856
+ // consistently within polygon bounds
857
+ {
858
+ x: event.clientX + bleed,
859
+ y: event.clientY
860
+ }, {
861
+ x: contentNearEdge,
862
+ y: contentRect.top
863
+ }, {
864
+ x: contentFarEdge,
865
+ y: contentRect.top
866
+ }, {
867
+ x: contentFarEdge,
868
+ y: contentRect.bottom
869
+ }, {
870
+ x: contentNearEdge,
871
+ y: contentRect.bottom
872
+ }],
873
+ side
874
+ }), window.clearTimeout(pointerGraceTimerRef.current), pointerGraceTimerRef.current = window.setTimeout(function () {
875
+ return contentContext.onPointerGraceIntentChange(null);
876
+ }, 300);
877
+ } else {
878
+ if (contentContext.onTriggerLeave(event), event.defaultPrevented) return;
879
+ contentContext.onPointerGraceIntentChange(null);
880
+ }
881
+ }),
882
+ ...(isWeb ? {
883
+ onKeyDown: composeEventHandlers(props.onKeyDown, function (event) {
884
+ var isTypingAhead = contentContext.searchRef.current !== "";
885
+ if (!(props.disabled || isTypingAhead && event.key === " ") && SUB_OPEN_KEYS[rootContext.dir].includes(event.key)) {
886
+ var _context_content;
887
+ context.onOpenChange(!0), (_context_content = context.content) === null || _context_content === void 0 || _context_content.focus(), event.preventDefault();
888
+ }
889
+ })
890
+ } : null)
891
+ })
892
+ });
893
+ });
894
+ MenuSubTrigger.displayName = SUB_TRIGGER_NAME;
895
+ var SUB_CONTENT_NAME = "MenuSubContent",
896
+ MenuSubContent = /* @__PURE__ */React.forwardRef(function (props, forwardedRef) {
897
+ var scope = props.scope || MENU_CONTEXT,
898
+ portalContext = usePortalContext(scope),
899
+ {
900
+ forceMount = portalContext.forceMount,
901
+ ...subContentProps
902
+ } = props,
903
+ context = useMenuContext(scope),
904
+ rootContext = useMenuRootContext(scope),
905
+ subContext = useMenuSubContext(scope),
906
+ ref = React.useRef(null),
907
+ composedRefs = useComposedRefs(forwardedRef, ref);
908
+ return /* @__PURE__ */_jsx(Collection.Provider, {
909
+ scope,
910
+ children: /* @__PURE__ */_jsx(Collection.Slot, {
911
+ scope,
912
+ children: /* @__PURE__ */_jsx(MenuContentImpl, {
913
+ id: subContext.contentId,
914
+ "aria-labelledby": subContext.triggerId,
915
+ ...subContentProps,
916
+ ref: composedRefs,
917
+ "data-side": rootContext.dir === "rtl" ? "left" : "right",
918
+ disableOutsidePointerEvents: !1,
919
+ disableOutsideScroll: !1,
920
+ trapFocus: !1,
921
+ onOpenAutoFocus: function (event) {
922
+ var _ref_current;
923
+ rootContext.isUsingKeyboardRef.current && ((_ref_current = ref.current) === null || _ref_current === void 0 || _ref_current.focus()), event.preventDefault();
924
+ },
925
+ // The menu might close because of focusing another menu item in the parent menu. We
926
+ // don't want it to refocus the trigger in that case so we handle trigger focus ourselves.
927
+ onCloseAutoFocus: function (event) {
928
+ return event.preventDefault();
929
+ },
930
+ onFocusOutside: composeEventHandlers(props.onFocusOutside, function (event) {
931
+ event.target !== subContext.trigger && context.onOpenChange(!1);
932
+ }),
933
+ onEscapeKeyDown: composeEventHandlers(props.onEscapeKeyDown, function (event) {
934
+ rootContext.onClose(), event.preventDefault();
935
+ }),
936
+ ...(isWeb ? {
937
+ onKeyDown: composeEventHandlers(props.onKeyDown, function (event) {
938
+ var isKeyDownInside = event.currentTarget.contains(event.target),
939
+ isCloseKey = SUB_CLOSE_KEYS[rootContext.dir].includes(event.key);
940
+ if (isKeyDownInside && isCloseKey) {
941
+ var _subContext_trigger;
942
+ context.onOpenChange(!1), (_subContext_trigger = subContext.trigger) === null || _subContext_trigger === void 0 || _subContext_trigger.focus(), event.preventDefault();
943
+ }
944
+ })
945
+ } : null)
946
+ })
947
+ })
948
+ });
949
+ });
950
+ MenuSubContent.displayName = SUB_CONTENT_NAME;
951
+ var Anchor = MenuAnchor,
952
+ Portal = MenuPortal,
953
+ Content = MenuContent,
954
+ Group = _MenuGroup,
955
+ Label = _Label,
956
+ Item = MenuItem,
957
+ CheckboxItem = MenuCheckboxItem,
958
+ RadioGroup = MenuRadioGroup,
959
+ RadioItem = MenuRadioItem,
960
+ ItemIndicator = MenuItemIndicator,
961
+ Separator = _Separator,
962
+ Arrow = MenuArrow,
963
+ Sub = MenuSub,
964
+ SubTrigger = MenuSubTrigger,
965
+ SubContent = MenuSubContent,
966
+ ItemTitle = MenuItemTitle,
967
+ ItemSubtitle = MenuItemSubTitle,
968
+ ItemImage = MenuItemImage,
969
+ ItemIcon = MenuItemIcon,
970
+ Menu = withStaticProperties(MenuComp, {
971
+ Anchor,
972
+ Portal,
973
+ Content,
974
+ Group,
975
+ Label,
976
+ Item,
977
+ CheckboxItem,
978
+ RadioGroup,
979
+ RadioItem,
980
+ ItemIndicator,
981
+ Separator,
982
+ Arrow,
983
+ Sub,
984
+ SubTrigger,
985
+ SubContent,
986
+ ItemTitle,
987
+ ItemSubtitle,
988
+ ItemImage,
989
+ ItemIcon
990
+ });
991
+ return {
992
+ Menu
993
+ };
994
+ }
995
+ function getOpenState(open) {
996
+ return open ? "open" : "closed";
997
+ }
998
+ function isIndeterminate(checked) {
999
+ return checked === "indeterminate";
1000
+ }
1001
+ function getCheckedState(checked) {
1002
+ return isIndeterminate(checked) ? "indeterminate" : checked ? "checked" : "unchecked";
1003
+ }
1004
+ function focusFirst(candidates) {
1005
+ var PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement,
1006
+ _iteratorNormalCompletion = !0,
1007
+ _didIteratorError = !1,
1008
+ _iteratorError = void 0;
1009
+ try {
1010
+ for (var _iterator = candidates[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = !0) {
1011
+ var candidate = _step.value;
1012
+ if (candidate === PREVIOUSLY_FOCUSED_ELEMENT || (candidate.focus(), document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT)) return;
1013
+ }
1014
+ } catch (err) {
1015
+ _didIteratorError = !0, _iteratorError = err;
1016
+ } finally {
1017
+ try {
1018
+ !_iteratorNormalCompletion && _iterator.return != null && _iterator.return();
1019
+ } finally {
1020
+ if (_didIteratorError) throw _iteratorError;
1021
+ }
1022
+ }
1023
+ }
1024
+ function wrapArray(array, startIndex) {
1025
+ return array.map(function (_, index) {
1026
+ return array[(startIndex + index) % array.length];
1027
+ });
1028
+ }
1029
+ function getNextMatch(values, search, currentMatch) {
1030
+ var isRepeated = search.length > 1 && Array.from(search).every(function (char) {
1031
+ return char === search[0];
1032
+ }),
1033
+ normalizedSearch = isRepeated ? search[0] : search,
1034
+ currentMatchIndex = currentMatch ? values.indexOf(currentMatch) : -1,
1035
+ wrappedValues = wrapArray(values, Math.max(currentMatchIndex, 0)),
1036
+ excludeCurrentMatch = normalizedSearch.length === 1;
1037
+ excludeCurrentMatch && (wrappedValues = wrappedValues.filter(function (v) {
1038
+ return v !== currentMatch;
1039
+ }));
1040
+ var nextMatch = wrappedValues.find(function (value) {
1041
+ return value.toLowerCase().startsWith(normalizedSearch.toLowerCase());
1042
+ });
1043
+ return nextMatch !== currentMatch ? nextMatch : void 0;
1044
+ }
1045
+ function isPointInPolygon(point, polygon) {
1046
+ for (var {
1047
+ x,
1048
+ y
1049
+ } = point, inside = !1, i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
1050
+ var xi = polygon[i].x,
1051
+ yi = polygon[i].y,
1052
+ xj = polygon[j].x,
1053
+ yj = polygon[j].y,
1054
+ intersect = yi > y != yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi;
1055
+ intersect && (inside = !inside);
1056
+ }
1057
+ return inside;
1058
+ }
1059
+ function isPointerInGraceArea(event, area) {
1060
+ if (!area) return !1;
1061
+ var cursorPos = {
1062
+ x: event.clientX,
1063
+ y: event.clientY
1064
+ };
1065
+ return isPointInPolygon(cursorPos, area);
1066
+ }
1067
+ export { createBaseMenu };
1068
+ //# sourceMappingURL=createBaseMenu.native.js.map