@tamagui/create-menu 1.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 (143) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/MenuPredefined.cjs +189 -0
  3. package/dist/cjs/MenuPredefined.js +168 -0
  4. package/dist/cjs/MenuPredefined.js.map +6 -0
  5. package/dist/cjs/MenuPredefined.native.js +192 -0
  6. package/dist/cjs/MenuPredefined.native.js.map +1 -0
  7. package/dist/cjs/createBaseMenu.cjs +1147 -0
  8. package/dist/cjs/createBaseMenu.js +884 -0
  9. package/dist/cjs/createBaseMenu.js.map +6 -0
  10. package/dist/cjs/createBaseMenu.native.js +1346 -0
  11. package/dist/cjs/createBaseMenu.native.js.map +1 -0
  12. package/dist/cjs/createNativeMenu/createNativeMenu.cjs +242 -0
  13. package/dist/cjs/createNativeMenu/createNativeMenu.js +184 -0
  14. package/dist/cjs/createNativeMenu/createNativeMenu.js.map +6 -0
  15. package/dist/cjs/createNativeMenu/createNativeMenu.native.js +307 -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/utils.cjs +68 -0
  23. package/dist/cjs/createNativeMenu/utils.js +66 -0
  24. package/dist/cjs/createNativeMenu/utils.js.map +6 -0
  25. package/dist/cjs/createNativeMenu/utils.native.js +94 -0
  26. package/dist/cjs/createNativeMenu/utils.native.js.map +1 -0
  27. package/dist/cjs/createNativeMenu/withNativeMenu.cjs +37 -0
  28. package/dist/cjs/createNativeMenu/withNativeMenu.js +30 -0
  29. package/dist/cjs/createNativeMenu/withNativeMenu.js.map +6 -0
  30. package/dist/cjs/createNativeMenu/withNativeMenu.native.js +43 -0
  31. package/dist/cjs/createNativeMenu/withNativeMenu.native.js.map +1 -0
  32. package/dist/cjs/index.cjs +30 -0
  33. package/dist/cjs/index.js +24 -0
  34. package/dist/cjs/index.js.map +6 -0
  35. package/dist/cjs/index.native.js +33 -0
  36. package/dist/cjs/index.native.js.map +1 -0
  37. package/dist/esm/MenuPredefined.js +154 -0
  38. package/dist/esm/MenuPredefined.js.map +6 -0
  39. package/dist/esm/MenuPredefined.mjs +166 -0
  40. package/dist/esm/MenuPredefined.mjs.map +1 -0
  41. package/dist/esm/MenuPredefined.native.js +166 -0
  42. package/dist/esm/MenuPredefined.native.js.map +1 -0
  43. package/dist/esm/createBaseMenu.js +892 -0
  44. package/dist/esm/createBaseMenu.js.map +6 -0
  45. package/dist/esm/createBaseMenu.mjs +1113 -0
  46. package/dist/esm/createBaseMenu.mjs.map +1 -0
  47. package/dist/esm/createBaseMenu.native.js +1309 -0
  48. package/dist/esm/createBaseMenu.native.js.map +1 -0
  49. package/dist/esm/createNativeMenu/createNativeMenu.js +163 -0
  50. package/dist/esm/createNativeMenu/createNativeMenu.js.map +6 -0
  51. package/dist/esm/createNativeMenu/createNativeMenu.mjs +208 -0
  52. package/dist/esm/createNativeMenu/createNativeMenu.mjs.map +1 -0
  53. package/dist/esm/createNativeMenu/createNativeMenu.native.js +270 -0
  54. package/dist/esm/createNativeMenu/createNativeMenu.native.js.map +1 -0
  55. package/dist/esm/createNativeMenu/createNativeMenuTypes.js +1 -0
  56. package/dist/esm/createNativeMenu/createNativeMenuTypes.js.map +6 -0
  57. package/dist/esm/createNativeMenu/createNativeMenuTypes.mjs +2 -0
  58. package/dist/esm/createNativeMenu/createNativeMenuTypes.mjs.map +1 -0
  59. package/dist/esm/createNativeMenu/createNativeMenuTypes.native.js +2 -0
  60. package/dist/esm/createNativeMenu/createNativeMenuTypes.native.js.map +1 -0
  61. package/dist/esm/createNativeMenu/utils.js +47 -0
  62. package/dist/esm/createNativeMenu/utils.js.map +6 -0
  63. package/dist/esm/createNativeMenu/utils.mjs +29 -0
  64. package/dist/esm/createNativeMenu/utils.mjs.map +1 -0
  65. package/dist/esm/createNativeMenu/utils.native.js +52 -0
  66. package/dist/esm/createNativeMenu/utils.native.js.map +1 -0
  67. package/dist/esm/createNativeMenu/withNativeMenu.js +15 -0
  68. package/dist/esm/createNativeMenu/withNativeMenu.js.map +6 -0
  69. package/dist/esm/createNativeMenu/withNativeMenu.mjs +14 -0
  70. package/dist/esm/createNativeMenu/withNativeMenu.mjs.map +1 -0
  71. package/dist/esm/createNativeMenu/withNativeMenu.native.js +17 -0
  72. package/dist/esm/createNativeMenu/withNativeMenu.native.js.map +1 -0
  73. package/dist/esm/index.js +8 -0
  74. package/dist/esm/index.js.map +6 -0
  75. package/dist/esm/index.mjs +6 -0
  76. package/dist/esm/index.mjs.map +1 -0
  77. package/dist/esm/index.native.js +6 -0
  78. package/dist/esm/index.native.js.map +1 -0
  79. package/dist/jsx/MenuPredefined.js +154 -0
  80. package/dist/jsx/MenuPredefined.js.map +6 -0
  81. package/dist/jsx/MenuPredefined.mjs +166 -0
  82. package/dist/jsx/MenuPredefined.mjs.map +1 -0
  83. package/dist/jsx/MenuPredefined.native.js +192 -0
  84. package/dist/jsx/MenuPredefined.native.js.map +1 -0
  85. package/dist/jsx/createBaseMenu.js +892 -0
  86. package/dist/jsx/createBaseMenu.js.map +6 -0
  87. package/dist/jsx/createBaseMenu.mjs +1113 -0
  88. package/dist/jsx/createBaseMenu.mjs.map +1 -0
  89. package/dist/jsx/createBaseMenu.native.js +1346 -0
  90. package/dist/jsx/createBaseMenu.native.js.map +1 -0
  91. package/dist/jsx/createNativeMenu/createNativeMenu.js +163 -0
  92. package/dist/jsx/createNativeMenu/createNativeMenu.js.map +6 -0
  93. package/dist/jsx/createNativeMenu/createNativeMenu.mjs +208 -0
  94. package/dist/jsx/createNativeMenu/createNativeMenu.mjs.map +1 -0
  95. package/dist/jsx/createNativeMenu/createNativeMenu.native.js +307 -0
  96. package/dist/jsx/createNativeMenu/createNativeMenu.native.js.map +1 -0
  97. package/dist/jsx/createNativeMenu/createNativeMenuTypes.js +1 -0
  98. package/dist/jsx/createNativeMenu/createNativeMenuTypes.js.map +6 -0
  99. package/dist/jsx/createNativeMenu/createNativeMenuTypes.mjs +2 -0
  100. package/dist/jsx/createNativeMenu/createNativeMenuTypes.mjs.map +1 -0
  101. package/dist/jsx/createNativeMenu/createNativeMenuTypes.native.js +19 -0
  102. package/dist/jsx/createNativeMenu/createNativeMenuTypes.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 +15 -0
  110. package/dist/jsx/createNativeMenu/withNativeMenu.js.map +6 -0
  111. package/dist/jsx/createNativeMenu/withNativeMenu.mjs +14 -0
  112. package/dist/jsx/createNativeMenu/withNativeMenu.mjs.map +1 -0
  113. package/dist/jsx/createNativeMenu/withNativeMenu.native.js +43 -0
  114. package/dist/jsx/createNativeMenu/withNativeMenu.native.js.map +1 -0
  115. package/dist/jsx/index.js +8 -0
  116. package/dist/jsx/index.js.map +6 -0
  117. package/dist/jsx/index.mjs +6 -0
  118. package/dist/jsx/index.mjs.map +1 -0
  119. package/dist/jsx/index.native.js +33 -0
  120. package/dist/jsx/index.native.js.map +1 -0
  121. package/package.json +69 -0
  122. package/src/MenuPredefined.tsx +204 -0
  123. package/src/createBaseMenu.tsx +2031 -0
  124. package/src/createNativeMenu/createNativeMenu.tsx +400 -0
  125. package/src/createNativeMenu/createNativeMenuTypes.ts +214 -0
  126. package/src/createNativeMenu/utils.tsx +150 -0
  127. package/src/createNativeMenu/withNativeMenu.tsx +39 -0
  128. package/src/index.tsx +5 -0
  129. package/types/MenuPredefined.d.ts +31 -0
  130. package/types/MenuPredefined.d.ts.map +1 -0
  131. package/types/createBaseMenu.d.ts +298 -0
  132. package/types/createBaseMenu.d.ts.map +1 -0
  133. package/types/createNativeMenu/createNativeMenu.d.ts +42 -0
  134. package/types/createNativeMenu/createNativeMenu.d.ts.map +1 -0
  135. package/types/createNativeMenu/createNativeMenuTypes.d.ts +188 -0
  136. package/types/createNativeMenu/createNativeMenuTypes.d.ts.map +1 -0
  137. package/types/createNativeMenu/index.d.ts +4 -0
  138. package/types/createNativeMenu/utils.d.ts +38 -0
  139. package/types/createNativeMenu/utils.d.ts.map +1 -0
  140. package/types/createNativeMenu/withNativeMenu.d.ts +9 -0
  141. package/types/createNativeMenu/withNativeMenu.d.ts.map +1 -0
  142. package/types/index.d.ts +6 -0
  143. package/types/index.d.ts.map +1 -0
