@octanejs/radix 0.1.31 → 0.1.33

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 (60) hide show
  1. package/dist/cjs/AccessibleIcon.cjs +56 -0
  2. package/dist/cjs/Accordion.cjs +272 -0
  3. package/dist/cjs/AlertDialog.cjs +144 -0
  4. package/dist/cjs/Arrow.cjs +43 -0
  5. package/dist/cjs/AspectRatio.cjs +56 -0
  6. package/dist/cjs/Avatar.cjs +150 -0
  7. package/dist/cjs/Checkbox.cjs +281 -0
  8. package/dist/cjs/Collapsible.cjs +176 -0
  9. package/dist/cjs/ContextMenu.cjs +315 -0
  10. package/dist/cjs/Dialog.cjs +291 -0
  11. package/dist/cjs/DismissableLayer.cjs +382 -0
  12. package/dist/cjs/DropdownMenu.cjs +296 -0
  13. package/dist/cjs/FocusScope.cjs +257 -0
  14. package/dist/cjs/Form.cjs +537 -0
  15. package/dist/cjs/HoverCard.cjs +309 -0
  16. package/dist/cjs/Label.cjs +42 -0
  17. package/dist/cjs/Menu.cjs +925 -0
  18. package/dist/cjs/Menubar.cjs +475 -0
  19. package/dist/cjs/NavigationMenu.cjs +942 -0
  20. package/dist/cjs/OneTimePasswordField.cjs +729 -0
  21. package/dist/cjs/PasswordToggleField.cjs +377 -0
  22. package/dist/cjs/Popover.cjs +340 -0
  23. package/dist/cjs/Popper.cjs +368 -0
  24. package/dist/cjs/Portal.cjs +40 -0
  25. package/dist/cjs/Presence.cjs +183 -0
  26. package/dist/cjs/Primitive.cjs +63 -0
  27. package/dist/cjs/Progress.cjs +111 -0
  28. package/dist/cjs/Radio.cjs +240 -0
  29. package/dist/cjs/RadioGroup.cjs +216 -0
  30. package/dist/cjs/RovingFocusGroup.cjs +253 -0
  31. package/dist/cjs/ScrollArea.cjs +828 -0
  32. package/dist/cjs/Select.cjs +1429 -0
  33. package/dist/cjs/Separator.cjs +51 -0
  34. package/dist/cjs/Slider.cjs +634 -0
  35. package/dist/cjs/Slot.cjs +97 -0
  36. package/dist/cjs/Switch.cjs +253 -0
  37. package/dist/cjs/Tabs.cjs +195 -0
  38. package/dist/cjs/Toast.cjs +733 -0
  39. package/dist/cjs/Toggle.cjs +54 -0
  40. package/dist/cjs/ToggleGroup.cjs +174 -0
  41. package/dist/cjs/Toolbar.cjs +165 -0
  42. package/dist/cjs/Tooltip.cjs +628 -0
  43. package/dist/cjs/VisuallyHidden.cjs +52 -0
  44. package/dist/cjs/collection.cjs +95 -0
  45. package/dist/cjs/compose-event-handlers.cjs +35 -0
  46. package/dist/cjs/compose-refs.cjs +68 -0
  47. package/dist/cjs/context.cjs +96 -0
  48. package/dist/cjs/direction.cjs +41 -0
  49. package/dist/cjs/focus-guards.cjs +76 -0
  50. package/dist/cjs/index.cjs +174 -0
  51. package/dist/cjs/internal.cjs +51 -0
  52. package/dist/cjs/scroll-lock.cjs +67 -0
  53. package/dist/cjs/use-callback-ref.cjs +47 -0
  54. package/dist/cjs/use-effect-event.cjs +52 -0
  55. package/dist/cjs/use-is-hydrated.cjs +43 -0
  56. package/dist/cjs/use-previous.cjs +47 -0
  57. package/dist/cjs/use-size.cjs +69 -0
  58. package/dist/cjs/useControllableState.cjs +80 -0
  59. package/dist/cjs/useId.cjs +36 -0
  60. package/package.json +14 -7
