@tamagui/create-menu 2.0.0-rc.9 → 2.0.0

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