@tamagui/create-menu 2.0.0-rc.4 → 2.0.0-rc.40

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 (149) hide show
  1. package/dist/cjs/MenuPredefined.cjs +159 -157
  2. package/dist/cjs/MenuPredefined.native.js +159 -157
  3. package/dist/cjs/MenuPredefined.native.js.map +1 -1
  4. package/dist/cjs/createBaseMenu.cjs +1144 -933
  5. package/dist/cjs/createBaseMenu.native.js +1266 -1100
  6. package/dist/cjs/createBaseMenu.native.js.map +1 -1
  7. package/dist/cjs/createNativeMenu/createNativeMenu.cjs +282 -159
  8. package/dist/cjs/createNativeMenu/createNativeMenu.native.js +390 -268
  9. package/dist/cjs/createNativeMenu/createNativeMenu.native.js.map +1 -1
  10. package/dist/cjs/createNativeMenu/createNativeMenuTypes.cjs +7 -5
  11. package/dist/cjs/createNativeMenu/createNativeMenuTypes.native.js +7 -5
  12. package/dist/cjs/createNativeMenu/createNativeMenuTypes.native.js.map +1 -1
  13. package/dist/cjs/createNativeMenu/utils.cjs +85 -42
  14. package/dist/cjs/createNativeMenu/utils.native.js +83 -58
  15. package/dist/cjs/createNativeMenu/utils.native.js.map +1 -1
  16. package/dist/cjs/createNativeMenu/withNativeMenu.cjs +27 -17
  17. package/dist/cjs/createNativeMenu/withNativeMenu.native.js +22 -14
  18. package/dist/cjs/createNativeMenu/withNativeMenu.native.js.map +1 -1
  19. package/dist/cjs/index.cjs +15 -12
  20. package/dist/cjs/index.native.js +15 -12
  21. package/dist/cjs/index.native.js.map +1 -1
  22. package/dist/esm/MenuPredefined.mjs +144 -144
  23. package/dist/esm/MenuPredefined.mjs.map +1 -1
  24. package/dist/esm/MenuPredefined.native.js +144 -144
  25. package/dist/esm/MenuPredefined.native.js.map +1 -1
  26. package/dist/esm/createBaseMenu.mjs +1104 -895
  27. package/dist/esm/createBaseMenu.mjs.map +1 -1
  28. package/dist/esm/createBaseMenu.native.js +1226 -1062
  29. package/dist/esm/createBaseMenu.native.js.map +1 -1
  30. package/dist/esm/createNativeMenu/createNativeMenu.mjs +255 -134
  31. package/dist/esm/createNativeMenu/createNativeMenu.mjs.map +1 -1
  32. package/dist/esm/createNativeMenu/createNativeMenu.native.js +336 -216
  33. package/dist/esm/createNativeMenu/createNativeMenu.native.js.map +1 -1
  34. package/dist/esm/createNativeMenu/utils.mjs +58 -17
  35. package/dist/esm/createNativeMenu/utils.mjs.map +1 -1
  36. package/dist/esm/createNativeMenu/utils.native.js +57 -34
  37. package/dist/esm/createNativeMenu/utils.native.js.map +1 -1
  38. package/dist/esm/createNativeMenu/withNativeMenu.mjs +13 -5
  39. package/dist/esm/createNativeMenu/withNativeMenu.mjs.map +1 -1
  40. package/dist/esm/createNativeMenu/withNativeMenu.native.js +8 -2
  41. package/dist/esm/createNativeMenu/withNativeMenu.native.js.map +1 -1
  42. package/dist/esm/index.js +5 -6
  43. package/dist/esm/index.js.map +1 -6
  44. package/dist/esm/index.mjs +2 -1
  45. package/dist/esm/index.mjs.map +1 -1
  46. package/dist/esm/index.native.js +2 -1
  47. package/dist/esm/index.native.js.map +1 -1
  48. package/dist/jsx/MenuPredefined.mjs +144 -144
  49. package/dist/jsx/MenuPredefined.mjs.map +1 -1
  50. package/dist/jsx/MenuPredefined.native.js +159 -157
  51. package/dist/jsx/MenuPredefined.native.js.map +1 -1
  52. package/dist/jsx/createBaseMenu.mjs +1104 -895
  53. package/dist/jsx/createBaseMenu.mjs.map +1 -1
  54. package/dist/jsx/createBaseMenu.native.js +1266 -1100
  55. package/dist/jsx/createBaseMenu.native.js.map +1 -1
  56. package/dist/jsx/createNativeMenu/createNativeMenu.mjs +255 -134
  57. package/dist/jsx/createNativeMenu/createNativeMenu.mjs.map +1 -1
  58. package/dist/jsx/createNativeMenu/createNativeMenu.native.js +390 -268
  59. package/dist/jsx/createNativeMenu/createNativeMenu.native.js.map +1 -1
  60. package/dist/jsx/createNativeMenu/createNativeMenuTypes.native.js +7 -5
  61. package/dist/jsx/createNativeMenu/utils.mjs +58 -17
  62. package/dist/jsx/createNativeMenu/utils.mjs.map +1 -1
  63. package/dist/jsx/createNativeMenu/utils.native.js +83 -58
  64. package/dist/jsx/createNativeMenu/utils.native.js.map +1 -1
  65. package/dist/jsx/createNativeMenu/withNativeMenu.mjs +13 -5
  66. package/dist/jsx/createNativeMenu/withNativeMenu.mjs.map +1 -1
  67. package/dist/jsx/createNativeMenu/withNativeMenu.native.js +22 -14
  68. package/dist/jsx/createNativeMenu/withNativeMenu.native.js.map +1 -1
  69. package/dist/jsx/index.js +5 -6
  70. package/dist/jsx/index.js.map +1 -6
  71. package/dist/jsx/index.mjs +2 -1
  72. package/dist/jsx/index.mjs.map +1 -1
  73. package/dist/jsx/index.native.js +15 -12
  74. package/dist/jsx/index.native.js.map +1 -1
  75. package/package.json +25 -27
  76. package/src/MenuPredefined.tsx +1 -1
  77. package/src/createBaseMenu.tsx +359 -271
  78. package/src/createNativeMenu/createNativeMenu.tsx +383 -222
  79. package/src/createNativeMenu/createNativeMenuTypes.ts +20 -20
  80. package/src/createNativeMenu/withNativeMenu.tsx +5 -3
  81. package/src/index.tsx +3 -5
  82. package/types/createBaseMenu.d.ts +121 -35
  83. package/types/createBaseMenu.d.ts.map +1 -1
  84. package/types/createNativeMenu/createNativeMenu.d.ts +21 -21
  85. package/types/createNativeMenu/createNativeMenu.d.ts.map +1 -1
  86. package/types/createNativeMenu/createNativeMenuTypes.d.ts +20 -20
  87. package/types/createNativeMenu/createNativeMenuTypes.d.ts.map +1 -1
  88. package/types/createNativeMenu/withNativeMenu.d.ts +3 -3
  89. package/types/createNativeMenu/withNativeMenu.d.ts.map +1 -1
  90. package/types/index.d.ts +3 -2
  91. package/types/index.d.ts.map +1 -1
  92. package/dist/cjs/MenuPredefined.js +0 -168
  93. package/dist/cjs/MenuPredefined.js.map +0 -6
  94. package/dist/cjs/createBaseMenu.js +0 -832
  95. package/dist/cjs/createBaseMenu.js.map +0 -6
  96. package/dist/cjs/createNativeMenu/createNativeMenu.js +0 -177
  97. package/dist/cjs/createNativeMenu/createNativeMenu.js.map +0 -6
  98. package/dist/cjs/createNativeMenu/createNativeMenuTypes.js +0 -14
  99. package/dist/cjs/createNativeMenu/createNativeMenuTypes.js.map +0 -6
  100. package/dist/cjs/createNativeMenu/index.cjs +0 -19
  101. package/dist/cjs/createNativeMenu/index.js +0 -16
  102. package/dist/cjs/createNativeMenu/index.js.map +0 -6
  103. package/dist/cjs/createNativeMenu/index.native.js +0 -22
  104. package/dist/cjs/createNativeMenu/index.native.js.map +0 -1
  105. package/dist/cjs/createNativeMenu/utils.js +0 -66
  106. package/dist/cjs/createNativeMenu/utils.js.map +0 -6
  107. package/dist/cjs/createNativeMenu/withNativeMenu.js +0 -30
  108. package/dist/cjs/createNativeMenu/withNativeMenu.js.map +0 -6
  109. package/dist/cjs/index.js +0 -23
  110. package/dist/cjs/index.js.map +0 -6
  111. package/dist/esm/MenuPredefined.js +0 -154
  112. package/dist/esm/MenuPredefined.js.map +0 -6
  113. package/dist/esm/createBaseMenu.js +0 -838
  114. package/dist/esm/createBaseMenu.js.map +0 -6
  115. package/dist/esm/createNativeMenu/createNativeMenu.js +0 -156
  116. package/dist/esm/createNativeMenu/createNativeMenu.js.map +0 -6
  117. package/dist/esm/createNativeMenu/createNativeMenuTypes.js +0 -1
  118. package/dist/esm/createNativeMenu/createNativeMenuTypes.js.map +0 -6
  119. package/dist/esm/createNativeMenu/index.js +0 -3
  120. package/dist/esm/createNativeMenu/index.js.map +0 -6
  121. package/dist/esm/createNativeMenu/index.mjs +0 -3
  122. package/dist/esm/createNativeMenu/index.mjs.map +0 -1
  123. package/dist/esm/createNativeMenu/index.native.js +0 -3
  124. package/dist/esm/createNativeMenu/index.native.js.map +0 -1
  125. package/dist/esm/createNativeMenu/utils.js +0 -47
  126. package/dist/esm/createNativeMenu/utils.js.map +0 -6
  127. package/dist/esm/createNativeMenu/withNativeMenu.js +0 -15
  128. package/dist/esm/createNativeMenu/withNativeMenu.js.map +0 -6
  129. package/dist/jsx/MenuPredefined.js +0 -154
  130. package/dist/jsx/MenuPredefined.js.map +0 -6
  131. package/dist/jsx/createBaseMenu.js +0 -838
  132. package/dist/jsx/createBaseMenu.js.map +0 -6
  133. package/dist/jsx/createNativeMenu/createNativeMenu.js +0 -156
  134. package/dist/jsx/createNativeMenu/createNativeMenu.js.map +0 -6
  135. package/dist/jsx/createNativeMenu/createNativeMenuTypes.js +0 -1
  136. package/dist/jsx/createNativeMenu/createNativeMenuTypes.js.map +0 -6
  137. package/dist/jsx/createNativeMenu/index.js +0 -3
  138. package/dist/jsx/createNativeMenu/index.js.map +0 -6
  139. package/dist/jsx/createNativeMenu/index.mjs +0 -3
  140. package/dist/jsx/createNativeMenu/index.mjs.map +0 -1
  141. package/dist/jsx/createNativeMenu/index.native.js +0 -22
  142. package/dist/jsx/createNativeMenu/index.native.js.map +0 -1
  143. package/dist/jsx/createNativeMenu/utils.js +0 -47
  144. package/dist/jsx/createNativeMenu/utils.js.map +0 -6
  145. package/dist/jsx/createNativeMenu/withNativeMenu.js +0 -15
  146. package/dist/jsx/createNativeMenu/withNativeMenu.js.map +0 -6
  147. package/src/createNativeMenu/index.tsx +0 -7
  148. package/types/createNativeMenu/index.d.ts +0 -4
  149. package/types/createNativeMenu/index.d.ts.map +0 -1
@@ -10,7 +10,7 @@ import { RemoveScroll } from "@tamagui/remove-scroll";
10
10
  import { RovingFocusGroup } from "@tamagui/roving-focus";
11
11
  import { useCallbackRef } from "@tamagui/use-callback-ref";
12
12
  import { useDirection } from "@tamagui/use-direction";
13
- import { composeEventHandlers, composeRefs, createStyledContext, isWeb, Text, Theme, useComposedRefs, useThemeName, View, withStaticProperties } from "@tamagui/web";
13
+ import { composeEventHandlers, composeRefs, createStyledContext, isWeb, styled, Text, Theme, useComposedRefs, useIsTouchDevice, useThemeName, View, withStaticProperties } from "@tamagui/web";
14
14
  import * as React from "react";
15
15
  import { useId } from "react";
16
16
  import { MenuPredefined } from "./MenuPredefined.mjs";
@@ -18,29 +18,29 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
18
18
  function whenMouse(handler) {
19
19
  return event => event.pointerType === "mouse" ? handler(event) : void 0;
20
20
  }