@@ -0,0 +1,925 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ 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", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var Menu_exports = {};
30
+ __export(Menu_exports, {
31
+ Anchor: () => Anchor,
32
+ Arrow: () => Arrow,
33
+ CheckboxItem: () => CheckboxItem,
34
+ Content: () => Content,
35
+ Group: () => Group,
36
+ Item: () => Item,
37
+ ItemIndicator: () => ItemIndicator,
38
+ Label: () => Label,
39
+ Menu: () => Root,
40
+ MenuAnchor: () => Anchor,
41
+ MenuContent: () => Content,
42
+ MenuItem: () => Item,
43
+ Portal: () => Portal,
44
+ RadioGroup: () => RadioGroup,
45
+ RadioItem: () => RadioItem,
46
+ Root: () => Root,
47
+ Separator: () => Separator,
48
+ Sub: () => Sub,
49
+ SubContent: () => SubContent,
50
+ SubTrigger: () => SubTrigger,
51
+ createMenuScope: () => createMenuScope
52
+ });
53
+ module.exports = __toCommonJS(Menu_exports);
54
+ var import_octane = require("octane");
55
+ var import_aria_hidden = require("aria-hidden");
56
+ var import_collection = require("./collection.cjs");
57
+ var import_compose_event_handlers = require("./compose-event-handlers.cjs");
58
+ var import_compose_refs = require("./compose-refs.cjs");
59
+ var import_context = require("./context.cjs");
60
+ var import_direction = require("./direction.cjs");
61
+ var import_DismissableLayer = require("./DismissableLayer.cjs");
62
+ var import_FocusScope = require("./FocusScope.cjs");
63
+ var import_focus_guards = require("./focus-guards.cjs");
64
+ var import_internal = require("./internal.cjs");
65
+ var PopperPrimitive = __toESM(require("./Popper.cjs"), 1);
66
+ var import_Popper = require("./Popper.cjs");
67
+ var import_Portal = require("./Portal.cjs");
68
+ var import_Presence = require("./Presence.cjs");
69
+ var import_Primitive = require("./Primitive.cjs");
70
+ var RovingFocusGroup = __toESM(require("./RovingFocusGroup.cjs"), 1);
71
+ var import_RovingFocusGroup = require("./RovingFocusGroup.cjs");
72
+ var import_scroll_lock = require("./scroll-lock.cjs");
73
+ var import_use_callback_ref = require("./use-callback-ref.cjs");
74
+ var import_useId = require("./useId.cjs");
75
+ const SELECTION_KEYS = ["Enter", " "];
76
+ const FIRST_KEYS = ["ArrowDown", "PageUp", "Home"];
77
+ const LAST_KEYS = ["ArrowUp", "PageDown", "End"];
78
+ const FIRST_LAST_KEYS = [...FIRST_KEYS, ...LAST_KEYS];
79
+ const SUB_OPEN_KEYS = {
80
+ ltr: [...SELECTION_KEYS, "ArrowRight"],
81
+ rtl: [...SELECTION_KEYS, "ArrowLeft"]
82
+ };
83
+ const SUB_CLOSE_KEYS = {
84
+ ltr: ["ArrowLeft"],
85
+ rtl: ["ArrowRight"]
86
+ };
87
+ const MENU_NAME = "Menu";
88
+ const [Collection, useCollection, createCollectionScope] = (0, import_collection.createCollection)(MENU_NAME);
89
+ const [createMenuContext, createMenuScope] = (0, import_context.createContextScope)(MENU_NAME, [
90
+ createCollectionScope,
91
+ import_Popper.createPopperScope,
92
+ import_RovingFocusGroup.createRovingFocusGroupScope
93
+ ]);
94
+ const usePopperScope = (0, import_Popper.createPopperScope)();
95
+ const useRovingFocusGroupScope = (0, import_RovingFocusGroup.createRovingFocusGroupScope)();
96
+ const [MenuProvider, useMenuContext] = createMenuContext(MENU_NAME);
97
+ const [MenuRootProvider, useMenuRootContext] = createMenuContext(MENU_NAME);
98
+ function Root(props) {
99
+ const slot = (0, import_internal.S)("Menu.Root");
100
+ const { __scopeMenu, open = false, children, dir, onOpenChange, modal = true } = props ?? {};
101
+ const popperScope = usePopperScope(__scopeMenu, (0, import_internal.subSlot)(slot, "popper"));
102
+ const [content, setContent] = (0, import_octane.useState)(null, (0, import_internal.subSlot)(slot, "content"));
103
+ const isUsingKeyboardRef = (0, import_octane.useRef)(false, (0, import_internal.subSlot)(slot, "keyboard"));
104
+ const handleOpenChange = (0, import_use_callback_ref.useCallbackRef)(onOpenChange, (0, import_internal.subSlot)(slot, "openChange"));
105
+ const direction = (0, import_direction.useDirection)(dir);
106
+ (0, import_octane.useEffect)(
107
+ () => {
108
+ const handleKeyDown = () => {
109
+ isUsingKeyboardRef.current = true;
110
+ document.addEventListener("pointerdown", handlePointer, { capture: true, once: true });
111
+ document.addEventListener("pointermove", handlePointer, { capture: true, once: true });
112
+ };
113
+ const handlePointer = () => isUsingKeyboardRef.current = false;
114
+ document.addEventListener("keydown", handleKeyDown, { capture: true });
115
+ return () => {
116
+ document.removeEventListener("keydown", handleKeyDown, { capture: true });
117
+ document.removeEventListener("pointerdown", handlePointer, { capture: true });
118
+ document.removeEventListener("pointermove", handlePointer, { capture: true });
119
+ };
120
+ },
121
+ [],
122
+ (0, import_internal.subSlot)(slot, "e:keyboard")
123
+ );
124
+ (0, import_octane.useEffect)(
125
+ () => {
126
+ if (!open) return;
127
+ const handleBlur = () => handleOpenChange(false);
128
+ window.addEventListener("blur", handleBlur);
129
+ return () => window.removeEventListener("blur", handleBlur);
130
+ },
131
+ [open, handleOpenChange],
132
+ (0, import_internal.subSlot)(slot, "e:blur")
133
+ );
134
+ return (0, import_octane.createElement)(PopperPrimitive.Root, {
135
+ ...popperScope,
136
+ children: (0, import_octane.createElement)(MenuProvider, {
137
+ scope: __scopeMenu,
138
+ open,
139
+ onOpenChange: handleOpenChange,
140
+ content,
141
+ onContentChange: setContent,
142
+ children: (0, import_octane.createElement)(MenuRootProvider, {
143
+ scope: __scopeMenu,
144
+ onClose: (0, import_octane.useCallback)(
145
+ () => handleOpenChange(false),
146
+ [handleOpenChange],
147
+ (0, import_internal.subSlot)(slot, "close")
148
+ ),
149
+ isUsingKeyboardRef,
150
+ dir: direction,
151
+ modal,
152
+ children
153
+ })
154
+ })
155
+ });
156
+ }
157
+ function Anchor(props) {
158
+ const slot = (0, import_internal.S)("Menu.Anchor");
159
+ const { __scopeMenu, ...anchorProps } = props ?? {};
160
+ const popperScope = usePopperScope(__scopeMenu, (0, import_internal.subSlot)(slot, "popper"));
161
+ return (0, import_octane.createElement)(PopperPrimitive.Anchor, { ...popperScope, ...anchorProps });
162
+ }
163
+ const [PortalProvider, usePortalContext] = createMenuContext(
164
+ "MenuPortal",
165
+ { forceMount: void 0 }
166
+ );
167
+ function Portal(props) {
168
+ const { __scopeMenu, forceMount, children, container } = props ?? {};
169
+ const context = useMenuContext("MenuPortal", __scopeMenu);
170
+ return (0, import_octane.createElement)(PortalProvider, {
171
+ scope: __scopeMenu,
172
+ forceMount,
173
+ children: (0, import_octane.createElement)(import_Presence.Presence, {
174
+ present: forceMount || context.open,
175
+ children: (0, import_octane.createElement)(import_Portal.Portal, {
176
+ asChild: typeof children !== "function",
177
+ container,
178
+ children
179
+ })
180
+ })
181
+ });
182
+ }
183
+ const CONTENT_NAME = "MenuContent";
184
+ const [MenuContentProvider, useMenuContentContext] = createMenuContext(CONTENT_NAME);
185
+ function Content(props) {
186
+ const portalContext = usePortalContext(CONTENT_NAME, props?.__scopeMenu);
187
+ const { forceMount = portalContext.forceMount, ...contentProps } = props ?? {};
188
+ const context = useMenuContext(CONTENT_NAME, props?.__scopeMenu);
189
+ const rootContext = useMenuRootContext(CONTENT_NAME, props?.__scopeMenu);
190
+ return (0, import_octane.createElement)(Collection.Provider, {
191
+ scope: props?.__scopeMenu,
192
+ children: (0, import_octane.createElement)(import_Presence.Presence, {
193
+ present: forceMount || context.open,
194
+ children: (0, import_octane.createElement)(Collection.Slot, {
195
+ scope: props?.__scopeMenu,
196
+ children: rootContext.modal ? (0, import_octane.createElement)(MenuRootContentModal, contentProps) : (0, import_octane.createElement)(MenuRootContentNonModal, contentProps)
197
+ })
198
+ })
199
+ });
200
+ }
201
+ function MenuRootContentModal(props) {
202
+ const slot = (0, import_internal.S)("Menu.RootContentModal");
203
+ const { ref: forwardedRef, ...rest } = props;
204
+ const context = useMenuContext(CONTENT_NAME, props.__scopeMenu);
205
+ const ref = (0, import_octane.useRef)(null, (0, import_internal.subSlot)(slot, "ref"));
206
+ const composedRefs = (0, import_compose_refs.useComposedRefs)(forwardedRef, ref, (0, import_internal.subSlot)(slot, "refs"));
207
+ (0, import_octane.useEffect)(
208
+ () => {
209
+ const content = ref.current;
210
+ if (content) return (0, import_aria_hidden.hideOthers)(content);
211
+ },
212
+ [],
213
+ (0, import_internal.subSlot)(slot, "e:hide")
214
+ );
215
+ return (0, import_octane.createElement)(MenuContentImpl, {
216
+ ...rest,
217
+ __scopeMenu: props.__scopeMenu,
218
+ ref: composedRefs,
219
+ // we make sure we're not trapping once it's been closed
220
+ // (closed !== unmounted when animating out)
221
+ trapFocus: context.open,
222
+ // make sure to only disable pointer events when open
223
+ // this avoids blocking interactions while animating out
224
+ disableOutsidePointerEvents: context.open,
225
+ disableOutsideScroll: true,
226
+ // When focus is trapped, a `focusout` event may still happen.
227
+ // We make sure we don't trigger our `onDismiss` in such case.
228
+ onFocusOutside: (0, import_compose_event_handlers.composeEventHandlers)(
229
+ props.onFocusOutside,
230
+ (event) => event.preventDefault(),
231
+ { checkForDefaultPrevented: false }
232
+ ),
233
+ onDismiss: () => context.onOpenChange(false)
234
+ });
235
+ }
236
+ function MenuRootContentNonModal(props) {
237
+ const context = useMenuContext(CONTENT_NAME, props.__scopeMenu);
238
+ return (0, import_octane.createElement)(MenuContentImpl, {
239
+ ...props,
240
+ trapFocus: false,
241
+ disableOutsidePointerEvents: false,
242
+ disableOutsideScroll: false,
243
+ onDismiss: () => context.onOpenChange(false)
244
+ });
245
+ }
246
+ function MenuContentImpl(props) {
247
+ const slot = (0, import_internal.S)("Menu.ContentImpl");
248
+ const {
249
+ __scopeMenu,
250
+ ref: forwardedRef,
251
+ loop = false,
252
+ trapFocus,
253
+ onOpenAutoFocus,
254
+ onCloseAutoFocus,
255
+ disableOutsidePointerEvents,
256
+ onEntryFocus,
257
+ onEscapeKeyDown,
258
+ onPointerDownOutside,
259
+ onFocusOutside,
260
+ onInteractOutside,
261
+ onDismiss,
262
+ disableOutsideScroll,
263
+ ...contentProps
264
+ } = props;
265
+ const context = useMenuContext(CONTENT_NAME, __scopeMenu);
266
+ const rootContext = useMenuRootContext(CONTENT_NAME, __scopeMenu);
267
+ const popperScope = usePopperScope(__scopeMenu, (0, import_internal.subSlot)(slot, "popper"));
268
+ const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeMenu, (0, import_internal.subSlot)(slot, "rfs"));
269
+ const getItems = useCollection(__scopeMenu, (0, import_internal.subSlot)(slot, "items"));
270
+ const [currentItemId, setCurrentItemId] = (0, import_octane.useState)(null, (0, import_internal.subSlot)(slot, "item"));
271
+ const contentRef = (0, import_octane.useRef)(null, (0, import_internal.subSlot)(slot, "content"));
272
+ const composedRefs = (0, import_compose_refs.useComposedRefs)(
273
+ forwardedRef,
274
+ contentRef,
275
+ context.onContentChange,
276
+ (0, import_internal.subSlot)(slot, "refs")
277
+ );
278
+ const timerRef = (0, import_octane.useRef)(0, (0, import_internal.subSlot)(slot, "timer"));
279
+ const searchRef = (0, import_octane.useRef)("", (0, import_internal.subSlot)(slot, "search"));
280
+ const pointerGraceTimerRef = (0, import_octane.useRef)(0, (0, import_internal.subSlot)(slot, "graceTimer"));
281
+ const pointerGraceIntentRef = (0, import_octane.useRef)(null, (0, import_internal.subSlot)(slot, "graceIntent"));
282
+ const pointerDirRef = (0, import_octane.useRef)("right", (0, import_internal.subSlot)(slot, "pointerDir"));
283
+ const lastPointerXRef = (0, import_octane.useRef)(0, (0, import_internal.subSlot)(slot, "lastX"));
284
+ (0, import_scroll_lock.useScrollLock)(!!disableOutsideScroll, (0, import_internal.subSlot)(slot, "lock"));
285
+ const handleTypeaheadSearch = (key) => {
286
+ const search = searchRef.current + key;
287
+ const items = getItems().filter((item) => !item.disabled);
288
+ const currentItem = document.activeElement;
289
+ const currentMatch = items.find((item) => item.ref.current === currentItem)?.textValue;
290
+ const values = items.map((item) => item.textValue);
291
+ const nextMatch = getNextMatch(values, search, currentMatch);
292
+ const newItem = items.find((item) => item.textValue === nextMatch)?.ref.current;
293
+ (function updateSearch(value) {
294
+ searchRef.current = value;
295
+ window.clearTimeout(timerRef.current);
296
+ if (value !== "") timerRef.current = window.setTimeout(() => updateSearch(""), 1e3);
297
+ })(search);
298
+ if (newItem) {
299
+ setTimeout(() => newItem.focus());
300
+ }
301
+ };
302
+ (0, import_octane.useEffect)(
303
+ () => {
304
+ return () => window.clearTimeout(timerRef.current);
305
+ },
306
+ [],
307
+ (0, import_internal.subSlot)(slot, "e:timer")
308
+ );
309
+ (0, import_focus_guards.useFocusGuards)((0, import_internal.subSlot)(slot, "guards"));
310
+ const isPointerMovingToSubmenu = (0, import_octane.useCallback)(
311
+ (event) => {
312
+ const isMovingTowards = pointerDirRef.current === pointerGraceIntentRef.current?.side;
313
+ return isMovingTowards && isPointerInGraceArea(event, pointerGraceIntentRef.current?.area);
314
+ },
315
+ [],
316
+ (0, import_internal.subSlot)(slot, "movingToSub")
317
+ );
318
+ return (0, import_octane.createElement)(MenuContentProvider, {
319
+ scope: __scopeMenu,
320
+ searchRef,
321
+ onItemEnter: (0, import_octane.useCallback)(
322
+ (event) => {
323
+ if (isPointerMovingToSubmenu(event)) event.preventDefault();
324
+ },
325
+ [isPointerMovingToSubmenu],
326
+ (0, import_internal.subSlot)(slot, "itemEnter")
327
+ ),
328
+ onItemLeave: (0, import_octane.useCallback)(
329
+ (event) => {
330
+ if (isPointerMovingToSubmenu(event)) return;
331
+ contentRef.current?.focus();
332
+ setCurrentItemId(null);
333
+ },
334
+ [isPointerMovingToSubmenu],
335
+ (0, import_internal.subSlot)(slot, "itemLeave")
336
+ ),
337
+ onTriggerLeave: (0, import_octane.useCallback)(
338
+ (event) => {
339
+ if (isPointerMovingToSubmenu(event)) event.preventDefault();
340
+ },
341
+ [isPointerMovingToSubmenu],
342
+ (0, import_internal.subSlot)(slot, "triggerLeave")
343
+ ),
344
+ pointerGraceTimerRef,
345
+ onPointerGraceIntentChange: (0, import_octane.useCallback)(
346
+ (intent) => {
347
+ pointerGraceIntentRef.current = intent;
348
+ },
349
+ [],
350
+ (0, import_internal.subSlot)(slot, "graceChange")
351
+ ),
352
+ children: (0, import_octane.createElement)(import_FocusScope.FocusScope, {
353
+ asChild: true,
354
+ trapped: trapFocus,
355
+ onMountAutoFocus: (0, import_compose_event_handlers.composeEventHandlers)(onOpenAutoFocus, (event) => {
356
+ event.preventDefault();
357
+ contentRef.current?.focus({ preventScroll: true });
358
+ }),
359
+ onUnmountAutoFocus: onCloseAutoFocus,
360
+ children: (0, import_octane.createElement)(import_DismissableLayer.DismissableLayer, {
361
+ asChild: true,
362
+ disableOutsidePointerEvents,
363
+ onEscapeKeyDown,
364
+ onPointerDownOutside,
365
+ onFocusOutside,
366
+ onInteractOutside,
367
+ onDismiss,
368
+ children: (0, import_octane.createElement)(RovingFocusGroup.Root, {
369
+ asChild: true,
370
+ ...rovingFocusGroupScope,
371
+ dir: rootContext.dir,
372
+ orientation: "vertical",
373
+ loop,
374
+ currentTabStopId: currentItemId,
375
+ onCurrentTabStopIdChange: setCurrentItemId,
376
+ onEntryFocus: (0, import_compose_event_handlers.composeEventHandlers)(onEntryFocus, (event) => {
377
+ if (!rootContext.isUsingKeyboardRef.current) event.preventDefault();
378
+ }),
379
+ preventScrollOnEntryFocus: true,
380
+ children: (0, import_octane.createElement)(PopperPrimitive.Content, {
381
+ role: "menu",
382
+ "aria-orientation": "vertical",
383
+ "data-state": getOpenState(context.open),
384
+ "data-radix-menu-content": "",
385
+ dir: rootContext.dir,
386
+ ...popperScope,
387
+ ...contentProps,
388
+ ref: composedRefs,
389
+ style: { outline: "none", ...contentProps.style },
390
+ onKeyDown: (0, import_compose_event_handlers.composeEventHandlers)(contentProps.onKeyDown, (event) => {
391
+ const target = event.target;
392
+ const isKeyDownInside = target.closest("[data-radix-menu-content]") === event.currentTarget;
393
+ const isModifierKey = event.ctrlKey || event.altKey || event.metaKey;
394
+ const isCharacterKey = event.key.length === 1;
395
+ if (isKeyDownInside) {
396
+ if (event.key === "Tab") event.preventDefault();
397
+ if (!isModifierKey && isCharacterKey) handleTypeaheadSearch(event.key);
398
+ }
399
+ const content = contentRef.current;
400
+ if (event.target !== content) return;
401
+ if (!FIRST_LAST_KEYS.includes(event.key)) return;
402
+ event.preventDefault();
403
+ const items = getItems().filter((item) => !item.disabled);
404
+ const candidateNodes = items.map((item) => item.ref.current);
405
+ if (LAST_KEYS.includes(event.key)) candidateNodes.reverse();
406
+ focusFirst(candidateNodes);
407
+ }),
408
+ onBlur: (0, import_compose_event_handlers.composeEventHandlers)(props.onBlur, (event) => {
409
+ if (!event.currentTarget.contains(event.target)) {
410
+ window.clearTimeout(timerRef.current);
411
+ searchRef.current = "";
412
+ }
413
+ }),
414
+ onPointerMove: (0, import_compose_event_handlers.composeEventHandlers)(
415
+ props.onPointerMove,
416
+ whenMouse((event) => {
417
+ const target = event.target;
418
+ const pointerXHasChanged = lastPointerXRef.current !== event.clientX;
419
+ if (event.currentTarget.contains(target) && pointerXHasChanged) {
420
+ const newDir = event.clientX > lastPointerXRef.current ? "right" : "left";
421
+ pointerDirRef.current = newDir;
422
+ lastPointerXRef.current = event.clientX;
423
+ }
424
+ })
425
+ )
426
+ })
427
+ })
428
+ })
429
+ })
430
+ });
431
+ }
432
+ function Group(props) {
433
+ const { __scopeMenu, ...groupProps } = props ?? {};
434
+ return (0, import_octane.createElement)(import_Primitive.Primitive.div, { role: "group", ...groupProps });
435
+ }
436
+ function Label(props) {
437
+ const { __scopeMenu, ...labelProps } = props ?? {};
438
+ return (0, import_octane.createElement)(import_Primitive.Primitive.div, { ...labelProps });
439
+ }
440
+ const ITEM_NAME = "MenuItem";
441
+ const ITEM_SELECT = "menu.itemSelect";
442
+ function Item(props) {
443
+ const slot = (0, import_internal.S)("Menu.Item");
444
+ const { disabled = false, onSelect, ref: forwardedRef, ...itemProps } = props ?? {};
445
+ const ref = (0, import_octane.useRef)(null, (0, import_internal.subSlot)(slot, "ref"));
446
+ const rootContext = useMenuRootContext(ITEM_NAME, props?.__scopeMenu);
447
+ const contentContext = useMenuContentContext(ITEM_NAME, props?.__scopeMenu);
448
+ const composedRefs = (0, import_compose_refs.useComposedRefs)(forwardedRef, ref, (0, import_internal.subSlot)(slot, "refs"));
449
+ const isPointerDownRef = (0, import_octane.useRef)(false, (0, import_internal.subSlot)(slot, "pointerDown"));
450
+ const handleSelect = () => {
451
+ const menuItem = ref.current;
452
+ if (!disabled && menuItem) {
453
+ const itemSelectEvent = new CustomEvent(ITEM_SELECT, { bubbles: true, cancelable: true });
454
+ menuItem.addEventListener(ITEM_SELECT, (event) => onSelect?.(event), { once: true });
455
+ (0, import_Primitive.dispatchDiscreteCustomEvent)(menuItem, itemSelectEvent);
456
+ if (itemSelectEvent.defaultPrevented) {
457
+ isPointerDownRef.current = false;
458
+ } else {
459
+ rootContext.onClose();
460
+ }
461
+ }
462
+ };
463
+ return (0, import_octane.createElement)(MenuItemImpl, {
464
+ ...itemProps,
465
+ __scopeMenu: props?.__scopeMenu,
466
+ ref: composedRefs,
467
+ disabled,
468
+ onClick: (0, import_compose_event_handlers.composeEventHandlers)(props?.onClick, handleSelect),
469
+ onPointerDown: (event) => {
470
+ props?.onPointerDown?.(event);
471
+ isPointerDownRef.current = true;
472
+ },
473
+ onPointerUp: (0, import_compose_event_handlers.composeEventHandlers)(props?.onPointerUp, (event) => {
474
+ if (!isPointerDownRef.current) event.currentTarget?.click();
475
+ }),
476
+ onKeyDown: (0, import_compose_event_handlers.composeEventHandlers)(props?.onKeyDown, (event) => {
477
+ const isTypingAhead = contentContext.searchRef.current !== "";
478
+ if (disabled || isTypingAhead && event.key === " ") return;
479
+ if (SELECTION_KEYS.includes(event.key)) {
480
+ event.currentTarget.click();
481
+ event.preventDefault();
482
+ }
483
+ })
484
+ });
485
+ }
486
+ function MenuItemImpl(props) {
487
+ const slot = (0, import_internal.S)("Menu.ItemImpl");
488
+ const { __scopeMenu, disabled = false, textValue, ref: forwardedRef, ...itemProps } = props;
489
+ const contentContext = useMenuContentContext(ITEM_NAME, __scopeMenu);
490
+ const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeMenu, (0, import_internal.subSlot)(slot, "rfs"));
491
+ const ref = (0, import_octane.useRef)(null, (0, import_internal.subSlot)(slot, "ref"));
492
+ const composedRefs = (0, import_compose_refs.useComposedRefs)(forwardedRef, ref, (0, import_internal.subSlot)(slot, "refs"));
493
+ const [isFocused, setIsFocused] = (0, import_octane.useState)(false, (0, import_internal.subSlot)(slot, "focused"));
494
+ const [textContent, setTextContent] = (0, import_octane.useState)("", (0, import_internal.subSlot)(slot, "text"));
495
+ (0, import_octane.useEffect)(
496
+ () => {
497
+ const menuItem = ref.current;
498
+ if (menuItem) {
499
+ setTextContent((menuItem.textContent ?? "").trim());
500
+ }
501
+ },
502
+ [itemProps.children],
503
+ (0, import_internal.subSlot)(slot, "e:text")
504
+ );
505
+ return (0, import_octane.createElement)(Collection.ItemSlot, {
506
+ scope: __scopeMenu,
507
+ disabled,
508
+ textValue: textValue ?? textContent,
509
+ children: (0, import_octane.createElement)(RovingFocusGroup.Item, {
510
+ asChild: true,
511
+ ...rovingFocusGroupScope,
512
+ focusable: !disabled,
513
+ children: (0, import_octane.createElement)(import_Primitive.Primitive.div, {
514
+ role: "menuitem",
515
+ "data-highlighted": isFocused ? "" : void 0,
516
+ "aria-disabled": disabled || void 0,
517
+ "data-disabled": disabled ? "" : void 0,
518
+ ...itemProps,
519
+ ref: composedRefs,
520
+ /**
521
+ * We focus items on `pointerMove` to achieve the following:
522
+ *
523
+ * - Mouse over an item (it focuses)
524
+ * - Leave mouse where it is and use keyboard to focus a different item
525
+ * - Wiggle mouse without it leaving previously focused item
526
+ * - Previously focused item should re-focus
527
+ *
528
+ * If we used `mouseOver`/`mouseEnter` it would not re-focus when the mouse
529
+ * wiggles. This is to match native menu implementation.
530
+ */
531
+ onPointerMove: (0, import_compose_event_handlers.composeEventHandlers)(
532
+ props.onPointerMove,
533
+ whenMouse((event) => {
534
+ if (disabled) {
535
+ contentContext.onItemLeave(event);
536
+ } else {
537
+ contentContext.onItemEnter(event);
538
+ if (!event.defaultPrevented) {
539
+ const item = event.currentTarget;
540
+ item.focus({ preventScroll: true });
541
+ }
542
+ }
543
+ })
544
+ ),
545
+ onPointerLeave: (0, import_compose_event_handlers.composeEventHandlers)(
546
+ props.onPointerLeave,
547
+ whenMouse((event) => contentContext.onItemLeave(event))
548
+ ),
549
+ onFocus: (0, import_compose_event_handlers.composeEventHandlers)(props.onFocus, () => setIsFocused(true)),
550
+ onBlur: (0, import_compose_event_handlers.composeEventHandlers)(props.onBlur, () => setIsFocused(false))
551
+ })
552
+ })
553
+ });
554
+ }
555
+ function CheckboxItem(props) {
556
+ const { checked = false, onCheckedChange, ...checkboxItemProps } = props ?? {};
557
+ return (0, import_octane.createElement)(ItemIndicatorProvider, {
558
+ scope: props?.__scopeMenu,
559
+ checked,
560
+ children: (0, import_octane.createElement)(Item, {
561
+ role: "menuitemcheckbox",
562
+ "aria-checked": isIndeterminate(checked) ? "mixed" : checked,
563
+ ...checkboxItemProps,
564
+ "data-state": getCheckedState(checked),
565
+ onSelect: (0, import_compose_event_handlers.composeEventHandlers)(
566
+ checkboxItemProps.onSelect,
567
+ () => onCheckedChange?.(isIndeterminate(checked) ? true : !checked),
568
+ { checkForDefaultPrevented: false }
569
+ )
570
+ })
571
+ });
572
+ }
573
+ const [RadioGroupProvider, useRadioGroupContext] = createMenuContext("MenuRadioGroup", { value: void 0, onValueChange: () => {
574
+ } });
575
+ function RadioGroup(props) {
576
+ const slot = (0, import_internal.S)("Menu.RadioGroup");
577
+ const { value, onValueChange, ...groupProps } = props ?? {};
578
+ const handleValueChange = (0, import_use_callback_ref.useCallbackRef)(onValueChange, (0, import_internal.subSlot)(slot, "change"));
579
+ return (0, import_octane.createElement)(RadioGroupProvider, {
580
+ scope: props?.__scopeMenu,
581
+ value,
582
+ onValueChange: handleValueChange,
583
+ children: (0, import_octane.createElement)(Group, groupProps)
584
+ });
585
+ }
586
+ function RadioItem(props) {
587
+ const { value, ...radioItemProps } = props ?? {};
588
+ const context = useRadioGroupContext("MenuRadioItem", props?.__scopeMenu);
589
+ const checked = value === context.value;
590
+ return (0, import_octane.createElement)(ItemIndicatorProvider, {
591
+ scope: props?.__scopeMenu,
592
+ checked,
593
+ children: (0, import_octane.createElement)(Item, {
594
+ role: "menuitemradio",
595
+ "aria-checked": checked,
596
+ ...radioItemProps,
597
+ "data-state": getCheckedState(checked),
598
+ onSelect: (0, import_compose_event_handlers.composeEventHandlers)(
599
+ radioItemProps.onSelect,
600
+ () => context.onValueChange?.(value),
601
+ { checkForDefaultPrevented: false }
602
+ )
603
+ })
604
+ });
605
+ }
606
+ const [ItemIndicatorProvider, useItemIndicatorContext] = createMenuContext("MenuItemIndicator", { checked: false });
607
+ function ItemIndicator(props) {
608
+ const { __scopeMenu, forceMount, ...itemIndicatorProps } = props ?? {};
609
+ const indicatorContext = useItemIndicatorContext("MenuItemIndicator", __scopeMenu);
610
+ return (0, import_octane.createElement)(import_Presence.Presence, {
611
+ present: forceMount || isIndeterminate(indicatorContext.checked) || indicatorContext.checked === true,
612
+ children: (0, import_octane.createElement)(import_Primitive.Primitive.span, {
613
+ ...itemIndicatorProps,
614
+ "data-state": getCheckedState(indicatorContext.checked)
615
+ })
616
+ });
617
+ }
618
+ function Separator(props) {
619
+ const { __scopeMenu, ...separatorProps } = props ?? {};
620
+ return (0, import_octane.createElement)(import_Primitive.Primitive.div, {
621
+ role: "separator",
622
+ "aria-orientation": "horizontal",
623
+ ...separatorProps
624
+ });
625
+ }
626
+ function Arrow(props) {
627
+ const slot = (0, import_internal.S)("Menu.Arrow");
628
+ const { __scopeMenu, ...arrowProps } = props ?? {};
629
+ const popperScope = usePopperScope(__scopeMenu, (0, import_internal.subSlot)(slot, "popper"));
630
+ return (0, import_octane.createElement)(PopperPrimitive.Arrow, { ...popperScope, ...arrowProps });
631
+ }
632
+ const SUB_NAME = "MenuSub";
633
+ const [MenuSubProvider, useMenuSubContext] = createMenuContext(SUB_NAME);
634
+ function Sub(props) {
635
+ const slot = (0, import_internal.S)("Menu.Sub");
636
+ const { __scopeMenu, children, open = false, onOpenChange } = props ?? {};
637
+ const parentMenuContext = useMenuContext(SUB_NAME, __scopeMenu);
638
+ const popperScope = usePopperScope(__scopeMenu, (0, import_internal.subSlot)(slot, "popper"));
639
+ const [trigger, setTrigger] = (0, import_octane.useState)(null, (0, import_internal.subSlot)(slot, "trigger"));
640
+ const [content, setContent] = (0, import_octane.useState)(null, (0, import_internal.subSlot)(slot, "content"));
641
+ const handleOpenChange = (0, import_use_callback_ref.useCallbackRef)(onOpenChange, (0, import_internal.subSlot)(slot, "openChange"));
642
+ (0, import_octane.useEffect)(
643
+ () => {
644
+ if (parentMenuContext.open === false) handleOpenChange(false);
645
+ return () => handleOpenChange(false);
646
+ },
647
+ [parentMenuContext.open, handleOpenChange],
648
+ (0, import_internal.subSlot)(slot, "e:parent")
649
+ );
650
+ return (0, import_octane.createElement)(PopperPrimitive.Root, {
651
+ ...popperScope,
652
+ children: (0, import_octane.createElement)(MenuProvider, {
653
+ scope: __scopeMenu,
654
+ open,
655
+ onOpenChange: handleOpenChange,
656
+ content,
657
+ onContentChange: setContent,
658
+ children: (0, import_octane.createElement)(MenuSubProvider, {
659
+ scope: __scopeMenu,
660
+ contentId: (0, import_useId.useId)((0, import_internal.subSlot)(slot, "contentId")),
661
+ triggerId: (0, import_useId.useId)((0, import_internal.subSlot)(slot, "triggerId")),
662
+ trigger,
663
+ onTriggerChange: setTrigger,
664
+ children
665
+ })
666
+ })
667
+ });
668
+ }
669
+ const SUB_TRIGGER_NAME = "MenuSubTrigger";
670
+ function SubTrigger(props) {
671
+ const slot = (0, import_internal.S)("Menu.SubTrigger");
672
+ const context = useMenuContext(SUB_TRIGGER_NAME, props?.__scopeMenu);
673
+ const rootContext = useMenuRootContext(SUB_TRIGGER_NAME, props?.__scopeMenu);
674
+ const subContext = useMenuSubContext(SUB_TRIGGER_NAME, props?.__scopeMenu);
675
+ const contentContext = useMenuContentContext(SUB_TRIGGER_NAME, props?.__scopeMenu);
676
+ const openTimerRef = (0, import_octane.useRef)(null, (0, import_internal.subSlot)(slot, "openTimer"));
677
+ const { pointerGraceTimerRef, onPointerGraceIntentChange } = contentContext;
678
+ const scope = { __scopeMenu: props?.__scopeMenu };
679
+ const clearOpenTimer = (0, import_octane.useCallback)(
680
+ () => {
681
+ if (openTimerRef.current) window.clearTimeout(openTimerRef.current);
682
+ openTimerRef.current = null;
683
+ },
684
+ [],
685
+ (0, import_internal.subSlot)(slot, "clear")
686
+ );
687
+ (0, import_octane.useEffect)(() => clearOpenTimer, [clearOpenTimer], (0, import_internal.subSlot)(slot, "e:clear"));
688
+ (0, import_octane.useEffect)(
689
+ () => {
690
+ const pointerGraceTimer = pointerGraceTimerRef.current;
691
+ return () => {
692
+ window.clearTimeout(pointerGraceTimer);
693
+ onPointerGraceIntentChange(null);
694
+ };
695
+ },
696
+ [pointerGraceTimerRef, onPointerGraceIntentChange],
697
+ (0, import_internal.subSlot)(slot, "e:grace")
698
+ );
699
+ const composedRefs = (0, import_compose_refs.useComposedRefs)(
700
+ props?.ref,
701
+ subContext.onTriggerChange,
702
+ (0, import_internal.subSlot)(slot, "refs")
703
+ );
704
+ return (0, import_octane.createElement)(Anchor, {
705
+ asChild: true,
706
+ ...scope,
707
+ children: (0, import_octane.createElement)(MenuItemImpl, {
708
+ id: subContext.triggerId,
709
+ "aria-haspopup": "menu",
710
+ "aria-expanded": context.open,
711
+ "aria-controls": context.open ? subContext.contentId : void 0,
712
+ "data-state": getOpenState(context.open),
713
+ ...props,
714
+ ref: composedRefs,
715
+ // This is redundant for mouse users but we cannot determine pointer type from
716
+ // click event and we cannot use pointerup event (see git history for reasons why)
717
+ onClick: (event) => {
718
+ props?.onClick?.(event);
719
+ if (props?.disabled || event.defaultPrevented) return;
720
+ event.currentTarget.focus();
721
+ if (!context.open) context.onOpenChange(true);
722
+ },
723
+ onPointerMove: (0, import_compose_event_handlers.composeEventHandlers)(
724
+ props?.onPointerMove,
725
+ whenMouse((event) => {
726
+ contentContext.onItemEnter(event);
727
+ if (event.defaultPrevented) return;
728
+ if (!props?.disabled && !context.open && !openTimerRef.current) {
729
+ contentContext.onPointerGraceIntentChange(null);
730
+ openTimerRef.current = window.setTimeout(() => {
731
+ context.onOpenChange(true);
732
+ clearOpenTimer();
733
+ }, 100);
734
+ }
735
+ })
736
+ ),
737
+ onPointerLeave: (0, import_compose_event_handlers.composeEventHandlers)(
738
+ props?.onPointerLeave,
739
+ whenMouse((event) => {
740
+ clearOpenTimer();
741
+ const contentRect = context.content?.getBoundingClientRect();
742
+ if (contentRect) {
743
+ const side = context.content?.dataset.side ?? "right";
744
+ const rightSide = side === "right";
745
+ const bleed = rightSide ? -5 : 5;
746
+ const contentNearEdge = contentRect[rightSide ? "left" : "right"];
747
+ const contentFarEdge = contentRect[rightSide ? "right" : "left"];
748
+ contentContext.onPointerGraceIntentChange({
749
+ area: [
750
+ // Apply a bleed on clientX to ensure that our exit point is
751
+ // consistently within polygon bounds
752
+ { x: event.clientX + bleed, y: event.clientY },
753
+ { x: contentNearEdge, y: contentRect.top },
754
+ { x: contentFarEdge, y: contentRect.top },
755
+ { x: contentFarEdge, y: contentRect.bottom },
756
+ { x: contentNearEdge, y: contentRect.bottom }
757
+ ],
758
+ side
759
+ });
760
+ window.clearTimeout(pointerGraceTimerRef.current);
761
+ pointerGraceTimerRef.current = window.setTimeout(
762
+ () => contentContext.onPointerGraceIntentChange(null),
763
+ 300
764
+ );
765
+ } else {
766
+ contentContext.onTriggerLeave(event);
767
+ if (event.defaultPrevented) return;
768
+ contentContext.onPointerGraceIntentChange(null);
769
+ }
770
+ })
771
+ ),
772
+ onKeyDown: (0, import_compose_event_handlers.composeEventHandlers)(props?.onKeyDown, (event) => {
773
+ const isTypingAhead = contentContext.searchRef.current !== "";
774
+ if (props?.disabled || isTypingAhead && event.key === " ") return;
775
+ if (SUB_OPEN_KEYS[rootContext.dir].includes(event.key)) {
776
+ context.onOpenChange(true);
777
+ context.content?.focus();
778
+ event.preventDefault();
779
+ }
780
+ })
781
+ })
782
+ });
783
+ }
784
+ const SUB_CONTENT_NAME = "MenuSubContent";
785
+ function SubContent(props) {
786
+ const slot = (0, import_internal.S)("Menu.SubContent");
787
+ const portalContext = usePortalContext(CONTENT_NAME, props?.__scopeMenu);
788
+ const {
789
+ forceMount = portalContext.forceMount,
790
+ align = "start",
791
+ ref: forwardedRef,
792
+ ...subContentProps
793
+ } = props ?? {};
794
+ const context = useMenuContext(CONTENT_NAME, props?.__scopeMenu);
795
+ const rootContext = useMenuRootContext(CONTENT_NAME, props?.__scopeMenu);
796
+ const subContext = useMenuSubContext(SUB_CONTENT_NAME, props?.__scopeMenu);
797
+ const ref = (0, import_octane.useRef)(null, (0, import_internal.subSlot)(slot, "ref"));
798
+ const composedRefs = (0, import_compose_refs.useComposedRefs)(forwardedRef, ref, (0, import_internal.subSlot)(slot, "refs"));
799
+ return (0, import_octane.createElement)(Collection.Provider, {
800
+ scope: props?.__scopeMenu,
801
+ children: (0, import_octane.createElement)(import_Presence.Presence, {
802
+ present: forceMount || context.open,
803
+ children: (0, import_octane.createElement)(Collection.Slot, {
804
+ scope: props?.__scopeMenu,
805
+ children: (0, import_octane.createElement)(MenuContentImpl, {
806
+ id: subContext.contentId,
807
+ "aria-labelledby": subContext.triggerId,
808
+ ...subContentProps,
809
+ __scopeMenu: props?.__scopeMenu,
810
+ ref: composedRefs,
811
+ align,
812
+ side: rootContext.dir === "rtl" ? "left" : "right",
813
+ disableOutsidePointerEvents: false,
814
+ disableOutsideScroll: false,
815
+ trapFocus: false,
816
+ onOpenAutoFocus: (event) => {
817
+ if (rootContext.isUsingKeyboardRef.current) ref.current?.focus();
818
+ event.preventDefault();
819
+ },
820
+ // The menu might close because of focusing another menu item in the parent
821
+ // menu. We don't want it to refocus the trigger in that case so we handle
822
+ // trigger focus ourselves.
823
+ onCloseAutoFocus: (event) => event.preventDefault(),
824
+ onFocusOutside: (0, import_compose_event_handlers.composeEventHandlers)(props?.onFocusOutside, (event) => {
825
+ if (event.target !== subContext.trigger) context.onOpenChange(false);
826
+ }),
827
+ onEscapeKeyDown: (0, import_compose_event_handlers.composeEventHandlers)(props?.onEscapeKeyDown, (event) => {
828
+ rootContext.onClose();
829
+ event.preventDefault();
830
+ }),
831
+ onKeyDown: (0, import_compose_event_handlers.composeEventHandlers)(props?.onKeyDown, (event) => {
832
+ const isKeyDownInside = event.currentTarget.contains(
833
+ event.target
834
+ );
835
+ const isCloseKey = SUB_CLOSE_KEYS[rootContext.dir].includes(event.key);
836
+ if (isKeyDownInside && isCloseKey) {
837
+ context.onOpenChange(false);
838
+ subContext.trigger?.focus();
839
+ event.preventDefault();
840
+ }
841
+ })
842
+ })
843
+ })
844
+ })
845
+ });
846
+ }
847
+ function getOpenState(open) {
848
+ return open ? "open" : "closed";
849
+ }
850
+ function isIndeterminate(checked) {
851
+ return checked === "indeterminate";
852
+ }
853
+ function getCheckedState(checked) {
854
+ return isIndeterminate(checked) ? "indeterminate" : checked ? "checked" : "unchecked";
855
+ }
856
+ function focusFirst(candidates) {
857
+ const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;
858
+ for (const candidate of candidates) {
859
+ if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return;
860
+ candidate.focus();
861
+ if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return;
862
+ }
863
+ }
864
+ function wrapArray(array, startIndex) {
865
+ return array.map((_, index) => array[(startIndex + index) % array.length]);
866
+ }
867
+ function getNextMatch(values, search, currentMatch) {
868
+ const isRepeated = search.length > 1 && Array.from(search).every((char) => char === search[0]);
869
+ const normalizedSearch = isRepeated ? search[0] : search;
870
+ const currentMatchIndex = currentMatch ? values.indexOf(currentMatch) : -1;
871
+ let wrappedValues = wrapArray(values, Math.max(currentMatchIndex, 0));
872
+ const excludeCurrentMatch = normalizedSearch.length === 1;
873
+ if (excludeCurrentMatch) wrappedValues = wrappedValues.filter((v) => v !== currentMatch);
874
+ const nextMatch = wrappedValues.find(
875
+ (value) => value.toLowerCase().startsWith(normalizedSearch.toLowerCase())
876
+ );
877
+ return nextMatch !== currentMatch ? nextMatch : void 0;
878
+ }
879
+ function isPointInPolygon(point, polygon) {
880
+ const { x, y } = point;
881
+ let inside = false;
882
+ for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
883
+ const ii = polygon[i];
884
+ const jj = polygon[j];
885
+ const xi = ii.x;
886
+ const yi = ii.y;
887
+ const xj = jj.x;
888
+ const yj = jj.y;
889
+ const intersect = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi;
890
+ if (intersect) inside = !inside;
891
+ }
892
+ return inside;
893
+ }
894
+ function isPointerInGraceArea(event, area) {
895
+ if (!area) return false;
896
+ const cursorPos = { x: event.clientX, y: event.clientY };
897
+ return isPointInPolygon(cursorPos, area);
898
+ }
899
+ function whenMouse(handler) {
900
+ return (event) => event.pointerType === "mouse" ? handler(event) : void 0;
901
+ }
902
+ // Annotate the CommonJS export names for ESM import in node:
903
+ 0 && (module.exports = {
904
+ Anchor,
905
+ Arrow,
906
+ CheckboxItem,
907
+ Content,
908
+ Group,
909
+ Item,
910
+ ItemIndicator,
911
+ Label,
912
+ Menu,
913
+ MenuAnchor,
914
+ MenuContent,
915
+ MenuItem,
916
+ Portal,
917
+ RadioGroup,
918
+ RadioItem,
919
+ Root,
920
+ Separator,
921
+ Sub,
922
+ SubContent,
923
+ SubTrigger,
924
+ createMenuScope
925
+ });