@jobber/components 9.5.3 → 9.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Combobox.d.ts +1 -0
- package/Combobox.js +17 -0
- package/dist/Autocomplete/index.cjs +0 -2
- package/dist/Autocomplete/index.mjs +0 -2
- package/dist/Autocomplete-cjs.js +4 -5
- package/dist/Autocomplete-es.js +1 -2
- package/dist/Card/index.cjs +2 -2
- package/dist/Card/index.mjs +2 -2
- package/dist/Chip/index.cjs +0 -2
- package/dist/Chip/index.mjs +0 -2
- package/dist/Chips/InternalChipDismissible/hooks/index.cjs +0 -2
- package/dist/Chips/InternalChipDismissible/hooks/index.mjs +0 -2
- package/dist/Chips/InternalChipDismissible/index.cjs +0 -2
- package/dist/Chips/InternalChipDismissible/index.mjs +0 -2
- package/dist/Chips/index.cjs +0 -2
- package/dist/Chips/index.mjs +0 -2
- package/dist/Combobox/Combobox.contentSlots.d.ts +5 -0
- package/dist/Combobox/Combobox.context.d.ts +34 -0
- package/dist/Combobox/Combobox.d.ts +69 -0
- package/dist/Combobox/Combobox.footer.d.ts +7 -0
- package/dist/Combobox/Combobox.items.d.ts +25 -0
- package/dist/Combobox/Combobox.responsive.d.ts +54 -0
- package/dist/Combobox/Combobox.selectAll.d.ts +4 -0
- package/dist/Combobox/Combobox.slotFactory.d.ts +7 -0
- package/dist/Combobox/Combobox.testUtils.d.ts +12 -0
- package/dist/Combobox/Combobox.types.d.ts +166 -0
- package/dist/Combobox/index.cjs +35 -0
- package/dist/Combobox/index.d.ts +2 -0
- package/dist/Combobox/index.mjs +29 -0
- package/dist/Combobox-cjs.js +675 -0
- package/dist/Combobox-es.js +673 -0
- package/dist/ComboboxPrimitive-cjs.js +88 -47
- package/dist/ComboboxPrimitive-es.js +39 -23
- package/dist/{ComboboxChipRemove-cjs.js → ComboboxSeparator-cjs.js} +501 -455
- package/dist/{ComboboxChipRemove-es.js → ComboboxSeparator-es.js} +500 -456
- package/dist/ConfirmationModal/index.cjs +0 -2
- package/dist/ConfirmationModal/index.mjs +0 -2
- package/dist/ContentBlock/index.cjs +1 -0
- package/dist/ContentBlock/index.mjs +1 -0
- package/dist/ContentBlock-cjs.js +2 -18
- package/dist/ContentBlock-es.js +1 -17
- package/dist/DataDump/index.cjs +2 -2
- package/dist/DataDump/index.mjs +2 -2
- package/dist/DataList/components/DataListActions/index.cjs +0 -2
- package/dist/DataList/components/DataListActions/index.mjs +0 -2
- package/dist/DataList/components/DataListBulkActions/index.cjs +0 -2
- package/dist/DataList/components/DataListBulkActions/index.mjs +0 -2
- package/dist/DataList/components/DataListFilters/components/DataListSort/index.cjs +0 -2
- package/dist/DataList/components/DataListFilters/components/DataListSort/index.mjs +0 -2
- package/dist/DataList/components/DataListFilters/index.cjs +0 -2
- package/dist/DataList/components/DataListFilters/index.mjs +0 -2
- package/dist/DataList/components/DataListHeader/index.cjs +0 -2
- package/dist/DataList/components/DataListHeader/index.mjs +0 -2
- package/dist/DataList/components/DataListItem/index.cjs +0 -2
- package/dist/DataList/components/DataListItem/index.mjs +0 -2
- package/dist/DataList/components/DataListItemActions/index.cjs +0 -2
- package/dist/DataList/components/DataListItemActions/index.mjs +0 -2
- package/dist/DataList/components/DataListItemActionsOverflow/index.cjs +0 -2
- package/dist/DataList/components/DataListItemActionsOverflow/index.mjs +0 -2
- package/dist/DataList/components/DataListItems/index.cjs +0 -2
- package/dist/DataList/components/DataListItems/index.mjs +0 -2
- package/dist/DataList/components/DataListLayout/index.cjs +0 -2
- package/dist/DataList/components/DataListLayout/index.mjs +0 -2
- package/dist/DataList/components/DataListLayoutActions/index.cjs +0 -2
- package/dist/DataList/components/DataListLayoutActions/index.mjs +0 -2
- package/dist/DataList/index.cjs +0 -2
- package/dist/DataList/index.mjs +0 -2
- package/dist/DatePicker/index.cjs +0 -2
- package/dist/DatePicker/index.mjs +0 -2
- package/dist/DatePicker-cjs.js +4 -5
- package/dist/DatePicker-es.js +1 -2
- package/dist/Dialog/index.cjs +2 -2
- package/dist/Dialog/index.mjs +2 -2
- package/dist/DrawerDescription-cjs.js +268 -99
- package/dist/DrawerDescription-es.js +270 -103
- package/dist/DrawerTitle-cjs.js +2 -6
- package/dist/DrawerTitle-es.js +3 -7
- package/dist/FieldDescription-cjs.js +184 -181
- package/dist/FieldDescription-es.js +187 -184
- package/dist/FilterPicker/components/FilterPickerActivator/index.cjs +0 -2
- package/dist/FilterPicker/components/FilterPickerActivator/index.mjs +0 -2
- package/dist/FilterPicker/components/FilterPickerContent/index.cjs +0 -2
- package/dist/FilterPicker/components/FilterPickerContent/index.mjs +0 -2
- package/dist/FilterPicker/components/FilterPickerTrigger/index.cjs +0 -2
- package/dist/FilterPicker/components/FilterPickerTrigger/index.mjs +0 -2
- package/dist/FilterPicker/index.cjs +0 -2
- package/dist/FilterPicker/index.mjs +0 -2
- package/dist/FilterPickerContent-cjs.js +4 -5
- package/dist/FilterPickerContent-es.js +1 -2
- package/dist/FormatFile/index.cjs +0 -2
- package/dist/FormatFile/index.mjs +0 -2
- package/dist/Gallery/index.cjs +0 -2
- package/dist/Gallery/index.mjs +0 -2
- package/dist/InputDate/index.cjs +0 -2
- package/dist/InputDate/index.mjs +0 -2
- package/dist/InputNumber/index.cjs +2 -2
- package/dist/InputNumber/index.mjs +2 -2
- package/dist/InputNumber/types.d.ts +5 -0
- package/dist/InputNumber-cjs.js +2 -2
- package/dist/InputNumber-es.js +2 -2
- package/dist/LightBox/index.cjs +0 -2
- package/dist/LightBox/index.mjs +0 -2
- package/dist/Menu/index.cjs +2 -2
- package/dist/Menu/index.mjs +2 -2
- package/dist/Menu-cjs.js +4 -5
- package/dist/Menu-es.js +1 -2
- package/dist/MenuSubmenuTrigger-cjs.js +206 -164
- package/dist/MenuSubmenuTrigger-es.js +194 -152
- package/dist/Modal/index.cjs +0 -2
- package/dist/Modal/index.mjs +1 -3
- package/dist/NumberFieldInput-cjs.js +187 -308
- package/dist/NumberFieldInput-es.js +187 -308
- package/dist/Page/index.cjs +2 -2
- package/dist/Page/index.mjs +2 -2
- package/dist/Popover/index.cjs +0 -2
- package/dist/Popover/index.mjs +0 -2
- package/dist/Popover-cjs.js +7 -8
- package/dist/Popover-es.js +1 -2
- package/dist/ScrollAreaViewport-cjs.js +747 -1093
- package/dist/ScrollAreaViewport-es.js +734 -1081
- package/dist/Select/index.cjs +2 -2
- package/dist/Select/index.mjs +2 -2
- package/dist/SelectGroupLabel-cjs.js +207 -306
- package/dist/SelectGroupLabel-es.js +203 -302
- package/dist/SelectPrimitive-cjs.js +11 -17
- package/dist/SelectPrimitive-es.js +1 -7
- package/dist/Tooltip/index.cjs +0 -2
- package/dist/Tooltip/index.mjs +0 -2
- package/dist/Tooltip-cjs.js +6 -7
- package/dist/Tooltip-es.js +1 -2
- package/dist/buttonRenderAdapter-cjs.js +2 -1
- package/dist/buttonRenderAdapter-es.js +2 -1
- package/dist/dialogReturnFocus-cjs.js +1 -1
- package/dist/dialogReturnFocus-es.js +2 -2
- package/dist/docs/InputNumber/InputNumber.md +2 -2
- package/dist/docs/SelectPrimitive/SelectPrimitive.md +1 -1
- package/dist/floating-ui.react-cjs.js +2557 -185
- package/dist/floating-ui.react-es.js +2512 -149
- package/dist/getMappedBreakpointWidth-cjs.js +21 -0
- package/dist/getMappedBreakpointWidth-es.js +18 -0
- package/dist/index.cjs +15 -10
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +14 -10
- package/dist/mergeClassName-cjs.js +12 -0
- package/dist/mergeClassName-es.js +10 -0
- package/dist/primitives/BottomSheet/index.cjs +1 -1
- package/dist/primitives/BottomSheet/index.mjs +1 -1
- package/dist/primitives/ComboboxPrimitive/ComboboxPrimitive.d.ts +2 -2
- package/dist/primitives/ComboboxPrimitive/index.cjs +4 -5
- package/dist/primitives/ComboboxPrimitive/index.mjs +4 -5
- package/dist/primitives/SelectPrimitive/index.cjs +1 -2
- package/dist/primitives/SelectPrimitive/index.mjs +1 -2
- package/dist/primitives/index.cjs +3 -3
- package/dist/primitives/index.mjs +3 -3
- package/dist/scrollEdges-cjs.js +1 -11
- package/dist/scrollEdges-es.js +1 -11
- package/dist/scrollable-cjs.js +58 -0
- package/dist/scrollable-es.js +54 -0
- package/dist/styles.css +759 -42
- package/dist/unstyledPrimitives/index.cjs +720 -478
- package/dist/unstyledPrimitives/index.mjs +663 -421
- package/dist/useCompositeListItem-cjs.js +2108 -361
- package/dist/useCompositeListItem-es.js +2076 -331
- package/dist/useLabel-cjs.js +2 -3
- package/dist/useLabel-es.js +2 -3
- package/dist/useRenderElement-cjs.js +9 -7
- package/dist/useRenderElement-es.js +9 -7
- package/dist/useScrollLock-cjs.js +819 -344
- package/dist/useScrollLock-es.js +732 -296
- package/dist/useScrollToActive-cjs.js +4 -5
- package/dist/useScrollToActive-es.js +1 -2
- package/dist/utils/meta/meta.json +43 -1
- package/package.json +8 -3
- package/dist/floating-ui.react-dom-cjs.js +0 -2103
- package/dist/floating-ui.react-dom-es.js +0 -2072
- package/dist/floating-ui.utils-cjs.js +0 -342
- package/dist/floating-ui.utils-es.js +0 -300
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
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 {
|
|
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';
|
|
4
4
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
|
-
import {
|
|
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';
|
|
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 {
|
|
9
|
-
import { p as popupStoreSelectors, n as createInitialPopupStoreState } from './ScrollAreaViewport-es.js';
|
|
8
|
+
import { N as NullStore, o as createInitialPopupStoreState, p as popupStoreSelectors, q as usePopupHandleStore } from './ScrollAreaViewport-es.js';
|
|
10
9
|
import * as ReactDOM from 'react-dom';
|
|
11
10
|
|
|
12
11
|
function resolveValue(value, pointerType) {
|
|
@@ -438,7 +437,8 @@ function useHoverReferenceInteraction(context, props = {}) {
|
|
|
438
437
|
isActiveTrigger = true,
|
|
439
438
|
getHandleCloseContext,
|
|
440
439
|
isClosing,
|
|
441
|
-
shouldOpen: shouldOpenProp
|
|
440
|
+
shouldOpen: shouldOpenProp,
|
|
441
|
+
guardStaleOpen = false
|
|
442
442
|
} = props;
|
|
443
443
|
const store = 'rootStore' in context ? context.rootStore : context;
|
|
444
444
|
const {
|
|
@@ -640,13 +640,24 @@ 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;
|
|
643
654
|
if (move) {
|
|
644
655
|
return mergeCleanups(addEventListener(trigger, 'mousemove', onMouseEnter, {
|
|
645
656
|
once: true
|
|
646
|
-
}), addEventListener(trigger, 'mouseenter', onMouseEnter), addEventListener(trigger, 'mouseleave', onMouseLeave));
|
|
657
|
+
}), addEventListener(trigger, 'mouseenter', onMouseEnter), addEventListener(trigger, 'mouseleave', onMouseLeave), staleOpenGuard);
|
|
647
658
|
}
|
|
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]);
|
|
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]);
|
|
650
661
|
return React.useMemo(() => {
|
|
651
662
|
if (!enabled) {
|
|
652
663
|
return undefined;
|
|
@@ -987,11 +998,6 @@ function useContextMenuRootContext(optional = true) {
|
|
|
987
998
|
return context;
|
|
988
999
|
}
|
|
989
1000
|
|
|
990
|
-
const stateAttributesMapping$1 = {
|
|
991
|
-
...popupStateMapping,
|
|
992
|
-
...transitionStatusMapping
|
|
993
|
-
};
|
|
994
|
-
|
|
995
1001
|
/**
|
|
996
1002
|
* An overlay displayed beneath the menu popup.
|
|
997
1003
|
* Renders a `<div>` element.
|
|
@@ -1020,7 +1026,7 @@ const MenuBackdrop = /*#__PURE__*/React.forwardRef(function MenuBackdrop(compone
|
|
|
1020
1026
|
return useRenderElement('div', componentProps, {
|
|
1021
1027
|
ref: contextMenuContext?.backdropRef ? [forwardedRef, contextMenuContext.backdropRef] : forwardedRef,
|
|
1022
1028
|
state,
|
|
1023
|
-
stateAttributesMapping:
|
|
1029
|
+
stateAttributesMapping: popupTransitionStateMapping,
|
|
1024
1030
|
props: [{
|
|
1025
1031
|
role: 'presentation',
|
|
1026
1032
|
hidden: !mounted,
|
|
@@ -1102,8 +1108,12 @@ function useMenuItemCommonProps(params) {
|
|
|
1102
1108
|
if (itemRef.current && store.context.allowMouseUpTriggerRef.current && (!isContextMenu || event.button === 2)) {
|
|
1103
1109
|
// This fires whenever the user clicks on the trigger, moves the cursor, and releases it over the item.
|
|
1104
1110
|
// We trigger the click and override the `closeOnClick` preference to always close the menu.
|
|
1105
|
-
if (
|
|
1106
|
-
|
|
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
|
+
});
|
|
1107
1117
|
}
|
|
1108
1118
|
}
|
|
1109
1119
|
}
|
|
@@ -1116,7 +1126,7 @@ const REGULAR_ITEM = {
|
|
|
1116
1126
|
function useMenuItem(params) {
|
|
1117
1127
|
const {
|
|
1118
1128
|
closeOnClick,
|
|
1119
|
-
disabled
|
|
1129
|
+
disabled,
|
|
1120
1130
|
highlighted,
|
|
1121
1131
|
id,
|
|
1122
1132
|
store,
|
|
@@ -1125,8 +1135,6 @@ function useMenuItem(params) {
|
|
|
1125
1135
|
itemMetadata,
|
|
1126
1136
|
nodeId
|
|
1127
1137
|
} = params;
|
|
1128
|
-
const rootDisabled = store.useState('disabled');
|
|
1129
|
-
const disabled = disabledProp || rootDisabled;
|
|
1130
1138
|
const itemRef = React.useRef(null);
|
|
1131
1139
|
const {
|
|
1132
1140
|
getButtonProps,
|
|
@@ -1250,7 +1258,7 @@ const MenuGroupLabel = /*#__PURE__*/React.forwardRef(function MenuGroupLabel(com
|
|
|
1250
1258
|
useIsoLayoutEffect(() => {
|
|
1251
1259
|
setLabelId(id);
|
|
1252
1260
|
return () => {
|
|
1253
|
-
setLabelId(undefined);
|
|
1261
|
+
setLabelId(currentId => currentId === id ? undefined : currentId);
|
|
1254
1262
|
};
|
|
1255
1263
|
}, [setLabelId, id]);
|
|
1256
1264
|
return useRenderElement('div', componentProps, {
|
|
@@ -1277,12 +1285,13 @@ const MenuItem = /*#__PURE__*/React.forwardRef(function MenuItem(componentProps,
|
|
|
1277
1285
|
id: idProp,
|
|
1278
1286
|
label,
|
|
1279
1287
|
nativeButton = false,
|
|
1280
|
-
disabled = false,
|
|
1288
|
+
disabled: disabledProp = false,
|
|
1281
1289
|
closeOnClick = true,
|
|
1282
1290
|
style,
|
|
1283
1291
|
...elementProps
|
|
1284
1292
|
} = componentProps;
|
|
1285
1293
|
const listItem = useCompositeListItem({
|
|
1294
|
+
guess: true,
|
|
1286
1295
|
label
|
|
1287
1296
|
});
|
|
1288
1297
|
const menuPositionerContext = useMenuPositionerContext(true);
|
|
@@ -1290,6 +1299,8 @@ const MenuItem = /*#__PURE__*/React.forwardRef(function MenuItem(componentProps,
|
|
|
1290
1299
|
const {
|
|
1291
1300
|
store
|
|
1292
1301
|
} = useMenuRootContext();
|
|
1302
|
+
const rootDisabled = store.useState('disabled');
|
|
1303
|
+
const disabled = disabledProp || rootDisabled;
|
|
1293
1304
|
const highlighted = store.useState('isActive', listItem.index);
|
|
1294
1305
|
const itemProps = store.useState('itemProps');
|
|
1295
1306
|
const {
|
|
@@ -1335,6 +1346,7 @@ const MenuLinkItem = /*#__PURE__*/React.forwardRef(function MenuLinkItem(compone
|
|
|
1335
1346
|
} = componentProps;
|
|
1336
1347
|
const linkRef = React.useRef(null);
|
|
1337
1348
|
const listItem = useCompositeListItem({
|
|
1349
|
+
guess: true,
|
|
1338
1350
|
label
|
|
1339
1351
|
});
|
|
1340
1352
|
const menuPositionerContext = useMenuPositionerContext(true);
|
|
@@ -1360,7 +1372,8 @@ const MenuLinkItem = /*#__PURE__*/React.forwardRef(function MenuLinkItem(compone
|
|
|
1360
1372
|
nodeId,
|
|
1361
1373
|
store,
|
|
1362
1374
|
typingRef,
|
|
1363
|
-
itemRef: linkRef
|
|
1375
|
+
itemRef: linkRef,
|
|
1376
|
+
itemMetadata: REGULAR_ITEM
|
|
1364
1377
|
});
|
|
1365
1378
|
function getItemProps(externalProps) {
|
|
1366
1379
|
return mergeProps(commonProps, externalProps, getButtonProps);
|
|
@@ -1376,17 +1389,6 @@ const MenuLinkItem = /*#__PURE__*/React.forwardRef(function MenuLinkItem(compone
|
|
|
1376
1389
|
});
|
|
1377
1390
|
if (process.env.NODE_ENV !== "production") MenuLinkItem.displayName = "MenuLinkItem";
|
|
1378
1391
|
|
|
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
|
-
*/
|
|
1390
1392
|
const MenuPopup = /*#__PURE__*/React.forwardRef(function MenuPopup(componentProps, forwardedRef) {
|
|
1391
1393
|
const {
|
|
1392
1394
|
render,
|
|
@@ -1408,14 +1410,13 @@ const MenuPopup = /*#__PURE__*/React.forwardRef(function MenuPopup(componentProp
|
|
|
1408
1410
|
const popupProps = store.useState('popupProps');
|
|
1409
1411
|
const mounted = store.useState('mounted');
|
|
1410
1412
|
const instantType = store.useState('instantType');
|
|
1411
|
-
const
|
|
1413
|
+
const activeTriggerElement = store.useState('activeTriggerElement');
|
|
1412
1414
|
const parent = store.useState('parent');
|
|
1413
1415
|
const lastOpenChangeReason = store.useState('lastOpenChangeReason');
|
|
1414
1416
|
const rootId = store.useState('rootId');
|
|
1415
1417
|
const floatingContext = store.useState('floatingRootContext');
|
|
1416
1418
|
const floatingTreeRoot = store.useState('floatingTreeRoot');
|
|
1417
1419
|
const closeDelay = store.useState('closeDelay');
|
|
1418
|
-
const activeTriggerElement = store.useState('activeTriggerElement');
|
|
1419
1420
|
const hoverEnabled = store.useState('hoverEnabled');
|
|
1420
1421
|
const disabled = store.useState('disabled');
|
|
1421
1422
|
const openMethod = store.useState('openMethod');
|
|
@@ -1442,9 +1443,7 @@ const MenuPopup = /*#__PURE__*/React.forwardRef(function MenuPopup(componentProp
|
|
|
1442
1443
|
enabled: hoverEnabled && !disabled && !isContextMenu && parent.type !== 'menubar',
|
|
1443
1444
|
closeDelay
|
|
1444
1445
|
});
|
|
1445
|
-
const setPopupElement =
|
|
1446
|
-
store.set('popupElement', element);
|
|
1447
|
-
}, [store]);
|
|
1446
|
+
const setPopupElement = store.useStateSetter('popupElement');
|
|
1448
1447
|
const state = {
|
|
1449
1448
|
transitionStatus,
|
|
1450
1449
|
side,
|
|
@@ -1456,7 +1455,7 @@ const MenuPopup = /*#__PURE__*/React.forwardRef(function MenuPopup(componentProp
|
|
|
1456
1455
|
const element = useRenderElement('div', componentProps, {
|
|
1457
1456
|
state,
|
|
1458
1457
|
ref: [forwardedRef, store.context.popupRef, setPopupElement],
|
|
1459
|
-
stateAttributesMapping,
|
|
1458
|
+
stateAttributesMapping: popupTransitionStateMapping,
|
|
1460
1459
|
props: [popupProps, {
|
|
1461
1460
|
onKeyDown(event) {
|
|
1462
1461
|
if (insideToolbar && COMPOSITE_KEYS.has(event.key)) {
|
|
@@ -1468,7 +1467,7 @@ const MenuPopup = /*#__PURE__*/React.forwardRef(function MenuPopup(componentProp
|
|
|
1468
1467
|
}]
|
|
1469
1468
|
});
|
|
1470
1469
|
let returnFocus = parent.type === undefined || isContextMenu;
|
|
1471
|
-
if (
|
|
1470
|
+
if (activeTriggerElement || parent.type === 'menubar' && lastOpenChangeReason !== outsidePress) {
|
|
1472
1471
|
returnFocus = true;
|
|
1473
1472
|
}
|
|
1474
1473
|
return /*#__PURE__*/jsx(FloatingFocusManager, {
|
|
@@ -1556,13 +1555,13 @@ const MenuPositioner = /*#__PURE__*/React.forwardRef(function MenuPositioner(com
|
|
|
1556
1555
|
const transitionStatus = store.useState('transitionStatus');
|
|
1557
1556
|
const positionerElement = store.useState('positionerElement');
|
|
1558
1557
|
const instantType = store.useState('instantType');
|
|
1559
|
-
const
|
|
1558
|
+
const adaptiveOrigin = store.useState('adaptiveOrigin');
|
|
1560
1559
|
const lastOpenChangeReason = store.useState('lastOpenChangeReason');
|
|
1561
1560
|
const floatingNodeId = store.useState('floatingNodeId');
|
|
1562
1561
|
const floatingParentNodeId = store.useState('floatingParentNodeId');
|
|
1563
1562
|
const domReference = floatingRootContext.useState('domReferenceElement');
|
|
1564
1563
|
const previousTriggerRef = React.useRef(null);
|
|
1565
|
-
const runOnceAnimationsFinish = useAnimationsFinished(positionerElement
|
|
1564
|
+
const runOnceAnimationsFinish = useAnimationsFinished(positionerElement);
|
|
1566
1565
|
let anchor = anchorProp;
|
|
1567
1566
|
let sideOffset = sideOffsetProp;
|
|
1568
1567
|
let alignOffset = alignOffsetProp;
|
|
@@ -1604,9 +1603,12 @@ const MenuPositioner = /*#__PURE__*/React.forwardRef(function MenuPositioner(com
|
|
|
1604
1603
|
keepMounted,
|
|
1605
1604
|
disableAnchorTracking,
|
|
1606
1605
|
collisionAvoidance,
|
|
1607
|
-
|
|
1606
|
+
shift: contextMenu ? {
|
|
1607
|
+
crossAxis: !('side' in collisionAvoidance && collisionAvoidance.side === 'flip'),
|
|
1608
|
+
rootBoundary: 'layoutViewport'
|
|
1609
|
+
} : undefined,
|
|
1608
1610
|
externalTree: floatingTreeRoot,
|
|
1609
|
-
adaptiveOrigin
|
|
1611
|
+
adaptiveOrigin
|
|
1610
1612
|
});
|
|
1611
1613
|
React.useEffect(() => {
|
|
1612
1614
|
function onMenuOpenChange(details) {
|
|
@@ -1846,6 +1848,7 @@ const MenuRadioItem = /*#__PURE__*/React.forwardRef(function MenuRadioItem(compo
|
|
|
1846
1848
|
...elementProps
|
|
1847
1849
|
} = componentProps;
|
|
1848
1850
|
const listItem = useCompositeListItem({
|
|
1851
|
+
guess: true,
|
|
1849
1852
|
label
|
|
1850
1853
|
});
|
|
1851
1854
|
const menuPositionerContext = useMenuPositionerContext(true);
|
|
@@ -1860,7 +1863,8 @@ const MenuRadioItem = /*#__PURE__*/React.forwardRef(function MenuRadioItem(compo
|
|
|
1860
1863
|
setValue: setSelectedValue,
|
|
1861
1864
|
disabled: groupDisabled
|
|
1862
1865
|
} = useMenuRadioGroupContext();
|
|
1863
|
-
const
|
|
1866
|
+
const rootDisabled = store.useState('disabled');
|
|
1867
|
+
const disabled = disabledProp || groupDisabled || rootDisabled;
|
|
1864
1868
|
const checked = selectedValue === value;
|
|
1865
1869
|
const {
|
|
1866
1870
|
getItemProps,
|
|
@@ -1882,7 +1886,7 @@ const MenuRadioItem = /*#__PURE__*/React.forwardRef(function MenuRadioItem(compo
|
|
|
1882
1886
|
}), [disabled, highlighted, checked]);
|
|
1883
1887
|
function handleClick(event) {
|
|
1884
1888
|
const details = createChangeEventDetails(itemPress, event.nativeEvent, undefined, {
|
|
1885
|
-
preventUnmountOnClose
|
|
1889
|
+
preventUnmountOnClose: NOOP
|
|
1886
1890
|
});
|
|
1887
1891
|
setSelectedValue(value, details);
|
|
1888
1892
|
}
|
|
@@ -1921,6 +1925,7 @@ const MenuRadioItemIndicator = /*#__PURE__*/React.forwardRef(function MenuRadioI
|
|
|
1921
1925
|
const indicatorRef = React.useRef(null);
|
|
1922
1926
|
const {
|
|
1923
1927
|
transitionStatus,
|
|
1928
|
+
mounted,
|
|
1924
1929
|
setMounted
|
|
1925
1930
|
} = useTransitionStatus(item.checked);
|
|
1926
1931
|
useOpenChangeComplete({
|
|
@@ -1946,7 +1951,7 @@ const MenuRadioItemIndicator = /*#__PURE__*/React.forwardRef(function MenuRadioI
|
|
|
1946
1951
|
'aria-hidden': true,
|
|
1947
1952
|
...elementProps
|
|
1948
1953
|
},
|
|
1949
|
-
enabled: keepMounted ||
|
|
1954
|
+
enabled: keepMounted || mounted
|
|
1950
1955
|
});
|
|
1951
1956
|
return element;
|
|
1952
1957
|
});
|
|
@@ -1964,36 +1969,35 @@ function useMenubarContext(optional) {
|
|
|
1964
1969
|
|
|
1965
1970
|
const selectors = {
|
|
1966
1971
|
...popupStoreSelectors,
|
|
1967
|
-
disabled:
|
|
1968
|
-
modal:
|
|
1969
|
-
openMethod:
|
|
1970
|
-
allowMouseEnter:
|
|
1971
|
-
highlightItemOnHover:
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
rootId: createSelector(state => {
|
|
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 => {
|
|
1975
1979
|
if (state.parent.type === 'menu') {
|
|
1976
1980
|
return state.parent.store.select('rootId');
|
|
1977
1981
|
}
|
|
1978
1982
|
return state.parent.type !== undefined ? state.parent.context.rootId : state.rootId;
|
|
1979
|
-
}
|
|
1980
|
-
activeIndex:
|
|
1981
|
-
isActive:
|
|
1982
|
-
hoverEnabled:
|
|
1983
|
-
instantType:
|
|
1984
|
-
lastOpenChangeReason:
|
|
1985
|
-
floatingTreeRoot:
|
|
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 => {
|
|
1986
1990
|
if (state.parent.type === 'menu') {
|
|
1987
1991
|
return state.parent.store.select('floatingTreeRoot');
|
|
1988
1992
|
}
|
|
1989
1993
|
return state.floatingTreeRoot;
|
|
1990
|
-
}
|
|
1991
|
-
floatingNodeId:
|
|
1992
|
-
floatingParentNodeId:
|
|
1993
|
-
itemProps:
|
|
1994
|
-
closeDelay:
|
|
1995
|
-
|
|
1996
|
-
keyboardEventRelay:
|
|
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 => {
|
|
1997
2001
|
if (state.keyboardEventRelay) {
|
|
1998
2002
|
return state.keyboardEventRelay;
|
|
1999
2003
|
}
|
|
@@ -2001,33 +2005,23 @@ const selectors = {
|
|
|
2001
2005
|
return state.parent.store.select('keyboardEventRelay');
|
|
2002
2006
|
}
|
|
2003
2007
|
return undefined;
|
|
2004
|
-
}
|
|
2008
|
+
}
|
|
2005
2009
|
};
|
|
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
|
+
|
|
2006
2019
|
class MenuStore extends ReactStore {
|
|
2007
2020
|
constructor(initialState) {
|
|
2008
2021
|
super({
|
|
2009
2022
|
...createInitialState(),
|
|
2010
2023
|
...initialState
|
|
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);
|
|
2024
|
+
}, createInitialContext(), selectors);
|
|
2031
2025
|
|
|
2032
2026
|
// Set up propagation of state from parent menu if applicable.
|
|
2033
2027
|
this.unsubscribeParentListener = this.observe('parent', parent => {
|
|
@@ -2063,15 +2057,44 @@ class MenuStore extends ReactStore {
|
|
|
2063
2057
|
eventDetails
|
|
2064
2058
|
});
|
|
2065
2059
|
}
|
|
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
|
-
}
|
|
2073
2060
|
unsubscribeParentListener = null;
|
|
2074
2061
|
}
|
|
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
|
+
}
|
|
2075
2098
|
function createInitialState() {
|
|
2076
2099
|
return {
|
|
2077
2100
|
...createInitialPopupStoreState(),
|
|
@@ -2080,7 +2103,6 @@ function createInitialState() {
|
|
|
2080
2103
|
openMethod: null,
|
|
2081
2104
|
allowMouseEnter: false,
|
|
2082
2105
|
highlightItemOnHover: true,
|
|
2083
|
-
stickIfOpen: true,
|
|
2084
2106
|
parent: {
|
|
2085
2107
|
type: undefined
|
|
2086
2108
|
},
|
|
@@ -2095,7 +2117,7 @@ function createInitialState() {
|
|
|
2095
2117
|
itemProps: EMPTY_OBJECT,
|
|
2096
2118
|
keyboardEventRelay: undefined,
|
|
2097
2119
|
closeDelay: 0,
|
|
2098
|
-
|
|
2120
|
+
adaptiveOrigin: undefined
|
|
2099
2121
|
};
|
|
2100
2122
|
}
|
|
2101
2123
|
|
|
@@ -2154,14 +2176,13 @@ const MenuRoot = fastComponent(function MenuRoot(props) {
|
|
|
2154
2176
|
type: undefined
|
|
2155
2177
|
};
|
|
2156
2178
|
}, [contextMenuContext, parentMenuRootContext, menubarContext, isSubmenu]);
|
|
2157
|
-
const store =
|
|
2179
|
+
const store = useMenuRootStore({
|
|
2158
2180
|
open: defaultOpen,
|
|
2159
2181
|
openProp,
|
|
2160
2182
|
activeTriggerId: defaultTriggerIdProp,
|
|
2161
2183
|
triggerIdProp,
|
|
2162
2184
|
parent: parentFromContext
|
|
2163
2185
|
});
|
|
2164
|
-
useInitialOpenSync(store, openProp, defaultOpen, defaultTriggerIdProp);
|
|
2165
2186
|
store.useControlledProp('openProp', openProp);
|
|
2166
2187
|
store.useControlledProp('triggerIdProp', triggerIdProp);
|
|
2167
2188
|
store.useContextCallback('onOpenChangeComplete', onOpenChangeComplete);
|
|
@@ -2206,10 +2227,7 @@ const MenuRoot = fastComponent(function MenuRoot(props) {
|
|
|
2206
2227
|
const {
|
|
2207
2228
|
forceUnmount
|
|
2208
2229
|
} = useOpenStateTransitions(open, store, () => {
|
|
2209
|
-
store.
|
|
2210
|
-
allowMouseEnter: false,
|
|
2211
|
-
stickIfOpen: true
|
|
2212
|
-
});
|
|
2230
|
+
store.set('allowMouseEnter', false);
|
|
2213
2231
|
});
|
|
2214
2232
|
useIsoLayoutEffect(() => {
|
|
2215
2233
|
if (contextMenuContext && !parentMenuRootContext) {
|
|
@@ -2257,6 +2275,12 @@ const MenuRoot = fastComponent(function MenuRoot(props) {
|
|
|
2257
2275
|
}, [open, hoverEnabled, store]);
|
|
2258
2276
|
const setOpen = useStableCallback((nextOpen, eventDetails) => {
|
|
2259
2277
|
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
|
+
}
|
|
2260
2284
|
if (open === nextOpen && eventDetails.trigger === activeTriggerElement && lastOpenChangeReason === reason) {
|
|
2261
2285
|
return;
|
|
2262
2286
|
}
|
|
@@ -2289,13 +2313,17 @@ const MenuRoot = fastComponent(function MenuRoot(props) {
|
|
|
2289
2313
|
allowTouchToCloseRef.current = true;
|
|
2290
2314
|
allowTouchToCloseTimeout.clear();
|
|
2291
2315
|
}
|
|
2292
|
-
|
|
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;
|
|
2293
2321
|
const isDismissClose = !nextOpen && (reason === escapeKey || reason == null);
|
|
2294
2322
|
const updatedState = {
|
|
2295
2323
|
open: nextOpen,
|
|
2296
2324
|
openChangeReason: reason
|
|
2297
2325
|
};
|
|
2298
|
-
openEventRef.current = eventDetails.event
|
|
2326
|
+
openEventRef.current = eventDetails.event;
|
|
2299
2327
|
setPopupOpenState(updatedState, nextOpen, eventDetails.trigger, shouldPreventUnmountOnClose());
|
|
2300
2328
|
store.update(updatedState);
|
|
2301
2329
|
if (parent.type === 'menubar' && (reason === triggerFocus || reason === focusOut || reason === triggerHover || reason === listNavigation || reason === siblingOpen)) {
|
|
@@ -2313,7 +2341,11 @@ const MenuRoot = fastComponent(function MenuRoot(props) {
|
|
|
2313
2341
|
onOpenChange: setOpen
|
|
2314
2342
|
});
|
|
2315
2343
|
const floatingEvents = floatingRootContext.context.events;
|
|
2316
|
-
|
|
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(() => {
|
|
2317
2349
|
const handleSetOpenEvent = ({
|
|
2318
2350
|
open: nextOpen,
|
|
2319
2351
|
eventDetails
|
|
@@ -2442,11 +2474,14 @@ const MenuRoot = fastComponent(function MenuRoot(props) {
|
|
|
2442
2474
|
store,
|
|
2443
2475
|
parent: parentFromContext
|
|
2444
2476
|
}), [store, parentFromContext]);
|
|
2445
|
-
const content = /*#__PURE__*/
|
|
2477
|
+
const content = /*#__PURE__*/jsxs(MenuRootContext.Provider, {
|
|
2446
2478
|
value: context,
|
|
2447
|
-
children:
|
|
2479
|
+
children: [handle && /*#__PURE__*/jsx(PopupHandleAttachment, {
|
|
2480
|
+
handle: handle,
|
|
2481
|
+
store: store
|
|
2482
|
+
}), typeof children === 'function' ? children({
|
|
2448
2483
|
payload
|
|
2449
|
-
}) : children
|
|
2484
|
+
}) : children]
|
|
2450
2485
|
});
|
|
2451
2486
|
if (parent.type === undefined || parent.type === 'context-menu') {
|
|
2452
2487
|
// set up a FloatingTree to provide the context to nested menus
|
|
@@ -2458,6 +2493,15 @@ const MenuRoot = fastComponent(function MenuRoot(props) {
|
|
|
2458
2493
|
return content;
|
|
2459
2494
|
});
|
|
2460
2495
|
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
|
+
}
|
|
2461
2505
|
|
|
2462
2506
|
/**
|
|
2463
2507
|
* Groups all parts of a submenu.
|
|
@@ -2514,9 +2558,6 @@ function useCompositeItem(params = {}) {
|
|
|
2514
2558
|
};
|
|
2515
2559
|
}
|
|
2516
2560
|
|
|
2517
|
-
/**
|
|
2518
|
-
* @internal
|
|
2519
|
-
*/
|
|
2520
2561
|
function CompositeItem(componentProps) {
|
|
2521
2562
|
const {
|
|
2522
2563
|
render,
|
|
@@ -2538,7 +2579,8 @@ function CompositeItem(componentProps) {
|
|
|
2538
2579
|
});
|
|
2539
2580
|
return useRenderElement(tag, componentProps, {
|
|
2540
2581
|
state,
|
|
2541
|
-
ref
|
|
2582
|
+
// The composite ref attaches first so an outer item wins when nested items share a DOM node.
|
|
2583
|
+
ref: [compositeRef, ...refs],
|
|
2542
2584
|
props: [compositeProps, ...props, elementProps],
|
|
2543
2585
|
stateAttributesMapping
|
|
2544
2586
|
});
|
|
@@ -2546,7 +2588,7 @@ function CompositeItem(componentProps) {
|
|
|
2546
2588
|
|
|
2547
2589
|
function findRootOwnerId(node) {
|
|
2548
2590
|
if (isHTMLElement(node) && node.hasAttribute('data-rootownerid')) {
|
|
2549
|
-
return node.getAttribute('data-rootownerid')
|
|
2591
|
+
return node.getAttribute('data-rootownerid');
|
|
2550
2592
|
}
|
|
2551
2593
|
if (isLastTraversableNode(node)) {
|
|
2552
2594
|
return undefined;
|
|
@@ -2638,14 +2680,6 @@ function useMixedToggleClickHandler(params) {
|
|
|
2638
2680
|
}, [enabled, mouseDownAction, open]);
|
|
2639
2681
|
}
|
|
2640
2682
|
|
|
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
|
-
*/
|
|
2649
2683
|
const MenuTrigger = fastComponentRef(function MenuTrigger(componentProps, forwardedRef) {
|
|
2650
2684
|
const {
|
|
2651
2685
|
render,
|
|
@@ -2662,7 +2696,8 @@ const MenuTrigger = fastComponentRef(function MenuTrigger(componentProps, forwar
|
|
|
2662
2696
|
...elementProps
|
|
2663
2697
|
} = componentProps;
|
|
2664
2698
|
const rootContext = useMenuRootContext(true);
|
|
2665
|
-
const
|
|
2699
|
+
const handleStore = usePopupHandleStore(handle);
|
|
2700
|
+
const store = handleStore ?? rootContext?.store;
|
|
2666
2701
|
if (!store) {
|
|
2667
2702
|
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));
|
|
2668
2703
|
}
|
|
@@ -2722,8 +2757,7 @@ const MenuTrigger = fastComponentRef(function MenuTrigger(componentProps, forwar
|
|
|
2722
2757
|
if (mouseUpTarget != null && findRootOwnerId(mouseUpTarget) === store.select('rootId')) {
|
|
2723
2758
|
return;
|
|
2724
2759
|
}
|
|
2725
|
-
|
|
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) {
|
|
2760
|
+
if (isMouseWithinBounds(mouseEvent, triggerRef.current)) {
|
|
2727
2761
|
return;
|
|
2728
2762
|
}
|
|
2729
2763
|
floatingTreeRoot.events.emit('close', {
|
|
@@ -2742,7 +2776,7 @@ const MenuTrigger = fastComponentRef(function MenuTrigger(componentProps, forwar
|
|
|
2742
2776
|
const parentMenubarHasSubmenuOpen = isInMenubar && parent.context.hasSubmenuOpen;
|
|
2743
2777
|
const openOnHover = openOnHoverProp ?? parentMenubarHasSubmenuOpen;
|
|
2744
2778
|
const hoverProps = useHoverReferenceInteraction(floatingRootContext, {
|
|
2745
|
-
enabled: openOnHover && !disabled &&
|
|
2779
|
+
enabled: openOnHover && !disabled && (!isInMenubar || parentMenubarHasSubmenuOpen && !isMountedByThisTrigger),
|
|
2746
2780
|
handleClose: safePolygon({
|
|
2747
2781
|
blockPointerEvents: !isInMenubar
|
|
2748
2782
|
}),
|
|
@@ -2763,7 +2797,7 @@ const MenuTrigger = fastComponentRef(function MenuTrigger(componentProps, forwar
|
|
|
2763
2797
|
// only when `isOpenedByThisTrigger` changes.
|
|
2764
2798
|
const stickIfOpen = useStickIfOpen(isOpenedByThisTrigger, store.select('lastOpenChangeReason'));
|
|
2765
2799
|
const click = useClick(floatingRootContext, {
|
|
2766
|
-
enabled: !disabled
|
|
2800
|
+
enabled: !disabled,
|
|
2767
2801
|
event: isOpenedByThisTrigger && isInMenubar ? 'click' : 'mousedown',
|
|
2768
2802
|
toggle: true,
|
|
2769
2803
|
ignoreMouse: false,
|
|
@@ -2858,7 +2892,7 @@ function useStickIfOpen(open, openReason) {
|
|
|
2858
2892
|
const stickIfOpenTimeout = useTimeout();
|
|
2859
2893
|
const [stickIfOpen, setStickIfOpen] = React.useState(false);
|
|
2860
2894
|
useIsoLayoutEffect(() => {
|
|
2861
|
-
if (open && openReason ===
|
|
2895
|
+
if (open && openReason === triggerHover) {
|
|
2862
2896
|
// Only allow "patient" clicks to close the menu if it's open.
|
|
2863
2897
|
// If they clicked within 500ms of the menu opening, keep it open.
|
|
2864
2898
|
setStickIfOpen(true);
|
|
@@ -2873,8 +2907,6 @@ function useStickIfOpen(open, openReason) {
|
|
|
2873
2907
|
return stickIfOpen;
|
|
2874
2908
|
}
|
|
2875
2909
|
function useMenuParent() {
|
|
2876
|
-
const contextMenuContext = useContextMenuRootContext(true);
|
|
2877
|
-
const parentContext = useMenuRootContext(true);
|
|
2878
2910
|
const menubarContext = useMenubarContext(true);
|
|
2879
2911
|
const parent = React.useMemo(() => {
|
|
2880
2912
|
if (menubarContext) {
|
|
@@ -2883,23 +2915,17 @@ function useMenuParent() {
|
|
|
2883
2915
|
context: menubarContext
|
|
2884
2916
|
};
|
|
2885
2917
|
}
|
|
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
|
-
}
|
|
2896
2918
|
return {
|
|
2897
2919
|
type: undefined
|
|
2898
2920
|
};
|
|
2899
|
-
}, [
|
|
2921
|
+
}, [menubarContext]);
|
|
2900
2922
|
return parent;
|
|
2901
2923
|
}
|
|
2902
2924
|
|
|
2925
|
+
const VOICE_OVER_EXPANDED_PROPS = {
|
|
2926
|
+
'aria-expanded': undefined
|
|
2927
|
+
};
|
|
2928
|
+
|
|
2903
2929
|
/**
|
|
2904
2930
|
* A menu item that opens a submenu.
|
|
2905
2931
|
* Renders a `<div>` element.
|
|
@@ -2920,7 +2946,12 @@ const MenuSubmenuTrigger = /*#__PURE__*/React.forwardRef(function MenuSubmenuTri
|
|
|
2920
2946
|
disabled: disabledProp = false,
|
|
2921
2947
|
...elementProps
|
|
2922
2948
|
} = 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
|
+
}
|
|
2923
2953
|
const listItem = useCompositeListItem({
|
|
2954
|
+
guess: true,
|
|
2924
2955
|
label
|
|
2925
2956
|
});
|
|
2926
2957
|
const menuPositionerContext = useMenuPositionerContext();
|
|
@@ -2949,10 +2980,6 @@ const MenuSubmenuTrigger = /*#__PURE__*/React.forwardRef(function MenuSubmenuTri
|
|
|
2949
2980
|
triggerElementRef.current = el;
|
|
2950
2981
|
store.set('activeTriggerElement', el);
|
|
2951
2982
|
}, [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
|
-
}
|
|
2956
2983
|
store.useSyncedValue('closeDelay', closeDelay);
|
|
2957
2984
|
const parentMenuStore = submenuRootContext.parentMenu;
|
|
2958
2985
|
const rootDisabled = store.useState('disabled');
|
|
@@ -2960,7 +2987,7 @@ const MenuSubmenuTrigger = /*#__PURE__*/React.forwardRef(function MenuSubmenuTri
|
|
|
2960
2987
|
const disabled = disabledProp || rootDisabled || parentDisabled;
|
|
2961
2988
|
if (process.env.NODE_ENV !== 'production') {
|
|
2962
2989
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
2963
|
-
|
|
2990
|
+
React.useEffect(() => {
|
|
2964
2991
|
const element = triggerElementRef.current;
|
|
2965
2992
|
if (element && isElementDisabled(element) && !disabled) {
|
|
2966
2993
|
const ownerStackMessage = SafeReact.captureOwnerStack?.() || '';
|
|
@@ -3008,7 +3035,10 @@ const MenuSubmenuTrigger = /*#__PURE__*/React.forwardRef(function MenuSubmenuTri
|
|
|
3008
3035
|
shouldOpen: delay > 0 ? () => parentMenuStore.select('allowMouseEnter') : undefined,
|
|
3009
3036
|
triggerElementRef,
|
|
3010
3037
|
externalTree: floatingTreeRoot,
|
|
3011
|
-
isClosing: () => store.select('transitionStatus') === 'ending'
|
|
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
|
|
3012
3042
|
});
|
|
3013
3043
|
const click = useClick(floatingRootContext, {
|
|
3014
3044
|
enabled: !disabled,
|
|
@@ -3025,10 +3055,22 @@ const MenuSubmenuTrigger = /*#__PURE__*/React.forwardRef(function MenuSubmenuTri
|
|
|
3025
3055
|
highlighted,
|
|
3026
3056
|
open
|
|
3027
3057
|
};
|
|
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;
|
|
3028
3064
|
const element = useRenderElement('div', componentProps, {
|
|
3029
3065
|
state,
|
|
3030
3066
|
stateAttributesMapping: triggerOpenStateMapping,
|
|
3031
|
-
props: [localInteractionProps, hoverProps, rootTriggerProps, itemProps,
|
|
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, {
|
|
3032
3074
|
'aria-controls': popupId,
|
|
3033
3075
|
tabIndex: open || highlighted ? 0 : -1,
|
|
3034
3076
|
onBlur() {
|
|
@@ -3043,4 +3085,4 @@ const MenuSubmenuTrigger = /*#__PURE__*/React.forwardRef(function MenuSubmenuTri
|
|
|
3043
3085
|
});
|
|
3044
3086
|
if (process.env.NODE_ENV !== "production") MenuSubmenuTrigger.displayName = "MenuSubmenuTrigger";
|
|
3045
3087
|
|
|
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,
|
|
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 };
|