@jobber/components 9.6.1 → 9.6.2

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 (141) hide show
  1. package/dist/Autocomplete/index.cjs +2 -0
  2. package/dist/Autocomplete/index.mjs +2 -0
  3. package/dist/Autocomplete-cjs.js +5 -4
  4. package/dist/Autocomplete-es.js +2 -1
  5. package/dist/Card/index.cjs +2 -1
  6. package/dist/Card/index.mjs +2 -1
  7. package/dist/Chip/index.cjs +2 -0
  8. package/dist/Chip/index.mjs +2 -0
  9. package/dist/Chips/InternalChipDismissible/hooks/index.cjs +2 -0
  10. package/dist/Chips/InternalChipDismissible/hooks/index.mjs +2 -0
  11. package/dist/Chips/InternalChipDismissible/index.cjs +2 -0
  12. package/dist/Chips/InternalChipDismissible/index.mjs +2 -0
  13. package/dist/Chips/index.cjs +2 -0
  14. package/dist/Chips/index.mjs +2 -0
  15. package/dist/Combobox/index.cjs +4 -2
  16. package/dist/Combobox/index.mjs +4 -2
  17. package/dist/{ComboboxSeparator-cjs.js → ComboboxChipRemove-cjs.js} +455 -501
  18. package/dist/{ComboboxSeparator-es.js → ComboboxChipRemove-es.js} +456 -500
  19. package/dist/ComboboxPrimitive-cjs.js +30 -29
  20. package/dist/ComboboxPrimitive-es.js +3 -2
  21. package/dist/ConfirmationModal/index.cjs +2 -0
  22. package/dist/ConfirmationModal/index.mjs +2 -0
  23. package/dist/DataDump/index.cjs +2 -1
  24. package/dist/DataDump/index.mjs +2 -1
  25. package/dist/DataList/components/DataListActions/index.cjs +2 -0
  26. package/dist/DataList/components/DataListActions/index.mjs +2 -0
  27. package/dist/DataList/components/DataListBulkActions/index.cjs +2 -0
  28. package/dist/DataList/components/DataListBulkActions/index.mjs +2 -0
  29. package/dist/DataList/components/DataListFilters/components/DataListSort/index.cjs +2 -0
  30. package/dist/DataList/components/DataListFilters/components/DataListSort/index.mjs +2 -0
  31. package/dist/DataList/components/DataListFilters/index.cjs +2 -0
  32. package/dist/DataList/components/DataListFilters/index.mjs +2 -0
  33. package/dist/DataList/components/DataListHeader/index.cjs +2 -0
  34. package/dist/DataList/components/DataListHeader/index.mjs +2 -0
  35. package/dist/DataList/components/DataListItem/index.cjs +2 -0
  36. package/dist/DataList/components/DataListItem/index.mjs +2 -0
  37. package/dist/DataList/components/DataListItemActions/index.cjs +2 -0
  38. package/dist/DataList/components/DataListItemActions/index.mjs +2 -0
  39. package/dist/DataList/components/DataListItemActionsOverflow/index.cjs +2 -0
  40. package/dist/DataList/components/DataListItemActionsOverflow/index.mjs +2 -0
  41. package/dist/DataList/components/DataListItems/index.cjs +2 -0
  42. package/dist/DataList/components/DataListItems/index.mjs +2 -0
  43. package/dist/DataList/components/DataListLayout/index.cjs +2 -0
  44. package/dist/DataList/components/DataListLayout/index.mjs +2 -0
  45. package/dist/DataList/components/DataListLayoutActions/index.cjs +2 -0
  46. package/dist/DataList/components/DataListLayoutActions/index.mjs +2 -0
  47. package/dist/DataList/index.cjs +2 -0
  48. package/dist/DataList/index.mjs +2 -0
  49. package/dist/DatePicker/index.cjs +2 -0
  50. package/dist/DatePicker/index.mjs +2 -0
  51. package/dist/DatePicker-cjs.js +5 -4
  52. package/dist/DatePicker-es.js +2 -1
  53. package/dist/Dialog/index.cjs +2 -1
  54. package/dist/Dialog/index.mjs +2 -1
  55. package/dist/DrawerDescription-cjs.js +99 -268
  56. package/dist/DrawerDescription-es.js +103 -270
  57. package/dist/DrawerTitle-cjs.js +6 -2
  58. package/dist/DrawerTitle-es.js +7 -3
  59. package/dist/FieldDescription-cjs.js +181 -184
  60. package/dist/FieldDescription-es.js +184 -187
  61. package/dist/FilterPicker/components/FilterPickerActivator/index.cjs +2 -0
  62. package/dist/FilterPicker/components/FilterPickerActivator/index.mjs +2 -0
  63. package/dist/FilterPicker/components/FilterPickerContent/index.cjs +2 -0
  64. package/dist/FilterPicker/components/FilterPickerContent/index.mjs +2 -0
  65. package/dist/FilterPicker/components/FilterPickerTrigger/index.cjs +2 -0
  66. package/dist/FilterPicker/components/FilterPickerTrigger/index.mjs +2 -0
  67. package/dist/FilterPicker/index.cjs +2 -0
  68. package/dist/FilterPicker/index.mjs +2 -0
  69. package/dist/FilterPickerContent-cjs.js +5 -4
  70. package/dist/FilterPickerContent-es.js +2 -1
  71. package/dist/FormatFile/index.cjs +2 -0
  72. package/dist/FormatFile/index.mjs +2 -0
  73. package/dist/Gallery/index.cjs +2 -0
  74. package/dist/Gallery/index.mjs +2 -0
  75. package/dist/InputDate/index.cjs +2 -0
  76. package/dist/InputDate/index.mjs +2 -0
  77. package/dist/InputNumber/index.cjs +2 -1
  78. package/dist/InputNumber/index.mjs +2 -1
  79. package/dist/LightBox/index.cjs +2 -0
  80. package/dist/LightBox/index.mjs +2 -0
  81. package/dist/Menu/index.cjs +2 -1
  82. package/dist/Menu/index.mjs +2 -1
  83. package/dist/Menu-cjs.js +5 -4
  84. package/dist/Menu-es.js +2 -1
  85. package/dist/MenuSubmenuTrigger-cjs.js +164 -206
  86. package/dist/MenuSubmenuTrigger-es.js +152 -194
  87. package/dist/Modal/index.cjs +2 -0
  88. package/dist/Modal/index.mjs +3 -1
  89. package/dist/NumberFieldInput-cjs.js +308 -187
  90. package/dist/NumberFieldInput-es.js +308 -187
  91. package/dist/Page/index.cjs +2 -1
  92. package/dist/Page/index.mjs +2 -1
  93. package/dist/Popover/index.cjs +2 -0
  94. package/dist/Popover/index.mjs +2 -0
  95. package/dist/Popover-cjs.js +8 -7
  96. package/dist/Popover-es.js +2 -1
  97. package/dist/ScrollAreaViewport-cjs.js +1093 -747
  98. package/dist/ScrollAreaViewport-es.js +1081 -734
  99. package/dist/Select/index.cjs +2 -1
  100. package/dist/Select/index.mjs +2 -1
  101. package/dist/SelectGroupLabel-cjs.js +306 -207
  102. package/dist/SelectGroupLabel-es.js +302 -203
  103. package/dist/Tooltip/index.cjs +2 -0
  104. package/dist/Tooltip/index.mjs +2 -0
  105. package/dist/Tooltip-cjs.js +7 -6
  106. package/dist/Tooltip-es.js +2 -1
  107. package/dist/dialogReturnFocus-cjs.js +1 -1
  108. package/dist/dialogReturnFocus-es.js +2 -2
  109. package/dist/floating-ui.react-cjs.js +192 -2564
  110. package/dist/floating-ui.react-dom-cjs.js +2103 -0
  111. package/dist/floating-ui.react-dom-es.js +2072 -0
  112. package/dist/floating-ui.react-es.js +156 -2519
  113. package/dist/floating-ui.utils-cjs.js +342 -0
  114. package/dist/floating-ui.utils-es.js +300 -0
  115. package/dist/index.cjs +4 -3
  116. package/dist/index.mjs +4 -3
  117. package/dist/primitives/BottomSheet/index.cjs +1 -1
  118. package/dist/primitives/BottomSheet/index.mjs +1 -1
  119. package/dist/primitives/ComboboxPrimitive/index.cjs +4 -2
  120. package/dist/primitives/ComboboxPrimitive/index.mjs +4 -2
  121. package/dist/primitives/SelectPrimitive/index.cjs +2 -0
  122. package/dist/primitives/SelectPrimitive/index.mjs +2 -0
  123. package/dist/primitives/index.cjs +3 -2
  124. package/dist/primitives/index.mjs +3 -2
  125. package/dist/scrollEdges-cjs.js +11 -1
  126. package/dist/scrollEdges-es.js +11 -1
  127. package/dist/unstyledPrimitives/index.cjs +478 -720
  128. package/dist/unstyledPrimitives/index.mjs +421 -663
  129. package/dist/useCompositeListItem-cjs.js +361 -2108
  130. package/dist/useCompositeListItem-es.js +331 -2076
  131. package/dist/useLabel-cjs.js +3 -2
  132. package/dist/useLabel-es.js +3 -2
  133. package/dist/useRenderElement-cjs.js +7 -9
  134. package/dist/useRenderElement-es.js +7 -9
  135. package/dist/useScrollLock-cjs.js +344 -819
  136. package/dist/useScrollLock-es.js +296 -732
  137. package/dist/useScrollToActive-cjs.js +5 -4
  138. package/dist/useScrollToActive-es.js +2 -1
  139. package/package.json +3 -3
  140. package/dist/scrollable-cjs.js +0 -58
  141. package/dist/scrollable-es.js +0 -54
