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