@jobber/components 8.20.1 → 8.21.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 (84) hide show
  1. package/LegacySelect.d.ts +1 -0
  2. package/{Select.js → LegacySelect.js} +3 -3
  3. package/dist/BottomSheet-cjs.js +9 -58
  4. package/dist/BottomSheet-es.js +2 -47
  5. package/dist/Card/index.cjs +4 -0
  6. package/dist/Card/index.mjs +4 -0
  7. package/dist/ComboboxChipRemove-cjs.js +3418 -0
  8. package/dist/ComboboxChipRemove-es.js +3366 -0
  9. package/dist/ComboboxPrimitive-cjs.js +170 -0
  10. package/dist/ComboboxPrimitive-es.js +168 -0
  11. package/dist/DataDump/index.cjs +4 -0
  12. package/dist/DataDump/index.mjs +4 -0
  13. package/dist/DataTable/index.cjs +1 -1
  14. package/dist/DataTable/index.mjs +1 -1
  15. package/dist/DataTable-cjs.js +3 -3
  16. package/dist/DataTable-es.js +2 -2
  17. package/dist/InputNumberExperimental-cjs.js +45 -44
  18. package/dist/InputNumberExperimental-es.js +3 -2
  19. package/dist/InternalBackdrop-cjs.js +4278 -0
  20. package/dist/InternalBackdrop-es.js +4204 -0
  21. package/dist/LegacySelect/LegacySelect.d.ts +7 -0
  22. package/dist/{Select/Select.types.d.ts → LegacySelect/LegacySelect.types.d.ts} +1 -1
  23. package/dist/{Select → LegacySelect}/index.cjs +3 -3
  24. package/dist/LegacySelect/index.d.ts +3 -0
  25. package/dist/{Select → LegacySelect}/index.mjs +1 -1
  26. package/dist/{Select-cjs.js → LegacySelect-cjs.js} +5 -5
  27. package/dist/{Select-es.js → LegacySelect-es.js} +5 -5
  28. package/dist/Menu/index.cjs +4 -0
  29. package/dist/Menu/index.mjs +4 -0
  30. package/dist/Menu-cjs.js +9 -8
  31. package/dist/Menu-es.js +2 -1
  32. package/dist/MenuSubmenuTrigger-cjs.js +208 -1969
  33. package/dist/MenuSubmenuTrigger-es.js +7 -1759
  34. package/dist/NumberFieldInput-cjs.js +56 -439
  35. package/dist/NumberFieldInput-es.js +6 -376
  36. package/dist/Page/index.cjs +4 -0
  37. package/dist/Page/index.mjs +4 -0
  38. package/dist/ScrollAreaViewport-cjs.js +108 -4356
  39. package/dist/ScrollAreaViewport-es.js +6 -4201
  40. package/dist/buttonRenderAdapter-cjs.js +56 -0
  41. package/dist/buttonRenderAdapter-es.js +51 -0
  42. package/dist/clamp-cjs.js +0 -1194
  43. package/dist/clamp-es.js +1 -1091
  44. package/dist/docs/Autocomplete/Autocomplete.md +1 -1
  45. package/dist/docs/Chip/Chip.md +2 -2
  46. package/dist/docs/{Select/Select.md → LegacySelect/LegacySelect.md} +67 -62
  47. package/dist/docs/Menu/Menu.md +1 -1
  48. package/dist/docs/MultiSelect/MultiSelect.md +1 -1
  49. package/dist/docs/Tabs/Tabs.md +2 -1
  50. package/dist/docs/empty-states/empty-states.md +29 -0
  51. package/dist/docs/index.md +1 -1
  52. package/dist/index.cjs +7 -3
  53. package/dist/index.d.mts +1 -1
  54. package/dist/index.d.ts +1 -1
  55. package/dist/index.mjs +5 -1
  56. package/dist/primitives/BottomSheet/index.cjs +5 -2
  57. package/dist/primitives/BottomSheet/index.mjs +5 -2
  58. package/dist/primitives/ComboboxPrimitive/ComboboxPrimitive.d.ts +32 -0
  59. package/dist/primitives/ComboboxPrimitive/ComboboxPrimitive.types.d.ts +30 -0
  60. package/dist/primitives/ComboboxPrimitive/index.cjs +28 -0
  61. package/dist/primitives/ComboboxPrimitive/index.d.ts +2 -0
  62. package/dist/primitives/ComboboxPrimitive/index.mjs +22 -0
  63. package/dist/primitives/InputNumberExperimental/index.cjs +4 -2
  64. package/dist/primitives/InputNumberExperimental/index.mjs +4 -2
  65. package/dist/primitives/index.cjs +11 -2
  66. package/dist/primitives/index.d.ts +1 -0
  67. package/dist/primitives/index.mjs +10 -2
  68. package/dist/styles.css +793 -26
  69. package/dist/unstyledPrimitives/index.cjs +237 -3588
  70. package/dist/unstyledPrimitives/index.mjs +96 -3447
  71. package/dist/useButton-cjs.js +1196 -0
  72. package/dist/useButton-es.js +1091 -0
  73. package/dist/useCompositeListItem-cjs.js +1792 -0
  74. package/dist/useCompositeListItem-es.js +1762 -0
  75. package/dist/useLabel-cjs.js +411 -0
  76. package/dist/useLabel-es.js +378 -0
  77. package/dist/utils/meta/meta.json +3 -3
  78. package/package.json +7 -7
  79. package/Select.d.ts +0 -1
  80. package/dist/Select/Select.d.ts +0 -7
  81. package/dist/Select/index.d.ts +0 -3
  82. /package/dist/{Select → LegacySelect}/Option.d.ts +0 -0
  83. /package/dist/{Select → LegacySelect}/OptionGroup.d.ts +0 -0
  84. /package/dist/{Select → LegacySelect}/hooks/useSelectActions.d.ts +0 -0
@@ -3,11 +3,11 @@
3
3
  var React = require('react');
4
4
  var ScrollAreaViewport = require('./ScrollAreaViewport-cjs.js');
5
5
  var useRenderElement = require('./useRenderElement-cjs.js');
6
- var clamp = require('./clamp-cjs.js');
6
+ var useButton = require('./useButton-cjs.js');
7
7
  var jsxRuntime = require('react/jsx-runtime');
8
+ var useCompositeListItem = require('./useCompositeListItem-cjs.js');
9
+ var InternalBackdrop = require('./InternalBackdrop-cjs.js');
8
10
  var floatingUi_utils_dom = require('./floating-ui.utils.dom-cjs.js');
9
- var index_esm = require('./index.esm-cjs.js');
10
- var floatingUi_reactDom = require('./floating-ui.react-dom-cjs.js');
11
11
  var ReactDOM = require('react-dom');
12
12
 