@@ -1,11 +1,12 @@
1
1
  import * as React from 'react';
2
- import { a as useRefWithInit, f as formatErrorMessage, u as useRenderElement, m as mergeProps, b as useMergedRefs, N as NOOP, E as EMPTY_OBJECT, c as EMPTY_ARRAY, w as warn } from './useRenderElement-es.js';
3
- import { bl as isMouseLikePointerType, q as useTimeout, I as getWindow, bm as mergeCleanups, y as addEventListener, e as getTarget, au as isElement, bn as isTypeableElement, bo as matchesFocusVisible, bp as isTargetInsideEnabledTrigger, h as createChangeEventDetails, bq as triggerFocus, br as createAttribute, D as activeElement, o as ownerDocument, a0 as contains, bs as mac, a9 as webkit, i as isHTMLElement, bt as triggerPress, bu as escapeKey, H as useOnMount, T as Timeout, aM as useFloatingTree, aJ as useFloatingParentNodeId, d as useStableCallback, c as useIsoLayoutEffect, bv as isInteractiveElement, bw as getNodeChildren, bx as triggerHover, w as useValueAsRef, p as popupTransitionStateMapping, ad as itemPress, by as dispatchClickWithModifiers, f as useButton, t as transitionStatusMapping, u as useBaseUiId, l as useOpenChangeComplete, Z as outsidePress, n as FloatingFocusManager, a2 as FloatingPortal, bz as useAnimationsFinished, bA as POPUP_COLLISION_AVOIDANCE, a3 as InternalBackdrop, a4 as inertValue, bB as FloatingNode, a5 as DROPDOWN_COLLISION_AVOIDANCE, bC as siblingOpen, v as useControlled, s as useTransitionStatus, aL as PopupTriggerMap, bD as FloatingTreeStore, X as ReactStore, bE as fastComponent, aI as useId, bF as useFloatingNodeId, R as useOpenInteractionType, b8 as useImplicitActiveTrigger, b9 as useOpenStateTransitions, bG as attachPreventUnmountOnClose, b5 as setPopupOpenState, Y as focusOut, aS as listNavigation, bH as useSyncedFloatingRootContext, k as imperativeAction, W as useDismiss, a7 as useDirection, bI as TYPEAHEAD_RESET_MS, F as FOCUSABLE_POPUP_PROPS, b4 as usePopupInteractionProps, ba as PopupHandleAttachment, bJ as FloatingTree, bK as useCompositeRootContext, a as isLastTraversableNode, b as getParentNode, bL as getTabbableBeforeElement, bM as isOutsideEvent, bN as getTabbableAfterElement, bO as getNextTabbable, bP as fastComponentRef, bb as useTriggerDataForwarding, a1 as cancelOpen, V as useClick, _ as pressableTriggerOpenStateMapping, bQ as FocusGuard, bR as PATIENT_CLICK_THRESHOLD, bS as useTriggerRegistration, S as SafeReact, be as triggerOpenStateMapping, bT as voiceOver } from './useScrollLock-es.js';
2
+ import { a as useRefWithInit, f as formatErrorMessage, u as useRenderElement, m as mergeProps, b as useMergedRefs, E as EMPTY_OBJECT, c as EMPTY_ARRAY, w as warn } from './useRenderElement-es.js';
3
+ import { aw as isMouseLikePointerType, k as useTimeout, ax as mergeCleanups, s as addEventListener, g as getTarget, ay as isTypeableElement, az as matchesFocusVisible, aA as isTargetInsideEnabledTrigger, d as createChangeEventDetails, aB as triggerFocus, aC as createAttribute, D as activeElement, o as ownerDocument, _ as contains, aD as mac, a6 as webkit, aE as triggerPress, aF as escapeKey, H as useOnMount, T as Timeout, ae as useFloatingTree, ab as useFloatingParentNodeId, b as useStableCallback, a as useIsoLayoutEffect, aG as isInteractiveElement, aH as getNodeChildren, aI as triggerHover, q as useValueAsRef, p as popupStateMapping, t as transitionStatusMapping, a9 as itemPress, c as useButton, u as useBaseUiId, f as useOpenChangeComplete, X as outsidePress, i as FloatingFocusManager, a0 as FloatingPortal, aJ as useAnimationsFinished, aK as POPUP_COLLISION_AVOIDANCE, a1 as InternalBackdrop, a2 as inertValue, aL as FloatingNode, a3 as DROPDOWN_COLLISION_AVOIDANCE, aM as siblingOpen, n as useControlled, m as useTransitionStatus, N as createSelector, aN as ReactStore, ad as PopupTriggerMap, aO as FloatingTreeStore, aP as fastComponent, aQ as useInitialOpenSync, aa as useId, aR as useFloatingNodeId, O as useOpenInteractionType, aS as useImplicitActiveTrigger, aT as useOpenStateTransitions, aU as attachPreventUnmountOnClose, aV as setPopupOpenState, W as focusOut, aj as listNavigation, aW as useSyncedFloatingRootContext, j as imperativeAction, R as useDismiss, a4 as useDirection, aX as TYPEAHEAD_RESET_MS, F as FOCUSABLE_POPUP_PROPS, aY as usePopupInteractionProps, aZ as FloatingTree, a_ as useCompositeRootContext, a$ as getTabbableBeforeElement, b0 as isOutsideEvent, b1 as getTabbableAfterElement, b2 as getNextTabbable, b3 as fastComponentRef, b4 as useTriggerDataForwarding, $ as cancelOpen, Q as useClick, Y as pressableTriggerOpenStateMapping, b5 as FocusGuard, b6 as PATIENT_CLICK_THRESHOLD, b7 as useTriggerRegistration, S as SafeReact, b8 as triggerOpenStateMapping } from './useScrollLock-es.js';
4
4
  import { jsx, jsxs } from 'react/jsx-runtime';