21
- const SELECTION_KEYS = ["Enter", " "],
22
- FIRST_KEYS = ["ArrowDown", "PageUp", "Home"],
23
- LAST_KEYS = ["ArrowUp", "PageDown", "End"],
24
- FIRST_LAST_KEYS = [...FIRST_KEYS, ...LAST_KEYS],
25
- SUB_OPEN_KEYS = {
26
- ltr: [...SELECTION_KEYS, "ArrowRight"],
27
- rtl: [...SELECTION_KEYS, "ArrowLeft"]
28
- },
29
- SUB_CLOSE_KEYS = {
30
- ltr: ["ArrowLeft"],
31
- rtl: ["ArrowRight"]
32
- },
33
- MENU_NAME = "Menu",
34
- [Collection, useCollection] = createCollection(MENU_NAME),
35
- {
36
- Provider: MenuProvider,
37
- useStyledContext: useMenuContext
38
- } = createStyledContext(),
39
- {
40
- Provider: MenuRootProvider,
41
- useStyledContext: useMenuRootContext
42
- } = createStyledContext(),
43
- MENU_CONTEXT = "MenuContext";
21
+ const SELECTION_KEYS = ["Enter", " "];
22
+ const FIRST_KEYS = ["ArrowDown", "PageUp", "Home"];
23
+ const LAST_KEYS = ["ArrowUp", "PageDown", "End"];
24
+ const FIRST_LAST_KEYS = [...FIRST_KEYS, ...LAST_KEYS];
25
+ const SUB_OPEN_KEYS = {
26
+ ltr: [...SELECTION_KEYS, "ArrowRight"],
27
+ rtl: [...SELECTION_KEYS, "ArrowLeft"]
28
+ };
29
+ const SUB_CLOSE_KEYS = {
30
+ ltr: ["ArrowLeft"],
31
+ rtl: ["ArrowRight"]
32
+ };
33
+ const MENU_NAME = "Menu";
34
+ const [Collection, useCollection] = createCollection(MENU_NAME);
35
+ const {
36
+ Provider: MenuProvider,
37
+ useStyledContext: useMenuContext
38
+ } = createStyledContext();
39
+ const {
40
+ Provider: MenuRootProvider,
41
+ useStyledContext: useMenuRootContext
42
+ } = createStyledContext();
43
+ const MENU_CONTEXT = "MenuContext";
44
44
  function createBaseMenu({
45
45
  Item: _Item = MenuPredefined.MenuItem,
46
46
  Title: _Title = MenuPredefined.Title,
@@ -53,950 +53,1151 @@ function createBaseMenu({
53
53
  Label: _Label = MenuPredefined.MenuLabel
54
54
  }) {
55
55
  const MenuComp = props => {
56
- const {
57
- scope = MENU_CONTEXT,
58
- open = !1,
59
- children,
60
- dir,
61
- onOpenChange,
62
- modal = !0,
63
- ...rest
64
- } = props,
65
- [content, setContent] = React.useState(null),
66
- isUsingKeyboardRef = React.useRef(!1),
67
- handleOpenChange = useCallbackRef(onOpenChange),
68
- direction = useDirection(dir);
69
- return isWeb && React.useEffect(() => {
56
+ const direction = useDirection(props.dir);
57
+ const defaultPlacement = direction === "rtl" ? "bottom-end" : "bottom-start";
58
+ const {
59
+ scope = MENU_CONTEXT,
60
+ open = false,
61
+ children,
62
+ dir,
63
+ onOpenChange,
64
+ modal = true,
65
+ allowFlip = {
66
+ padding: 10
67
+ },
68
+ stayInFrame = {
69
+ padding: 10
70
+ },
71
+ placement = defaultPlacement,
72
+ resize = true,
73
+ offset = 10,
74
+ ...rest
75
+ } = props;
76
+ const [content, setContent] = React.useState(null);
77
+ const isUsingKeyboardRef = React.useRef(false);
78
+ const handleOpenChange = useCallbackRef(onOpenChange);
79
+ if (isWeb) {
80
+ React.useEffect(() => {
70
81
  const handleKeyDown = () => {
71
- isUsingKeyboardRef.current = !0, document.addEventListener("pointerdown", handlePointer, {
72
- capture: !0,
73
- once: !0
74
- }), document.addEventListener("pointermove", handlePointer, {
75
- capture: !0,
76
- once: !0
77
- });
78
- },
79
- handlePointer = () => isUsingKeyboardRef.current = !1;
80
- return document.addEventListener("keydown", handleKeyDown, {
81
- capture: !0
82
- }), () => {
82
+ isUsingKeyboardRef.current = true;
83
+ document.addEventListener("pointerdown", handlePointer, {
84
+ capture: true,
85
+ once: true
86
+ });
87
+ document.addEventListener("pointermove", handlePointer, {
88
+ capture: true,
89
+ once: true
90
+ });
91
+ };
92
+ const handlePointer = () => isUsingKeyboardRef.current = false;
93
+ document.addEventListener("keydown", handleKeyDown, {
94
+ capture: true
95
+ });
96
+ return () => {
83
97
  document.removeEventListener("keydown", handleKeyDown, {
84
- capture: !0
85
- }), document.removeEventListener("pointerdown", handlePointer, {
86
- capture: !0
87
- }), document.removeEventListener("pointermove", handlePointer, {
88
- capture: !0
98
+ capture: true
99
+ });
100
+ document.removeEventListener("pointerdown", handlePointer, {
101
+ capture: true
102
+ });
103
+ document.removeEventListener("pointermove", handlePointer, {
104
+ capture: true
89
105
  });
90
106
  };
91
- }, []), /* @__PURE__ */jsx(PopperPrimitive.Popper, {
107
+ }, []);
108
+ }
109
+ return /* @__PURE__ */jsx(PopperPrimitive.Popper, {
110
+ scope,
111
+ open,
112
+ placement,
113
+ allowFlip,
114
+ stayInFrame,
115
+ resize,
116
+ offset,
117
+ ...rest,
118
+ children: /* @__PURE__ */jsx(MenuProvider, {
92
119
  scope,
93
- ...rest,
94
- children: /* @__PURE__ */jsx(MenuProvider, {
120
+ open,
121
+ onOpenChange: handleOpenChange,
122
+ content,
123
+ onContentChange: setContent,
124
+ children: /* @__PURE__ */jsx(MenuRootProvider, {
95
125
  scope,
96
126
  open,
97
- onOpenChange: handleOpenChange,
98
- content,
99
- onContentChange: setContent,
100
- children: /* @__PURE__ */jsx(MenuRootProvider, {
127
+ onClose: React.useCallback(() => handleOpenChange(false), [handleOpenChange]),
128
+ isUsingKeyboardRef,
129
+ dir: direction,
130
+ modal,
131
+ children: /* @__PURE__ */jsx(MenuSubProvider, {
101
132
  scope,
102
- open,
103
- onClose: React.useCallback(() => handleOpenChange(!1), [handleOpenChange]),
104
- isUsingKeyboardRef,
105
- dir: direction,
106
- modal,
107
- children: /* @__PURE__ */jsx(MenuSubProvider, {
108
- scope,
109
- children
110
- })
133
+ children
111
134
  })
112
135
  })
113
- });
114
- },
115
- RepropagateMenuAndMenuRootProvider = props => {
116
- const {
117
- scope = MENU_CONTEXT,
118
- menuContext,
119
- rootContext,
120
- popperContext,
121
- menuSubContext,
122
- children
123
- } = props;
124
- return /* @__PURE__ */jsx(PopperPrimitive.PopperProvider, {
125
- ...popperContext,
136
+ })
137
+ });
138
+ };
139
+ const RepropagateMenuAndMenuRootProvider = props => {
140
+ const {
141
+ scope = MENU_CONTEXT,
142
+ menuContext,
143
+ rootContext,
144
+ popperContext,
145
+ menuSubContext,
146
+ children
147
+ } = props;
148
+ return /* @__PURE__ */jsx(PopperPrimitive.PopperProvider, {
149
+ ...popperContext,
150
+ scope,
151
+ children: /* @__PURE__ */jsx(MenuProvider, {
126
152
  scope,
127
- children: /* @__PURE__ */jsx(MenuProvider, {
153
+ ...menuContext,
154
+ children: /* @__PURE__ */jsx(MenuRootProvider, {
128
155
  scope,
129
- ...menuContext,
130
- children: /* @__PURE__ */jsx(MenuRootProvider, {
156
+ ...rootContext,
157
+ children: menuSubContext ? /* @__PURE__ */jsx(MenuSubProvider, {
131
158
  scope,
132
- ...rootContext,
133
- children: menuSubContext ? /* @__PURE__ */jsx(MenuSubProvider, {
134
- scope,
135
- ...menuSubContext,
136
- children
137
- }) : children
138
- })
159
+ ...menuSubContext,
160
+ children
161
+ }) : children
139
162
  })
140
- });
141
- };
163
+ })
164
+ });
165
+ };
142
166
  MenuComp.displayName = MENU_NAME;
143
- const ANCHOR_NAME = "MenuAnchor",
144
- MenuAnchor = props => /* @__PURE__ */jsx(PopperPrimitive.PopperAnchor, {
167
+ const ANCHOR_NAME = "MenuAnchor";
168
+ const MenuAnchor = props => {
169
+ return /* @__PURE__ */jsx(PopperPrimitive.PopperAnchor, {
145
170
  scope: MENU_CONTEXT,
146
171
  ...props
147
172
  });
173
+ };
148
174
  MenuAnchor.displayName = ANCHOR_NAME;
149
- const PORTAL_NAME = "MenuPortal",
150
- {
151
- Provider: PortalProvider,
152
- useStyledContext: usePortalContext
153
- } = createStyledContext(void 0, "Portal"),
154
- MenuPortal = props => {
155
- const {
156
- scope = MENU_CONTEXT,
157
- forceMount,
158
- zIndex,
159
- children
160
- } = props,
161
- menuContext = useMenuContext(scope),
162
- rootContext = useMenuRootContext(scope),
163
- popperContext = PopperPrimitive.usePopperContext(scope),
164
- menuSubContext = useMenuSubContext(scope),
165
- themeName = useThemeName(),
166
- themedChildren = /* @__PURE__ */jsx(Theme, {
167
- forceClassName: !0,
168
- name: themeName,
169
- children
170
- }),
171
- content = needsPortalRepropagation() ? /* @__PURE__ */jsx(RepropagateMenuAndMenuRootProvider, {
172
- menuContext,
173
- rootContext,
174
- popperContext,
175
- menuSubContext,
176
- scope,
177
- children: themedChildren
178
- }) : themedChildren,
179
- isPresent = forceMount || rootContext.open && menuContext.open;
180
- return /* @__PURE__ */jsx(Animate, {
181
- type: "presence",
182
- present: isPresent,
183
- children: /* @__PURE__ */jsx(PortalPrimitive, {
184
- children: /* @__PURE__ */jsx(Fragment, {
185
- children: /* @__PURE__ */jsx(PortalProvider, {
186
- scope,
187
- forceMount,
188
- children: /* @__PURE__ */jsxs(View, {
189
- zIndex: zIndex || 100,
175
+ const PORTAL_NAME = "MenuPortal";
176
+ const {
177
+ Provider: PortalProvider,
178
+ useStyledContext: usePortalContext
179
+ } = createStyledContext(void 0, "Portal");
180
+ const MenuPortal = props => {
181
+ const {
182
+ scope = MENU_CONTEXT,
183
+ forceMount,
184
+ zIndex,
185
+ children
186
+ } = props;
187
+ const menuContext = useMenuContext(scope);
188
+ const rootContext = useMenuRootContext(scope);
189
+ const popperContext = PopperPrimitive.usePopperContext(scope);
190
+ const menuSubContext = useMenuSubContext(scope);
191
+ const themeName = useThemeName();
192
+ const themedChildren = /* @__PURE__ */jsx(Theme, {
193
+ forceClassName: true,
194
+ name: themeName,
195
+ children
196
+ });
197
+ const content = needsPortalRepropagation() ? /* @__PURE__ */jsx(RepropagateMenuAndMenuRootProvider, {
198
+ menuContext,
199
+ rootContext,
200
+ popperContext,
201
+ menuSubContext,
202
+ scope,
203
+ children: themedChildren
204
+ }) : themedChildren;
205
+ const isPresent = forceMount || rootContext.open && menuContext.open;
206
+ return /* @__PURE__ */jsx(Animate, {
207
+ type: "presence",
208
+ present: isPresent,
209
+ children: /* @__PURE__ */jsx(PortalPrimitive, {
210
+ stackZIndex: true,
211
+ children: /* @__PURE__ */jsx(Fragment, {
212
+ children: /* @__PURE__ */jsx(PortalProvider, {
213
+ scope,
214
+ forceMount,
215
+ children: /* @__PURE__ */jsxs(View, {
216
+ zIndex: zIndex || 100,
217
+ inset: 0,
218
+ position: "absolute",
219
+ children: [!!menuContext.open && !isWeb && /* @__PURE__ */jsx(View, {
190
220
  inset: 0,
191
221
  position: "absolute",
192
- children: [!!menuContext.open && !isWeb && /* @__PURE__ */jsx(View, {
193
- inset: 0,
194
- position: "absolute",
195
- onPress: () => menuContext.onOpenChange(!menuContext.open)
196
- }), content]
197
- })
222
+ onPress: () => menuContext.onOpenChange(!menuContext.open)
223
+ }), content]
198
224
  })
199
225
  })
200
226
  })
201
- });
202
- };
227
+ })
228
+ });
229
+ };
203
230
  MenuPortal.displayName = PORTAL_NAME;
204
- const CONTENT_NAME = "MenuContent",
205
- {
206
- Provider: MenuContentProvider,
207
- useStyledContext: useMenuContentContext
208
- } = createStyledContext(),
209
- MenuContent = React.forwardRef((props, forwardedRef) => {
210
- const scope = props.scope || MENU_CONTEXT,
211
- portalContext = usePortalContext(scope),
212
- {
213
- forceMount = portalContext.forceMount,
214
- ...contentProps
215
- } = props,
216
- rootContext = useMenuRootContext(scope);
217
- return /* @__PURE__ */jsx(Collection.Provider, {
231
+ const CONTENT_NAME = "MenuContent";
232
+ const {
233
+ Provider: MenuContentProvider,
234
+ useStyledContext: useMenuContentContext
235
+ } = createStyledContext();
236
+ const MenuContentFrame = styled(PopperPrimitive.PopperContentFrame, {
237
+ name: CONTENT_NAME
238
+ });
239
+ const MenuContent = MenuContentFrame.styleable((props, forwardedRef) => {
240
+ const scope = props.scope || MENU_CONTEXT;
241
+ const portalContext = usePortalContext(scope);
242
+ const {
243
+ forceMount = portalContext.forceMount,
244
+ ...contentProps
245
+ } = props;
246
+ const rootContext = useMenuRootContext(scope);
247
+ return /* @__PURE__ */jsx(Collection.Provider, {
248
+ scope,
249
+ children: /* @__PURE__ */jsx(Collection.Slot, {
218
250
  scope,
219
- children: /* @__PURE__ */jsx(Collection.Slot, {
220
- scope,
221
- children: rootContext.modal ? /* @__PURE__ */jsx(MenuRootContentModal, {
222
- ...contentProps,
223
- ref: forwardedRef
224
- }) : /* @__PURE__ */jsx(MenuRootContentNonModal, {
225
- ...contentProps,
226
- ref: forwardedRef
227
- })
251
+ children: rootContext.modal ? /* @__PURE__ */jsx(MenuRootContentModal, {
252
+ ...contentProps,
253
+ ref: forwardedRef
254
+ }) : /* @__PURE__ */jsx(MenuRootContentNonModal, {
255
+ ...contentProps,
256
+ ref: forwardedRef
228
257
  })
258
+ })
259
+ });
260
+ });
261
+ const MenuRootContentModal = React.forwardRef((props, forwardedRef) => {
262
+ const scope = props.scope || MENU_CONTEXT;
263
+ const context = useMenuContext(scope);
264
+ const ref = React.useRef(null);
265
+ const composedRefs = useComposedRefs(forwardedRef, ref);
266
+ return /* @__PURE__ */jsx(MenuContentImpl, {
267
+ ...props,
268
+ scope,
269
+ ref: composedRefs,
270
+ trapFocus: context.open,
271
+ disableOutsidePointerEvents: context.open,
272
+ disableOutsideScroll: false,
273
+ onFocusOutside: composeEventHandlers(props.onFocusOutside, event => event.preventDefault(), {
274
+ checkDefaultPrevented: false
275
+ }),
276
+ onDismiss: () => context.onOpenChange(false)
277
+ });
278
+ });
279
+ const MenuRootContentNonModal = React.forwardRef((props, forwardedRef) => {
280
+ const scope = props.scope || MENU_CONTEXT;
281
+ const context = useMenuContext(scope);
282
+ return /* @__PURE__ */jsx(MenuContentImpl, {
283
+ ...props,
284
+ scope,
285
+ ref: forwardedRef,
286
+ trapFocus: false,
287
+ disableOutsidePointerEvents: false,
288
+ disableOutsideScroll: false,
289
+ onDismiss: () => context.onOpenChange(false)
290
+ });
291
+ });
292
+ const MenuContentImpl = React.forwardRef((props, forwardedRef) => {
293
+ const {
294
+ scope = MENU_CONTEXT,
295
+ loop = false,
296
+ trapFocus,
297
+ onOpenAutoFocus,
298
+ onCloseAutoFocus,
299
+ disableOutsidePointerEvents,
300
+ onEntryFocus,
301
+ onEscapeKeyDown,
302
+ onPointerDownOutside,
303
+ onFocusOutside,
304
+ onInteractOutside,
305
+ onDismiss,
306
+ disableOutsideScroll,
307
+ disableDismissOnScroll = false,
308
+ unstyled = process.env.TAMAGUI_HEADLESS === "1",
309
+ ...contentProps
310
+ } = props;
311
+ const context = useMenuContext(scope);
312
+ const rootContext = useMenuRootContext(scope);
313
+ const getItems = useCollection(scope);
314
+ const [currentItemId, setCurrentItemId] = React.useState(null);
315
+ const contentRef = React.useRef(null);
316
+ const focusableContentRef = React.useRef(null);
317
+ const composedRefs = useComposedRefs(forwardedRef, contentRef, context.onContentChange);
318
+ const timerRef = React.useRef(0);
319
+ const searchRef = React.useRef("");
320
+ const pointerGraceTimerRef = React.useRef(0);
321
+ const pointerGraceIntentRef = React.useRef(null);
322
+ const pointerDirRef = React.useRef("right");
323
+ const lastPointerXRef = React.useRef(0);
324
+ const handleTypeaheadSearch = key => {
325
+ const search = searchRef.current + key;
326
+ const items = getItems().filter(item => !item.disabled);
327
+ const currentItem = document.activeElement;
328
+ const currentMatch = items.find(item => item.ref.current === currentItem)?.textValue;
329
+ const values = items.map(item => item.textValue);
330
+ const nextMatch = getNextMatch(values, search, currentMatch);
331
+ const newItem = items.find(item => item.textValue === nextMatch)?.ref.current;
332
+ (function updateSearch(value) {
333
+ searchRef.current = value;
334
+ clearTimeout(timerRef.current);
335
+ if (value !== "") timerRef.current = setTimeout(() => updateSearch(""), 1e3);
336
+ })(search);
337
+ if (newItem) {
338
+ setTimeout(() => newItem.focus());
339
+ }
340
+ };
341
+ React.useEffect(() => {
342
+ return () => clearTimeout(timerRef.current);
343
+ }, []);
344
+ React.useEffect(() => {
345
+ if (!isWeb || !context.open) return;
346
+ const frame = requestAnimationFrame(() => {
347
+ const container = contentRef.current;
348
+ const el = container?.querySelector("[data-tamagui-menu-content]");
349
+ if (el) focusableContentRef.current = el;
229
350
  });
230
- }),
231
- MenuRootContentModal = React.forwardRef((props, forwardedRef) => {
232
- const scope = props.scope || MENU_CONTEXT,
233
- context = useMenuContext(scope),
234
- ref = React.useRef(null),
235
- composedRefs = useComposedRefs(forwardedRef, ref);
236
- return /* @__PURE__ */jsx(MenuContentImpl, {
237
- ...props,
238
- scope,
239
- ref: composedRefs,
240
- trapFocus: context.open,
241
- disableOutsidePointerEvents: context.open,
242
- disableOutsideScroll: !1,
243
- onFocusOutside: composeEventHandlers(props.onFocusOutside, event => event.preventDefault(), {
244
- checkDefaultPrevented: !1
245
- }),
246
- onDismiss: () => context.onOpenChange(!1)
351
+ return () => cancelAnimationFrame(frame);
352
+ }, [context.open]);
353
+ React.useEffect(() => {
354
+ if (!isWeb || disableDismissOnScroll || !context.open) return;
355
+ const handleScroll = event => {
356
+ const target = event.target;
357
+ if (contentRef.current?.contains(target)) return;
358
+ onDismiss?.();
359
+ };
360
+ window.addEventListener("scroll", handleScroll, {
361
+ capture: true,
362
+ passive: true
247
363
  });
248
- }),
249
- MenuRootContentNonModal = React.forwardRef((props, forwardedRef) => {
250
- const scope = props.scope || MENU_CONTEXT,
251
- context = useMenuContext(scope);
252
- return /* @__PURE__ */jsx(MenuContentImpl, {
253
- ...props,
254
- scope,
255
- ref: forwardedRef,
256
- trapFocus: !1,
257
- disableOutsidePointerEvents: !1,
258
- disableOutsideScroll: !1,
259
- onDismiss: () => context.onOpenChange(!1)
260
- });
261
- }),
262
- MenuContentImpl = React.forwardRef((props, forwardedRef) => {
263
- const {
264
- scope = MENU_CONTEXT,
265
- loop = !1,
266
- trapFocus,
267
- onOpenAutoFocus,
268
- onCloseAutoFocus,
269
- disableOutsidePointerEvents,
270
- onEntryFocus,
271
- onEscapeKeyDown,
272
- onPointerDownOutside,
273
- onFocusOutside,
274
- onInteractOutside,
275
- onDismiss,
276
- disableOutsideScroll,
277
- disableDismissOnScroll = !1,
278
- unstyled = process.env.TAMAGUI_HEADLESS === "1",
279
- ...contentProps
280
- } = props,
281
- context = useMenuContext(scope),
282
- rootContext = useMenuRootContext(scope),
283
- getItems = useCollection(scope),
284
- [currentItemId, setCurrentItemId] = React.useState(null),
285
- contentRef = React.useRef(null),
286
- composedRefs = useComposedRefs(forwardedRef, contentRef, context.onContentChange),
287
- timerRef = React.useRef(0),
288
- searchRef = React.useRef(""),
289
- pointerGraceTimerRef = React.useRef(0),
290
- pointerGraceIntentRef = React.useRef(null),
291
- pointerDirRef = React.useRef("right"),
292
- lastPointerXRef = React.useRef(0),
293
- handleTypeaheadSearch = key => {
294
- const search = searchRef.current + key,
295
- items = getItems().filter(item => !item.disabled),
296
- currentItem = document.activeElement,
297
- currentMatch = items.find(item => item.ref.current === currentItem)?.textValue,
298
- values = items.map(item => item.textValue),
299
- nextMatch = getNextMatch(values, search, currentMatch),
300
- newItem = items.find(item => item.textValue === nextMatch)?.ref.current;
301
- (function updateSearch(value) {
302
- searchRef.current = value, clearTimeout(timerRef.current), value !== "" && (timerRef.current = setTimeout(() => updateSearch(""), 1e3));
303
- })(search), newItem && setTimeout(() => newItem.focus());
304
- };
305
- React.useEffect(() => () => clearTimeout(timerRef.current), []), React.useEffect(() => {
306
- if (!isWeb || disableDismissOnScroll || !context.open) return;
307
- const handleScroll = () => {
308
- onDismiss?.();
309
- };
310
- return window.addEventListener("scroll", handleScroll, {
311
- capture: !0,
312
- passive: !0
313
- }), () => {
314
- window.removeEventListener("scroll", handleScroll, {
315
- capture: !0
364
+ return () => {
365
+ window.removeEventListener("scroll", handleScroll, {
366
+ capture: true
367
+ });
368
+ };
369
+ }, [disableDismissOnScroll, context.open, onDismiss]);
370
+ if (isWeb) {
371
+ useFocusGuards();
372
+ }
373
+ const isPointerMovingToSubmenu = React.useCallback(event => {
374
+ const isMovingTowards = pointerDirRef.current === pointerGraceIntentRef.current?.side;
375
+ const inArea = isPointerInGraceArea(event, pointerGraceIntentRef.current?.area);
376
+ return isMovingTowards && inArea;
377
+ }, []);
378
+ const content = /* @__PURE__ */jsx(PopperPrimitive.PopperContent, {
379
+ role: "menu",
380
+ tabIndex: -1,
381
+ unstyled,
382
+ ...(!unstyled && {
383
+ backgroundColor: "$background",
384
+ borderWidth: 1,
385
+ borderColor: "$borderColor",
386
+ outlineWidth: 0,
387
+ minWidth: 180
388
+ }),
389
+ "aria-orientation": "vertical",
390
+ "data-state": getOpenState(context.open),
391
+ "data-tamagui-menu-content": "",
392
+ dir: rootContext.dir,
393
+ scope: scope || MENU_CONTEXT,
394
+ ...contentProps,
395
+ ref: composedRefs,
396
+ className: contentProps.transition ? void 0 : contentProps.className,
397
+ ...(isWeb ? {
398
+ onKeyDown: composeEventHandlers(contentProps.onKeyDown, event => {
399
+ const target = event.target;
400
+ const isKeyDownInside = target.closest("[data-tamagui-menu-content]") === event.currentTarget;
401
+ const isModifierKey = event.ctrlKey || event.altKey || event.metaKey;
402
+ const isCharacterKey = event.key.length === 1;
403
+ if (isKeyDownInside) {
404
+ if (event.key === "Tab") event.preventDefault();
405
+ if (!isModifierKey && isCharacterKey) handleTypeaheadSearch(event.key);
406
+ }
407
+ const isOnContentFrame = event.target.hasAttribute("data-tamagui-menu-content");
408
+ if (!isKeyDownInside || !isOnContentFrame) return;
409
+ if (!FIRST_LAST_KEYS.includes(event.key)) return;
410
+ event.preventDefault();
411
+ const items = getItems().filter(item => !item.disabled);
412
+ const candidateNodes = items.map(item => item.ref.current);
413
+ if (LAST_KEYS.includes(event.key)) candidateNodes.reverse();
414
+ focusFirst(candidateNodes, {
415
+ focusVisible: true
316
416
  });
317
- };
318
- }, [disableDismissOnScroll, context.open, onDismiss]), isWeb && useFocusGuards();
319
- const isPointerMovingToSubmenu = React.useCallback(event => {
320
- const isMovingTowards = pointerDirRef.current === pointerGraceIntentRef.current?.side,
321
- inArea = isPointerInGraceArea(event, pointerGraceIntentRef.current?.area);
322
- return isMovingTowards && inArea;
323
- }, []),
324
- content = /* @__PURE__ */jsx(PopperPrimitive.PopperContent, {
325
- role: "menu",
326
- ...(!unstyled && {
327
- padding: 4,
328
- backgroundColor: "$background",
329
- borderWidth: 1,
330
- borderColor: "$borderColor",
331
- outlineWidth: 0,
332
- minWidth: 180
417
+ }),
418
+ // TODO
419
+ // @ts-ignore
420
+ onBlur: composeEventHandlers(props.onBlur, event => {
421
+ if (!event.currentTarget?.contains(event.target)) {
422
+ clearTimeout(timerRef.current);
423
+ searchRef.current = "";
424
+ }
425
+ }),
426
+ // TODO
427
+ onPointerMove: composeEventHandlers(props.onPointerMove, event => {
428
+ if (event.pointerType !== "mouse") return;
429
+ const target = event.target;
430
+ const pointerXHasChanged = lastPointerXRef.current !== event.clientX;
431
+ if (event.currentTarget?.contains(target) && pointerXHasChanged) {
432
+ const newDir = event.clientX > lastPointerXRef.current ? "right" : "left";
433
+ pointerDirRef.current = newDir;
434
+ lastPointerXRef.current = event.clientX;
435
+ }
436
+ })
437
+ } : {})
438
+ });
439
+ return /* @__PURE__ */jsx(MenuContentProvider, {
440
+ scope,
441
+ searchRef,
442
+ onItemEnter: React.useCallback(event => {
443
+ if (isPointerMovingToSubmenu(event)) event.preventDefault();
444
+ }, [isPointerMovingToSubmenu]),
445
+ onItemLeave: React.useCallback(event => {
446
+ if (isPointerMovingToSubmenu(event)) return;
447
+ focusableContentRef.current?.focus();
448
+ setCurrentItemId(null);
449
+ }, [isPointerMovingToSubmenu]),
450
+ onTriggerLeave: React.useCallback(event => {
451
+ if (isPointerMovingToSubmenu(event)) event.preventDefault();
452
+ }, [isPointerMovingToSubmenu]),
453
+ pointerGraceTimerRef,
454
+ onPointerGraceIntentChange: React.useCallback(intent => {
455
+ pointerGraceIntentRef.current = intent;
456
+ }, []),
457
+ children: /* @__PURE__ */jsx(RemoveScroll, {
458
+ enabled: disableOutsideScroll,
459
+ children: /* @__PURE__ */jsx(FocusScope, {
460
+ asChild: false,
461
+ trapped: trapFocus,
462
+ onMountAutoFocus: composeEventHandlers(onOpenAutoFocus, event => {
463
+ event.preventDefault();
464
+ const content2 = document.querySelector("[data-tamagui-menu-content]");
465
+ content2?.focus({
466
+ preventScroll: true
467
+ });
333
468
  }),
334
- "aria-orientation": "vertical",
335
- "data-state": getOpenState(context.open),
336
- "data-tamagui-menu-content": "",
337
- dir: rootContext.dir,
338
- scope: scope || MENU_CONTEXT,
339
- ...contentProps,
340
- ref: composedRefs,
341
- className: contentProps.transition ? void 0 : contentProps.className,
342
- ...(isWeb ? {
343
- onKeyDown: composeEventHandlers(contentProps.onKeyDown, event => {
344
- const isKeyDownInside = event.target.closest("[data-tamagui-menu-content]") === event.currentTarget,
345
- isModifierKey = event.ctrlKey || event.altKey || event.metaKey,
346
- isCharacterKey = event.key.length === 1;
347
- isKeyDownInside && (event.key === "Tab" && event.preventDefault(), !isModifierKey && isCharacterKey && handleTypeaheadSearch(event.key));
348
- const isOnContentFrame = event.target.hasAttribute("data-tamagui-menu-content");
349
- if (!isKeyDownInside || !isOnContentFrame || !FIRST_LAST_KEYS.includes(event.key)) return;
350
- event.preventDefault();
351
- const candidateNodes = getItems().filter(item => !item.disabled).map(item => item.ref.current);
352
- LAST_KEYS.includes(event.key) && candidateNodes.reverse(), focusFirst(candidateNodes, {
353
- focusVisible: !0
354
- });
355
- }),
356
- // TODO
357
- // @ts-ignore
358
- onBlur: composeEventHandlers(props.onBlur, event => {
359
- event.currentTarget?.contains(event.target) || (clearTimeout(timerRef.current), searchRef.current = "");
360
- }),
361
- // TODO
362
- onPointerMove: composeEventHandlers(props.onPointerMove, event => {
363
- if (event.pointerType !== "mouse") return;
364
- const target = event.target,
365
- pointerXHasChanged = lastPointerXRef.current !== event.clientX;
366
- if (event.currentTarget?.contains(target) && pointerXHasChanged) {
367
- const newDir = event.clientX > lastPointerXRef.current ? "right" : "left";
368
- pointerDirRef.current = newDir, lastPointerXRef.current = event.clientX;
369
- }
370
- })
371
- } : {})
372
- });
373
- return /* @__PURE__ */jsx(MenuContentProvider, {
374
- scope,
375
- searchRef,
376
- onItemEnter: React.useCallback(event => {
377
- isPointerMovingToSubmenu(event) && event.preventDefault();
378
- }, [isPointerMovingToSubmenu]),
379
- onItemLeave: React.useCallback(event => {
380
- isPointerMovingToSubmenu(event) || (contentRef.current?.focus(), setCurrentItemId(null));
381
- }, [isPointerMovingToSubmenu]),
382
- onTriggerLeave: React.useCallback(event => {
383
- isPointerMovingToSubmenu(event) && event.preventDefault();
384
- }, [isPointerMovingToSubmenu]),
385
- pointerGraceTimerRef,
386
- onPointerGraceIntentChange: React.useCallback(intent => {
387
- pointerGraceIntentRef.current = intent;
388
- }, []),
389
- children: /* @__PURE__ */jsx(RemoveScroll, {
390
- enabled: disableOutsideScroll,
391
- children: /* @__PURE__ */jsx(FocusScope, {
392
- asChild: !1,
393
- trapped: trapFocus,
394
- onMountAutoFocus: composeEventHandlers(onOpenAutoFocus, event => {
395
- event.preventDefault(), document.querySelector("[data-tamagui-menu-content]")?.focus();
396
- }),
397
- onUnmountAutoFocus: onCloseAutoFocus,
398
- children: /* @__PURE__ */jsx(DismissableLayer, {
399
- disableOutsidePointerEvents,
400
- onEscapeKeyDown,
401
- onPointerDownOutside,
402
- onFocusOutside,
403
- onInteractOutside,
404
- onDismiss,
405
- asChild: !0,
406
- children: /* @__PURE__ */jsx(RovingFocusGroup, {
407
- asChild: !0,
408
- __scopeRovingFocusGroup: scope || MENU_CONTEXT,
409
- dir: rootContext.dir,
410
- orientation: "vertical",
411
- loop,
412
- currentTabStopId: currentItemId,
413
- onCurrentTabStopIdChange: setCurrentItemId,
414
- onEntryFocus: composeEventHandlers(onEntryFocus, event => {
415
- rootContext.isUsingKeyboardRef.current || event.preventDefault();
416
- }),
417
- children: content
418
- })
469
+ onUnmountAutoFocus: onCloseAutoFocus,
470
+ children: /* @__PURE__ */jsx(DismissableLayer, {
471
+ disableOutsidePointerEvents,
472
+ onEscapeKeyDown,
473
+ onPointerDownOutside,
474
+ onFocusOutside,
475
+ onInteractOutside,
476
+ onDismiss,
477
+ asChild: true,
478
+ children: /* @__PURE__ */jsx(RovingFocusGroup, {
479
+ asChild: true,
480
+ __scopeRovingFocusGroup: scope || MENU_CONTEXT,
481
+ dir: rootContext.dir,
482
+ orientation: "vertical",
483
+ loop,
484
+ currentTabStopId: currentItemId,
485
+ onCurrentTabStopIdChange: setCurrentItemId,
486
+ onEntryFocus: composeEventHandlers(onEntryFocus, event => {
487
+ if (!rootContext.isUsingKeyboardRef.current) {
488
+ event.preventDefault();
489
+ }
490
+ }),
491
+ children: content
419
492
  })
420
493
  })
421
494
  })
422
- });
495
+ })
423
496
  });
497
+ });
424
498
  MenuContent.displayName = CONTENT_NAME;
425
- const ITEM_NAME = "MenuItem",
426
- ITEM_SELECT = "menu.itemSelect",
427
- MenuItem = React.forwardRef((props, forwardedRef) => {
428
- const {
429
- disabled = !1,
430
- onSelect,
431
- children,
432
- scope = MENU_CONTEXT,
433
- // filter out native-only props that shouldn't reach the DOM
434
- // @ts-ignore
435
- destructive,
436
- // @ts-ignore
437
- hidden,
438
- // @ts-ignore
439
- androidIconName,
440
- // @ts-ignore
441
- iosIconName,
442
- ...itemProps
443
- } = props,
444
- ref = React.useRef(null),
445
- rootContext = useMenuRootContext(scope),
446
- contentContext = useMenuContentContext(scope),
447
- composedRefs = useComposedRefs(forwardedRef, ref),
448
- isPointerDownRef = React.useRef(!1),
449
- handleSelect = () => {
450
- const menuItem = ref.current;
451
- if (!disabled && menuItem) if (isWeb) {
452
- const menuItemEl = menuItem,
453
- itemSelectEvent = new CustomEvent(ITEM_SELECT, {
454
- bubbles: !0,
455
- cancelable: !0
456
- });
457
- menuItemEl.addEventListener(ITEM_SELECT, event => onSelect?.(event), {
458
- once: !0
459
- }), dispatchDiscreteCustomEvent(menuItemEl, itemSelectEvent), itemSelectEvent.defaultPrevented ? isPointerDownRef.current = !1 : rootContext.onClose();
460
- } else onSelect?.({
499
+ const ITEM_NAME = "MenuItem";
500
+ const ITEM_SELECT = "menu.itemSelect";
501
+ const MenuItem = _Item.styleable((props, forwardedRef) => {
502
+ const {
503
+ disabled = false,
504
+ onSelect,
505
+ preventCloseOnSelect,
506
+ children,
507
+ scope = MENU_CONTEXT,
508
+ // filter out native-only props that shouldn't reach the DOM
509
+ // @ts-ignore
510
+ destructive,
511
+ // @ts-ignore
512
+ hidden,
513
+ // @ts-ignore
514
+ androidIconName,
515
+ // @ts-ignore
516
+ iosIconName,
517
+ ...itemProps
518
+ } = props;
519
+ const ref = React.useRef(null);
520
+ const rootContext = useMenuRootContext(scope);
521
+ const contentContext = useMenuContentContext(scope);
522
+ const composedRefs = useComposedRefs(forwardedRef, ref);
523
+ const isPointerDownRef = React.useRef(false);
524
+ const handleSelect = () => {
525
+ const menuItem = ref.current;
526
+ if (!disabled && menuItem) {
527
+ if (isWeb) {
528
+ const menuItemEl = menuItem;
529
+ const itemSelectEvent = new CustomEvent(ITEM_SELECT, {
530
+ bubbles: true,
531
+ cancelable: true
532
+ });
533
+ menuItemEl.addEventListener(ITEM_SELECT, event => onSelect?.(event), {
534
+ once: true
535
+ });
536
+ dispatchDiscreteCustomEvent(menuItemEl, itemSelectEvent);
537
+ if (itemSelectEvent.defaultPrevented || preventCloseOnSelect) {
538
+ isPointerDownRef.current = false;
539
+ } else {
540
+ rootContext.onClose();
541
+ }
542
+ } else {
543
+ onSelect?.({
461
544
  target: menuItem
462
- }), isPointerDownRef.current = !1, rootContext.onClose();
463
- },
464
- content = typeof children == "string" ? /* @__PURE__ */jsx(Text, {
465
- children
466
- }) : children;
467
- return /* @__PURE__ */jsx(MenuItemImpl, {
468
- outlineStyle: "none",
469
- ...itemProps,
470
- scope,
471
- ref: composedRefs,
472
- disabled,
473
- onPress: composeEventHandlers(props.onPress, handleSelect),
474
- onPointerDown: event => {
475
- props.onPointerDown?.(event), isPointerDownRef.current = !0;
476
- },
477
- onPointerUp: composeEventHandlers(props.onPointerUp, event => {
478
- isWeb && (isPointerDownRef.current || event.currentTarget?.click());
479
- }),
480
- ...(isWeb ? {
481
- onKeyDown: composeEventHandlers(props.onKeyDown, event => {
482
- const isTypingAhead = contentContext.searchRef.current !== "";
483
- disabled || isTypingAhead && event.key === " " || SELECTION_KEYS.includes(event.key) && (event.currentTarget?.click(), event.preventDefault());
484
- })
485
- } : {}),
486
- children: content
487
- });
488
- }),
489
- MenuItemImpl = React.forwardRef((props, forwardedRef) => {
490
- const {
491
- scope = MENU_CONTEXT,
492
- disabled = !1,
493
- textValue,
494
- unstyled = process.env.TAMAGUI_HEADLESS === "1",
495
- ...itemProps
496
- } = props,
497
- contentContext = useMenuContentContext(scope),
498
- ref = React.useRef(null),
499
- composedRefs = useComposedRefs(forwardedRef, ref),
500
- [isFocused, setIsFocused] = React.useState(!1),
501
- [textContent, setTextContent] = React.useState("");
502
- return isWeb && React.useEffect(() => {
545
+ });
546
+ isPointerDownRef.current = false;
547
+ if (!preventCloseOnSelect) {
548
+ rootContext.onClose();
549
+ }
550
+ }
551
+ }
552
+ };
553
+ const content = typeof children === "string" ? /* @__PURE__ */jsx(Text, {
554
+ children
555
+ }) : children;
556
+ return /* @__PURE__ */jsx(MenuItemImpl, {
557
+ outlineStyle: "none",
558
+ ...itemProps,
559
+ scope,
560
+ ref: composedRefs,
561
+ disabled,
562
+ onPress: composeEventHandlers(props.onPress, handleSelect),
563
+ onPointerDown: event => {
564
+ props.onPointerDown?.(event);
565
+ isPointerDownRef.current = true;
566
+ },
567
+ onPointerUp: composeEventHandlers(props.onPointerUp, event => {
568
+ if (isWeb) {
569
+ if (!isPointerDownRef.current) event.currentTarget?.click();
570
+ }
571
+ }),
572
+ ...(isWeb ? {
573
+ onKeyDown: composeEventHandlers(props.onKeyDown, event => {
574
+ const isTypingAhead = contentContext.searchRef.current !== "";
575
+ if (disabled || isTypingAhead && event.key === " ") return;
576
+ if (SELECTION_KEYS.includes(event.key)) {
577
+ event.currentTarget?.click();
578
+ event.preventDefault();
579
+ }
580
+ })
581
+ } : {}),
582
+ children: content
583
+ });
584
+ });
585
+ const MenuItemImpl = React.forwardRef((props, forwardedRef) => {
586
+ const {
587
+ scope = MENU_CONTEXT,
588
+ disabled = false,
589
+ textValue,
590
+ unstyled = process.env.TAMAGUI_HEADLESS === "1",
591
+ ...itemProps
592
+ } = props;
593
+ const contentContext = useMenuContentContext(scope);
594
+ const ref = React.useRef(null);
595
+ const composedRefs = useComposedRefs(forwardedRef, ref);
596
+ const [isFocused, setIsFocused] = React.useState(false);
597
+ const [textContent, setTextContent] = React.useState("");
598
+ if (isWeb) {
599
+ React.useEffect(() => {
503
600
  const menuItem = ref.current;
504
- menuItem && setTextContent((menuItem.textContent ?? "").trim());
505
- }, [itemProps.children]), /* @__PURE__ */jsx(Collection.ItemSlot, {
506
- scope,
507
- disabled,
508
- textValue: textValue ?? textContent,
509
- children: /* @__PURE__ */jsx(RovingFocusGroup.Item, {
510
- asChild: !0,
511
- __scopeRovingFocusGroup: scope,
512
- focusable: !disabled,
513
- ...(!unstyled && {
514
- flexDirection: "row",
515
- alignItems: "center"
516
- }),
601
+ if (menuItem) {
602
+ setTextContent((menuItem.textContent ?? "").trim());
603
+ }
604
+ }, [itemProps.children]);
605
+ }
606
+ return /* @__PURE__ */jsx(Collection.ItemSlot, {
607
+ scope,
608
+ disabled,
609
+ textValue: textValue ?? textContent,
610
+ children: /* @__PURE__ */jsx(RovingFocusGroup.Item, {
611
+ asChild: true,
612
+ __scopeRovingFocusGroup: scope,
613
+ focusable: !disabled,
614
+ children: /* @__PURE__ */jsx(_Item, {
615
+ unstyled,
616
+ componentName: ITEM_NAME,
617
+ role: "menuitem",
618
+ "data-highlighted": isFocused ? "" : void 0,
619
+ "aria-disabled": disabled || void 0,
620
+ "data-disabled": disabled ? "" : void 0,
517
621
  ...itemProps,
518
- children: /* @__PURE__ */jsx(_Item, {
519
- componentName: ITEM_NAME,
520
- role: "menuitem",
521
- "data-highlighted": isFocused ? "" : void 0,
522
- "aria-disabled": disabled || void 0,
523
- "data-disabled": disabled ? "" : void 0,
524
- ...itemProps,
525
- ref: composedRefs,
526
- onPointerMove: composeEventHandlers(props.onPointerMove, event => {
527
- event.pointerType === "mouse" && (disabled ? contentContext.onItemLeave(event) : (contentContext.onItemEnter(event), event.defaultPrevented || event.currentTarget.focus({
528
- preventScroll: !0,
529
- focusVisible: !1
530
- })));
531
- }),
532
- onPointerLeave: composeEventHandlers(props.onPointerLeave, event => {
622
+ ref: composedRefs,
623
+ onPointerMove: composeEventHandlers(props.onPointerMove, event => {
624
+ if (event.pointerType !== "mouse") return;
625
+ if (disabled) {
533
626
  contentContext.onItemLeave(event);
534
- }),
535
- onFocus: composeEventHandlers(props.onFocus, () => setIsFocused(!0)),
536
- onBlur: composeEventHandlers(props.onBlur, () => setIsFocused(!1))
537
- })
627
+ } else {
628
+ contentContext.onItemEnter(event);
629
+ if (!event.defaultPrevented) {
630
+ const item = event.currentTarget;
631
+ item.focus({
632
+ preventScroll: true,
633
+ focusVisible: false
634
+ });
635
+ }
636
+ }
637
+ }),
638
+ onPointerLeave: composeEventHandlers(props.onPointerLeave, event => {
639
+ contentContext.onItemLeave(event);
640
+ }),
641
+ onFocus: composeEventHandlers(props.onFocus, () => setIsFocused(true)),
642
+ onBlur: composeEventHandlers(props.onBlur, () => setIsFocused(false))
538
643
  })
539
- });
644
+ })
540
645
  });
646
+ });
541
647
  MenuItem.displayName = ITEM_NAME;
542
- const ITEM_TITLE_NAME = "MenuItemTitle",
543
- MenuItemTitle = _Title.styleable((props, forwardedRef) => /* @__PURE__ */jsx(_Title, {
648
+ const ITEM_TITLE_NAME = "MenuItemTitle";
649
+ const MenuItemTitle = _Title.styleable((props, forwardedRef) => {
650
+ return /* @__PURE__ */jsx(_Title, {
544
651
  ...props,
545
652
  ref: forwardedRef
546
- }));
653
+ });
654
+ });
547
655
  MenuItemTitle.displayName = ITEM_TITLE_NAME;
548
- const ITEM_SUB_TITLE_NAME = "MenuItemSubTitle",
549
- MenuItemSubTitle = _SubTitle.styleable((props, forwardedRef) => /* @__PURE__ */jsx(_SubTitle, {
656
+ const ITEM_SUB_TITLE_NAME = "MenuItemSubTitle";
657
+ const MenuItemSubTitle = _SubTitle.styleable((props, forwardedRef) => {
658
+ return /* @__PURE__ */jsx(_SubTitle, {
550
659
  ...props,
551
660
  ref: forwardedRef
552
- }));
661
+ });
662
+ });
553
663
  MenuItemSubTitle.displayName = ITEM_SUB_TITLE_NAME;
554
- const ITEM_IMAGE = "MenuItemImage",
555
- MenuItemImage = React.forwardRef((props, forwardedRef) => {
556
- const {
557
- // @ts-ignore - native menu ios config
558
- ios,
559
- // @ts-ignore
560
- androidIconName,
561
- // @ts-ignore
562
- iosIconName,
563
- ...rest
564
- } = props;
565
- return /* @__PURE__ */jsx(_Image, {
566
- ...rest,
567
- ref: forwardedRef
568
- });
664
+ const ITEM_IMAGE = "MenuItemImage";
665
+ const MenuItemImage = React.forwardRef((props, forwardedRef) => {
666
+ const {
667
+ // @ts-ignore - native menu ios config
668
+ ios,
669
+ // @ts-ignore
670
+ androidIconName,
671
+ // @ts-ignore
672
+ iosIconName,
673
+ ...rest
674
+ } = props;
675
+ return /* @__PURE__ */jsx(_Image, {
676
+ ...rest,
677
+ ref: forwardedRef
569
678
  });
679
+ });
570
680
  MenuItemImage.displayName = ITEM_IMAGE;
571
- const ITEM_ICON = "MenuItemIcon",
572
- MenuItemIcon = _Icon.styleable((props, forwardedRef) => {
573
- const {
574
- // @ts-ignore
575
- ios,
576
- // @ts-ignore
577
- android,
578
- // @ts-ignore
579
- androidIconName,
580
- // @ts-ignore
581
- iosIconName,
582
- ...rest
583
- } = props;
584
- return /* @__PURE__ */jsx(_Icon, {
585
- ...rest,
586
- ref: forwardedRef
587
- });
681
+ const ITEM_ICON = "MenuItemIcon";
682
+ const MenuItemIcon = _Icon.styleable((props, forwardedRef) => {
683
+ const {
684
+ // @ts-ignore
685
+ ios,
686
+ // @ts-ignore
687
+ android,
688
+ // @ts-ignore
689
+ androidIconName,
690
+ // @ts-ignore
691
+ iosIconName,
692
+ ...rest
693
+ } = props;
694
+ return /* @__PURE__ */jsx(_Icon, {
695
+ ...rest,
696
+ ref: forwardedRef
588
697
  });
698
+ });
589
699
  MenuItemIcon.displayName = ITEM_ICON;
590
- const CHECKBOX_ITEM_NAME = "MenuCheckboxItem",
591
- MenuCheckboxItem = React.forwardRef((props, forwardedRef) => {
592
- const {
593
- checked = !1,
594
- onCheckedChange,
595
- scope = MENU_CONTEXT,
596
- // filter out native-only props
597
- // @ts-ignore - native menu value state
598
- value,
599
- // @ts-ignore - native menu value change handler
600
- onValueChange,
601
- ...checkboxItemProps
602
- } = props;
603
- return /* @__PURE__ */jsx(ItemIndicatorProvider, {
700
+ const CHECKBOX_ITEM_NAME = "MenuCheckboxItem";
701
+ const MenuCheckboxItem = _Item.styleable((props, forwardedRef) => {
702
+ const {
703
+ checked = false,
704
+ onCheckedChange,
705
+ scope = MENU_CONTEXT,
706
+ // filter out native-only props
707
+ // @ts-ignore - native menu value state
708
+ value,
709
+ // @ts-ignore - native menu value change handler
710
+ onValueChange,
711
+ ...checkboxItemProps
712
+ } = props;
713
+ return /* @__PURE__ */jsx(ItemIndicatorProvider, {
714
+ scope,
715
+ checked,
716
+ children: /* @__PURE__ */jsx(MenuItem, {
717
+ componentName: CHECKBOX_ITEM_NAME,
718
+ role: isWeb ? "menuitemcheckbox" : "menuitem",
719
+ "aria-checked": isIndeterminate(checked) ? "mixed" : checked,
720
+ ...checkboxItemProps,
604
721
  scope,
605
- checked,
606
- children: /* @__PURE__ */jsx(MenuItem, {
607
- componentName: CHECKBOX_ITEM_NAME,
608
- role: isWeb ? "menuitemcheckbox" : "menuitem",
609
- "aria-checked": isIndeterminate(checked) ? "mixed" : checked,
610
- ...checkboxItemProps,
611
- scope,
612
- ref: forwardedRef,
613
- "data-state": getCheckedState(checked),
614
- onSelect: composeEventHandlers(checkboxItemProps.onSelect, () => onCheckedChange?.(isIndeterminate(checked) ? !0 : !checked), {
615
- checkDefaultPrevented: !1
616
- })
722
+ ref: forwardedRef,
723
+ "data-state": getCheckedState(checked),
724
+ onSelect: composeEventHandlers(checkboxItemProps.onSelect, () => onCheckedChange?.(isIndeterminate(checked) ? true : !checked), {
725
+ checkDefaultPrevented: false
617
726
  })
618
- });
727
+ })
619
728
  });
729
+ });
620
730
  MenuCheckboxItem.displayName = CHECKBOX_ITEM_NAME;
621
- const RADIO_GROUP_NAME = "MenuRadioGroup",
622
- {
623
- Provider: RadioGroupProvider,
624
- useStyledContext: useRadioGroupContext
625
- } = createStyledContext(),
626
- MenuRadioGroup = _MenuGroup.styleable((props, forwardedRef) => {
627
- const {
628
- value,
629
- onValueChange,
630
- scope = MENU_CONTEXT,
631
- ...groupProps
632
- } = props,
633
- handleValueChange = useCallbackRef(onValueChange);
634
- return /* @__PURE__ */jsx(RadioGroupProvider, {
635
- scope,
636
- value,
637
- onValueChange: handleValueChange,
638
- children: /* @__PURE__ */jsx(_MenuGroup, {
639
- componentName: RADIO_GROUP_NAME,
640
- ...groupProps,
641
- ref: forwardedRef
642
- })
643
- });
731
+ const RADIO_GROUP_NAME = "MenuRadioGroup";
732
+ const {
733
+ Provider: RadioGroupProvider,
734
+ useStyledContext: useRadioGroupContext
735
+ } = createStyledContext();
736
+ const MenuRadioGroup = _MenuGroup.styleable((props, forwardedRef) => {
737
+ const {
738
+ value,
739
+ onValueChange,
740
+ scope = MENU_CONTEXT,
741
+ ...groupProps
742
+ } = props;
743
+ const handleValueChange = useCallbackRef(onValueChange);
744
+ return /* @__PURE__ */jsx(RadioGroupProvider, {
745
+ scope,
746
+ value,
747
+ onValueChange: handleValueChange,
748
+ children: /* @__PURE__ */jsx(_MenuGroup, {
749
+ componentName: RADIO_GROUP_NAME,
750
+ ...groupProps,
751
+ ref: forwardedRef
752
+ })
644
753
  });
754
+ });
645
755
  MenuRadioGroup.displayName = RADIO_GROUP_NAME;
646
- const RADIO_ITEM_NAME = "MenuRadioItem",
647
- MenuRadioItem = React.forwardRef((props, forwardedRef) => {
648
- const {
649
- value,
650
- scope = MENU_CONTEXT,
651
- ...radioItemProps
652
- } = props,
653
- context = useRadioGroupContext(scope),
654
- checked = value === context.value;
655
- return /* @__PURE__ */jsx(ItemIndicatorProvider, {
756
+ const RADIO_ITEM_NAME = "MenuRadioItem";
757
+ const MenuRadioItem = _Item.styleable((props, forwardedRef) => {
758
+ const {
759
+ value,
760
+ scope = MENU_CONTEXT,
761
+ ...radioItemProps
762
+ } = props;
763
+ const context = useRadioGroupContext(scope);
764
+ const checked = value === context.value;
765
+ return /* @__PURE__ */jsx(ItemIndicatorProvider, {
766
+ scope,
767
+ checked,
768
+ children: /* @__PURE__ */jsx(MenuItem, {
769
+ componentName: RADIO_ITEM_NAME,
770
+ ...radioItemProps,
656
771
  scope,
657
- checked,
658
- children: /* @__PURE__ */jsx(MenuItem, {
659
- componentName: RADIO_ITEM_NAME,
660
- ...radioItemProps,
661
- scope,
662
- "aria-checked": checked,
663
- ref: forwardedRef,
664
- role: isWeb ? "menuitemradio" : "menuitem",
665
- "data-state": getCheckedState(checked),
666
- onSelect: composeEventHandlers(radioItemProps.onSelect, () => context.onValueChange?.(value), {
667
- checkDefaultPrevented: !1
668
- })
772
+ "aria-checked": checked,
773
+ ref: forwardedRef,
774
+ role: isWeb ? "menuitemradio" : "menuitem",
775
+ "data-state": getCheckedState(checked),
776
+ onSelect: composeEventHandlers(radioItemProps.onSelect, () => context.onValueChange?.(value), {
777
+ checkDefaultPrevented: false
669
778
  })
670
- });
779
+ })
671
780
  });
781
+ });
672
782
  MenuRadioItem.displayName = RADIO_ITEM_NAME;
673
- const ITEM_INDICATOR_NAME = "MenuItemIndicator",
674
- {
675
- Provider: ItemIndicatorProvider,
676
- useStyledContext: useItemIndicatorContext
677
- } = createStyledContext(),
678
- MenuItemIndicator = _Indicator.styleable((props, forwardedRef) => {
679
- const {
680
- scope = MENU_CONTEXT,
681
- forceMount,
682
- ...itemIndicatorProps
683
- } = props,
684
- indicatorContext = useItemIndicatorContext(scope);
685
- return /* @__PURE__ */jsx(Presence, {
686
- children: forceMount || isIndeterminate(indicatorContext.checked) || indicatorContext.checked === !0 ? /* @__PURE__ */jsx(_Indicator, {
687
- componentName: ITEM_INDICATOR_NAME,
688
- render: "span",
689
- ...itemIndicatorProps,
690
- ref: forwardedRef,
691
- "data-state": getCheckedState(indicatorContext.checked)
692
- }) : null
693
- });
783
+ const ITEM_INDICATOR_NAME = "MenuItemIndicator";
784
+ const {
785
+ Provider: ItemIndicatorProvider,
786
+ useStyledContext: useItemIndicatorContext
787
+ } = createStyledContext();
788
+ const MenuItemIndicator = _Indicator.styleable((props, forwardedRef) => {
789
+ const {
790
+ scope = MENU_CONTEXT,
791
+ forceMount,
792
+ ...itemIndicatorProps
793
+ } = props;
794
+ const indicatorContext = useItemIndicatorContext(scope);
795
+ return /* @__PURE__ */jsx(Presence, {
796
+ children: forceMount || isIndeterminate(indicatorContext.checked) || indicatorContext.checked === true ? /* @__PURE__ */jsx(_Indicator, {
797
+ componentName: ITEM_INDICATOR_NAME,
798
+ render: "span",
799
+ ...itemIndicatorProps,
800
+ ref: forwardedRef,
801
+ "data-state": getCheckedState(indicatorContext.checked)
802
+ }) : null
694
803
  });
804
+ });
695
805
  MenuItemIndicator.displayName = ITEM_INDICATOR_NAME;
696
- const MenuArrow = React.forwardRef(function (props, forwardedRef) {
697
- const {
698
- scope = MENU_CONTEXT,
699
- unstyled = process.env.TAMAGUI_HEADLESS === "1",
700
- ...rest
701
- } = props;
702
- return /* @__PURE__ */jsx(PopperPrimitive.PopperArrow, {
703
- scope,
704
- componentName: "PopperArrow",
705
- ...(!unstyled && {
706
- backgroundColor: "$background"
707
- }),
708
- ...rest,
709
- ref: forwardedRef
710
- });
711
- }),
712
- SUB_NAME = "MenuSub",
713
- {
714
- Provider: MenuSubProvider,
715
- useStyledContext: useMenuSubContext
716
- } = createStyledContext(),
717
- MenuSub = props => {
718
- const {
719
- scope = MENU_CONTEXT,
720
- children,
721
- open = !1,
722
- onOpenChange,
723
- allowFlip = {
724
- padding: 10
725
- },
726
- stayInFrame = {
727
- padding: 10
728
- },
729
- ...rest
730
- } = props,
731
- parentMenuContext = useMenuContext(scope),
732
- [trigger, setTrigger] = React.useState(null),
733
- [content, setContent] = React.useState(null),
734
- handleOpenChange = useCallbackRef(onOpenChange);
735
- return React.useEffect(() => (parentMenuContext.open === !1 && handleOpenChange(!1), () => handleOpenChange(!1)), [parentMenuContext.open, handleOpenChange]), /* @__PURE__ */jsx(PopperPrimitive.Popper, {
736
- allowFlip,
737
- stayInFrame,
738
- ...rest,
806
+ const MenuArrow = React.forwardRef(function MenuArrow2(props, forwardedRef) {
807
+ const {
808
+ scope = MENU_CONTEXT,
809
+ unstyled = process.env.TAMAGUI_HEADLESS === "1",
810
+ ...rest
811
+ } = props;
812
+ return /* @__PURE__ */jsx(PopperPrimitive.PopperArrow, {
813
+ scope,
814
+ componentName: "PopperArrow",
815
+ unstyled,
816
+ ...(!unstyled && {
817
+ backgroundColor: "$background"
818
+ }),
819
+ ...rest,
820
+ ref: forwardedRef
821
+ });
822
+ });
823
+ const SUB_NAME = "MenuSub";
824
+ const {
825
+ Provider: MenuSubProvider,
826
+ useStyledContext: useMenuSubContext
827
+ } = createStyledContext();
828
+ const MenuSub = props => {
829
+ const isTouchDevice = useIsTouchDevice();
830
+ const {
831
+ scope = MENU_CONTEXT
832
+ } = props;
833
+ const rootContext = useMenuRootContext(scope);
834
+ const parentPopperContext = PopperPrimitive.usePopperContext(scope);
835
+ const parentSide = parentPopperContext.placement?.split("-")[0];
836
+ const isNestedSubmenu = parentSide === "left" || parentSide === "right";
837
+ const defaultPlacement = isTouchDevice ? "bottom" : isNestedSubmenu ? `${parentSide}-start` : rootContext.dir === "rtl" ? "left-start" : "right-start";
838
+ const {
839
+ children,
840
+ open = false,
841
+ onOpenChange,
842
+ allowFlip: allowFlipProp = {
843
+ padding: 10
844
+ },
845
+ stayInFrame = {
846
+ padding: 10
847
+ },
848
+ placement = defaultPlacement,
849
+ ...rest
850
+ } = props;
851
+ const allowFlip = React.useMemo(() => {
852
+ if (!isNestedSubmenu || typeof allowFlipProp === "boolean") return allowFlipProp;
853
+ if (allowFlipProp.fallbackPlacements) return allowFlipProp;
854
+ const side = placement.split("-")[0];
855
+ const align = placement.split("-")[1] || "start";
856
+ const otherAlign = align === "start" ? "end" : "start";
857
+ if (side === "left" || side === "right") {
858
+ const oppositeSide = side === "right" ? "left" : "right";
859
+ return {
860
+ ...(typeof allowFlipProp === "object" ? allowFlipProp : {}),
861
+ fallbackPlacements: [`${side}-${otherAlign}`, `${oppositeSide}-${align}`, `${oppositeSide}-${otherAlign}`]
862
+ };
863
+ }
864
+ return allowFlipProp;
865
+ }, [isNestedSubmenu, allowFlipProp, placement]);
866
+ const parentMenuContext = useMenuContext(scope);
867
+ const [trigger, setTrigger] = React.useState(null);
868
+ const [content, setContent] = React.useState(null);
869
+ const handleOpenChange = useCallbackRef(onOpenChange);
870
+ React.useEffect(() => {
871
+ if (parentMenuContext.open === false) handleOpenChange(false);
872
+ return () => handleOpenChange(false);
873
+ }, [parentMenuContext.open, handleOpenChange]);
874
+ return /* @__PURE__ */jsx(PopperPrimitive.Popper, {
875
+ open,
876
+ placement,
877
+ allowFlip,
878
+ stayInFrame,
879
+ ...rest,
880
+ scope,
881
+ children: /* @__PURE__ */jsx(MenuProvider, {
739
882
  scope,
740
- children: /* @__PURE__ */jsx(MenuProvider, {
883
+ open,
884
+ onOpenChange: handleOpenChange,
885
+ content,
886
+ onContentChange: setContent,
887
+ children: /* @__PURE__ */jsx(MenuSubProvider, {
741
888
  scope,
742
- open,
743
- onOpenChange: handleOpenChange,
744
- content,
745
- onContentChange: setContent,
746
- children: /* @__PURE__ */jsx(MenuSubProvider, {
747
- scope,
748
- contentId: useId(),
749
- triggerId: useId(),
750
- trigger,
751
- onTriggerChange: setTrigger,
752
- children
753
- })
889
+ contentId: useId(),
890
+ triggerId: useId(),
891
+ trigger,
892
+ onTriggerChange: setTrigger,
893
+ children
754
894
  })
755
- });
756
- };
895
+ })
896
+ });
897
+ };
757
898
  MenuSub.displayName = SUB_NAME;
758
- const SUB_TRIGGER_NAME = "MenuSubTrigger",
759
- MenuSubTrigger = React.forwardRef((props, forwardedRef) => {
760
- const scope = props.scope || MENU_CONTEXT,
761
- context = useMenuContext(scope),
762
- rootContext = useMenuRootContext(scope),
763
- subContext = useMenuSubContext(scope),
764
- contentContext = useMenuContentContext(scope),
765
- popperContext = PopperPrimitive.usePopperContext(scope),
766
- openTimerRef = React.useRef(null),
767
- {
768
- pointerGraceTimerRef,
769
- onPointerGraceIntentChange
770
- } = contentContext,
771
- placementSide = popperContext.placement?.split("-")[0],
772
- effectiveDir = placementSide === "left" ? "rtl" : placementSide === "right" ? "ltr" : rootContext.dir,
773
- clearOpenTimer = React.useCallback(() => {
774
- openTimerRef.current && window.clearTimeout(openTimerRef.current), openTimerRef.current = null;
775
- }, []);
776
- return React.useEffect(() => clearOpenTimer, [clearOpenTimer]), React.useEffect(() => {
777
- const pointerGraceTimer = pointerGraceTimerRef.current;
778
- return () => {
779
- window.clearTimeout(pointerGraceTimer), onPointerGraceIntentChange(null);
780
- };
781
- }, [pointerGraceTimerRef, onPointerGraceIntentChange]), /* @__PURE__ */jsx(MenuAnchor, {
782
- componentName: SUB_TRIGGER_NAME,
783
- asChild: "except-style",
784
- scope,
785
- children: /* @__PURE__ */jsx(MenuItemImpl, {
786
- id: subContext.triggerId,
787
- "aria-haspopup": "menu",
788
- "aria-expanded": context.open,
789
- "aria-controls": subContext.contentId,
790
- "data-state": getOpenState(context.open),
791
- outlineStyle: "none",
792
- ...props,
793
- ref: composeRefs(forwardedRef, subContext.onTriggerChange),
794
- onPress: event => {
795
- props.onPress?.(event), !(props.disabled || event.defaultPrevented) && (isWeb && event.currentTarget.focus(), context.open || context.onOpenChange(!0));
796
- },
797
- onPointerMove: composeEventHandlers(props.onPointerMove,
798
- // @ts-ignore
799
- whenMouse(event => {
800
- contentContext.onItemEnter(event), !event.defaultPrevented && !props.disabled && !context.open && !openTimerRef.current && (contentContext.onPointerGraceIntentChange(null), openTimerRef.current = window.setTimeout(() => {
801
- context.onOpenChange(!0), clearOpenTimer();
802
- }, 100));
803
- })),
804
- onPointerLeave: composeEventHandlers(props.onPointerLeave, eventIn => {
805
- const event = eventIn;
806
- clearOpenTimer();
807
- const contentRect = context.content?.getBoundingClientRect();
808
- if (contentRect) {
809
- const contentEl = context.content,
810
- side = (contentEl?.dataset?.side ? contentEl : contentEl?.querySelector("[data-side]"))?.dataset?.side || "right",
811
- rightSide = side === "right",
812
- bleed = rightSide ? -5 : 5,
813
- contentNearEdge = contentRect[rightSide ? "left" : "right"],
814
- contentFarEdge = contentRect[rightSide ? "right" : "left"],
815
- polygon = {
816
- area: [
817
- // Apply a bleed on clientX to ensure that our exit point is
818
- // consistently within polygon bounds
819
- {
820
- x: event.clientX + bleed,
821
- y: event.clientY
822
- }, {
823
- x: contentNearEdge,
824
- y: contentRect.top
825
- }, {
826
- x: contentFarEdge,
827
- y: contentRect.top
828
- }, {
829
- x: contentFarEdge,
830
- y: contentRect.bottom
831
- }, {
832
- x: contentNearEdge,
833
- y: contentRect.bottom
834
- }],
835
- side
836
- };
837
- contentContext.onPointerGraceIntentChange(polygon), window.clearTimeout(pointerGraceTimerRef.current), pointerGraceTimerRef.current = window.setTimeout(() => contentContext.onPointerGraceIntentChange(null), 300);
838
- } else if (isWeb && subContext.trigger) {
839
- const triggerRect = subContext.trigger?.getBoundingClientRect();
840
- if (triggerRect) {
841
- const placementSide2 = popperContext.placement?.split("-")[0],
842
- side = placementSide2 === "left" || placementSide2 === "right" ? placementSide2 : rootContext.dir === "rtl" ? "left" : "right",
843
- rightSide = side === "right",
844
- bleed = rightSide ? -5 : 5,
845
- nearEdge = rightSide ? triggerRect.right + 4 : triggerRect.left - 4,
846
- farEdge = rightSide ? nearEdge + 200 : nearEdge - 200,
847
- polygon = {
848
- area: [{
849
- x: event.clientX + bleed,
850
- y: event.clientY
851
- }, {
852
- x: nearEdge,
853
- y: triggerRect.top - 50
854
- }, {
855
- x: farEdge,
856
- y: triggerRect.top - 50
857
- }, {
858
- x: farEdge,
859
- y: triggerRect.bottom + 50
860
- }, {
861
- x: nearEdge,
862
- y: triggerRect.bottom + 50
863
- }],
864
- side
865
- };
866
- contentContext.onPointerGraceIntentChange(polygon), window.clearTimeout(pointerGraceTimerRef.current), pointerGraceTimerRef.current = window.setTimeout(() => contentContext.onPointerGraceIntentChange(null), 300);
899
+ const SUB_TRIGGER_NAME = "MenuSubTrigger";
900
+ const MenuSubTrigger = React.forwardRef((props, forwardedRef) => {
901
+ const scope = props.scope || MENU_CONTEXT;
902
+ const context = useMenuContext(scope);
903
+ const rootContext = useMenuRootContext(scope);
904
+ const subContext = useMenuSubContext(scope);
905
+ const contentContext = useMenuContentContext(scope);
906
+ const popperContext = PopperPrimitive.usePopperContext(scope);
907
+ const openTimerRef = React.useRef(null);
908
+ const {
909
+ pointerGraceTimerRef,
910
+ onPointerGraceIntentChange
911
+ } = contentContext;
912
+ const effectiveDir = rootContext.dir;
913
+ const clearOpenTimer = React.useCallback(() => {
914
+ if (openTimerRef.current) window.clearTimeout(openTimerRef.current);
915
+ openTimerRef.current = null;
916
+ }, []);
917
+ React.useEffect(() => clearOpenTimer, [clearOpenTimer]);
918
+ React.useEffect(() => {
919
+ const pointerGraceTimer = pointerGraceTimerRef.current;
920
+ return () => {
921
+ window.clearTimeout(pointerGraceTimer);
922
+ onPointerGraceIntentChange(null);
923
+ };
924
+ }, [pointerGraceTimerRef, onPointerGraceIntentChange]);
925
+ return /* @__PURE__ */jsx(MenuAnchor, {
926
+ componentName: SUB_TRIGGER_NAME,
927
+ asChild: "except-style",
928
+ scope,
929
+ children: /* @__PURE__ */jsx(MenuItemImpl, {
930
+ id: subContext.triggerId,
931
+ "aria-haspopup": "menu",
932
+ "aria-expanded": context.open,
933
+ "aria-controls": subContext.contentId,
934
+ "data-state": getOpenState(context.open),
935
+ outlineStyle: "none",
936
+ ...props,
937
+ ref: composeRefs(forwardedRef, subContext.onTriggerChange),
938
+ onPress: event => {
939
+ props.onPress?.(event);
940
+ if (props.disabled || event.defaultPrevented) return;
941
+ if (isWeb) {
942
+ event.currentTarget.focus();
943
+ }
944
+ if (!context.open) context.onOpenChange(true);
945
+ },
946
+ onPointerMove: composeEventHandlers(props.onPointerMove,
947
+ // @ts-ignore
948
+ whenMouse(event => {
949
+ contentContext.onItemEnter(event);
950
+ if (event.defaultPrevented) return;
951
+ if (!props.disabled && !context.open && !openTimerRef.current) {
952
+ contentContext.onPointerGraceIntentChange(null);
953
+ openTimerRef.current = window.setTimeout(() => {
954
+ context.onOpenChange(true);
955
+ clearOpenTimer();
956
+ }, 100);
957
+ }
958
+ })),
959
+ onPointerLeave: composeEventHandlers(props.onPointerLeave, eventIn => {
960
+ const event = eventIn;
961
+ clearOpenTimer();
962
+ const contentRect = context.content?.getBoundingClientRect();
963
+ if (contentRect) {
964
+ const contentEl = context.content;
965
+ const sideEl = contentEl?.dataset?.side ? contentEl : contentEl?.querySelector("[data-side]");
966
+ const side = sideEl?.dataset?.side || "right";
967
+ const rightSide = side === "right";
968
+ const bleed = rightSide ? -5 : 5;
969
+ const contentNearEdge = contentRect[rightSide ? "left" : "right"];
970
+ const contentFarEdge = contentRect[rightSide ? "right" : "left"];
971
+ const polygon = {
972
+ area: [
973
+ // Apply a bleed on clientX to ensure that our exit point is
974
+ // consistently within polygon bounds
975
+ {
976
+ x: event.clientX + bleed,
977
+ y: event.clientY
978
+ }, {
979
+ x: contentNearEdge,
980
+ y: contentRect.top
981
+ }, {
982
+ x: contentFarEdge,
983
+ y: contentRect.top
984
+ }, {
985
+ x: contentFarEdge,
986
+ y: contentRect.bottom
987
+ }, {
988
+ x: contentNearEdge,
989
+ y: contentRect.bottom
990
+ }],
991
+ side
992
+ };
993
+ contentContext.onPointerGraceIntentChange(polygon);
994
+ window.clearTimeout(pointerGraceTimerRef.current);
995
+ pointerGraceTimerRef.current = window.setTimeout(() => contentContext.onPointerGraceIntentChange(null), 300);
996
+ } else if (isWeb && subContext.trigger) {
997
+ const triggerEl = subContext.trigger;
998
+ const triggerRect = triggerEl?.getBoundingClientRect();
999
+ if (triggerRect) {
1000
+ const placementSide = popperContext.placement?.split("-")[0];
1001
+ const side = placementSide === "left" || placementSide === "right" ? placementSide : rootContext.dir === "rtl" ? "left" : "right";
1002
+ const rightSide = side === "right";
1003
+ const bleed = rightSide ? -5 : 5;
1004
+ const nearEdge = rightSide ? triggerRect.right + 4 : triggerRect.left - 4;
1005
+ const farEdge = rightSide ? nearEdge + 200 : nearEdge - 200;
1006
+ const polygon = {
1007
+ area: [{
1008
+ x: event.clientX + bleed,
1009
+ y: event.clientY
1010
+ }, {
1011
+ x: nearEdge,
1012
+ y: triggerRect.top - 50
1013
+ }, {
1014
+ x: farEdge,
1015
+ y: triggerRect.top - 50
1016
+ }, {
1017
+ x: farEdge,
1018
+ y: triggerRect.bottom + 50
1019
+ }, {
1020
+ x: nearEdge,
1021
+ y: triggerRect.bottom + 50
1022
+ }],
1023
+ side
1024
+ };
1025
+ contentContext.onPointerGraceIntentChange(polygon);
1026
+ window.clearTimeout(pointerGraceTimerRef.current);
1027
+ pointerGraceTimerRef.current = window.setTimeout(() => contentContext.onPointerGraceIntentChange(null), 300);
1028
+ }
1029
+ } else {
1030
+ contentContext.onTriggerLeave(event);
1031
+ if (event.defaultPrevented) return;
1032
+ contentContext.onPointerGraceIntentChange(null);
1033
+ }
1034
+ }),
1035
+ ...(isWeb ? {
1036
+ onKeyDown: composeEventHandlers(props.onKeyDown, event => {
1037
+ const isTypingAhead = contentContext.searchRef.current !== "";
1038
+ if (props.disabled || isTypingAhead && event.key === " ") return;
1039
+ const willOpen = SUB_OPEN_KEYS[effectiveDir].includes(event.key);
1040
+ if (willOpen) {
1041
+ if (context.open && context.content) {
1042
+ const contentEl = context.content;
1043
+ const firstItem = contentEl.querySelector?.('[role="menuitem"]:not([data-disabled])');
1044
+ if (firstItem) {
1045
+ firstItem.focus({
1046
+ focusVisible: true
1047
+ });
1048
+ event.preventDefault();
1049
+ return;
1050
+ }
867
1051
  }
868
- } else {
869
- if (contentContext.onTriggerLeave(event), event.defaultPrevented) return;
870
- contentContext.onPointerGraceIntentChange(null);
1052
+ const triggerEl = event.currentTarget;
1053
+ popperContext.refs?.setReference(triggerEl);
1054
+ context.onOpenChange(true);
1055
+ requestAnimationFrame(() => {
1056
+ popperContext.update?.();
1057
+ });
1058
+ context.content?.focus({
1059
+ focusVisible: true
1060
+ });
1061
+ event.preventDefault();
871
1062
  }
1063
+ })
1064
+ } : null)
1065
+ })
1066
+ });
1067
+ });
1068
+ MenuSubTrigger.displayName = SUB_TRIGGER_NAME;
1069
+ const SUB_CONTENT_NAME = "MenuSubContent";
1070
+ const MenuSubContentFrame = styled(PopperPrimitive.PopperContentFrame, {
1071
+ name: SUB_CONTENT_NAME
1072
+ });
1073
+ const MenuSubContent = MenuSubContentFrame.styleable((props, forwardedRef) => {
1074
+ const scope = props.scope || MENU_CONTEXT;
1075
+ const portalContext = usePortalContext(scope);
1076
+ const {
1077
+ forceMount = portalContext.forceMount,
1078
+ ...subContentProps
1079
+ } = props;
1080
+ const context = useMenuContext(scope);
1081
+ const rootContext = useMenuRootContext(scope);
1082
+ const subContext = useMenuSubContext(scope);
1083
+ const popperContext = PopperPrimitive.usePopperContext(scope);
1084
+ const ref = React.useRef(null);
1085
+ const composedRefs = useComposedRefs(forwardedRef, ref);
1086
+ const placementSide = popperContext.placement?.split("-")[0];
1087
+ const dataSide = placementSide === "left" || placementSide === "right" ? placementSide : rootContext.dir === "rtl" ? "left" : "right";
1088
+ const effectiveDir = rootContext.dir;
1089
+ return /* @__PURE__ */jsx(Collection.Provider, {
1090
+ scope,
1091
+ children: /* @__PURE__ */jsx(Collection.Slot, {
1092
+ scope,
1093
+ children: /* @__PURE__ */jsx(MenuContentImpl, {
1094
+ id: subContext.contentId,
1095
+ "aria-labelledby": subContext.triggerId,
1096
+ ...subContentProps,
1097
+ ref: composedRefs,
1098
+ "data-side": dataSide,
1099
+ disableOutsidePointerEvents: false,
1100
+ disableOutsideScroll: false,
1101
+ trapFocus: false,
1102
+ onOpenAutoFocus: event => {
1103
+ if (rootContext.isUsingKeyboardRef.current) {
1104
+ const root = ref.current;
1105
+ const content = root?.querySelector?.("[data-tamagui-menu-content]");
1106
+ (content || root)?.focus({
1107
+ preventScroll: true
1108
+ });
1109
+ }
1110
+ event.preventDefault();
1111
+ },
1112
+ onCloseAutoFocus: event => event.preventDefault(),
1113
+ onFocusOutside: composeEventHandlers(props.onFocusOutside, event => {
1114
+ if (event.target !== subContext.trigger) context.onOpenChange(false);
1115
+ }),
1116
+ onEscapeKeyDown: composeEventHandlers(props.onEscapeKeyDown, event => {
1117
+ context.onOpenChange(false);
1118
+ subContext.trigger?.focus({
1119
+ focusVisible: true
1120
+ });
1121
+ event.preventDefault();
872
1122
  }),
873
1123
  ...(isWeb ? {
874
1124
  onKeyDown: composeEventHandlers(props.onKeyDown, event => {
875
- const isTypingAhead = contentContext.searchRef.current !== "";
876
- if (props.disabled || isTypingAhead && event.key === " ") return;
877
- if (SUB_OPEN_KEYS[effectiveDir].includes(event.key)) {
878
- if (context.open && context.content) {
879
- const firstItem = context.content.querySelector?.('[role="menuitem"]:not([data-disabled])');
880
- if (firstItem) {
881
- firstItem.focus({
882
- focusVisible: !0
883
- }), event.preventDefault();
884
- return;
885
- }
886
- }
887
- const triggerEl = event.currentTarget;
888
- popperContext.refs?.setReference(triggerEl), context.onOpenChange(!0), requestAnimationFrame(() => {
889
- popperContext.update?.();
890
- }), context.content?.focus({
891
- focusVisible: !0
892
- }), event.preventDefault();
1125
+ const isKeyDownInside = event.currentTarget.contains(event.target);
1126
+ const isCloseKey = SUB_CLOSE_KEYS[effectiveDir].includes(event.key);
1127
+ if (isKeyDownInside && isCloseKey) {
1128
+ context.onOpenChange(false);
1129
+ subContext.trigger?.focus({
1130
+ focusVisible: true
1131
+ });
1132
+ event.preventDefault();
893
1133
  }
894
1134
  })
895
1135
  } : null)
896
1136
  })
897
- });
898
- });
899
- MenuSubTrigger.displayName = SUB_TRIGGER_NAME;
900
- const SUB_CONTENT_NAME = "MenuSubContent",
901
- MenuSubContent = React.forwardRef((props, forwardedRef) => {
902
- const scope = props.scope || MENU_CONTEXT,
903
- portalContext = usePortalContext(scope),
904
- {
905
- forceMount = portalContext.forceMount,
906
- ...subContentProps
907
- } = props,
908
- context = useMenuContext(scope),
909
- rootContext = useMenuRootContext(scope),
910
- subContext = useMenuSubContext(scope),
911
- popperContext = PopperPrimitive.usePopperContext(scope),
912
- ref = React.useRef(null),
913
- composedRefs = useComposedRefs(forwardedRef, ref),
914
- placementSide = popperContext.placement?.split("-")[0],
915
- dataSide = placementSide === "left" || placementSide === "right" ? placementSide : rootContext.dir === "rtl" ? "left" : "right",
916
- effectiveDir = placementSide === "left" ? "rtl" : placementSide === "right" ? "ltr" : rootContext.dir;
917
- return /* @__PURE__ */jsx(Collection.Provider, {
918
- scope,
919
- children: /* @__PURE__ */jsx(Collection.Slot, {
920
- scope,
921
- children: /* @__PURE__ */jsx(MenuContentImpl, {
922
- id: subContext.contentId,
923
- "aria-labelledby": subContext.triggerId,
924
- ...subContentProps,
925
- ref: composedRefs,
926
- "data-side": dataSide,
927
- disableOutsidePointerEvents: !1,
928
- disableOutsideScroll: !1,
929
- trapFocus: !1,
930
- onOpenAutoFocus: event => {
931
- rootContext.isUsingKeyboardRef.current && document.querySelector("[data-tamagui-menu-content][data-side]")?.focus(), event.preventDefault();
932
- },
933
- onCloseAutoFocus: event => event.preventDefault(),
934
- onFocusOutside: composeEventHandlers(props.onFocusOutside, event => {
935
- event.target !== subContext.trigger && context.onOpenChange(!1);
936
- }),
937
- onEscapeKeyDown: composeEventHandlers(props.onEscapeKeyDown, event => {
938
- context.onOpenChange(!1), subContext.trigger?.focus({
939
- focusVisible: !0
940
- }), event.preventDefault();
941
- }),
942
- ...(isWeb ? {
943
- onKeyDown: composeEventHandlers(props.onKeyDown, event => {
944
- const isKeyDownInside = event.currentTarget.contains(event.target),
945
- isCloseKey = SUB_CLOSE_KEYS[effectiveDir].includes(event.key);
946
- isKeyDownInside && isCloseKey && (context.onOpenChange(!1), subContext.trigger?.focus({
947
- focusVisible: !0
948
- }), event.preventDefault());
949
- })
950
- } : null)
951
- })
952
- })
953
- });
1137
+ })
954
1138
  });
1139
+ });
955
1140
  MenuSubContent.displayName = SUB_CONTENT_NAME;
956
- const Anchor = MenuAnchor,
957
- Portal = MenuPortal,
958
- Content = MenuContent,
959
- Group = _MenuGroup.styleable((props, ref) => /* @__PURE__ */jsx(_MenuGroup, {
1141
+ const Anchor = MenuAnchor;
1142
+ const Portal = MenuPortal;
1143
+ const Content = MenuContent;
1144
+ const Group = _MenuGroup.styleable((props, ref) => {
1145
+ return /* @__PURE__ */jsx(_MenuGroup, {
960
1146
  ...props,
961
1147
  ref
962
- }));
1148
+ });
1149
+ });
963
1150
  Group.displayName = "MenuGroup";
964
- const Label = _Label.styleable((props, ref) => /* @__PURE__ */jsx(_Label, {
965
- ...props,
966
- ref
967
- }));
1151
+ const Label = _Label.styleable((props, ref) => {
1152
+ return /* @__PURE__ */jsx(_Label, {
1153
+ ...props,
1154
+ ref
1155
+ });
1156
+ });
968
1157
  Label.displayName = "MenuLabel";
969
- const Item = MenuItem,
970
- CheckboxItem = MenuCheckboxItem,
971
- RadioGroup = MenuRadioGroup,
972
- RadioItem = MenuRadioItem,
973
- ItemIndicator = MenuItemIndicator,
974
- Separator = _Separator.styleable((props, ref) => /* @__PURE__ */jsx(_Separator, {
1158
+ const Item = MenuItem;
1159
+ const CheckboxItem = MenuCheckboxItem;
1160
+ const RadioGroup = MenuRadioGroup;
1161
+ const RadioItem = MenuRadioItem;
1162
+ const ItemIndicator = MenuItemIndicator;
1163
+ const Separator = _Separator.styleable((props, ref) => {
1164
+ return /* @__PURE__ */jsx(_Separator, {
975
1165
  ...props,
976
1166
  ref
977
- }));
978
- return Separator.displayName = "MenuSeparator", {
979
- Menu: withStaticProperties(MenuComp, {
980
- Anchor,
981
- Portal,
982
- Content,
983
- Group,
984
- Label,
985
- Item,
986
- CheckboxItem,
987
- RadioGroup,
988
- RadioItem,
989
- ItemIndicator,
990
- Separator,
991
- Arrow: MenuArrow,
992
- Sub: MenuSub,
993
- SubTrigger: MenuSubTrigger,
994
- SubContent: MenuSubContent,
995
- ItemTitle: MenuItemTitle,
996
- ItemSubtitle: MenuItemSubTitle,
997
- ItemImage: MenuItemImage,
998
- ItemIcon: MenuItemIcon
999
- })
1167
+ });
1168
+ });
1169
+ Separator.displayName = "MenuSeparator";
1170
+ const Arrow = MenuArrow;
1171
+ const Sub = MenuSub;
1172
+ const SubTrigger = MenuSubTrigger;
1173
+ const SubContent = MenuSubContent;
1174
+ const ItemTitle = MenuItemTitle;
1175
+ const ItemSubtitle = MenuItemSubTitle;
1176
+ const ItemImage = MenuItemImage;
1177
+ const ItemIcon = MenuItemIcon;
1178
+ const Menu = withStaticProperties(MenuComp, {
1179
+ Anchor,
1180
+ Portal,
1181
+ Content,
1182
+ Group,
1183
+ Label,
1184
+ Item,
1185
+ CheckboxItem,
1186
+ RadioGroup,
1187
+ RadioItem,
1188
+ ItemIndicator,
1189
+ Separator,
1190
+ Arrow,
1191
+ Sub,
1192
+ SubTrigger,
1193
+ SubContent,
1194
+ ItemTitle,
1195
+ ItemSubtitle,
1196
+ ItemImage,
1197
+ ItemIcon
1198
+ });
1199
+ return {
1200
+ Menu
1000
1201
  };
1001
1202
  }
1002
1203
  function getOpenState(open) {
@@ -1010,18 +1211,25 @@ function getCheckedState(checked) {
1010
1211
  }
1011
1212
  function focusFirst(candidates, options) {
1012
1213
  const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;
1013
- for (const candidate of candidates) if (candidate === PREVIOUSLY_FOCUSED_ELEMENT || (candidate.focus({
1014
- focusVisible: options?.focusVisible
1015
- }), document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT)) return;
1214
+ for (const candidate of candidates) {
1215
+ if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return;
1216
+ candidate.focus({
1217
+ preventScroll: true,
1218
+ focusVisible: options?.focusVisible
1219
+ });
1220
+ if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return;
1221
+ }
1016
1222
  }
1017
1223
  function wrapArray(array, startIndex) {
1018
1224
  return array.map((_, index) => array[(startIndex + index) % array.length]);
1019
1225
  }
1020
1226
  function getNextMatch(values, search, currentMatch) {
1021
- const normalizedSearch = search.length > 1 && Array.from(search).every(char => char === search[0]) ? search[0] : search,
1022
- currentMatchIndex = currentMatch ? values.indexOf(currentMatch) : -1;
1227
+ const isRepeated = search.length > 1 && Array.from(search).every(char => char === search[0]);
1228
+ const normalizedSearch = isRepeated ? search[0] : search;
1229
+ const currentMatchIndex = currentMatch ? values.indexOf(currentMatch) : -1;
1023
1230
  let wrappedValues = wrapArray(values, Math.max(currentMatchIndex, 0));
1024
- normalizedSearch.length === 1 && (wrappedValues = wrappedValues.filter(v => v !== currentMatch));
1231
+ const excludeCurrentMatch = normalizedSearch.length === 1;
1232
+ if (excludeCurrentMatch) wrappedValues = wrappedValues.filter(v => v !== currentMatch);
1025
1233
  const nextMatch = wrappedValues.find(value => value.toLowerCase().startsWith(normalizedSearch.toLowerCase()));
1026
1234
  return nextMatch !== currentMatch ? nextMatch : void 0;
1027
1235
  }
@@ -1030,18 +1238,19 @@ function isPointInPolygon(point, polygon) {
1030
1238
  x,
1031
1239
  y
1032
1240
  } = point;
1033
- let inside = !1;
1241
+ let inside = false;
1034
1242
  for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
1035
- const xi = polygon[i].x,
1036
- yi = polygon[i].y,
1037
- xj = polygon[j].x,
1038
- yj = polygon[j].y;
1039
- yi > y != yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi && (inside = !inside);
1243
+ const xi = polygon[i].x;
1244
+ const yi = polygon[i].y;
1245
+ const xj = polygon[j].x;
1246
+ const yj = polygon[j].y;
1247
+ const intersect = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi;
1248
+ if (intersect) inside = !inside;
1040
1249
  }
1041
1250
  return inside;
1042
1251
  }
1043
1252
  function isPointerInGraceArea(event, area) {
1044
- if (!area) return !1;
1253
+ if (!area) return false;
1045
1254
  const cursorPos = {
1046
1255
  x: event.clientX,
1047
1256
  y: event.clientY