13
13
  function _interopNamespaceDefault(e) {
@@ -31,7 +31,7 @@ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
31
31
  var ReactDOM__namespace = /*#__PURE__*/_interopNamespaceDefault(ReactDOM);
32
32
 
33
33
  function resolveValue(value, pointerType) {
34
- if (pointerType != null && !clamp.isMouseLikePointerType(pointerType)) {
34
+ if (pointerType != null && !useButton.isMouseLikePointerType(pointerType)) {
35
35
  return 0;
36
36
  }
37
37
  if (typeof value === 'function') {
@@ -56,163 +56,7 @@ function isClickLikeOpenEvent(openEventType, interactedInside) {
56
56
  return interactedInside || openEventType === 'click' || openEventType === 'mousedown';
57
57
  }
58
58
 
59
- function useFloatingRootContext(options) {
60
- const {
61
- open = false,
62
- onOpenChange,
63
- elements = {}
64
- } = options;
65
- const floatingId = clamp.useId();
66
- const nested = ScrollAreaViewport.useFloatingParentNodeId() != null;
67
- if (process.env.NODE_ENV !== 'production') {
68
- const optionDomReference = elements.reference;
69
- if (optionDomReference && !floatingUi_utils_dom.isElement(optionDomReference)) {
70
- console.error('Cannot pass a virtual element to the `elements.reference` option,', 'as it must be a real DOM element. Use `context.setPositionReference()`', 'instead.');
71
- }
72
- }
73
- const store = useRenderElement.useRefWithInit(() => new ScrollAreaViewport.FloatingRootStore({
74
- open,
75
- onOpenChange,
76
- referenceElement: elements.reference ?? null,
77
- floatingElement: elements.floating ?? null,
78
- triggerElements: new ScrollAreaViewport.PopupTriggerMap(),
79
- floatingId,
80
- nested,
81
- noEmit: false
82
- })).current;
83
- clamp.useIsoLayoutEffect(() => {
84
- const valuesToSync = {
85
- open,
86
- floatingId
87
- };
88
-
89
- // Only sync elements that are defined to avoid overwriting existing ones
90
- if (elements.reference !== undefined) {
91
- valuesToSync.referenceElement = elements.reference;
92
- valuesToSync.domReferenceElement = floatingUi_utils_dom.isElement(elements.reference) ? elements.reference : null;
93
- }
94
- if (elements.floating !== undefined) {
95
- valuesToSync.floatingElement = elements.floating;
96
- }
97
- store.update(valuesToSync);
98
- }, [open, floatingId, elements.reference, elements.floating, store]);
99
- store.context.onOpenChange = onOpenChange;
100
- store.context.nested = nested;
101
- store.context.noEmit = false;
102
- return store;
103
- }
104
-
105
- /**
106
- * Provides data to position a floating element and context to add interactions.
107
- * @see https://floating-ui.com/docs/useFloating
108
- */
109
- function useFloating(options = {}) {
110
- const {
111
- nodeId,
112
- externalTree
113
- } = options;
114
- const internalRootStore = useFloatingRootContext(options);
115
- const rootContext = options.rootContext || internalRootStore;
116
- const rootContextElements = {
117
- reference: rootContext.useState('referenceElement'),
118
- floating: rootContext.useState('floatingElement'),
119
- domReference: rootContext.useState('domReferenceElement')
120
- };
121
- const [positionReference, setPositionReferenceRaw] = React__namespace.useState(null);
122
- const domReferenceRef = React__namespace.useRef(null);
123
- const tree = ScrollAreaViewport.useFloatingTree(externalTree);
124
- clamp.useIsoLayoutEffect(() => {
125
- if (rootContextElements.domReference) {
126
- domReferenceRef.current = rootContextElements.domReference;
127
- }
128
- }, [rootContextElements.domReference]);
129
- const position = floatingUi_reactDom.useFloating({
130
- ...options,
131
- elements: {
132
- ...rootContextElements,
133
- ...(positionReference && {
134
- reference: positionReference
135
- })
136
- }
137
- });
138
- const setPositionReference = React__namespace.useCallback(node => {
139
- const computedPositionReference = floatingUi_utils_dom.isElement(node) ? {
140
- getBoundingClientRect: () => node.getBoundingClientRect(),
141
- getClientRects: () => node.getClientRects(),
142
- contextElement: node
143
- } : node;
144
- // Store the positionReference in state if the DOM reference is specified externally via the
145
- // `elements.reference` option. This ensures that it won't be overridden on future renders.
146
- setPositionReferenceRaw(computedPositionReference);
147
- position.refs.setReference(computedPositionReference);
148
- }, [position.refs]);
149
- const [localDomReference, setLocalDomReference] = React__namespace.useState(null);
150
- const [localFloatingElement, setLocalFloatingElement] = React__namespace.useState(null);
151
- rootContext.useSyncedValue('referenceElement', localDomReference);
152
- rootContext.useSyncedValue('domReferenceElement', floatingUi_utils_dom.isElement(localDomReference) ? localDomReference : null);
153
- rootContext.useSyncedValue('floatingElement', localFloatingElement);
154
- const setReference = React__namespace.useCallback(node => {
155
- if (floatingUi_utils_dom.isElement(node) || node === null) {
156
- domReferenceRef.current = node;
157
- setLocalDomReference(node);
158
- }
159
-
160
- // Backwards-compatibility for passing a virtual element to `reference`
161
- // after it has set the DOM reference.
162
- if (floatingUi_utils_dom.isElement(position.refs.reference.current) || position.refs.reference.current === null ||
163
- // Don't allow setting virtual elements using the old technique back to
164
- // `null` to support `positionReference` + an unstable `reference`
165
- // callback ref.
166
- node !== null && !floatingUi_utils_dom.isElement(node)) {
167
- position.refs.setReference(node);
168
- }
169
- }, [position.refs, setLocalDomReference]);
170
- const setFloating = React__namespace.useCallback(node => {
171
- setLocalFloatingElement(node);
172
- position.refs.setFloating(node);
173
- }, [position.refs]);
174
- const refs = React__namespace.useMemo(() => ({
175
- ...position.refs,
176
- setReference,
177
- setFloating,
178
- setPositionReference,
179
- domReference: domReferenceRef
180
- }), [position.refs, setReference, setFloating, setPositionReference]);
181
- const elements = React__namespace.useMemo(() => ({
182
- ...position.elements,
183
- domReference: rootContextElements.domReference
184
- }), [position.elements, rootContextElements.domReference]);
185
- const open = rootContext.useState('open');
186
- const floatingId = rootContext.useState('floatingId');
187
- const context = React__namespace.useMemo(() => ({
188
- ...position,
189
- dataRef: rootContext.context.dataRef,
190
- open,
191
- onOpenChange: rootContext.setOpen,
192
- events: rootContext.context.events,
193
- floatingId,
194
- refs,
195
- elements,
196
- nodeId,
197
- rootStore: rootContext
198
- }), [position, refs, elements, nodeId, rootContext, open, floatingId]);
199
- clamp.useIsoLayoutEffect(() => {
200
- rootContext.context.dataRef.current.floatingContext = context;
201
- const node = tree?.nodesRef.current.find(n => n.id === nodeId);
202
- if (node) {
203
- node.context = context;
204
- }
205
- });
206
- return React__namespace.useMemo(() => ({
207
- ...position,
208
- context,
209
- refs,
210
- elements,
211
- rootStore: rootContext
212
- }), [position, refs, elements, context, rootContext]);
213
- }
214
-
215
- const isMacSafari = clamp.isMac && clamp.isSafari;
59
+ const isMacSafari = useButton.isMac && useButton.isSafari;
216
60
  /**
217
61
  * Opens the floating element while the reference element has focus, like CSS
218
62
  * `:focus`.
@@ -231,7 +75,7 @@ function useFocus(context, props = {}) {
231
75
  const blockFocusRef = React__namespace.useRef(false);
232
76
  // Track which reference should be blocked from re-opening after Escape/press dismissal.
233
77
  const blockedReferenceRef = React__namespace.useRef(null);
234
- const timeout = clamp.useTimeout();
78
+ const timeout = useButton.useTimeout();
235
79
  const keyboardModalityRef = React__namespace.useRef(true);
236
80
  React__namespace.useEffect(() => {
237
81
  const domReference = store.select('domReferenceElement');
@@ -245,7 +89,7 @@ function useFocus(context, props = {}) {
245
89
  // return to the tab/window.
246
90
  function onBlur() {
247
91
  const currentDomReference = store.select('domReferenceElement');
248
- if (!store.select('open') && floatingUi_utils_dom.isHTMLElement(currentDomReference) && currentDomReference === clamp.activeElement(clamp.ownerDocument(currentDomReference))) {
92
+ if (!store.select('open') && floatingUi_utils_dom.isHTMLElement(currentDomReference) && currentDomReference === useButton.activeElement(useButton.ownerDocument(currentDomReference))) {
249
93
  blockFocusRef.current = true;
250
94
  }
251
95
  }
@@ -273,7 +117,7 @@ function useFocus(context, props = {}) {
273
117
  return undefined;
274
118
  }
275
119
  function onOpenChangeLocal(details) {
276
- if (details.reason === clamp.triggerPress || details.reason === clamp.escapeKey) {
120
+ if (details.reason === useButton.triggerPress || details.reason === useButton.escapeKey) {
277
121
  const referenceElement = store.select('domReferenceElement');
278
122
  if (floatingUi_utils_dom.isElement(referenceElement)) {
279
123
  blockedReferenceRef.current = referenceElement;
@@ -300,33 +144,33 @@ function useFocus(context, props = {}) {
300
144
  blockFocusRef.current = false;
301
145
  blockedReferenceRef.current = null;
302
146
  }
303
- const target = clamp.getTarget(event.nativeEvent);
147
+ const target = useButton.getTarget(event.nativeEvent);
304
148
  if (floatingUi_utils_dom.isElement(target)) {
305
149
  // Safari fails to match `:focus-visible` if focus was initially
306
150
  // outside the document.
307
151
  if (isMacSafari && !event.relatedTarget) {
308
- if (!keyboardModalityRef.current && !clamp.isTypeableElement(target)) {
152
+ if (!keyboardModalityRef.current && !useButton.isTypeableElement(target)) {
309
153
  return;
310
154
  }
311
- } else if (!clamp.matchesFocusVisible(target)) {
155
+ } else if (!useButton.matchesFocusVisible(target)) {
312
156
  return;
313
157
  }
314
158
  }
315
- const movedFromOtherEnabledTrigger = clamp.isTargetInsideEnabledTrigger(event.relatedTarget, store.context.triggerElements);
159
+ const movedFromOtherEnabledTrigger = useButton.isTargetInsideEnabledTrigger(event.relatedTarget, store.context.triggerElements);
316
160
  const {
317
161
  nativeEvent,
318
162
  currentTarget
319
163
  } = event;
320
164
  const delayValue = typeof delay === 'function' ? delay() : delay;
321
165
  if (store.select('open') && movedFromOtherEnabledTrigger || delayValue === 0 || delayValue === undefined) {
322
- store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerFocus, nativeEvent, currentTarget));
166
+ store.setOpen(true, useButton.createChangeEventDetails(useButton.triggerFocus, nativeEvent, currentTarget));
323
167
  return;
324
168
  }
325
169
  timeout.start(delayValue, () => {
326
170
  if (blockFocusRef.current) {
327
171
  return;
328
172
  }
329
- store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerFocus, nativeEvent, currentTarget));
173
+ store.setOpen(true, useButton.createChangeEventDetails(useButton.triggerFocus, nativeEvent, currentTarget));
330
174
  });
331
175
  },
332
176
  onBlur(event) {
@@ -337,12 +181,12 @@ function useFocus(context, props = {}) {
337
181
 
338
182
  // Hit the non-modal focus management portal guard. Focus will be
339
183
  // moved into the floating element immediately after.
340
- const movedToFocusGuard = floatingUi_utils_dom.isElement(relatedTarget) && relatedTarget.hasAttribute(ScrollAreaViewport.createAttribute('focus-guard')) && relatedTarget.getAttribute('data-type') === 'outside';
184
+ const movedToFocusGuard = floatingUi_utils_dom.isElement(relatedTarget) && relatedTarget.hasAttribute(InternalBackdrop.createAttribute('focus-guard')) && relatedTarget.getAttribute('data-type') === 'outside';
341
185
 
342
186
  // Wait for the window blur listener to fire.
343
187
  timeout.start(0, () => {
344
188
  const domReference = store.select('domReferenceElement');
345
- const activeEl = clamp.activeElement(domReference ? domReference.ownerDocument : document);
189
+ const activeEl = useButton.activeElement(domReference ? domReference.ownerDocument : document);
346
190
 
347
191
  // Focus left the page, keep it open.
348
192
  if (!relatedTarget && activeEl === domReference) {
@@ -356,7 +200,7 @@ function useFocus(context, props = {}) {
356
200
  // as it will only point to the shadow host of the newly focused element
357
201
  // and not the element that actually has received focus if it is located
358
202
  // inside a shadow root.
359
- if (clamp.contains(dataRef.current.floatingContext?.refs.floating.current, activeEl) || clamp.contains(domReference, activeEl) || movedToFocusGuard) {
203
+ if (useButton.contains(dataRef.current.floatingContext?.refs.floating.current, activeEl) || useButton.contains(domReference, activeEl) || movedToFocusGuard) {
360
204
  return;
361
205
  }
362
206
 
@@ -364,10 +208,10 @@ function useFocus(context, props = {}) {
364
208
  // the floating element. The focus handler of that trigger will
365
209
  // handle the open state.
366
210
  const nextFocusedElement = relatedTarget ?? activeEl;
367
- if (clamp.isTargetInsideEnabledTrigger(nextFocusedElement, store.context.triggerElements)) {
211
+ if (useButton.isTargetInsideEnabledTrigger(nextFocusedElement, store.context.triggerElements)) {
368
212
  return;
369
213
  }
370
- store.setOpen(false, clamp.createChangeEventDetails(clamp.triggerFocus, nativeEvent));
214
+ store.setOpen(false, useButton.createChangeEventDetails(useButton.triggerFocus, nativeEvent));
371
215
  });
372
216
  }
373
217
  }), [dataRef, store, timeout, delay]);
@@ -377,7 +221,7 @@ function useFocus(context, props = {}) {
377
221
  } : {}, [enabled, reference]);
378
222
  }
379
223
 
380
- const interactiveSelector = `button,a,[role="button"],select,[tabindex]:not([tabindex="-1"]),${clamp.TYPEABLE_SELECTOR}`;
224
+ const interactiveSelector = `button,a,[role="button"],select,[tabindex]:not([tabindex="-1"]),${useButton.TYPEABLE_SELECTOR}`;
381
225
  function isInteractiveElement(element) {
382
226
  return element ? Boolean(element.closest(interactiveSelector)) : false;
383
227
  }
@@ -392,8 +236,8 @@ class HoverInteraction {
392
236
  this.pointerEventsReferenceElement = null;
393
237
  this.pointerEventsFloatingElement = null;
394
238
  this.restTimeoutPending = false;
395
- this.openChangeTimeout = new clamp.Timeout();
396
- this.restTimeout = new clamp.Timeout();
239
+ this.openChangeTimeout = new useButton.Timeout();
240
+ this.restTimeout = new useButton.Timeout();
397
241
  this.handleCloseOptions = undefined;
398
242
  }
399
243
  static create() {
@@ -440,7 +284,7 @@ function useHoverInteractionSharedState(store) {
440
284
  if (!data.hoverInteractionState) {
441
285
  data.hoverInteractionState = instance;
442
286
  }
443
- clamp.useOnMount(data.hoverInteractionState.disposeEffect);
287
+ useButton.useOnMount(data.hoverInteractionState.disposeEffect);
444
288
  return data.hoverInteractionState;
445
289
  }
446
290
 
@@ -460,22 +304,22 @@ function useHoverFloatingInteraction(context, parameters = {}) {
460
304
  closeDelay: closeDelayProp = 0
461
305
  } = parameters;
462
306
  const instance = useHoverInteractionSharedState(store);
463
- const tree = ScrollAreaViewport.useFloatingTree();
464
- const parentId = ScrollAreaViewport.useFloatingParentNodeId();
465
- const isClickLikeOpenEvent$1 = clamp.useStableCallback(() => {
307
+ const tree = InternalBackdrop.useFloatingTree();
308
+ const parentId = InternalBackdrop.useFloatingParentNodeId();
309
+ const isClickLikeOpenEvent$1 = useButton.useStableCallback(() => {
466
310
  return isClickLikeOpenEvent(dataRef.current.openEvent?.type, instance.interactedInside);
467
311
  });
468
- const isHoverOpen = clamp.useStableCallback(() => {
312
+ const isHoverOpen = useButton.useStableCallback(() => {
469
313
  const type = dataRef.current.openEvent?.type;
470
314
  return type?.includes('mouse') && type !== 'mousedown';
471
315
  });
472
- const isRelatedTargetInsideEnabledTrigger = clamp.useStableCallback(target => {
473
- return clamp.isTargetInsideEnabledTrigger(target, store.context.triggerElements);
316
+ const isRelatedTargetInsideEnabledTrigger = useButton.useStableCallback(target => {
317
+ return useButton.isTargetInsideEnabledTrigger(target, store.context.triggerElements);
474
318
  });
475
319
  const closeWithDelay = React__namespace.useCallback(event => {
476
320
  const closeDelay = getDelay(closeDelayProp, 'close', instance.pointerType);
477
321
  const close = () => {
478
- store.setOpen(false, clamp.createChangeEventDetails(clamp.triggerHover, event));
322
+ store.setOpen(false, useButton.createChangeEventDetails(useButton.triggerHover, event));
479
323
  tree?.events.emit('floating.closed', event);
480
324
  };
481
325
  if (closeDelay) {
@@ -485,18 +329,18 @@ function useHoverFloatingInteraction(context, parameters = {}) {
485
329
  close();
486
330
  }
487
331
  }, [closeDelayProp, store, instance, tree]);
488
- const clearPointerEvents = clamp.useStableCallback(() => {
332
+ const clearPointerEvents = useButton.useStableCallback(() => {
489
333
  clearSafePolygonPointerEventsMutation(instance);
490
334
  });
491
- const handleInteractInside = clamp.useStableCallback(event => {
492
- const target = clamp.getTarget(event);
335
+ const handleInteractInside = useButton.useStableCallback(event => {
336
+ const target = useButton.getTarget(event);
493
337
  if (!isInteractiveElement(target)) {
494
338
  instance.interactedInside = false;
495
339
  return;
496
340
  }
497
341
  instance.interactedInside = target?.closest('[aria-haspopup]') != null;
498
342
  });
499
- clamp.useIsoLayoutEffect(() => {
343
+ useButton.useIsoLayoutEffect(() => {
500
344
  if (!open) {
501
345
  instance.pointerType = undefined;
502
346
  instance.restTimeoutPending = false;
@@ -507,14 +351,14 @@ function useHoverFloatingInteraction(context, parameters = {}) {
507
351
  React__namespace.useEffect(() => {
508
352
  return clearPointerEvents;
509
353
  }, [clearPointerEvents]);
510
- clamp.useIsoLayoutEffect(() => {
354
+ useButton.useIsoLayoutEffect(() => {
511
355
  if (!enabled) {
512
356
  return undefined;
513
357
  }
514
358
  if (open && instance.handleCloseOptions?.blockPointerEvents && isHoverOpen() && floatingUi_utils_dom.isElement(domReferenceElement) && floatingElement) {
515
359
  const ref = domReferenceElement;
516
360
  const floatingEl = floatingElement;
517
- const doc = clamp.ownerDocument(floatingElement);
361
+ const doc = useButton.ownerDocument(floatingElement);
518
362
  const parentFloating = tree?.nodesRef.current.find(node => node.id === parentId)?.context?.elements.floating;
519
363
  if (parentFloating) {
520
364
  parentFloating.style.pointerEvents = '';
@@ -531,7 +375,7 @@ function useHoverFloatingInteraction(context, parameters = {}) {
531
375
  }
532
376
  return undefined;
533
377
  }, [enabled, open, domReferenceElement, floatingElement, instance, isHoverOpen, tree, parentId, clearPointerEvents]);
534
- const childClosedTimeout = clamp.useTimeout();
378
+ const childClosedTimeout = useButton.useTimeout();
535
379
  React__namespace.useEffect(() => {
536
380
  if (!enabled) {
537
381
  return undefined;
@@ -543,7 +387,7 @@ function useHoverFloatingInteraction(context, parameters = {}) {
543
387
  clearPointerEvents();
544
388
  }
545
389
  function onFloatingMouseLeave(event) {
546
- if (tree && parentId && ScrollAreaViewport.getNodeChildren(tree.nodesRef.current, parentId).length > 0) {
390
+ if (tree && parentId && InternalBackdrop.getNodeChildren(tree.nodesRef.current, parentId).length > 0) {
547
391
  tree.events.on('floating.closed', onNodeClosed);
548
392
  return;
549
393
  }
@@ -564,13 +408,13 @@ function useHoverFloatingInteraction(context, parameters = {}) {
564
408
  }
565
409
  }
566
410
  function onNodeClosed(event) {
567
- if (!tree || !parentId || ScrollAreaViewport.getNodeChildren(tree.nodesRef.current, parentId).length > 0) {
411
+ if (!tree || !parentId || InternalBackdrop.getNodeChildren(tree.nodesRef.current, parentId).length > 0) {
568
412
  return;
569
413
  }
570
414
  // Allow the mouseenter event to fire in case child was closed because mouse moved into parent.
571
415
  childClosedTimeout.start(0, () => {
572
416
  tree.events.off('floating.closed', onNodeClosed);
573
- store.setOpen(false, clamp.createChangeEventDetails(clamp.triggerHover, event));
417
+ store.setOpen(false, useButton.createChangeEventDetails(useButton.triggerHover, event));
574
418
  tree.events.emit('floating.closed', event);
575
419
  });
576
420
  }
@@ -617,28 +461,28 @@ function useHoverReferenceInteraction(context, props = {}) {
617
461
  isActiveTrigger = true,
618
462
  getHandleCloseContext
619
463
  } = props;
620
- const tree = ScrollAreaViewport.useFloatingTree(externalTree);
464
+ const tree = InternalBackdrop.useFloatingTree(externalTree);
621
465
  const instance = useHoverInteractionSharedState(store);
622
- const handleCloseRef = clamp.useValueAsRef(handleClose);
623
- const delayRef = clamp.useValueAsRef(delay);
624
- const restMsRef = clamp.useValueAsRef(restMs);
625
- const enabledRef = clamp.useValueAsRef(enabled);
466
+ const handleCloseRef = useButton.useValueAsRef(handleClose);
467
+ const delayRef = useButton.useValueAsRef(delay);
468
+ const restMsRef = useButton.useValueAsRef(restMs);
469
+ const enabledRef = useButton.useValueAsRef(enabled);
626
470
  if (isActiveTrigger) {
627
471
  // eslint-disable-next-line no-underscore-dangle
628
472
  instance.handleCloseOptions = handleCloseRef.current?.__options;
629
473
  }
630
- const isClickLikeOpenEvent$1 = clamp.useStableCallback(() => {
474
+ const isClickLikeOpenEvent$1 = useButton.useStableCallback(() => {
631
475
  return isClickLikeOpenEvent(dataRef.current.openEvent?.type, instance.interactedInside);
632
476
  });
633
- const isRelatedTargetInsideEnabledTrigger = clamp.useStableCallback(target => {
634
- return clamp.isTargetInsideEnabledTrigger(target, store.context.triggerElements);
477
+ const isRelatedTargetInsideEnabledTrigger = useButton.useStableCallback(target => {
478
+ return useButton.isTargetInsideEnabledTrigger(target, store.context.triggerElements);
635
479
  });
636
- const isOverInactiveTrigger = clamp.useStableCallback((currentDomReference, currentTarget, target) => {
480
+ const isOverInactiveTrigger = useButton.useStableCallback((currentDomReference, currentTarget, target) => {
637
481
  const allTriggers = store.context.triggerElements;
638
482
 
639
483
  // Fast path for normal usage where handlers are attached directly to triggers.
640
484
  if (allTriggers.hasElement(currentTarget)) {
641
- return !currentDomReference || !clamp.contains(currentDomReference, currentTarget);
485
+ return !currentDomReference || !useButton.contains(currentDomReference, currentTarget);
642
486
  }
643
487
 
644
488
  // Fallback for delegated/wrapper usage where currentTarget may be outside the trigger map.
@@ -646,31 +490,31 @@ function useHoverReferenceInteraction(context, props = {}) {
646
490
  return false;
647
491
  }
648
492
  const targetElement = target;
649
- return allTriggers.hasMatchingElement(trigger => clamp.contains(trigger, targetElement)) && (!currentDomReference || !clamp.contains(currentDomReference, targetElement));
493
+ return allTriggers.hasMatchingElement(trigger => useButton.contains(trigger, targetElement)) && (!currentDomReference || !useButton.contains(currentDomReference, targetElement));
650
494
  });
651
495
  const closeWithDelay = React__namespace.useCallback((event, runElseBranch = true) => {
652
496
  const closeDelay = getDelay(delayRef.current, 'close', instance.pointerType);
653
497
  if (closeDelay) {
654
498
  instance.openChangeTimeout.start(closeDelay, () => {
655
- store.setOpen(false, clamp.createChangeEventDetails(clamp.triggerHover, event));
499
+ store.setOpen(false, useButton.createChangeEventDetails(useButton.triggerHover, event));
656
500
  tree?.events.emit('floating.closed', event);
657
501
  });
658
502
  } else if (runElseBranch) {
659
503
  instance.openChangeTimeout.clear();
660
- store.setOpen(false, clamp.createChangeEventDetails(clamp.triggerHover, event));
504
+ store.setOpen(false, useButton.createChangeEventDetails(useButton.triggerHover, event));
661
505
  tree?.events.emit('floating.closed', event);
662
506
  }
663
507
  }, [delayRef, store, instance, tree]);
664
- const cleanupMouseMoveHandler = clamp.useStableCallback(() => {
508
+ const cleanupMouseMoveHandler = useButton.useStableCallback(() => {
665
509
  if (!instance.handler) {
666
510
  return;
667
511
  }
668
- const doc = clamp.ownerDocument(store.select('domReferenceElement'));
512
+ const doc = useButton.ownerDocument(store.select('domReferenceElement'));
669
513
  doc.removeEventListener('mousemove', instance.handler);
670
514
  instance.handler = undefined;
671
515
  });
672
516
  React__namespace.useEffect(() => cleanupMouseMoveHandler, [cleanupMouseMoveHandler]);
673
- const clearPointerEvents = clamp.useStableCallback(() => {
517
+ const clearPointerEvents = useButton.useStableCallback(() => {
674
518
  clearSafePolygonPointerEventsMutation(instance);
675
519
  });
676
520
 
@@ -705,7 +549,7 @@ function useHoverReferenceInteraction(context, props = {}) {
705
549
  function onMouseEnter(event) {
706
550
  instance.openChangeTimeout.clear();
707
551
  instance.blockMouseMove = false;
708
- if (mouseOnly && !clamp.isMouseLikePointerType(instance.pointerType)) {
552
+ if (mouseOnly && !useButton.isMouseLikePointerType(instance.pointerType)) {
709
553
  return;
710
554
  }
711
555
 
@@ -724,15 +568,15 @@ function useHoverReferenceInteraction(context, props = {}) {
724
568
 
725
569
  // When moving between triggers while already open, open immediately without delay
726
570
  if (isOverInactive && isOpen) {
727
- store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerHover, event, triggerNode));
571
+ store.setOpen(true, useButton.createChangeEventDetails(useButton.triggerHover, event, triggerNode));
728
572
  } else if (openDelay) {
729
573
  instance.openChangeTimeout.start(openDelay, () => {
730
574
  if (shouldOpen) {
731
- store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerHover, event, triggerNode));
575
+ store.setOpen(true, useButton.createChangeEventDetails(useButton.triggerHover, event, triggerNode));
732
576
  }
733
577
  });
734
578
  } else if (shouldOpen) {
735
- store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerHover, event, triggerNode));
579
+ store.setOpen(true, useButton.createChangeEventDetails(useButton.triggerHover, event, triggerNode));
736
580
  }
737
581
  }
738
582
  function onMouseLeave(event) {
@@ -742,7 +586,7 @@ function useHoverReferenceInteraction(context, props = {}) {
742
586
  }
743
587
  cleanupMouseMoveHandler();
744
588
  const domReferenceElement = store.select('domReferenceElement');
745
- const doc = clamp.ownerDocument(domReferenceElement);
589
+ const doc = useButton.ownerDocument(domReferenceElement);
746
590
  instance.restTimeout.clear();
747
591
  instance.restTimeoutPending = false;
748
592
  const handleCloseContextBase = dataRef.current.floatingContext ?? getHandleCloseContext?.();
@@ -772,7 +616,7 @@ function useHoverReferenceInteraction(context, props = {}) {
772
616
  instance.handler(event);
773
617
  return;
774
618
  }
775
- const shouldClose = instance.pointerType === 'touch' ? !clamp.contains(store.select('floatingElement'), event.relatedTarget) : true;
619
+ const shouldClose = instance.pointerType === 'touch' ? !useButton.contains(store.select('floatingElement'), event.relatedTarget) : true;
776
620
  if (shouldClose) {
777
621
  closeWithDelay(event);
778
622
  }
@@ -810,7 +654,7 @@ function useHoverReferenceInteraction(context, props = {}) {
810
654
  const currentDomReference = store.select('domReferenceElement');
811
655
  const currentOpen = store.select('open');
812
656
  const isOverInactive = isOverInactiveTrigger(currentDomReference, trigger, event.target);
813
- if (mouseOnly && !clamp.isMouseLikePointerType(instance.pointerType)) {
657
+ if (mouseOnly && !useButton.isMouseLikePointerType(instance.pointerType)) {
814
658
  return;
815
659
  }
816
660
  const restMsValue = getRestMs(restMsRef.current);
@@ -831,7 +675,7 @@ function useHoverReferenceInteraction(context, props = {}) {
831
675
  }
832
676
  const latestOpen = store.select('open');
833
677
  if (!instance.blockMouseMove && (!latestOpen || isOverInactive)) {
834
- store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerHover, nativeEvent, trigger));
678
+ store.setOpen(true, useButton.createChangeEventDetails(useButton.triggerHover, nativeEvent, trigger));
835
679
  }
836
680
  }
837
681
  if (instance.pointerType === 'touch') {
@@ -849,756 +693,6 @@ function useHoverReferenceInteraction(context, props = {}) {
849
693
  }, [enabled, instance, isClickLikeOpenEvent$1, isOverInactiveTrigger, mouseOnly, store, restMsRef]);
850
694
  }
851
695
 
852
- const ESCAPE = 'Escape';
853
- function doSwitch(orientation, vertical, horizontal) {
854
- switch (orientation) {
855
- case 'vertical':
856
- return vertical;
857
- case 'horizontal':
858
- return horizontal;
859
- default:
860
- return vertical || horizontal;
861
- }
862
- }
863
- function isMainOrientationKey(key, orientation) {
864
- const vertical = key === clamp.ARROW_UP || key === clamp.ARROW_DOWN;
865
- const horizontal = key === clamp.ARROW_LEFT || key === clamp.ARROW_RIGHT;
866
- return doSwitch(orientation, vertical, horizontal);
867
- }
868
- function isMainOrientationToEndKey(key, orientation, rtl) {
869
- const vertical = key === clamp.ARROW_DOWN;
870
- const horizontal = rtl ? key === clamp.ARROW_LEFT : key === clamp.ARROW_RIGHT;
871
- return doSwitch(orientation, vertical, horizontal) || key === 'Enter' || key === ' ' || key === '';
872
- }
873
- function isCrossOrientationOpenKey(key, orientation, rtl) {
874
- const vertical = rtl ? key === clamp.ARROW_LEFT : key === clamp.ARROW_RIGHT;
875
- const horizontal = key === clamp.ARROW_DOWN;
876
- return doSwitch(orientation, vertical, horizontal);
877
- }
878
- function isCrossOrientationCloseKey(key, orientation, rtl, cols) {
879
- const vertical = rtl ? key === clamp.ARROW_RIGHT : key === clamp.ARROW_LEFT;
880
- const horizontal = key === clamp.ARROW_UP;
881
- if (orientation === 'both' || orientation === 'horizontal' && cols && cols > 1) {
882
- return key === ESCAPE;
883
- }
884
- return doSwitch(orientation, vertical, horizontal);
885
- }
886
- /**
887
- * Adds arrow key-based navigation of a list of items, either using real DOM
888
- * focus or virtual focus.
889
- * @see https://floating-ui.com/docs/useListNavigation
890
- */
891
- function useListNavigation(context, props) {
892
- const store = 'rootStore' in context ? context.rootStore : context;
893
- const open = store.useState('open');
894
- const floatingElement = store.useState('floatingElement');
895
- const domReferenceElement = store.useState('domReferenceElement');
896
- const dataRef = store.context.dataRef;
897
- const {
898
- listRef,
899
- activeIndex,
900
- onNavigate: onNavigateProp = () => {},
901
- enabled = true,
902
- selectedIndex = null,
903
- allowEscape = false,
904
- loopFocus = false,
905
- nested = false,
906
- rtl = false,
907
- virtual = false,
908
- focusItemOnOpen = 'auto',
909
- focusItemOnHover = true,
910
- openOnArrowKeyDown = true,
911
- disabledIndices = undefined,
912
- orientation = 'vertical',
913
- parentOrientation,
914
- cols = 1,
915
- id,
916
- resetOnPointerLeave = true,
917
- externalTree
918
- } = props;
919
- if (process.env.NODE_ENV !== 'production') {
920
- if (allowEscape) {
921
- if (!loopFocus) {
922
- console.warn('`useListNavigation` looping must be enabled to allow escaping.');
923
- }
924
- if (!virtual) {
925
- console.warn('`useListNavigation` must be virtual to allow escaping.');
926
- }
927
- }
928
- if (orientation === 'vertical' && cols > 1) {
929
- console.warn('In grid list navigation mode (`cols` > 1), the `orientation` should', 'be either "horizontal" or "both".');
930
- }
931
- }
932
- const floatingFocusElement = clamp.getFloatingFocusElement(floatingElement);
933
- const floatingFocusElementRef = clamp.useValueAsRef(floatingFocusElement);
934
- const parentId = ScrollAreaViewport.useFloatingParentNodeId();
935
- const tree = ScrollAreaViewport.useFloatingTree(externalTree);
936
- clamp.useIsoLayoutEffect(() => {
937
- dataRef.current.orientation = orientation;
938
- }, [dataRef, orientation]);
939
- const typeableComboboxReference = clamp.isTypeableCombobox(domReferenceElement);
940
- const focusItemOnOpenRef = React__namespace.useRef(focusItemOnOpen);
941
- const indexRef = React__namespace.useRef(selectedIndex ?? -1);
942
- const keyRef = React__namespace.useRef(null);
943
- const isPointerModalityRef = React__namespace.useRef(true);
944
- const onNavigate = clamp.useStableCallback(event => {
945
- onNavigateProp(indexRef.current === -1 ? null : indexRef.current, event);
946
- });
947
- const previousOnNavigateRef = React__namespace.useRef(onNavigate);
948
- const previousMountedRef = React__namespace.useRef(!!floatingElement);
949
- const previousOpenRef = React__namespace.useRef(open);
950
- const forceSyncFocusRef = React__namespace.useRef(false);
951
- const forceScrollIntoViewRef = React__namespace.useRef(false);
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(() => {
957
- function runFocus(item) {
958
- if (virtual) {
959
- tree?.events.emit('virtualfocus', item);
960
- } else {
961
- ScrollAreaViewport.enqueueFocus(item, {
962
- sync: forceSyncFocusRef.current,
963
- preventScroll: true
964
- });
965
- }
966
- }
967
- const initialItem = listRef.current[indexRef.current];
968
- const forceScrollIntoView = forceScrollIntoViewRef.current;
969
- if (initialItem) {
970
- runFocus(initialItem);
971
- }
972
- const scheduler = forceSyncFocusRef.current ? v => v() : requestAnimationFrame;
973
- scheduler(() => {
974
- const waitedItem = listRef.current[indexRef.current] || initialItem;
975
- if (!waitedItem) {
976
- return;
977
- }
978
- if (!initialItem) {
979
- runFocus(waitedItem);
980
- }
981
- const shouldScrollIntoView =
982
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
983
- item && (forceScrollIntoView || !isPointerModalityRef.current);
984
- if (shouldScrollIntoView) {
985
- // JSDOM doesn't support `.scrollIntoView()` but it's widely supported
986
- // by all browsers.
987
- waitedItem.scrollIntoView?.({
988
- block: 'nearest',
989
- inline: 'nearest'
990
- });
991
- }
992
- });
993
- });
994
-
995
- // Sync `selectedIndex` to be the `activeIndex` upon opening the floating
996
- // element. Also, reset `activeIndex` upon closing the floating element.
997
- clamp.useIsoLayoutEffect(() => {
998
- if (!enabled) {
999
- return;
1000
- }
1001
- if (open && floatingElement) {
1002
- indexRef.current = selectedIndex ?? -1;
1003
- if (focusItemOnOpenRef.current && selectedIndex != null) {
1004
- // Regardless of the pointer modality, we want to ensure the selected
1005
- // item comes into view when the floating element is opened.
1006
- forceScrollIntoViewRef.current = true;
1007
- onNavigate();
1008
- }
1009
- } else if (previousMountedRef.current) {
1010
- // Since the user can specify `onNavigate` conditionally
1011
- // (onNavigate: open ? setActiveIndex : setSelectedIndex),
1012
- // we store and call the previous function.
1013
- indexRef.current = -1;
1014
- previousOnNavigateRef.current();
1015
- }
1016
- }, [enabled, open, floatingElement, selectedIndex, onNavigate]);
1017
-
1018
- // Sync `activeIndex` to be the focused item while the floating element is
1019
- // open.
1020
- clamp.useIsoLayoutEffect(() => {
1021
- if (!enabled) {
1022
- return;
1023
- }
1024
- if (!open) {
1025
- forceSyncFocusRef.current = false;
1026
- return;
1027
- }
1028
- if (!floatingElement) {
1029
- return;
1030
- }
1031
- if (activeIndex == null) {
1032
- forceSyncFocusRef.current = false;
1033
- if (selectedIndexRef.current != null) {
1034
- return;
1035
- }
1036
-
1037
- // Reset while the floating element was open (e.g. the list changed).
1038
- if (previousMountedRef.current) {
1039
- indexRef.current = -1;
1040
- focusItem();
1041
- }
1042
-
1043
- // Initial sync.
1044
- if ((!previousOpenRef.current || !previousMountedRef.current) && focusItemOnOpenRef.current && (keyRef.current != null || focusItemOnOpenRef.current === true && keyRef.current == null)) {
1045
- let runs = 0;
1046
- const waitForListPopulated = () => {
1047
- if (listRef.current[0] == null) {
1048
- // Avoid letting the browser paint if possible on the first try,
1049
- // otherwise use rAF. Don't try more than twice, since something
1050
- // is wrong otherwise.
1051
- if (runs < 2) {
1052
- const scheduler = runs ? requestAnimationFrame : queueMicrotask;
1053
- scheduler(waitForListPopulated);
1054
- }
1055
- runs += 1;
1056
- } else {
1057
- // initially focus the first non-disabled item
1058
- indexRef.current = keyRef.current == null || isMainOrientationToEndKey(keyRef.current, orientation, rtl) || nested ? ScrollAreaViewport.getMinListIndex(listRef) : ScrollAreaViewport.getMaxListIndex(listRef);
1059
- keyRef.current = null;
1060
- onNavigate();
1061
- }
1062
- };
1063
- waitForListPopulated();
1064
- }
1065
- } else if (!ScrollAreaViewport.isIndexOutOfListBounds(listRef, activeIndex)) {
1066
- indexRef.current = activeIndex;
1067
- focusItem();
1068
- forceScrollIntoViewRef.current = false;
1069
- }
1070
- }, [enabled, open, floatingElement, activeIndex, selectedIndexRef, nested, listRef, orientation, rtl, onNavigate, focusItem, disabledIndicesRef]);
1071
-
1072
- // Ensure the parent floating element has focus when a nested child closes
1073
- // to allow arrow key navigation to work after the pointer leaves the child.
1074
- clamp.useIsoLayoutEffect(() => {
1075
- if (!enabled || floatingElement || !tree || virtual || !previousMountedRef.current) {
1076
- return;
1077
- }
1078
- const nodes = tree.nodesRef.current;
1079
- const parent = nodes.find(node => node.id === parentId)?.context?.elements.floating;
1080
- const activeEl = clamp.activeElement(clamp.ownerDocument(floatingElement));
1081
- const treeContainsActiveEl = nodes.some(node => node.context && clamp.contains(node.context.elements.floating, activeEl));
1082
- if (parent && !treeContainsActiveEl && isPointerModalityRef.current) {
1083
- parent.focus({
1084
- preventScroll: true
1085
- });
1086
- }
1087
- }, [enabled, floatingElement, tree, parentId, virtual]);
1088
- clamp.useIsoLayoutEffect(() => {
1089
- previousOnNavigateRef.current = onNavigate;
1090
- previousOpenRef.current = open;
1091
- previousMountedRef.current = !!floatingElement;
1092
- });
1093
- clamp.useIsoLayoutEffect(() => {
1094
- if (!open) {
1095
- keyRef.current = null;
1096
- focusItemOnOpenRef.current = focusItemOnOpen;
1097
- }
1098
- }, [open, focusItemOnOpen]);
1099
- const hasActiveIndex = activeIndex != null;
1100
- const item = React__namespace.useMemo(() => {
1101
- function syncCurrentTarget(event) {
1102
- if (!latestOpenRef.current) {
1103
- return;
1104
- }
1105
- const index = listRef.current.indexOf(event.currentTarget);
1106
- if (index !== -1 && indexRef.current !== index) {
1107
- indexRef.current = index;
1108
- onNavigate(event);
1109
- }
1110
- }
1111
- const itemProps = {
1112
- onFocus(event) {
1113
- forceSyncFocusRef.current = true;
1114
- syncCurrentTarget(event);
1115
- },
1116
- onClick: ({
1117
- currentTarget
1118
- }) => currentTarget.focus({
1119
- preventScroll: true
1120
- }),
1121
- // Safari
1122
- onMouseMove(event) {
1123
- forceSyncFocusRef.current = true;
1124
- forceScrollIntoViewRef.current = false;
1125
- if (focusItemOnHover) {
1126
- syncCurrentTarget(event);
1127
- }
1128
- },
1129
- onPointerLeave(event) {
1130
- if (!latestOpenRef.current || !isPointerModalityRef.current || event.pointerType === 'touch') {
1131
- return;
1132
- }
1133
- forceSyncFocusRef.current = true;
1134
- const relatedTarget = event.relatedTarget;
1135
- if (!focusItemOnHover || listRef.current.includes(relatedTarget)) {
1136
- return;
1137
- }
1138
- if (!resetOnPointerLeaveRef.current) {
1139
- return;
1140
- }
1141
- ScrollAreaViewport.enqueueFocus(null, {
1142
- sync: true
1143
- });
1144
- indexRef.current = -1;
1145
- onNavigate(event);
1146
- if (!virtual) {
1147
- const floatingFocusEl = floatingFocusElementRef.current;
1148
- const activeEl = clamp.activeElement(clamp.ownerDocument(floatingFocusEl));
1149
- if (floatingFocusEl && clamp.contains(floatingFocusEl, activeEl)) {
1150
- floatingFocusEl.focus({
1151
- preventScroll: true
1152
- });
1153
- }
1154
- }
1155
- }
1156
- };
1157
- return itemProps;
1158
- }, [latestOpenRef, floatingFocusElementRef, focusItemOnHover, listRef, onNavigate, resetOnPointerLeaveRef, virtual]);
1159
- const getParentOrientation = React__namespace.useCallback(() => {
1160
- return parentOrientation ?? tree?.nodesRef.current.find(node => node.id === parentId)?.context?.dataRef?.current.orientation;
1161
- }, [parentId, tree, parentOrientation]);
1162
- const commonOnKeyDown = clamp.useStableCallback(event => {
1163
- isPointerModalityRef.current = false;
1164
- forceSyncFocusRef.current = true;
1165
-
1166
- // When composing a character, Chrome fires ArrowDown twice. Firefox/Safari
1167
- // don't appear to suffer from this. `event.isComposing` is avoided due to
1168
- // Safari not supporting it properly (although it's not needed in the first
1169
- // place for Safari, just avoiding any possible issues).
1170
- if (event.which === 229) {
1171
- return;
1172
- }
1173
-
1174
- // If the floating element is animating out, ignore navigation. Otherwise,
1175
- // the `activeIndex` gets set to 0 despite not being open so the next time
1176
- // the user ArrowDowns, the first item won't be focused.
1177
- if (!latestOpenRef.current && event.currentTarget === floatingFocusElementRef.current) {
1178
- return;
1179
- }
1180
- if (nested && isCrossOrientationCloseKey(event.key, orientation, rtl, cols)) {
1181
- // If the nested list's close key is also the parent navigation key,
1182
- // let the parent navigate. Otherwise, stop propagating the event.
1183
- if (!isMainOrientationKey(event.key, getParentOrientation())) {
1184
- clamp.stopEvent(event);
1185
- }
1186
- store.setOpen(false, clamp.createChangeEventDetails(clamp.listNavigation, event.nativeEvent));
1187
- if (floatingUi_utils_dom.isHTMLElement(domReferenceElement)) {
1188
- if (virtual) {
1189
- tree?.events.emit('virtualfocus', domReferenceElement);
1190
- } else {
1191
- domReferenceElement.focus();
1192
- }
1193
- }
1194
- return;
1195
- }
1196
- const currentIndex = indexRef.current;
1197
- const minIndex = ScrollAreaViewport.getMinListIndex(listRef, disabledIndices);
1198
- const maxIndex = ScrollAreaViewport.getMaxListIndex(listRef, disabledIndices);
1199
- if (!typeableComboboxReference) {
1200
- if (event.key === 'Home') {
1201
- clamp.stopEvent(event);
1202
- indexRef.current = minIndex;
1203
- onNavigate(event);
1204
- }
1205
- if (event.key === 'End') {
1206
- clamp.stopEvent(event);
1207
- indexRef.current = maxIndex;
1208
- onNavigate(event);
1209
- }
1210
- }
1211
-
1212
- // Grid navigation.
1213
- if (cols > 1) {
1214
- const sizes = Array.from({
1215
- length: listRef.current.length
1216
- }, () => ({
1217
- width: 1,
1218
- height: 1
1219
- }));
1220
- // To calculate movements on the grid, we use hypothetical cell indices
1221
- // as if every item was 1x1, then convert back to real indices.
1222
- const cellMap = ScrollAreaViewport.createGridCellMap(sizes, cols);
1223
- const minGridIndex = cellMap.findIndex(index => index != null && !ScrollAreaViewport.isListIndexDisabled(listRef, index, disabledIndices));
1224
- // last enabled index
1225
- const maxGridIndex = cellMap.reduce((foundIndex, index, cellIndex) => index != null && !ScrollAreaViewport.isListIndexDisabled(listRef, index, disabledIndices) ? cellIndex : foundIndex, -1);
1226
- const index = cellMap[ScrollAreaViewport.getGridNavigatedIndex({
1227
- current: cellMap.map(itemIndex => itemIndex != null ? listRef.current[itemIndex] : null)
1228
- }, {
1229
- event,
1230
- orientation,
1231
- loopFocus,
1232
- rtl,
1233
- cols,
1234
- // treat undefined (empty grid spaces) as disabled indices so we
1235
- // don't end up in them
1236
- disabledIndices: ScrollAreaViewport.getGridCellIndices([...((typeof disabledIndices !== 'function' ? disabledIndices : null) || listRef.current.map((_, listIndex) => ScrollAreaViewport.isListIndexDisabled(listRef, listIndex, disabledIndices) ? listIndex : undefined)), undefined], cellMap),
1237
- minIndex: minGridIndex,
1238
- maxIndex: maxGridIndex,
1239
- prevIndex: ScrollAreaViewport.getGridCellIndexOfCorner(indexRef.current > maxIndex ? minIndex : indexRef.current, sizes, cellMap, cols,
1240
- // use a corner matching the edge closest to the direction
1241
- // we're moving in so we don't end up in the same item. Prefer
1242
- // top/left over bottom/right.
1243
- // eslint-disable-next-line no-nested-ternary
1244
- event.key === clamp.ARROW_DOWN ? 'bl' : event.key === (rtl ? clamp.ARROW_LEFT : clamp.ARROW_RIGHT) ? 'tr' : 'tl'),
1245
- stopEvent: true
1246
- })];
1247
- if (index != null) {
1248
- indexRef.current = index;
1249
- onNavigate(event);
1250
- }
1251
- if (orientation === 'both') {
1252
- return;
1253
- }
1254
- }
1255
- if (isMainOrientationKey(event.key, orientation)) {
1256
- clamp.stopEvent(event);
1257
-
1258
- // Reset the index if no item is focused.
1259
- if (open && !virtual && clamp.activeElement(event.currentTarget.ownerDocument) === event.currentTarget) {
1260
- indexRef.current = isMainOrientationToEndKey(event.key, orientation, rtl) ? minIndex : maxIndex;
1261
- onNavigate(event);
1262
- return;
1263
- }
1264
- if (isMainOrientationToEndKey(event.key, orientation, rtl)) {
1265
- if (loopFocus) {
1266
- if (currentIndex >= maxIndex) {
1267
- if (allowEscape && currentIndex !== listRef.current.length) {
1268
- indexRef.current = -1;
1269
- } else {
1270
- // Give time for virtualizers to update the listRef.
1271
- forceSyncFocusRef.current = false;
1272
- indexRef.current = minIndex;
1273
- }
1274
- } else {
1275
- indexRef.current = ScrollAreaViewport.findNonDisabledListIndex(listRef, {
1276
- startingIndex: currentIndex,
1277
- disabledIndices
1278
- });
1279
- }
1280
- } else {
1281
- indexRef.current = Math.min(maxIndex, ScrollAreaViewport.findNonDisabledListIndex(listRef, {
1282
- startingIndex: currentIndex,
1283
- disabledIndices
1284
- }));
1285
- }
1286
- } else if (loopFocus) {
1287
- if (currentIndex <= minIndex) {
1288
- if (allowEscape && currentIndex !== -1) {
1289
- indexRef.current = listRef.current.length;
1290
- } else {
1291
- // Give time for virtualizers to update the listRef.
1292
- forceSyncFocusRef.current = false;
1293
- indexRef.current = maxIndex;
1294
- }
1295
- } else {
1296
- indexRef.current = ScrollAreaViewport.findNonDisabledListIndex(listRef, {
1297
- startingIndex: currentIndex,
1298
- decrement: true,
1299
- disabledIndices
1300
- });
1301
- }
1302
- } else {
1303
- indexRef.current = Math.max(minIndex, ScrollAreaViewport.findNonDisabledListIndex(listRef, {
1304
- startingIndex: currentIndex,
1305
- decrement: true,
1306
- disabledIndices
1307
- }));
1308
- }
1309
- if (ScrollAreaViewport.isIndexOutOfListBounds(listRef, indexRef.current)) {
1310
- indexRef.current = -1;
1311
- }
1312
- onNavigate(event);
1313
- }
1314
- });
1315
- const ariaActiveDescendantProp = React__namespace.useMemo(() => {
1316
- return virtual && open && hasActiveIndex && {
1317
- 'aria-activedescendant': `${id}-${activeIndex}`
1318
- };
1319
- }, [virtual, open, hasActiveIndex, id, activeIndex]);
1320
- const floating = React__namespace.useMemo(() => {
1321
- return {
1322
- 'aria-orientation': orientation === 'both' ? undefined : orientation,
1323
- ...(!typeableComboboxReference ? ariaActiveDescendantProp : {}),
1324
- onKeyDown(event) {
1325
- // Close submenu on Shift+Tab
1326
- if (event.key === 'Tab' && event.shiftKey && open && !virtual) {
1327
- // If the event originated from within a nested element (e.g., a Dialog opened from
1328
- // within the menu), don't close the menu. The nested element has its own focus
1329
- // management and should handle the Tab key.
1330
- const target = clamp.getTarget(event.nativeEvent);
1331
- if (target && !clamp.contains(floatingFocusElementRef.current, target)) {
1332
- return;
1333
- }
1334
- clamp.stopEvent(event);
1335
- store.setOpen(false, clamp.createChangeEventDetails(clamp.focusOut, event.nativeEvent));
1336
- if (floatingUi_utils_dom.isHTMLElement(domReferenceElement)) {
1337
- domReferenceElement.focus();
1338
- }
1339
- return;
1340
- }
1341
- commonOnKeyDown(event);
1342
- },
1343
- onPointerMove() {
1344
- isPointerModalityRef.current = true;
1345
- }
1346
- };
1347
- }, [ariaActiveDescendantProp, commonOnKeyDown, floatingFocusElementRef, orientation, typeableComboboxReference, store, open, virtual, domReferenceElement]);
1348
- const trigger = React__namespace.useMemo(() => {
1349
- function checkVirtualMouse(event) {
1350
- if (focusItemOnOpen === 'auto' && clamp.isVirtualClick(event.nativeEvent)) {
1351
- focusItemOnOpenRef.current = !virtual;
1352
- }
1353
- }
1354
- function checkVirtualPointer(event) {
1355
- // `pointerdown` fires first, reset the state then perform the checks.
1356
- focusItemOnOpenRef.current = focusItemOnOpen;
1357
- if (focusItemOnOpen === 'auto' && clamp.isVirtualPointerEvent(event.nativeEvent)) {
1358
- focusItemOnOpenRef.current = true;
1359
- }
1360
- }
1361
- return {
1362
- onKeyDown(event) {
1363
- // non-reactive open state (to prevent re-creation of the handler)
1364
- const currentOpen = store.select('open');
1365
- isPointerModalityRef.current = false;
1366
- const isArrowKey = event.key.startsWith('Arrow');
1367
- const isParentCrossOpenKey = isCrossOrientationOpenKey(event.key, getParentOrientation(), rtl);
1368
- const isMainKey = isMainOrientationKey(event.key, orientation);
1369
- const isNavigationKey = (nested ? isParentCrossOpenKey : isMainKey) || event.key === 'Enter' || event.key.trim() === '';
1370
- if (virtual && currentOpen) {
1371
- return commonOnKeyDown(event);
1372
- }
1373
-
1374
- // If a floating element should not open on arrow key down, avoid
1375
- // setting `activeIndex` while it's closed.
1376
- if (!currentOpen && !openOnArrowKeyDown && isArrowKey) {
1377
- return undefined;
1378
- }
1379
- if (isNavigationKey) {
1380
- const isParentMainKey = isMainOrientationKey(event.key, getParentOrientation());
1381
- keyRef.current = nested && isParentMainKey ? null : event.key;
1382
- }
1383
- if (nested) {
1384
- if (isParentCrossOpenKey) {
1385
- clamp.stopEvent(event);
1386
- if (currentOpen) {
1387
- indexRef.current = ScrollAreaViewport.getMinListIndex(listRef, disabledIndicesRef.current);
1388
- onNavigate(event);
1389
- } else {
1390
- store.setOpen(true, clamp.createChangeEventDetails(clamp.listNavigation, event.nativeEvent, event.currentTarget));
1391
- }
1392
- }
1393
- return undefined;
1394
- }
1395
- if (isMainKey) {
1396
- if (selectedIndexRef.current != null) {
1397
- indexRef.current = selectedIndexRef.current;
1398
- }
1399
- clamp.stopEvent(event);
1400
- if (!currentOpen && openOnArrowKeyDown) {
1401
- store.setOpen(true, clamp.createChangeEventDetails(clamp.listNavigation, event.nativeEvent, event.currentTarget));
1402
- } else {
1403
- commonOnKeyDown(event);
1404
- }
1405
- if (currentOpen) {
1406
- onNavigate(event);
1407
- }
1408
- }
1409
- return undefined;
1410
- },
1411
- onFocus(event) {
1412
- if (store.select('open') && !virtual) {
1413
- indexRef.current = -1;
1414
- onNavigate(event);
1415
- }
1416
- },
1417
- onPointerDown: checkVirtualPointer,
1418
- onPointerEnter: checkVirtualPointer,
1419
- onMouseDown: checkVirtualMouse,
1420
- onClick: checkVirtualMouse
1421
- };
1422
- }, [commonOnKeyDown, disabledIndicesRef, focusItemOnOpen, listRef, nested, onNavigate, store, openOnArrowKeyDown, orientation, getParentOrientation, rtl, selectedIndexRef, virtual]);
1423
- const reference = React__namespace.useMemo(() => {
1424
- return {
1425
- ...ariaActiveDescendantProp,
1426
- ...trigger
1427
- };
1428
- }, [ariaActiveDescendantProp, trigger]);
1429
- return React__namespace.useMemo(() => enabled ? {
1430
- reference,
1431
- floating,
1432
- item,
1433
- trigger
1434
- } : {}, [enabled, reference, floating, trigger, item]);
1435
- }
1436
-
1437
- /**
1438
- * Provides a matching callback that can be used to focus an item as the user
1439
- * types, often used in tandem with `useListNavigation()`.
1440
- * @see https://floating-ui.com/docs/useTypeahead
1441
- */
1442
- function useTypeahead(context, props) {
1443
- const store = 'rootStore' in context ? context.rootStore : context;
1444
- const dataRef = store.context.dataRef;
1445
- const open = store.useState('open');
1446
- const {
1447
- listRef,
1448
- elementsRef,
1449
- activeIndex,
1450
- onMatch: onMatchProp,
1451
- onTypingChange,
1452
- enabled = true,
1453
- resetMs = 750,
1454
- selectedIndex = null
1455
- } = props;
1456
- const timeout = clamp.useTimeout();
1457
- const stringRef = React__namespace.useRef('');
1458
- const prevIndexRef = React__namespace.useRef(selectedIndex ?? activeIndex ?? -1);
1459
- const matchIndexRef = React__namespace.useRef(null);
1460
- clamp.useIsoLayoutEffect(() => {
1461
- if (!open && selectedIndex !== null) {
1462
- return;
1463
- }
1464
- timeout.clear();
1465
- matchIndexRef.current = null;
1466
- if (stringRef.current !== '') {
1467
- stringRef.current = '';
1468
- }
1469
- }, [open, selectedIndex, timeout]);
1470
- clamp.useIsoLayoutEffect(() => {
1471
- // Sync arrow key navigation but not typeahead navigation.
1472
- if (open && stringRef.current === '') {
1473
- prevIndexRef.current = selectedIndex ?? activeIndex ?? -1;
1474
- }
1475
- }, [open, selectedIndex, activeIndex]);
1476
- const setTypingChange = clamp.useStableCallback(value => {
1477
- if (value) {
1478
- if (!dataRef.current.typing) {
1479
- dataRef.current.typing = value;
1480
- onTypingChange?.(value);
1481
- }
1482
- } else if (dataRef.current.typing) {
1483
- dataRef.current.typing = value;
1484
- onTypingChange?.(value);
1485
- }
1486
- });
1487
- const onKeyDown = clamp.useStableCallback(event => {
1488
- function isVisible(index) {
1489
- const element = elementsRef?.current[index];
1490
- return !element || ScrollAreaViewport.isElementVisible(element);
1491
- }
1492
- function getMatchingIndex(list, string, startIndex = 0) {
1493
- if (list.length === 0) {
1494
- return -1;
1495
- }
1496
- const normalizedStartIndex = (startIndex % list.length + list.length) % list.length;
1497
- const lowerString = string.toLocaleLowerCase();
1498
- for (let offset = 0; offset < list.length; offset += 1) {
1499
- const index = (normalizedStartIndex + offset) % list.length;
1500
- const text = list[index];
1501
- if (!text?.toLocaleLowerCase().startsWith(lowerString) || !isVisible(index)) {
1502
- continue;
1503
- }
1504
- return index;
1505
- }
1506
- return -1;
1507
- }
1508
- const listContent = listRef.current;
1509
- if (stringRef.current.length > 0 && event.key === ' ') {
1510
- // Space should continue the in-progress typeahead session.
1511
- clamp.stopEvent(event);
1512
- setTypingChange(true);
1513
- }
1514
- if (stringRef.current.length > 0 && stringRef.current[0] !== ' ') {
1515
- if (getMatchingIndex(listContent, stringRef.current) === -1 && event.key !== ' ') {
1516
- setTypingChange(false);
1517
- }
1518
- }
1519
- if (listContent == null ||
1520
- // Character key.
1521
- event.key.length !== 1 ||
1522
- // Modifier key.
1523
- event.ctrlKey || event.metaKey || event.altKey) {
1524
- return;
1525
- }
1526
- if (open && event.key !== ' ') {
1527
- clamp.stopEvent(event);
1528
- setTypingChange(true);
1529
- }
1530
-
1531
- // Capture whether this is a new typing session before mutating the string.
1532
- const isNewSession = stringRef.current === '';
1533
- if (isNewSession) {
1534
- prevIndexRef.current = selectedIndex ?? activeIndex ?? -1;
1535
- }
1536
-
1537
- // Bail out if the list contains a word like "llama" or "aaron". TODO:
1538
- // allow it in this case, too.
1539
- const allowRapidSuccessionOfFirstLetter = listContent.every(text => text ? text[0]?.toLocaleLowerCase() !== text[1]?.toLocaleLowerCase() : true);
1540
-
1541
- // Allows the user to cycle through items that start with the same letter
1542
- // in rapid succession.
1543
- if (allowRapidSuccessionOfFirstLetter && stringRef.current === event.key) {
1544
- stringRef.current = '';
1545
- prevIndexRef.current = matchIndexRef.current;
1546
- }
1547
- stringRef.current += event.key;
1548
- timeout.start(resetMs, () => {
1549
- stringRef.current = '';
1550
- prevIndexRef.current = matchIndexRef.current;
1551
- setTypingChange(false);
1552
- });
1553
-
1554
- // Compute the starting index for this search.
1555
- // If this is a new typing session (string is empty), base it on the current
1556
- // selection/active item; otherwise continue from the last matched index.
1557
- const prevIndex = isNewSession ? selectedIndex ?? activeIndex ?? -1 : prevIndexRef.current;
1558
- const startIndex = (prevIndex ?? 0) + 1;
1559
- const index = getMatchingIndex(listContent, stringRef.current, startIndex);
1560
- if (index !== -1) {
1561
- onMatchProp?.(index);
1562
- matchIndexRef.current = index;
1563
- } else if (event.key !== ' ') {
1564
- stringRef.current = '';
1565
- setTypingChange(false);
1566
- }
1567
- });
1568
- const onBlur = clamp.useStableCallback(event => {
1569
- const next = event.relatedTarget;
1570
- const currentDomReferenceElement = store.select('domReferenceElement');
1571
- const currentFloatingElement = store.select('floatingElement');
1572
- const withinReference = clamp.contains(currentDomReferenceElement, next);
1573
- const withinFloating = clamp.contains(currentFloatingElement, next);
1574
-
1575
- // Keep the session if focus moves within the composite (reference <-> floating).
1576
- if (withinReference || withinFloating) {
1577
- return;
1578
- }
1579
-
1580
- // End the current typing session when focus leaves the composite entirely.
1581
- timeout.clear();
1582
- stringRef.current = '';
1583
- prevIndexRef.current = matchIndexRef.current;
1584
- setTypingChange(false);
1585
- });
1586
- const reference = React__namespace.useMemo(() => ({
1587
- onKeyDown,
1588
- onBlur
1589
- }), [onKeyDown, onBlur]);
1590
- const floating = React__namespace.useMemo(() => {
1591
- return {
1592
- onKeyDown,
1593
- onBlur
1594
- };
1595
- }, [onKeyDown, onBlur]);
1596
- return React__namespace.useMemo(() => enabled ? {
1597
- reference,
1598
- floating
1599
- } : {}, [enabled, reference, floating]);
1600
- }
1601
-
1602
696
  /* eslint-disable no-nested-ternary */
1603
697
 
1604
698
  const CURSOR_SPEED_THRESHOLD = 0.1;
@@ -1642,7 +736,7 @@ function safePolygon(options = {}) {
1642
736
  const {
1643
737
  blockPointerEvents = false
1644
738
  } = options;
1645
- const timeout = new clamp.Timeout();
739
+ const timeout = new useButton.Timeout();
1646
740
  const fn = ({
1647
741
  x,
1648
742
  y,
@@ -1690,10 +784,10 @@ function safePolygon(options = {}) {
1690
784
  clientX,
1691
785
  clientY
1692
786
  } = event;
1693
- const target = clamp.getTarget(event);
787
+ const target = useButton.getTarget(event);
1694
788
  const isLeave = event.type === 'mouseleave';
1695
- const isOverFloatingEl = clamp.contains(floating, target);
1696
- const isOverReferenceEl = clamp.contains(domReference, target);
789
+ const isOverFloatingEl = useButton.contains(floating, target);
790
+ const isOverReferenceEl = useButton.contains(domReference, target);
1697
791
  if (isOverFloatingEl) {
1698
792
  hasLanded = true;
1699
793
  if (!isLeave) {
@@ -1710,11 +804,11 @@ function safePolygon(options = {}) {
1710
804
 
1711
805
  // Prevent overlapping floating element from being stuck in an open-close
1712
806
  // loop: https://github.com/floating-ui/floating-ui/issues/1910
1713
- if (isLeave && floatingUi_utils_dom.isElement(event.relatedTarget) && clamp.contains(floating, event.relatedTarget)) {
807
+ if (isLeave && floatingUi_utils_dom.isElement(event.relatedTarget) && useButton.contains(floating, event.relatedTarget)) {
1714
808
  return undefined;
1715
809
  }
1716
810
  function hasOpenChildNode() {
1717
- return Boolean(tree && ScrollAreaViewport.getNodeChildren(tree.nodesRef.current, nodeId).length > 0);
811
+ return Boolean(tree && InternalBackdrop.getNodeChildren(tree.nodesRef.current, nodeId).length > 0);
1718
812
  }
1719
813
  function closeIfNoOpenChild() {
1720
814
  if (!hasOpenChildNode()) {
@@ -1840,852 +934,6 @@ function safePolygon(options = {}) {
1840
934
  return fn;
1841
935
  }
1842
936
 
1843
- function getPseudoElementBounds(element) {
1844
- const elementRect = element.getBoundingClientRect();
1845
-
1846
- // Avoid "Not implemented: window.getComputedStyle(elt, pseudoElt)"
1847
- if (process.env.NODE_ENV !== 'production') {
1848
- return elementRect;
1849
- }
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;
1855
- }
1856
-
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;
1862
-
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);
1866
-
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
- };
1876
- }
1877
-
1878
- const CompositeListContext = /*#__PURE__*/React__namespace.createContext({
1879
- register: () => {},
1880
- unregister: () => {},
1881
- subscribeMapChange: () => {
1882
- return () => {};
1883
- },
1884
- elementsRef: {
1885
- current: []
1886
- },
1887
- nextIndexRef: {
1888
- current: 0
1889
- }
1890
- });
1891
- if (process.env.NODE_ENV !== "production") CompositeListContext.displayName = "CompositeListContext";
1892
- function useCompositeListContext() {
1893
- return React__namespace.useContext(CompositeListContext);
1894
- }
1895
-
1896
- /* eslint-disable no-bitwise */
1897
- /**
1898
- * Provides context for a list of items in a composite component.
1899
- * @internal
1900
- */
1901
- function CompositeList(props) {
1902
- const {
1903
- children,
1904
- elementsRef,
1905
- labelsRef,
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) {
1950
- return undefined;
1951
- }
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);
1962
- }
1963
- });
1964
- sortedMap.forEach((_, node) => {
1965
- if (node.parentElement) {
1966
- mutationObserver.observe(node.parentElement, {
1967
- childList: true
1968
- });
1969
- }
1970
- });
1971
- return () => {
1972
- mutationObserver.disconnect();
1973
- };
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;
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
- };
2005
- });
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
2020
- });
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
- }
2038
-
2039
- /**
2040
- * Fork of the original `arrow` middleware from Floating UI that allows
2041
- * configuring the offset parent.
2042
- */
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
2069
- };
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];
2085
- }
2086
- const centerToReference = endDiff / 2 - startDiff / 2;
2087
-
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
- }
2120
- });
2121
-
2122
- /**
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
2127
- */
2128
- const arrow = (options, deps) => ({
2129
- ...baseArrow(options),
2130
- options: [options, deps]
2131
- });
2132
-
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
- };
2149
- }
2150
- };
2151
-
2152
- const DEFAULT_SIDES = {
2153
- sideX: 'left',
2154
- sideY: 'top'
2155
- };
2156
- const adaptiveOrigin = {
2157
- name: 'adaptiveOrigin',
2158
- async fn(state) {
2159
- const {
2160
- x: rawX,
2161
- y: rawY,
2162
- rects: {
2163
- floating: floatRect
2164
- },
2165
- elements: {
2166
- floating
2167
- },
2168
- platform,
2169
- strategy,
2170
- placement
2171
- } = state;
2172
- const win = floatingUi_utils_dom.getWindow(floating);
2173
- const styles = win.getComputedStyle(floating);
2174
- const hasTransition = styles.transitionDuration !== '0s' && styles.transitionDuration !== '';
2175
- if (!hasTransition) {
2176
- return {
2177
- x: rawX,
2178
- y: rawY,
2179
- data: DEFAULT_SIDES
2180
- };
2181
- }
2182
- const offsetParent = await platform.getOffsetParent?.(floating);
2183
- let offsetDimensions = {
2184
- width: 0,
2185
- height: 0
2186
- };
2187
-
2188
- // For fixed strategy, prefer visualViewport if available
2189
- if (strategy === 'fixed' && win?.visualViewport) {
2190
- offsetDimensions = {
2191
- width: win.visualViewport.width,
2192
- height: win.visualViewport.height
2193
- };
2194
- } else if (offsetParent === win) {
2195
- const doc = clamp.ownerDocument(floating);
2196
- offsetDimensions = {
2197
- width: doc.documentElement.clientWidth,
2198
- height: doc.documentElement.clientHeight
2199
- };
2200
- } else if (await platform.isElement?.(offsetParent)) {
2201
- offsetDimensions = await platform.getDimensions(offsetParent);
2202
- }
2203
- const currentSide = index_esm.getSide(placement);
2204
- let x = rawX;
2205
- let y = rawY;
2206
- if (currentSide === 'left') {
2207
- x = offsetDimensions.width - (rawX + floatRect.width);
2208
- }
2209
- if (currentSide === 'top') {
2210
- y = offsetDimensions.height - (rawY + floatRect.height);
2211
- }
2212
- const sideX = currentSide === 'left' ? 'right' : DEFAULT_SIDES.sideX;
2213
- const sideY = currentSide === 'top' ? 'bottom' : DEFAULT_SIDES.sideY;
2214
- return {
2215
- x,
2216
- y,
2217
- data: {
2218
- sideX,
2219
- sideY
2220
- }
2221
- };
2222
- }
2223
- };
2224
-
2225
- function getLogicalSide(sideParam, renderedSide, isRtl) {
2226
- const isLogicalSideParam = sideParam === 'inline-start' || sideParam === 'inline-end';
2227
- const logicalRight = isRtl ? 'inline-start' : 'inline-end';
2228
- const logicalLeft = isRtl ? 'inline-end' : 'inline-start';
2229
- return {
2230
- top: 'top',
2231
- right: isLogicalSideParam ? logicalRight : 'right',
2232
- bottom: 'bottom',
2233
- left: isLogicalSideParam ? logicalLeft : 'left'
2234
- }[renderedSide];
2235
- }
2236
- function getOffsetData(state, sideParam, isRtl) {
2237
- const {
2238
- rects,
2239
- placement
2240
- } = state;
2241
- const data = {
2242
- side: getLogicalSide(sideParam, index_esm.getSide(placement), isRtl),
2243
- align: index_esm.getAlignment(placement) || 'center',
2244
- anchor: {
2245
- width: rects.reference.width,
2246
- height: rects.reference.height
2247
- },
2248
- positioner: {
2249
- width: rects.floating.width,
2250
- height: rects.floating.height
2251
- }
2252
- };
2253
- return data;
2254
- }
2255
- /**
2256
- * Provides standardized anchor positioning behavior for floating elements. Wraps Floating UI's
2257
- * `useFloating` hook.
2258
- */
2259
- function useAnchorPositioning(params) {
2260
- const {
2261
- // Public parameters
2262
- anchor,
2263
- positionMethod = 'absolute',
2264
- side: sideParam = 'bottom',
2265
- sideOffset = 0,
2266
- align = 'center',
2267
- alignOffset = 0,
2268
- collisionBoundary,
2269
- collisionPadding: collisionPaddingParam = 5,
2270
- sticky = false,
2271
- arrowPadding = 5,
2272
- disableAnchorTracking = false,
2273
- // Private parameters
2274
- keepMounted = false,
2275
- floatingRootContext,
2276
- mounted,
2277
- collisionAvoidance,
2278
- shiftCrossAxis = false,
2279
- nodeId,
2280
- adaptiveOrigin,
2281
- lazyFlip = false,
2282
- externalTree
2283
- } = params;
2284
- const [mountSide, setMountSide] = React__namespace.useState(null);
2285
- if (!mounted && mountSide !== null) {
2286
- setMountSide(null);
2287
- }
2288
- const collisionAvoidanceSide = collisionAvoidance.side || 'flip';
2289
- const collisionAvoidanceAlign = collisionAvoidance.align || 'flip';
2290
- const collisionAvoidanceFallbackAxisSide = collisionAvoidance.fallbackAxisSide || 'end';
2291
- const anchorFn = typeof anchor === 'function' ? anchor : undefined;
2292
- const anchorFnCallback = clamp.useStableCallback(anchorFn);
2293
- const anchorDep = anchorFn ? anchorFnCallback : anchor;
2294
- const anchorValueRef = clamp.useValueAsRef(anchor);
2295
- const direction = ScrollAreaViewport.useDirection();
2296
- const isRtl = direction === 'rtl';
2297
- const side = mountSide || {
2298
- top: 'top',
2299
- right: 'right',
2300
- bottom: 'bottom',
2301
- left: 'left',
2302
- 'inline-end': isRtl ? 'left' : 'right',
2303
- 'inline-start': isRtl ? 'right' : 'left'
2304
- }[sideParam];
2305
- const placement = align === 'center' ? side : `${side}-${align}`;
2306
- let collisionPadding = collisionPaddingParam;
2307
-
2308
- // Create a bias to the preferred side.
2309
- // On iOS, when the mobile software keyboard opens, the input is exactly centered
2310
- // in the viewport, but this can cause it to flip to the top undesirably.
2311
- const bias = 1;
2312
- const biasTop = sideParam === 'bottom' ? bias : 0;
2313
- const biasBottom = sideParam === 'top' ? bias : 0;
2314
- const biasLeft = sideParam === 'right' ? bias : 0;
2315
- const biasRight = sideParam === 'left' ? bias : 0;
2316
- if (typeof collisionPadding === 'number') {
2317
- collisionPadding = {
2318
- top: collisionPadding + biasTop,
2319
- right: collisionPadding + biasRight,
2320
- bottom: collisionPadding + biasBottom,
2321
- left: collisionPadding + biasLeft
2322
- };
2323
- } else if (collisionPadding) {
2324
- collisionPadding = {
2325
- top: (collisionPadding.top || 0) + biasTop,
2326
- right: (collisionPadding.right || 0) + biasRight,
2327
- bottom: (collisionPadding.bottom || 0) + biasBottom,
2328
- left: (collisionPadding.left || 0) + biasLeft
2329
- };
2330
- }
2331
- const commonCollisionProps = {
2332
- boundary: collisionBoundary === 'clipping-ancestors' ? 'clippingAncestors' : collisionBoundary,
2333
- padding: collisionPadding
2334
- };
2335
-
2336
- // Using a ref assumes that the arrow element is always present in the DOM for the lifetime of the
2337
- // popup. If this assumption ends up being false, we can switch to state to manage the arrow's
2338
- // presence.
2339
- const arrowRef = React__namespace.useRef(null);
2340
-
2341
- // Keep these reactive if they're not functions
2342
- const sideOffsetRef = clamp.useValueAsRef(sideOffset);
2343
- const alignOffsetRef = clamp.useValueAsRef(alignOffset);
2344
- const sideOffsetDep = typeof sideOffset !== 'function' ? sideOffset : 0;
2345
- const alignOffsetDep = typeof alignOffset !== 'function' ? alignOffset : 0;
2346
- const middleware = [floatingUi_reactDom.offset(state => {
2347
- const data = getOffsetData(state, sideParam, isRtl);
2348
- const sideAxis = typeof sideOffsetRef.current === 'function' ? sideOffsetRef.current(data) : sideOffsetRef.current;
2349
- const alignAxis = typeof alignOffsetRef.current === 'function' ? alignOffsetRef.current(data) : alignOffsetRef.current;
2350
- return {
2351
- mainAxis: sideAxis,
2352
- crossAxis: alignAxis,
2353
- alignmentAxis: alignAxis
2354
- };
2355
- }, [sideOffsetDep, alignOffsetDep, isRtl, sideParam])];
2356
- const shiftDisabled = collisionAvoidanceAlign === 'none' && collisionAvoidanceSide !== 'shift';
2357
- const crossAxisShiftEnabled = !shiftDisabled && (sticky || shiftCrossAxis || collisionAvoidanceSide === 'shift');
2358
- const flipMiddleware = collisionAvoidanceSide === 'none' ? null : floatingUi_reactDom.flip({
2359
- ...commonCollisionProps,
2360
- // Ensure the popup flips if it's been limited by its --available-height and it resizes.
2361
- // Since the size() padding is smaller than the flip() padding, flip() will take precedence.
2362
- padding: {
2363
- top: collisionPadding.top + bias,
2364
- right: collisionPadding.right + bias,
2365
- bottom: collisionPadding.bottom + bias,
2366
- left: collisionPadding.left + bias
2367
- },
2368
- mainAxis: !shiftCrossAxis && collisionAvoidanceSide === 'flip',
2369
- crossAxis: collisionAvoidanceAlign === 'flip' ? 'alignment' : false,
2370
- fallbackAxisSideDirection: collisionAvoidanceFallbackAxisSide
2371
- });
2372
- const shiftMiddleware = shiftDisabled ? null : floatingUi_reactDom.shift(data => {
2373
- const html = clamp.ownerDocument(data.elements.floating).documentElement;
2374
- return {
2375
- ...commonCollisionProps,
2376
- // Use the Layout Viewport to avoid shifting around when pinch-zooming
2377
- // for context menus.
2378
- rootBoundary: shiftCrossAxis ? {
2379
- x: 0,
2380
- y: 0,
2381
- width: html.clientWidth,
2382
- height: html.clientHeight
2383
- } : undefined,
2384
- mainAxis: collisionAvoidanceAlign !== 'none',
2385
- crossAxis: crossAxisShiftEnabled,
2386
- limiter: sticky || shiftCrossAxis ? undefined : floatingUi_reactDom.limitShift(limitData => {
2387
- if (!arrowRef.current) {
2388
- return {};
2389
- }
2390
- const {
2391
- width,
2392
- height
2393
- } = arrowRef.current.getBoundingClientRect();
2394
- const sideAxis = index_esm.getSideAxis(index_esm.getSide(limitData.placement));
2395
- const arrowSize = sideAxis === 'y' ? width : height;
2396
- const offsetAmount = sideAxis === 'y' ? collisionPadding.left + collisionPadding.right : collisionPadding.top + collisionPadding.bottom;
2397
- return {
2398
- offset: arrowSize / 2 + offsetAmount / 2
2399
- };
2400
- })
2401
- };
2402
- }, [commonCollisionProps, sticky, shiftCrossAxis, collisionPadding, collisionAvoidanceAlign]);
2403
-
2404
- // https://floating-ui.com/docs/flip#combining-with-shift
2405
- if (collisionAvoidanceSide === 'shift' || collisionAvoidanceAlign === 'shift' || align === 'center') {
2406
- middleware.push(shiftMiddleware, flipMiddleware);
2407
- } else {
2408
- middleware.push(flipMiddleware, shiftMiddleware);
2409
- }
2410
- middleware.push(floatingUi_reactDom.size({
2411
- ...commonCollisionProps,
2412
- apply({
2413
- elements: {
2414
- floating
2415
- },
2416
- availableWidth,
2417
- availableHeight,
2418
- rects
2419
- }) {
2420
- const floatingStyle = floating.style;
2421
- floatingStyle.setProperty('--available-width', `${availableWidth}px`);
2422
- floatingStyle.setProperty('--available-height', `${availableHeight}px`);
2423
-
2424
- // Snap anchor dimensions to device pixels to ensure the popup's visual width matches the anchor's one.
2425
- const dpr = window.devicePixelRatio || 1;
2426
- const {
2427
- x,
2428
- y,
2429
- width,
2430
- height
2431
- } = rects.reference;
2432
- const anchorWidth = (Math.round((x + width) * dpr) - Math.round(x * dpr)) / dpr;
2433
- const anchorHeight = (Math.round((y + height) * dpr) - Math.round(y * dpr)) / dpr;
2434
- floatingStyle.setProperty('--anchor-width', `${anchorWidth}px`);
2435
- floatingStyle.setProperty('--anchor-height', `${anchorHeight}px`);
2436
- }
2437
- }), arrow(() => ({
2438
- // `transform-origin` calculations rely on an element existing. If the arrow hasn't been set,
2439
- // we'll create a fake element.
2440
- element: arrowRef.current || document.createElement('div'),
2441
- padding: arrowPadding,
2442
- offsetParent: 'floating'
2443
- }), [arrowPadding]), {
2444
- name: 'transformOrigin',
2445
- fn(state) {
2446
- const {
2447
- elements,
2448
- middlewareData,
2449
- placement: renderedPlacement,
2450
- rects,
2451
- y
2452
- } = state;
2453
- const currentRenderedSide = index_esm.getSide(renderedPlacement);
2454
- const currentRenderedAxis = index_esm.getSideAxis(currentRenderedSide);
2455
- const arrowEl = arrowRef.current;
2456
- const arrowX = middlewareData.arrow?.x || 0;
2457
- const arrowY = middlewareData.arrow?.y || 0;
2458
- const arrowWidth = arrowEl?.clientWidth || 0;
2459
- const arrowHeight = arrowEl?.clientHeight || 0;
2460
- const transformX = arrowX + arrowWidth / 2;
2461
- const transformY = arrowY + arrowHeight / 2;
2462
- const shiftY = Math.abs(middlewareData.shift?.y || 0);
2463
- const halfAnchorHeight = rects.reference.height / 2;
2464
- const sideOffsetValue = typeof sideOffset === 'function' ? sideOffset(getOffsetData(state, sideParam, isRtl)) : sideOffset;
2465
- const isOverlappingAnchor = shiftY > sideOffsetValue;
2466
- const adjacentTransformOrigin = {
2467
- top: `${transformX}px calc(100% + ${sideOffsetValue}px)`,
2468
- bottom: `${transformX}px ${-sideOffsetValue}px`,
2469
- left: `calc(100% + ${sideOffsetValue}px) ${transformY}px`,
2470
- right: `${-sideOffsetValue}px ${transformY}px`
2471
- }[currentRenderedSide];
2472
- const overlapTransformOrigin = `${transformX}px ${rects.reference.y + halfAnchorHeight - y}px`;
2473
- elements.floating.style.setProperty('--transform-origin', crossAxisShiftEnabled && currentRenderedAxis === 'y' && isOverlappingAnchor ? overlapTransformOrigin : adjacentTransformOrigin);
2474
- return {};
2475
- }
2476
- }, hide, adaptiveOrigin);
2477
- clamp.useIsoLayoutEffect(() => {
2478
- // Ensure positioning doesn't run initially for `keepMounted` elements that
2479
- // aren't initially open.
2480
- if (!mounted && floatingRootContext) {
2481
- floatingRootContext.update({
2482
- referenceElement: null,
2483
- floatingElement: null,
2484
- domReferenceElement: null
2485
- });
2486
- }
2487
- }, [mounted, floatingRootContext]);
2488
- const autoUpdateOptions = React__namespace.useMemo(() => ({
2489
- elementResize: !disableAnchorTracking && typeof ResizeObserver !== 'undefined',
2490
- layoutShift: !disableAnchorTracking && typeof IntersectionObserver !== 'undefined'
2491
- }), [disableAnchorTracking]);
2492
- const {
2493
- refs,
2494
- elements,
2495
- x,
2496
- y,
2497
- middlewareData,
2498
- update,
2499
- placement: renderedPlacement,
2500
- context,
2501
- isPositioned,
2502
- floatingStyles: originalFloatingStyles
2503
- } = useFloating({
2504
- rootContext: floatingRootContext,
2505
- placement,
2506
- middleware,
2507
- strategy: positionMethod,
2508
- whileElementsMounted: keepMounted ? undefined : (...args) => floatingUi_reactDom.autoUpdate(...args, autoUpdateOptions),
2509
- nodeId,
2510
- externalTree
2511
- });
2512
- const {
2513
- sideX,
2514
- sideY
2515
- } = middlewareData.adaptiveOrigin || DEFAULT_SIDES;
2516
-
2517
- // Default to `fixed` when not positioned to prevent `autoFocus` scroll jumps.
2518
- // This ensures the popup is inside the viewport initially before it gets positioned.
2519
- const resolvedPosition = isPositioned ? positionMethod : 'fixed';
2520
- const floatingStyles = React__namespace.useMemo(() => {
2521
- const base = adaptiveOrigin ? {
2522
- position: resolvedPosition,
2523
- [sideX]: x,
2524
- [sideY]: y
2525
- } : {
2526
- position: resolvedPosition,
2527
- ...originalFloatingStyles
2528
- };
2529
- if (!isPositioned) {
2530
- base.opacity = 0;
2531
- }
2532
- return base;
2533
- }, [adaptiveOrigin, resolvedPosition, sideX, x, sideY, y, originalFloatingStyles, isPositioned]);
2534
- const registeredPositionReferenceRef = React__namespace.useRef(null);
2535
- clamp.useIsoLayoutEffect(() => {
2536
- if (!mounted) {
2537
- return;
2538
- }
2539
- const anchorValue = anchorValueRef.current;
2540
- const resolvedAnchor = typeof anchorValue === 'function' ? anchorValue() : anchorValue;
2541
- const unwrappedElement = (isRef(resolvedAnchor) ? resolvedAnchor.current : resolvedAnchor) || null;
2542
- const finalAnchor = unwrappedElement || null;
2543
- if (finalAnchor !== registeredPositionReferenceRef.current) {
2544
- refs.setPositionReference(finalAnchor);
2545
- registeredPositionReferenceRef.current = finalAnchor;
2546
- }
2547
- }, [mounted, refs, anchorDep, anchorValueRef]);
2548
- React__namespace.useEffect(() => {
2549
- if (!mounted) {
2550
- return;
2551
- }
2552
- const anchorValue = anchorValueRef.current;
2553
-
2554
- // Refs from parent components are set after useLayoutEffect runs and are available in useEffect.
2555
- // Therefore, if the anchor is a ref, we need to update the position reference in useEffect.
2556
- if (typeof anchorValue === 'function') {
2557
- return;
2558
- }
2559
- if (isRef(anchorValue) && anchorValue.current !== registeredPositionReferenceRef.current) {
2560
- refs.setPositionReference(anchorValue.current);
2561
- registeredPositionReferenceRef.current = anchorValue.current;
2562
- }
2563
- }, [mounted, refs, anchorDep, anchorValueRef]);
2564
- React__namespace.useEffect(() => {
2565
- if (keepMounted && mounted && elements.domReference && elements.floating) {
2566
- return floatingUi_reactDom.autoUpdate(elements.domReference, elements.floating, update, autoUpdateOptions);
2567
- }
2568
- return undefined;
2569
- }, [keepMounted, mounted, elements, update, autoUpdateOptions]);
2570
- const renderedSide = index_esm.getSide(renderedPlacement);
2571
- const logicalRenderedSide = getLogicalSide(sideParam, renderedSide, isRtl);
2572
- const renderedAlign = index_esm.getAlignment(renderedPlacement) || 'center';
2573
- const anchorHidden = Boolean(middlewareData.hide?.referenceHidden);
2574
-
2575
- /**
2576
- * Locks the flip (makes it "sticky") so it doesn't prefer a given placement
2577
- * and flips back lazily, not eagerly. Ideal for filtered lists that change
2578
- * the size of the popup dynamically to avoid unwanted flipping when typing.
2579
- */
2580
- clamp.useIsoLayoutEffect(() => {
2581
- if (lazyFlip && mounted && isPositioned) {
2582
- setMountSide(renderedSide);
2583
- }
2584
- }, [lazyFlip, mounted, isPositioned, renderedSide]);
2585
- const arrowStyles = React__namespace.useMemo(() => ({
2586
- position: 'absolute',
2587
- top: middlewareData.arrow?.y,
2588
- left: middlewareData.arrow?.x
2589
- }), [middlewareData.arrow]);
2590
- const arrowUncentered = middlewareData.arrow?.centerOffset !== 0;
2591
- return React__namespace.useMemo(() => ({
2592
- positionerStyles: floatingStyles,
2593
- arrowStyles,
2594
- arrowRef,
2595
- arrowUncentered,
2596
- side: logicalRenderedSide,
2597
- align: renderedAlign,
2598
- physicalSide: renderedSide,
2599
- anchorHidden,
2600
- refs,
2601
- context,
2602
- isPositioned,
2603
- update
2604
- }), [floatingStyles, arrowStyles, arrowRef, arrowUncentered, logicalRenderedSide, renderedAlign, renderedSide, anchorHidden, refs, context, isPositioned, update]);
2605
- }
2606
- function isRef(param) {
2607
- return param != null && 'current' in param;
2608
- }
2609
-
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
-
2620
- /**
2621
- * Used to register a list item and its index (DOM position) in the `CompositeList`.
2622
- */
2623
- function useCompositeListItem(params = {}) {
2624
- const {
2625
- label,
2626
- metadata,
2627
- textRef,
2628
- indexGuessBehavior,
2629
- index: externalIndex
2630
- } = params;
2631
- const {
2632
- register,
2633
- unregister,
2634
- subscribeMapChange,
2635
- elementsRef,
2636
- labelsRef,
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) {
2661
- return undefined;
2662
- }
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);
2680
- }
2681
- });
2682
- }, [externalIndex, subscribeMapChange, setIndex]);
2683
- return React__namespace.useMemo(() => ({
2684
- ref,
2685
- index
2686
- }), [index, ref]);
2687
- }
2688
-
2689
937
  /**
2690
938
  * A button that closes the dialog.
2691
939
  * Renders a `<button>` element.
@@ -2706,13 +954,13 @@ const DialogClose = /*#__PURE__*/React__namespace.forwardRef(function DialogClos
2706
954
  const open = store.useState('open');
2707
955
  function handleClick(event) {
2708
956
  if (open) {
2709
- store.setOpen(false, clamp.createChangeEventDetails(clamp.closePress, event.nativeEvent));
957
+ store.setOpen(false, useButton.createChangeEventDetails(useButton.closePress, event.nativeEvent));
2710
958
  }
2711
959
  }
2712
960
  const {
2713
961
  getButtonProps,
2714
962
  buttonRef
2715
- } = clamp.useButton({
963
+ } = useButton.useButton({
2716
964
  disabled,
2717
965
  native: nativeButton
2718
966
  });
@@ -2753,7 +1001,7 @@ const DialogTitle = /*#__PURE__*/React__namespace.forwardRef(function DialogTitl
2753
1001
  const {
2754
1002
  store
2755
1003
  } = ScrollAreaViewport.useDialogRootContext();
2756
- const id = clamp.useBaseUiId(idProp);
1004
+ const id = useButton.useBaseUiId(idProp);
2757
1005
  store.useSyncedValueWithCleanup('titleElementId', id);
2758
1006
  return useRenderElement.useRenderElement('h2', componentProps, {
2759
1007
  ref: forwardedRef,
@@ -2848,7 +1096,7 @@ function useMenuItemCommonProps(params) {
2848
1096
  if (closeOnClick) {
2849
1097
  menuEvents.emit('close', {
2850
1098
  domEvent: event,
2851
- reason: clamp.itemPress
1099
+ reason: useButton.itemPress
2852
1100
  });
2853
1101
  }
2854
1102
  },
@@ -2862,7 +1110,7 @@ function useMenuItemCommonProps(params) {
2862
1110
 
2863
1111
  // On non-macOS platforms, this mouseup belongs to the right-click gesture
2864
1112
  // that opened the context menu, so it must not activate an item.
2865
- if (isContextMenu && !clamp.isMac && event.button === 2) {
1113
+ if (isContextMenu && !useButton.isMac && event.button === 2) {
2866
1114
  return;
2867
1115
  }
2868
1116
  }
@@ -2896,7 +1144,7 @@ function useMenuItem(params) {
2896
1144
  const {
2897
1145
  getButtonProps,
2898
1146
  buttonRef
2899
- } = clamp.useButton({
1147
+ } = useButton.useButton({
2900
1148
  disabled,
2901
1149
  focusableWhenDisabled: true,
2902
1150
  native: nativeButton,
@@ -2960,7 +1208,7 @@ const itemMapping = {
2960
1208
  [MenuCheckboxItemDataAttributes.unchecked]: ''
2961
1209
  };
2962
1210
  },
2963
- ...clamp.transitionStatusMapping
1211
+ ...useButton.transitionStatusMapping
2964
1212
  };
2965
1213
 
2966
1214
  const MenuGroupContext = /*#__PURE__*/React__namespace.createContext(undefined);
@@ -3011,11 +1259,11 @@ const MenuGroupLabel = /*#__PURE__*/React__namespace.forwardRef(function MenuGro
3011
1259
  id: idProp,
3012
1260
  ...elementProps
3013
1261
  } = componentProps;
3014
- const id = clamp.useBaseUiId(idProp);
1262
+ const id = useButton.useBaseUiId(idProp);
3015
1263
  const {
3016
1264
  setLabelId
3017
1265
  } = useMenuGroupRootContext();
3018
- clamp.useIsoLayoutEffect(() => {
1266
+ useButton.useIsoLayoutEffect(() => {
3019
1267
  setLabelId(id);
3020
1268
  return () => {
3021
1269
  setLabelId(undefined);
@@ -3049,11 +1297,11 @@ const MenuItem = /*#__PURE__*/React__namespace.forwardRef(function MenuItem(comp
3049
1297
  closeOnClick = true,
3050
1298
  ...elementProps
3051
1299
  } = componentProps;
3052
- const listItem = useCompositeListItem({
1300
+ const listItem = useCompositeListItem.useCompositeListItem({
3053
1301
  label
3054
1302
  });
3055
1303
  const menuPositionerContext = useMenuPositionerContext(true);
3056
- const id = clamp.useBaseUiId(idProp);
1304
+ const id = useButton.useBaseUiId(idProp);
3057
1305
  const {
3058
1306
  store
3059
1307
  } = useMenuRootContext();
@@ -3100,12 +1348,12 @@ const MenuLinkItem = /*#__PURE__*/React__namespace.forwardRef(function MenuLinkI
3100
1348
  ...elementProps
3101
1349
  } = componentProps;
3102
1350
  const linkRef = React__namespace.useRef(null);
3103
- const listItem = useCompositeListItem({
1351
+ const listItem = useCompositeListItem.useCompositeListItem({
3104
1352
  label
3105
1353
  });
3106
1354
  const menuPositionerContext = useMenuPositionerContext(true);
3107
1355
  const nodeId = menuPositionerContext?.nodeId;
3108
- const id = clamp.useBaseUiId(idProp);
1356
+ const id = useButton.useBaseUiId(idProp);
3109
1357
  const {
3110
1358
  store
3111
1359
  } = useMenuRootContext();
@@ -3115,7 +1363,7 @@ const MenuLinkItem = /*#__PURE__*/React__namespace.forwardRef(function MenuLinkI
3115
1363
  const {
3116
1364
  getButtonProps,
3117
1365
  buttonRef
3118
- } = clamp.useButton({
1366
+ } = useButton.useButton({
3119
1367
  native: false,
3120
1368
  composite: true
3121
1369
  });
@@ -3153,8 +1401,8 @@ function useToolbarRootContext(optional) {
3153
1401
  }
3154
1402
 
3155
1403
  const stateAttributesMapping = {
3156
- ...ScrollAreaViewport.popupStateMapping,
3157
- ...clamp.transitionStatusMapping
1404
+ ...InternalBackdrop.popupStateMapping,
1405
+ ...useButton.transitionStatusMapping
3158
1406
  };
3159
1407
 
3160
1408
  /**
@@ -3192,7 +1440,7 @@ const MenuPopup = /*#__PURE__*/React__namespace.forwardRef(function MenuPopup(co
3192
1440
  const closeDelay = store.useState('closeDelay');
3193
1441
  const activeTriggerElement = store.useState('activeTriggerElement');
3194
1442
  const isContextMenu = parent.type === 'context-menu';
3195
- clamp.useOpenChangeComplete({
1443
+ useButton.useOpenChangeComplete({
3196
1444
  open,
3197
1445
  ref: store.context.popupRef,
3198
1446
  onComplete() {
@@ -3203,7 +1451,7 @@ const MenuPopup = /*#__PURE__*/React__namespace.forwardRef(function MenuPopup(co
3203
1451
  });
3204
1452
  React__namespace.useEffect(() => {
3205
1453
  function handleClose(event) {
3206
- store.setOpen(false, clamp.createChangeEventDetails(event.reason, event.domEvent));
1454
+ store.setOpen(false, useButton.createChangeEventDetails(event.reason, event.domEvent));
3207
1455
  }
3208
1456
  floatingTreeRoot.events.on('close', handleClose);
3209
1457
  return () => {
@@ -3237,15 +1485,15 @@ const MenuPopup = /*#__PURE__*/React__namespace.forwardRef(function MenuPopup(co
3237
1485
  event.stopPropagation();
3238
1486
  }
3239
1487
  }
3240
- }, getDisabledMountTransitionStyles(transitionStatus), elementProps, {
1488
+ }, useCompositeListItem.getDisabledMountTransitionStyles(transitionStatus), elementProps, {
3241
1489
  'data-rootownerid': rootId
3242
1490
  }]
3243
1491
  });
3244
1492
  let returnFocus = parent.type === undefined || isContextMenu;
3245
- if (triggerElement || parent.type === 'menubar' && lastOpenChangeReason !== clamp.outsidePress) {
1493
+ if (triggerElement || parent.type === 'menubar' && lastOpenChangeReason !== useButton.outsidePress) {
3246
1494
  returnFocus = true;
3247
1495
  }
3248
- return /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.FloatingFocusManager, {
1496
+ return /*#__PURE__*/jsxRuntime.jsx(InternalBackdrop.FloatingFocusManager, {
3249
1497
  context: floatingContext,
3250
1498
  modal: isContextMenu,
3251
1499
  disabled: !mounted,
@@ -3286,7 +1534,7 @@ const MenuPortal = /*#__PURE__*/React__namespace.forwardRef(function MenuPortal(
3286
1534
  }
3287
1535
  return /*#__PURE__*/jsxRuntime.jsx(MenuPortalContext.Provider, {
3288
1536
  value: keepMounted,
3289
- children: /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.FloatingPortal, {
1537
+ children: /*#__PURE__*/jsxRuntime.jsx(InternalBackdrop.FloatingPortal, {
3290
1538
  ref: forwardedRef,
3291
1539
  ...portalProps
3292
1540
  })
@@ -3309,7 +1557,7 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
3309
1557
  arrowPadding = 5,
3310
1558
  sticky = false,
3311
1559
  disableAnchorTracking = false,
3312
- collisionAvoidance: collisionAvoidanceProp = ScrollAreaViewport.DROPDOWN_COLLISION_AVOIDANCE,
1560
+ collisionAvoidance: collisionAvoidanceProp = InternalBackdrop.DROPDOWN_COLLISION_AVOIDANCE,
3313
1561
  ...elementProps
3314
1562
  } = componentProps;
3315
1563
  const {
@@ -3333,7 +1581,7 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
3333
1581
  const floatingParentNodeId = store.useState('floatingParentNodeId');
3334
1582
  const domReference = floatingRootContext.useState('domReferenceElement');
3335
1583
  const previousTriggerRef = React__namespace.useRef(null);
3336
- const runOnceAnimationsFinish = clamp.useAnimationsFinished(positionerElement, false, false);
1584
+ const runOnceAnimationsFinish = useButton.useAnimationsFinished(positionerElement, false, false);
3337
1585
  let anchor = anchorProp;
3338
1586
  let sideOffset = sideOffsetProp;
3339
1587
  let alignOffset = alignOffsetProp;
@@ -3352,13 +1600,13 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
3352
1600
  if (parent.type === 'menu') {
3353
1601
  computedSide = computedSide ?? 'inline-end';
3354
1602
  computedAlign = computedAlign ?? 'start';
3355
- collisionAvoidance = componentProps.collisionAvoidance ?? ScrollAreaViewport.POPUP_COLLISION_AVOIDANCE;
1603
+ collisionAvoidance = componentProps.collisionAvoidance ?? InternalBackdrop.POPUP_COLLISION_AVOIDANCE;
3356
1604
  } else if (parent.type === 'menubar') {
3357
1605
  computedSide = computedSide ?? 'bottom';
3358
1606
  computedAlign = computedAlign ?? 'start';
3359
1607
  }
3360
1608
  const contextMenu = parent.type === 'context-menu';
3361
- const positioner = useAnchorPositioning({
1609
+ const positioner = useCompositeListItem.useAnchorPositioning({
3362
1610
  anchor,
3363
1611
  floatingRootContext,
3364
1612
  positionMethod: contextMenuContext ? 'fixed' : positionMethodProp,
@@ -3377,7 +1625,7 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
3377
1625
  collisionAvoidance,
3378
1626
  shiftCrossAxis: contextMenu && !('side' in collisionAvoidance && collisionAvoidance.side === 'flip'),
3379
1627
  externalTree: floatingTreeRoot,
3380
- adaptiveOrigin: hasViewport ? adaptiveOrigin : undefined
1628
+ adaptiveOrigin: hasViewport ? useCompositeListItem.adaptiveOrigin : undefined
3381
1629
  });
3382
1630
  const positionerProps = React__namespace.useMemo(() => {
3383
1631
  const hiddenStyles = {};
@@ -3400,7 +1648,7 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
3400
1648
  store.set('hoverEnabled', false);
3401
1649
  }
3402
1650
  if (details.nodeId !== floatingNodeId && details.parentNodeId === store.select('floatingParentNodeId')) {
3403
- store.setOpen(false, clamp.createChangeEventDetails(clamp.siblingOpen));
1651
+ store.setOpen(false, useButton.createChangeEventDetails(useButton.siblingOpen));
3404
1652
  }
3405
1653
  }
3406
1654
  }
@@ -3417,15 +1665,15 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
3417
1665
  if (details.open || details.nodeId !== store.select('floatingParentNodeId')) {
3418
1666
  return;
3419
1667
  }
3420
- const reason = details.reason ?? clamp.siblingOpen;
3421
- store.setOpen(false, clamp.createChangeEventDetails(reason));
1668
+ const reason = details.reason ?? useButton.siblingOpen;
1669
+ store.setOpen(false, useButton.createChangeEventDetails(reason));
3422
1670
  }
3423
1671
  floatingTreeRoot.events.on('menuopenchange', onParentClose);
3424
1672
  return () => {
3425
1673
  floatingTreeRoot.events.off('menuopenchange', onParentClose);
3426
1674
  };
3427
1675
  }, [floatingTreeRoot.events, store]);
3428
- const closeTimeout = clamp.useTimeout();
1676
+ const closeTimeout = useButton.useTimeout();
3429
1677
 
3430
1678
  // Clear pending close timeout when the menu closes.
3431
1679
  React__namespace.useEffect(() => {
@@ -3447,11 +1695,11 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
3447
1695
  if (delay > 0) {
3448
1696
  if (!closeTimeout.isStarted()) {
3449
1697
  closeTimeout.start(delay, () => {
3450
- store.setOpen(false, clamp.createChangeEventDetails(clamp.siblingOpen));
1698
+ store.setOpen(false, useButton.createChangeEventDetails(useButton.siblingOpen));
3451
1699
  });
3452
1700
  }
3453
1701
  } else {
3454
- store.setOpen(false, clamp.createChangeEventDetails(clamp.siblingOpen));
1702
+ store.setOpen(false, useButton.createChangeEventDetails(useButton.siblingOpen));
3455
1703
  }
3456
1704
  } else {
3457
1705
  // User re-hovered the submenu trigger, cancel pending close.
@@ -3474,7 +1722,7 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
3474
1722
  }, [floatingTreeRoot.events, open, store, floatingNodeId, floatingParentNodeId]);
3475
1723
 
3476
1724
  // Keep positioner transition behavior aligned with Popover when switching detached triggers.
3477
- clamp.useIsoLayoutEffect(() => {
1725
+ useButton.useIsoLayoutEffect(() => {
3478
1726
  const currentTrigger = domReference;
3479
1727
  const previousTrigger = previousTriggerRef.current;
3480
1728
  if (currentTrigger) {
@@ -3510,11 +1758,11 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
3510
1758
  }), [positioner.side, positioner.align, positioner.arrowRef, positioner.arrowUncentered, positioner.arrowStyles, positioner.context.nodeId]);
3511
1759
  const element = useRenderElement.useRenderElement('div', componentProps, {
3512
1760
  state,
3513
- stateAttributesMapping: ScrollAreaViewport.popupStateMapping,
1761
+ stateAttributesMapping: InternalBackdrop.popupStateMapping,
3514
1762
  ref: [forwardedRef, store.useStateSetter('positionerElement')],
3515
- props: [positionerProps, getDisabledMountTransitionStyles(transitionStatus), elementProps]
1763
+ props: [positionerProps, useCompositeListItem.getDisabledMountTransitionStyles(transitionStatus), elementProps]
3516
1764
  });
3517
- const shouldRenderBackdrop = mounted && parent.type !== 'menu' && (parent.type !== 'menubar' && modal && lastOpenChangeReason !== clamp.triggerHover || parent.type === 'menubar' && parent.context.modal);
1765
+ const shouldRenderBackdrop = mounted && parent.type !== 'menu' && (parent.type !== 'menubar' && modal && lastOpenChangeReason !== useButton.triggerHover || parent.type === 'menubar' && parent.context.modal);
3518
1766
 
3519
1767
  // cuts a hole in the backdrop to allow pointer interaction with the menubar or dropdown menu trigger element
3520
1768
  let backdropCutout = null;
@@ -3525,13 +1773,13 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
3525
1773
  }
3526
1774
  return /*#__PURE__*/jsxRuntime.jsxs(MenuPositionerContext.Provider, {
3527
1775
  value: contextValue,
3528
- children: [shouldRenderBackdrop && /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.InternalBackdrop, {
1776
+ children: [shouldRenderBackdrop && /*#__PURE__*/jsxRuntime.jsx(InternalBackdrop.InternalBackdrop, {
3529
1777
  ref: parent.type === 'context-menu' || parent.type === 'nested-context-menu' ? parent.context.internalBackdropRef : null,
3530
- inert: ScrollAreaViewport.inertValue(!open),
1778
+ inert: InternalBackdrop.inertValue(!open),
3531
1779
  cutout: backdropCutout
3532
- }), /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.FloatingNode, {
1780
+ }), /*#__PURE__*/jsxRuntime.jsx(InternalBackdrop.FloatingNode, {
3533
1781
  id: floatingNodeId,
3534
- children: /*#__PURE__*/jsxRuntime.jsx(CompositeList, {
1782
+ children: /*#__PURE__*/jsxRuntime.jsx(useCompositeListItem.CompositeList, {
3535
1783
  elementsRef: store.context.itemDomElements,
3536
1784
  labelsRef: store.context.itemLabels,
3537
1785
  children: element
@@ -3567,13 +1815,13 @@ const MenuRadioGroup = /*#__PURE__*/React__namespace.memo(/*#__PURE__*/React__na
3567
1815
  disabled = false,
3568
1816
  ...elementProps
3569
1817
  } = componentProps;
3570
- const [value, setValueUnwrapped] = clamp.useControlled({
1818
+ const [value, setValueUnwrapped] = useButton.useControlled({
3571
1819
  controlled: valueProp,
3572
1820
  default: defaultValue,
3573
1821
  name: 'MenuRadioGroup'
3574
1822
  });
3575
- const onValueChange = clamp.useStableCallback(onValueChangeProp);
3576
- const setValue = clamp.useStableCallback((newValue, eventDetails) => {
1823
+ const onValueChange = useButton.useStableCallback(onValueChangeProp);
1824
+ const setValue = useButton.useStableCallback((newValue, eventDetails) => {
3577
1825
  onValueChange?.(newValue, eventDetails);
3578
1826
  if (eventDetails.isCanceled) {
3579
1827
  return;
@@ -3626,11 +1874,11 @@ const MenuRadioItem = /*#__PURE__*/React__namespace.forwardRef(function MenuRadi
3626
1874
  value,
3627
1875
  ...elementProps
3628
1876
  } = componentProps;
3629
- const listItem = useCompositeListItem({
1877
+ const listItem = useCompositeListItem.useCompositeListItem({
3630
1878
  label
3631
1879
  });
3632
1880
  const menuPositionerContext = useMenuPositionerContext(true);
3633
- const id = clamp.useBaseUiId(idProp);
1881
+ const id = useButton.useBaseUiId(idProp);
3634
1882
  const {
3635
1883
  store
3636
1884
  } = useMenuRootContext();
@@ -3661,9 +1909,9 @@ const MenuRadioItem = /*#__PURE__*/React__namespace.forwardRef(function MenuRadi
3661
1909
  highlighted,
3662
1910
  checked
3663
1911
  }), [disabled, highlighted, checked]);
3664
- const handleClick = clamp.useStableCallback(event => {
1912
+ const handleClick = useButton.useStableCallback(event => {
3665
1913
  const details = {
3666
- ...clamp.createChangeEventDetails(clamp.itemPress, event.nativeEvent),
1914
+ ...useButton.createChangeEventDetails(useButton.itemPress, event.nativeEvent),
3667
1915
  preventUnmountOnClose: () => {}
3668
1916
  };
3669
1917
  setSelectedValue(value, details);
@@ -3703,8 +1951,8 @@ const MenuRadioItemIndicator = /*#__PURE__*/React__namespace.forwardRef(function
3703
1951
  const {
3704
1952
  transitionStatus,
3705
1953
  setMounted
3706
- } = clamp.useTransitionStatus(item.checked);
3707
- clamp.useOpenChangeComplete({
1954
+ } = useButton.useTransitionStatus(item.checked);
1955
+ useButton.useOpenChangeComplete({
3708
1956
  open: item.checked,
3709
1957
  ref: indicatorRef,
3710
1958
  onComplete() {
@@ -3745,34 +1993,34 @@ function useMenubarContext(optional) {
3745
1993
 
3746
1994
  const selectors = {
3747
1995
  ...ScrollAreaViewport.popupStoreSelectors,
3748
- disabled: ScrollAreaViewport.createSelector(state => state.parent.type === 'menubar' ? state.parent.context.disabled || state.disabled : state.disabled),
3749
- modal: ScrollAreaViewport.createSelector(state => (state.parent.type === undefined || state.parent.type === 'context-menu') && (state.modal ?? true)),
3750
- allowMouseEnter: ScrollAreaViewport.createSelector(state => state.allowMouseEnter),
3751
- stickIfOpen: ScrollAreaViewport.createSelector(state => state.stickIfOpen),
3752
- parent: ScrollAreaViewport.createSelector(state => state.parent),
3753
- rootId: ScrollAreaViewport.createSelector(state => {
1996
+ disabled: InternalBackdrop.createSelector(state => state.parent.type === 'menubar' ? state.parent.context.disabled || state.disabled : state.disabled),
1997
+ modal: InternalBackdrop.createSelector(state => (state.parent.type === undefined || state.parent.type === 'context-menu') && (state.modal ?? true)),
1998
+ allowMouseEnter: InternalBackdrop.createSelector(state => state.allowMouseEnter),
1999
+ stickIfOpen: InternalBackdrop.createSelector(state => state.stickIfOpen),
2000
+ parent: InternalBackdrop.createSelector(state => state.parent),
2001
+ rootId: InternalBackdrop.createSelector(state => {
3754
2002
  if (state.parent.type === 'menu') {
3755
2003
  return state.parent.store.select('rootId');
3756
2004
  }
3757
2005
  return state.parent.type !== undefined ? state.parent.context.rootId : state.rootId;
3758
2006
  }),
3759
- activeIndex: ScrollAreaViewport.createSelector(state => state.activeIndex),
3760
- isActive: ScrollAreaViewport.createSelector((state, itemIndex) => state.activeIndex === itemIndex),
3761
- hoverEnabled: ScrollAreaViewport.createSelector(state => state.hoverEnabled),
3762
- instantType: ScrollAreaViewport.createSelector(state => state.instantType),
3763
- lastOpenChangeReason: ScrollAreaViewport.createSelector(state => state.openChangeReason),
3764
- floatingTreeRoot: ScrollAreaViewport.createSelector(state => {
2007
+ activeIndex: InternalBackdrop.createSelector(state => state.activeIndex),
2008
+ isActive: InternalBackdrop.createSelector((state, itemIndex) => state.activeIndex === itemIndex),
2009
+ hoverEnabled: InternalBackdrop.createSelector(state => state.hoverEnabled),
2010
+ instantType: InternalBackdrop.createSelector(state => state.instantType),
2011
+ lastOpenChangeReason: InternalBackdrop.createSelector(state => state.openChangeReason),
2012
+ floatingTreeRoot: InternalBackdrop.createSelector(state => {
3765
2013
  if (state.parent.type === 'menu') {
3766
2014
  return state.parent.store.select('floatingTreeRoot');
3767
2015
  }
3768
2016
  return state.floatingTreeRoot;
3769
2017
  }),
3770
- floatingNodeId: ScrollAreaViewport.createSelector(state => state.floatingNodeId),
3771
- floatingParentNodeId: ScrollAreaViewport.createSelector(state => state.floatingParentNodeId),
3772
- itemProps: ScrollAreaViewport.createSelector(state => state.itemProps),
3773
- closeDelay: ScrollAreaViewport.createSelector(state => state.closeDelay),
3774
- hasViewport: ScrollAreaViewport.createSelector(state => state.hasViewport),
3775
- keyboardEventRelay: ScrollAreaViewport.createSelector(state => {
2018
+ floatingNodeId: InternalBackdrop.createSelector(state => state.floatingNodeId),
2019
+ floatingParentNodeId: InternalBackdrop.createSelector(state => state.floatingParentNodeId),
2020
+ itemProps: InternalBackdrop.createSelector(state => state.itemProps),
2021
+ closeDelay: InternalBackdrop.createSelector(state => state.closeDelay),
2022
+ hasViewport: InternalBackdrop.createSelector(state => state.hasViewport),
2023
+ keyboardEventRelay: InternalBackdrop.createSelector(state => {
3776
2024
  if (state.keyboardEventRelay) {
3777
2025
  return state.keyboardEventRelay;
3778
2026
  }
@@ -3782,7 +2030,7 @@ const selectors = {
3782
2030
  return undefined;
3783
2031
  })
3784
2032
  };
3785
- class MenuStore extends ScrollAreaViewport.ReactStore {
2033
+ class MenuStore extends InternalBackdrop.ReactStore {
3786
2034
  constructor(initialState) {
3787
2035
  super({
3788
2036
  ...createInitialState(),
@@ -3805,7 +2053,7 @@ class MenuStore extends ScrollAreaViewport.ReactStore {
3805
2053
  triggerFocusTargetRef: /*#__PURE__*/React__namespace.createRef(),
3806
2054
  beforeContentFocusGuardRef: /*#__PURE__*/React__namespace.createRef(),
3807
2055
  onOpenChangeComplete: undefined,
3808
- triggerElements: new ScrollAreaViewport.PopupTriggerMap()
2056
+ triggerElements: new InternalBackdrop.PopupTriggerMap()
3809
2057
  }, selectors);
3810
2058
 
3811
2059
  // Set up propagation of state from parent menu if applicable.
@@ -3866,7 +2114,7 @@ function createInitialState() {
3866
2114
  hoverEnabled: true,
3867
2115
  instantType: undefined,
3868
2116
  openChangeReason: null,
3869
- floatingTreeRoot: new ScrollAreaViewport.FloatingTreeStore(),
2117
+ floatingTreeRoot: new InternalBackdrop.FloatingTreeStore(),
3870
2118
  floatingNodeId: undefined,
3871
2119
  floatingParentNodeId: null,
3872
2120
  itemProps: useRenderElement.EMPTY_OBJECT,
@@ -3882,7 +2130,7 @@ function useMenuSubmenuRootContext() {
3882
2130
  return React__namespace.useContext(MenuSubmenuRootContext);
3883
2131
  }
3884
2132
 
3885
- const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
2133
+ const MenuRoot = InternalBackdrop.fastComponent(function MenuRoot(props) {
3886
2134
  const {
3887
2135
  children,
3888
2136
  open: openProp,
@@ -3940,7 +2188,7 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
3940
2188
  });
3941
2189
 
3942
2190
  // Support initially open state when uncontrolled
3943
- ScrollAreaViewport.useOnFirstRender(() => {
2191
+ InternalBackdrop.useOnFirstRender(() => {
3944
2192
  if (openProp === undefined && store.state.open === false && defaultOpen === true) {
3945
2193
  store.update({
3946
2194
  open: true,
@@ -3952,9 +2200,9 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
3952
2200
  store.useControlledProp('triggerIdProp', triggerIdProp);
3953
2201
  store.useContextCallback('onOpenChangeComplete', onOpenChangeComplete);
3954
2202
  const floatingTreeRoot = store.useState('floatingTreeRoot');
3955
- const floatingNodeIdFromContext = ScrollAreaViewport.useFloatingNodeId(floatingTreeRoot);
3956
- const floatingParentNodeIdFromContext = ScrollAreaViewport.useFloatingParentNodeId();
3957
- clamp.useIsoLayoutEffect(() => {
2203
+ const floatingNodeIdFromContext = InternalBackdrop.useFloatingNodeId(floatingTreeRoot);
2204
+ const floatingParentNodeIdFromContext = InternalBackdrop.useFloatingParentNodeId();
2205
+ useButton.useIsoLayoutEffect(() => {
3958
2206
  if (contextMenuContext && !parentMenuRootContext) {
3959
2207
  // This is a context menu root.
3960
2208
  // It doesn't support detached triggers yet, so we have to sync the parent context manually.
@@ -3995,12 +2243,12 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
3995
2243
  store.useSyncedValues({
3996
2244
  disabled: disabledProp,
3997
2245
  modal: parent.type === undefined ? modalProp : undefined,
3998
- rootId: clamp.useId()
2246
+ rootId: useButton.useId()
3999
2247
  });
4000
2248
  const {
4001
2249
  openMethod,
4002
2250
  triggerProps: interactionTypeProps
4003
- } = ScrollAreaViewport.useOpenInteractionType(open);
2251
+ } = InternalBackdrop.useOpenInteractionType(open);
4004
2252
  ScrollAreaViewport.useImplicitActiveTrigger(store);
4005
2253
  const {
4006
2254
  forceUnmount
@@ -4011,7 +2259,7 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
4011
2259
  });
4012
2260
  });
4013
2261
  const allowOutsidePressDismissalRef = React__namespace.useRef(parent.type !== 'context-menu');
4014
- const allowOutsidePressDismissalTimeout = clamp.useTimeout();
2262
+ const allowOutsidePressDismissalTimeout = useButton.useTimeout();
4015
2263
  React__namespace.useEffect(() => {
4016
2264
  if (!open) {
4017
2265
  openEventRef.current = null;
@@ -4032,15 +2280,15 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
4032
2280
  allowOutsidePressDismissalRef.current = true;
4033
2281
  });
4034
2282
  }, [allowOutsidePressDismissalTimeout, open, parent.type]);
4035
- ScrollAreaViewport.useScrollLock(open && modal && lastOpenChangeReason !== clamp.triggerHover && openMethod !== 'touch', positionerElement);
4036
- clamp.useIsoLayoutEffect(() => {
2283
+ InternalBackdrop.useScrollLock(open && modal && lastOpenChangeReason !== useButton.triggerHover && openMethod !== 'touch', positionerElement);
2284
+ useButton.useIsoLayoutEffect(() => {
4037
2285
  if (!open && !hoverEnabled) {
4038
2286
  store.set('hoverEnabled', true);
4039
2287
  }
4040
2288
  }, [open, hoverEnabled, store]);
4041
2289
  const allowTouchToCloseRef = React__namespace.useRef(true);
4042
- const allowTouchToCloseTimeout = clamp.useTimeout();
4043
- const setOpen = clamp.useStableCallback((nextOpen, eventDetails) => {
2290
+ const allowTouchToCloseTimeout = useButton.useTimeout();
2291
+ const setOpen = useButton.useStableCallback((nextOpen, eventDetails) => {
4044
2292
  const reason = eventDetails.reason;
4045
2293
  if (open === nextOpen && eventDetails.trigger === activeTriggerElement && lastOpenChangeReason === reason) {
4046
2294
  return;
@@ -4086,7 +2334,7 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
4086
2334
  // Prevent the menu from closing on mobile devices that have a delayed click event.
4087
2335
  // In some cases the menu, when tapped, will fire the focus event first and then the click event.
4088
2336
  // Without this guard, the menu will close immediately after opening.
4089
- if (nextOpen && reason === clamp.triggerFocus) {
2337
+ if (nextOpen && reason === useButton.triggerFocus) {
4090
2338
  allowTouchToCloseRef.current = false;
4091
2339
  allowTouchToCloseTimeout.start(300, () => {
4092
2340
  allowTouchToCloseRef.current = true;
@@ -4095,8 +2343,8 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
4095
2343
  allowTouchToCloseRef.current = true;
4096
2344
  allowTouchToCloseTimeout.clear();
4097
2345
  }
4098
- const isKeyboardClick = (reason === clamp.triggerPress || reason === clamp.itemPress) && nativeEvent.detail === 0 && nativeEvent?.isTrusted;
4099
- const isDismissClose = !nextOpen && (reason === clamp.escapeKey || reason == null);
2346
+ const isKeyboardClick = (reason === useButton.triggerPress || reason === useButton.itemPress) && nativeEvent.detail === 0 && nativeEvent?.isTrusted;
2347
+ const isDismissClose = !nextOpen && (reason === useButton.escapeKey || reason == null);
4100
2348
  const updatedState = {
4101
2349
  open: nextOpen,
4102
2350
  openChangeReason: reason
@@ -4111,7 +2359,7 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
4111
2359
  updatedState.activeTriggerElement = eventDetails.trigger ?? null;
4112
2360
  }
4113
2361
  store.update(updatedState);
4114
- if (parent.type === 'menubar' && (reason === clamp.triggerFocus || reason === clamp.focusOut || reason === clamp.triggerHover || reason === clamp.listNavigation || reason === clamp.siblingOpen)) {
2362
+ if (parent.type === 'menubar' && (reason === useButton.triggerFocus || reason === useButton.focusOut || reason === useButton.triggerHover || reason === useButton.listNavigation || reason === useButton.siblingOpen)) {
4115
2363
  store.set('instantType', 'group');
4116
2364
  } else if (isKeyboardClick || isDismissClose) {
4117
2365
  store.set('instantType', isKeyboardClick ? 'click' : 'dismiss');
@@ -4120,14 +2368,14 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
4120
2368
  }
4121
2369
  });
4122
2370
  const createMenuEventDetails = React__namespace.useCallback(reason => {
4123
- const details = clamp.createChangeEventDetails(reason);
2371
+ const details = useButton.createChangeEventDetails(reason);
4124
2372
  details.preventUnmountOnClose = () => {
4125
2373
  store.set('preventUnmountingOnClose', true);
4126
2374
  };
4127
2375
  return details;
4128
2376
  }, [store]);
4129
2377
  const handleImperativeClose = React__namespace.useCallback(() => {
4130
- store.setOpen(false, createMenuEventDetails(clamp.imperativeAction));
2378
+ store.setOpen(false, createMenuEventDetails(useButton.imperativeAction));
4131
2379
  }, [store, createMenuEventDetails]);
4132
2380
  React__namespace.useImperativeHandle(actionsRef, () => ({
4133
2381
  unmount: forceUnmount,
@@ -4156,7 +2404,7 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
4156
2404
  floatingEvents?.off('setOpen', handleSetOpenEvent);
4157
2405
  };
4158
2406
  }, [floatingEvents, setOpen]);
4159
- const dismiss = ScrollAreaViewport.useDismiss(floatingRootContext, {
2407
+ const dismiss = InternalBackdrop.useDismiss(floatingRootContext, {
4160
2408
  enabled: !disabled,
4161
2409
  bubbles: {
4162
2410
  escapeKey: closeParentOnEsc && parent.type === 'menu'
@@ -4172,14 +2420,14 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
4172
2420
  const role = ScrollAreaViewport.useRole(floatingRootContext, {
4173
2421
  role: 'menu'
4174
2422
  });
4175
- const direction = ScrollAreaViewport.useDirection();
2423
+ const direction = InternalBackdrop.useDirection();
4176
2424
  const setActiveIndex = React__namespace.useCallback(index => {
4177
2425
  if (store.select('activeIndex') === index) {
4178
2426
  return;
4179
2427
  }
4180
2428
  store.set('activeIndex', index);
4181
2429
  }, [store]);
4182
- const listNavigation = useListNavigation(floatingRootContext, {
2430
+ const listNavigation = useCompositeListItem.useListNavigation(floatingRootContext, {
4183
2431
  enabled: !disabled,
4184
2432
  listRef: store.context.itemDomElements,
4185
2433
  activeIndex,
@@ -4197,11 +2445,11 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
4197
2445
  const onTypingChange = React__namespace.useCallback(nextTyping => {
4198
2446
  store.context.typingRef.current = nextTyping;
4199
2447
  }, [store]);
4200
- const typeahead = useTypeahead(floatingRootContext, {
2448
+ const typeahead = useCompositeListItem.useTypeahead(floatingRootContext, {
4201
2449
  listRef: store.context.itemLabels,
4202
2450
  elementsRef: store.context.itemDomElements,
4203
2451
  activeIndex,
4204
- resetMs: ScrollAreaViewport.TYPEAHEAD_RESET_MS,
2452
+ resetMs: InternalBackdrop.TYPEAHEAD_RESET_MS,
4205
2453
  onMatch: index => {
4206
2454
  if (open && index !== activeIndex) {
4207
2455
  store.set('activeIndex', index);
@@ -4214,7 +2462,7 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
4214
2462
  getFloatingProps,
4215
2463
  getItemProps,
4216
2464
  getTriggerProps
4217
- } = ScrollAreaViewport.useInteractions([dismiss, role, listNavigation, typeahead]);
2465
+ } = InternalBackdrop.useInteractions([dismiss, role, listNavigation, typeahead]);
4218
2466
  const activeTriggerProps = React__namespace.useMemo(() => {
4219
2467
  const mergedProps = useRenderElement.mergeProps(getReferenceProps(), {
4220
2468
  onMouseMove() {
@@ -4276,7 +2524,7 @@ const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
4276
2524
  });
4277
2525
  if (parent.type === undefined || parent.type === 'context-menu') {
4278
2526
  // set up a FloatingTree to provide the context to nested menus
4279
- return /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.FloatingTree, {
2527
+ return /*#__PURE__*/jsxRuntime.jsx(InternalBackdrop.FloatingTree, {
4280
2528
  externalTree: floatingTreeRoot,
4281
2529
  children: content
4282
2530
  });
@@ -4309,11 +2557,11 @@ function useCompositeItem(params = {}) {
4309
2557
  highlightItemOnHover,
4310
2558
  highlightedIndex,
4311
2559
  onHighlightedIndexChange
4312
- } = clamp.useCompositeRootContext();
2560
+ } = useButton.useCompositeRootContext();
4313
2561
  const {
4314
2562
  ref,
4315
2563
  index
4316
- } = useCompositeListItem(params);
2564
+ } = useCompositeListItem.useCompositeListItem(params);
4317
2565
  const isHighlighted = highlightedIndex === index;
4318
2566
  const itemRef = React__namespace.useRef(null);
4319
2567
  const mergedRef = useRenderElement.useMergedRefs(ref, itemRef);
@@ -4399,7 +2647,7 @@ function useMixedToggleClickHandler(params) {
4399
2647
  onMouseDown: event => {
4400
2648
  if (mouseDownAction === 'open' && !open || mouseDownAction === 'close' && open) {
4401
2649
  ignoreClickRef.current = true;
4402
- clamp.ownerDocument(event.currentTarget).addEventListener('click', () => {
2650
+ useButton.ownerDocument(event.currentTarget).addEventListener('click', () => {
4403
2651
  ignoreClickRef.current = false;
4404
2652
  }, {
4405
2653
  once: true
@@ -4424,7 +2672,7 @@ const BOUNDARY_OFFSET = 2;
4424
2672
  *
4425
2673
  * Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
4426
2674
  */
4427
- const MenuTrigger = ScrollAreaViewport.fastComponentRef(function MenuTrigger(componentProps, forwardedRef) {
2675
+ const MenuTrigger = InternalBackdrop.fastComponentRef(function MenuTrigger(componentProps, forwardedRef) {
4428
2676
  const {
4429
2677
  render,
4430
2678
  className,
@@ -4443,19 +2691,19 @@ const MenuTrigger = ScrollAreaViewport.fastComponentRef(function MenuTrigger(com
4443
2691
  if (!store) {
4444
2692
  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
2693
  }
4446
- const thisTriggerId = clamp.useBaseUiId(idProp);
2694
+ const thisTriggerId = useButton.useBaseUiId(idProp);
4447
2695
  const isTriggerActive = store.useState('isTriggerActive', thisTriggerId);
4448
2696
  const floatingRootContext = store.useState('floatingRootContext');
4449
2697
  const isOpenedByThisTrigger = store.useState('isOpenedByTrigger', thisTriggerId);
4450
2698
  const triggerElementRef = React__namespace.useRef(null);
4451
2699
  const parent = useMenuParent();
4452
- const compositeRootContext = clamp.useCompositeRootContext(true);
4453
- const floatingTreeRootFromContext = ScrollAreaViewport.useFloatingTree();
2700
+ const compositeRootContext = useButton.useCompositeRootContext(true);
2701
+ const floatingTreeRootFromContext = InternalBackdrop.useFloatingTree();
4454
2702
  const floatingTreeRoot = React__namespace.useMemo(() => {
4455
- return floatingTreeRootFromContext ?? new ScrollAreaViewport.FloatingTreeStore();
2703
+ return floatingTreeRootFromContext ?? new InternalBackdrop.FloatingTreeStore();
4456
2704
  }, [floatingTreeRootFromContext]);
4457
- const floatingNodeId = ScrollAreaViewport.useFloatingNodeId(floatingTreeRoot);
4458
- const floatingParentNodeId = ScrollAreaViewport.useFloatingParentNodeId();
2705
+ const floatingNodeId = InternalBackdrop.useFloatingNodeId(floatingTreeRoot);
2706
+ const floatingParentNodeId = InternalBackdrop.useFloatingParentNodeId();
4459
2707
  const {
4460
2708
  registerTrigger,
4461
2709
  isMountedByThisTrigger
@@ -4474,7 +2722,7 @@ const MenuTrigger = ScrollAreaViewport.fastComponentRef(function MenuTrigger(com
4474
2722
  const {
4475
2723
  getButtonProps,
4476
2724
  buttonRef
4477
- } = clamp.useButton({
2725
+ } = useButton.useButton({
4478
2726
  disabled,
4479
2727
  native: nativeButton
4480
2728
  });
@@ -4484,32 +2732,32 @@ const MenuTrigger = ScrollAreaViewport.fastComponentRef(function MenuTrigger(com
4484
2732
  }
4485
2733
  }, [store, isOpenedByThisTrigger, parent.type]);
4486
2734
  const triggerRef = React__namespace.useRef(null);
4487
- const allowMouseUpTriggerTimeout = clamp.useTimeout();
4488
- const handleDocumentMouseUp = clamp.useStableCallback(mouseEvent => {
2735
+ const allowMouseUpTriggerTimeout = useButton.useTimeout();
2736
+ const handleDocumentMouseUp = useButton.useStableCallback(mouseEvent => {
4489
2737
  if (!triggerRef.current) {
4490
2738
  return;
4491
2739
  }
4492
2740
  allowMouseUpTriggerTimeout.clear();
4493
2741
  store.context.allowMouseUpTriggerRef.current = false;
4494
2742
  const mouseUpTarget = mouseEvent.target;
4495
- if (clamp.contains(triggerRef.current, mouseUpTarget) || clamp.contains(store.select('positionerElement'), mouseUpTarget) || mouseUpTarget === triggerRef.current) {
2743
+ if (useButton.contains(triggerRef.current, mouseUpTarget) || useButton.contains(store.select('positionerElement'), mouseUpTarget) || mouseUpTarget === triggerRef.current) {
4496
2744
  return;
4497
2745
  }
4498
2746
  if (mouseUpTarget != null && findRootOwnerId(mouseUpTarget) === store.select('rootId')) {
4499
2747
  return;
4500
2748
  }
4501
- const bounds = getPseudoElementBounds(triggerRef.current);
2749
+ const bounds = useCompositeListItem.getPseudoElementBounds(triggerRef.current);
4502
2750
  if (mouseEvent.clientX >= bounds.left - BOUNDARY_OFFSET && mouseEvent.clientX <= bounds.right + BOUNDARY_OFFSET && mouseEvent.clientY >= bounds.top - BOUNDARY_OFFSET && mouseEvent.clientY <= bounds.bottom + BOUNDARY_OFFSET) {
4503
2751
  return;
4504
2752
  }
4505
2753
  floatingTreeRoot.events.emit('close', {
4506
2754
  domEvent: mouseEvent,
4507
- reason: clamp.cancelOpen
2755
+ reason: useButton.cancelOpen
4508
2756
  });
4509
2757
  });
4510
2758
  React__namespace.useEffect(() => {
4511
- if (isOpenedByThisTrigger && store.select('lastOpenChangeReason') === clamp.triggerHover) {
4512
- const doc = clamp.ownerDocument(triggerRef.current);
2759
+ if (isOpenedByThisTrigger && store.select('lastOpenChangeReason') === useButton.triggerHover) {
2760
+ const doc = useButton.ownerDocument(triggerRef.current);
4513
2761
  doc.addEventListener('mouseup', handleDocumentMouseUp, {
4514
2762
  once: true
4515
2763
  });
@@ -4537,7 +2785,7 @@ const MenuTrigger = ScrollAreaViewport.fastComponentRef(function MenuTrigger(com
4537
2785
  // `lastOpenChangeReason` doesn't need to be reactive here, as we need to run this
4538
2786
  // only when `isOpenedByThisTrigger` changes.
4539
2787
  const stickIfOpen = useStickIfOpen(isOpenedByThisTrigger, store.select('lastOpenChangeReason'));
4540
- const click = ScrollAreaViewport.useClick(floatingRootContext, {
2788
+ const click = InternalBackdrop.useClick(floatingRootContext, {
4541
2789
  enabled: !disabled && parent.type !== 'context-menu',
4542
2790
  event: isOpenedByThisTrigger && isInMenubar ? 'click' : 'mousedown',
4543
2791
  toggle: true,
@@ -4552,7 +2800,7 @@ const MenuTrigger = ScrollAreaViewport.fastComponentRef(function MenuTrigger(com
4552
2800
  enabled: isInMenubar,
4553
2801
  mouseDownAction: 'open'
4554
2802
  });
4555
- const localInteractionProps = ScrollAreaViewport.useInteractions([click, focus]);
2803
+ const localInteractionProps = InternalBackdrop.useInteractions([click, focus]);
4556
2804
  const state = {
4557
2805
  disabled,
4558
2806
  open: isOpenedByThisTrigger
@@ -4571,7 +2819,7 @@ const MenuTrigger = ScrollAreaViewport.fastComponentRef(function MenuTrigger(com
4571
2819
  allowMouseUpTriggerTimeout.start(200, () => {
4572
2820
  store.context.allowMouseUpTriggerRef.current = true;
4573
2821
  });
4574
- const doc = clamp.ownerDocument(event.currentTarget);
2822
+ const doc = useButton.ownerDocument(event.currentTarget);
4575
2823
  doc.addEventListener('mouseup', handleDocumentMouseUp, {
4576
2824
  once: true
4577
2825
  });
@@ -4580,25 +2828,25 @@ const MenuTrigger = ScrollAreaViewport.fastComponentRef(function MenuTrigger(com
4580
2828
  role: 'menuitem'
4581
2829
  } : {}, mixedToggleHandlers, elementProps, getButtonProps];
4582
2830
  const preFocusGuardRef = React__namespace.useRef(null);
4583
- const handlePreFocusGuardFocus = clamp.useStableCallback(event => {
2831
+ const handlePreFocusGuardFocus = useButton.useStableCallback(event => {
4584
2832
  ReactDOM__namespace.flushSync(() => {
4585
- store.setOpen(false, clamp.createChangeEventDetails(clamp.focusOut, event.nativeEvent, event.currentTarget));
2833
+ store.setOpen(false, useButton.createChangeEventDetails(useButton.focusOut, event.nativeEvent, event.currentTarget));
4586
2834
  });
4587
- const previousTabbable = ScrollAreaViewport.getTabbableBeforeElement(preFocusGuardRef.current);
2835
+ const previousTabbable = InternalBackdrop.getTabbableBeforeElement(preFocusGuardRef.current);
4588
2836
  previousTabbable?.focus();
4589
2837
  });
4590
- const handleFocusTargetFocus = clamp.useStableCallback(event => {
2838
+ const handleFocusTargetFocus = useButton.useStableCallback(event => {
4591
2839
  const currentPositionerElement = store.select('positionerElement');
4592
- if (currentPositionerElement && ScrollAreaViewport.isOutsideEvent(event, currentPositionerElement)) {
2840
+ if (currentPositionerElement && InternalBackdrop.isOutsideEvent(event, currentPositionerElement)) {
4593
2841
  store.context.beforeContentFocusGuardRef.current?.focus();
4594
2842
  } else {
4595
2843
  ReactDOM__namespace.flushSync(() => {
4596
- store.setOpen(false, clamp.createChangeEventDetails(clamp.focusOut, event.nativeEvent, event.currentTarget));
2844
+ store.setOpen(false, useButton.createChangeEventDetails(useButton.focusOut, event.nativeEvent, event.currentTarget));
4597
2845
  });
4598
- let nextTabbable = ScrollAreaViewport.getTabbableAfterElement(store.context.triggerFocusTargetRef.current || triggerElementRef.current);
4599
- while (nextTabbable !== null && clamp.contains(currentPositionerElement, nextTabbable)) {
2846
+ let nextTabbable = InternalBackdrop.getTabbableAfterElement(store.context.triggerFocusTargetRef.current || triggerElementRef.current);
2847
+ while (nextTabbable !== null && useButton.contains(currentPositionerElement, nextTabbable)) {
4600
2848
  const prevTabbable = nextTabbable;
4601
- nextTabbable = ScrollAreaViewport.getNextTabbable(nextTabbable);
2849
+ nextTabbable = InternalBackdrop.getNextTabbable(nextTabbable);
4602
2850
  if (nextTabbable === prevTabbable) {
4603
2851
  break;
4604
2852
  }
@@ -4608,7 +2856,7 @@ const MenuTrigger = ScrollAreaViewport.fastComponentRef(function MenuTrigger(com
4608
2856
  });
4609
2857
  const element = useRenderElement.useRenderElement('button', componentProps, {
4610
2858
  enabled: !isInMenubar,
4611
- stateAttributesMapping: ScrollAreaViewport.pressableTriggerOpenStateMapping,
2859
+ stateAttributesMapping: InternalBackdrop.pressableTriggerOpenStateMapping,
4612
2860
  state,
4613
2861
  ref,
4614
2862
  props
@@ -4621,7 +2869,7 @@ const MenuTrigger = ScrollAreaViewport.fastComponentRef(function MenuTrigger(com
4621
2869
  state: state,
4622
2870
  refs: ref,
4623
2871
  props: props,
4624
- stateAttributesMapping: ScrollAreaViewport.pressableTriggerOpenStateMapping
2872
+ stateAttributesMapping: InternalBackdrop.pressableTriggerOpenStateMapping
4625
2873
  });
4626
2874
  }
4627
2875
 
@@ -4630,12 +2878,12 @@ const MenuTrigger = ScrollAreaViewport.fastComponentRef(function MenuTrigger(com
4630
2878
 
4631
2879
  if (isOpenedByThisTrigger) {
4632
2880
  return /*#__PURE__*/jsxRuntime.jsxs(React__namespace.Fragment, {
4633
- children: [/*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.FocusGuard, {
2881
+ children: [/*#__PURE__*/jsxRuntime.jsx(InternalBackdrop.FocusGuard, {
4634
2882
  ref: preFocusGuardRef,
4635
2883
  onFocus: handlePreFocusGuardFocus
4636
2884
  }, `${thisTriggerId}-pre-focus-guard`), /*#__PURE__*/jsxRuntime.jsx(React__namespace.Fragment, {
4637
2885
  children: element
4638
- }, thisTriggerId), /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.FocusGuard, {
2886
+ }, thisTriggerId), /*#__PURE__*/jsxRuntime.jsx(InternalBackdrop.FocusGuard, {
4639
2887
  ref: store.context.triggerFocusTargetRef,
4640
2888
  onFocus: handleFocusTargetFocus
4641
2889
  }, `${thisTriggerId}-post-focus-guard`)]
@@ -4650,14 +2898,14 @@ if (process.env.NODE_ENV !== "production") MenuTrigger.displayName = "MenuTrigge
4650
2898
  * Determines whether to ignore clicks after a hover-open.
4651
2899
  */
4652
2900
  function useStickIfOpen(open, openReason) {
4653
- const stickIfOpenTimeout = clamp.useTimeout();
2901
+ const stickIfOpenTimeout = useButton.useTimeout();
4654
2902
  const [stickIfOpen, setStickIfOpen] = React__namespace.useState(false);
4655
- clamp.useIsoLayoutEffect(() => {
2903
+ useButton.useIsoLayoutEffect(() => {
4656
2904
  if (open && openReason === 'trigger-hover') {
4657
2905
  // Only allow "patient" clicks to close the menu if it's open.
4658
2906
  // If they clicked within 500ms of the menu opening, keep it open.
4659
2907
  setStickIfOpen(true);
4660
- stickIfOpenTimeout.start(ScrollAreaViewport.PATIENT_CLICK_THRESHOLD, () => {
2908
+ stickIfOpenTimeout.start(InternalBackdrop.PATIENT_CLICK_THRESHOLD, () => {
4661
2909
  setStickIfOpen(false);
4662
2910
  });
4663
2911
  } else if (!open) {
@@ -4714,12 +2962,12 @@ const MenuSubmenuTrigger = /*#__PURE__*/React__namespace.forwardRef(function Sub
4714
2962
  disabled: disabledProp = false,
4715
2963
  ...elementProps
4716
2964
  } = componentProps;
4717
- const listItem = useCompositeListItem();
2965
+ const listItem = useCompositeListItem.useCompositeListItem();
4718
2966
  const menuPositionerContext = useMenuPositionerContext();
4719
2967
  const {
4720
2968
  store
4721
2969
  } = useMenuRootContext();
4722
- const thisTriggerId = clamp.useBaseUiId(idProp);
2970
+ const thisTriggerId = useButton.useBaseUiId(idProp);
4723
2971
  const open = store.useState('open');
4724
2972
  const floatingRootContext = store.useState('floatingRootContext');
4725
2973
  const floatingTreeRoot = store.useState('floatingTreeRoot');
@@ -4787,14 +3035,14 @@ const MenuSubmenuTrigger = /*#__PURE__*/React__namespace.forwardRef(function Sub
4787
3035
  triggerElementRef,
4788
3036
  externalTree: floatingTreeRoot
4789
3037
  });
4790
- const click = ScrollAreaViewport.useClick(floatingRootContext, {
3038
+ const click = InternalBackdrop.useClick(floatingRootContext, {
4791
3039
  enabled: !disabled,
4792
3040
  event: 'mousedown',
4793
3041
  toggle: !openOnHover,
4794
3042
  ignoreMouse: openOnHover,
4795
3043
  stickIfOpen: false
4796
3044
  });
4797
- const localInteractionProps = ScrollAreaViewport.useInteractions([click]);
3045
+ const localInteractionProps = InternalBackdrop.useInteractions([click]);
4798
3046
  const rootTriggerProps = store.useState('triggerProps', true);
4799
3047
  delete rootTriggerProps.id;
4800
3048
  const state = {
@@ -4804,7 +3052,7 @@ const MenuSubmenuTrigger = /*#__PURE__*/React__namespace.forwardRef(function Sub
4804
3052
  };
4805
3053
  const element = useRenderElement.useRenderElement('div', componentProps, {
4806
3054
  state,
4807
- stateAttributesMapping: ScrollAreaViewport.triggerOpenStateMapping,
3055
+ stateAttributesMapping: InternalBackdrop.triggerOpenStateMapping,
4808
3056
  props: [localInteractionProps.getReferenceProps(), hoverProps, rootTriggerProps, itemProps, {
4809
3057
  tabIndex: open || highlighted ? 0 : -1,
4810
3058
  onBlur() {
@@ -4819,10 +3067,8 @@ const MenuSubmenuTrigger = /*#__PURE__*/React__namespace.forwardRef(function Sub
4819
3067
  });
4820
3068
  if (process.env.NODE_ENV !== "production") MenuSubmenuTrigger.displayName = "MenuSubmenuTrigger";
4821
3069
 
4822
- exports.CompositeList = CompositeList;
4823
3070
  exports.DrawerClose = DrawerClose;
4824
3071
  exports.DrawerTitle = DrawerTitle;
4825
- exports.IndexGuessBehavior = IndexGuessBehavior;
4826
3072
  exports.MenuGroup = MenuGroup;
4827
3073
  exports.MenuGroupLabel = MenuGroupLabel;
4828
3074
  exports.MenuItem = MenuItem;
@@ -4839,15 +3085,8 @@ exports.MenuSubmenuRoot = MenuSubmenuRoot;
4839
3085
  exports.MenuSubmenuTrigger = MenuSubmenuTrigger;
4840
3086
  exports.MenuTrigger = MenuTrigger;
4841
3087
  exports.REGULAR_ITEM = REGULAR_ITEM;
4842
- exports.getDisabledMountTransitionStyles = getDisabledMountTransitionStyles;
4843
- exports.getPseudoElementBounds = getPseudoElementBounds;
4844
3088
  exports.itemMapping = itemMapping;
4845
- exports.useAnchorPositioning = useAnchorPositioning;
4846
- exports.useCompositeListItem = useCompositeListItem;
4847
3089
  exports.useContextMenuRootContext = useContextMenuRootContext;
4848
- exports.useFloatingRootContext = useFloatingRootContext;
4849
- exports.useListNavigation = useListNavigation;
4850
3090
  exports.useMenuItem = useMenuItem;
4851
3091
  exports.useMenuPositionerContext = useMenuPositionerContext;
4852
3092
  exports.useMenuRootContext = useMenuRootContext;
4853
- exports.useTypeahead = useTypeahead;