5
- import { A as useCompositeListItem, z as getDisabledMountTransitionStyles, w as useAnchorPositioning, v as useAnchoredPopupScrollLock, x as usePositioner, C as CompositeList, j as useListNavigation, k as useTypeahead, p as isMouseWithinBounds } from './useCompositeListItem-es.js';
5
+ import { z as useCompositeListItem, y as getDisabledMountTransitionStyles, v as useAnchorPositioning, B as adaptiveOrigin, t as useAnchoredPopupScrollLock, w as usePositioner, C as CompositeList, j as useListNavigation, k as useTypeahead, o as getPseudoElementBounds } from './useCompositeListItem-es.js';
6
6
  import { u as useToolbarRootContext, l as isElementDisabled } from './SelectGroupLabel-es.js';
7
7
  import { C as COMPOSITE_KEYS } from './scrollEdges-es.js';
8
- import { N as NullStore, o as createInitialPopupStoreState, p as popupStoreSelectors, q as usePopupHandleStore } from './ScrollAreaViewport-es.js';
8
+ import { K as getWindow, b as isElement, i as isHTMLElement, d as isLastTraversableNode, e as getParentNode } from './floating-ui.utils-es.js';
9
+ import { p as popupStoreSelectors, n as createInitialPopupStoreState } from './ScrollAreaViewport-es.js';
9
10
  import * as ReactDOM from 'react-dom';
10
11
 
11
12
  function resolveValue(value, pointerType) {
@@ -437,8 +438,7 @@ function useHoverReferenceInteraction(context, props = {}) {
437
438
  isActiveTrigger = true,
438
439
  getHandleCloseContext,
439
440
  isClosing,
440
- shouldOpen: shouldOpenProp,
441
- guardStaleOpen = false
441
+ shouldOpen: shouldOpenProp
442
442
  } = props;
443
443
  const store = 'rootStore' in context ? context.rootStore : context;
444
444
  const {
@@ -640,24 +640,13 @@ function useHoverReferenceInteraction(context, props = {}) {
640
640
  closeWithDelay(event);
641
641
  }
642
642
  }
643
-
644
- // Backup cancellation for Chrome's dropped `mouseleave` — see `guardStaleOpen`.
645
- function onMouseOut(event) {
646
- if (contains(trigger, event.relatedTarget)) {
647
- return; // moved within the trigger's own subtree
648
- }
649
- instance.openChangeTimeout.clear();
650
- instance.restTimeout.clear();
651
- instance.restTimeoutPending = false;
652
- }
653
- const staleOpenGuard = guardStaleOpen ? addEventListener(trigger, 'mouseout', onMouseOut) : undefined;
654
643
  if (move) {
655
644
  return mergeCleanups(addEventListener(trigger, 'mousemove', onMouseEnter, {
656
645
  once: true
657
- }), addEventListener(trigger, 'mouseenter', onMouseEnter), addEventListener(trigger, 'mouseleave', onMouseLeave), staleOpenGuard);
646
+ }), addEventListener(trigger, 'mouseenter', onMouseEnter), addEventListener(trigger, 'mouseleave', onMouseLeave));
658
647
  }
