@jobber/components 8.15.0 → 8.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/Card/index.cjs +1 -1
  2. package/dist/Card/index.mjs +1 -1
  3. package/dist/DataDump/index.cjs +1 -1
  4. package/dist/DataDump/index.mjs +1 -1
  5. package/dist/InputNumberExperimental-cjs.js +27 -23
  6. package/dist/InputNumberExperimental-es.js +12 -8
  7. package/dist/Menu/index.cjs +1 -1
  8. package/dist/Menu/index.mjs +1 -1
  9. package/dist/MenuSubmenuTrigger-cjs.js +1060 -1060
  10. package/dist/MenuSubmenuTrigger-es.js +928 -928
  11. package/dist/NumberFieldInput-cjs.js +53 -53
  12. package/dist/NumberFieldInput-es.js +1 -1
  13. package/dist/Page/index.cjs +1 -1
  14. package/dist/Page/index.mjs +1 -1
  15. package/dist/ScrollAreaViewport-cjs.js +4436 -4436
  16. package/dist/ScrollAreaViewport-es.js +4372 -4372
  17. package/dist/{useValueChanged-cjs.js → clamp-cjs.js} +594 -592
  18. package/dist/{useValueChanged-es.js → clamp-es.js} +595 -594
  19. package/dist/index.cjs +1 -1
  20. package/dist/index.mjs +1 -1
  21. package/dist/primitives/BottomSheet/index.cjs +2 -2
  22. package/dist/primitives/BottomSheet/index.mjs +2 -2
  23. package/dist/primitives/InputNumberExperimental/index.cjs +2 -2
  24. package/dist/primitives/InputNumberExperimental/index.mjs +2 -2
  25. package/dist/primitives/InputNumberExperimental/types.d.ts +5 -0
  26. package/dist/primitives/index.cjs +2 -2
  27. package/dist/primitives/index.mjs +2 -2
  28. package/dist/styles.css +1 -2
  29. package/dist/unstyledPrimitives/index.cjs +6271 -6134
  30. package/dist/unstyledPrimitives/index.d.ts +1 -0
  31. package/dist/unstyledPrimitives/index.mjs +6318 -6182
  32. package/dist/useRenderElement-cjs.js +30 -30
  33. package/dist/useRenderElement-es.js +30 -30
  34. 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 useValueChanged = require('./useValueChanged-cjs.js');
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 && !useValueChanged.isMouseLikePointerType(pointerType)) {
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 = useValueChanged.useId();
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
- useValueChanged.useIsoLayoutEffect(() => {
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
- useValueChanged.useIsoLayoutEffect(() => {
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
- useValueChanged.useIsoLayoutEffect(() => {
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 = useValueChanged.isMac && useValueChanged.isSafari;
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 = useValueChanged.useTimeout();
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(useValueChanged.ownerDocument(currentDomReference))) {
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 === useValueChanged.triggerPress || details.reason === useValueChanged.escapeKey) {
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, useValueChanged.createChangeEventDetails(useValueChanged.triggerFocus, nativeEvent, currentTarget));
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, useValueChanged.createChangeEventDetails(useValueChanged.triggerFocus, nativeEvent, currentTarget));
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, useValueChanged.createChangeEventDetails(useValueChanged.triggerFocus, nativeEvent));
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 useValueChanged.Timeout();
447
- this.restTimeout = new useValueChanged.Timeout();
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
- useValueChanged.useOnMount(data.hoverInteractionState.disposeEffect);
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 = useValueChanged.useStableCallback(() => {
465
+ const isClickLikeOpenEvent$1 = clamp.useStableCallback(() => {
517
466
  return isClickLikeOpenEvent(dataRef.current.openEvent?.type, instance.interactedInside);
518
467
  });
519
- const isHoverOpen = useValueChanged.useStableCallback(() => {
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 = useValueChanged.useStableCallback(target => {
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, useValueChanged.createChangeEventDetails(useValueChanged.triggerHover, event));
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 = useValueChanged.useStableCallback(() => {
488
+ const clearPointerEvents = clamp.useStableCallback(() => {
540
489
  clearSafePolygonPointerEventsMutation(instance);
541
490
  });
542
- const handleInteractInside = useValueChanged.useStableCallback(event => {
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
- useValueChanged.useIsoLayoutEffect(() => {
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
- useValueChanged.useIsoLayoutEffect(() => {
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 = useValueChanged.ownerDocument(floatingElement);
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 = useValueChanged.useTimeout();
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, useValueChanged.createChangeEventDetails(useValueChanged.triggerHover, event));
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 = useValueChanged.useValueAsRef(handleClose);
674
- const delayRef = useValueChanged.useValueAsRef(delay);
675
- const restMsRef = useValueChanged.useValueAsRef(restMs);
676
- const enabledRef = useValueChanged.useValueAsRef(enabled);
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 = useValueChanged.useStableCallback(() => {
630
+ const isClickLikeOpenEvent$1 = clamp.useStableCallback(() => {
682
631
  return isClickLikeOpenEvent(dataRef.current.openEvent?.type, instance.interactedInside);
683
632
  });
684
- const isRelatedTargetInsideEnabledTrigger = useValueChanged.useStableCallback(target => {
633
+ const isRelatedTargetInsideEnabledTrigger = clamp.useStableCallback(target => {
685
634
  return ScrollAreaViewport.isTargetInsideEnabledTrigger(target, store.context.triggerElements);
686
635
  });
687
- const isOverInactiveTrigger = useValueChanged.useStableCallback((currentDomReference, currentTarget, target) => {
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, useValueChanged.createChangeEventDetails(useValueChanged.triggerHover, event));
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, useValueChanged.createChangeEventDetails(useValueChanged.triggerHover, event));
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 = useValueChanged.useStableCallback(() => {
664
+ const cleanupMouseMoveHandler = clamp.useStableCallback(() => {
716
665
  if (!instance.handler) {
717
666
  return;
718
667
  }
719
- const doc = useValueChanged.ownerDocument(store.select('domReferenceElement'));
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 = useValueChanged.useStableCallback(() => {
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 && !useValueChanged.isMouseLikePointerType(instance.pointerType)) {
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, useValueChanged.createChangeEventDetails(useValueChanged.triggerHover, event, triggerNode));
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, useValueChanged.createChangeEventDetails(useValueChanged.triggerHover, event, triggerNode));
731
+ store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerHover, event, triggerNode));
783
732
  }
784
733
  });
785
734
  } else if (shouldOpen) {
786
- store.setOpen(true, useValueChanged.createChangeEventDetails(useValueChanged.triggerHover, event, triggerNode));
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 = useValueChanged.ownerDocument(domReferenceElement);
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 && !useValueChanged.isMouseLikePointerType(instance.pointerType)) {
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, useValueChanged.createChangeEventDetails(useValueChanged.triggerHover, nativeEvent, trigger));
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 = useValueChanged.useValueAsRef(floatingFocusElement);
933
+ const floatingFocusElementRef = clamp.useValueAsRef(floatingFocusElement);
985
934
  const parentId = ScrollAreaViewport.useFloatingParentNodeId();
986
935
  const tree = ScrollAreaViewport.useFloatingTree(externalTree);
987
- useValueChanged.useIsoLayoutEffect(() => {
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 = useValueChanged.useStableCallback(event => {
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 = useValueChanged.useValueAsRef(disabledIndices);
1004
- const latestOpenRef = useValueChanged.useValueAsRef(open);
1005
- const selectedIndexRef = useValueChanged.useValueAsRef(selectedIndex);
1006
- const resetOnPointerLeaveRef = useValueChanged.useValueAsRef(resetOnPointerLeave);
1007
- const focusItem = useValueChanged.useStableCallback(() => {
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
- useValueChanged.useIsoLayoutEffect(() => {
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
- useValueChanged.useIsoLayoutEffect(() => {
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
- useValueChanged.useIsoLayoutEffect(() => {
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(useValueChanged.ownerDocument(floatingElement));
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
- useValueChanged.useIsoLayoutEffect(() => {
1088
+ clamp.useIsoLayoutEffect(() => {
1140
1089
  previousOnNavigateRef.current = onNavigate;
1141
1090
  previousOpenRef.current = open;
1142
1091
  previousMountedRef.current = !!floatingElement;
1143
1092
  });
1144
- useValueChanged.useIsoLayoutEffect(() => {
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(useValueChanged.ownerDocument(floatingFocusEl));
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 = useValueChanged.useStableCallback(event => {
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
- useValueChanged.stopEvent(event);
1184
+ clamp.stopEvent(event);
1236
1185
  }
1237
- store.setOpen(false, useValueChanged.createChangeEventDetails(useValueChanged.listNavigation, event.nativeEvent));
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
- useValueChanged.stopEvent(event);
1201
+ clamp.stopEvent(event);
1253
1202
  indexRef.current = minIndex;
1254
1203
  onNavigate(event);
1255
1204
  }
1256
1205
  if (event.key === 'End') {
1257
- useValueChanged.stopEvent(event);
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
- useValueChanged.stopEvent(event);
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
- useValueChanged.stopEvent(event);
1386
- store.setOpen(false, useValueChanged.createChangeEventDetails(useValueChanged.focusOut, event.nativeEvent));
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' && useValueChanged.isVirtualClick(event.nativeEvent)) {
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' && useValueChanged.isVirtualPointerEvent(event.nativeEvent)) {
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
- useValueChanged.stopEvent(event);
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, useValueChanged.createChangeEventDetails(useValueChanged.listNavigation, event.nativeEvent, event.currentTarget));
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
- useValueChanged.stopEvent(event);
1399
+ clamp.stopEvent(event);
1451
1400
  if (!currentOpen && openOnArrowKeyDown) {
1452
- store.setOpen(true, useValueChanged.createChangeEventDetails(useValueChanged.listNavigation, event.nativeEvent, event.currentTarget));
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 = useValueChanged.useTimeout();
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
- useValueChanged.useIsoLayoutEffect(() => {
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
- useValueChanged.useIsoLayoutEffect(() => {
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 = useValueChanged.useStableCallback(value => {
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 = useValueChanged.useStableCallback(event => {
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
- useValueChanged.stopEvent(event);
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
- useValueChanged.stopEvent(event);
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 = useValueChanged.useStableCallback(event => {
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 useValueChanged.Timeout();
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
- * A heading that labels the dialog.
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
- const MenuRootContext = /*#__PURE__*/React__namespace.createContext(undefined);
1940
- if (process.env.NODE_ENV !== "production") MenuRootContext.displayName = "MenuRootContext";
1941
- function useMenuRootContext(optional) {
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
- return context;
1947
- }
1948
-
1949
- const ContextMenuRootContext = /*#__PURE__*/React__namespace.createContext(undefined);
1950
- if (process.env.NODE_ENV !== "production") ContextMenuRootContext.displayName = "ContextMenuRootContext";
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
- // Inform the floating tree that a menu item within this menu was hovered/moved over
1995
- // so unrelated descendant submenus can be closed.
1996
- menuEvents.emit('itemhover', {
1997
- nodeId,
1998
- target: event.currentTarget
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
- // On non-macOS platforms, this mouseup belongs to the right-click gesture
2018
- // that opened the context menu, so it must not activate an item.
2019
- if (isContextMenu && !useValueChanged.isMac && event.button === 2) {
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
- const REGULAR_ITEM = {
2035
- type: 'regular-item'
2036
- };
2037
- function useMenuItem(params) {
2038
- const {
2039
- closeOnClick,
2040
- disabled = false,
2041
- highlighted,
2042
- id,
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
- let IndexGuessBehavior = /*#__PURE__*/function (IndexGuessBehavior) {
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
- * Used to register a list item and its index (DOM position) in the `CompositeList`.
1898
+ * Provides context for a list of items in a composite component.
1899
+ * @internal
2112
1900
  */
2113
- function useCompositeListItem(params = {}) {
2114
- const {
2115
- label,
2116
- metadata,
2117
- textRef,
2118
- indexGuessBehavior,
2119
- index: externalIndex
2120
- } = params;
1901
+ function CompositeList(props) {
2121
1902
  const {
2122
- register,
2123
- unregister,
2124
- subscribeMapChange,
1903
+ children,
2125
1904
  elementsRef,
2126
1905
  labelsRef,
2127
- nextIndexRef
2128
- } = useCompositeListContext();
2129
- const indexRef = React__namespace.useRef(-1);
2130
- const [index, setIndex] = React__namespace.useState(externalIndex ?? (indexGuessBehavior === IndexGuessBehavior.GuessFromOrder ? () => {
2131
- if (indexRef.current === -1) {
2132
- const newIndex = nextIndexRef.current;
2133
- nextIndexRef.current += 1;
2134
- indexRef.current = newIndex;
2135
- }
2136
- return indexRef.current;
2137
- } : -1));
2138
- const componentRef = React__namespace.useRef(null);
2139
- const ref = React__namespace.useCallback(node => {
2140
- componentRef.current = node;
2141
- if (index !== -1 && node !== null) {
2142
- elementsRef.current[index] = node;
2143
- if (labelsRef) {
2144
- const isLabelDefined = label !== undefined;
2145
- labelsRef.current[index] = isLabelDefined ? label : textRef?.current?.textContent ?? node.textContent;
2146
- }
2147
- }
2148
- }, [index, elementsRef, labelsRef, label, textRef]);
2149
- useValueChanged.useIsoLayoutEffect(() => {
2150
- if (externalIndex != null) {
2151
- return undefined;
2152
- }
2153
- const node = componentRef.current;
2154
- if (node) {
2155
- register(node, metadata);
2156
- return () => {
2157
- unregister(node);
2158
- };
2159
- }
2160
- return undefined;
2161
- }, [externalIndex, register, unregister, metadata]);
2162
- useValueChanged.useIsoLayoutEffect(() => {
2163
- if (externalIndex != null) {
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
- return subscribeMapChange(map => {
2167
- const i = componentRef.current ? map.get(componentRef.current)?.index : null;
2168
- if (i != null) {
2169
- setIndex(i);
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
- }, [externalIndex, subscribeMapChange, setIndex]);
2173
- return React__namespace.useMemo(() => ({
2174
- ref,
2175
- index
2176
- }), [index, ref]);
2177
- }
2178
-
2179
- let MenuCheckboxItemDataAttributes = /*#__PURE__*/function (MenuCheckboxItemDataAttributes) {
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
- ...useValueChanged.transitionStatusMapping
2211
- };
2212
-
2213
- const MenuGroupContext = /*#__PURE__*/React__namespace.createContext(undefined);
2214
- if (process.env.NODE_ENV !== "production") MenuGroupContext.displayName = "MenuGroupContext";
2215
- function useMenuGroupRootContext() {
2216
- const context = React__namespace.useContext(MenuGroupContext);
2217
- if (context === undefined) {
2218
- 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));
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
- return /*#__PURE__*/jsxRuntime.jsx(MenuGroupContext.Provider, {
2242
- value: context,
2243
- children: element
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
- if (process.env.NODE_ENV !== "production") MenuGroup.displayName = "MenuGroup";
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
- * An accessible label that is automatically associated with its parent group.
2250
- * Renders a `<div>` element.
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 MenuGroupLabel = /*#__PURE__*/React__namespace.forwardRef(function MenuGroupLabelComponent(componentProps, forwardedRef) {
2255
- const {
2256
- className,
2257
- render,
2258
- id: idProp,
2259
- ...elementProps
2260
- } = componentProps;
2261
- const id = useValueChanged.useBaseUiId(idProp);
2262
- const {
2263
- setLabelId
2264
- } = useMenuGroupRootContext();
2265
- useValueChanged.useIsoLayoutEffect(() => {
2266
- setLabelId(id);
2267
- return () => {
2268
- setLabelId(undefined);
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
- }, [setLabelId, id]);
2271
- return useRenderElement.useRenderElement('div', componentProps, {
2272
- ref: forwardedRef,
2273
- props: {
2274
- id,
2275
- role: 'presentation',
2276
- ...elementProps
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
- * An individual interactive item in the menu.
2284
- * Renders a `<div>` element.
2285
- *
2286
- * Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
2287
- */
2288
- const MenuItem = /*#__PURE__*/React__namespace.forwardRef(function MenuItem(componentProps, forwardedRef) {
2289
- const {
2290
- render,
2291
- className,
2292
- id: idProp,
2293
- label,
2294
- nativeButton = false,
2295
- disabled = false,
2296
- closeOnClick = true,
2297
- ...elementProps
2298
- } = componentProps;
2299
- const listItem = useCompositeListItem({
2300
- label
2301
- });
2302
- const menuPositionerContext = useMenuPositionerContext(true);
2303
- const id = useValueChanged.useBaseUiId(idProp);
2304
- const {
2305
- store
2306
- } = useMenuRootContext();
2307
- const highlighted = store.useState('isActive', listItem.index);
2308
- const itemProps = store.useState('itemProps');
2309
- const {
2310
- getItemProps,
2311
- itemRef
2312
- } = useMenuItem({
2313
- closeOnClick,
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
- * A link in the menu that can be used to navigate to a different page or section.
2336
- * Renders an `<a>` element.
2337
- *
2338
- * Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
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 MenuLinkItem = /*#__PURE__*/React__namespace.forwardRef(function MenuLinkItem(componentProps, forwardedRef) {
2341
- const {
2342
- render,
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 ToolbarRootContext = /*#__PURE__*/React__namespace.createContext(undefined);
2393
- if (process.env.NODE_ENV !== "production") ToolbarRootContext.displayName = "ToolbarRootContext";
2394
- function useToolbarRootContext(optional) {
2395
- const context = React__namespace.useContext(ToolbarRootContext);
2396
- if (context === undefined && !optional) {
2397
- throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: ToolbarRootContext is missing. Toolbar parts must be placed within <Toolbar.Root>.' : useRenderElement.formatErrorMessage(69));
2398
- }
2399
- return context;
2400
- }
2401
-
2402
- function getDisabledMountTransitionStyles(transitionStatus) {
2403
- return transitionStatus === 'starting' ? ScrollAreaViewport.DISABLED_TRANSITIONS_STYLE : useRenderElement.EMPTY_OBJECT;
2404
- }
2405
-
2406
- const stateAttributesMapping = {
2407
- ...ScrollAreaViewport.popupStateMapping,
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 = useValueChanged.ownerDocument(floating);
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 = useValueChanged.useStableCallback(anchorFn);
2292
+ const anchorFnCallback = clamp.useStableCallback(anchorFn);
2802
2293
  const anchorDep = anchorFn ? anchorFnCallback : anchor;
2803
- const anchorValueRef = useValueChanged.useValueAsRef(anchor);
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 = useValueChanged.useValueAsRef(sideOffset);
2852
- const alignOffsetRef = useValueChanged.useValueAsRef(alignOffset);
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 = useValueChanged.ownerDocument(data.elements.floating).documentElement;
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
- useValueChanged.useIsoLayoutEffect(() => {
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
- useValueChanged.useIsoLayoutEffect(() => {
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
- useValueChanged.useIsoLayoutEffect(() => {
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
- /* eslint-disable no-bitwise */
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
- * Provides context for a list of items in a composite component.
3122
- * @internal
2621
+ * Used to register a list item and its index (DOM position) in the `CompositeList`.
3123
2622
  */
3124
- function CompositeList(props) {
2623
+ function useCompositeListItem(params = {}) {
3125
2624
  const {
3126
- children,
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
- onMapChange: onMapChangeProp
3130
- } = props;
3131
- const onMapChange = useValueChanged.useStableCallback(onMapChangeProp);
3132
- const nextIndexRef = React__namespace.useRef(0);
3133
- const listeners = useRenderElement.useRefWithInit(createListeners).current;
3134
-
3135
- // We use a stable `map` to avoid O(n^2) re-allocation costs for large lists.
3136
- // `mapTick` is our re-render trigger mechanism. We also need to update the
3137
- // elements and label refs, but there's a lot of async work going on and sometimes
3138
- // the effect that handles `onMapChange` gets called after those refs have been
3139
- // filled, and we don't want to lose those values by setting their lengths to `0`.
3140
- // We also need to have them at the proper length because floating-ui uses that
3141
- // information for list navigation.
3142
-
3143
- const map = useRenderElement.useRefWithInit(createMap).current;
3144
- // `mapTick` uses a counter rather than objects for low precision-loss risk and better memory efficiency
3145
- const [mapTick, setMapTick] = React__namespace.useState(0);
3146
- const lastTickRef = React__namespace.useRef(mapTick);
3147
- const register = useValueChanged.useStableCallback((node, metadata) => {
3148
- map.set(node, metadata ?? null);
3149
- lastTickRef.current += 1;
3150
- setMapTick(lastTickRef.current);
3151
- });
3152
- const unregister = useValueChanged.useStableCallback(node => {
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 mutationObserver = new MutationObserver(entries => {
3176
- const diff = new Set();
3177
- const updateDiff = node => diff.has(node) ? diff.delete(node) : diff.add(node);
3178
- entries.forEach(entry => {
3179
- entry.removedNodes.forEach(updateDiff);
3180
- entry.addedNodes.forEach(updateDiff);
3181
- });
3182
- if (diff.size === 0) {
3183
- lastTickRef.current += 1;
3184
- setMapTick(lastTickRef.current);
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
- sortedMap.forEach((_, node) => {
3188
- if (node.parentElement) {
3189
- mutationObserver.observe(node.parentElement, {
3190
- childList: true
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
- mutationObserver.disconnect();
3021
+ setLabelId(undefined);
3196
3022
  };
3197
- }, [sortedMap]);
3198
- useValueChanged.useIsoLayoutEffect(() => {
3199
- const shouldUpdateLengths = lastTickRef.current === mapTick;
3200
- if (shouldUpdateLengths) {
3201
- if (elementsRef.current.length !== sortedMap.size) {
3202
- elementsRef.current.length = sortedMap.size;
3203
- }
3204
- if (labelsRef && labelsRef.current.length !== sortedMap.size) {
3205
- labelsRef.current.length = sortedMap.size;
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
- onMapChange(sortedMap);
3210
- }, [onMapChange, sortedMap, elementsRef, labelsRef, mapTick]);
3211
- useValueChanged.useIsoLayoutEffect(() => {
3212
- return () => {
3213
- elementsRef.current = [];
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
- listeners.delete(fn);
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
- useValueChanged.useIsoLayoutEffect(() => {
3230
- listeners.forEach(l => l(sortedMap));
3231
- }, [listeners, sortedMap]);
3232
- const contextValue = React__namespace.useMemo(() => ({
3233
- register,
3234
- unregister,
3235
- subscribeMapChange,
3236
- elementsRef,
3237
- labelsRef,
3238
- nextIndexRef
3239
- }), [register, unregister, subscribeMapChange, elementsRef, labelsRef, nextIndexRef]);
3240
- return /*#__PURE__*/jsxRuntime.jsx(CompositeListContext.Provider, {
3241
- value: contextValue,
3242
- children: children
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
- function createMap() {
3246
- return new Map();
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
- if (position & Node.DOCUMENT_POSITION_PRECEDING || position & Node.DOCUMENT_POSITION_CONTAINS) {
3257
- return 1;
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 0;
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 = useValueChanged.useAnimationsFinished(positionerElement, false, false);
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, useValueChanged.createChangeEventDetails(useValueChanged.siblingOpen));
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 ?? useValueChanged.siblingOpen;
3386
- store.setOpen(false, useValueChanged.createChangeEventDetails(reason));
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 = useValueChanged.useTimeout();
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, useValueChanged.createChangeEventDetails(useValueChanged.siblingOpen));
3450
+ store.setOpen(false, clamp.createChangeEventDetails(clamp.siblingOpen));
3416
3451
  });
3417
3452
  }
3418
3453
  } else {
3419
- store.setOpen(false, useValueChanged.createChangeEventDetails(useValueChanged.siblingOpen));
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
- useValueChanged.useIsoLayoutEffect(() => {
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 !== useValueChanged.triggerHover || parent.type === 'menubar' && parent.context.modal);
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] = useValueChanged.useControlled({
3570
+ const [value, setValueUnwrapped] = clamp.useControlled({
3536
3571
  controlled: valueProp,
3537
3572
  default: defaultValue,
3538
3573
  name: 'MenuRadioGroup'
3539
3574
  });
3540
- const onValueChange = useValueChanged.useStableCallback(onValueChangeProp);
3541
- const setValue = useValueChanged.useStableCallback((newValue, eventDetails) => {
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 = useValueChanged.useBaseUiId(idProp);
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 = useValueChanged.useStableCallback(event => {
3664
+ const handleClick = clamp.useStableCallback(event => {
3630
3665
  const details = {
3631
- ...useValueChanged.createChangeEventDetails(useValueChanged.itemPress, event.nativeEvent),
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
- } = useValueChanged.useTransitionStatus(item.checked);
3672
- useValueChanged.useOpenChangeComplete({
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
- useValueChanged.useIsoLayoutEffect(() => {
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: useValueChanged.useId()
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 = useValueChanged.useTimeout();
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 !== useValueChanged.triggerHover && openMethod !== 'touch', positionerElement);
4001
- useValueChanged.useIsoLayoutEffect(() => {
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 = useValueChanged.useTimeout();
4008
- const setOpen = useValueChanged.useStableCallback((nextOpen, eventDetails) => {
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 === useValueChanged.triggerFocus) {
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 === useValueChanged.triggerPress || reason === useValueChanged.itemPress) && nativeEvent.detail === 0 && nativeEvent?.isTrusted;
4064
- const isDismissClose = !nextOpen && (reason === useValueChanged.escapeKey || reason == null);
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 === useValueChanged.triggerFocus || reason === useValueChanged.focusOut || reason === useValueChanged.triggerHover || reason === useValueChanged.listNavigation || reason === useValueChanged.siblingOpen)) {
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 = useValueChanged.createChangeEventDetails(reason);
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(useValueChanged.imperativeAction));
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
- } = useValueChanged.useCompositeRootContext();
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
- useValueChanged.ownerDocument(event.currentTarget).addEventListener('click', () => {
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 = useValueChanged.useBaseUiId(idProp);
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 = useValueChanged.useCompositeRootContext(true);
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
- } = useValueChanged.useButton({
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 = useValueChanged.useTimeout();
4488
- const handleDocumentMouseUp = useValueChanged.useStableCallback(mouseEvent => {
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: useValueChanged.cancelOpen
4507
+ reason: clamp.cancelOpen
4508
4508
  });
4509
4509
  });
4510
4510
  React__namespace.useEffect(() => {
4511
- if (isOpenedByThisTrigger && store.select('lastOpenChangeReason') === useValueChanged.triggerHover) {
4512
- const doc = useValueChanged.ownerDocument(triggerRef.current);
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 = useValueChanged.ownerDocument(event.currentTarget);
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 = useValueChanged.useStableCallback(event => {
4583
+ const handlePreFocusGuardFocus = clamp.useStableCallback(event => {
4584
4584
  ReactDOM__namespace.flushSync(() => {
4585
- store.setOpen(false, useValueChanged.createChangeEventDetails(useValueChanged.focusOut, event.nativeEvent, event.currentTarget));
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 = useValueChanged.useStableCallback(event => {
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, useValueChanged.createChangeEventDetails(useValueChanged.focusOut, event.nativeEvent, event.currentTarget));
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 = useValueChanged.useTimeout();
4653
+ const stickIfOpenTimeout = clamp.useTimeout();
4654
4654
  const [stickIfOpen, setStickIfOpen] = React__namespace.useState(false);
4655
- useValueChanged.useIsoLayoutEffect(() => {
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 = useValueChanged.useBaseUiId(idProp);
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');