@jobber/components 8.15.0 → 8.16.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/dist/Card/index.cjs +1 -1
- package/dist/Card/index.mjs +1 -1
- package/dist/DataDump/index.cjs +1 -1
- package/dist/DataDump/index.mjs +1 -1
- package/dist/InputNumberExperimental-cjs.js +16 -16
- package/dist/InputNumberExperimental-es.js +1 -1
- package/dist/Menu/index.cjs +1 -1
- package/dist/Menu/index.mjs +1 -1
- package/dist/MenuSubmenuTrigger-cjs.js +1060 -1060
- package/dist/MenuSubmenuTrigger-es.js +928 -928
- package/dist/NumberFieldInput-cjs.js +53 -53
- package/dist/NumberFieldInput-es.js +1 -1
- package/dist/Page/index.cjs +1 -1
- package/dist/Page/index.mjs +1 -1
- package/dist/ScrollAreaViewport-cjs.js +4436 -4436
- package/dist/ScrollAreaViewport-es.js +4372 -4372
- package/dist/{useValueChanged-cjs.js → clamp-cjs.js} +594 -592
- package/dist/{useValueChanged-es.js → clamp-es.js} +595 -594
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/primitives/BottomSheet/index.cjs +2 -2
- package/dist/primitives/BottomSheet/index.mjs +2 -2
- package/dist/primitives/InputNumberExperimental/index.cjs +2 -2
- package/dist/primitives/InputNumberExperimental/index.mjs +2 -2
- package/dist/primitives/index.cjs +2 -2
- package/dist/primitives/index.mjs +2 -2
- package/dist/unstyledPrimitives/index.cjs +6271 -6134
- package/dist/unstyledPrimitives/index.d.ts +1 -0
- package/dist/unstyledPrimitives/index.mjs +6318 -6182
- package/dist/useRenderElement-cjs.js +30 -30
- package/dist/useRenderElement-es.js +30 -30
- package/package.json +2 -2
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
var React = require('react');
|
|
4
4
|
var ScrollAreaViewport = require('./ScrollAreaViewport-cjs.js');
|
|
5
5
|
var useRenderElement = require('./useRenderElement-cjs.js');
|
|
6
|
-
var
|
|
6
|
+
var clamp = require('./clamp-cjs.js');
|
|
7
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
8
|
var floatingUi_utils_dom = require('./floating-ui.utils.dom-cjs.js');
|
|
9
9
|
var index_esm = require('./index.esm-cjs.js');
|
|
@@ -30,59 +30,8 @@ function _interopNamespaceDefault(e) {
|
|
|
30
30
|
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
|
31
31
|
var ReactDOM__namespace = /*#__PURE__*/_interopNamespaceDefault(ReactDOM);
|
|
32
32
|
|
|
33
|
-
/**
|
|
34
|
-
* A button that closes the dialog.
|
|
35
|
-
* Renders a `<button>` element.
|
|
36
|
-
*
|
|
37
|
-
* Documentation: [Base UI Dialog](https://base-ui.com/react/components/dialog)
|
|
38
|
-
*/
|
|
39
|
-
const DialogClose = /*#__PURE__*/React__namespace.forwardRef(function DialogClose(componentProps, forwardedRef) {
|
|
40
|
-
const {
|
|
41
|
-
render,
|
|
42
|
-
className,
|
|
43
|
-
disabled = false,
|
|
44
|
-
nativeButton = true,
|
|
45
|
-
...elementProps
|
|
46
|
-
} = componentProps;
|
|
47
|
-
const {
|
|
48
|
-
store
|
|
49
|
-
} = ScrollAreaViewport.useDialogRootContext();
|
|
50
|
-
const open = store.useState('open');
|
|
51
|
-
function handleClick(event) {
|
|
52
|
-
if (open) {
|
|
53
|
-
store.setOpen(false, useValueChanged.createChangeEventDetails(useValueChanged.closePress, event.nativeEvent));
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
const {
|
|
57
|
-
getButtonProps,
|
|
58
|
-
buttonRef
|
|
59
|
-
} = useValueChanged.useButton({
|
|
60
|
-
disabled,
|
|
61
|
-
native: nativeButton
|
|
62
|
-
});
|
|
63
|
-
const state = {
|
|
64
|
-
disabled
|
|
65
|
-
};
|
|
66
|
-
return useRenderElement.useRenderElement('button', componentProps, {
|
|
67
|
-
state,
|
|
68
|
-
ref: [forwardedRef, buttonRef],
|
|
69
|
-
props: [{
|
|
70
|
-
onClick: handleClick
|
|
71
|
-
}, elementProps, getButtonProps]
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
if (process.env.NODE_ENV !== "production") DialogClose.displayName = "DialogClose";
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* A button that closes the drawer.
|
|
78
|
-
* Renders a `<button>` element.
|
|
79
|
-
*
|
|
80
|
-
* Documentation: [Base UI Drawer](https://base-ui.com/react/components/drawer)
|
|
81
|
-
*/
|
|
82
|
-
const DrawerClose = DialogClose;
|
|
83
|
-
|
|
84
33
|
function resolveValue(value, pointerType) {
|
|
85
|
-
if (pointerType != null && !
|
|
34
|
+
if (pointerType != null && !clamp.isMouseLikePointerType(pointerType)) {
|
|
86
35
|
return 0;
|
|
87
36
|
}
|
|
88
37
|
if (typeof value === 'function') {
|
|
@@ -113,7 +62,7 @@ function useFloatingRootContext(options) {
|
|
|
113
62
|
onOpenChange,
|
|
114
63
|
elements = {}
|
|
115
64
|
} = options;
|
|
116
|
-
const floatingId =
|
|
65
|
+
const floatingId = clamp.useId();
|
|
117
66
|
const nested = ScrollAreaViewport.useFloatingParentNodeId() != null;
|
|
118
67
|
if (process.env.NODE_ENV !== 'production') {
|
|
119
68
|
const optionDomReference = elements.reference;
|
|
@@ -131,7 +80,7 @@ function useFloatingRootContext(options) {
|
|
|
131
80
|
nested,
|
|
132
81
|
noEmit: false
|
|
133
82
|
})).current;
|
|
134
|
-
|
|
83
|
+
clamp.useIsoLayoutEffect(() => {
|
|
135
84
|
const valuesToSync = {
|
|
136
85
|
open,
|
|
137
86
|
floatingId
|
|
@@ -172,7 +121,7 @@ function useFloating(options = {}) {
|
|
|
172
121
|
const [positionReference, setPositionReferenceRaw] = React__namespace.useState(null);
|
|
173
122
|
const domReferenceRef = React__namespace.useRef(null);
|
|
174
123
|
const tree = ScrollAreaViewport.useFloatingTree(externalTree);
|
|
175
|
-
|
|
124
|
+
clamp.useIsoLayoutEffect(() => {
|
|
176
125
|
if (rootContextElements.domReference) {
|
|
177
126
|
domReferenceRef.current = rootContextElements.domReference;
|
|
178
127
|
}
|
|
@@ -247,7 +196,7 @@ function useFloating(options = {}) {
|
|
|
247
196
|
nodeId,
|
|
248
197
|
rootStore: rootContext
|
|
249
198
|
}), [position, refs, elements, nodeId, rootContext, open, floatingId]);
|
|
250
|
-
|
|
199
|
+
clamp.useIsoLayoutEffect(() => {
|
|
251
200
|
rootContext.context.dataRef.current.floatingContext = context;
|
|
252
201
|
const node = tree?.nodesRef.current.find(n => n.id === nodeId);
|
|
253
202
|
if (node) {
|
|
@@ -263,7 +212,7 @@ function useFloating(options = {}) {
|
|
|
263
212
|
}), [position, refs, elements, context, rootContext]);
|
|
264
213
|
}
|
|
265
214
|
|
|
266
|
-
const isMacSafari =
|
|
215
|
+
const isMacSafari = clamp.isMac && clamp.isSafari;
|
|
267
216
|
/**
|
|
268
217
|
* Opens the floating element while the reference element has focus, like CSS
|
|
269
218
|
* `:focus`.
|
|
@@ -282,7 +231,7 @@ function useFocus(context, props = {}) {
|
|
|
282
231
|
const blockFocusRef = React__namespace.useRef(false);
|
|
283
232
|
// Track which reference should be blocked from re-opening after Escape/press dismissal.
|
|
284
233
|
const blockedReferenceRef = React__namespace.useRef(null);
|
|
285
|
-
const timeout =
|
|
234
|
+
const timeout = clamp.useTimeout();
|
|
286
235
|
const keyboardModalityRef = React__namespace.useRef(true);
|
|
287
236
|
React__namespace.useEffect(() => {
|
|
288
237
|
const domReference = store.select('domReferenceElement');
|
|
@@ -296,7 +245,7 @@ function useFocus(context, props = {}) {
|
|
|
296
245
|
// return to the tab/window.
|
|
297
246
|
function onBlur() {
|
|
298
247
|
const currentDomReference = store.select('domReferenceElement');
|
|
299
|
-
if (!store.select('open') && floatingUi_utils_dom.isHTMLElement(currentDomReference) && currentDomReference === ScrollAreaViewport.activeElement(
|
|
248
|
+
if (!store.select('open') && floatingUi_utils_dom.isHTMLElement(currentDomReference) && currentDomReference === ScrollAreaViewport.activeElement(clamp.ownerDocument(currentDomReference))) {
|
|
300
249
|
blockFocusRef.current = true;
|
|
301
250
|
}
|
|
302
251
|
}
|
|
@@ -324,7 +273,7 @@ function useFocus(context, props = {}) {
|
|
|
324
273
|
return undefined;
|
|
325
274
|
}
|
|
326
275
|
function onOpenChangeLocal(details) {
|
|
327
|
-
if (details.reason ===
|
|
276
|
+
if (details.reason === clamp.triggerPress || details.reason === clamp.escapeKey) {
|
|
328
277
|
const referenceElement = store.select('domReferenceElement');
|
|
329
278
|
if (floatingUi_utils_dom.isElement(referenceElement)) {
|
|
330
279
|
blockedReferenceRef.current = referenceElement;
|
|
@@ -370,14 +319,14 @@ function useFocus(context, props = {}) {
|
|
|
370
319
|
} = event;
|
|
371
320
|
const delayValue = typeof delay === 'function' ? delay() : delay;
|
|
372
321
|
if (store.select('open') && movedFromOtherEnabledTrigger || delayValue === 0 || delayValue === undefined) {
|
|
373
|
-
store.setOpen(true,
|
|
322
|
+
store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerFocus, nativeEvent, currentTarget));
|
|
374
323
|
return;
|
|
375
324
|
}
|
|
376
325
|
timeout.start(delayValue, () => {
|
|
377
326
|
if (blockFocusRef.current) {
|
|
378
327
|
return;
|
|
379
328
|
}
|
|
380
|
-
store.setOpen(true,
|
|
329
|
+
store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerFocus, nativeEvent, currentTarget));
|
|
381
330
|
});
|
|
382
331
|
},
|
|
383
332
|
onBlur(event) {
|
|
@@ -418,7 +367,7 @@ function useFocus(context, props = {}) {
|
|
|
418
367
|
if (ScrollAreaViewport.isTargetInsideEnabledTrigger(nextFocusedElement, store.context.triggerElements)) {
|
|
419
368
|
return;
|
|
420
369
|
}
|
|
421
|
-
store.setOpen(false,
|
|
370
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.triggerFocus, nativeEvent));
|
|
422
371
|
});
|
|
423
372
|
}
|
|
424
373
|
}), [dataRef, store, timeout, delay]);
|
|
@@ -443,8 +392,8 @@ class HoverInteraction {
|
|
|
443
392
|
this.pointerEventsReferenceElement = null;
|
|
444
393
|
this.pointerEventsFloatingElement = null;
|
|
445
394
|
this.restTimeoutPending = false;
|
|
446
|
-
this.openChangeTimeout = new
|
|
447
|
-
this.restTimeout = new
|
|
395
|
+
this.openChangeTimeout = new clamp.Timeout();
|
|
396
|
+
this.restTimeout = new clamp.Timeout();
|
|
448
397
|
this.handleCloseOptions = undefined;
|
|
449
398
|
}
|
|
450
399
|
static create() {
|
|
@@ -491,7 +440,7 @@ function useHoverInteractionSharedState(store) {
|
|
|
491
440
|
if (!data.hoverInteractionState) {
|
|
492
441
|
data.hoverInteractionState = instance;
|
|
493
442
|
}
|
|
494
|
-
|
|
443
|
+
clamp.useOnMount(data.hoverInteractionState.disposeEffect);
|
|
495
444
|
return data.hoverInteractionState;
|
|
496
445
|
}
|
|
497
446
|
|
|
@@ -513,20 +462,20 @@ function useHoverFloatingInteraction(context, parameters = {}) {
|
|
|
513
462
|
const instance = useHoverInteractionSharedState(store);
|
|
514
463
|
const tree = ScrollAreaViewport.useFloatingTree();
|
|
515
464
|
const parentId = ScrollAreaViewport.useFloatingParentNodeId();
|
|
516
|
-
const isClickLikeOpenEvent$1 =
|
|
465
|
+
const isClickLikeOpenEvent$1 = clamp.useStableCallback(() => {
|
|
517
466
|
return isClickLikeOpenEvent(dataRef.current.openEvent?.type, instance.interactedInside);
|
|
518
467
|
});
|
|
519
|
-
const isHoverOpen =
|
|
468
|
+
const isHoverOpen = clamp.useStableCallback(() => {
|
|
520
469
|
const type = dataRef.current.openEvent?.type;
|
|
521
470
|
return type?.includes('mouse') && type !== 'mousedown';
|
|
522
471
|
});
|
|
523
|
-
const isRelatedTargetInsideEnabledTrigger =
|
|
472
|
+
const isRelatedTargetInsideEnabledTrigger = clamp.useStableCallback(target => {
|
|
524
473
|
return ScrollAreaViewport.isTargetInsideEnabledTrigger(target, store.context.triggerElements);
|
|
525
474
|
});
|
|
526
475
|
const closeWithDelay = React__namespace.useCallback(event => {
|
|
527
476
|
const closeDelay = getDelay(closeDelayProp, 'close', instance.pointerType);
|
|
528
477
|
const close = () => {
|
|
529
|
-
store.setOpen(false,
|
|
478
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.triggerHover, event));
|
|
530
479
|
tree?.events.emit('floating.closed', event);
|
|
531
480
|
};
|
|
532
481
|
if (closeDelay) {
|
|
@@ -536,10 +485,10 @@ function useHoverFloatingInteraction(context, parameters = {}) {
|
|
|
536
485
|
close();
|
|
537
486
|
}
|
|
538
487
|
}, [closeDelayProp, store, instance, tree]);
|
|
539
|
-
const clearPointerEvents =
|
|
488
|
+
const clearPointerEvents = clamp.useStableCallback(() => {
|
|
540
489
|
clearSafePolygonPointerEventsMutation(instance);
|
|
541
490
|
});
|
|
542
|
-
const handleInteractInside =
|
|
491
|
+
const handleInteractInside = clamp.useStableCallback(event => {
|
|
543
492
|
const target = ScrollAreaViewport.getTarget(event);
|
|
544
493
|
if (!isInteractiveElement(target)) {
|
|
545
494
|
instance.interactedInside = false;
|
|
@@ -547,7 +496,7 @@ function useHoverFloatingInteraction(context, parameters = {}) {
|
|
|
547
496
|
}
|
|
548
497
|
instance.interactedInside = target?.closest('[aria-haspopup]') != null;
|
|
549
498
|
});
|
|
550
|
-
|
|
499
|
+
clamp.useIsoLayoutEffect(() => {
|
|
551
500
|
if (!open) {
|
|
552
501
|
instance.pointerType = undefined;
|
|
553
502
|
instance.restTimeoutPending = false;
|
|
@@ -558,14 +507,14 @@ function useHoverFloatingInteraction(context, parameters = {}) {
|
|
|
558
507
|
React__namespace.useEffect(() => {
|
|
559
508
|
return clearPointerEvents;
|
|
560
509
|
}, [clearPointerEvents]);
|
|
561
|
-
|
|
510
|
+
clamp.useIsoLayoutEffect(() => {
|
|
562
511
|
if (!enabled) {
|
|
563
512
|
return undefined;
|
|
564
513
|
}
|
|
565
514
|
if (open && instance.handleCloseOptions?.blockPointerEvents && isHoverOpen() && floatingUi_utils_dom.isElement(domReferenceElement) && floatingElement) {
|
|
566
515
|
const ref = domReferenceElement;
|
|
567
516
|
const floatingEl = floatingElement;
|
|
568
|
-
const doc =
|
|
517
|
+
const doc = clamp.ownerDocument(floatingElement);
|
|
569
518
|
const parentFloating = tree?.nodesRef.current.find(node => node.id === parentId)?.context?.elements.floating;
|
|
570
519
|
if (parentFloating) {
|
|
571
520
|
parentFloating.style.pointerEvents = '';
|
|
@@ -582,7 +531,7 @@ function useHoverFloatingInteraction(context, parameters = {}) {
|
|
|
582
531
|
}
|
|
583
532
|
return undefined;
|
|
584
533
|
}, [enabled, open, domReferenceElement, floatingElement, instance, isHoverOpen, tree, parentId, clearPointerEvents]);
|
|
585
|
-
const childClosedTimeout =
|
|
534
|
+
const childClosedTimeout = clamp.useTimeout();
|
|
586
535
|
React__namespace.useEffect(() => {
|
|
587
536
|
if (!enabled) {
|
|
588
537
|
return undefined;
|
|
@@ -621,7 +570,7 @@ function useHoverFloatingInteraction(context, parameters = {}) {
|
|
|
621
570
|
// Allow the mouseenter event to fire in case child was closed because mouse moved into parent.
|
|
622
571
|
childClosedTimeout.start(0, () => {
|
|
623
572
|
tree.events.off('floating.closed', onNodeClosed);
|
|
624
|
-
store.setOpen(false,
|
|
573
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.triggerHover, event));
|
|
625
574
|
tree.events.emit('floating.closed', event);
|
|
626
575
|
});
|
|
627
576
|
}
|
|
@@ -670,21 +619,21 @@ function useHoverReferenceInteraction(context, props = {}) {
|
|
|
670
619
|
} = props;
|
|
671
620
|
const tree = ScrollAreaViewport.useFloatingTree(externalTree);
|
|
672
621
|
const instance = useHoverInteractionSharedState(store);
|
|
673
|
-
const handleCloseRef =
|
|
674
|
-
const delayRef =
|
|
675
|
-
const restMsRef =
|
|
676
|
-
const enabledRef =
|
|
622
|
+
const handleCloseRef = clamp.useValueAsRef(handleClose);
|
|
623
|
+
const delayRef = clamp.useValueAsRef(delay);
|
|
624
|
+
const restMsRef = clamp.useValueAsRef(restMs);
|
|
625
|
+
const enabledRef = clamp.useValueAsRef(enabled);
|
|
677
626
|
if (isActiveTrigger) {
|
|
678
627
|
// eslint-disable-next-line no-underscore-dangle
|
|
679
628
|
instance.handleCloseOptions = handleCloseRef.current?.__options;
|
|
680
629
|
}
|
|
681
|
-
const isClickLikeOpenEvent$1 =
|
|
630
|
+
const isClickLikeOpenEvent$1 = clamp.useStableCallback(() => {
|
|
682
631
|
return isClickLikeOpenEvent(dataRef.current.openEvent?.type, instance.interactedInside);
|
|
683
632
|
});
|
|
684
|
-
const isRelatedTargetInsideEnabledTrigger =
|
|
633
|
+
const isRelatedTargetInsideEnabledTrigger = clamp.useStableCallback(target => {
|
|
685
634
|
return ScrollAreaViewport.isTargetInsideEnabledTrigger(target, store.context.triggerElements);
|
|
686
635
|
});
|
|
687
|
-
const isOverInactiveTrigger =
|
|
636
|
+
const isOverInactiveTrigger = clamp.useStableCallback((currentDomReference, currentTarget, target) => {
|
|
688
637
|
const allTriggers = store.context.triggerElements;
|
|
689
638
|
|
|
690
639
|
// Fast path for normal usage where handlers are attached directly to triggers.
|
|
@@ -703,25 +652,25 @@ function useHoverReferenceInteraction(context, props = {}) {
|
|
|
703
652
|
const closeDelay = getDelay(delayRef.current, 'close', instance.pointerType);
|
|
704
653
|
if (closeDelay) {
|
|
705
654
|
instance.openChangeTimeout.start(closeDelay, () => {
|
|
706
|
-
store.setOpen(false,
|
|
655
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.triggerHover, event));
|
|
707
656
|
tree?.events.emit('floating.closed', event);
|
|
708
657
|
});
|
|
709
658
|
} else if (runElseBranch) {
|
|
710
659
|
instance.openChangeTimeout.clear();
|
|
711
|
-
store.setOpen(false,
|
|
660
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.triggerHover, event));
|
|
712
661
|
tree?.events.emit('floating.closed', event);
|
|
713
662
|
}
|
|
714
663
|
}, [delayRef, store, instance, tree]);
|
|
715
|
-
const cleanupMouseMoveHandler =
|
|
664
|
+
const cleanupMouseMoveHandler = clamp.useStableCallback(() => {
|
|
716
665
|
if (!instance.handler) {
|
|
717
666
|
return;
|
|
718
667
|
}
|
|
719
|
-
const doc =
|
|
668
|
+
const doc = clamp.ownerDocument(store.select('domReferenceElement'));
|
|
720
669
|
doc.removeEventListener('mousemove', instance.handler);
|
|
721
670
|
instance.handler = undefined;
|
|
722
671
|
});
|
|
723
672
|
React__namespace.useEffect(() => cleanupMouseMoveHandler, [cleanupMouseMoveHandler]);
|
|
724
|
-
const clearPointerEvents =
|
|
673
|
+
const clearPointerEvents = clamp.useStableCallback(() => {
|
|
725
674
|
clearSafePolygonPointerEventsMutation(instance);
|
|
726
675
|
});
|
|
727
676
|
|
|
@@ -756,7 +705,7 @@ function useHoverReferenceInteraction(context, props = {}) {
|
|
|
756
705
|
function onMouseEnter(event) {
|
|
757
706
|
instance.openChangeTimeout.clear();
|
|
758
707
|
instance.blockMouseMove = false;
|
|
759
|
-
if (mouseOnly && !
|
|
708
|
+
if (mouseOnly && !clamp.isMouseLikePointerType(instance.pointerType)) {
|
|
760
709
|
return;
|
|
761
710
|
}
|
|
762
711
|
|
|
@@ -775,15 +724,15 @@ function useHoverReferenceInteraction(context, props = {}) {
|
|
|
775
724
|
|
|
776
725
|
// When moving between triggers while already open, open immediately without delay
|
|
777
726
|
if (isOverInactive && isOpen) {
|
|
778
|
-
store.setOpen(true,
|
|
727
|
+
store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerHover, event, triggerNode));
|
|
779
728
|
} else if (openDelay) {
|
|
780
729
|
instance.openChangeTimeout.start(openDelay, () => {
|
|
781
730
|
if (shouldOpen) {
|
|
782
|
-
store.setOpen(true,
|
|
731
|
+
store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerHover, event, triggerNode));
|
|
783
732
|
}
|
|
784
733
|
});
|
|
785
734
|
} else if (shouldOpen) {
|
|
786
|
-
store.setOpen(true,
|
|
735
|
+
store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerHover, event, triggerNode));
|
|
787
736
|
}
|
|
788
737
|
}
|
|
789
738
|
function onMouseLeave(event) {
|
|
@@ -793,7 +742,7 @@ function useHoverReferenceInteraction(context, props = {}) {
|
|
|
793
742
|
}
|
|
794
743
|
cleanupMouseMoveHandler();
|
|
795
744
|
const domReferenceElement = store.select('domReferenceElement');
|
|
796
|
-
const doc =
|
|
745
|
+
const doc = clamp.ownerDocument(domReferenceElement);
|
|
797
746
|
instance.restTimeout.clear();
|
|
798
747
|
instance.restTimeoutPending = false;
|
|
799
748
|
const handleCloseContextBase = dataRef.current.floatingContext ?? getHandleCloseContext?.();
|
|
@@ -861,7 +810,7 @@ function useHoverReferenceInteraction(context, props = {}) {
|
|
|
861
810
|
const currentDomReference = store.select('domReferenceElement');
|
|
862
811
|
const currentOpen = store.select('open');
|
|
863
812
|
const isOverInactive = isOverInactiveTrigger(currentDomReference, trigger, event.target);
|
|
864
|
-
if (mouseOnly && !
|
|
813
|
+
if (mouseOnly && !clamp.isMouseLikePointerType(instance.pointerType)) {
|
|
865
814
|
return;
|
|
866
815
|
}
|
|
867
816
|
const restMsValue = getRestMs(restMsRef.current);
|
|
@@ -882,7 +831,7 @@ function useHoverReferenceInteraction(context, props = {}) {
|
|
|
882
831
|
}
|
|
883
832
|
const latestOpen = store.select('open');
|
|
884
833
|
if (!instance.blockMouseMove && (!latestOpen || isOverInactive)) {
|
|
885
|
-
store.setOpen(true,
|
|
834
|
+
store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerHover, nativeEvent, trigger));
|
|
886
835
|
}
|
|
887
836
|
}
|
|
888
837
|
if (instance.pointerType === 'touch') {
|
|
@@ -981,10 +930,10 @@ function useListNavigation(context, props) {
|
|
|
981
930
|
}
|
|
982
931
|
}
|
|
983
932
|
const floatingFocusElement = ScrollAreaViewport.getFloatingFocusElement(floatingElement);
|
|
984
|
-
const floatingFocusElementRef =
|
|
933
|
+
const floatingFocusElementRef = clamp.useValueAsRef(floatingFocusElement);
|
|
985
934
|
const parentId = ScrollAreaViewport.useFloatingParentNodeId();
|
|
986
935
|
const tree = ScrollAreaViewport.useFloatingTree(externalTree);
|
|
987
|
-
|
|
936
|
+
clamp.useIsoLayoutEffect(() => {
|
|
988
937
|
dataRef.current.orientation = orientation;
|
|
989
938
|
}, [dataRef, orientation]);
|
|
990
939
|
const typeableComboboxReference = ScrollAreaViewport.isTypeableCombobox(domReferenceElement);
|
|
@@ -992,7 +941,7 @@ function useListNavigation(context, props) {
|
|
|
992
941
|
const indexRef = React__namespace.useRef(selectedIndex ?? -1);
|
|
993
942
|
const keyRef = React__namespace.useRef(null);
|
|
994
943
|
const isPointerModalityRef = React__namespace.useRef(true);
|
|
995
|
-
const onNavigate =
|
|
944
|
+
const onNavigate = clamp.useStableCallback(event => {
|
|
996
945
|
onNavigateProp(indexRef.current === -1 ? null : indexRef.current, event);
|
|
997
946
|
});
|
|
998
947
|
const previousOnNavigateRef = React__namespace.useRef(onNavigate);
|
|
@@ -1000,11 +949,11 @@ function useListNavigation(context, props) {
|
|
|
1000
949
|
const previousOpenRef = React__namespace.useRef(open);
|
|
1001
950
|
const forceSyncFocusRef = React__namespace.useRef(false);
|
|
1002
951
|
const forceScrollIntoViewRef = React__namespace.useRef(false);
|
|
1003
|
-
const disabledIndicesRef =
|
|
1004
|
-
const latestOpenRef =
|
|
1005
|
-
const selectedIndexRef =
|
|
1006
|
-
const resetOnPointerLeaveRef =
|
|
1007
|
-
const focusItem =
|
|
952
|
+
const disabledIndicesRef = clamp.useValueAsRef(disabledIndices);
|
|
953
|
+
const latestOpenRef = clamp.useValueAsRef(open);
|
|
954
|
+
const selectedIndexRef = clamp.useValueAsRef(selectedIndex);
|
|
955
|
+
const resetOnPointerLeaveRef = clamp.useValueAsRef(resetOnPointerLeave);
|
|
956
|
+
const focusItem = clamp.useStableCallback(() => {
|
|
1008
957
|
function runFocus(item) {
|
|
1009
958
|
if (virtual) {
|
|
1010
959
|
tree?.events.emit('virtualfocus', item);
|
|
@@ -1045,7 +994,7 @@ function useListNavigation(context, props) {
|
|
|
1045
994
|
|
|
1046
995
|
// Sync `selectedIndex` to be the `activeIndex` upon opening the floating
|
|
1047
996
|
// element. Also, reset `activeIndex` upon closing the floating element.
|
|
1048
|
-
|
|
997
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1049
998
|
if (!enabled) {
|
|
1050
999
|
return;
|
|
1051
1000
|
}
|
|
@@ -1068,7 +1017,7 @@ function useListNavigation(context, props) {
|
|
|
1068
1017
|
|
|
1069
1018
|
// Sync `activeIndex` to be the focused item while the floating element is
|
|
1070
1019
|
// open.
|
|
1071
|
-
|
|
1020
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1072
1021
|
if (!enabled) {
|
|
1073
1022
|
return;
|
|
1074
1023
|
}
|
|
@@ -1122,13 +1071,13 @@ function useListNavigation(context, props) {
|
|
|
1122
1071
|
|
|
1123
1072
|
// Ensure the parent floating element has focus when a nested child closes
|
|
1124
1073
|
// to allow arrow key navigation to work after the pointer leaves the child.
|
|
1125
|
-
|
|
1074
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1126
1075
|
if (!enabled || floatingElement || !tree || virtual || !previousMountedRef.current) {
|
|
1127
1076
|
return;
|
|
1128
1077
|
}
|
|
1129
1078
|
const nodes = tree.nodesRef.current;
|
|
1130
1079
|
const parent = nodes.find(node => node.id === parentId)?.context?.elements.floating;
|
|
1131
|
-
const activeEl = ScrollAreaViewport.activeElement(
|
|
1080
|
+
const activeEl = ScrollAreaViewport.activeElement(clamp.ownerDocument(floatingElement));
|
|
1132
1081
|
const treeContainsActiveEl = nodes.some(node => node.context && ScrollAreaViewport.contains(node.context.elements.floating, activeEl));
|
|
1133
1082
|
if (parent && !treeContainsActiveEl && isPointerModalityRef.current) {
|
|
1134
1083
|
parent.focus({
|
|
@@ -1136,12 +1085,12 @@ function useListNavigation(context, props) {
|
|
|
1136
1085
|
});
|
|
1137
1086
|
}
|
|
1138
1087
|
}, [enabled, floatingElement, tree, parentId, virtual]);
|
|
1139
|
-
|
|
1088
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1140
1089
|
previousOnNavigateRef.current = onNavigate;
|
|
1141
1090
|
previousOpenRef.current = open;
|
|
1142
1091
|
previousMountedRef.current = !!floatingElement;
|
|
1143
1092
|
});
|
|
1144
|
-
|
|
1093
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1145
1094
|
if (!open) {
|
|
1146
1095
|
keyRef.current = null;
|
|
1147
1096
|
focusItemOnOpenRef.current = focusItemOnOpen;
|
|
@@ -1196,7 +1145,7 @@ function useListNavigation(context, props) {
|
|
|
1196
1145
|
onNavigate(event);
|
|
1197
1146
|
if (!virtual) {
|
|
1198
1147
|
const floatingFocusEl = floatingFocusElementRef.current;
|
|
1199
|
-
const activeEl = ScrollAreaViewport.activeElement(
|
|
1148
|
+
const activeEl = ScrollAreaViewport.activeElement(clamp.ownerDocument(floatingFocusEl));
|
|
1200
1149
|
if (floatingFocusEl && ScrollAreaViewport.contains(floatingFocusEl, activeEl)) {
|
|
1201
1150
|
floatingFocusEl.focus({
|
|
1202
1151
|
preventScroll: true
|
|
@@ -1210,7 +1159,7 @@ function useListNavigation(context, props) {
|
|
|
1210
1159
|
const getParentOrientation = React__namespace.useCallback(() => {
|
|
1211
1160
|
return parentOrientation ?? tree?.nodesRef.current.find(node => node.id === parentId)?.context?.dataRef?.current.orientation;
|
|
1212
1161
|
}, [parentId, tree, parentOrientation]);
|
|
1213
|
-
const commonOnKeyDown =
|
|
1162
|
+
const commonOnKeyDown = clamp.useStableCallback(event => {
|
|
1214
1163
|
isPointerModalityRef.current = false;
|
|
1215
1164
|
forceSyncFocusRef.current = true;
|
|
1216
1165
|
|
|
@@ -1232,9 +1181,9 @@ function useListNavigation(context, props) {
|
|
|
1232
1181
|
// If the nested list's close key is also the parent navigation key,
|
|
1233
1182
|
// let the parent navigate. Otherwise, stop propagating the event.
|
|
1234
1183
|
if (!isMainOrientationKey(event.key, getParentOrientation())) {
|
|
1235
|
-
|
|
1184
|
+
clamp.stopEvent(event);
|
|
1236
1185
|
}
|
|
1237
|
-
store.setOpen(false,
|
|
1186
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.listNavigation, event.nativeEvent));
|
|
1238
1187
|
if (floatingUi_utils_dom.isHTMLElement(domReferenceElement)) {
|
|
1239
1188
|
if (virtual) {
|
|
1240
1189
|
tree?.events.emit('virtualfocus', domReferenceElement);
|
|
@@ -1249,12 +1198,12 @@ function useListNavigation(context, props) {
|
|
|
1249
1198
|
const maxIndex = ScrollAreaViewport.getMaxListIndex(listRef, disabledIndices);
|
|
1250
1199
|
if (!typeableComboboxReference) {
|
|
1251
1200
|
if (event.key === 'Home') {
|
|
1252
|
-
|
|
1201
|
+
clamp.stopEvent(event);
|
|
1253
1202
|
indexRef.current = minIndex;
|
|
1254
1203
|
onNavigate(event);
|
|
1255
1204
|
}
|
|
1256
1205
|
if (event.key === 'End') {
|
|
1257
|
-
|
|
1206
|
+
clamp.stopEvent(event);
|
|
1258
1207
|
indexRef.current = maxIndex;
|
|
1259
1208
|
onNavigate(event);
|
|
1260
1209
|
}
|
|
@@ -1304,7 +1253,7 @@ function useListNavigation(context, props) {
|
|
|
1304
1253
|
}
|
|
1305
1254
|
}
|
|
1306
1255
|
if (isMainOrientationKey(event.key, orientation)) {
|
|
1307
|
-
|
|
1256
|
+
clamp.stopEvent(event);
|
|
1308
1257
|
|
|
1309
1258
|
// Reset the index if no item is focused.
|
|
1310
1259
|
if (open && !virtual && ScrollAreaViewport.activeElement(event.currentTarget.ownerDocument) === event.currentTarget) {
|
|
@@ -1382,8 +1331,8 @@ function useListNavigation(context, props) {
|
|
|
1382
1331
|
if (target && !ScrollAreaViewport.contains(floatingFocusElementRef.current, target)) {
|
|
1383
1332
|
return;
|
|
1384
1333
|
}
|
|
1385
|
-
|
|
1386
|
-
store.setOpen(false,
|
|
1334
|
+
clamp.stopEvent(event);
|
|
1335
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.focusOut, event.nativeEvent));
|
|
1387
1336
|
if (floatingUi_utils_dom.isHTMLElement(domReferenceElement)) {
|
|
1388
1337
|
domReferenceElement.focus();
|
|
1389
1338
|
}
|
|
@@ -1398,14 +1347,14 @@ function useListNavigation(context, props) {
|
|
|
1398
1347
|
}, [ariaActiveDescendantProp, commonOnKeyDown, floatingFocusElementRef, orientation, typeableComboboxReference, store, open, virtual, domReferenceElement]);
|
|
1399
1348
|
const trigger = React__namespace.useMemo(() => {
|
|
1400
1349
|
function checkVirtualMouse(event) {
|
|
1401
|
-
if (focusItemOnOpen === 'auto' &&
|
|
1350
|
+
if (focusItemOnOpen === 'auto' && clamp.isVirtualClick(event.nativeEvent)) {
|
|
1402
1351
|
focusItemOnOpenRef.current = !virtual;
|
|
1403
1352
|
}
|
|
1404
1353
|
}
|
|
1405
1354
|
function checkVirtualPointer(event) {
|
|
1406
1355
|
// `pointerdown` fires first, reset the state then perform the checks.
|
|
1407
1356
|
focusItemOnOpenRef.current = focusItemOnOpen;
|
|
1408
|
-
if (focusItemOnOpen === 'auto' &&
|
|
1357
|
+
if (focusItemOnOpen === 'auto' && clamp.isVirtualPointerEvent(event.nativeEvent)) {
|
|
1409
1358
|
focusItemOnOpenRef.current = true;
|
|
1410
1359
|
}
|
|
1411
1360
|
}
|
|
@@ -1433,12 +1382,12 @@ function useListNavigation(context, props) {
|
|
|
1433
1382
|
}
|
|
1434
1383
|
if (nested) {
|
|
1435
1384
|
if (isParentCrossOpenKey) {
|
|
1436
|
-
|
|
1385
|
+
clamp.stopEvent(event);
|
|
1437
1386
|
if (currentOpen) {
|
|
1438
1387
|
indexRef.current = ScrollAreaViewport.getMinListIndex(listRef, disabledIndicesRef.current);
|
|
1439
1388
|
onNavigate(event);
|
|
1440
1389
|
} else {
|
|
1441
|
-
store.setOpen(true,
|
|
1390
|
+
store.setOpen(true, clamp.createChangeEventDetails(clamp.listNavigation, event.nativeEvent, event.currentTarget));
|
|
1442
1391
|
}
|
|
1443
1392
|
}
|
|
1444
1393
|
return undefined;
|
|
@@ -1447,9 +1396,9 @@ function useListNavigation(context, props) {
|
|
|
1447
1396
|
if (selectedIndexRef.current != null) {
|
|
1448
1397
|
indexRef.current = selectedIndexRef.current;
|
|
1449
1398
|
}
|
|
1450
|
-
|
|
1399
|
+
clamp.stopEvent(event);
|
|
1451
1400
|
if (!currentOpen && openOnArrowKeyDown) {
|
|
1452
|
-
store.setOpen(true,
|
|
1401
|
+
store.setOpen(true, clamp.createChangeEventDetails(clamp.listNavigation, event.nativeEvent, event.currentTarget));
|
|
1453
1402
|
} else {
|
|
1454
1403
|
commonOnKeyDown(event);
|
|
1455
1404
|
}
|
|
@@ -1504,11 +1453,11 @@ function useTypeahead(context, props) {
|
|
|
1504
1453
|
resetMs = 750,
|
|
1505
1454
|
selectedIndex = null
|
|
1506
1455
|
} = props;
|
|
1507
|
-
const timeout =
|
|
1456
|
+
const timeout = clamp.useTimeout();
|
|
1508
1457
|
const stringRef = React__namespace.useRef('');
|
|
1509
1458
|
const prevIndexRef = React__namespace.useRef(selectedIndex ?? activeIndex ?? -1);
|
|
1510
1459
|
const matchIndexRef = React__namespace.useRef(null);
|
|
1511
|
-
|
|
1460
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1512
1461
|
if (!open && selectedIndex !== null) {
|
|
1513
1462
|
return;
|
|
1514
1463
|
}
|
|
@@ -1518,13 +1467,13 @@ function useTypeahead(context, props) {
|
|
|
1518
1467
|
stringRef.current = '';
|
|
1519
1468
|
}
|
|
1520
1469
|
}, [open, selectedIndex, timeout]);
|
|
1521
|
-
|
|
1470
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1522
1471
|
// Sync arrow key navigation but not typeahead navigation.
|
|
1523
1472
|
if (open && stringRef.current === '') {
|
|
1524
1473
|
prevIndexRef.current = selectedIndex ?? activeIndex ?? -1;
|
|
1525
1474
|
}
|
|
1526
1475
|
}, [open, selectedIndex, activeIndex]);
|
|
1527
|
-
const setTypingChange =
|
|
1476
|
+
const setTypingChange = clamp.useStableCallback(value => {
|
|
1528
1477
|
if (value) {
|
|
1529
1478
|
if (!dataRef.current.typing) {
|
|
1530
1479
|
dataRef.current.typing = value;
|
|
@@ -1535,7 +1484,7 @@ function useTypeahead(context, props) {
|
|
|
1535
1484
|
onTypingChange?.(value);
|
|
1536
1485
|
}
|
|
1537
1486
|
});
|
|
1538
|
-
const onKeyDown =
|
|
1487
|
+
const onKeyDown = clamp.useStableCallback(event => {
|
|
1539
1488
|
function isVisible(index) {
|
|
1540
1489
|
const element = elementsRef?.current[index];
|
|
1541
1490
|
return !element || ScrollAreaViewport.isElementVisible(element);
|
|
@@ -1559,7 +1508,7 @@ function useTypeahead(context, props) {
|
|
|
1559
1508
|
const listContent = listRef.current;
|
|
1560
1509
|
if (stringRef.current.length > 0 && event.key === ' ') {
|
|
1561
1510
|
// Space should continue the in-progress typeahead session.
|
|
1562
|
-
|
|
1511
|
+
clamp.stopEvent(event);
|
|
1563
1512
|
setTypingChange(true);
|
|
1564
1513
|
}
|
|
1565
1514
|
if (stringRef.current.length > 0 && stringRef.current[0] !== ' ') {
|
|
@@ -1575,7 +1524,7 @@ function useTypeahead(context, props) {
|
|
|
1575
1524
|
return;
|
|
1576
1525
|
}
|
|
1577
1526
|
if (open && event.key !== ' ') {
|
|
1578
|
-
|
|
1527
|
+
clamp.stopEvent(event);
|
|
1579
1528
|
setTypingChange(true);
|
|
1580
1529
|
}
|
|
1581
1530
|
|
|
@@ -1616,7 +1565,7 @@ function useTypeahead(context, props) {
|
|
|
1616
1565
|
setTypingChange(false);
|
|
1617
1566
|
}
|
|
1618
1567
|
});
|
|
1619
|
-
const onBlur =
|
|
1568
|
+
const onBlur = clamp.useStableCallback(event => {
|
|
1620
1569
|
const next = event.relatedTarget;
|
|
1621
1570
|
const currentDomReferenceElement = store.select('domReferenceElement');
|
|
1622
1571
|
const currentFloatingElement = store.select('floatingElement');
|
|
@@ -1693,7 +1642,7 @@ function safePolygon(options = {}) {
|
|
|
1693
1642
|
const {
|
|
1694
1643
|
blockPointerEvents = false
|
|
1695
1644
|
} = options;
|
|
1696
|
-
const timeout = new
|
|
1645
|
+
const timeout = new clamp.Timeout();
|
|
1697
1646
|
const fn = ({
|
|
1698
1647
|
x,
|
|
1699
1648
|
y,
|
|
@@ -1891,196 +1840,39 @@ function safePolygon(options = {}) {
|
|
|
1891
1840
|
return fn;
|
|
1892
1841
|
}
|
|
1893
1842
|
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
* Renders an `<h2>` element.
|
|
1897
|
-
*
|
|
1898
|
-
* Documentation: [Base UI Dialog](https://base-ui.com/react/components/dialog)
|
|
1899
|
-
*/
|
|
1900
|
-
const DialogTitle = /*#__PURE__*/React__namespace.forwardRef(function DialogTitle(componentProps, forwardedRef) {
|
|
1901
|
-
const {
|
|
1902
|
-
render,
|
|
1903
|
-
className,
|
|
1904
|
-
id: idProp,
|
|
1905
|
-
...elementProps
|
|
1906
|
-
} = componentProps;
|
|
1907
|
-
const {
|
|
1908
|
-
store
|
|
1909
|
-
} = ScrollAreaViewport.useDialogRootContext();
|
|
1910
|
-
const id = useValueChanged.useBaseUiId(idProp);
|
|
1911
|
-
store.useSyncedValueWithCleanup('titleElementId', id);
|
|
1912
|
-
return useRenderElement.useRenderElement('h2', componentProps, {
|
|
1913
|
-
ref: forwardedRef,
|
|
1914
|
-
props: [{
|
|
1915
|
-
id
|
|
1916
|
-
}, elementProps]
|
|
1917
|
-
});
|
|
1918
|
-
});
|
|
1919
|
-
if (process.env.NODE_ENV !== "production") DialogTitle.displayName = "DialogTitle";
|
|
1920
|
-
|
|
1921
|
-
/**
|
|
1922
|
-
* A heading that labels the drawer.
|
|
1923
|
-
* Renders an `<h2>` element.
|
|
1924
|
-
*
|
|
1925
|
-
* Documentation: [Base UI Drawer](https://base-ui.com/react/components/drawer)
|
|
1926
|
-
*/
|
|
1927
|
-
const DrawerTitle = DialogTitle;
|
|
1928
|
-
|
|
1929
|
-
const MenuPositionerContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
1930
|
-
if (process.env.NODE_ENV !== "production") MenuPositionerContext.displayName = "MenuPositionerContext";
|
|
1931
|
-
function useMenuPositionerContext(optional) {
|
|
1932
|
-
const context = React__namespace.useContext(MenuPositionerContext);
|
|
1933
|
-
if (context === undefined && !optional) {
|
|
1934
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: MenuPositionerContext is missing. MenuPositioner parts must be placed within <Menu.Positioner>.' : useRenderElement.formatErrorMessage(33));
|
|
1935
|
-
}
|
|
1936
|
-
return context;
|
|
1937
|
-
}
|
|
1843
|
+
function getPseudoElementBounds(element) {
|
|
1844
|
+
const elementRect = element.getBoundingClientRect();
|
|
1938
1845
|
|
|
1939
|
-
|
|
1940
|
-
if (process.env.NODE_ENV !==
|
|
1941
|
-
|
|
1942
|
-
const context = React__namespace.useContext(MenuRootContext);
|
|
1943
|
-
if (context === undefined && !optional) {
|
|
1944
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: MenuRootContext is missing. Menu parts must be placed within <Menu.Root>.' : useRenderElement.formatErrorMessage(36));
|
|
1846
|
+
// Avoid "Not implemented: window.getComputedStyle(elt, pseudoElt)"
|
|
1847
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1848
|
+
return elementRect;
|
|
1945
1849
|
}
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
function useContextMenuRootContext(optional = true) {
|
|
1952
|
-
const context = React__namespace.useContext(ContextMenuRootContext);
|
|
1953
|
-
if (context === undefined && !optional) {
|
|
1954
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: ContextMenuRootContext is missing. ContextMenu parts must be placed within <ContextMenu.Root>.' : useRenderElement.formatErrorMessage(25));
|
|
1850
|
+
const beforeStyles = window.getComputedStyle(element, '::before');
|
|
1851
|
+
const afterStyles = window.getComputedStyle(element, '::after');
|
|
1852
|
+
const hasPseudoElements = beforeStyles.content !== 'none' || afterStyles.content !== 'none';
|
|
1853
|
+
if (!hasPseudoElements) {
|
|
1854
|
+
return elementRect;
|
|
1955
1855
|
}
|
|
1956
|
-
return context;
|
|
1957
|
-
}
|
|
1958
|
-
|
|
1959
|
-
/**
|
|
1960
|
-
* Returns common props shared by all menu item types.
|
|
1961
|
-
* This hook extracts the shared logic for id, role, tabIndex, onKeyDown,
|
|
1962
|
-
* onMouseMove, onClick, and onMouseUp handlers.
|
|
1963
|
-
*/
|
|
1964
|
-
function useMenuItemCommonProps(params) {
|
|
1965
|
-
const {
|
|
1966
|
-
closeOnClick,
|
|
1967
|
-
highlighted,
|
|
1968
|
-
id,
|
|
1969
|
-
nodeId,
|
|
1970
|
-
store,
|
|
1971
|
-
typingRef,
|
|
1972
|
-
itemRef,
|
|
1973
|
-
itemMetadata
|
|
1974
|
-
} = params;
|
|
1975
|
-
const {
|
|
1976
|
-
events: menuEvents
|
|
1977
|
-
} = store.useState('floatingTreeRoot');
|
|
1978
|
-
const contextMenuContext = useContextMenuRootContext(true);
|
|
1979
|
-
const isContextMenu = contextMenuContext !== undefined;
|
|
1980
|
-
return React__namespace.useMemo(() => ({
|
|
1981
|
-
id,
|
|
1982
|
-
role: 'menuitem',
|
|
1983
|
-
tabIndex: highlighted ? 0 : -1,
|
|
1984
|
-
onKeyDown(event) {
|
|
1985
|
-
if (event.key === ' ' && typingRef?.current) {
|
|
1986
|
-
event.preventDefault();
|
|
1987
|
-
}
|
|
1988
|
-
},
|
|
1989
|
-
onMouseMove(event) {
|
|
1990
|
-
if (!nodeId) {
|
|
1991
|
-
return;
|
|
1992
|
-
}
|
|
1993
1856
|
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
});
|
|
2000
|
-
},
|
|
2001
|
-
onClick(event) {
|
|
2002
|
-
if (closeOnClick) {
|
|
2003
|
-
menuEvents.emit('close', {
|
|
2004
|
-
domEvent: event,
|
|
2005
|
-
reason: useValueChanged.itemPress
|
|
2006
|
-
});
|
|
2007
|
-
}
|
|
2008
|
-
},
|
|
2009
|
-
onMouseUp(event) {
|
|
2010
|
-
if (contextMenuContext) {
|
|
2011
|
-
const initialCursorPoint = contextMenuContext.initialCursorPointRef.current;
|
|
2012
|
-
contextMenuContext.initialCursorPointRef.current = null;
|
|
2013
|
-
if (isContextMenu && initialCursorPoint && Math.abs(event.clientX - initialCursorPoint.x) <= 1 && Math.abs(event.clientY - initialCursorPoint.y) <= 1) {
|
|
2014
|
-
return;
|
|
2015
|
-
}
|
|
1857
|
+
// Get dimensions of pseudo-elements
|
|
1858
|
+
const beforeWidth = parseFloat(beforeStyles.width) || 0;
|
|
1859
|
+
const beforeHeight = parseFloat(beforeStyles.height) || 0;
|
|
1860
|
+
const afterWidth = parseFloat(afterStyles.width) || 0;
|
|
1861
|
+
const afterHeight = parseFloat(afterStyles.height) || 0;
|
|
2016
1862
|
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
return;
|
|
2021
|
-
}
|
|
2022
|
-
}
|
|
2023
|
-
if (itemRef.current && store.context.allowMouseUpTriggerRef.current && (!isContextMenu || event.button === 2)) {
|
|
2024
|
-
// This fires whenever the user clicks on the trigger, moves the cursor, and releases it over the item.
|
|
2025
|
-
// We trigger the click and override the `closeOnClick` preference to always close the menu.
|
|
2026
|
-
if (!itemMetadata || itemMetadata.type === 'regular-item') {
|
|
2027
|
-
itemRef.current.click();
|
|
2028
|
-
}
|
|
2029
|
-
}
|
|
2030
|
-
}
|
|
2031
|
-
}), [closeOnClick, highlighted, id, menuEvents, nodeId, store, typingRef, itemRef, contextMenuContext, isContextMenu, itemMetadata]);
|
|
2032
|
-
}
|
|
1863
|
+
// Calculate max dimensions including pseudo-elements
|
|
1864
|
+
const totalWidth = Math.max(elementRect.width, beforeWidth, afterWidth);
|
|
1865
|
+
const totalHeight = Math.max(elementRect.height, beforeHeight, afterHeight);
|
|
2033
1866
|
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
store,
|
|
2044
|
-
typingRef = store.context.typingRef,
|
|
2045
|
-
nativeButton,
|
|
2046
|
-
itemMetadata,
|
|
2047
|
-
nodeId
|
|
2048
|
-
} = params;
|
|
2049
|
-
const itemRef = React__namespace.useRef(null);
|
|
2050
|
-
const {
|
|
2051
|
-
getButtonProps,
|
|
2052
|
-
buttonRef
|
|
2053
|
-
} = useValueChanged.useButton({
|
|
2054
|
-
disabled,
|
|
2055
|
-
focusableWhenDisabled: true,
|
|
2056
|
-
native: nativeButton,
|
|
2057
|
-
composite: true
|
|
2058
|
-
});
|
|
2059
|
-
const commonProps = useMenuItemCommonProps({
|
|
2060
|
-
closeOnClick,
|
|
2061
|
-
highlighted,
|
|
2062
|
-
id,
|
|
2063
|
-
nodeId,
|
|
2064
|
-
store,
|
|
2065
|
-
typingRef,
|
|
2066
|
-
itemRef,
|
|
2067
|
-
itemMetadata
|
|
2068
|
-
});
|
|
2069
|
-
const getItemProps = React__namespace.useCallback(externalProps => {
|
|
2070
|
-
return useRenderElement.mergeProps(commonProps, {
|
|
2071
|
-
onMouseEnter() {
|
|
2072
|
-
if (itemMetadata.type !== 'submenu-trigger') {
|
|
2073
|
-
return;
|
|
2074
|
-
}
|
|
2075
|
-
itemMetadata.setActive();
|
|
2076
|
-
}
|
|
2077
|
-
}, externalProps, getButtonProps);
|
|
2078
|
-
}, [commonProps, getButtonProps, itemMetadata]);
|
|
2079
|
-
const mergedRef = useRenderElement.useMergedRefs(itemRef, buttonRef);
|
|
2080
|
-
return React__namespace.useMemo(() => ({
|
|
2081
|
-
getItemProps,
|
|
2082
|
-
itemRef: mergedRef
|
|
2083
|
-
}), [getItemProps, mergedRef]);
|
|
1867
|
+
// Calculate the differences to extend the bounds
|
|
1868
|
+
const widthDiff = totalWidth - elementRect.width;
|
|
1869
|
+
const heightDiff = totalHeight - elementRect.height;
|
|
1870
|
+
return {
|
|
1871
|
+
left: elementRect.left - widthDiff / 2,
|
|
1872
|
+
right: elementRect.right + widthDiff / 2,
|
|
1873
|
+
top: elementRect.top - heightDiff / 2,
|
|
1874
|
+
bottom: elementRect.bottom + heightDiff / 2
|
|
1875
|
+
};
|
|
2084
1876
|
}
|
|
2085
1877
|
|
|
2086
1878
|
const CompositeListContext = /*#__PURE__*/React__namespace.createContext({
|
|
@@ -2101,560 +1893,259 @@ function useCompositeListContext() {
|
|
|
2101
1893
|
return React__namespace.useContext(CompositeListContext);
|
|
2102
1894
|
}
|
|
2103
1895
|
|
|
2104
|
-
|
|
2105
|
-
IndexGuessBehavior[IndexGuessBehavior["None"] = 0] = "None";
|
|
2106
|
-
IndexGuessBehavior[IndexGuessBehavior["GuessFromOrder"] = 1] = "GuessFromOrder";
|
|
2107
|
-
return IndexGuessBehavior;
|
|
2108
|
-
}({});
|
|
2109
|
-
|
|
1896
|
+
/* eslint-disable no-bitwise */
|
|
2110
1897
|
/**
|
|
2111
|
-
*
|
|
1898
|
+
* Provides context for a list of items in a composite component.
|
|
1899
|
+
* @internal
|
|
2112
1900
|
*/
|
|
2113
|
-
function
|
|
2114
|
-
const {
|
|
2115
|
-
label,
|
|
2116
|
-
metadata,
|
|
2117
|
-
textRef,
|
|
2118
|
-
indexGuessBehavior,
|
|
2119
|
-
index: externalIndex
|
|
2120
|
-
} = params;
|
|
1901
|
+
function CompositeList(props) {
|
|
2121
1902
|
const {
|
|
2122
|
-
|
|
2123
|
-
unregister,
|
|
2124
|
-
subscribeMapChange,
|
|
1903
|
+
children,
|
|
2125
1904
|
elementsRef,
|
|
2126
1905
|
labelsRef,
|
|
2127
|
-
|
|
2128
|
-
} =
|
|
2129
|
-
const
|
|
2130
|
-
const
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
1906
|
+
onMapChange: onMapChangeProp
|
|
1907
|
+
} = props;
|
|
1908
|
+
const onMapChange = clamp.useStableCallback(onMapChangeProp);
|
|
1909
|
+
const nextIndexRef = React__namespace.useRef(0);
|
|
1910
|
+
const listeners = useRenderElement.useRefWithInit(createListeners).current;
|
|
1911
|
+
|
|
1912
|
+
// We use a stable `map` to avoid O(n^2) re-allocation costs for large lists.
|
|
1913
|
+
// `mapTick` is our re-render trigger mechanism. We also need to update the
|
|
1914
|
+
// elements and label refs, but there's a lot of async work going on and sometimes
|
|
1915
|
+
// the effect that handles `onMapChange` gets called after those refs have been
|
|
1916
|
+
// filled, and we don't want to lose those values by setting their lengths to `0`.
|
|
1917
|
+
// We also need to have them at the proper length because floating-ui uses that
|
|
1918
|
+
// information for list navigation.
|
|
1919
|
+
|
|
1920
|
+
const map = useRenderElement.useRefWithInit(createMap).current;
|
|
1921
|
+
// `mapTick` uses a counter rather than objects for low precision-loss risk and better memory efficiency
|
|
1922
|
+
const [mapTick, setMapTick] = React__namespace.useState(0);
|
|
1923
|
+
const lastTickRef = React__namespace.useRef(mapTick);
|
|
1924
|
+
const register = clamp.useStableCallback((node, metadata) => {
|
|
1925
|
+
map.set(node, metadata ?? null);
|
|
1926
|
+
lastTickRef.current += 1;
|
|
1927
|
+
setMapTick(lastTickRef.current);
|
|
1928
|
+
});
|
|
1929
|
+
const unregister = clamp.useStableCallback(node => {
|
|
1930
|
+
map.delete(node);
|
|
1931
|
+
lastTickRef.current += 1;
|
|
1932
|
+
setMapTick(lastTickRef.current);
|
|
1933
|
+
});
|
|
1934
|
+
const sortedMap = React__namespace.useMemo(() => {
|
|
1935
|
+
const newMap = new Map();
|
|
1936
|
+
// Filter out disconnected elements before sorting to avoid inconsistent
|
|
1937
|
+
// compareDocumentPosition results when elements are detached from the DOM.
|
|
1938
|
+
const sortedNodes = Array.from(map.keys()).filter(node => node.isConnected).sort(sortByDocumentPosition);
|
|
1939
|
+
sortedNodes.forEach((node, index) => {
|
|
1940
|
+
const metadata = map.get(node) ?? {};
|
|
1941
|
+
newMap.set(node, {
|
|
1942
|
+
...metadata,
|
|
1943
|
+
index
|
|
1944
|
+
});
|
|
1945
|
+
});
|
|
1946
|
+
return newMap;
|
|
1947
|
+
}, [map, mapTick]);
|
|
1948
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1949
|
+
if (typeof MutationObserver !== 'function' || sortedMap.size === 0) {
|
|
2164
1950
|
return undefined;
|
|
2165
1951
|
}
|
|
2166
|
-
|
|
2167
|
-
const
|
|
2168
|
-
|
|
2169
|
-
|
|
1952
|
+
const mutationObserver = new MutationObserver(entries => {
|
|
1953
|
+
const diff = new Set();
|
|
1954
|
+
const updateDiff = node => diff.has(node) ? diff.delete(node) : diff.add(node);
|
|
1955
|
+
entries.forEach(entry => {
|
|
1956
|
+
entry.removedNodes.forEach(updateDiff);
|
|
1957
|
+
entry.addedNodes.forEach(updateDiff);
|
|
1958
|
+
});
|
|
1959
|
+
if (diff.size === 0) {
|
|
1960
|
+
lastTickRef.current += 1;
|
|
1961
|
+
setMapTick(lastTickRef.current);
|
|
2170
1962
|
}
|
|
2171
1963
|
});
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
}
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
* Present when the menu checkbox item is checked.
|
|
2182
|
-
*/
|
|
2183
|
-
MenuCheckboxItemDataAttributes["checked"] = "data-checked";
|
|
2184
|
-
/**
|
|
2185
|
-
* Present when the menu checkbox item is not checked.
|
|
2186
|
-
*/
|
|
2187
|
-
MenuCheckboxItemDataAttributes["unchecked"] = "data-unchecked";
|
|
2188
|
-
/**
|
|
2189
|
-
* Present when the menu checkbox item is disabled.
|
|
2190
|
-
*/
|
|
2191
|
-
MenuCheckboxItemDataAttributes["disabled"] = "data-disabled";
|
|
2192
|
-
/**
|
|
2193
|
-
* Present when the menu checkbox item is highlighted.
|
|
2194
|
-
*/
|
|
2195
|
-
MenuCheckboxItemDataAttributes["highlighted"] = "data-highlighted";
|
|
2196
|
-
return MenuCheckboxItemDataAttributes;
|
|
2197
|
-
}({});
|
|
2198
|
-
|
|
2199
|
-
const itemMapping = {
|
|
2200
|
-
checked(value) {
|
|
2201
|
-
if (value) {
|
|
2202
|
-
return {
|
|
2203
|
-
[MenuCheckboxItemDataAttributes.checked]: ''
|
|
2204
|
-
};
|
|
2205
|
-
}
|
|
2206
|
-
return {
|
|
2207
|
-
[MenuCheckboxItemDataAttributes.unchecked]: ''
|
|
1964
|
+
sortedMap.forEach((_, node) => {
|
|
1965
|
+
if (node.parentElement) {
|
|
1966
|
+
mutationObserver.observe(node.parentElement, {
|
|
1967
|
+
childList: true
|
|
1968
|
+
});
|
|
1969
|
+
}
|
|
1970
|
+
});
|
|
1971
|
+
return () => {
|
|
1972
|
+
mutationObserver.disconnect();
|
|
2208
1973
|
};
|
|
2209
|
-
},
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
return context;
|
|
2221
|
-
}
|
|
2222
|
-
|
|
2223
|
-
const MenuGroup = /*#__PURE__*/React__namespace.forwardRef(function MenuGroup(componentProps, forwardedRef) {
|
|
2224
|
-
const {
|
|
2225
|
-
render,
|
|
2226
|
-
className,
|
|
2227
|
-
...elementProps
|
|
2228
|
-
} = componentProps;
|
|
2229
|
-
const [labelId, setLabelId] = React__namespace.useState(undefined);
|
|
2230
|
-
const context = React__namespace.useMemo(() => ({
|
|
2231
|
-
setLabelId
|
|
2232
|
-
}), [setLabelId]);
|
|
2233
|
-
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
2234
|
-
ref: forwardedRef,
|
|
2235
|
-
props: {
|
|
2236
|
-
role: 'group',
|
|
2237
|
-
'aria-labelledby': labelId,
|
|
2238
|
-
...elementProps
|
|
1974
|
+
}, [sortedMap]);
|
|
1975
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1976
|
+
const shouldUpdateLengths = lastTickRef.current === mapTick;
|
|
1977
|
+
if (shouldUpdateLengths) {
|
|
1978
|
+
if (elementsRef.current.length !== sortedMap.size) {
|
|
1979
|
+
elementsRef.current.length = sortedMap.size;
|
|
1980
|
+
}
|
|
1981
|
+
if (labelsRef && labelsRef.current.length !== sortedMap.size) {
|
|
1982
|
+
labelsRef.current.length = sortedMap.size;
|
|
1983
|
+
}
|
|
1984
|
+
nextIndexRef.current = sortedMap.size;
|
|
2239
1985
|
}
|
|
1986
|
+
onMapChange(sortedMap);
|
|
1987
|
+
}, [onMapChange, sortedMap, elementsRef, labelsRef, mapTick]);
|
|
1988
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1989
|
+
return () => {
|
|
1990
|
+
elementsRef.current = [];
|
|
1991
|
+
};
|
|
1992
|
+
}, [elementsRef]);
|
|
1993
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1994
|
+
return () => {
|
|
1995
|
+
if (labelsRef) {
|
|
1996
|
+
labelsRef.current = [];
|
|
1997
|
+
}
|
|
1998
|
+
};
|
|
1999
|
+
}, [labelsRef]);
|
|
2000
|
+
const subscribeMapChange = clamp.useStableCallback(fn => {
|
|
2001
|
+
listeners.add(fn);
|
|
2002
|
+
return () => {
|
|
2003
|
+
listeners.delete(fn);
|
|
2004
|
+
};
|
|
2240
2005
|
});
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2006
|
+
clamp.useIsoLayoutEffect(() => {
|
|
2007
|
+
listeners.forEach(l => l(sortedMap));
|
|
2008
|
+
}, [listeners, sortedMap]);
|
|
2009
|
+
const contextValue = React__namespace.useMemo(() => ({
|
|
2010
|
+
register,
|
|
2011
|
+
unregister,
|
|
2012
|
+
subscribeMapChange,
|
|
2013
|
+
elementsRef,
|
|
2014
|
+
labelsRef,
|
|
2015
|
+
nextIndexRef
|
|
2016
|
+
}), [register, unregister, subscribeMapChange, elementsRef, labelsRef, nextIndexRef]);
|
|
2017
|
+
return /*#__PURE__*/jsxRuntime.jsx(CompositeListContext.Provider, {
|
|
2018
|
+
value: contextValue,
|
|
2019
|
+
children: children
|
|
2244
2020
|
});
|
|
2245
|
-
}
|
|
2246
|
-
|
|
2021
|
+
}
|
|
2022
|
+
function createMap() {
|
|
2023
|
+
return new Map();
|
|
2024
|
+
}
|
|
2025
|
+
function createListeners() {
|
|
2026
|
+
return new Set();
|
|
2027
|
+
}
|
|
2028
|
+
function sortByDocumentPosition(a, b) {
|
|
2029
|
+
const position = a.compareDocumentPosition(b);
|
|
2030
|
+
if (position & Node.DOCUMENT_POSITION_FOLLOWING || position & Node.DOCUMENT_POSITION_CONTAINED_BY) {
|
|
2031
|
+
return -1;
|
|
2032
|
+
}
|
|
2033
|
+
if (position & Node.DOCUMENT_POSITION_PRECEDING || position & Node.DOCUMENT_POSITION_CONTAINS) {
|
|
2034
|
+
return 1;
|
|
2035
|
+
}
|
|
2036
|
+
return 0;
|
|
2037
|
+
}
|
|
2247
2038
|
|
|
2248
2039
|
/**
|
|
2249
|
-
*
|
|
2250
|
-
*
|
|
2251
|
-
*
|
|
2252
|
-
* Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
|
|
2040
|
+
* Fork of the original `arrow` middleware from Floating UI that allows
|
|
2041
|
+
* configuring the offset parent.
|
|
2253
2042
|
*/
|
|
2254
|
-
const
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2043
|
+
const baseArrow = options => ({
|
|
2044
|
+
name: 'arrow',
|
|
2045
|
+
options,
|
|
2046
|
+
async fn(state) {
|
|
2047
|
+
const {
|
|
2048
|
+
x,
|
|
2049
|
+
y,
|
|
2050
|
+
placement,
|
|
2051
|
+
rects,
|
|
2052
|
+
platform,
|
|
2053
|
+
elements,
|
|
2054
|
+
middlewareData
|
|
2055
|
+
} = state;
|
|
2056
|
+
// Since `element` is required, we don't Partial<> the type.
|
|
2057
|
+
const {
|
|
2058
|
+
element,
|
|
2059
|
+
padding = 0,
|
|
2060
|
+
offsetParent = 'real'
|
|
2061
|
+
} = index_esm.evaluate(options, state) || {};
|
|
2062
|
+
if (element == null) {
|
|
2063
|
+
return {};
|
|
2064
|
+
}
|
|
2065
|
+
const paddingObject = index_esm.getPaddingObject(padding);
|
|
2066
|
+
const coords = {
|
|
2067
|
+
x,
|
|
2068
|
+
y
|
|
2269
2069
|
};
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2070
|
+
const axis = index_esm.getAlignmentAxis(placement);
|
|
2071
|
+
const length = index_esm.getAxisLength(axis);
|
|
2072
|
+
const arrowDimensions = await platform.getDimensions(element);
|
|
2073
|
+
const isYAxis = axis === 'y';
|
|
2074
|
+
const minProp = isYAxis ? 'top' : 'left';
|
|
2075
|
+
const maxProp = isYAxis ? 'bottom' : 'right';
|
|
2076
|
+
const clientProp = isYAxis ? 'clientHeight' : 'clientWidth';
|
|
2077
|
+
const endDiff = rects.reference[length] + rects.reference[axis] - coords[axis] - rects.floating[length];
|
|
2078
|
+
const startDiff = coords[axis] - rects.reference[axis];
|
|
2079
|
+
const arrowOffsetParent = offsetParent === 'real' ? await platform.getOffsetParent?.(element) : elements.floating;
|
|
2080
|
+
let clientSize = elements.floating[clientProp] || rects.floating[length];
|
|
2081
|
+
|
|
2082
|
+
// DOM platform can return `window` as the `offsetParent`.
|
|
2083
|
+
if (!clientSize || !(await platform.isElement?.(arrowOffsetParent))) {
|
|
2084
|
+
clientSize = elements.floating[clientProp] || rects.floating[length];
|
|
2277
2085
|
}
|
|
2278
|
-
|
|
2279
|
-
});
|
|
2280
|
-
if (process.env.NODE_ENV !== "production") MenuGroupLabel.displayName = "MenuGroupLabel";
|
|
2086
|
+
const centerToReference = endDiff / 2 - startDiff / 2;
|
|
2281
2087
|
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
disabled,
|
|
2315
|
-
highlighted,
|
|
2316
|
-
id,
|
|
2317
|
-
store,
|
|
2318
|
-
nativeButton,
|
|
2319
|
-
nodeId: menuPositionerContext?.nodeId,
|
|
2320
|
-
itemMetadata: REGULAR_ITEM
|
|
2321
|
-
});
|
|
2322
|
-
const state = {
|
|
2323
|
-
disabled,
|
|
2324
|
-
highlighted
|
|
2325
|
-
};
|
|
2326
|
-
return useRenderElement.useRenderElement('div', componentProps, {
|
|
2327
|
-
state,
|
|
2328
|
-
props: [itemProps, elementProps, getItemProps],
|
|
2329
|
-
ref: [itemRef, forwardedRef, listItem.ref]
|
|
2330
|
-
});
|
|
2088
|
+
// If the padding is large enough that it causes the arrow to no longer be
|
|
2089
|
+
// centered, modify the padding so that it is centered.
|
|
2090
|
+
const largestPossiblePadding = clientSize / 2 - arrowDimensions[length] / 2 - 1;
|
|
2091
|
+
const minPadding = Math.min(paddingObject[minProp], largestPossiblePadding);
|
|
2092
|
+
const maxPadding = Math.min(paddingObject[maxProp], largestPossiblePadding);
|
|
2093
|
+
|
|
2094
|
+
// Make sure the arrow doesn't overflow the floating element if the center
|
|
2095
|
+
// point is outside the floating element's bounds.
|
|
2096
|
+
const min = minPadding;
|
|
2097
|
+
const max = clientSize - arrowDimensions[length] - maxPadding;
|
|
2098
|
+
const center = clientSize / 2 - arrowDimensions[length] / 2 + centerToReference;
|
|
2099
|
+
const offset = index_esm.clamp(min, center, max);
|
|
2100
|
+
|
|
2101
|
+
// If the reference is small enough that the arrow's padding causes it to
|
|
2102
|
+
// to point to nothing for an aligned placement, adjust the offset of the
|
|
2103
|
+
// floating element itself. To ensure `shift()` continues to take action,
|
|
2104
|
+
// a single reset is performed when this is true.
|
|
2105
|
+
const shouldAddOffset = !middlewareData.arrow && index_esm.getAlignment(placement) != null && center !== offset && rects.reference[length] / 2 - (center < min ? minPadding : maxPadding) - arrowDimensions[length] / 2 < 0;
|
|
2106
|
+
// eslint-disable-next-line no-nested-ternary
|
|
2107
|
+
const alignmentOffset = shouldAddOffset ? center < min ? center - min : center - max : 0;
|
|
2108
|
+
return {
|
|
2109
|
+
[axis]: coords[axis] + alignmentOffset,
|
|
2110
|
+
data: {
|
|
2111
|
+
[axis]: offset,
|
|
2112
|
+
centerOffset: center - offset - alignmentOffset,
|
|
2113
|
+
...(shouldAddOffset && {
|
|
2114
|
+
alignmentOffset
|
|
2115
|
+
})
|
|
2116
|
+
},
|
|
2117
|
+
reset: shouldAddOffset
|
|
2118
|
+
};
|
|
2119
|
+
}
|
|
2331
2120
|
});
|
|
2332
|
-
if (process.env.NODE_ENV !== "production") MenuItem.displayName = "MenuItem";
|
|
2333
2121
|
|
|
2334
2122
|
/**
|
|
2335
|
-
*
|
|
2336
|
-
*
|
|
2337
|
-
*
|
|
2338
|
-
*
|
|
2123
|
+
* Provides data to position an inner element of the floating element so that it
|
|
2124
|
+
* appears centered to the reference element.
|
|
2125
|
+
* This wraps the core `arrow` middleware to allow React refs as the element.
|
|
2126
|
+
* @see https://floating-ui.com/docs/arrow
|
|
2339
2127
|
*/
|
|
2340
|
-
const
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
className,
|
|
2344
|
-
id: idProp,
|
|
2345
|
-
label,
|
|
2346
|
-
closeOnClick = false,
|
|
2347
|
-
...elementProps
|
|
2348
|
-
} = componentProps;
|
|
2349
|
-
const linkRef = React__namespace.useRef(null);
|
|
2350
|
-
const listItem = useCompositeListItem({
|
|
2351
|
-
label
|
|
2352
|
-
});
|
|
2353
|
-
const menuPositionerContext = useMenuPositionerContext(true);
|
|
2354
|
-
const nodeId = menuPositionerContext?.nodeId;
|
|
2355
|
-
const id = useValueChanged.useBaseUiId(idProp);
|
|
2356
|
-
const {
|
|
2357
|
-
store
|
|
2358
|
-
} = useMenuRootContext();
|
|
2359
|
-
const highlighted = store.useState('isActive', listItem.index);
|
|
2360
|
-
const itemProps = store.useState('itemProps');
|
|
2361
|
-
const typingRef = store.context.typingRef;
|
|
2362
|
-
const {
|
|
2363
|
-
getButtonProps,
|
|
2364
|
-
buttonRef
|
|
2365
|
-
} = useValueChanged.useButton({
|
|
2366
|
-
native: false,
|
|
2367
|
-
composite: true
|
|
2368
|
-
});
|
|
2369
|
-
const commonProps = useMenuItemCommonProps({
|
|
2370
|
-
closeOnClick,
|
|
2371
|
-
highlighted,
|
|
2372
|
-
id,
|
|
2373
|
-
nodeId,
|
|
2374
|
-
store,
|
|
2375
|
-
typingRef,
|
|
2376
|
-
itemRef: linkRef
|
|
2377
|
-
});
|
|
2378
|
-
function getItemProps(externalProps) {
|
|
2379
|
-
return useRenderElement.mergeProps(commonProps, externalProps, getButtonProps);
|
|
2380
|
-
}
|
|
2381
|
-
const state = React__namespace.useMemo(() => ({
|
|
2382
|
-
highlighted
|
|
2383
|
-
}), [highlighted]);
|
|
2384
|
-
return useRenderElement.useRenderElement('a', componentProps, {
|
|
2385
|
-
state,
|
|
2386
|
-
props: [itemProps, elementProps, getItemProps],
|
|
2387
|
-
ref: [linkRef, buttonRef, forwardedRef, listItem.ref]
|
|
2388
|
-
});
|
|
2128
|
+
const arrow = (options, deps) => ({
|
|
2129
|
+
...baseArrow(options),
|
|
2130
|
+
options: [options, deps]
|
|
2389
2131
|
});
|
|
2390
|
-
if (process.env.NODE_ENV !== "production") MenuLinkItem.displayName = "MenuLinkItem";
|
|
2391
2132
|
|
|
2392
|
-
const
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
}
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
...useValueChanged.transitionStatusMapping
|
|
2409
|
-
};
|
|
2410
|
-
|
|
2411
|
-
/**
|
|
2412
|
-
* A container for the menu items.
|
|
2413
|
-
* Renders a `<div>` element.
|
|
2414
|
-
*
|
|
2415
|
-
* Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
|
|
2416
|
-
*/
|
|
2417
|
-
const MenuPopup = /*#__PURE__*/React__namespace.forwardRef(function MenuPopup(componentProps, forwardedRef) {
|
|
2418
|
-
const {
|
|
2419
|
-
render,
|
|
2420
|
-
className,
|
|
2421
|
-
finalFocus,
|
|
2422
|
-
...elementProps
|
|
2423
|
-
} = componentProps;
|
|
2424
|
-
const {
|
|
2425
|
-
store
|
|
2426
|
-
} = useMenuRootContext();
|
|
2427
|
-
const {
|
|
2428
|
-
side,
|
|
2429
|
-
align
|
|
2430
|
-
} = useMenuPositionerContext();
|
|
2431
|
-
const insideToolbar = useToolbarRootContext(true) != null;
|
|
2432
|
-
const open = store.useState('open');
|
|
2433
|
-
const transitionStatus = store.useState('transitionStatus');
|
|
2434
|
-
const popupProps = store.useState('popupProps');
|
|
2435
|
-
const mounted = store.useState('mounted');
|
|
2436
|
-
const instantType = store.useState('instantType');
|
|
2437
|
-
const triggerElement = store.useState('activeTriggerElement');
|
|
2438
|
-
const parent = store.useState('parent');
|
|
2439
|
-
const lastOpenChangeReason = store.useState('lastOpenChangeReason');
|
|
2440
|
-
const rootId = store.useState('rootId');
|
|
2441
|
-
const floatingContext = store.useState('floatingRootContext');
|
|
2442
|
-
const floatingTreeRoot = store.useState('floatingTreeRoot');
|
|
2443
|
-
const closeDelay = store.useState('closeDelay');
|
|
2444
|
-
const activeTriggerElement = store.useState('activeTriggerElement');
|
|
2445
|
-
const isContextMenu = parent.type === 'context-menu';
|
|
2446
|
-
useValueChanged.useOpenChangeComplete({
|
|
2447
|
-
open,
|
|
2448
|
-
ref: store.context.popupRef,
|
|
2449
|
-
onComplete() {
|
|
2450
|
-
if (open) {
|
|
2451
|
-
store.context.onOpenChangeComplete?.(true);
|
|
2452
|
-
}
|
|
2453
|
-
}
|
|
2454
|
-
});
|
|
2455
|
-
React__namespace.useEffect(() => {
|
|
2456
|
-
function handleClose(event) {
|
|
2457
|
-
store.setOpen(false, useValueChanged.createChangeEventDetails(event.reason, event.domEvent));
|
|
2458
|
-
}
|
|
2459
|
-
floatingTreeRoot.events.on('close', handleClose);
|
|
2460
|
-
return () => {
|
|
2461
|
-
floatingTreeRoot.events.off('close', handleClose);
|
|
2462
|
-
};
|
|
2463
|
-
}, [floatingTreeRoot.events, store]);
|
|
2464
|
-
const hoverEnabled = store.useState('hoverEnabled');
|
|
2465
|
-
const disabled = store.useState('disabled');
|
|
2466
|
-
useHoverFloatingInteraction(floatingContext, {
|
|
2467
|
-
enabled: hoverEnabled && !disabled && !isContextMenu && parent.type !== 'menubar',
|
|
2468
|
-
closeDelay
|
|
2469
|
-
});
|
|
2470
|
-
const state = {
|
|
2471
|
-
transitionStatus,
|
|
2472
|
-
side,
|
|
2473
|
-
align,
|
|
2474
|
-
open,
|
|
2475
|
-
nested: parent.type === 'menu',
|
|
2476
|
-
instant: instantType
|
|
2477
|
-
};
|
|
2478
|
-
const setPopupElement = React__namespace.useCallback(element => {
|
|
2479
|
-
store.set('popupElement', element);
|
|
2480
|
-
}, [store]);
|
|
2481
|
-
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
2482
|
-
state,
|
|
2483
|
-
ref: [forwardedRef, store.context.popupRef, setPopupElement],
|
|
2484
|
-
stateAttributesMapping,
|
|
2485
|
-
props: [popupProps, {
|
|
2486
|
-
onKeyDown(event) {
|
|
2487
|
-
if (insideToolbar && ScrollAreaViewport.COMPOSITE_KEYS.has(event.key)) {
|
|
2488
|
-
event.stopPropagation();
|
|
2489
|
-
}
|
|
2490
|
-
}
|
|
2491
|
-
}, getDisabledMountTransitionStyles(transitionStatus), elementProps, {
|
|
2492
|
-
'data-rootownerid': rootId
|
|
2493
|
-
}]
|
|
2494
|
-
});
|
|
2495
|
-
let returnFocus = parent.type === undefined || isContextMenu;
|
|
2496
|
-
if (triggerElement || parent.type === 'menubar' && lastOpenChangeReason !== useValueChanged.outsidePress) {
|
|
2497
|
-
returnFocus = true;
|
|
2498
|
-
}
|
|
2499
|
-
return /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.FloatingFocusManager, {
|
|
2500
|
-
context: floatingContext,
|
|
2501
|
-
modal: isContextMenu,
|
|
2502
|
-
disabled: !mounted,
|
|
2503
|
-
returnFocus: finalFocus === undefined ? returnFocus : finalFocus,
|
|
2504
|
-
initialFocus: parent.type !== 'menu',
|
|
2505
|
-
restoreFocus: true,
|
|
2506
|
-
externalTree: parent.type !== 'menubar' ? floatingTreeRoot : undefined,
|
|
2507
|
-
previousFocusableElement: activeTriggerElement,
|
|
2508
|
-
nextFocusableElement: parent.type === undefined ? store.context.triggerFocusTargetRef : undefined,
|
|
2509
|
-
beforeContentFocusGuardRef: parent.type === undefined ? store.context.beforeContentFocusGuardRef : undefined,
|
|
2510
|
-
children: element
|
|
2511
|
-
});
|
|
2512
|
-
});
|
|
2513
|
-
if (process.env.NODE_ENV !== "production") MenuPopup.displayName = "MenuPopup";
|
|
2514
|
-
|
|
2515
|
-
const MenuPortalContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
2516
|
-
if (process.env.NODE_ENV !== "production") MenuPortalContext.displayName = "MenuPortalContext";
|
|
2517
|
-
function useMenuPortalContext() {
|
|
2518
|
-
const value = React__namespace.useContext(MenuPortalContext);
|
|
2519
|
-
if (value === undefined) {
|
|
2520
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: <Menu.Portal> is missing.' : useRenderElement.formatErrorMessage(32));
|
|
2521
|
-
}
|
|
2522
|
-
return value;
|
|
2523
|
-
}
|
|
2524
|
-
|
|
2525
|
-
const MenuPortal = /*#__PURE__*/React__namespace.forwardRef(function MenuPortal(props, forwardedRef) {
|
|
2526
|
-
const {
|
|
2527
|
-
keepMounted = false,
|
|
2528
|
-
...portalProps
|
|
2529
|
-
} = props;
|
|
2530
|
-
const {
|
|
2531
|
-
store
|
|
2532
|
-
} = useMenuRootContext();
|
|
2533
|
-
const mounted = store.useState('mounted');
|
|
2534
|
-
const shouldRender = mounted || keepMounted;
|
|
2535
|
-
if (!shouldRender) {
|
|
2536
|
-
return null;
|
|
2537
|
-
}
|
|
2538
|
-
return /*#__PURE__*/jsxRuntime.jsx(MenuPortalContext.Provider, {
|
|
2539
|
-
value: keepMounted,
|
|
2540
|
-
children: /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.FloatingPortal, {
|
|
2541
|
-
ref: forwardedRef,
|
|
2542
|
-
...portalProps
|
|
2543
|
-
})
|
|
2544
|
-
});
|
|
2545
|
-
});
|
|
2546
|
-
if (process.env.NODE_ENV !== "production") MenuPortal.displayName = "MenuPortal";
|
|
2547
|
-
|
|
2548
|
-
/**
|
|
2549
|
-
* Fork of the original `arrow` middleware from Floating UI that allows
|
|
2550
|
-
* configuring the offset parent.
|
|
2551
|
-
*/
|
|
2552
|
-
const baseArrow = options => ({
|
|
2553
|
-
name: 'arrow',
|
|
2554
|
-
options,
|
|
2555
|
-
async fn(state) {
|
|
2556
|
-
const {
|
|
2557
|
-
x,
|
|
2558
|
-
y,
|
|
2559
|
-
placement,
|
|
2560
|
-
rects,
|
|
2561
|
-
platform,
|
|
2562
|
-
elements,
|
|
2563
|
-
middlewareData
|
|
2564
|
-
} = state;
|
|
2565
|
-
// Since `element` is required, we don't Partial<> the type.
|
|
2566
|
-
const {
|
|
2567
|
-
element,
|
|
2568
|
-
padding = 0,
|
|
2569
|
-
offsetParent = 'real'
|
|
2570
|
-
} = index_esm.evaluate(options, state) || {};
|
|
2571
|
-
if (element == null) {
|
|
2572
|
-
return {};
|
|
2573
|
-
}
|
|
2574
|
-
const paddingObject = index_esm.getPaddingObject(padding);
|
|
2575
|
-
const coords = {
|
|
2576
|
-
x,
|
|
2577
|
-
y
|
|
2578
|
-
};
|
|
2579
|
-
const axis = index_esm.getAlignmentAxis(placement);
|
|
2580
|
-
const length = index_esm.getAxisLength(axis);
|
|
2581
|
-
const arrowDimensions = await platform.getDimensions(element);
|
|
2582
|
-
const isYAxis = axis === 'y';
|
|
2583
|
-
const minProp = isYAxis ? 'top' : 'left';
|
|
2584
|
-
const maxProp = isYAxis ? 'bottom' : 'right';
|
|
2585
|
-
const clientProp = isYAxis ? 'clientHeight' : 'clientWidth';
|
|
2586
|
-
const endDiff = rects.reference[length] + rects.reference[axis] - coords[axis] - rects.floating[length];
|
|
2587
|
-
const startDiff = coords[axis] - rects.reference[axis];
|
|
2588
|
-
const arrowOffsetParent = offsetParent === 'real' ? await platform.getOffsetParent?.(element) : elements.floating;
|
|
2589
|
-
let clientSize = elements.floating[clientProp] || rects.floating[length];
|
|
2590
|
-
|
|
2591
|
-
// DOM platform can return `window` as the `offsetParent`.
|
|
2592
|
-
if (!clientSize || !(await platform.isElement?.(arrowOffsetParent))) {
|
|
2593
|
-
clientSize = elements.floating[clientProp] || rects.floating[length];
|
|
2594
|
-
}
|
|
2595
|
-
const centerToReference = endDiff / 2 - startDiff / 2;
|
|
2596
|
-
|
|
2597
|
-
// If the padding is large enough that it causes the arrow to no longer be
|
|
2598
|
-
// centered, modify the padding so that it is centered.
|
|
2599
|
-
const largestPossiblePadding = clientSize / 2 - arrowDimensions[length] / 2 - 1;
|
|
2600
|
-
const minPadding = Math.min(paddingObject[minProp], largestPossiblePadding);
|
|
2601
|
-
const maxPadding = Math.min(paddingObject[maxProp], largestPossiblePadding);
|
|
2602
|
-
|
|
2603
|
-
// Make sure the arrow doesn't overflow the floating element if the center
|
|
2604
|
-
// point is outside the floating element's bounds.
|
|
2605
|
-
const min = minPadding;
|
|
2606
|
-
const max = clientSize - arrowDimensions[length] - maxPadding;
|
|
2607
|
-
const center = clientSize / 2 - arrowDimensions[length] / 2 + centerToReference;
|
|
2608
|
-
const offset = index_esm.clamp(min, center, max);
|
|
2609
|
-
|
|
2610
|
-
// If the reference is small enough that the arrow's padding causes it to
|
|
2611
|
-
// to point to nothing for an aligned placement, adjust the offset of the
|
|
2612
|
-
// floating element itself. To ensure `shift()` continues to take action,
|
|
2613
|
-
// a single reset is performed when this is true.
|
|
2614
|
-
const shouldAddOffset = !middlewareData.arrow && index_esm.getAlignment(placement) != null && center !== offset && rects.reference[length] / 2 - (center < min ? minPadding : maxPadding) - arrowDimensions[length] / 2 < 0;
|
|
2615
|
-
// eslint-disable-next-line no-nested-ternary
|
|
2616
|
-
const alignmentOffset = shouldAddOffset ? center < min ? center - min : center - max : 0;
|
|
2617
|
-
return {
|
|
2618
|
-
[axis]: coords[axis] + alignmentOffset,
|
|
2619
|
-
data: {
|
|
2620
|
-
[axis]: offset,
|
|
2621
|
-
centerOffset: center - offset - alignmentOffset,
|
|
2622
|
-
...(shouldAddOffset && {
|
|
2623
|
-
alignmentOffset
|
|
2624
|
-
})
|
|
2625
|
-
},
|
|
2626
|
-
reset: shouldAddOffset
|
|
2627
|
-
};
|
|
2628
|
-
}
|
|
2629
|
-
});
|
|
2630
|
-
|
|
2631
|
-
/**
|
|
2632
|
-
* Provides data to position an inner element of the floating element so that it
|
|
2633
|
-
* appears centered to the reference element.
|
|
2634
|
-
* This wraps the core `arrow` middleware to allow React refs as the element.
|
|
2635
|
-
* @see https://floating-ui.com/docs/arrow
|
|
2636
|
-
*/
|
|
2637
|
-
const arrow = (options, deps) => ({
|
|
2638
|
-
...baseArrow(options),
|
|
2639
|
-
options: [options, deps]
|
|
2640
|
-
});
|
|
2641
|
-
|
|
2642
|
-
const hide = {
|
|
2643
|
-
name: 'hide',
|
|
2644
|
-
async fn(state) {
|
|
2645
|
-
const {
|
|
2646
|
-
width,
|
|
2647
|
-
height,
|
|
2648
|
-
x,
|
|
2649
|
-
y
|
|
2650
|
-
} = state.rects.reference;
|
|
2651
|
-
const anchorHidden = width === 0 && height === 0 && x === 0 && y === 0;
|
|
2652
|
-
const nativeHideResult = await floatingUi_reactDom.hide().fn(state);
|
|
2653
|
-
return {
|
|
2654
|
-
data: {
|
|
2655
|
-
referenceHidden: nativeHideResult.data?.referenceHidden || anchorHidden
|
|
2656
|
-
}
|
|
2657
|
-
};
|
|
2133
|
+
const hide = {
|
|
2134
|
+
name: 'hide',
|
|
2135
|
+
async fn(state) {
|
|
2136
|
+
const {
|
|
2137
|
+
width,
|
|
2138
|
+
height,
|
|
2139
|
+
x,
|
|
2140
|
+
y
|
|
2141
|
+
} = state.rects.reference;
|
|
2142
|
+
const anchorHidden = width === 0 && height === 0 && x === 0 && y === 0;
|
|
2143
|
+
const nativeHideResult = await floatingUi_reactDom.hide().fn(state);
|
|
2144
|
+
return {
|
|
2145
|
+
data: {
|
|
2146
|
+
referenceHidden: nativeHideResult.data?.referenceHidden || anchorHidden
|
|
2147
|
+
}
|
|
2148
|
+
};
|
|
2658
2149
|
}
|
|
2659
2150
|
};
|
|
2660
2151
|
|
|
@@ -2701,7 +2192,7 @@ const adaptiveOrigin = {
|
|
|
2701
2192
|
height: win.visualViewport.height
|
|
2702
2193
|
};
|
|
2703
2194
|
} else if (offsetParent === win) {
|
|
2704
|
-
const doc =
|
|
2195
|
+
const doc = clamp.ownerDocument(floating);
|
|
2705
2196
|
offsetDimensions = {
|
|
2706
2197
|
width: doc.documentElement.clientWidth,
|
|
2707
2198
|
height: doc.documentElement.clientHeight
|
|
@@ -2798,9 +2289,9 @@ function useAnchorPositioning(params) {
|
|
|
2798
2289
|
const collisionAvoidanceAlign = collisionAvoidance.align || 'flip';
|
|
2799
2290
|
const collisionAvoidanceFallbackAxisSide = collisionAvoidance.fallbackAxisSide || 'end';
|
|
2800
2291
|
const anchorFn = typeof anchor === 'function' ? anchor : undefined;
|
|
2801
|
-
const anchorFnCallback =
|
|
2292
|
+
const anchorFnCallback = clamp.useStableCallback(anchorFn);
|
|
2802
2293
|
const anchorDep = anchorFn ? anchorFnCallback : anchor;
|
|
2803
|
-
const anchorValueRef =
|
|
2294
|
+
const anchorValueRef = clamp.useValueAsRef(anchor);
|
|
2804
2295
|
const direction = ScrollAreaViewport.useDirection();
|
|
2805
2296
|
const isRtl = direction === 'rtl';
|
|
2806
2297
|
const side = mountSide || {
|
|
@@ -2848,8 +2339,8 @@ function useAnchorPositioning(params) {
|
|
|
2848
2339
|
const arrowRef = React__namespace.useRef(null);
|
|
2849
2340
|
|
|
2850
2341
|
// Keep these reactive if they're not functions
|
|
2851
|
-
const sideOffsetRef =
|
|
2852
|
-
const alignOffsetRef =
|
|
2342
|
+
const sideOffsetRef = clamp.useValueAsRef(sideOffset);
|
|
2343
|
+
const alignOffsetRef = clamp.useValueAsRef(alignOffset);
|
|
2853
2344
|
const sideOffsetDep = typeof sideOffset !== 'function' ? sideOffset : 0;
|
|
2854
2345
|
const alignOffsetDep = typeof alignOffset !== 'function' ? alignOffset : 0;
|
|
2855
2346
|
const middleware = [floatingUi_reactDom.offset(state => {
|
|
@@ -2879,7 +2370,7 @@ function useAnchorPositioning(params) {
|
|
|
2879
2370
|
fallbackAxisSideDirection: collisionAvoidanceFallbackAxisSide
|
|
2880
2371
|
});
|
|
2881
2372
|
const shiftMiddleware = shiftDisabled ? null : floatingUi_reactDom.shift(data => {
|
|
2882
|
-
const html =
|
|
2373
|
+
const html = clamp.ownerDocument(data.elements.floating).documentElement;
|
|
2883
2374
|
return {
|
|
2884
2375
|
...commonCollisionProps,
|
|
2885
2376
|
// Use the Layout Viewport to avoid shifting around when pinch-zooming
|
|
@@ -2983,7 +2474,7 @@ function useAnchorPositioning(params) {
|
|
|
2983
2474
|
return {};
|
|
2984
2475
|
}
|
|
2985
2476
|
}, hide, adaptiveOrigin);
|
|
2986
|
-
|
|
2477
|
+
clamp.useIsoLayoutEffect(() => {
|
|
2987
2478
|
// Ensure positioning doesn't run initially for `keepMounted` elements that
|
|
2988
2479
|
// aren't initially open.
|
|
2989
2480
|
if (!mounted && floatingRootContext) {
|
|
@@ -3041,7 +2532,7 @@ function useAnchorPositioning(params) {
|
|
|
3041
2532
|
return base;
|
|
3042
2533
|
}, [adaptiveOrigin, resolvedPosition, sideX, x, sideY, y, originalFloatingStyles, isPositioned]);
|
|
3043
2534
|
const registeredPositionReferenceRef = React__namespace.useRef(null);
|
|
3044
|
-
|
|
2535
|
+
clamp.useIsoLayoutEffect(() => {
|
|
3045
2536
|
if (!mounted) {
|
|
3046
2537
|
return;
|
|
3047
2538
|
}
|
|
@@ -3086,7 +2577,7 @@ function useAnchorPositioning(params) {
|
|
|
3086
2577
|
* and flips back lazily, not eagerly. Ideal for filtered lists that change
|
|
3087
2578
|
* the size of the popup dynamically to avoid unwanted flipping when typing.
|
|
3088
2579
|
*/
|
|
3089
|
-
|
|
2580
|
+
clamp.useIsoLayoutEffect(() => {
|
|
3090
2581
|
if (lazyFlip && mounted && isPositioned) {
|
|
3091
2582
|
setMountSide(renderedSide);
|
|
3092
2583
|
}
|
|
@@ -3116,149 +2607,693 @@ function isRef(param) {
|
|
|
3116
2607
|
return param != null && 'current' in param;
|
|
3117
2608
|
}
|
|
3118
2609
|
|
|
3119
|
-
|
|
2610
|
+
function getDisabledMountTransitionStyles(transitionStatus) {
|
|
2611
|
+
return transitionStatus === 'starting' ? ScrollAreaViewport.DISABLED_TRANSITIONS_STYLE : useRenderElement.EMPTY_OBJECT;
|
|
2612
|
+
}
|
|
2613
|
+
|
|
2614
|
+
let IndexGuessBehavior = /*#__PURE__*/function (IndexGuessBehavior) {
|
|
2615
|
+
IndexGuessBehavior[IndexGuessBehavior["None"] = 0] = "None";
|
|
2616
|
+
IndexGuessBehavior[IndexGuessBehavior["GuessFromOrder"] = 1] = "GuessFromOrder";
|
|
2617
|
+
return IndexGuessBehavior;
|
|
2618
|
+
}({});
|
|
2619
|
+
|
|
3120
2620
|
/**
|
|
3121
|
-
*
|
|
3122
|
-
* @internal
|
|
2621
|
+
* Used to register a list item and its index (DOM position) in the `CompositeList`.
|
|
3123
2622
|
*/
|
|
3124
|
-
function
|
|
2623
|
+
function useCompositeListItem(params = {}) {
|
|
3125
2624
|
const {
|
|
3126
|
-
|
|
2625
|
+
label,
|
|
2626
|
+
metadata,
|
|
2627
|
+
textRef,
|
|
2628
|
+
indexGuessBehavior,
|
|
2629
|
+
index: externalIndex
|
|
2630
|
+
} = params;
|
|
2631
|
+
const {
|
|
2632
|
+
register,
|
|
2633
|
+
unregister,
|
|
2634
|
+
subscribeMapChange,
|
|
3127
2635
|
elementsRef,
|
|
3128
2636
|
labelsRef,
|
|
3129
|
-
|
|
3130
|
-
} =
|
|
3131
|
-
const
|
|
3132
|
-
const
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
map.delete(node);
|
|
3154
|
-
lastTickRef.current += 1;
|
|
3155
|
-
setMapTick(lastTickRef.current);
|
|
3156
|
-
});
|
|
3157
|
-
const sortedMap = React__namespace.useMemo(() => {
|
|
3158
|
-
const newMap = new Map();
|
|
3159
|
-
// Filter out disconnected elements before sorting to avoid inconsistent
|
|
3160
|
-
// compareDocumentPosition results when elements are detached from the DOM.
|
|
3161
|
-
const sortedNodes = Array.from(map.keys()).filter(node => node.isConnected).sort(sortByDocumentPosition);
|
|
3162
|
-
sortedNodes.forEach((node, index) => {
|
|
3163
|
-
const metadata = map.get(node) ?? {};
|
|
3164
|
-
newMap.set(node, {
|
|
3165
|
-
...metadata,
|
|
3166
|
-
index
|
|
3167
|
-
});
|
|
3168
|
-
});
|
|
3169
|
-
return newMap;
|
|
3170
|
-
}, [map, mapTick]);
|
|
3171
|
-
useValueChanged.useIsoLayoutEffect(() => {
|
|
3172
|
-
if (typeof MutationObserver !== 'function' || sortedMap.size === 0) {
|
|
2637
|
+
nextIndexRef
|
|
2638
|
+
} = useCompositeListContext();
|
|
2639
|
+
const indexRef = React__namespace.useRef(-1);
|
|
2640
|
+
const [index, setIndex] = React__namespace.useState(externalIndex ?? (indexGuessBehavior === IndexGuessBehavior.GuessFromOrder ? () => {
|
|
2641
|
+
if (indexRef.current === -1) {
|
|
2642
|
+
const newIndex = nextIndexRef.current;
|
|
2643
|
+
nextIndexRef.current += 1;
|
|
2644
|
+
indexRef.current = newIndex;
|
|
2645
|
+
}
|
|
2646
|
+
return indexRef.current;
|
|
2647
|
+
} : -1));
|
|
2648
|
+
const componentRef = React__namespace.useRef(null);
|
|
2649
|
+
const ref = React__namespace.useCallback(node => {
|
|
2650
|
+
componentRef.current = node;
|
|
2651
|
+
if (index !== -1 && node !== null) {
|
|
2652
|
+
elementsRef.current[index] = node;
|
|
2653
|
+
if (labelsRef) {
|
|
2654
|
+
const isLabelDefined = label !== undefined;
|
|
2655
|
+
labelsRef.current[index] = isLabelDefined ? label : textRef?.current?.textContent ?? node.textContent;
|
|
2656
|
+
}
|
|
2657
|
+
}
|
|
2658
|
+
}, [index, elementsRef, labelsRef, label, textRef]);
|
|
2659
|
+
clamp.useIsoLayoutEffect(() => {
|
|
2660
|
+
if (externalIndex != null) {
|
|
3173
2661
|
return undefined;
|
|
3174
2662
|
}
|
|
3175
|
-
const
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
2663
|
+
const node = componentRef.current;
|
|
2664
|
+
if (node) {
|
|
2665
|
+
register(node, metadata);
|
|
2666
|
+
return () => {
|
|
2667
|
+
unregister(node);
|
|
2668
|
+
};
|
|
2669
|
+
}
|
|
2670
|
+
return undefined;
|
|
2671
|
+
}, [externalIndex, register, unregister, metadata]);
|
|
2672
|
+
clamp.useIsoLayoutEffect(() => {
|
|
2673
|
+
if (externalIndex != null) {
|
|
2674
|
+
return undefined;
|
|
2675
|
+
}
|
|
2676
|
+
return subscribeMapChange(map => {
|
|
2677
|
+
const i = componentRef.current ? map.get(componentRef.current)?.index : null;
|
|
2678
|
+
if (i != null) {
|
|
2679
|
+
setIndex(i);
|
|
3185
2680
|
}
|
|
3186
2681
|
});
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
2682
|
+
}, [externalIndex, subscribeMapChange, setIndex]);
|
|
2683
|
+
return React__namespace.useMemo(() => ({
|
|
2684
|
+
ref,
|
|
2685
|
+
index
|
|
2686
|
+
}), [index, ref]);
|
|
2687
|
+
}
|
|
2688
|
+
|
|
2689
|
+
/**
|
|
2690
|
+
* A button that closes the dialog.
|
|
2691
|
+
* Renders a `<button>` element.
|
|
2692
|
+
*
|
|
2693
|
+
* Documentation: [Base UI Dialog](https://base-ui.com/react/components/dialog)
|
|
2694
|
+
*/
|
|
2695
|
+
const DialogClose = /*#__PURE__*/React__namespace.forwardRef(function DialogClose(componentProps, forwardedRef) {
|
|
2696
|
+
const {
|
|
2697
|
+
render,
|
|
2698
|
+
className,
|
|
2699
|
+
disabled = false,
|
|
2700
|
+
nativeButton = true,
|
|
2701
|
+
...elementProps
|
|
2702
|
+
} = componentProps;
|
|
2703
|
+
const {
|
|
2704
|
+
store
|
|
2705
|
+
} = ScrollAreaViewport.useDialogRootContext();
|
|
2706
|
+
const open = store.useState('open');
|
|
2707
|
+
function handleClick(event) {
|
|
2708
|
+
if (open) {
|
|
2709
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.closePress, event.nativeEvent));
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
const {
|
|
2713
|
+
getButtonProps,
|
|
2714
|
+
buttonRef
|
|
2715
|
+
} = clamp.useButton({
|
|
2716
|
+
disabled,
|
|
2717
|
+
native: nativeButton
|
|
2718
|
+
});
|
|
2719
|
+
const state = {
|
|
2720
|
+
disabled
|
|
2721
|
+
};
|
|
2722
|
+
return useRenderElement.useRenderElement('button', componentProps, {
|
|
2723
|
+
state,
|
|
2724
|
+
ref: [forwardedRef, buttonRef],
|
|
2725
|
+
props: [{
|
|
2726
|
+
onClick: handleClick
|
|
2727
|
+
}, elementProps, getButtonProps]
|
|
2728
|
+
});
|
|
2729
|
+
});
|
|
2730
|
+
if (process.env.NODE_ENV !== "production") DialogClose.displayName = "DialogClose";
|
|
2731
|
+
|
|
2732
|
+
/**
|
|
2733
|
+
* A button that closes the drawer.
|
|
2734
|
+
* Renders a `<button>` element.
|
|
2735
|
+
*
|
|
2736
|
+
* Documentation: [Base UI Drawer](https://base-ui.com/react/components/drawer)
|
|
2737
|
+
*/
|
|
2738
|
+
const DrawerClose = DialogClose;
|
|
2739
|
+
|
|
2740
|
+
/**
|
|
2741
|
+
* A heading that labels the dialog.
|
|
2742
|
+
* Renders an `<h2>` element.
|
|
2743
|
+
*
|
|
2744
|
+
* Documentation: [Base UI Dialog](https://base-ui.com/react/components/dialog)
|
|
2745
|
+
*/
|
|
2746
|
+
const DialogTitle = /*#__PURE__*/React__namespace.forwardRef(function DialogTitle(componentProps, forwardedRef) {
|
|
2747
|
+
const {
|
|
2748
|
+
render,
|
|
2749
|
+
className,
|
|
2750
|
+
id: idProp,
|
|
2751
|
+
...elementProps
|
|
2752
|
+
} = componentProps;
|
|
2753
|
+
const {
|
|
2754
|
+
store
|
|
2755
|
+
} = ScrollAreaViewport.useDialogRootContext();
|
|
2756
|
+
const id = clamp.useBaseUiId(idProp);
|
|
2757
|
+
store.useSyncedValueWithCleanup('titleElementId', id);
|
|
2758
|
+
return useRenderElement.useRenderElement('h2', componentProps, {
|
|
2759
|
+
ref: forwardedRef,
|
|
2760
|
+
props: [{
|
|
2761
|
+
id
|
|
2762
|
+
}, elementProps]
|
|
2763
|
+
});
|
|
2764
|
+
});
|
|
2765
|
+
if (process.env.NODE_ENV !== "production") DialogTitle.displayName = "DialogTitle";
|
|
2766
|
+
|
|
2767
|
+
/**
|
|
2768
|
+
* A heading that labels the drawer.
|
|
2769
|
+
* Renders an `<h2>` element.
|
|
2770
|
+
*
|
|
2771
|
+
* Documentation: [Base UI Drawer](https://base-ui.com/react/components/drawer)
|
|
2772
|
+
*/
|
|
2773
|
+
const DrawerTitle = DialogTitle;
|
|
2774
|
+
|
|
2775
|
+
const MenuPositionerContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
2776
|
+
if (process.env.NODE_ENV !== "production") MenuPositionerContext.displayName = "MenuPositionerContext";
|
|
2777
|
+
function useMenuPositionerContext(optional) {
|
|
2778
|
+
const context = React__namespace.useContext(MenuPositionerContext);
|
|
2779
|
+
if (context === undefined && !optional) {
|
|
2780
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: MenuPositionerContext is missing. MenuPositioner parts must be placed within <Menu.Positioner>.' : useRenderElement.formatErrorMessage(33));
|
|
2781
|
+
}
|
|
2782
|
+
return context;
|
|
2783
|
+
}
|
|
2784
|
+
|
|
2785
|
+
const MenuRootContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
2786
|
+
if (process.env.NODE_ENV !== "production") MenuRootContext.displayName = "MenuRootContext";
|
|
2787
|
+
function useMenuRootContext(optional) {
|
|
2788
|
+
const context = React__namespace.useContext(MenuRootContext);
|
|
2789
|
+
if (context === undefined && !optional) {
|
|
2790
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: MenuRootContext is missing. Menu parts must be placed within <Menu.Root>.' : useRenderElement.formatErrorMessage(36));
|
|
2791
|
+
}
|
|
2792
|
+
return context;
|
|
2793
|
+
}
|
|
2794
|
+
|
|
2795
|
+
const ContextMenuRootContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
2796
|
+
if (process.env.NODE_ENV !== "production") ContextMenuRootContext.displayName = "ContextMenuRootContext";
|
|
2797
|
+
function useContextMenuRootContext(optional = true) {
|
|
2798
|
+
const context = React__namespace.useContext(ContextMenuRootContext);
|
|
2799
|
+
if (context === undefined && !optional) {
|
|
2800
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: ContextMenuRootContext is missing. ContextMenu parts must be placed within <ContextMenu.Root>.' : useRenderElement.formatErrorMessage(25));
|
|
2801
|
+
}
|
|
2802
|
+
return context;
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2805
|
+
/**
|
|
2806
|
+
* Returns common props shared by all menu item types.
|
|
2807
|
+
* This hook extracts the shared logic for id, role, tabIndex, onKeyDown,
|
|
2808
|
+
* onMouseMove, onClick, and onMouseUp handlers.
|
|
2809
|
+
*/
|
|
2810
|
+
function useMenuItemCommonProps(params) {
|
|
2811
|
+
const {
|
|
2812
|
+
closeOnClick,
|
|
2813
|
+
highlighted,
|
|
2814
|
+
id,
|
|
2815
|
+
nodeId,
|
|
2816
|
+
store,
|
|
2817
|
+
typingRef,
|
|
2818
|
+
itemRef,
|
|
2819
|
+
itemMetadata
|
|
2820
|
+
} = params;
|
|
2821
|
+
const {
|
|
2822
|
+
events: menuEvents
|
|
2823
|
+
} = store.useState('floatingTreeRoot');
|
|
2824
|
+
const contextMenuContext = useContextMenuRootContext(true);
|
|
2825
|
+
const isContextMenu = contextMenuContext !== undefined;
|
|
2826
|
+
return React__namespace.useMemo(() => ({
|
|
2827
|
+
id,
|
|
2828
|
+
role: 'menuitem',
|
|
2829
|
+
tabIndex: highlighted ? 0 : -1,
|
|
2830
|
+
onKeyDown(event) {
|
|
2831
|
+
if (event.key === ' ' && typingRef?.current) {
|
|
2832
|
+
event.preventDefault();
|
|
2833
|
+
}
|
|
2834
|
+
},
|
|
2835
|
+
onMouseMove(event) {
|
|
2836
|
+
if (!nodeId) {
|
|
2837
|
+
return;
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2840
|
+
// Inform the floating tree that a menu item within this menu was hovered/moved over
|
|
2841
|
+
// so unrelated descendant submenus can be closed.
|
|
2842
|
+
menuEvents.emit('itemhover', {
|
|
2843
|
+
nodeId,
|
|
2844
|
+
target: event.currentTarget
|
|
2845
|
+
});
|
|
2846
|
+
},
|
|
2847
|
+
onClick(event) {
|
|
2848
|
+
if (closeOnClick) {
|
|
2849
|
+
menuEvents.emit('close', {
|
|
2850
|
+
domEvent: event,
|
|
2851
|
+
reason: clamp.itemPress
|
|
3191
2852
|
});
|
|
3192
2853
|
}
|
|
3193
|
-
}
|
|
2854
|
+
},
|
|
2855
|
+
onMouseUp(event) {
|
|
2856
|
+
if (contextMenuContext) {
|
|
2857
|
+
const initialCursorPoint = contextMenuContext.initialCursorPointRef.current;
|
|
2858
|
+
contextMenuContext.initialCursorPointRef.current = null;
|
|
2859
|
+
if (isContextMenu && initialCursorPoint && Math.abs(event.clientX - initialCursorPoint.x) <= 1 && Math.abs(event.clientY - initialCursorPoint.y) <= 1) {
|
|
2860
|
+
return;
|
|
2861
|
+
}
|
|
2862
|
+
|
|
2863
|
+
// On non-macOS platforms, this mouseup belongs to the right-click gesture
|
|
2864
|
+
// that opened the context menu, so it must not activate an item.
|
|
2865
|
+
if (isContextMenu && !clamp.isMac && event.button === 2) {
|
|
2866
|
+
return;
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
if (itemRef.current && store.context.allowMouseUpTriggerRef.current && (!isContextMenu || event.button === 2)) {
|
|
2870
|
+
// This fires whenever the user clicks on the trigger, moves the cursor, and releases it over the item.
|
|
2871
|
+
// We trigger the click and override the `closeOnClick` preference to always close the menu.
|
|
2872
|
+
if (!itemMetadata || itemMetadata.type === 'regular-item') {
|
|
2873
|
+
itemRef.current.click();
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
}), [closeOnClick, highlighted, id, menuEvents, nodeId, store, typingRef, itemRef, contextMenuContext, isContextMenu, itemMetadata]);
|
|
2878
|
+
}
|
|
2879
|
+
|
|
2880
|
+
const REGULAR_ITEM = {
|
|
2881
|
+
type: 'regular-item'
|
|
2882
|
+
};
|
|
2883
|
+
function useMenuItem(params) {
|
|
2884
|
+
const {
|
|
2885
|
+
closeOnClick,
|
|
2886
|
+
disabled = false,
|
|
2887
|
+
highlighted,
|
|
2888
|
+
id,
|
|
2889
|
+
store,
|
|
2890
|
+
typingRef = store.context.typingRef,
|
|
2891
|
+
nativeButton,
|
|
2892
|
+
itemMetadata,
|
|
2893
|
+
nodeId
|
|
2894
|
+
} = params;
|
|
2895
|
+
const itemRef = React__namespace.useRef(null);
|
|
2896
|
+
const {
|
|
2897
|
+
getButtonProps,
|
|
2898
|
+
buttonRef
|
|
2899
|
+
} = clamp.useButton({
|
|
2900
|
+
disabled,
|
|
2901
|
+
focusableWhenDisabled: true,
|
|
2902
|
+
native: nativeButton,
|
|
2903
|
+
composite: true
|
|
2904
|
+
});
|
|
2905
|
+
const commonProps = useMenuItemCommonProps({
|
|
2906
|
+
closeOnClick,
|
|
2907
|
+
highlighted,
|
|
2908
|
+
id,
|
|
2909
|
+
nodeId,
|
|
2910
|
+
store,
|
|
2911
|
+
typingRef,
|
|
2912
|
+
itemRef,
|
|
2913
|
+
itemMetadata
|
|
2914
|
+
});
|
|
2915
|
+
const getItemProps = React__namespace.useCallback(externalProps => {
|
|
2916
|
+
return useRenderElement.mergeProps(commonProps, {
|
|
2917
|
+
onMouseEnter() {
|
|
2918
|
+
if (itemMetadata.type !== 'submenu-trigger') {
|
|
2919
|
+
return;
|
|
2920
|
+
}
|
|
2921
|
+
itemMetadata.setActive();
|
|
2922
|
+
}
|
|
2923
|
+
}, externalProps, getButtonProps);
|
|
2924
|
+
}, [commonProps, getButtonProps, itemMetadata]);
|
|
2925
|
+
const mergedRef = useRenderElement.useMergedRefs(itemRef, buttonRef);
|
|
2926
|
+
return React__namespace.useMemo(() => ({
|
|
2927
|
+
getItemProps,
|
|
2928
|
+
itemRef: mergedRef
|
|
2929
|
+
}), [getItemProps, mergedRef]);
|
|
2930
|
+
}
|
|
2931
|
+
|
|
2932
|
+
let MenuCheckboxItemDataAttributes = /*#__PURE__*/function (MenuCheckboxItemDataAttributes) {
|
|
2933
|
+
/**
|
|
2934
|
+
* Present when the menu checkbox item is checked.
|
|
2935
|
+
*/
|
|
2936
|
+
MenuCheckboxItemDataAttributes["checked"] = "data-checked";
|
|
2937
|
+
/**
|
|
2938
|
+
* Present when the menu checkbox item is not checked.
|
|
2939
|
+
*/
|
|
2940
|
+
MenuCheckboxItemDataAttributes["unchecked"] = "data-unchecked";
|
|
2941
|
+
/**
|
|
2942
|
+
* Present when the menu checkbox item is disabled.
|
|
2943
|
+
*/
|
|
2944
|
+
MenuCheckboxItemDataAttributes["disabled"] = "data-disabled";
|
|
2945
|
+
/**
|
|
2946
|
+
* Present when the menu checkbox item is highlighted.
|
|
2947
|
+
*/
|
|
2948
|
+
MenuCheckboxItemDataAttributes["highlighted"] = "data-highlighted";
|
|
2949
|
+
return MenuCheckboxItemDataAttributes;
|
|
2950
|
+
}({});
|
|
2951
|
+
|
|
2952
|
+
const itemMapping = {
|
|
2953
|
+
checked(value) {
|
|
2954
|
+
if (value) {
|
|
2955
|
+
return {
|
|
2956
|
+
[MenuCheckboxItemDataAttributes.checked]: ''
|
|
2957
|
+
};
|
|
2958
|
+
}
|
|
2959
|
+
return {
|
|
2960
|
+
[MenuCheckboxItemDataAttributes.unchecked]: ''
|
|
2961
|
+
};
|
|
2962
|
+
},
|
|
2963
|
+
...clamp.transitionStatusMapping
|
|
2964
|
+
};
|
|
2965
|
+
|
|
2966
|
+
const MenuGroupContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
2967
|
+
if (process.env.NODE_ENV !== "production") MenuGroupContext.displayName = "MenuGroupContext";
|
|
2968
|
+
function useMenuGroupRootContext() {
|
|
2969
|
+
const context = React__namespace.useContext(MenuGroupContext);
|
|
2970
|
+
if (context === undefined) {
|
|
2971
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: MenuGroupRootContext is missing. Menu group parts must be used within <Menu.Group>.' : useRenderElement.formatErrorMessage(31));
|
|
2972
|
+
}
|
|
2973
|
+
return context;
|
|
2974
|
+
}
|
|
2975
|
+
|
|
2976
|
+
const MenuGroup = /*#__PURE__*/React__namespace.forwardRef(function MenuGroup(componentProps, forwardedRef) {
|
|
2977
|
+
const {
|
|
2978
|
+
render,
|
|
2979
|
+
className,
|
|
2980
|
+
...elementProps
|
|
2981
|
+
} = componentProps;
|
|
2982
|
+
const [labelId, setLabelId] = React__namespace.useState(undefined);
|
|
2983
|
+
const context = React__namespace.useMemo(() => ({
|
|
2984
|
+
setLabelId
|
|
2985
|
+
}), [setLabelId]);
|
|
2986
|
+
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
2987
|
+
ref: forwardedRef,
|
|
2988
|
+
props: {
|
|
2989
|
+
role: 'group',
|
|
2990
|
+
'aria-labelledby': labelId,
|
|
2991
|
+
...elementProps
|
|
2992
|
+
}
|
|
2993
|
+
});
|
|
2994
|
+
return /*#__PURE__*/jsxRuntime.jsx(MenuGroupContext.Provider, {
|
|
2995
|
+
value: context,
|
|
2996
|
+
children: element
|
|
2997
|
+
});
|
|
2998
|
+
});
|
|
2999
|
+
if (process.env.NODE_ENV !== "production") MenuGroup.displayName = "MenuGroup";
|
|
3000
|
+
|
|
3001
|
+
/**
|
|
3002
|
+
* An accessible label that is automatically associated with its parent group.
|
|
3003
|
+
* Renders a `<div>` element.
|
|
3004
|
+
*
|
|
3005
|
+
* Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
|
|
3006
|
+
*/
|
|
3007
|
+
const MenuGroupLabel = /*#__PURE__*/React__namespace.forwardRef(function MenuGroupLabelComponent(componentProps, forwardedRef) {
|
|
3008
|
+
const {
|
|
3009
|
+
className,
|
|
3010
|
+
render,
|
|
3011
|
+
id: idProp,
|
|
3012
|
+
...elementProps
|
|
3013
|
+
} = componentProps;
|
|
3014
|
+
const id = clamp.useBaseUiId(idProp);
|
|
3015
|
+
const {
|
|
3016
|
+
setLabelId
|
|
3017
|
+
} = useMenuGroupRootContext();
|
|
3018
|
+
clamp.useIsoLayoutEffect(() => {
|
|
3019
|
+
setLabelId(id);
|
|
3194
3020
|
return () => {
|
|
3195
|
-
|
|
3021
|
+
setLabelId(undefined);
|
|
3196
3022
|
};
|
|
3197
|
-
}, [
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3023
|
+
}, [setLabelId, id]);
|
|
3024
|
+
return useRenderElement.useRenderElement('div', componentProps, {
|
|
3025
|
+
ref: forwardedRef,
|
|
3026
|
+
props: {
|
|
3027
|
+
id,
|
|
3028
|
+
role: 'presentation',
|
|
3029
|
+
...elementProps
|
|
3030
|
+
}
|
|
3031
|
+
});
|
|
3032
|
+
});
|
|
3033
|
+
if (process.env.NODE_ENV !== "production") MenuGroupLabel.displayName = "MenuGroupLabel";
|
|
3034
|
+
|
|
3035
|
+
/**
|
|
3036
|
+
* An individual interactive item in the menu.
|
|
3037
|
+
* Renders a `<div>` element.
|
|
3038
|
+
*
|
|
3039
|
+
* Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
|
|
3040
|
+
*/
|
|
3041
|
+
const MenuItem = /*#__PURE__*/React__namespace.forwardRef(function MenuItem(componentProps, forwardedRef) {
|
|
3042
|
+
const {
|
|
3043
|
+
render,
|
|
3044
|
+
className,
|
|
3045
|
+
id: idProp,
|
|
3046
|
+
label,
|
|
3047
|
+
nativeButton = false,
|
|
3048
|
+
disabled = false,
|
|
3049
|
+
closeOnClick = true,
|
|
3050
|
+
...elementProps
|
|
3051
|
+
} = componentProps;
|
|
3052
|
+
const listItem = useCompositeListItem({
|
|
3053
|
+
label
|
|
3054
|
+
});
|
|
3055
|
+
const menuPositionerContext = useMenuPositionerContext(true);
|
|
3056
|
+
const id = clamp.useBaseUiId(idProp);
|
|
3057
|
+
const {
|
|
3058
|
+
store
|
|
3059
|
+
} = useMenuRootContext();
|
|
3060
|
+
const highlighted = store.useState('isActive', listItem.index);
|
|
3061
|
+
const itemProps = store.useState('itemProps');
|
|
3062
|
+
const {
|
|
3063
|
+
getItemProps,
|
|
3064
|
+
itemRef
|
|
3065
|
+
} = useMenuItem({
|
|
3066
|
+
closeOnClick,
|
|
3067
|
+
disabled,
|
|
3068
|
+
highlighted,
|
|
3069
|
+
id,
|
|
3070
|
+
store,
|
|
3071
|
+
nativeButton,
|
|
3072
|
+
nodeId: menuPositionerContext?.nodeId,
|
|
3073
|
+
itemMetadata: REGULAR_ITEM
|
|
3074
|
+
});
|
|
3075
|
+
const state = {
|
|
3076
|
+
disabled,
|
|
3077
|
+
highlighted
|
|
3078
|
+
};
|
|
3079
|
+
return useRenderElement.useRenderElement('div', componentProps, {
|
|
3080
|
+
state,
|
|
3081
|
+
props: [itemProps, elementProps, getItemProps],
|
|
3082
|
+
ref: [itemRef, forwardedRef, listItem.ref]
|
|
3083
|
+
});
|
|
3084
|
+
});
|
|
3085
|
+
if (process.env.NODE_ENV !== "production") MenuItem.displayName = "MenuItem";
|
|
3086
|
+
|
|
3087
|
+
/**
|
|
3088
|
+
* A link in the menu that can be used to navigate to a different page or section.
|
|
3089
|
+
* Renders an `<a>` element.
|
|
3090
|
+
*
|
|
3091
|
+
* Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
|
|
3092
|
+
*/
|
|
3093
|
+
const MenuLinkItem = /*#__PURE__*/React__namespace.forwardRef(function MenuLinkItem(componentProps, forwardedRef) {
|
|
3094
|
+
const {
|
|
3095
|
+
render,
|
|
3096
|
+
className,
|
|
3097
|
+
id: idProp,
|
|
3098
|
+
label,
|
|
3099
|
+
closeOnClick = false,
|
|
3100
|
+
...elementProps
|
|
3101
|
+
} = componentProps;
|
|
3102
|
+
const linkRef = React__namespace.useRef(null);
|
|
3103
|
+
const listItem = useCompositeListItem({
|
|
3104
|
+
label
|
|
3105
|
+
});
|
|
3106
|
+
const menuPositionerContext = useMenuPositionerContext(true);
|
|
3107
|
+
const nodeId = menuPositionerContext?.nodeId;
|
|
3108
|
+
const id = clamp.useBaseUiId(idProp);
|
|
3109
|
+
const {
|
|
3110
|
+
store
|
|
3111
|
+
} = useMenuRootContext();
|
|
3112
|
+
const highlighted = store.useState('isActive', listItem.index);
|
|
3113
|
+
const itemProps = store.useState('itemProps');
|
|
3114
|
+
const typingRef = store.context.typingRef;
|
|
3115
|
+
const {
|
|
3116
|
+
getButtonProps,
|
|
3117
|
+
buttonRef
|
|
3118
|
+
} = clamp.useButton({
|
|
3119
|
+
native: false,
|
|
3120
|
+
composite: true
|
|
3121
|
+
});
|
|
3122
|
+
const commonProps = useMenuItemCommonProps({
|
|
3123
|
+
closeOnClick,
|
|
3124
|
+
highlighted,
|
|
3125
|
+
id,
|
|
3126
|
+
nodeId,
|
|
3127
|
+
store,
|
|
3128
|
+
typingRef,
|
|
3129
|
+
itemRef: linkRef
|
|
3130
|
+
});
|
|
3131
|
+
function getItemProps(externalProps) {
|
|
3132
|
+
return useRenderElement.mergeProps(commonProps, externalProps, getButtonProps);
|
|
3133
|
+
}
|
|
3134
|
+
const state = React__namespace.useMemo(() => ({
|
|
3135
|
+
highlighted
|
|
3136
|
+
}), [highlighted]);
|
|
3137
|
+
return useRenderElement.useRenderElement('a', componentProps, {
|
|
3138
|
+
state,
|
|
3139
|
+
props: [itemProps, elementProps, getItemProps],
|
|
3140
|
+
ref: [linkRef, buttonRef, forwardedRef, listItem.ref]
|
|
3141
|
+
});
|
|
3142
|
+
});
|
|
3143
|
+
if (process.env.NODE_ENV !== "production") MenuLinkItem.displayName = "MenuLinkItem";
|
|
3144
|
+
|
|
3145
|
+
const ToolbarRootContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
3146
|
+
if (process.env.NODE_ENV !== "production") ToolbarRootContext.displayName = "ToolbarRootContext";
|
|
3147
|
+
function useToolbarRootContext(optional) {
|
|
3148
|
+
const context = React__namespace.useContext(ToolbarRootContext);
|
|
3149
|
+
if (context === undefined && !optional) {
|
|
3150
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: ToolbarRootContext is missing. Toolbar parts must be placed within <Toolbar.Root>.' : useRenderElement.formatErrorMessage(69));
|
|
3151
|
+
}
|
|
3152
|
+
return context;
|
|
3153
|
+
}
|
|
3154
|
+
|
|
3155
|
+
const stateAttributesMapping = {
|
|
3156
|
+
...ScrollAreaViewport.popupStateMapping,
|
|
3157
|
+
...clamp.transitionStatusMapping
|
|
3158
|
+
};
|
|
3159
|
+
|
|
3160
|
+
/**
|
|
3161
|
+
* A container for the menu items.
|
|
3162
|
+
* Renders a `<div>` element.
|
|
3163
|
+
*
|
|
3164
|
+
* Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
|
|
3165
|
+
*/
|
|
3166
|
+
const MenuPopup = /*#__PURE__*/React__namespace.forwardRef(function MenuPopup(componentProps, forwardedRef) {
|
|
3167
|
+
const {
|
|
3168
|
+
render,
|
|
3169
|
+
className,
|
|
3170
|
+
finalFocus,
|
|
3171
|
+
...elementProps
|
|
3172
|
+
} = componentProps;
|
|
3173
|
+
const {
|
|
3174
|
+
store
|
|
3175
|
+
} = useMenuRootContext();
|
|
3176
|
+
const {
|
|
3177
|
+
side,
|
|
3178
|
+
align
|
|
3179
|
+
} = useMenuPositionerContext();
|
|
3180
|
+
const insideToolbar = useToolbarRootContext(true) != null;
|
|
3181
|
+
const open = store.useState('open');
|
|
3182
|
+
const transitionStatus = store.useState('transitionStatus');
|
|
3183
|
+
const popupProps = store.useState('popupProps');
|
|
3184
|
+
const mounted = store.useState('mounted');
|
|
3185
|
+
const instantType = store.useState('instantType');
|
|
3186
|
+
const triggerElement = store.useState('activeTriggerElement');
|
|
3187
|
+
const parent = store.useState('parent');
|
|
3188
|
+
const lastOpenChangeReason = store.useState('lastOpenChangeReason');
|
|
3189
|
+
const rootId = store.useState('rootId');
|
|
3190
|
+
const floatingContext = store.useState('floatingRootContext');
|
|
3191
|
+
const floatingTreeRoot = store.useState('floatingTreeRoot');
|
|
3192
|
+
const closeDelay = store.useState('closeDelay');
|
|
3193
|
+
const activeTriggerElement = store.useState('activeTriggerElement');
|
|
3194
|
+
const isContextMenu = parent.type === 'context-menu';
|
|
3195
|
+
clamp.useOpenChangeComplete({
|
|
3196
|
+
open,
|
|
3197
|
+
ref: store.context.popupRef,
|
|
3198
|
+
onComplete() {
|
|
3199
|
+
if (open) {
|
|
3200
|
+
store.context.onOpenChangeComplete?.(true);
|
|
3206
3201
|
}
|
|
3207
|
-
nextIndexRef.current = sortedMap.size;
|
|
3208
3202
|
}
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
}, [elementsRef]);
|
|
3216
|
-
useValueChanged.useIsoLayoutEffect(() => {
|
|
3217
|
-
return () => {
|
|
3218
|
-
if (labelsRef) {
|
|
3219
|
-
labelsRef.current = [];
|
|
3220
|
-
}
|
|
3221
|
-
};
|
|
3222
|
-
}, [labelsRef]);
|
|
3223
|
-
const subscribeMapChange = useValueChanged.useStableCallback(fn => {
|
|
3224
|
-
listeners.add(fn);
|
|
3203
|
+
});
|
|
3204
|
+
React__namespace.useEffect(() => {
|
|
3205
|
+
function handleClose(event) {
|
|
3206
|
+
store.setOpen(false, clamp.createChangeEventDetails(event.reason, event.domEvent));
|
|
3207
|
+
}
|
|
3208
|
+
floatingTreeRoot.events.on('close', handleClose);
|
|
3225
3209
|
return () => {
|
|
3226
|
-
|
|
3210
|
+
floatingTreeRoot.events.off('close', handleClose);
|
|
3227
3211
|
};
|
|
3212
|
+
}, [floatingTreeRoot.events, store]);
|
|
3213
|
+
const hoverEnabled = store.useState('hoverEnabled');
|
|
3214
|
+
const disabled = store.useState('disabled');
|
|
3215
|
+
useHoverFloatingInteraction(floatingContext, {
|
|
3216
|
+
enabled: hoverEnabled && !disabled && !isContextMenu && parent.type !== 'menubar',
|
|
3217
|
+
closeDelay
|
|
3228
3218
|
});
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
}
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3219
|
+
const state = {
|
|
3220
|
+
transitionStatus,
|
|
3221
|
+
side,
|
|
3222
|
+
align,
|
|
3223
|
+
open,
|
|
3224
|
+
nested: parent.type === 'menu',
|
|
3225
|
+
instant: instantType
|
|
3226
|
+
};
|
|
3227
|
+
const setPopupElement = React__namespace.useCallback(element => {
|
|
3228
|
+
store.set('popupElement', element);
|
|
3229
|
+
}, [store]);
|
|
3230
|
+
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
3231
|
+
state,
|
|
3232
|
+
ref: [forwardedRef, store.context.popupRef, setPopupElement],
|
|
3233
|
+
stateAttributesMapping,
|
|
3234
|
+
props: [popupProps, {
|
|
3235
|
+
onKeyDown(event) {
|
|
3236
|
+
if (insideToolbar && ScrollAreaViewport.COMPOSITE_KEYS.has(event.key)) {
|
|
3237
|
+
event.stopPropagation();
|
|
3238
|
+
}
|
|
3239
|
+
}
|
|
3240
|
+
}, getDisabledMountTransitionStyles(transitionStatus), elementProps, {
|
|
3241
|
+
'data-rootownerid': rootId
|
|
3242
|
+
}]
|
|
3243
3243
|
});
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
}
|
|
3248
|
-
function createListeners() {
|
|
3249
|
-
return new Set();
|
|
3250
|
-
}
|
|
3251
|
-
function sortByDocumentPosition(a, b) {
|
|
3252
|
-
const position = a.compareDocumentPosition(b);
|
|
3253
|
-
if (position & Node.DOCUMENT_POSITION_FOLLOWING || position & Node.DOCUMENT_POSITION_CONTAINED_BY) {
|
|
3254
|
-
return -1;
|
|
3244
|
+
let returnFocus = parent.type === undefined || isContextMenu;
|
|
3245
|
+
if (triggerElement || parent.type === 'menubar' && lastOpenChangeReason !== clamp.outsidePress) {
|
|
3246
|
+
returnFocus = true;
|
|
3255
3247
|
}
|
|
3256
|
-
|
|
3257
|
-
|
|
3248
|
+
return /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.FloatingFocusManager, {
|
|
3249
|
+
context: floatingContext,
|
|
3250
|
+
modal: isContextMenu,
|
|
3251
|
+
disabled: !mounted,
|
|
3252
|
+
returnFocus: finalFocus === undefined ? returnFocus : finalFocus,
|
|
3253
|
+
initialFocus: parent.type !== 'menu',
|
|
3254
|
+
restoreFocus: true,
|
|
3255
|
+
externalTree: parent.type !== 'menubar' ? floatingTreeRoot : undefined,
|
|
3256
|
+
previousFocusableElement: activeTriggerElement,
|
|
3257
|
+
nextFocusableElement: parent.type === undefined ? store.context.triggerFocusTargetRef : undefined,
|
|
3258
|
+
beforeContentFocusGuardRef: parent.type === undefined ? store.context.beforeContentFocusGuardRef : undefined,
|
|
3259
|
+
children: element
|
|
3260
|
+
});
|
|
3261
|
+
});
|
|
3262
|
+
if (process.env.NODE_ENV !== "production") MenuPopup.displayName = "MenuPopup";
|
|
3263
|
+
|
|
3264
|
+
const MenuPortalContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
3265
|
+
if (process.env.NODE_ENV !== "production") MenuPortalContext.displayName = "MenuPortalContext";
|
|
3266
|
+
function useMenuPortalContext() {
|
|
3267
|
+
const value = React__namespace.useContext(MenuPortalContext);
|
|
3268
|
+
if (value === undefined) {
|
|
3269
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: <Menu.Portal> is missing.' : useRenderElement.formatErrorMessage(32));
|
|
3258
3270
|
}
|
|
3259
|
-
return
|
|
3271
|
+
return value;
|
|
3260
3272
|
}
|
|
3261
3273
|
|
|
3274
|
+
const MenuPortal = /*#__PURE__*/React__namespace.forwardRef(function MenuPortal(props, forwardedRef) {
|
|
3275
|
+
const {
|
|
3276
|
+
keepMounted = false,
|
|
3277
|
+
...portalProps
|
|
3278
|
+
} = props;
|
|
3279
|
+
const {
|
|
3280
|
+
store
|
|
3281
|
+
} = useMenuRootContext();
|
|
3282
|
+
const mounted = store.useState('mounted');
|
|
3283
|
+
const shouldRender = mounted || keepMounted;
|
|
3284
|
+
if (!shouldRender) {
|
|
3285
|
+
return null;
|
|
3286
|
+
}
|
|
3287
|
+
return /*#__PURE__*/jsxRuntime.jsx(MenuPortalContext.Provider, {
|
|
3288
|
+
value: keepMounted,
|
|
3289
|
+
children: /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.FloatingPortal, {
|
|
3290
|
+
ref: forwardedRef,
|
|
3291
|
+
...portalProps
|
|
3292
|
+
})
|
|
3293
|
+
});
|
|
3294
|
+
});
|
|
3295
|
+
if (process.env.NODE_ENV !== "production") MenuPortal.displayName = "MenuPortal";
|
|
3296
|
+
|
|
3262
3297
|
const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPositioner(componentProps, forwardedRef) {
|
|
3263
3298
|
const {
|
|
3264
3299
|
anchor: anchorProp,
|
|
@@ -3298,7 +3333,7 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
|
|
|
3298
3333
|
const floatingParentNodeId = store.useState('floatingParentNodeId');
|
|
3299
3334
|
const domReference = floatingRootContext.useState('domReferenceElement');
|
|
3300
3335
|
const previousTriggerRef = React__namespace.useRef(null);
|
|
3301
|
-
const runOnceAnimationsFinish =
|
|
3336
|
+
const runOnceAnimationsFinish = clamp.useAnimationsFinished(positionerElement, false, false);
|
|
3302
3337
|
let anchor = anchorProp;
|
|
3303
3338
|
let sideOffset = sideOffsetProp;
|
|
3304
3339
|
let alignOffset = alignOffsetProp;
|
|
@@ -3365,7 +3400,7 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
|
|
|
3365
3400
|
store.set('hoverEnabled', false);
|
|
3366
3401
|
}
|
|
3367
3402
|
if (details.nodeId !== floatingNodeId && details.parentNodeId === store.select('floatingParentNodeId')) {
|
|
3368
|
-
store.setOpen(false,
|
|
3403
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.siblingOpen));
|
|
3369
3404
|
}
|
|
3370
3405
|
}
|
|
3371
3406
|
}
|
|
@@ -3382,15 +3417,15 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
|
|
|
3382
3417
|
if (details.open || details.nodeId !== store.select('floatingParentNodeId')) {
|
|
3383
3418
|
return;
|
|
3384
3419
|
}
|
|
3385
|
-
const reason = details.reason ??
|
|
3386
|
-
store.setOpen(false,
|
|
3420
|
+
const reason = details.reason ?? clamp.siblingOpen;
|
|
3421
|
+
store.setOpen(false, clamp.createChangeEventDetails(reason));
|
|
3387
3422
|
}
|
|
3388
3423
|
floatingTreeRoot.events.on('menuopenchange', onParentClose);
|
|
3389
3424
|
return () => {
|
|
3390
3425
|
floatingTreeRoot.events.off('menuopenchange', onParentClose);
|
|
3391
3426
|
};
|
|
3392
3427
|
}, [floatingTreeRoot.events, store]);
|
|
3393
|
-
const closeTimeout =
|
|
3428
|
+
const closeTimeout = clamp.useTimeout();
|
|
3394
3429
|
|
|
3395
3430
|
// Clear pending close timeout when the menu closes.
|
|
3396
3431
|
React__namespace.useEffect(() => {
|
|
@@ -3412,11 +3447,11 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
|
|
|
3412
3447
|
if (delay > 0) {
|
|
3413
3448
|
if (!closeTimeout.isStarted()) {
|
|
3414
3449
|
closeTimeout.start(delay, () => {
|
|
3415
|
-
store.setOpen(false,
|
|
3450
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.siblingOpen));
|
|
3416
3451
|
});
|
|
3417
3452
|
}
|
|
3418
3453
|
} else {
|
|
3419
|
-
store.setOpen(false,
|
|
3454
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.siblingOpen));
|
|
3420
3455
|
}
|
|
3421
3456
|
} else {
|
|
3422
3457
|
// User re-hovered the submenu trigger, cancel pending close.
|
|
@@ -3439,7 +3474,7 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
|
|
|
3439
3474
|
}, [floatingTreeRoot.events, open, store, floatingNodeId, floatingParentNodeId]);
|
|
3440
3475
|
|
|
3441
3476
|
// Keep positioner transition behavior aligned with Popover when switching detached triggers.
|
|
3442
|
-
|
|
3477
|
+
clamp.useIsoLayoutEffect(() => {
|
|
3443
3478
|
const currentTrigger = domReference;
|
|
3444
3479
|
const previousTrigger = previousTriggerRef.current;
|
|
3445
3480
|
if (currentTrigger) {
|
|
@@ -3479,7 +3514,7 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
|
|
|
3479
3514
|
ref: [forwardedRef, store.useStateSetter('positionerElement')],
|
|
3480
3515
|
props: [positionerProps, getDisabledMountTransitionStyles(transitionStatus), elementProps]
|
|
3481
3516
|
});
|
|
3482
|
-
const shouldRenderBackdrop = mounted && parent.type !== 'menu' && (parent.type !== 'menubar' && modal && lastOpenChangeReason !==
|
|
3517
|
+
const shouldRenderBackdrop = mounted && parent.type !== 'menu' && (parent.type !== 'menubar' && modal && lastOpenChangeReason !== clamp.triggerHover || parent.type === 'menubar' && parent.context.modal);
|
|
3483
3518
|
|
|
3484
3519
|
// cuts a hole in the backdrop to allow pointer interaction with the menubar or dropdown menu trigger element
|
|
3485
3520
|
let backdropCutout = null;
|
|
@@ -3532,13 +3567,13 @@ const MenuRadioGroup = /*#__PURE__*/React__namespace.memo(/*#__PURE__*/React__na
|
|
|
3532
3567
|
disabled = false,
|
|
3533
3568
|
...elementProps
|
|
3534
3569
|
} = componentProps;
|
|
3535
|
-
const [value, setValueUnwrapped] =
|
|
3570
|
+
const [value, setValueUnwrapped] = clamp.useControlled({
|
|
3536
3571
|
controlled: valueProp,
|
|
3537
3572
|
default: defaultValue,
|
|
3538
3573
|
name: 'MenuRadioGroup'
|
|
3539
3574
|
});
|
|
3540
|
-
const onValueChange =
|
|
3541
|
-
const setValue =
|
|
3575
|
+
const onValueChange = clamp.useStableCallback(onValueChangeProp);
|
|
3576
|
+
const setValue = clamp.useStableCallback((newValue, eventDetails) => {
|
|
3542
3577
|
onValueChange?.(newValue, eventDetails);
|
|
3543
3578
|
if (eventDetails.isCanceled) {
|
|
3544
3579
|
return;
|
|
@@ -3595,7 +3630,7 @@ const MenuRadioItem = /*#__PURE__*/React__namespace.forwardRef(function MenuRadi
|
|
|
3595
3630
|
label
|
|
3596
3631
|
});
|
|
3597
3632
|
const menuPositionerContext = useMenuPositionerContext(true);
|
|
3598
|
-
const id =
|
|
3633
|
+
const id = clamp.useBaseUiId(idProp);
|
|
3599
3634
|
const {
|
|
3600
3635
|
store
|
|
3601
3636
|
} = useMenuRootContext();
|
|
@@ -3626,9 +3661,9 @@ const MenuRadioItem = /*#__PURE__*/React__namespace.forwardRef(function MenuRadi
|
|
|
3626
3661
|
highlighted,
|
|
3627
3662
|
checked
|
|
3628
3663
|
}), [disabled, highlighted, checked]);
|
|
3629
|
-
const handleClick =
|
|
3664
|
+
const handleClick = clamp.useStableCallback(event => {
|
|
3630
3665
|
const details = {
|
|
3631
|
-
...
|
|
3666
|
+
...clamp.createChangeEventDetails(clamp.itemPress, event.nativeEvent),
|
|
3632
3667
|
preventUnmountOnClose: () => {}
|
|
3633
3668
|
};
|
|
3634
3669
|
setSelectedValue(value, details);
|
|
@@ -3668,8 +3703,8 @@ const MenuRadioItemIndicator = /*#__PURE__*/React__namespace.forwardRef(function
|
|
|
3668
3703
|
const {
|
|
3669
3704
|
transitionStatus,
|
|
3670
3705
|
setMounted
|
|
3671
|
-
} =
|
|
3672
|
-
|
|
3706
|
+
} = clamp.useTransitionStatus(item.checked);
|
|
3707
|
+
clamp.useOpenChangeComplete({
|
|
3673
3708
|
open: item.checked,
|
|
3674
3709
|
ref: indicatorRef,
|
|
3675
3710
|
onComplete() {
|
|
@@ -3919,7 +3954,7 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
|
|
|
3919
3954
|
const floatingTreeRoot = store.useState('floatingTreeRoot');
|
|
3920
3955
|
const floatingNodeIdFromContext = ScrollAreaViewport.useFloatingNodeId(floatingTreeRoot);
|
|
3921
3956
|
const floatingParentNodeIdFromContext = ScrollAreaViewport.useFloatingParentNodeId();
|
|
3922
|
-
|
|
3957
|
+
clamp.useIsoLayoutEffect(() => {
|
|
3923
3958
|
if (contextMenuContext && !parentMenuRootContext) {
|
|
3924
3959
|
// This is a context menu root.
|
|
3925
3960
|
// It doesn't support detached triggers yet, so we have to sync the parent context manually.
|
|
@@ -3960,7 +3995,7 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
|
|
|
3960
3995
|
store.useSyncedValues({
|
|
3961
3996
|
disabled: disabledProp,
|
|
3962
3997
|
modal: parent.type === undefined ? modalProp : undefined,
|
|
3963
|
-
rootId:
|
|
3998
|
+
rootId: clamp.useId()
|
|
3964
3999
|
});
|
|
3965
4000
|
const {
|
|
3966
4001
|
openMethod,
|
|
@@ -3976,7 +4011,7 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
|
|
|
3976
4011
|
});
|
|
3977
4012
|
});
|
|
3978
4013
|
const allowOutsidePressDismissalRef = React__namespace.useRef(parent.type !== 'context-menu');
|
|
3979
|
-
const allowOutsidePressDismissalTimeout =
|
|
4014
|
+
const allowOutsidePressDismissalTimeout = clamp.useTimeout();
|
|
3980
4015
|
React__namespace.useEffect(() => {
|
|
3981
4016
|
if (!open) {
|
|
3982
4017
|
openEventRef.current = null;
|
|
@@ -3997,15 +4032,15 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
|
|
|
3997
4032
|
allowOutsidePressDismissalRef.current = true;
|
|
3998
4033
|
});
|
|
3999
4034
|
}, [allowOutsidePressDismissalTimeout, open, parent.type]);
|
|
4000
|
-
ScrollAreaViewport.useScrollLock(open && modal && lastOpenChangeReason !==
|
|
4001
|
-
|
|
4035
|
+
ScrollAreaViewport.useScrollLock(open && modal && lastOpenChangeReason !== clamp.triggerHover && openMethod !== 'touch', positionerElement);
|
|
4036
|
+
clamp.useIsoLayoutEffect(() => {
|
|
4002
4037
|
if (!open && !hoverEnabled) {
|
|
4003
4038
|
store.set('hoverEnabled', true);
|
|
4004
4039
|
}
|
|
4005
4040
|
}, [open, hoverEnabled, store]);
|
|
4006
4041
|
const allowTouchToCloseRef = React__namespace.useRef(true);
|
|
4007
|
-
const allowTouchToCloseTimeout =
|
|
4008
|
-
const setOpen =
|
|
4042
|
+
const allowTouchToCloseTimeout = clamp.useTimeout();
|
|
4043
|
+
const setOpen = clamp.useStableCallback((nextOpen, eventDetails) => {
|
|
4009
4044
|
const reason = eventDetails.reason;
|
|
4010
4045
|
if (open === nextOpen && eventDetails.trigger === activeTriggerElement && lastOpenChangeReason === reason) {
|
|
4011
4046
|
return;
|
|
@@ -4051,7 +4086,7 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
|
|
|
4051
4086
|
// Prevent the menu from closing on mobile devices that have a delayed click event.
|
|
4052
4087
|
// In some cases the menu, when tapped, will fire the focus event first and then the click event.
|
|
4053
4088
|
// Without this guard, the menu will close immediately after opening.
|
|
4054
|
-
if (nextOpen && reason ===
|
|
4089
|
+
if (nextOpen && reason === clamp.triggerFocus) {
|
|
4055
4090
|
allowTouchToCloseRef.current = false;
|
|
4056
4091
|
allowTouchToCloseTimeout.start(300, () => {
|
|
4057
4092
|
allowTouchToCloseRef.current = true;
|
|
@@ -4060,8 +4095,8 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
|
|
|
4060
4095
|
allowTouchToCloseRef.current = true;
|
|
4061
4096
|
allowTouchToCloseTimeout.clear();
|
|
4062
4097
|
}
|
|
4063
|
-
const isKeyboardClick = (reason ===
|
|
4064
|
-
const isDismissClose = !nextOpen && (reason ===
|
|
4098
|
+
const isKeyboardClick = (reason === clamp.triggerPress || reason === clamp.itemPress) && nativeEvent.detail === 0 && nativeEvent?.isTrusted;
|
|
4099
|
+
const isDismissClose = !nextOpen && (reason === clamp.escapeKey || reason == null);
|
|
4065
4100
|
const updatedState = {
|
|
4066
4101
|
open: nextOpen,
|
|
4067
4102
|
openChangeReason: reason
|
|
@@ -4076,7 +4111,7 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
|
|
|
4076
4111
|
updatedState.activeTriggerElement = eventDetails.trigger ?? null;
|
|
4077
4112
|
}
|
|
4078
4113
|
store.update(updatedState);
|
|
4079
|
-
if (parent.type === 'menubar' && (reason ===
|
|
4114
|
+
if (parent.type === 'menubar' && (reason === clamp.triggerFocus || reason === clamp.focusOut || reason === clamp.triggerHover || reason === clamp.listNavigation || reason === clamp.siblingOpen)) {
|
|
4080
4115
|
store.set('instantType', 'group');
|
|
4081
4116
|
} else if (isKeyboardClick || isDismissClose) {
|
|
4082
4117
|
store.set('instantType', isKeyboardClick ? 'click' : 'dismiss');
|
|
@@ -4085,14 +4120,14 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
|
|
|
4085
4120
|
}
|
|
4086
4121
|
});
|
|
4087
4122
|
const createMenuEventDetails = React__namespace.useCallback(reason => {
|
|
4088
|
-
const details =
|
|
4123
|
+
const details = clamp.createChangeEventDetails(reason);
|
|
4089
4124
|
details.preventUnmountOnClose = () => {
|
|
4090
4125
|
store.set('preventUnmountingOnClose', true);
|
|
4091
4126
|
};
|
|
4092
4127
|
return details;
|
|
4093
4128
|
}, [store]);
|
|
4094
4129
|
const handleImperativeClose = React__namespace.useCallback(() => {
|
|
4095
|
-
store.setOpen(false, createMenuEventDetails(
|
|
4130
|
+
store.setOpen(false, createMenuEventDetails(clamp.imperativeAction));
|
|
4096
4131
|
}, [store, createMenuEventDetails]);
|
|
4097
4132
|
React__namespace.useImperativeHandle(actionsRef, () => ({
|
|
4098
4133
|
unmount: forceUnmount,
|
|
@@ -4269,47 +4304,12 @@ function MenuSubmenuRoot(props) {
|
|
|
4269
4304
|
});
|
|
4270
4305
|
}
|
|
4271
4306
|
|
|
4272
|
-
function getPseudoElementBounds(element) {
|
|
4273
|
-
const elementRect = element.getBoundingClientRect();
|
|
4274
|
-
|
|
4275
|
-
// Avoid "Not implemented: window.getComputedStyle(elt, pseudoElt)"
|
|
4276
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
4277
|
-
return elementRect;
|
|
4278
|
-
}
|
|
4279
|
-
const beforeStyles = window.getComputedStyle(element, '::before');
|
|
4280
|
-
const afterStyles = window.getComputedStyle(element, '::after');
|
|
4281
|
-
const hasPseudoElements = beforeStyles.content !== 'none' || afterStyles.content !== 'none';
|
|
4282
|
-
if (!hasPseudoElements) {
|
|
4283
|
-
return elementRect;
|
|
4284
|
-
}
|
|
4285
|
-
|
|
4286
|
-
// Get dimensions of pseudo-elements
|
|
4287
|
-
const beforeWidth = parseFloat(beforeStyles.width) || 0;
|
|
4288
|
-
const beforeHeight = parseFloat(beforeStyles.height) || 0;
|
|
4289
|
-
const afterWidth = parseFloat(afterStyles.width) || 0;
|
|
4290
|
-
const afterHeight = parseFloat(afterStyles.height) || 0;
|
|
4291
|
-
|
|
4292
|
-
// Calculate max dimensions including pseudo-elements
|
|
4293
|
-
const totalWidth = Math.max(elementRect.width, beforeWidth, afterWidth);
|
|
4294
|
-
const totalHeight = Math.max(elementRect.height, beforeHeight, afterHeight);
|
|
4295
|
-
|
|
4296
|
-
// Calculate the differences to extend the bounds
|
|
4297
|
-
const widthDiff = totalWidth - elementRect.width;
|
|
4298
|
-
const heightDiff = totalHeight - elementRect.height;
|
|
4299
|
-
return {
|
|
4300
|
-
left: elementRect.left - widthDiff / 2,
|
|
4301
|
-
right: elementRect.right + widthDiff / 2,
|
|
4302
|
-
top: elementRect.top - heightDiff / 2,
|
|
4303
|
-
bottom: elementRect.bottom + heightDiff / 2
|
|
4304
|
-
};
|
|
4305
|
-
}
|
|
4306
|
-
|
|
4307
4307
|
function useCompositeItem(params = {}) {
|
|
4308
4308
|
const {
|
|
4309
4309
|
highlightItemOnHover,
|
|
4310
4310
|
highlightedIndex,
|
|
4311
4311
|
onHighlightedIndexChange
|
|
4312
|
-
} =
|
|
4312
|
+
} = clamp.useCompositeRootContext();
|
|
4313
4313
|
const {
|
|
4314
4314
|
ref,
|
|
4315
4315
|
index
|
|
@@ -4399,7 +4399,7 @@ function useMixedToggleClickHandler(params) {
|
|
|
4399
4399
|
onMouseDown: event => {
|
|
4400
4400
|
if (mouseDownAction === 'open' && !open || mouseDownAction === 'close' && open) {
|
|
4401
4401
|
ignoreClickRef.current = true;
|
|
4402
|
-
|
|
4402
|
+
clamp.ownerDocument(event.currentTarget).addEventListener('click', () => {
|
|
4403
4403
|
ignoreClickRef.current = false;
|
|
4404
4404
|
}, {
|
|
4405
4405
|
once: true
|
|
@@ -4443,13 +4443,13 @@ const MenuTrigger = ScrollAreaViewport.fastComponentRef(function MenuTrigger(com
|
|
|
4443
4443
|
if (!store) {
|
|
4444
4444
|
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.' : useRenderElement.formatErrorMessage(85));
|
|
4445
4445
|
}
|
|
4446
|
-
const thisTriggerId =
|
|
4446
|
+
const thisTriggerId = clamp.useBaseUiId(idProp);
|
|
4447
4447
|
const isTriggerActive = store.useState('isTriggerActive', thisTriggerId);
|
|
4448
4448
|
const floatingRootContext = store.useState('floatingRootContext');
|
|
4449
4449
|
const isOpenedByThisTrigger = store.useState('isOpenedByTrigger', thisTriggerId);
|
|
4450
4450
|
const triggerElementRef = React__namespace.useRef(null);
|
|
4451
4451
|
const parent = useMenuParent();
|
|
4452
|
-
const compositeRootContext =
|
|
4452
|
+
const compositeRootContext = clamp.useCompositeRootContext(true);
|
|
4453
4453
|
const floatingTreeRootFromContext = ScrollAreaViewport.useFloatingTree();
|
|
4454
4454
|
const floatingTreeRoot = React__namespace.useMemo(() => {
|
|
4455
4455
|
return floatingTreeRootFromContext ?? new ScrollAreaViewport.FloatingTreeStore();
|
|
@@ -4474,7 +4474,7 @@ const MenuTrigger = ScrollAreaViewport.fastComponentRef(function MenuTrigger(com
|
|
|
4474
4474
|
const {
|
|
4475
4475
|
getButtonProps,
|
|
4476
4476
|
buttonRef
|
|
4477
|
-
} =
|
|
4477
|
+
} = clamp.useButton({
|
|
4478
4478
|
disabled,
|
|
4479
4479
|
native: nativeButton
|
|
4480
4480
|
});
|
|
@@ -4484,8 +4484,8 @@ const MenuTrigger = ScrollAreaViewport.fastComponentRef(function MenuTrigger(com
|
|
|
4484
4484
|
}
|
|
4485
4485
|
}, [store, isOpenedByThisTrigger, parent.type]);
|
|
4486
4486
|
const triggerRef = React__namespace.useRef(null);
|
|
4487
|
-
const allowMouseUpTriggerTimeout =
|
|
4488
|
-
const handleDocumentMouseUp =
|
|
4487
|
+
const allowMouseUpTriggerTimeout = clamp.useTimeout();
|
|
4488
|
+
const handleDocumentMouseUp = clamp.useStableCallback(mouseEvent => {
|
|
4489
4489
|
if (!triggerRef.current) {
|
|
4490
4490
|
return;
|
|
4491
4491
|
}
|
|
@@ -4504,12 +4504,12 @@ const MenuTrigger = ScrollAreaViewport.fastComponentRef(function MenuTrigger(com
|
|
|
4504
4504
|
}
|
|
4505
4505
|
floatingTreeRoot.events.emit('close', {
|
|
4506
4506
|
domEvent: mouseEvent,
|
|
4507
|
-
reason:
|
|
4507
|
+
reason: clamp.cancelOpen
|
|
4508
4508
|
});
|
|
4509
4509
|
});
|
|
4510
4510
|
React__namespace.useEffect(() => {
|
|
4511
|
-
if (isOpenedByThisTrigger && store.select('lastOpenChangeReason') ===
|
|
4512
|
-
const doc =
|
|
4511
|
+
if (isOpenedByThisTrigger && store.select('lastOpenChangeReason') === clamp.triggerHover) {
|
|
4512
|
+
const doc = clamp.ownerDocument(triggerRef.current);
|
|
4513
4513
|
doc.addEventListener('mouseup', handleDocumentMouseUp, {
|
|
4514
4514
|
once: true
|
|
4515
4515
|
});
|
|
@@ -4571,7 +4571,7 @@ const MenuTrigger = ScrollAreaViewport.fastComponentRef(function MenuTrigger(com
|
|
|
4571
4571
|
allowMouseUpTriggerTimeout.start(200, () => {
|
|
4572
4572
|
store.context.allowMouseUpTriggerRef.current = true;
|
|
4573
4573
|
});
|
|
4574
|
-
const doc =
|
|
4574
|
+
const doc = clamp.ownerDocument(event.currentTarget);
|
|
4575
4575
|
doc.addEventListener('mouseup', handleDocumentMouseUp, {
|
|
4576
4576
|
once: true
|
|
4577
4577
|
});
|
|
@@ -4580,20 +4580,20 @@ const MenuTrigger = ScrollAreaViewport.fastComponentRef(function MenuTrigger(com
|
|
|
4580
4580
|
role: 'menuitem'
|
|
4581
4581
|
} : {}, mixedToggleHandlers, elementProps, getButtonProps];
|
|
4582
4582
|
const preFocusGuardRef = React__namespace.useRef(null);
|
|
4583
|
-
const handlePreFocusGuardFocus =
|
|
4583
|
+
const handlePreFocusGuardFocus = clamp.useStableCallback(event => {
|
|
4584
4584
|
ReactDOM__namespace.flushSync(() => {
|
|
4585
|
-
store.setOpen(false,
|
|
4585
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.focusOut, event.nativeEvent, event.currentTarget));
|
|
4586
4586
|
});
|
|
4587
4587
|
const previousTabbable = ScrollAreaViewport.getTabbableBeforeElement(preFocusGuardRef.current);
|
|
4588
4588
|
previousTabbable?.focus();
|
|
4589
4589
|
});
|
|
4590
|
-
const handleFocusTargetFocus =
|
|
4590
|
+
const handleFocusTargetFocus = clamp.useStableCallback(event => {
|
|
4591
4591
|
const currentPositionerElement = store.select('positionerElement');
|
|
4592
4592
|
if (currentPositionerElement && ScrollAreaViewport.isOutsideEvent(event, currentPositionerElement)) {
|
|
4593
4593
|
store.context.beforeContentFocusGuardRef.current?.focus();
|
|
4594
4594
|
} else {
|
|
4595
4595
|
ReactDOM__namespace.flushSync(() => {
|
|
4596
|
-
store.setOpen(false,
|
|
4596
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.focusOut, event.nativeEvent, event.currentTarget));
|
|
4597
4597
|
});
|
|
4598
4598
|
let nextTabbable = ScrollAreaViewport.getTabbableAfterElement(store.context.triggerFocusTargetRef.current || triggerElementRef.current);
|
|
4599
4599
|
while (nextTabbable !== null && ScrollAreaViewport.contains(currentPositionerElement, nextTabbable)) {
|
|
@@ -4650,9 +4650,9 @@ if (process.env.NODE_ENV !== "production") MenuTrigger.displayName = "MenuTrigge
|
|
|
4650
4650
|
* Determines whether to ignore clicks after a hover-open.
|
|
4651
4651
|
*/
|
|
4652
4652
|
function useStickIfOpen(open, openReason) {
|
|
4653
|
-
const stickIfOpenTimeout =
|
|
4653
|
+
const stickIfOpenTimeout = clamp.useTimeout();
|
|
4654
4654
|
const [stickIfOpen, setStickIfOpen] = React__namespace.useState(false);
|
|
4655
|
-
|
|
4655
|
+
clamp.useIsoLayoutEffect(() => {
|
|
4656
4656
|
if (open && openReason === 'trigger-hover') {
|
|
4657
4657
|
// Only allow "patient" clicks to close the menu if it's open.
|
|
4658
4658
|
// If they clicked within 500ms of the menu opening, keep it open.
|
|
@@ -4719,7 +4719,7 @@ const MenuSubmenuTrigger = /*#__PURE__*/React__namespace.forwardRef(function Sub
|
|
|
4719
4719
|
const {
|
|
4720
4720
|
store
|
|
4721
4721
|
} = useMenuRootContext();
|
|
4722
|
-
const thisTriggerId =
|
|
4722
|
+
const thisTriggerId = clamp.useBaseUiId(idProp);
|
|
4723
4723
|
const open = store.useState('open');
|
|
4724
4724
|
const floatingRootContext = store.useState('floatingRootContext');
|
|
4725
4725
|
const floatingTreeRoot = store.useState('floatingTreeRoot');
|