659
- return mergeCleanups(addEventListener(trigger, 'mouseenter', onMouseEnter), addEventListener(trigger, 'mouseleave', onMouseLeave), staleOpenGuard);
660
- }, [cleanupMouseMoveHandler, clearPointerEvents, dataRef, delayRef, store, enabled, handleCloseRef, instance, isActiveTrigger, isOverInactiveTrigger, isClickLikeOpenEvent$1, mouseOnly, move, restMsRef, triggerElementRef, tree, enabledRef, getHandleCloseContext, isClosingRef, checkShouldOpen, guardStaleOpen]);
648
+ return mergeCleanups(addEventListener(trigger, 'mouseenter', onMouseEnter), addEventListener(trigger, 'mouseleave', onMouseLeave));
649
+ }, [cleanupMouseMoveHandler, clearPointerEvents, dataRef, delayRef, store, enabled, handleCloseRef, instance, isActiveTrigger, isOverInactiveTrigger, isClickLikeOpenEvent$1, mouseOnly, move, restMsRef, triggerElementRef, tree, enabledRef, getHandleCloseContext, isClosingRef, checkShouldOpen]);
661
650
  return React.useMemo(() => {
662
651
  if (!enabled) {
663
652
  return undefined;
@@ -998,6 +987,11 @@ function useContextMenuRootContext(optional = true) {
998
987
  return context;
999
988
  }
1000
989
 
990
+ const stateAttributesMapping$1 = {
991
+ ...popupStateMapping,
992
+ ...transitionStatusMapping
993
+ };
994
+
1001
995
  /**
1002
996
  * An overlay displayed beneath the menu popup.
1003
997
  * Renders a `<div>` element.
@@ -1026,7 +1020,7 @@ const MenuBackdrop = /*#__PURE__*/React.forwardRef(function MenuBackdrop(compone
1026
1020
  return useRenderElement('div', componentProps, {
1027
1021
  ref: contextMenuContext?.backdropRef ? [forwardedRef, contextMenuContext.backdropRef] : forwardedRef,
1028
1022
  state,
1029
- stateAttributesMapping: popupTransitionStateMapping,
1023
+ stateAttributesMapping: stateAttributesMapping$1,
1030
1024
  props: [{
1031
1025
  role: 'presentation',
1032
1026
  hidden: !mounted,
@@ -1108,12 +1102,8 @@ function useMenuItemCommonProps(params) {
1108
1102
  if (itemRef.current && store.context.allowMouseUpTriggerRef.current && (!isContextMenu || event.button === 2)) {
1109
1103
  // This fires whenever the user clicks on the trigger, moves the cursor, and releases it over the item.
1110
1104
  // We trigger the click and override the `closeOnClick` preference to always close the menu.
1111
- if (itemMetadata.type === 'regular-item') {
1112
- // `detail: 1` marks this as a mouse-gesture click so MenuRoot doesn't
1113
- // treat it as a keyboard activation (`detail === 0` → `data-instant`).
1114
- dispatchClickWithModifiers(itemRef.current, event, {
1115
- detail: 1
1116
- });
1105
+ if (!itemMetadata || itemMetadata.type === 'regular-item') {
1106
+ itemRef.current.click();
1117
1107
  }
1118
1108
  }
1119
1109
  }
@@ -1126,7 +1116,7 @@ const REGULAR_ITEM = {
1126
1116
  function useMenuItem(params) {
1127
1117
  const {
1128
1118
  closeOnClick,
1129
- disabled,
1119
+ disabled: disabledProp = false,
1130
1120
  highlighted,
1131
1121
  id,
1132
1122
  store,
@@ -1135,6 +1125,8 @@ function useMenuItem(params) {
1135
1125
  itemMetadata,
1136
1126
  nodeId
1137
1127
  } = params;
1128
+ const rootDisabled = store.useState('disabled');
1129
+ const disabled = disabledProp || rootDisabled;
1138
1130
  const itemRef = React.useRef(null);
1139
1131
  const {
1140
1132
  getButtonProps,
@@ -1258,7 +1250,7 @@ const MenuGroupLabel = /*#__PURE__*/React.forwardRef(function MenuGroupLabel(com
1258
1250
  useIsoLayoutEffect(() => {
1259
1251
  setLabelId(id);
1260
1252
  return () => {
1261
- setLabelId(currentId => currentId === id ? undefined : currentId);
1253
+ setLabelId(undefined);
1262
1254
  };
1263
1255
  }, [setLabelId, id]);
1264
1256
  return useRenderElement('div', componentProps, {
@@ -1285,13 +1277,12 @@ const MenuItem = /*#__PURE__*/React.forwardRef(function MenuItem(componentProps,
1285
1277
  id: idProp,
1286
1278
  label,
1287
1279
  nativeButton = false,
1288
- disabled: disabledProp = false,
1280
+ disabled = false,
1289
1281
  closeOnClick = true,
1290
1282
  style,
1291
1283
  ...elementProps
1292
1284
  } = componentProps;
1293
1285
  const listItem = useCompositeListItem({
1294
- guess: true,
1295
1286
  label
1296
1287
  });
1297
1288
  const menuPositionerContext = useMenuPositionerContext(true);
@@ -1299,8 +1290,6 @@ const MenuItem = /*#__PURE__*/React.forwardRef(function MenuItem(componentProps,
1299
1290
  const {
1300
1291
  store
1301
1292
  } = useMenuRootContext();
1302
- const rootDisabled = store.useState('disabled');
1303
- const disabled = disabledProp || rootDisabled;
1304
1293
  const highlighted = store.useState('isActive', listItem.index);
1305
1294
  const itemProps = store.useState('itemProps');
1306
1295
  const {
@@ -1346,7 +1335,6 @@ const MenuLinkItem = /*#__PURE__*/React.forwardRef(function MenuLinkItem(compone
1346
1335
  } = componentProps;
1347
1336
  const linkRef = React.useRef(null);
1348
1337
  const listItem = useCompositeListItem({
1349
- guess: true,
1350
1338
  label
1351
1339
  });
1352
1340
  const menuPositionerContext = useMenuPositionerContext(true);
@@ -1372,8 +1360,7 @@ const MenuLinkItem = /*#__PURE__*/React.forwardRef(function MenuLinkItem(compone
1372
1360
  nodeId,
1373
1361
  store,
1374
1362
  typingRef,
1375
- itemRef: linkRef,
1376
- itemMetadata: REGULAR_ITEM
1363
+ itemRef: linkRef
1377
1364
  });
1378
1365
  function getItemProps(externalProps) {
1379
1366
  return mergeProps(commonProps, externalProps, getButtonProps);
@@ -1389,6 +1376,17 @@ const MenuLinkItem = /*#__PURE__*/React.forwardRef(function MenuLinkItem(compone
1389
1376
  });
1390
1377
  if (process.env.NODE_ENV !== "production") MenuLinkItem.displayName = "MenuLinkItem";
1391
1378
 
1379
+ const stateAttributesMapping = {
1380
+ ...popupStateMapping,
1381
+ ...transitionStatusMapping
1382
+ };
1383
+
1384
+ /**
1385
+ * A container for the menu items.
1386
+ * Renders a `<div>` element.
1387
+ *
1388
+ * Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
1389
+ */
1392
1390
  const MenuPopup = /*#__PURE__*/React.forwardRef(function MenuPopup(componentProps, forwardedRef) {
1393
1391
  const {
1394
1392
  render,
@@ -1410,13 +1408,14 @@ const MenuPopup = /*#__PURE__*/React.forwardRef(function MenuPopup(componentProp
1410
1408
  const popupProps = store.useState('popupProps');
1411
1409
  const mounted = store.useState('mounted');
1412
1410
  const instantType = store.useState('instantType');
1413
- const activeTriggerElement = store.useState('activeTriggerElement');
1411
+ const triggerElement = store.useState('activeTriggerElement');
1414
1412
  const parent = store.useState('parent');
1415
1413
  const lastOpenChangeReason = store.useState('lastOpenChangeReason');
1416
1414
  const rootId = store.useState('rootId');
1417
1415
  const floatingContext = store.useState('floatingRootContext');
1418
1416
  const floatingTreeRoot = store.useState('floatingTreeRoot');
1419
1417
  const closeDelay = store.useState('closeDelay');
1418
+ const activeTriggerElement = store.useState('activeTriggerElement');
1420
1419
  const hoverEnabled = store.useState('hoverEnabled');
1421
1420
  const disabled = store.useState('disabled');
1422
1421
  const openMethod = store.useState('openMethod');
@@ -1443,7 +1442,9 @@ const MenuPopup = /*#__PURE__*/React.forwardRef(function MenuPopup(componentProp
1443
1442
  enabled: hoverEnabled && !disabled && !isContextMenu && parent.type !== 'menubar',
1444
1443
  closeDelay
1445
1444
  });
1446
- const setPopupElement = store.useStateSetter('popupElement');
1445
+ const setPopupElement = React.useCallback(element => {
1446
+ store.set('popupElement', element);
1447
+ }, [store]);
1447
1448
  const state = {
1448
1449
  transitionStatus,
1449
1450
  side,
@@ -1455,7 +1456,7 @@ const MenuPopup = /*#__PURE__*/React.forwardRef(function MenuPopup(componentProp
1455
1456
  const element = useRenderElement('div', componentProps, {
1456
1457
  state,
1457
1458
  ref: [forwardedRef, store.context.popupRef, setPopupElement],
1458
- stateAttributesMapping: popupTransitionStateMapping,
1459
+ stateAttributesMapping,
1459
1460
  props: [popupProps, {
1460
1461
  onKeyDown(event) {
1461
1462
  if (insideToolbar && COMPOSITE_KEYS.has(event.key)) {
@@ -1467,7 +1468,7 @@ const MenuPopup = /*#__PURE__*/React.forwardRef(function MenuPopup(componentProp
1467
1468
  }]
1468
1469
  });
1469
1470
  let returnFocus = parent.type === undefined || isContextMenu;
1470
- if (activeTriggerElement || parent.type === 'menubar' && lastOpenChangeReason !== outsidePress) {
1471
+ if (triggerElement || parent.type === 'menubar' && lastOpenChangeReason !== outsidePress) {
1471
1472
  returnFocus = true;
1472
1473
  }
1473
1474
  return /*#__PURE__*/jsx(FloatingFocusManager, {
@@ -1555,13 +1556,13 @@ const MenuPositioner = /*#__PURE__*/React.forwardRef(function MenuPositioner(com
1555
1556
  const transitionStatus = store.useState('transitionStatus');
1556
1557
  const positionerElement = store.useState('positionerElement');
1557
1558
  const instantType = store.useState('instantType');
1558
- const adaptiveOrigin = store.useState('adaptiveOrigin');
1559
+ const hasViewport = store.useState('hasViewport');
1559
1560
  const lastOpenChangeReason = store.useState('lastOpenChangeReason');
1560
1561
  const floatingNodeId = store.useState('floatingNodeId');
1561
1562
  const floatingParentNodeId = store.useState('floatingParentNodeId');
1562
1563
  const domReference = floatingRootContext.useState('domReferenceElement');
1563
1564
  const previousTriggerRef = React.useRef(null);
1564
- const runOnceAnimationsFinish = useAnimationsFinished(positionerElement);
1565
+ const runOnceAnimationsFinish = useAnimationsFinished(positionerElement, false, false);
1565
1566
  let anchor = anchorProp;
1566
1567
  let sideOffset = sideOffsetProp;
1567
1568
  let alignOffset = alignOffsetProp;
@@ -1603,12 +1604,9 @@ const MenuPositioner = /*#__PURE__*/React.forwardRef(function MenuPositioner(com
1603
1604
  keepMounted,
1604
1605
  disableAnchorTracking,
1605
1606
  collisionAvoidance,
1606
- shift: contextMenu ? {
1607
- crossAxis: !('side' in collisionAvoidance && collisionAvoidance.side === 'flip'),
1608
- rootBoundary: 'layoutViewport'
1609
- } : undefined,
1607
+ shiftCrossAxis: contextMenu && !('side' in collisionAvoidance && collisionAvoidance.side === 'flip'),
1610
1608
  externalTree: floatingTreeRoot,
1611
- adaptiveOrigin
1609
+ adaptiveOrigin: hasViewport ? adaptiveOrigin : undefined
1612
1610
  });
1613
1611
  React.useEffect(() => {
1614
1612
  function onMenuOpenChange(details) {
@@ -1848,7 +1846,6 @@ const MenuRadioItem = /*#__PURE__*/React.forwardRef(function MenuRadioItem(compo
1848
1846
  ...elementProps
1849
1847
  } = componentProps;
1850
1848
  const listItem = useCompositeListItem({
1851
- guess: true,
1852
1849
  label
1853
1850
  });
1854
1851
  const menuPositionerContext = useMenuPositionerContext(true);
@@ -1863,8 +1860,7 @@ const MenuRadioItem = /*#__PURE__*/React.forwardRef(function MenuRadioItem(compo
1863
1860
  setValue: setSelectedValue,
1864
1861
  disabled: groupDisabled
1865
1862
  } = useMenuRadioGroupContext();
1866
- const rootDisabled = store.useState('disabled');
1867
- const disabled = disabledProp || groupDisabled || rootDisabled;
1863
+ const disabled = groupDisabled || disabledProp;
1868
1864
  const checked = selectedValue === value;
1869
1865
  const {
1870
1866
  getItemProps,
@@ -1886,7 +1882,7 @@ const MenuRadioItem = /*#__PURE__*/React.forwardRef(function MenuRadioItem(compo
1886
1882
  }), [disabled, highlighted, checked]);
1887
1883
  function handleClick(event) {
1888
1884
  const details = createChangeEventDetails(itemPress, event.nativeEvent, undefined, {
1889
- preventUnmountOnClose: NOOP
1885
+ preventUnmountOnClose() {}
1890
1886
  });
1891
1887
  setSelectedValue(value, details);
1892
1888
  }
@@ -1925,7 +1921,6 @@ const MenuRadioItemIndicator = /*#__PURE__*/React.forwardRef(function MenuRadioI
1925
1921
  const indicatorRef = React.useRef(null);
1926
1922
  const {
1927
1923
  transitionStatus,
1928
- mounted,
1929
1924
  setMounted
1930
1925
  } = useTransitionStatus(item.checked);
1931
1926
  useOpenChangeComplete({
@@ -1951,7 +1946,7 @@ const MenuRadioItemIndicator = /*#__PURE__*/React.forwardRef(function MenuRadioI
1951
1946
  'aria-hidden': true,
1952
1947
  ...elementProps
1953
1948
  },
1954
- enabled: keepMounted || mounted
1949
+ enabled: keepMounted || item.checked
1955
1950
  });
1956
1951
  return element;
1957
1952
  });
@@ -1969,35 +1964,36 @@ function useMenubarContext(optional) {
1969
1964
 
1970
1965
  const selectors = {
1971
1966
  ...popupStoreSelectors,
1972
- disabled: state => state.parent.type === 'menubar' ? state.parent.context.disabled || state.disabled : state.disabled,
1973
- modal: state => (state.parent.type === undefined || state.parent.type === 'context-menu') && (state.modal ?? true),
1974
- openMethod: state => state.openMethod,
1975
- allowMouseEnter: state => state.allowMouseEnter,
1976
- highlightItemOnHover: state => state.highlightItemOnHover,
1977
- parent: state => state.parent,
1978
- rootId: state => {
1967
+ disabled: createSelector(state => state.parent.type === 'menubar' ? state.parent.context.disabled || state.disabled : state.disabled),
1968
+ modal: createSelector(state => (state.parent.type === undefined || state.parent.type === 'context-menu') && (state.modal ?? true)),
1969
+ openMethod: createSelector(state => state.openMethod),
1970
+ allowMouseEnter: createSelector(state => state.allowMouseEnter),
1971
+ highlightItemOnHover: createSelector(state => state.highlightItemOnHover),
1972
+ stickIfOpen: createSelector(state => state.stickIfOpen),
1973
+ parent: createSelector(state => state.parent),
1974
+ rootId: createSelector(state => {
1979
1975
  if (state.parent.type === 'menu') {
1980
1976
  return state.parent.store.select('rootId');
1981
1977
  }
1982
1978
  return state.parent.type !== undefined ? state.parent.context.rootId : state.rootId;
1983
- },
1984
- activeIndex: state => state.activeIndex,
1985
- isActive: (state, itemIndex) => state.activeIndex === itemIndex,
1986
- hoverEnabled: state => state.hoverEnabled,
1987
- instantType: state => state.instantType,
1988
- lastOpenChangeReason: state => state.openChangeReason,
1989
- floatingTreeRoot: state => {
1979
+ }),
1980
+ activeIndex: createSelector(state => state.activeIndex),
1981
+ isActive: createSelector((state, itemIndex) => state.activeIndex === itemIndex),
1982
+ hoverEnabled: createSelector(state => state.hoverEnabled),
1983
+ instantType: createSelector(state => state.instantType),
1984
+ lastOpenChangeReason: createSelector(state => state.openChangeReason),
1985
+ floatingTreeRoot: createSelector(state => {
1990
1986
  if (state.parent.type === 'menu') {
1991
1987
  return state.parent.store.select('floatingTreeRoot');
1992
1988
  }
1993
1989
  return state.floatingTreeRoot;
1994
- },
1995
- floatingNodeId: state => state.floatingNodeId,
1996
- floatingParentNodeId: state => state.floatingParentNodeId,
1997
- itemProps: state => state.itemProps,
1998
- closeDelay: state => state.closeDelay,
1999
- adaptiveOrigin: state => state.adaptiveOrigin,
2000
- keyboardEventRelay: state => {
1990
+ }),
1991
+ floatingNodeId: createSelector(state => state.floatingNodeId),
1992
+ floatingParentNodeId: createSelector(state => state.floatingParentNodeId),
1993
+ itemProps: createSelector(state => state.itemProps),
1994
+ closeDelay: createSelector(state => state.closeDelay),
1995
+ hasViewport: createSelector(state => state.hasViewport),
1996
+ keyboardEventRelay: createSelector(state => {
2001
1997
  if (state.keyboardEventRelay) {
2002
1998
  return state.keyboardEventRelay;
2003
1999
  }
@@ -2005,23 +2001,33 @@ const selectors = {
2005
2001
  return state.parent.store.select('keyboardEventRelay');
2006
2002
  }
2007
2003
  return undefined;
2008
- }
2004
+ })
2009
2005
  };
2010
-
2011
- /**
2012
- * The store view that detached handle-backed triggers read from. Both the real `MenuStore` and the
2013
- * inert fallback store satisfy it, so a trigger can read from whichever store the handle currently
2014
- * exposes. Narrowed to the members a trigger actually uses — the trigger-data members plus `setOpen`
2015
- * (called by the focus guards) — so the exposed surface can't bypass the open-change pipeline; on
2016
- * the detached fallback store every one of these mutations is a no-op.
2017
- */
2018
-
2019
2006
  class MenuStore extends ReactStore {
2020
2007
  constructor(initialState) {
2021
2008
  super({
2022
2009
  ...createInitialState(),
2023
2010
  ...initialState
2024
- }, createInitialContext(), selectors);
2011
+ }, {
2012
+ positionerRef: /*#__PURE__*/React.createRef(),
2013
+ popupRef: /*#__PURE__*/React.createRef(),
2014
+ typingRef: {
2015
+ current: false
2016
+ },
2017
+ itemDomElements: {
2018
+ current: []
2019
+ },
2020
+ itemLabels: {
2021
+ current: []
2022
+ },
2023
+ allowMouseUpTriggerRef: {
2024
+ current: false
2025
+ },
2026
+ triggerFocusTargetRef: /*#__PURE__*/React.createRef(),
2027
+ beforeContentFocusGuardRef: /*#__PURE__*/React.createRef(),
2028
+ onOpenChangeComplete: undefined,
2029
+ triggerElements: new PopupTriggerMap()
2030
+ }, selectors);
2025
2031
 
2026
2032
  // Set up propagation of state from parent menu if applicable.
2027
2033
  this.unsubscribeParentListener = this.observe('parent', parent => {
@@ -2057,44 +2063,15 @@ class MenuStore extends ReactStore {
2057
2063
  eventDetails
2058
2064
  });
2059
2065
  }
2066
+ static useStore(externalStore, initialState) {
2067
+ // eslint-disable-next-line react-hooks/rules-of-hooks
2068
+ const internalStore = useRefWithInit(() => {
2069
+ return new MenuStore(initialState);
2070
+ }).current;
2071
+ return externalStore ?? internalStore;
2072
+ }
2060
2073
  unsubscribeParentListener = null;
2061
2074
  }
2062
-
2063
- /**
2064
- * Creates the inert fallback store used by detached handle-backed triggers while no `Menu.Root` is
2065
- * attached. It preserves a menu-specific trigger registry in context so detached triggers can
2066
- * register before migrating to the live root store. `setOpen` is a no-op (matching the inert
2067
- * reads/writes of `NullStore`), so a trigger can hand the store to focus-guard helpers that expect
2068
- * `setOpen` without it ever taking effect while detached.
2069
- */
2070
- function createNullMenuStore() {
2071
- const store = new NullStore(Object.freeze(createInitialState()), Object.freeze(createInitialContext()), selectors);
2072
- return Object.assign(store, {
2073
- setOpen: NOOP
2074
- });
2075
- }
2076
- function createInitialContext() {
2077
- return {
2078
- positionerRef: /*#__PURE__*/React.createRef(),
2079
- popupRef: /*#__PURE__*/React.createRef(),
2080
- typingRef: {
2081
- current: false
2082
- },
2083
- itemDomElements: {
2084
- current: []
2085
- },
2086
- itemLabels: {
2087
- current: []
2088
- },
2089
- allowMouseUpTriggerRef: {
2090
- current: false
2091
- },
2092
- triggerFocusTargetRef: /*#__PURE__*/React.createRef(),
2093
- beforeContentFocusGuardRef: /*#__PURE__*/React.createRef(),
2094
- onOpenChangeComplete: undefined,
2095
- triggerElements: new PopupTriggerMap()
2096
- };
2097
- }
2098
2075
  function createInitialState() {
2099
2076
  return {
2100
2077
  ...createInitialPopupStoreState(),
@@ -2103,6 +2080,7 @@ function createInitialState() {
2103
2080
  openMethod: null,
2104
2081
  allowMouseEnter: false,
2105
2082
  highlightItemOnHover: true,
2083
+ stickIfOpen: true,
2106
2084
  parent: {
2107
2085
  type: undefined
2108
2086
  },
@@ -2117,7 +2095,7 @@ function createInitialState() {
2117
2095
  itemProps: EMPTY_OBJECT,
2118
2096
  keyboardEventRelay: undefined,
2119
2097
  closeDelay: 0,
2120
- adaptiveOrigin: undefined
2098
+ hasViewport: false
2121
2099
  };
2122
2100
  }
2123
2101
 
@@ -2176,13 +2154,14 @@ const MenuRoot = fastComponent(function MenuRoot(props) {
2176
2154
  type: undefined
2177
2155
  };
2178
2156
  }, [contextMenuContext, parentMenuRootContext, menubarContext, isSubmenu]);
2179
- const store = useMenuRootStore({
2157
+ const store = MenuStore.useStore(handle?.store, {
2180
2158
  open: defaultOpen,
2181
2159
  openProp,
2182
2160
  activeTriggerId: defaultTriggerIdProp,
2183
2161
  triggerIdProp,
2184
2162
  parent: parentFromContext
2185
2163
  });
2164
+ useInitialOpenSync(store, openProp, defaultOpen, defaultTriggerIdProp);
2186
2165
  store.useControlledProp('openProp', openProp);
2187
2166
  store.useControlledProp('triggerIdProp', triggerIdProp);
2188
2167
  store.useContextCallback('onOpenChangeComplete', onOpenChangeComplete);
@@ -2227,7 +2206,10 @@ const MenuRoot = fastComponent(function MenuRoot(props) {
2227
2206
  const {
2228
2207
  forceUnmount
2229
2208
  } = useOpenStateTransitions(open, store, () => {
2230
- store.set('allowMouseEnter', false);
2209
+ store.update({
2210
+ allowMouseEnter: false,
2211
+ stickIfOpen: true
2212
+ });
2231
2213
  });
2232
2214
  useIsoLayoutEffect(() => {
2233
2215
  if (contextMenuContext && !parentMenuRootContext) {
@@ -2275,12 +2257,6 @@ const MenuRoot = fastComponent(function MenuRoot(props) {
2275
2257
  }, [open, hoverEnabled, store]);
2276
2258
  const setOpen = useStableCallback((nextOpen, eventDetails) => {
2277
2259
  const reason = eventDetails.reason;
2278
-
2279
- // Read the store directly, as relayed tree events and stale hover timers can request
2280
- // a close after the state changed but before this component re-rendered.
2281
- if (!nextOpen && !store.select('open')) {
2282
- return;
2283
- }
2284
2260
  if (open === nextOpen && eventDetails.trigger === activeTriggerElement && lastOpenChangeReason === reason) {
2285
2261
  return;
2286
2262
  }
@@ -2313,17 +2289,13 @@ const MenuRoot = fastComponent(function MenuRoot(props) {
2313
2289
  allowTouchToCloseRef.current = true;
2314
2290
  allowTouchToCloseTimeout.clear();
2315
2291
  }
2316
-
2317
- // Keyboard and assistive-technology activations produce `detail === 0` clicks;
2318
- // mouse-gesture clicks (including the synthesized drag-release click from
2319
- // `useMenuItemCommonProps`) carry `detail >= 1`.
2320
- const isKeyboardClick = (reason === triggerPress || reason === itemPress) && nativeEvent.detail === 0;
2292
+ const isKeyboardClick = (reason === triggerPress || reason === itemPress) && nativeEvent.detail === 0 && nativeEvent?.isTrusted;
2321
2293
  const isDismissClose = !nextOpen && (reason === escapeKey || reason == null);
2322
2294
  const updatedState = {
2323
2295
  open: nextOpen,
2324
2296
  openChangeReason: reason
2325
2297
  };
2326
- openEventRef.current = eventDetails.event;
2298
+ openEventRef.current = eventDetails.event ?? null;
2327
2299
  setPopupOpenState(updatedState, nextOpen, eventDetails.trigger, shouldPreventUnmountOnClose());
2328
2300
  store.update(updatedState);
2329
2301
  if (parent.type === 'menubar' && (reason === triggerFocus || reason === focusOut || reason === triggerHover || reason === listNavigation || reason === siblingOpen)) {
@@ -2341,11 +2313,7 @@ const MenuRoot = fastComponent(function MenuRoot(props) {
2341
2313
  onOpenChange: setOpen
2342
2314
  });
2343
2315
  const floatingEvents = floatingRootContext.context.events;
2344
-
2345
- // Registered in a layout effect (not a passive one) so `setOpen` emits from imperative
2346
- // `MenuHandle.open()` calls made in the same commit this root mounts — e.g. from another layout
2347
- // effect during a route-transition handoff — are received instead of being silently dropped.
2348
- useIsoLayoutEffect(() => {
2316
+ React.useEffect(() => {
2349
2317
  const handleSetOpenEvent = ({
2350
2318
  open: nextOpen,
2351
2319
  eventDetails
@@ -2474,14 +2442,11 @@ const MenuRoot = fastComponent(function MenuRoot(props) {
2474
2442
  store,
2475
2443
  parent: parentFromContext
2476
2444
  }), [store, parentFromContext]);
2477
- const content = /*#__PURE__*/jsxs(MenuRootContext.Provider, {
2445
+ const content = /*#__PURE__*/jsx(MenuRootContext.Provider, {
2478
2446
  value: context,
2479
- children: [handle && /*#__PURE__*/jsx(PopupHandleAttachment, {
2480
- handle: handle,
2481
- store: store
2482
- }), typeof children === 'function' ? children({
2447
+ children: typeof children === 'function' ? children({
2483
2448
  payload
2484
- }) : children]
2449
+ }) : children
2485
2450
  });
2486
2451
  if (parent.type === undefined || parent.type === 'context-menu') {
2487
2452
  // set up a FloatingTree to provide the context to nested menus
@@ -2493,15 +2458,6 @@ const MenuRoot = fastComponent(function MenuRoot(props) {
2493
2458
  return content;
2494
2459
  });
2495
2460
  if (process.env.NODE_ENV !== "production") MenuRoot.displayName = "MenuRoot";
2496
- function useMenuRootStore(initialState) {
2497
- // The store is owned by this Root instance and created exactly once. It is not tied to the handle:
2498
- // the handle attaches to it, so swapping the handle re-attaches rather than recreating state.
2499
- // Default values are only initial values; controlled values and root state are synced after creation.
2500
- // Unlike other popups, Menu wires its floating root context separately (it relays open changes
2501
- // through an event).
2502
- const store = useRefWithInit(() => new MenuStore(initialState)).current;
2503
- return store;
2504
- }
2505
2461
 
2506
2462
  /**
2507
2463
  * Groups all parts of a submenu.
@@ -2558,6 +2514,9 @@ function useCompositeItem(params = {}) {
2558
2514
  };
2559
2515
  }
2560
2516
 
2517
+ /**
2518
+ * @internal
2519
+ */
2561
2520
  function CompositeItem(componentProps) {
2562
2521
  const {
2563
2522
  render,
@@ -2579,8 +2538,7 @@ function CompositeItem(componentProps) {
2579
2538
  });
2580
2539
  return useRenderElement(tag, componentProps, {
2581
2540
  state,
2582
- // The composite ref attaches first so an outer item wins when nested items share a DOM node.
2583
- ref: [compositeRef, ...refs],
2541
+ ref: [...refs, compositeRef],
2584
2542
  props: [compositeProps, ...props, elementProps],
2585
2543
  stateAttributesMapping
2586
2544
  });
@@ -2588,7 +2546,7 @@ function CompositeItem(componentProps) {
2588
2546
 
2589
2547
  function findRootOwnerId(node) {
2590
2548
  if (isHTMLElement(node) && node.hasAttribute('data-rootownerid')) {
2591
- return node.getAttribute('data-rootownerid');
2549
+ return node.getAttribute('data-rootownerid') ?? undefined;
2592
2550
  }
2593
2551
  if (isLastTraversableNode(node)) {
2594
2552
  return undefined;
@@ -2680,6 +2638,14 @@ function useMixedToggleClickHandler(params) {
2680
2638
  }, [enabled, mouseDownAction, open]);
2681
2639
  }
2682
2640
 
2641
+ const BOUNDARY_OFFSET = 2;
2642
+
2643
+ /**
2644
+ * A button that opens the menu.
2645
+ * Renders a `<button>` element.
2646
+ *
2647
+ * Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
2648
+ */
2683
2649
  const MenuTrigger = fastComponentRef(function MenuTrigger(componentProps, forwardedRef) {
2684
2650
  const {
2685
2651
  render,
@@ -2696,8 +2662,7 @@ const MenuTrigger = fastComponentRef(function MenuTrigger(componentProps, forwar
2696
2662
  ...elementProps
2697
2663
  } = componentProps;
2698
2664
  const rootContext = useMenuRootContext(true);
2699
- const handleStore = usePopupHandleStore(handle);
2700
- const store = handleStore ?? rootContext?.store;
2665
+ const store = handle?.store ?? rootContext?.store;
2701
2666
  if (!store) {
2702
2667
  throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: <Menu.Trigger> must be either used within a <Menu.Root> component or provided with a handle.' : formatErrorMessage(85));
2703
2668
  }
@@ -2757,7 +2722,8 @@ const MenuTrigger = fastComponentRef(function MenuTrigger(componentProps, forwar
2757
2722
  if (mouseUpTarget != null && findRootOwnerId(mouseUpTarget) === store.select('rootId')) {
2758
2723
  return;
2759
2724
  }
2760
- if (isMouseWithinBounds(mouseEvent, triggerRef.current)) {
2725
+ const bounds = getPseudoElementBounds(triggerRef.current);
2726
+ if (mouseEvent.clientX >= bounds.left - BOUNDARY_OFFSET && mouseEvent.clientX <= bounds.right + BOUNDARY_OFFSET && mouseEvent.clientY >= bounds.top - BOUNDARY_OFFSET && mouseEvent.clientY <= bounds.bottom + BOUNDARY_OFFSET) {
2761
2727
  return;
2762
2728
  }
2763
2729
  floatingTreeRoot.events.emit('close', {
@@ -2776,7 +2742,7 @@ const MenuTrigger = fastComponentRef(function MenuTrigger(componentProps, forwar
2776
2742
  const parentMenubarHasSubmenuOpen = isInMenubar && parent.context.hasSubmenuOpen;
2777
2743
  const openOnHover = openOnHoverProp ?? parentMenubarHasSubmenuOpen;
2778
2744
  const hoverProps = useHoverReferenceInteraction(floatingRootContext, {
2779
- enabled: openOnHover && !disabled && (!isInMenubar || parentMenubarHasSubmenuOpen && !isMountedByThisTrigger),
2745
+ enabled: openOnHover && !disabled && parent.type !== 'context-menu' && (!isInMenubar || parentMenubarHasSubmenuOpen && !isMountedByThisTrigger),
2780
2746
  handleClose: safePolygon({
2781
2747
  blockPointerEvents: !isInMenubar
2782
2748
  }),
@@ -2797,7 +2763,7 @@ const MenuTrigger = fastComponentRef(function MenuTrigger(componentProps, forwar
2797
2763
  // only when `isOpenedByThisTrigger` changes.
2798
2764
  const stickIfOpen = useStickIfOpen(isOpenedByThisTrigger, store.select('lastOpenChangeReason'));
2799
2765
  const click = useClick(floatingRootContext, {
2800
- enabled: !disabled,
2766
+ enabled: !disabled && parent.type !== 'context-menu',
2801
2767
  event: isOpenedByThisTrigger && isInMenubar ? 'click' : 'mousedown',
2802
2768
  toggle: true,
2803
2769
  ignoreMouse: false,
@@ -2892,7 +2858,7 @@ function useStickIfOpen(open, openReason) {
2892
2858
  const stickIfOpenTimeout = useTimeout();
2893
2859
  const [stickIfOpen, setStickIfOpen] = React.useState(false);
2894
2860
  useIsoLayoutEffect(() => {
2895
- if (open && openReason === triggerHover) {
2861
+ if (open && openReason === 'trigger-hover') {
2896
2862
  // Only allow "patient" clicks to close the menu if it's open.
2897
2863
  // If they clicked within 500ms of the menu opening, keep it open.
2898
2864
  setStickIfOpen(true);
@@ -2907,6 +2873,8 @@ function useStickIfOpen(open, openReason) {
2907
2873
  return stickIfOpen;
2908
2874
  }
2909
2875
  function useMenuParent() {
2876
+ const contextMenuContext = useContextMenuRootContext(true);
2877
+ const parentContext = useMenuRootContext(true);
2910
2878
  const menubarContext = useMenubarContext(true);
2911
2879
  const parent = React.useMemo(() => {
2912
2880
  if (menubarContext) {
@@ -2915,17 +2883,23 @@ function useMenuParent() {
2915
2883
  context: menubarContext
2916
2884
  };
2917
2885
  }
2886
+
2887
+ // Ensure this is not a Menu nested inside ContextMenu.Trigger.
2888
+ // ContextMenu parentContext is always undefined as ContextMenu.Root is instantiated with
2889
+ // <MenuRootContext.Provider value={undefined}>
2890
+ if (contextMenuContext && !parentContext) {
2891
+ return {
2892
+ type: 'context-menu',
2893
+ context: contextMenuContext
2894
+ };
2895
+ }
2918
2896
  return {
2919
2897
  type: undefined
2920
2898
  };
2921
- }, [menubarContext]);
2899
+ }, [contextMenuContext, parentContext, menubarContext]);
2922
2900
  return parent;
2923
2901
  }
2924
2902
 
2925
- const VOICE_OVER_EXPANDED_PROPS = {
2926
- 'aria-expanded': undefined
2927
- };
2928
-
2929
2903
  /**
2930
2904
  * A menu item that opens a submenu.
2931
2905
  * Renders a `<div>` element.
@@ -2946,12 +2920,7 @@ const MenuSubmenuTrigger = /*#__PURE__*/React.forwardRef(function MenuSubmenuTri
2946
2920
  disabled: disabledProp = false,
2947
2921
  ...elementProps
2948
2922
  } = componentProps;
2949
- const submenuRootContext = useMenuSubmenuRootContext();
2950
- if (!submenuRootContext?.parentMenu) {
2951
- throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: <Menu.SubmenuTrigger> must be placed in <Menu.SubmenuRoot>.' : formatErrorMessage(37));
2952
- }
2953
2923
  const listItem = useCompositeListItem({
2954
- guess: true,
2955
2924
  label
2956
2925
  });
2957
2926
  const menuPositionerContext = useMenuPositionerContext();
@@ -2980,6 +2949,10 @@ const MenuSubmenuTrigger = /*#__PURE__*/React.forwardRef(function MenuSubmenuTri
2980
2949
  triggerElementRef.current = el;
2981
2950
  store.set('activeTriggerElement', el);
2982
2951
  }, [store]);
2952
+ const submenuRootContext = useMenuSubmenuRootContext();
2953
+ if (!submenuRootContext?.parentMenu) {
2954
+ throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: <Menu.SubmenuTrigger> must be placed in <Menu.SubmenuRoot>.' : formatErrorMessage(37));
2955
+ }
2983
2956
  store.useSyncedValue('closeDelay', closeDelay);
2984
2957
  const parentMenuStore = submenuRootContext.parentMenu;
2985
2958
  const rootDisabled = store.useState('disabled');
@@ -2987,7 +2960,7 @@ const MenuSubmenuTrigger = /*#__PURE__*/React.forwardRef(function MenuSubmenuTri
2987
2960
  const disabled = disabledProp || rootDisabled || parentDisabled;
2988
2961
  if (process.env.NODE_ENV !== 'production') {
2989
2962
  // eslint-disable-next-line react-hooks/rules-of-hooks
2990
- React.useEffect(() => {
2963
+ useIsoLayoutEffect(() => {
2991
2964
  const element = triggerElementRef.current;
2992
2965
  if (element && isElementDisabled(element) && !disabled) {
2993
2966
  const ownerStackMessage = SafeReact.captureOwnerStack?.() || '';
@@ -3035,10 +3008,7 @@ const MenuSubmenuTrigger = /*#__PURE__*/React.forwardRef(function MenuSubmenuTri
3035
3008
  shouldOpen: delay > 0 ? () => parentMenuStore.select('allowMouseEnter') : undefined,
3036
3009
  triggerElementRef,
3037
3010
  externalTree: floatingTreeRoot,
3038
- isClosing: () => store.select('transitionStatus') === 'ending',
3039
- // Chrome can drop the trigger's `mouseleave` during a fast pointer sweep,
3040
- // leaving a stale submenu open (see #5152) — cancel from `mouseout` too.
3041
- guardStaleOpen: true
3011
+ isClosing: () => store.select('transitionStatus') === 'ending'
3042
3012
  });
3043
3013
  const click = useClick(floatingRootContext, {
3044
3014
  enabled: !disabled,
@@ -3055,22 +3025,10 @@ const MenuSubmenuTrigger = /*#__PURE__*/React.forwardRef(function MenuSubmenuTri
3055
3025
  highlighted,
3056
3026
  open
3057
3027
  };
3058
- const openMethod = store.useState('openMethod');
3059
- const lastOpenChangeReason = store.useState('lastOpenChangeReason');
3060
- // Arrow keys open the submenu through list navigation without dispatching a click, so
3061
- // `openMethod` stays null there; Enter and Space do dispatch one and report `keyboard`.
3062
- const openedByKeyboard = lastOpenChangeReason === listNavigation || openMethod === 'keyboard';
3063
- const shouldOmitExpanded = open && openedByKeyboard && voiceOver;
3064
3028
  const element = useRenderElement('div', componentProps, {
3065
3029
  state,
3066
3030
  stateAttributesMapping: triggerOpenStateMapping,
3067
- props: [localInteractionProps, hoverProps, rootTriggerProps, itemProps,
3068
- // Opening a submenu changes the trigger's expanded state while the trigger still holds
3069
- // focus, and VoiceOver announces that state change instead of the submenu item that focus
3070
- // moves to a moment later, so the first item is never announced. Dropping the state while
3071
- // the submenu is open avoids the announcement without claiming the submenu is collapsed;
3072
- // `aria-haspopup` still conveys that the item opens a submenu.
3073
- shouldOmitExpanded ? VOICE_OVER_EXPANDED_PROPS : undefined, {
3031
+ props: [localInteractionProps, hoverProps, rootTriggerProps, itemProps, {
3074
3032
  'aria-controls': popupId,
3075
3033
  tabIndex: open || highlighted ? 0 : -1,
3076
3034
  onBlur() {
@@ -3085,4 +3043,4 @@ const MenuSubmenuTrigger = /*#__PURE__*/React.forwardRef(function MenuSubmenuTri
3085
3043
  });
3086
3044
  if (process.env.NODE_ENV !== "production") MenuSubmenuTrigger.displayName = "MenuSubmenuTrigger";
3087
3045
 
3088
- export { MenuTrigger as M, REGULAR_ITEM as R, MenuLinkItem as a, MenuItem as b, MenuRadioItem as c, MenuRadioItemIndicator as d, MenuSubmenuTrigger as e, MenuRoot as f, MenuPortal as g, MenuBackdrop as h, MenuPositioner as i, MenuPopup as j, MenuRadioGroup as k, MenuGroup as l, MenuSubmenuRoot as m, MenuGroupLabel as n, useMenuPositionerContext as o, useMenuItem as p, itemMapping as q, createNullMenuStore as r, useMenuRootContext as u };
3046
+ export { MenuTrigger as M, REGULAR_ITEM as R, MenuLinkItem as a, MenuItem as b, MenuRadioItem as c, MenuRadioItemIndicator as d, MenuSubmenuTrigger as e, MenuRoot as f, MenuPortal as g, MenuBackdrop as h, MenuPositioner as i, MenuPopup as j, MenuRadioGroup as k, MenuGroup as l, MenuSubmenuRoot as m, MenuGroupLabel as n, useMenuPositionerContext as o, useMenuItem as p, itemMapping as q, MenuStore as r, useMenuRootContext as u };