@@ -0,0 +1,884 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf, __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: !0 });
9
+ }, __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from == "object" || typeof from == "function")
11
+ for (let key of __getOwnPropNames(from))
12
+ !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ return to;
14
+ };
15
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
16
+ // If the importer is in node compatibility mode or this is not an ESM
17
+ // file that has been converted to a CommonJS file using a Babel-
18
+ // compatible transform (i.e. "__esModule" has not been set), then set
19
+ // "default" to the CommonJS "module.exports" for node compatibility.
20
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: !0 }) : target,
21
+ mod
22
+ )), __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: !0 }), mod);
23
+ var createBaseMenu_exports = {};
24
+ __export(createBaseMenu_exports, {
25
+ createBaseMenu: () => createBaseMenu
26
+ });
27
+ module.exports = __toCommonJS(createBaseMenu_exports);
28
+ var import_animate = require("@tamagui/animate"), import_animate_presence = require("@tamagui/animate-presence"), import_collection = require("@tamagui/collection"), import_dismissable = require("@tamagui/dismissable"), import_focus_guard = require("@tamagui/focus-guard"), import_focus_scope = require("@tamagui/focus-scope"), PopperPrimitive = __toESM(require("@tamagui/popper"), 1), import_portal = require("@tamagui/portal"), import_remove_scroll = require("@tamagui/remove-scroll"), import_roving_focus = require("@tamagui/roving-focus"), import_use_callback_ref = require("@tamagui/use-callback-ref"), import_use_direction = require("@tamagui/use-direction"), import_web = require("@tamagui/web"), React = __toESM(require("react"), 1), import_react = require("react"), import_MenuPredefined = require("./MenuPredefined"), import_jsx_runtime = require("react/jsx-runtime");
29
+ function whenMouse(handler) {
30
+ return (event) => event.pointerType === "mouse" ? handler(event) : void 0;
31
+ }
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] = (0, import_collection.createCollection)(MENU_NAME), { Provider: MenuProvider, useStyledContext: useMenuContext } = (0, import_web.createStyledContext)(), { Provider: MenuRootProvider, useStyledContext: useMenuRootContext } = (0, import_web.createStyledContext)(), MENU_CONTEXT = "MenuContext";
39
+ function createBaseMenu({
40
+ Item: _Item = import_MenuPredefined.MenuPredefined.MenuItem,
41
+ Title: _Title = import_MenuPredefined.MenuPredefined.Title,
42
+ SubTitle: _SubTitle = import_MenuPredefined.MenuPredefined.SubTitle,
43
+ Image: _Image = import_MenuPredefined.MenuPredefined.MenuImage,
44
+ Icon: _Icon = import_MenuPredefined.MenuPredefined.MenuIcon,
45
+ Indicator: _Indicator = import_MenuPredefined.MenuPredefined.MenuIndicator,
46
+ Separator: _Separator = import_MenuPredefined.MenuPredefined.MenuSeparator,
47
+ MenuGroup: _MenuGroup = import_MenuPredefined.MenuPredefined.MenuGroup,
48
+ Label: _Label = import_MenuPredefined.MenuPredefined.MenuLabel
49
+ }) {
50
+ const MenuComp = (props) => {
51
+ const direction = (0, import_use_direction.useDirection)(props.dir), defaultPlacement = direction === "rtl" ? "bottom-end" : "bottom-start", {
52
+ scope = MENU_CONTEXT,
53
+ open = !1,
54
+ children,
55
+ dir,
56
+ onOpenChange,
57
+ modal = !0,
58
+ allowFlip = { padding: 10 },
59
+ stayInFrame = { padding: 10 },
60
+ placement = defaultPlacement,
61
+ resize = !0,
62
+ offset = 10,
63
+ ...rest
64
+ } = props, [content, setContent] = React.useState(null), isUsingKeyboardRef = React.useRef(!1), handleOpenChange = (0, import_use_callback_ref.useCallbackRef)(onOpenChange);
65
+ return import_web.isWeb && React.useEffect(() => {
66
+ const handleKeyDown = () => {
67
+ isUsingKeyboardRef.current = !0, document.addEventListener("pointerdown", handlePointer, {
68
+ capture: !0,
69
+ once: !0
70
+ }), document.addEventListener("pointermove", handlePointer, {
71
+ capture: !0,
72
+ once: !0
73
+ });
74
+ }, handlePointer = () => isUsingKeyboardRef.current = !1;
75
+ return document.addEventListener("keydown", handleKeyDown, { capture: !0 }), () => {
76
+ document.removeEventListener("keydown", handleKeyDown, { capture: !0 }), document.removeEventListener("pointerdown", handlePointer, { capture: !0 }), document.removeEventListener("pointermove", handlePointer, { capture: !0 });
77
+ };
78
+ }, []), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
79
+ PopperPrimitive.Popper,
80
+ {
81
+ scope,
82
+ open,
83
+ placement,
84
+ allowFlip,
85
+ stayInFrame,
86
+ resize,
87
+ offset,
88
+ ...rest,
89
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
90
+ MenuProvider,
91
+ {
92
+ scope,
93
+ open,
94
+ onOpenChange: handleOpenChange,
95
+ content,
96
+ onContentChange: setContent,
97
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
98
+ MenuRootProvider,
99
+ {
100
+ scope,
101
+ open,
102
+ onClose: React.useCallback(() => handleOpenChange(!1), [handleOpenChange]),
103
+ isUsingKeyboardRef,
104
+ dir: direction,
105
+ modal,
106
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuSubProvider, { scope, children })
107
+ }
108
+ )
109
+ }
110
+ )
111
+ }
112
+ );
113
+ }, RepropagateMenuAndMenuRootProvider = (props) => {
114
+ const {
115
+ scope = MENU_CONTEXT,
116
+ menuContext,
117
+ rootContext,
118
+ popperContext,
119
+ menuSubContext,
120
+ children
121
+ } = props;
122
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PopperPrimitive.PopperProvider, { ...popperContext, scope, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuProvider, { scope, ...menuContext, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuRootProvider, { scope, ...rootContext, children: menuSubContext ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuSubProvider, { scope, ...menuSubContext, children }) : children }) }) });
123
+ };
124
+ MenuComp.displayName = MENU_NAME;
125
+ const ANCHOR_NAME = "MenuAnchor", MenuAnchor = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PopperPrimitive.PopperAnchor, { scope: MENU_CONTEXT, ...props });
126
+ MenuAnchor.displayName = ANCHOR_NAME;
127
+ const PORTAL_NAME = "MenuPortal", { Provider: PortalProvider, useStyledContext: usePortalContext } = (0, import_web.createStyledContext)(void 0, "Portal"), MenuPortal = (props) => {
128
+ const { scope = MENU_CONTEXT, forceMount, zIndex, children } = props, menuContext = useMenuContext(scope), rootContext = useMenuRootContext(scope), popperContext = PopperPrimitive.usePopperContext(scope), menuSubContext = useMenuSubContext(scope), themeName = (0, import_web.useThemeName)(), themedChildren = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_web.Theme, { forceClassName: !0, name: themeName, children }), content = (0, import_portal.needsPortalRepropagation)() ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
129
+ RepropagateMenuAndMenuRootProvider,
130
+ {
131
+ menuContext,
132
+ rootContext,
133
+ popperContext,
134
+ menuSubContext,
135
+ scope,
136
+ children: themedChildren
137
+ }
138
+ ) : themedChildren, isPresent = forceMount || rootContext.open && menuContext.open;
139
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_animate.Animate, { type: "presence", present: isPresent, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_portal.Portal, { stackZIndex: !0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PortalProvider, { scope, forceMount, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_web.View, { zIndex: zIndex || 100, inset: 0, position: "absolute", children: [
140
+ !!menuContext.open && !import_web.isWeb && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
141
+ import_web.View,
142
+ {
143
+ inset: 0,
144
+ position: "absolute",
145
+ onPress: () => menuContext.onOpenChange(!menuContext.open)
146
+ }
147
+ ),
148
+ content
149
+ ] }) }) }) }) });
150
+ };
151
+ MenuPortal.displayName = PORTAL_NAME;
152
+ const CONTENT_NAME = "MenuContent", { Provider: MenuContentProvider, useStyledContext: useMenuContentContext } = (0, import_web.createStyledContext)(), MenuContent = (0, import_web.styled)(PopperPrimitive.PopperContentFrame, {
153
+ name: CONTENT_NAME
154
+ }).styleable(
155
+ (props, forwardedRef) => {
156
+ const scope = props.scope || MENU_CONTEXT, portalContext = usePortalContext(scope), { forceMount = portalContext.forceMount, ...contentProps } = props, rootContext = useMenuRootContext(scope);
157
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.Provider, { scope, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.Slot, { scope, children: rootContext.modal ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuRootContentModal, { ...contentProps, ref: forwardedRef }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuRootContentNonModal, { ...contentProps, ref: forwardedRef }) }) });
158
+ }
159
+ ), MenuRootContentModal = React.forwardRef((props, forwardedRef) => {
160
+ const scope = props.scope || MENU_CONTEXT, context = useMenuContext(scope), ref = React.useRef(null), composedRefs = (0, import_web.useComposedRefs)(forwardedRef, ref);
161
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
162
+ MenuContentImpl,
163
+ {
164
+ ...props,
165
+ scope,
166
+ ref: composedRefs,
167
+ trapFocus: context.open,
168
+ disableOutsidePointerEvents: context.open,
169
+ disableOutsideScroll: !1,
170
+ onFocusOutside: (0, import_web.composeEventHandlers)(
171
+ props.onFocusOutside,
172
+ (event) => event.preventDefault(),
173
+ { checkDefaultPrevented: !1 }
174
+ ),
175
+ onDismiss: () => context.onOpenChange(!1)
176
+ }
177
+ );
178
+ }), MenuRootContentNonModal = React.forwardRef((props, forwardedRef) => {
179
+ const scope = props.scope || MENU_CONTEXT, context = useMenuContext(scope);
180
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
181
+ MenuContentImpl,
182
+ {
183
+ ...props,
184
+ scope,
185
+ ref: forwardedRef,
186
+ trapFocus: !1,
187
+ disableOutsidePointerEvents: !1,
188
+ disableOutsideScroll: !1,
189
+ onDismiss: () => context.onOpenChange(!1)
190
+ }
191
+ );
192
+ }), MenuContentImpl = React.forwardRef((props, forwardedRef) => {
193
+ const {
194
+ scope = MENU_CONTEXT,
195
+ loop = !1,
196
+ trapFocus,
197
+ onOpenAutoFocus,
198
+ onCloseAutoFocus,
199
+ disableOutsidePointerEvents,
200
+ onEntryFocus,
201
+ onEscapeKeyDown,
202
+ onPointerDownOutside,
203
+ onFocusOutside,
204
+ onInteractOutside,
205
+ onDismiss,
206
+ disableOutsideScroll,
207
+ disableDismissOnScroll = !1,
208
+ unstyled = process.env.TAMAGUI_HEADLESS === "1",
209
+ ...contentProps
210
+ } = props, context = useMenuContext(scope), rootContext = useMenuRootContext(scope), getItems = useCollection(scope), [currentItemId, setCurrentItemId] = React.useState(null), contentRef = React.useRef(null), focusableContentRef = React.useRef(null), composedRefs = (0, import_web.useComposedRefs)(
211
+ forwardedRef,
212
+ contentRef,
213
+ context.onContentChange
214
+ ), 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) => {
215
+ const search = searchRef.current + key, items = getItems().filter((item) => !item.disabled), currentItem = document.activeElement, currentMatch = items.find(
216
+ (item) => item.ref.current === currentItem
217
+ )?.textValue, values = items.map((item) => item.textValue), nextMatch = getNextMatch(values, search, currentMatch), newItem = items.find((item) => item.textValue === nextMatch)?.ref.current;
218
+ (function updateSearch(value) {
219
+ searchRef.current = value, clearTimeout(timerRef.current), value !== "" && (timerRef.current = setTimeout(() => updateSearch(""), 1e3));
220
+ })(search), newItem && setTimeout(() => newItem.focus());
221
+ };
222
+ React.useEffect(() => () => clearTimeout(timerRef.current), []), React.useEffect(() => {
223
+ if (!import_web.isWeb || !context.open) return;
224
+ const frame = requestAnimationFrame(() => {
225
+ const el = contentRef.current?.querySelector("[data-tamagui-menu-content]");
226
+ el && (focusableContentRef.current = el);
227
+ });
228
+ return () => cancelAnimationFrame(frame);
229
+ }, [context.open]), React.useEffect(() => {
230
+ if (!import_web.isWeb || disableDismissOnScroll || !context.open) return;
231
+ const handleScroll = (event) => {
232
+ const target = event.target;
233
+ contentRef.current?.contains(target) || onDismiss?.();
234
+ };
235
+ return window.addEventListener("scroll", handleScroll, { capture: !0, passive: !0 }), () => {
236
+ window.removeEventListener("scroll", handleScroll, { capture: !0 });
237
+ };
238
+ }, [disableDismissOnScroll, context.open, onDismiss]), import_web.isWeb && (0, import_focus_guard.useFocusGuards)();
239
+ const isPointerMovingToSubmenu = React.useCallback((event) => {
240
+ const isMovingTowards = pointerDirRef.current === pointerGraceIntentRef.current?.side, inArea = isPointerInGraceArea(event, pointerGraceIntentRef.current?.area);
241
+ return isMovingTowards && inArea;
242
+ }, []), content = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
243
+ PopperPrimitive.PopperContent,
244
+ {
245
+ role: "menu",
246
+ tabIndex: -1,
247
+ unstyled,
248
+ ...!unstyled && {
249
+ backgroundColor: "$background",
250
+ borderWidth: 1,
251
+ borderColor: "$borderColor",
252
+ outlineWidth: 0,
253
+ minWidth: 180
254
+ },
255
+ "aria-orientation": "vertical",
256
+ "data-state": getOpenState(context.open),
257
+ "data-tamagui-menu-content": "",
258
+ dir: rootContext.dir,
259
+ scope: scope || MENU_CONTEXT,
260
+ ...contentProps,
261
+ ref: composedRefs,
262
+ className: contentProps.transition ? void 0 : contentProps.className,
263
+ ...import_web.isWeb ? {
264
+ onKeyDown: (0, import_web.composeEventHandlers)(contentProps.onKeyDown, (event) => {
265
+ const isKeyDownInside = event.target.closest("[data-tamagui-menu-content]") === event.currentTarget, isModifierKey = event.ctrlKey || event.altKey || event.metaKey, isCharacterKey = event.key.length === 1;
266
+ isKeyDownInside && (event.key === "Tab" && event.preventDefault(), !isModifierKey && isCharacterKey && handleTypeaheadSearch(event.key));
267
+ const isOnContentFrame = event.target.hasAttribute(
268
+ "data-tamagui-menu-content"
269
+ );
270
+ if (!isKeyDownInside || !isOnContentFrame || !FIRST_LAST_KEYS.includes(event.key)) return;
271
+ event.preventDefault();
272
+ const candidateNodes = getItems().filter((item) => !item.disabled).map((item) => item.ref.current);
273
+ LAST_KEYS.includes(event.key) && candidateNodes.reverse(), focusFirst(candidateNodes, { focusVisible: !0 });
274
+ }),
275
+ // TODO
276
+ // @ts-ignore
277
+ onBlur: (0, import_web.composeEventHandlers)(props.onBlur, (event) => {
278
+ event.currentTarget?.contains(event.target) || (clearTimeout(timerRef.current), searchRef.current = "");
279
+ }),
280
+ // TODO
281
+ onPointerMove: (0, import_web.composeEventHandlers)(props.onPointerMove, (event) => {
282
+ if (event.pointerType !== "mouse") return;
283
+ const target = event.target, pointerXHasChanged = lastPointerXRef.current !== event.clientX;
284
+ if (event.currentTarget?.contains(target) && pointerXHasChanged) {
285
+ const newDir = event.clientX > lastPointerXRef.current ? "right" : "left";
286
+ pointerDirRef.current = newDir, lastPointerXRef.current = event.clientX;
287
+ }
288
+ })
289
+ } : {}
290
+ }
291
+ );
292
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
293
+ MenuContentProvider,
294
+ {
295
+ scope,
296
+ searchRef,
297
+ onItemEnter: React.useCallback(
298
+ (event) => {
299
+ isPointerMovingToSubmenu(event) && event.preventDefault();
300
+ },
301
+ [isPointerMovingToSubmenu]
302
+ ),
303
+ onItemLeave: React.useCallback(
304
+ (event) => {
305
+ isPointerMovingToSubmenu(event) || (focusableContentRef.current?.focus(), setCurrentItemId(null));
306
+ },
307
+ [isPointerMovingToSubmenu]
308
+ ),
309
+ onTriggerLeave: React.useCallback(
310
+ (event) => {
311
+ isPointerMovingToSubmenu(event) && event.preventDefault();
312
+ },
313
+ [isPointerMovingToSubmenu]
314
+ ),
315
+ pointerGraceTimerRef,
316
+ onPointerGraceIntentChange: React.useCallback((intent) => {
317
+ pointerGraceIntentRef.current = intent;
318
+ }, []),
319
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_remove_scroll.RemoveScroll, { enabled: disableOutsideScroll, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
320
+ import_focus_scope.FocusScope,
321
+ {
322
+ asChild: !1,
323
+ trapped: trapFocus,
324
+ onMountAutoFocus: (0, import_web.composeEventHandlers)(onOpenAutoFocus, (event) => {
325
+ event.preventDefault(), document.querySelector(
326
+ "[data-tamagui-menu-content]"
327
+ )?.focus({ preventScroll: !0 });
328
+ }),
329
+ onUnmountAutoFocus: onCloseAutoFocus,
330
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
331
+ import_dismissable.Dismissable,
332
+ {
333
+ disableOutsidePointerEvents,
334
+ onEscapeKeyDown,
335
+ onPointerDownOutside,
336
+ onFocusOutside,
337
+ onInteractOutside,
338
+ onDismiss,
339
+ asChild: !0,
340
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
341
+ import_roving_focus.RovingFocusGroup,
342
+ {
343
+ asChild: !0,
344
+ __scopeRovingFocusGroup: scope || MENU_CONTEXT,
345
+ dir: rootContext.dir,
346
+ orientation: "vertical",
347
+ loop,
348
+ currentTabStopId: currentItemId,
349
+ onCurrentTabStopIdChange: setCurrentItemId,
350
+ onEntryFocus: (0, import_web.composeEventHandlers)(onEntryFocus, (event) => {
351
+ rootContext.isUsingKeyboardRef.current || event.preventDefault();
352
+ }),
353
+ children: content
354
+ }
355
+ )
356
+ }
357
+ )
358
+ }
359
+ ) })
360
+ }
361
+ );
362
+ });
363
+ MenuContent.displayName = CONTENT_NAME;
364
+ const ITEM_NAME = "MenuItem", ITEM_SELECT = "menu.itemSelect", MenuItem = _Item.styleable((props, forwardedRef) => {
365
+ const {
366
+ disabled = !1,
367
+ onSelect,
368
+ preventCloseOnSelect,
369
+ children,
370
+ scope = MENU_CONTEXT,
371
+ // filter out native-only props that shouldn't reach the DOM
372
+ // @ts-ignore
373
+ destructive,
374
+ // @ts-ignore
375
+ hidden,
376
+ // @ts-ignore
377
+ androidIconName,
378
+ // @ts-ignore
379
+ iosIconName,
380
+ ...itemProps
381
+ } = props, ref = React.useRef(null), rootContext = useMenuRootContext(scope), contentContext = useMenuContentContext(scope), composedRefs = (0, import_web.useComposedRefs)(forwardedRef, ref), isPointerDownRef = React.useRef(!1), handleSelect = () => {
382
+ const menuItem = ref.current;
383
+ if (!disabled && menuItem)
384
+ if (import_web.isWeb) {
385
+ const menuItemEl = menuItem, itemSelectEvent = new CustomEvent(ITEM_SELECT, {
386
+ bubbles: !0,
387
+ cancelable: !0
388
+ });
389
+ menuItemEl.addEventListener(ITEM_SELECT, (event) => onSelect?.(event), {
390
+ once: !0
391
+ }), (0, import_dismissable.dispatchDiscreteCustomEvent)(menuItemEl, itemSelectEvent), itemSelectEvent.defaultPrevented || preventCloseOnSelect ? isPointerDownRef.current = !1 : rootContext.onClose();
392
+ } else
393
+ onSelect?.({ target: menuItem }), isPointerDownRef.current = !1, preventCloseOnSelect || rootContext.onClose();
394
+ }, content = typeof children == "string" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_web.Text, { children }) : children;
395
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
396
+ MenuItemImpl,
397
+ {
398
+ outlineStyle: "none",
399
+ ...itemProps,
400
+ scope,
401
+ ref: composedRefs,
402
+ disabled,
403
+ onPress: (0, import_web.composeEventHandlers)(props.onPress, handleSelect),
404
+ onPointerDown: (event) => {
405
+ props.onPointerDown?.(event), isPointerDownRef.current = !0;
406
+ },
407
+ onPointerUp: (0, import_web.composeEventHandlers)(props.onPointerUp, (event) => {
408
+ import_web.isWeb && (isPointerDownRef.current || event.currentTarget?.click());
409
+ }),
410
+ ...import_web.isWeb ? {
411
+ onKeyDown: (0, import_web.composeEventHandlers)(props.onKeyDown, (event) => {
412
+ const isTypingAhead = contentContext.searchRef.current !== "";
413
+ disabled || isTypingAhead && event.key === " " || SELECTION_KEYS.includes(event.key) && (event.currentTarget?.click(), event.preventDefault());
414
+ })
415
+ } : {},
416
+ children: content
417
+ }
418
+ );
419
+ }), MenuItemImpl = React.forwardRef((props, forwardedRef) => {
420
+ const {
421
+ scope = MENU_CONTEXT,
422
+ disabled = !1,
423
+ textValue,
424
+ unstyled = process.env.TAMAGUI_HEADLESS === "1",
425
+ ...itemProps
426
+ } = props, contentContext = useMenuContentContext(scope), ref = React.useRef(null), composedRefs = (0, import_web.useComposedRefs)(forwardedRef, ref), [isFocused, setIsFocused] = React.useState(!1), [textContent, setTextContent] = React.useState("");
427
+ return import_web.isWeb && React.useEffect(() => {
428
+ const menuItem = ref.current;
429
+ menuItem && setTextContent((menuItem.textContent ?? "").trim());
430
+ }, [itemProps.children]), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
431
+ Collection.ItemSlot,
432
+ {
433
+ scope,
434
+ disabled,
435
+ textValue: textValue ?? textContent,
436
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
437
+ import_roving_focus.RovingFocusGroup.Item,
438
+ {
439
+ asChild: !0,
440
+ __scopeRovingFocusGroup: scope,
441
+ focusable: !disabled,
442
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
443
+ _Item,
444
+ {
445
+ unstyled,
446
+ componentName: ITEM_NAME,
447
+ role: "menuitem",
448
+ "data-highlighted": isFocused ? "" : void 0,
449
+ "aria-disabled": disabled || void 0,
450
+ "data-disabled": disabled ? "" : void 0,
451
+ ...itemProps,
452
+ ref: composedRefs,
453
+ onPointerMove: (0, import_web.composeEventHandlers)(props.onPointerMove, (event) => {
454
+ event.pointerType === "mouse" && (disabled ? contentContext.onItemLeave(event) : (contentContext.onItemEnter(event), event.defaultPrevented || event.currentTarget.focus({ preventScroll: !0, focusVisible: !1 })));
455
+ }),
456
+ onPointerLeave: (0, import_web.composeEventHandlers)(props.onPointerLeave, (event) => {
457
+ contentContext.onItemLeave(event);
458
+ }),
459
+ onFocus: (0, import_web.composeEventHandlers)(props.onFocus, () => setIsFocused(!0)),
460
+ onBlur: (0, import_web.composeEventHandlers)(props.onBlur, () => setIsFocused(!1))
461
+ }
462
+ )
463
+ }
464
+ )
465
+ }
466
+ );
467
+ });
468
+ MenuItem.displayName = ITEM_NAME;
469
+ const ITEM_TITLE_NAME = "MenuItemTitle", MenuItemTitle = _Title.styleable((props, forwardedRef) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(_Title, { ...props, ref: forwardedRef }));
470
+ MenuItemTitle.displayName = ITEM_TITLE_NAME;
471
+ const ITEM_SUB_TITLE_NAME = "MenuItemSubTitle", MenuItemSubTitle = _SubTitle.styleable(
472
+ (props, forwardedRef) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(_SubTitle, { ...props, ref: forwardedRef })
473
+ );
474
+ MenuItemSubTitle.displayName = ITEM_SUB_TITLE_NAME;
475
+ const ITEM_IMAGE = "MenuItemImage", MenuItemImage = React.forwardRef((props, forwardedRef) => {
476
+ const {
477
+ // @ts-ignore - native menu ios config
478
+ ios,
479
+ // @ts-ignore
480
+ androidIconName,
481
+ // @ts-ignore
482
+ iosIconName,
483
+ ...rest
484
+ } = props;
485
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(_Image, { ...rest, ref: forwardedRef });
486
+ });
487
+ MenuItemImage.displayName = ITEM_IMAGE;
488
+ const ITEM_ICON = "MenuItemIcon", MenuItemIcon = _Icon.styleable((props, forwardedRef) => {
489
+ const {
490
+ // @ts-ignore
491
+ ios,
492
+ // @ts-ignore
493
+ android,
494
+ // @ts-ignore
495
+ androidIconName,
496
+ // @ts-ignore
497
+ iosIconName,
498
+ ...rest
499
+ } = props;
500
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(_Icon, { ...rest, ref: forwardedRef });
501
+ });
502
+ MenuItemIcon.displayName = ITEM_ICON;
503
+ const CHECKBOX_ITEM_NAME = "MenuCheckboxItem", MenuCheckboxItem = _Item.styleable(
504
+ (props, forwardedRef) => {
505
+ const {
506
+ checked = !1,
507
+ onCheckedChange,
508
+ scope = MENU_CONTEXT,
509
+ // filter out native-only props
510
+ // @ts-ignore - native menu value state
511
+ value,
512
+ // @ts-ignore - native menu value change handler
513
+ onValueChange,
514
+ ...checkboxItemProps
515
+ } = props;
516
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ItemIndicatorProvider, { scope, checked, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
517
+ MenuItem,
518
+ {
519
+ componentName: CHECKBOX_ITEM_NAME,
520
+ role: import_web.isWeb ? "menuitemcheckbox" : "menuitem",
521
+ "aria-checked": isIndeterminate(checked) ? "mixed" : checked,
522
+ ...checkboxItemProps,
523
+ scope,
524
+ ref: forwardedRef,
525
+ "data-state": getCheckedState(checked),
526
+ onSelect: (0, import_web.composeEventHandlers)(
527
+ checkboxItemProps.onSelect,
528
+ () => onCheckedChange?.(isIndeterminate(checked) ? !0 : !checked),
529
+ { checkDefaultPrevented: !1 }
530
+ )
531
+ }
532
+ ) });
533
+ }
534
+ );
535
+ MenuCheckboxItem.displayName = CHECKBOX_ITEM_NAME;
536
+ const RADIO_GROUP_NAME = "MenuRadioGroup", { Provider: RadioGroupProvider, useStyledContext: useRadioGroupContext } = (0, import_web.createStyledContext)(), MenuRadioGroup = _MenuGroup.styleable(
537
+ (props, forwardedRef) => {
538
+ const { value, onValueChange, scope = MENU_CONTEXT, ...groupProps } = props, handleValueChange = (0, import_use_callback_ref.useCallbackRef)(onValueChange);
539
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RadioGroupProvider, { scope, value, onValueChange: handleValueChange, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
540
+ _MenuGroup,
541
+ {
542
+ componentName: RADIO_GROUP_NAME,
543
+ ...groupProps,
544
+ ref: forwardedRef
545
+ }
546
+ ) });
547
+ }
548
+ );
549
+ MenuRadioGroup.displayName = RADIO_GROUP_NAME;
550
+ const RADIO_ITEM_NAME = "MenuRadioItem", MenuRadioItem = _Item.styleable(
551
+ (props, forwardedRef) => {
552
+ const { value, scope = MENU_CONTEXT, ...radioItemProps } = props, context = useRadioGroupContext(scope), checked = value === context.value;
553
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ItemIndicatorProvider, { scope, checked, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
554
+ MenuItem,
555
+ {
556
+ componentName: RADIO_ITEM_NAME,
557
+ ...radioItemProps,
558
+ scope,
559
+ "aria-checked": checked,
560
+ ref: forwardedRef,
561
+ role: import_web.isWeb ? "menuitemradio" : "menuitem",
562
+ "data-state": getCheckedState(checked),
563
+ onSelect: (0, import_web.composeEventHandlers)(
564
+ radioItemProps.onSelect,
565
+ () => context.onValueChange?.(value),
566
+ { checkDefaultPrevented: !1 }
567
+ )
568
+ }
569
+ ) });
570
+ }
571
+ );
572
+ MenuRadioItem.displayName = RADIO_ITEM_NAME;
573
+ const ITEM_INDICATOR_NAME = "MenuItemIndicator", { Provider: ItemIndicatorProvider, useStyledContext: useItemIndicatorContext } = (0, import_web.createStyledContext)(), MenuItemIndicator = _Indicator.styleable(
574
+ (props, forwardedRef) => {
575
+ const { scope = MENU_CONTEXT, forceMount, ...itemIndicatorProps } = props, indicatorContext = useItemIndicatorContext(scope);
576
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_animate_presence.AnimatePresence, { children: forceMount || isIndeterminate(indicatorContext.checked) || indicatorContext.checked === !0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
577
+ _Indicator,
578
+ {
579
+ componentName: ITEM_INDICATOR_NAME,
580
+ render: "span",
581
+ ...itemIndicatorProps,
582
+ ref: forwardedRef,
583
+ "data-state": getCheckedState(indicatorContext.checked)
584
+ }
585
+ ) : null });
586
+ }
587
+ );
588
+ MenuItemIndicator.displayName = ITEM_INDICATOR_NAME;
589
+ const MenuArrow = React.forwardRef(
590
+ function(props, forwardedRef) {
591
+ const {
592
+ scope = MENU_CONTEXT,
593
+ unstyled = process.env.TAMAGUI_HEADLESS === "1",
594
+ ...rest
595
+ } = props;
596
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
597
+ PopperPrimitive.PopperArrow,
598
+ {
599
+ scope,
600
+ componentName: "PopperArrow",
601
+ unstyled,
602
+ ...!unstyled && {
603
+ backgroundColor: "$background"
604
+ },
605
+ ...rest,
606
+ ref: forwardedRef
607
+ }
608
+ );
609
+ }
610
+ ), SUB_NAME = "MenuSub", { Provider: MenuSubProvider, useStyledContext: useMenuSubContext } = (0, import_web.createStyledContext)(), MenuSub = (props) => {
611
+ const isTouchDevice = (0, import_web.useIsTouchDevice)(), { scope = MENU_CONTEXT } = props, rootContext = useMenuRootContext(scope), parentSide = PopperPrimitive.usePopperContext(scope).placement?.split("-")[0], isNestedSubmenu = parentSide === "left" || parentSide === "right", defaultPlacement = isTouchDevice ? "bottom" : isNestedSubmenu ? `${parentSide}-start` : rootContext.dir === "rtl" ? "left-start" : "right-start", {
612
+ children,
613
+ open = !1,
614
+ onOpenChange,
615
+ allowFlip: allowFlipProp = { padding: 10 },
616
+ stayInFrame = { padding: 10 },
617
+ placement = defaultPlacement,
618
+ ...rest
619
+ } = props, allowFlip = React.useMemo(() => {
620
+ if (!isNestedSubmenu || typeof allowFlipProp == "boolean" || allowFlipProp.fallbackPlacements) return allowFlipProp;
621
+ const side = placement.split("-")[0], align = placement.split("-")[1] || "start", otherAlign = align === "start" ? "end" : "start";
622
+ if (side === "left" || side === "right") {
623
+ const oppositeSide = side === "right" ? "left" : "right";
624
+ return {
625
+ ...typeof allowFlipProp == "object" ? allowFlipProp : {},
626
+ fallbackPlacements: [
627
+ `${side}-${otherAlign}`,
628
+ `${oppositeSide}-${align}`,
629
+ `${oppositeSide}-${otherAlign}`
630
+ ]
631
+ };
632
+ }
633
+ return allowFlipProp;
634
+ }, [isNestedSubmenu, allowFlipProp, placement]), parentMenuContext = useMenuContext(scope), [trigger, setTrigger] = React.useState(null), [content, setContent] = React.useState(null), handleOpenChange = (0, import_use_callback_ref.useCallbackRef)(onOpenChange);
635
+ return React.useEffect(() => (parentMenuContext.open === !1 && handleOpenChange(!1), () => handleOpenChange(!1)), [parentMenuContext.open, handleOpenChange]), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
636
+ PopperPrimitive.Popper,
637
+ {
638
+ open,
639
+ placement,
640
+ allowFlip,
641
+ stayInFrame,
642
+ ...rest,
643
+ scope,
644
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
645
+ MenuProvider,
646
+ {
647
+ scope,
648
+ open,
649
+ onOpenChange: handleOpenChange,
650
+ content,
651
+ onContentChange: setContent,
652
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
653
+ MenuSubProvider,
654
+ {
655
+ scope,
656
+ contentId: (0, import_react.useId)(),
657
+ triggerId: (0, import_react.useId)(),
658
+ trigger,
659
+ onTriggerChange: setTrigger,
660
+ children
661
+ }
662
+ )
663
+ }
664
+ )
665
+ }
666
+ );
667
+ };
668
+ MenuSub.displayName = SUB_NAME;
669
+ const SUB_TRIGGER_NAME = "MenuSubTrigger", MenuSubTrigger = React.forwardRef((props, forwardedRef) => {
670
+ const scope = props.scope || MENU_CONTEXT, context = useMenuContext(scope), rootContext = useMenuRootContext(scope), subContext = useMenuSubContext(scope), contentContext = useMenuContentContext(scope), popperContext = PopperPrimitive.usePopperContext(scope), openTimerRef = React.useRef(null), { pointerGraceTimerRef, onPointerGraceIntentChange } = contentContext, effectiveDir = rootContext.dir, clearOpenTimer = React.useCallback(() => {
671
+ openTimerRef.current && window.clearTimeout(openTimerRef.current), openTimerRef.current = null;
672
+ }, []);
673
+ return React.useEffect(() => clearOpenTimer, [clearOpenTimer]), React.useEffect(() => {
674
+ const pointerGraceTimer = pointerGraceTimerRef.current;
675
+ return () => {
676
+ window.clearTimeout(pointerGraceTimer), onPointerGraceIntentChange(null);
677
+ };
678
+ }, [pointerGraceTimerRef, onPointerGraceIntentChange]), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuAnchor, { componentName: SUB_TRIGGER_NAME, asChild: "except-style", scope, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
679
+ MenuItemImpl,
680
+ {
681
+ id: subContext.triggerId,
682
+ "aria-haspopup": "menu",
683
+ "aria-expanded": context.open,
684
+ "aria-controls": subContext.contentId,
685
+ "data-state": getOpenState(context.open),
686
+ outlineStyle: "none",
687
+ ...props,
688
+ ref: (0, import_web.composeRefs)(forwardedRef, subContext.onTriggerChange),
689
+ onPress: (event) => {
690
+ props.onPress?.(event), !(props.disabled || event.defaultPrevented) && (import_web.isWeb && event.currentTarget.focus(), context.open || context.onOpenChange(!0));
691
+ },
692
+ onPointerMove: (0, import_web.composeEventHandlers)(
693
+ props.onPointerMove,
694
+ // @ts-ignore
695
+ whenMouse((event) => {
696
+ contentContext.onItemEnter(event), !event.defaultPrevented && !props.disabled && !context.open && !openTimerRef.current && (contentContext.onPointerGraceIntentChange(null), openTimerRef.current = window.setTimeout(() => {
697
+ context.onOpenChange(!0), clearOpenTimer();
698
+ }, 100));
699
+ })
700
+ ),
701
+ onPointerLeave: (0, import_web.composeEventHandlers)(props.onPointerLeave, (eventIn) => {
702
+ const event = eventIn;
703
+ clearOpenTimer();
704
+ const contentRect = context.content?.getBoundingClientRect();
705
+ if (contentRect) {
706
+ const contentEl = context.content, side = (contentEl?.dataset?.side ? contentEl : contentEl?.querySelector("[data-side]"))?.dataset?.side || "right", rightSide = side === "right", bleed = rightSide ? -5 : 5, contentNearEdge = contentRect[rightSide ? "left" : "right"], contentFarEdge = contentRect[rightSide ? "right" : "left"], polygon = {
707
+ area: [
708
+ // Apply a bleed on clientX to ensure that our exit point is
709
+ // consistently within polygon bounds
710
+ { x: event.clientX + bleed, y: event.clientY },
711
+ { x: contentNearEdge, y: contentRect.top },
712
+ { x: contentFarEdge, y: contentRect.top },
713
+ { x: contentFarEdge, y: contentRect.bottom },
714
+ { x: contentNearEdge, y: contentRect.bottom }
715
+ ],
716
+ side
717
+ };
718
+ contentContext.onPointerGraceIntentChange(polygon), window.clearTimeout(pointerGraceTimerRef.current), pointerGraceTimerRef.current = window.setTimeout(
719
+ () => contentContext.onPointerGraceIntentChange(null),
720
+ 300
721
+ );
722
+ } else if (import_web.isWeb && subContext.trigger) {
723
+ const triggerRect = subContext.trigger?.getBoundingClientRect();
724
+ if (triggerRect) {
725
+ const placementSide = popperContext.placement?.split("-")[0], side = placementSide === "left" || placementSide === "right" ? placementSide : rootContext.dir === "rtl" ? "left" : "right", rightSide = side === "right", bleed = rightSide ? -5 : 5, nearEdge = rightSide ? triggerRect.right + 4 : triggerRect.left - 4, farEdge = rightSide ? nearEdge + 200 : nearEdge - 200, polygon = {
726
+ area: [
727
+ { x: event.clientX + bleed, y: event.clientY },
728
+ { x: nearEdge, y: triggerRect.top - 50 },
729
+ { x: farEdge, y: triggerRect.top - 50 },
730
+ { x: farEdge, y: triggerRect.bottom + 50 },
731
+ { x: nearEdge, y: triggerRect.bottom + 50 }
732
+ ],
733
+ side
734
+ };
735
+ contentContext.onPointerGraceIntentChange(polygon), window.clearTimeout(pointerGraceTimerRef.current), pointerGraceTimerRef.current = window.setTimeout(
736
+ () => contentContext.onPointerGraceIntentChange(null),
737
+ 300
738
+ );
739
+ }
740
+ } else {
741
+ if (contentContext.onTriggerLeave(event), event.defaultPrevented) return;
742
+ contentContext.onPointerGraceIntentChange(null);
743
+ }
744
+ }),
745
+ ...import_web.isWeb ? {
746
+ onKeyDown: (0, import_web.composeEventHandlers)(props.onKeyDown, (event) => {
747
+ const isTypingAhead = contentContext.searchRef.current !== "";
748
+ if (props.disabled || isTypingAhead && event.key === " ") return;
749
+ if (SUB_OPEN_KEYS[effectiveDir].includes(event.key)) {
750
+ if (context.open && context.content) {
751
+ const firstItem = context.content.querySelector?.(
752
+ '[role="menuitem"]:not([data-disabled])'
753
+ );
754
+ if (firstItem) {
755
+ firstItem.focus({ focusVisible: !0 }), event.preventDefault();
756
+ return;
757
+ }
758
+ }
759
+ const triggerEl = event.currentTarget;
760
+ popperContext.refs?.setReference(triggerEl), context.onOpenChange(!0), requestAnimationFrame(() => {
761
+ popperContext.update?.();
762
+ }), context.content?.focus({ focusVisible: !0 }), event.preventDefault();
763
+ }
764
+ })
765
+ } : null
766
+ }
767
+ ) });
768
+ });
769
+ MenuSubTrigger.displayName = SUB_TRIGGER_NAME;
770
+ const SUB_CONTENT_NAME = "MenuSubContent", MenuSubContent = (0, import_web.styled)(PopperPrimitive.PopperContentFrame, {
771
+ name: SUB_CONTENT_NAME
772
+ }).styleable(
773
+ (props, forwardedRef) => {
774
+ const scope = props.scope || MENU_CONTEXT, portalContext = usePortalContext(scope), { forceMount = portalContext.forceMount, ...subContentProps } = props, context = useMenuContext(scope), rootContext = useMenuRootContext(scope), subContext = useMenuSubContext(scope), popperContext = PopperPrimitive.usePopperContext(scope), ref = React.useRef(null), composedRefs = (0, import_web.useComposedRefs)(forwardedRef, ref), placementSide = popperContext.placement?.split("-")[0], dataSide = placementSide === "left" || placementSide === "right" ? placementSide : rootContext.dir === "rtl" ? "left" : "right", effectiveDir = rootContext.dir;
775
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.Provider, { scope, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.Slot, { scope, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
776
+ MenuContentImpl,
777
+ {
778
+ id: subContext.contentId,
779
+ "aria-labelledby": subContext.triggerId,
780
+ ...subContentProps,
781
+ ref: composedRefs,
782
+ "data-side": dataSide,
783
+ disableOutsidePointerEvents: !1,
784
+ disableOutsideScroll: !1,
785
+ trapFocus: !1,
786
+ onOpenAutoFocus: (event) => {
787
+ if (rootContext.isUsingKeyboardRef.current) {
788
+ const root = ref.current;
789
+ (root?.querySelector?.(
790
+ "[data-tamagui-menu-content]"
791
+ ) || root)?.focus({ preventScroll: !0 });
792
+ }
793
+ event.preventDefault();
794
+ },
795
+ onCloseAutoFocus: (event) => event.preventDefault(),
796
+ onFocusOutside: (0, import_web.composeEventHandlers)(props.onFocusOutside, (event) => {
797
+ event.target !== subContext.trigger && context.onOpenChange(!1);
798
+ }),
799
+ onEscapeKeyDown: (0, import_web.composeEventHandlers)(props.onEscapeKeyDown, (event) => {
800
+ context.onOpenChange(!1), subContext.trigger?.focus({ focusVisible: !0 }), event.preventDefault();
801
+ }),
802
+ ...import_web.isWeb ? {
803
+ onKeyDown: (0, import_web.composeEventHandlers)(props.onKeyDown, (event) => {
804
+ const isKeyDownInside = event.currentTarget.contains(
805
+ event.target
806
+ ), isCloseKey = SUB_CLOSE_KEYS[effectiveDir].includes(event.key);
807
+ isKeyDownInside && isCloseKey && (context.onOpenChange(!1), subContext.trigger?.focus({ focusVisible: !0 }), event.preventDefault());
808
+ })
809
+ } : null
810
+ }
811
+ ) }) });
812
+ }
813
+ );
814
+ MenuSubContent.displayName = SUB_CONTENT_NAME;
815
+ const Anchor = MenuAnchor, Portal = MenuPortal, Content = MenuContent, Group = _MenuGroup.styleable((props, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(_MenuGroup, { ...props, ref }));
816
+ Group.displayName = "MenuGroup";
817
+ const Label = _Label.styleable((props, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(_Label, { ...props, ref }));
818
+ Label.displayName = "MenuLabel";
819
+ const Item = MenuItem, CheckboxItem = MenuCheckboxItem, RadioGroup = MenuRadioGroup, RadioItem = MenuRadioItem, ItemIndicator = MenuItemIndicator, Separator = _Separator.styleable((props, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(_Separator, { ...props, ref }));
820
+ return Separator.displayName = "MenuSeparator", {
821
+ Menu: (0, import_web.withStaticProperties)(MenuComp, {
822
+ Anchor,
823
+ Portal,
824
+ Content,
825
+ Group,
826
+ Label,
827
+ Item,
828
+ CheckboxItem,
829
+ RadioGroup,
830
+ RadioItem,
831
+ ItemIndicator,
832
+ Separator,
833
+ Arrow: MenuArrow,
834
+ Sub: MenuSub,
835
+ SubTrigger: MenuSubTrigger,
836
+ SubContent: MenuSubContent,
837
+ ItemTitle: MenuItemTitle,
838
+ ItemSubtitle: MenuItemSubTitle,
839
+ ItemImage: MenuItemImage,
840
+ ItemIcon: MenuItemIcon
841
+ })
842
+ };
843
+ }
844
+ function getOpenState(open) {
845
+ return open ? "open" : "closed";
846
+ }
847
+ function isIndeterminate(checked) {
848
+ return checked === "indeterminate";
849
+ }
850
+ function getCheckedState(checked) {
851
+ return isIndeterminate(checked) ? "indeterminate" : checked ? "checked" : "unchecked";
852
+ }
853
+ function focusFirst(candidates, options) {
854
+ const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;
855
+ for (const candidate of candidates)
856
+ if (candidate === PREVIOUSLY_FOCUSED_ELEMENT || (candidate.focus({ preventScroll: !0, focusVisible: options?.focusVisible }), document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT)) return;
857
+ }
858
+ function wrapArray(array, startIndex) {
859
+ return array.map((_, index) => array[(startIndex + index) % array.length]);
860
+ }
861
+ function getNextMatch(values, search, currentMatch) {
862
+ const normalizedSearch = search.length > 1 && Array.from(search).every((char) => char === search[0]) ? search[0] : search, currentMatchIndex = currentMatch ? values.indexOf(currentMatch) : -1;
863
+ let wrappedValues = wrapArray(values, Math.max(currentMatchIndex, 0));
864
+ normalizedSearch.length === 1 && (wrappedValues = wrappedValues.filter((v) => v !== currentMatch));
865
+ const nextMatch = wrappedValues.find(
866
+ (value) => value.toLowerCase().startsWith(normalizedSearch.toLowerCase())
867
+ );
868
+ return nextMatch !== currentMatch ? nextMatch : void 0;
869
+ }
870
+ function isPointInPolygon(point, polygon) {
871
+ const { x, y } = point;
872
+ let inside = !1;
873
+ for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
874
+ const xi = polygon[i].x, yi = polygon[i].y, xj = polygon[j].x, yj = polygon[j].y;
875
+ yi > y != yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi && (inside = !inside);
876
+ }
877
+ return inside;
878
+ }
879
+ function isPointerInGraceArea(event, area) {
880
+ if (!area) return !1;
881
+ const cursorPos = { x: event.clientX, y: event.clientY };
882
+ return isPointInPolygon(cursorPos, area);
883
+ }
884
+ //# sourceMappingURL=createBaseMenu.js.map