@jobber/components 8.14.1 → 8.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Autocomplete-es.js +1 -1
- package/dist/BottomSheet-cjs.js +109 -77
- package/dist/BottomSheet-es.js +103 -75
- package/dist/Card/index.cjs +2 -3
- package/dist/Card/index.mjs +2 -3
- package/dist/DataDump/index.cjs +2 -3
- package/dist/DataDump/index.mjs +2 -3
- package/dist/InputNumberExperimental-cjs.js +16 -17
- package/dist/InputNumberExperimental-es.js +2 -3
- package/dist/Menu/index.cjs +2 -3
- package/dist/Menu/index.mjs +2 -3
- package/dist/Menu-cjs.js +11 -56
- package/dist/Menu-es.js +4 -49
- package/dist/MenuSubmenuTrigger-cjs.js +1608 -1793
- package/dist/MenuSubmenuTrigger-es.js +1340 -1522
- package/dist/Modal/index.mjs +1 -1
- package/dist/NumberFieldInput-cjs.js +53 -54
- package/dist/NumberFieldInput-es.js +2 -3
- package/dist/Page/index.cjs +2 -3
- package/dist/Page/index.mjs +2 -3
- package/dist/{DrawerRoot-cjs.js → ScrollAreaViewport-cjs.js} +5488 -4449
- package/dist/{DrawerRoot-es.js → ScrollAreaViewport-es.js} +5423 -4393
- package/dist/{useValueChanged-cjs.js → clamp-cjs.js} +573 -321
- package/dist/{useValueChanged-es.js → clamp-es.js} +569 -322
- package/dist/floating-ui.react-es.js +1 -1
- package/dist/index.cjs +2 -3
- package/dist/index.mjs +2 -3
- package/dist/primitives/BottomSheet/BottomSheet.d.ts +15 -16
- package/dist/primitives/BottomSheet/BottomSheet.types.d.ts +27 -0
- package/dist/primitives/BottomSheet/BottomSheet.utils.d.ts +6 -0
- package/dist/primitives/BottomSheet/index.cjs +8 -3
- package/dist/primitives/BottomSheet/index.d.ts +1 -0
- package/dist/primitives/BottomSheet/index.mjs +8 -3
- package/dist/primitives/InputNumberExperimental/index.cjs +2 -3
- package/dist/primitives/InputNumberExperimental/index.mjs +2 -3
- package/dist/primitives/index.cjs +8 -9
- package/dist/primitives/index.mjs +8 -9
- package/dist/styles.css +62 -1
- package/dist/unstyledPrimitives/index.cjs +6373 -5868
- package/dist/unstyledPrimitives/index.d.ts +2 -0
- package/dist/unstyledPrimitives/index.mjs +6325 -5822
- package/dist/useRenderElement-cjs.js +30 -30
- package/dist/useRenderElement-es.js +31 -31
- package/package.json +2 -2
- package/dist/useBaseUiId-cjs.js +0 -275
- package/dist/useBaseUiId-es.js +0 -251
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var React = require('react');
|
|
4
|
-
var
|
|
4
|
+
var ScrollAreaViewport = require('./ScrollAreaViewport-cjs.js');
|
|
5
5
|
var useRenderElement = require('./useRenderElement-cjs.js');
|
|
6
|
-
var
|
|
7
|
-
var useBaseUiId = require('./useBaseUiId-cjs.js');
|
|
6
|
+
var clamp = require('./clamp-cjs.js');
|
|
8
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
9
8
|
var floatingUi_utils_dom = require('./floating-ui.utils.dom-cjs.js');
|
|
10
9
|
var index_esm = require('./index.esm-cjs.js');
|
|
@@ -31,59 +30,8 @@ function _interopNamespaceDefault(e) {
|
|
|
31
30
|
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
|
32
31
|
var ReactDOM__namespace = /*#__PURE__*/_interopNamespaceDefault(ReactDOM);
|
|
33
32
|
|
|
34
|
-
/**
|
|
35
|
-
* A button that closes the dialog.
|
|
36
|
-
* Renders a `<button>` element.
|
|
37
|
-
*
|
|
38
|
-
* Documentation: [Base UI Dialog](https://base-ui.com/react/components/dialog)
|
|
39
|
-
*/
|
|
40
|
-
const DialogClose = /*#__PURE__*/React__namespace.forwardRef(function DialogClose(componentProps, forwardedRef) {
|
|
41
|
-
const {
|
|
42
|
-
render,
|
|
43
|
-
className,
|
|
44
|
-
disabled = false,
|
|
45
|
-
nativeButton = true,
|
|
46
|
-
...elementProps
|
|
47
|
-
} = componentProps;
|
|
48
|
-
const {
|
|
49
|
-
store
|
|
50
|
-
} = DrawerRoot.useDialogRootContext();
|
|
51
|
-
const open = store.useState('open');
|
|
52
|
-
function handleClick(event) {
|
|
53
|
-
if (open) {
|
|
54
|
-
store.setOpen(false, useValueChanged.createChangeEventDetails(useValueChanged.closePress, event.nativeEvent));
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
const {
|
|
58
|
-
getButtonProps,
|
|
59
|
-
buttonRef
|
|
60
|
-
} = useBaseUiId.useButton({
|
|
61
|
-
disabled,
|
|
62
|
-
native: nativeButton
|
|
63
|
-
});
|
|
64
|
-
const state = {
|
|
65
|
-
disabled
|
|
66
|
-
};
|
|
67
|
-
return useRenderElement.useRenderElement('button', componentProps, {
|
|
68
|
-
state,
|
|
69
|
-
ref: [forwardedRef, buttonRef],
|
|
70
|
-
props: [{
|
|
71
|
-
onClick: handleClick
|
|
72
|
-
}, elementProps, getButtonProps]
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
if (process.env.NODE_ENV !== "production") DialogClose.displayName = "DialogClose";
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* A button that closes the drawer.
|
|
79
|
-
* Renders a `<button>` element.
|
|
80
|
-
*
|
|
81
|
-
* Documentation: [Base UI Drawer](https://base-ui.com/react/components/drawer)
|
|
82
|
-
*/
|
|
83
|
-
const DrawerClose = DialogClose;
|
|
84
|
-
|
|
85
33
|
function resolveValue(value, pointerType) {
|
|
86
|
-
if (pointerType != null && !
|
|
34
|
+
if (pointerType != null && !clamp.isMouseLikePointerType(pointerType)) {
|
|
87
35
|
return 0;
|
|
88
36
|
}
|
|
89
37
|
if (typeof value === 'function') {
|
|
@@ -108,134 +56,31 @@ function isClickLikeOpenEvent(openEventType, interactedInside) {
|
|
|
108
56
|
return interactedInside || openEventType === 'click' || openEventType === 'mousedown';
|
|
109
57
|
}
|
|
110
58
|
|
|
111
|
-
/**
|
|
112
|
-
* Opens or closes the floating element when clicking the reference element.
|
|
113
|
-
* @see https://floating-ui.com/docs/useClick
|
|
114
|
-
*/
|
|
115
|
-
function useClick(context, props = {}) {
|
|
116
|
-
const store = 'rootStore' in context ? context.rootStore : context;
|
|
117
|
-
const dataRef = store.context.dataRef;
|
|
118
|
-
const {
|
|
119
|
-
enabled = true,
|
|
120
|
-
event: eventOption = 'click',
|
|
121
|
-
toggle = true,
|
|
122
|
-
ignoreMouse = false,
|
|
123
|
-
stickIfOpen = true,
|
|
124
|
-
touchOpenDelay = 0,
|
|
125
|
-
reason = useValueChanged.triggerPress
|
|
126
|
-
} = props;
|
|
127
|
-
const pointerTypeRef = React__namespace.useRef(undefined);
|
|
128
|
-
const frame = useValueChanged.useAnimationFrame();
|
|
129
|
-
const touchOpenTimeout = useValueChanged.useTimeout();
|
|
130
|
-
const reference = React__namespace.useMemo(() => ({
|
|
131
|
-
onPointerDown(event) {
|
|
132
|
-
pointerTypeRef.current = event.pointerType;
|
|
133
|
-
},
|
|
134
|
-
onMouseDown(event) {
|
|
135
|
-
const pointerType = pointerTypeRef.current;
|
|
136
|
-
const nativeEvent = event.nativeEvent;
|
|
137
|
-
const open = store.select('open');
|
|
138
|
-
|
|
139
|
-
// Ignore all buttons except for the "main" button.
|
|
140
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button
|
|
141
|
-
if (event.button !== 0 || eventOption === 'click' || useValueChanged.isMouseLikePointerType(pointerType, true) && ignoreMouse) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
const openEvent = dataRef.current.openEvent;
|
|
145
|
-
const openEventType = openEvent?.type;
|
|
146
|
-
const hasClickedOnInactiveTrigger = store.select('domReferenceElement') !== event.currentTarget;
|
|
147
|
-
const nextOpen = open && hasClickedOnInactiveTrigger || !(open && toggle && (openEvent && stickIfOpen ? openEventType === 'click' || openEventType === 'mousedown' : true));
|
|
148
|
-
|
|
149
|
-
// Animations sometimes won't run on a typeable element if using a rAF.
|
|
150
|
-
// Focus is always set on these elements. For touch, we may delay opening.
|
|
151
|
-
if (DrawerRoot.isTypeableElement(nativeEvent.target)) {
|
|
152
|
-
const details = useValueChanged.createChangeEventDetails(reason, nativeEvent, nativeEvent.target);
|
|
153
|
-
if (nextOpen && pointerType === 'touch' && touchOpenDelay > 0) {
|
|
154
|
-
touchOpenTimeout.start(touchOpenDelay, () => {
|
|
155
|
-
store.setOpen(true, details);
|
|
156
|
-
});
|
|
157
|
-
} else {
|
|
158
|
-
store.setOpen(nextOpen, details);
|
|
159
|
-
}
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// Capture the currentTarget before the rAF.
|
|
164
|
-
// as React sets it to null after the event handler completes.
|
|
165
|
-
const eventCurrentTarget = event.currentTarget;
|
|
166
|
-
|
|
167
|
-
// Wait until focus is set on the element. This is an alternative to
|
|
168
|
-
// `event.preventDefault()` to avoid :focus-visible from appearing when using a pointer.
|
|
169
|
-
frame.request(() => {
|
|
170
|
-
const details = useValueChanged.createChangeEventDetails(reason, nativeEvent, eventCurrentTarget);
|
|
171
|
-
if (nextOpen && pointerType === 'touch' && touchOpenDelay > 0) {
|
|
172
|
-
touchOpenTimeout.start(touchOpenDelay, () => {
|
|
173
|
-
store.setOpen(true, details);
|
|
174
|
-
});
|
|
175
|
-
} else {
|
|
176
|
-
store.setOpen(nextOpen, details);
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
},
|
|
180
|
-
onClick(event) {
|
|
181
|
-
if (eventOption === 'mousedown-only') {
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
const pointerType = pointerTypeRef.current;
|
|
185
|
-
if (eventOption === 'mousedown' && pointerType) {
|
|
186
|
-
pointerTypeRef.current = undefined;
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
if (useValueChanged.isMouseLikePointerType(pointerType, true) && ignoreMouse) {
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
const open = store.select('open');
|
|
193
|
-
const openEvent = dataRef.current.openEvent;
|
|
194
|
-
const hasClickedOnInactiveTrigger = store.select('domReferenceElement') !== event.currentTarget;
|
|
195
|
-
const nextOpen = open && hasClickedOnInactiveTrigger || !(open && toggle && (openEvent && stickIfOpen ? useValueChanged.isClickLikeEvent(openEvent) : true));
|
|
196
|
-
const details = useValueChanged.createChangeEventDetails(reason, event.nativeEvent, event.currentTarget);
|
|
197
|
-
if (nextOpen && pointerType === 'touch' && touchOpenDelay > 0) {
|
|
198
|
-
touchOpenTimeout.start(touchOpenDelay, () => {
|
|
199
|
-
store.setOpen(true, details);
|
|
200
|
-
});
|
|
201
|
-
} else {
|
|
202
|
-
store.setOpen(nextOpen, details);
|
|
203
|
-
}
|
|
204
|
-
},
|
|
205
|
-
onKeyDown() {
|
|
206
|
-
pointerTypeRef.current = undefined;
|
|
207
|
-
}
|
|
208
|
-
}), [dataRef, eventOption, ignoreMouse, store, stickIfOpen, toggle, frame, touchOpenTimeout, touchOpenDelay, reason]);
|
|
209
|
-
return React__namespace.useMemo(() => enabled ? {
|
|
210
|
-
reference
|
|
211
|
-
} : useRenderElement.EMPTY_OBJECT, [enabled, reference]);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
59
|
function useFloatingRootContext(options) {
|
|
215
60
|
const {
|
|
216
61
|
open = false,
|
|
217
62
|
onOpenChange,
|
|
218
63
|
elements = {}
|
|
219
64
|
} = options;
|
|
220
|
-
const floatingId =
|
|
221
|
-
const nested =
|
|
65
|
+
const floatingId = clamp.useId();
|
|
66
|
+
const nested = ScrollAreaViewport.useFloatingParentNodeId() != null;
|
|
222
67
|
if (process.env.NODE_ENV !== 'production') {
|
|
223
68
|
const optionDomReference = elements.reference;
|
|
224
69
|
if (optionDomReference && !floatingUi_utils_dom.isElement(optionDomReference)) {
|
|
225
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.');
|
|
226
71
|
}
|
|
227
72
|
}
|
|
228
|
-
const store = useRenderElement.useRefWithInit(() => new
|
|
73
|
+
const store = useRenderElement.useRefWithInit(() => new ScrollAreaViewport.FloatingRootStore({
|
|
229
74
|
open,
|
|
230
75
|
onOpenChange,
|
|
231
76
|
referenceElement: elements.reference ?? null,
|
|
232
77
|
floatingElement: elements.floating ?? null,
|
|
233
|
-
triggerElements: new
|
|
78
|
+
triggerElements: new ScrollAreaViewport.PopupTriggerMap(),
|
|
234
79
|
floatingId,
|
|
235
80
|
nested,
|
|
236
81
|
noEmit: false
|
|
237
82
|
})).current;
|
|
238
|
-
|
|
83
|
+
clamp.useIsoLayoutEffect(() => {
|
|
239
84
|
const valuesToSync = {
|
|
240
85
|
open,
|
|
241
86
|
floatingId
|
|
@@ -275,8 +120,8 @@ function useFloating(options = {}) {
|
|
|
275
120
|
};
|
|
276
121
|
const [positionReference, setPositionReferenceRaw] = React__namespace.useState(null);
|
|
277
122
|
const domReferenceRef = React__namespace.useRef(null);
|
|
278
|
-
const tree =
|
|
279
|
-
|
|
123
|
+
const tree = ScrollAreaViewport.useFloatingTree(externalTree);
|
|
124
|
+
clamp.useIsoLayoutEffect(() => {
|
|
280
125
|
if (rootContextElements.domReference) {
|
|
281
126
|
domReferenceRef.current = rootContextElements.domReference;
|
|
282
127
|
}
|
|
@@ -351,7 +196,7 @@ function useFloating(options = {}) {
|
|
|
351
196
|
nodeId,
|
|
352
197
|
rootStore: rootContext
|
|
353
198
|
}), [position, refs, elements, nodeId, rootContext, open, floatingId]);
|
|
354
|
-
|
|
199
|
+
clamp.useIsoLayoutEffect(() => {
|
|
355
200
|
rootContext.context.dataRef.current.floatingContext = context;
|
|
356
201
|
const node = tree?.nodesRef.current.find(n => n.id === nodeId);
|
|
357
202
|
if (node) {
|
|
@@ -367,7 +212,7 @@ function useFloating(options = {}) {
|
|
|
367
212
|
}), [position, refs, elements, context, rootContext]);
|
|
368
213
|
}
|
|
369
214
|
|
|
370
|
-
const isMacSafari =
|
|
215
|
+
const isMacSafari = clamp.isMac && clamp.isSafari;
|
|
371
216
|
/**
|
|
372
217
|
* Opens the floating element while the reference element has focus, like CSS
|
|
373
218
|
* `:focus`.
|
|
@@ -386,7 +231,7 @@ function useFocus(context, props = {}) {
|
|
|
386
231
|
const blockFocusRef = React__namespace.useRef(false);
|
|
387
232
|
// Track which reference should be blocked from re-opening after Escape/press dismissal.
|
|
388
233
|
const blockedReferenceRef = React__namespace.useRef(null);
|
|
389
|
-
const timeout =
|
|
234
|
+
const timeout = clamp.useTimeout();
|
|
390
235
|
const keyboardModalityRef = React__namespace.useRef(true);
|
|
391
236
|
React__namespace.useEffect(() => {
|
|
392
237
|
const domReference = store.select('domReferenceElement');
|
|
@@ -400,7 +245,7 @@ function useFocus(context, props = {}) {
|
|
|
400
245
|
// return to the tab/window.
|
|
401
246
|
function onBlur() {
|
|
402
247
|
const currentDomReference = store.select('domReferenceElement');
|
|
403
|
-
if (!store.select('open') && floatingUi_utils_dom.isHTMLElement(currentDomReference) && currentDomReference ===
|
|
248
|
+
if (!store.select('open') && floatingUi_utils_dom.isHTMLElement(currentDomReference) && currentDomReference === ScrollAreaViewport.activeElement(clamp.ownerDocument(currentDomReference))) {
|
|
404
249
|
blockFocusRef.current = true;
|
|
405
250
|
}
|
|
406
251
|
}
|
|
@@ -428,7 +273,7 @@ function useFocus(context, props = {}) {
|
|
|
428
273
|
return undefined;
|
|
429
274
|
}
|
|
430
275
|
function onOpenChangeLocal(details) {
|
|
431
|
-
if (details.reason ===
|
|
276
|
+
if (details.reason === clamp.triggerPress || details.reason === clamp.escapeKey) {
|
|
432
277
|
const referenceElement = store.select('domReferenceElement');
|
|
433
278
|
if (floatingUi_utils_dom.isElement(referenceElement)) {
|
|
434
279
|
blockedReferenceRef.current = referenceElement;
|
|
@@ -455,33 +300,33 @@ function useFocus(context, props = {}) {
|
|
|
455
300
|
blockFocusRef.current = false;
|
|
456
301
|
blockedReferenceRef.current = null;
|
|
457
302
|
}
|
|
458
|
-
const target =
|
|
303
|
+
const target = ScrollAreaViewport.getTarget(event.nativeEvent);
|
|
459
304
|
if (floatingUi_utils_dom.isElement(target)) {
|
|
460
305
|
// Safari fails to match `:focus-visible` if focus was initially
|
|
461
306
|
// outside the document.
|
|
462
307
|
if (isMacSafari && !event.relatedTarget) {
|
|
463
|
-
if (!keyboardModalityRef.current && !
|
|
308
|
+
if (!keyboardModalityRef.current && !ScrollAreaViewport.isTypeableElement(target)) {
|
|
464
309
|
return;
|
|
465
310
|
}
|
|
466
|
-
} else if (!
|
|
311
|
+
} else if (!ScrollAreaViewport.matchesFocusVisible(target)) {
|
|
467
312
|
return;
|
|
468
313
|
}
|
|
469
314
|
}
|
|
470
|
-
const movedFromOtherEnabledTrigger =
|
|
315
|
+
const movedFromOtherEnabledTrigger = ScrollAreaViewport.isTargetInsideEnabledTrigger(event.relatedTarget, store.context.triggerElements);
|
|
471
316
|
const {
|
|
472
317
|
nativeEvent,
|
|
473
318
|
currentTarget
|
|
474
319
|
} = event;
|
|
475
320
|
const delayValue = typeof delay === 'function' ? delay() : delay;
|
|
476
321
|
if (store.select('open') && movedFromOtherEnabledTrigger || delayValue === 0 || delayValue === undefined) {
|
|
477
|
-
store.setOpen(true,
|
|
322
|
+
store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerFocus, nativeEvent, currentTarget));
|
|
478
323
|
return;
|
|
479
324
|
}
|
|
480
325
|
timeout.start(delayValue, () => {
|
|
481
326
|
if (blockFocusRef.current) {
|
|
482
327
|
return;
|
|
483
328
|
}
|
|
484
|
-
store.setOpen(true,
|
|
329
|
+
store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerFocus, nativeEvent, currentTarget));
|
|
485
330
|
});
|
|
486
331
|
},
|
|
487
332
|
onBlur(event) {
|
|
@@ -492,12 +337,12 @@ function useFocus(context, props = {}) {
|
|
|
492
337
|
|
|
493
338
|
// Hit the non-modal focus management portal guard. Focus will be
|
|
494
339
|
// moved into the floating element immediately after.
|
|
495
|
-
const movedToFocusGuard = floatingUi_utils_dom.isElement(relatedTarget) && relatedTarget.hasAttribute(
|
|
340
|
+
const movedToFocusGuard = floatingUi_utils_dom.isElement(relatedTarget) && relatedTarget.hasAttribute(ScrollAreaViewport.createAttribute('focus-guard')) && relatedTarget.getAttribute('data-type') === 'outside';
|
|
496
341
|
|
|
497
342
|
// Wait for the window blur listener to fire.
|
|
498
343
|
timeout.start(0, () => {
|
|
499
344
|
const domReference = store.select('domReferenceElement');
|
|
500
|
-
const activeEl =
|
|
345
|
+
const activeEl = ScrollAreaViewport.activeElement(domReference ? domReference.ownerDocument : document);
|
|
501
346
|
|
|
502
347
|
// Focus left the page, keep it open.
|
|
503
348
|
if (!relatedTarget && activeEl === domReference) {
|
|
@@ -511,7 +356,7 @@ function useFocus(context, props = {}) {
|
|
|
511
356
|
// as it will only point to the shadow host of the newly focused element
|
|
512
357
|
// and not the element that actually has received focus if it is located
|
|
513
358
|
// inside a shadow root.
|
|
514
|
-
if (
|
|
359
|
+
if (ScrollAreaViewport.contains(dataRef.current.floatingContext?.refs.floating.current, activeEl) || ScrollAreaViewport.contains(domReference, activeEl) || movedToFocusGuard) {
|
|
515
360
|
return;
|
|
516
361
|
}
|
|
517
362
|
|
|
@@ -519,10 +364,10 @@ function useFocus(context, props = {}) {
|
|
|
519
364
|
// the floating element. The focus handler of that trigger will
|
|
520
365
|
// handle the open state.
|
|
521
366
|
const nextFocusedElement = relatedTarget ?? activeEl;
|
|
522
|
-
if (
|
|
367
|
+
if (ScrollAreaViewport.isTargetInsideEnabledTrigger(nextFocusedElement, store.context.triggerElements)) {
|
|
523
368
|
return;
|
|
524
369
|
}
|
|
525
|
-
store.setOpen(false,
|
|
370
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.triggerFocus, nativeEvent));
|
|
526
371
|
});
|
|
527
372
|
}
|
|
528
373
|
}), [dataRef, store, timeout, delay]);
|
|
@@ -532,7 +377,7 @@ function useFocus(context, props = {}) {
|
|
|
532
377
|
} : {}, [enabled, reference]);
|
|
533
378
|
}
|
|
534
379
|
|
|
535
|
-
const interactiveSelector = `button,a,[role="button"],select,[tabindex]:not([tabindex="-1"]),${
|
|
380
|
+
const interactiveSelector = `button,a,[role="button"],select,[tabindex]:not([tabindex="-1"]),${ScrollAreaViewport.TYPEABLE_SELECTOR}`;
|
|
536
381
|
function isInteractiveElement(element) {
|
|
537
382
|
return element ? Boolean(element.closest(interactiveSelector)) : false;
|
|
538
383
|
}
|
|
@@ -547,8 +392,8 @@ class HoverInteraction {
|
|
|
547
392
|
this.pointerEventsReferenceElement = null;
|
|
548
393
|
this.pointerEventsFloatingElement = null;
|
|
549
394
|
this.restTimeoutPending = false;
|
|
550
|
-
this.openChangeTimeout = new
|
|
551
|
-
this.restTimeout = new
|
|
395
|
+
this.openChangeTimeout = new clamp.Timeout();
|
|
396
|
+
this.restTimeout = new clamp.Timeout();
|
|
552
397
|
this.handleCloseOptions = undefined;
|
|
553
398
|
}
|
|
554
399
|
static create() {
|
|
@@ -595,7 +440,7 @@ function useHoverInteractionSharedState(store) {
|
|
|
595
440
|
if (!data.hoverInteractionState) {
|
|
596
441
|
data.hoverInteractionState = instance;
|
|
597
442
|
}
|
|
598
|
-
|
|
443
|
+
clamp.useOnMount(data.hoverInteractionState.disposeEffect);
|
|
599
444
|
return data.hoverInteractionState;
|
|
600
445
|
}
|
|
601
446
|
|
|
@@ -615,22 +460,22 @@ function useHoverFloatingInteraction(context, parameters = {}) {
|
|
|
615
460
|
closeDelay: closeDelayProp = 0
|
|
616
461
|
} = parameters;
|
|
617
462
|
const instance = useHoverInteractionSharedState(store);
|
|
618
|
-
const tree =
|
|
619
|
-
const parentId =
|
|
620
|
-
const isClickLikeOpenEvent$1 =
|
|
463
|
+
const tree = ScrollAreaViewport.useFloatingTree();
|
|
464
|
+
const parentId = ScrollAreaViewport.useFloatingParentNodeId();
|
|
465
|
+
const isClickLikeOpenEvent$1 = clamp.useStableCallback(() => {
|
|
621
466
|
return isClickLikeOpenEvent(dataRef.current.openEvent?.type, instance.interactedInside);
|
|
622
467
|
});
|
|
623
|
-
const isHoverOpen =
|
|
468
|
+
const isHoverOpen = clamp.useStableCallback(() => {
|
|
624
469
|
const type = dataRef.current.openEvent?.type;
|
|
625
470
|
return type?.includes('mouse') && type !== 'mousedown';
|
|
626
471
|
});
|
|
627
|
-
const isRelatedTargetInsideEnabledTrigger =
|
|
628
|
-
return
|
|
472
|
+
const isRelatedTargetInsideEnabledTrigger = clamp.useStableCallback(target => {
|
|
473
|
+
return ScrollAreaViewport.isTargetInsideEnabledTrigger(target, store.context.triggerElements);
|
|
629
474
|
});
|
|
630
475
|
const closeWithDelay = React__namespace.useCallback(event => {
|
|
631
476
|
const closeDelay = getDelay(closeDelayProp, 'close', instance.pointerType);
|
|
632
477
|
const close = () => {
|
|
633
|
-
store.setOpen(false,
|
|
478
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.triggerHover, event));
|
|
634
479
|
tree?.events.emit('floating.closed', event);
|
|
635
480
|
};
|
|
636
481
|
if (closeDelay) {
|
|
@@ -640,18 +485,18 @@ function useHoverFloatingInteraction(context, parameters = {}) {
|
|
|
640
485
|
close();
|
|
641
486
|
}
|
|
642
487
|
}, [closeDelayProp, store, instance, tree]);
|
|
643
|
-
const clearPointerEvents =
|
|
488
|
+
const clearPointerEvents = clamp.useStableCallback(() => {
|
|
644
489
|
clearSafePolygonPointerEventsMutation(instance);
|
|
645
490
|
});
|
|
646
|
-
const handleInteractInside =
|
|
647
|
-
const target =
|
|
491
|
+
const handleInteractInside = clamp.useStableCallback(event => {
|
|
492
|
+
const target = ScrollAreaViewport.getTarget(event);
|
|
648
493
|
if (!isInteractiveElement(target)) {
|
|
649
494
|
instance.interactedInside = false;
|
|
650
495
|
return;
|
|
651
496
|
}
|
|
652
497
|
instance.interactedInside = target?.closest('[aria-haspopup]') != null;
|
|
653
498
|
});
|
|
654
|
-
|
|
499
|
+
clamp.useIsoLayoutEffect(() => {
|
|
655
500
|
if (!open) {
|
|
656
501
|
instance.pointerType = undefined;
|
|
657
502
|
instance.restTimeoutPending = false;
|
|
@@ -662,14 +507,14 @@ function useHoverFloatingInteraction(context, parameters = {}) {
|
|
|
662
507
|
React__namespace.useEffect(() => {
|
|
663
508
|
return clearPointerEvents;
|
|
664
509
|
}, [clearPointerEvents]);
|
|
665
|
-
|
|
510
|
+
clamp.useIsoLayoutEffect(() => {
|
|
666
511
|
if (!enabled) {
|
|
667
512
|
return undefined;
|
|
668
513
|
}
|
|
669
514
|
if (open && instance.handleCloseOptions?.blockPointerEvents && isHoverOpen() && floatingUi_utils_dom.isElement(domReferenceElement) && floatingElement) {
|
|
670
515
|
const ref = domReferenceElement;
|
|
671
516
|
const floatingEl = floatingElement;
|
|
672
|
-
const doc =
|
|
517
|
+
const doc = clamp.ownerDocument(floatingElement);
|
|
673
518
|
const parentFloating = tree?.nodesRef.current.find(node => node.id === parentId)?.context?.elements.floating;
|
|
674
519
|
if (parentFloating) {
|
|
675
520
|
parentFloating.style.pointerEvents = '';
|
|
@@ -686,7 +531,7 @@ function useHoverFloatingInteraction(context, parameters = {}) {
|
|
|
686
531
|
}
|
|
687
532
|
return undefined;
|
|
688
533
|
}, [enabled, open, domReferenceElement, floatingElement, instance, isHoverOpen, tree, parentId, clearPointerEvents]);
|
|
689
|
-
const childClosedTimeout =
|
|
534
|
+
const childClosedTimeout = clamp.useTimeout();
|
|
690
535
|
React__namespace.useEffect(() => {
|
|
691
536
|
if (!enabled) {
|
|
692
537
|
return undefined;
|
|
@@ -698,7 +543,7 @@ function useHoverFloatingInteraction(context, parameters = {}) {
|
|
|
698
543
|
clearPointerEvents();
|
|
699
544
|
}
|
|
700
545
|
function onFloatingMouseLeave(event) {
|
|
701
|
-
if (tree && parentId &&
|
|
546
|
+
if (tree && parentId && ScrollAreaViewport.getNodeChildren(tree.nodesRef.current, parentId).length > 0) {
|
|
702
547
|
tree.events.on('floating.closed', onNodeClosed);
|
|
703
548
|
return;
|
|
704
549
|
}
|
|
@@ -719,13 +564,13 @@ function useHoverFloatingInteraction(context, parameters = {}) {
|
|
|
719
564
|
}
|
|
720
565
|
}
|
|
721
566
|
function onNodeClosed(event) {
|
|
722
|
-
if (!tree || !parentId ||
|
|
567
|
+
if (!tree || !parentId || ScrollAreaViewport.getNodeChildren(tree.nodesRef.current, parentId).length > 0) {
|
|
723
568
|
return;
|
|
724
569
|
}
|
|
725
570
|
// Allow the mouseenter event to fire in case child was closed because mouse moved into parent.
|
|
726
571
|
childClosedTimeout.start(0, () => {
|
|
727
572
|
tree.events.off('floating.closed', onNodeClosed);
|
|
728
|
-
store.setOpen(false,
|
|
573
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.triggerHover, event));
|
|
729
574
|
tree.events.emit('floating.closed', event);
|
|
730
575
|
});
|
|
731
576
|
}
|
|
@@ -772,28 +617,28 @@ function useHoverReferenceInteraction(context, props = {}) {
|
|
|
772
617
|
isActiveTrigger = true,
|
|
773
618
|
getHandleCloseContext
|
|
774
619
|
} = props;
|
|
775
|
-
const tree =
|
|
620
|
+
const tree = ScrollAreaViewport.useFloatingTree(externalTree);
|
|
776
621
|
const instance = useHoverInteractionSharedState(store);
|
|
777
|
-
const handleCloseRef =
|
|
778
|
-
const delayRef =
|
|
779
|
-
const restMsRef =
|
|
780
|
-
const enabledRef =
|
|
622
|
+
const handleCloseRef = clamp.useValueAsRef(handleClose);
|
|
623
|
+
const delayRef = clamp.useValueAsRef(delay);
|
|
624
|
+
const restMsRef = clamp.useValueAsRef(restMs);
|
|
625
|
+
const enabledRef = clamp.useValueAsRef(enabled);
|
|
781
626
|
if (isActiveTrigger) {
|
|
782
627
|
// eslint-disable-next-line no-underscore-dangle
|
|
783
628
|
instance.handleCloseOptions = handleCloseRef.current?.__options;
|
|
784
629
|
}
|
|
785
|
-
const isClickLikeOpenEvent$1 =
|
|
630
|
+
const isClickLikeOpenEvent$1 = clamp.useStableCallback(() => {
|
|
786
631
|
return isClickLikeOpenEvent(dataRef.current.openEvent?.type, instance.interactedInside);
|
|
787
632
|
});
|
|
788
|
-
const isRelatedTargetInsideEnabledTrigger =
|
|
789
|
-
return
|
|
633
|
+
const isRelatedTargetInsideEnabledTrigger = clamp.useStableCallback(target => {
|
|
634
|
+
return ScrollAreaViewport.isTargetInsideEnabledTrigger(target, store.context.triggerElements);
|
|
790
635
|
});
|
|
791
|
-
const isOverInactiveTrigger =
|
|
636
|
+
const isOverInactiveTrigger = clamp.useStableCallback((currentDomReference, currentTarget, target) => {
|
|
792
637
|
const allTriggers = store.context.triggerElements;
|
|
793
638
|
|
|
794
639
|
// Fast path for normal usage where handlers are attached directly to triggers.
|
|
795
640
|
if (allTriggers.hasElement(currentTarget)) {
|
|
796
|
-
return !currentDomReference || !
|
|
641
|
+
return !currentDomReference || !ScrollAreaViewport.contains(currentDomReference, currentTarget);
|
|
797
642
|
}
|
|
798
643
|
|
|
799
644
|
// Fallback for delegated/wrapper usage where currentTarget may be outside the trigger map.
|
|
@@ -801,31 +646,31 @@ function useHoverReferenceInteraction(context, props = {}) {
|
|
|
801
646
|
return false;
|
|
802
647
|
}
|
|
803
648
|
const targetElement = target;
|
|
804
|
-
return allTriggers.hasMatchingElement(trigger =>
|
|
649
|
+
return allTriggers.hasMatchingElement(trigger => ScrollAreaViewport.contains(trigger, targetElement)) && (!currentDomReference || !ScrollAreaViewport.contains(currentDomReference, targetElement));
|
|
805
650
|
});
|
|
806
651
|
const closeWithDelay = React__namespace.useCallback((event, runElseBranch = true) => {
|
|
807
652
|
const closeDelay = getDelay(delayRef.current, 'close', instance.pointerType);
|
|
808
653
|
if (closeDelay) {
|
|
809
654
|
instance.openChangeTimeout.start(closeDelay, () => {
|
|
810
|
-
store.setOpen(false,
|
|
655
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.triggerHover, event));
|
|
811
656
|
tree?.events.emit('floating.closed', event);
|
|
812
657
|
});
|
|
813
658
|
} else if (runElseBranch) {
|
|
814
659
|
instance.openChangeTimeout.clear();
|
|
815
|
-
store.setOpen(false,
|
|
660
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.triggerHover, event));
|
|
816
661
|
tree?.events.emit('floating.closed', event);
|
|
817
662
|
}
|
|
818
663
|
}, [delayRef, store, instance, tree]);
|
|
819
|
-
const cleanupMouseMoveHandler =
|
|
664
|
+
const cleanupMouseMoveHandler = clamp.useStableCallback(() => {
|
|
820
665
|
if (!instance.handler) {
|
|
821
666
|
return;
|
|
822
667
|
}
|
|
823
|
-
const doc =
|
|
668
|
+
const doc = clamp.ownerDocument(store.select('domReferenceElement'));
|
|
824
669
|
doc.removeEventListener('mousemove', instance.handler);
|
|
825
670
|
instance.handler = undefined;
|
|
826
671
|
});
|
|
827
672
|
React__namespace.useEffect(() => cleanupMouseMoveHandler, [cleanupMouseMoveHandler]);
|
|
828
|
-
const clearPointerEvents =
|
|
673
|
+
const clearPointerEvents = clamp.useStableCallback(() => {
|
|
829
674
|
clearSafePolygonPointerEventsMutation(instance);
|
|
830
675
|
});
|
|
831
676
|
|
|
@@ -860,7 +705,7 @@ function useHoverReferenceInteraction(context, props = {}) {
|
|
|
860
705
|
function onMouseEnter(event) {
|
|
861
706
|
instance.openChangeTimeout.clear();
|
|
862
707
|
instance.blockMouseMove = false;
|
|
863
|
-
if (mouseOnly && !
|
|
708
|
+
if (mouseOnly && !clamp.isMouseLikePointerType(instance.pointerType)) {
|
|
864
709
|
return;
|
|
865
710
|
}
|
|
866
711
|
|
|
@@ -879,15 +724,15 @@ function useHoverReferenceInteraction(context, props = {}) {
|
|
|
879
724
|
|
|
880
725
|
// When moving between triggers while already open, open immediately without delay
|
|
881
726
|
if (isOverInactive && isOpen) {
|
|
882
|
-
store.setOpen(true,
|
|
727
|
+
store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerHover, event, triggerNode));
|
|
883
728
|
} else if (openDelay) {
|
|
884
729
|
instance.openChangeTimeout.start(openDelay, () => {
|
|
885
730
|
if (shouldOpen) {
|
|
886
|
-
store.setOpen(true,
|
|
731
|
+
store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerHover, event, triggerNode));
|
|
887
732
|
}
|
|
888
733
|
});
|
|
889
734
|
} else if (shouldOpen) {
|
|
890
|
-
store.setOpen(true,
|
|
735
|
+
store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerHover, event, triggerNode));
|
|
891
736
|
}
|
|
892
737
|
}
|
|
893
738
|
function onMouseLeave(event) {
|
|
@@ -897,7 +742,7 @@ function useHoverReferenceInteraction(context, props = {}) {
|
|
|
897
742
|
}
|
|
898
743
|
cleanupMouseMoveHandler();
|
|
899
744
|
const domReferenceElement = store.select('domReferenceElement');
|
|
900
|
-
const doc =
|
|
745
|
+
const doc = clamp.ownerDocument(domReferenceElement);
|
|
901
746
|
instance.restTimeout.clear();
|
|
902
747
|
instance.restTimeoutPending = false;
|
|
903
748
|
const handleCloseContextBase = dataRef.current.floatingContext ?? getHandleCloseContext?.();
|
|
@@ -927,7 +772,7 @@ function useHoverReferenceInteraction(context, props = {}) {
|
|
|
927
772
|
instance.handler(event);
|
|
928
773
|
return;
|
|
929
774
|
}
|
|
930
|
-
const shouldClose = instance.pointerType === 'touch' ? !
|
|
775
|
+
const shouldClose = instance.pointerType === 'touch' ? !ScrollAreaViewport.contains(store.select('floatingElement'), event.relatedTarget) : true;
|
|
931
776
|
if (shouldClose) {
|
|
932
777
|
closeWithDelay(event);
|
|
933
778
|
}
|
|
@@ -965,7 +810,7 @@ function useHoverReferenceInteraction(context, props = {}) {
|
|
|
965
810
|
const currentDomReference = store.select('domReferenceElement');
|
|
966
811
|
const currentOpen = store.select('open');
|
|
967
812
|
const isOverInactive = isOverInactiveTrigger(currentDomReference, trigger, event.target);
|
|
968
|
-
if (mouseOnly && !
|
|
813
|
+
if (mouseOnly && !clamp.isMouseLikePointerType(instance.pointerType)) {
|
|
969
814
|
return;
|
|
970
815
|
}
|
|
971
816
|
const restMsValue = getRestMs(restMsRef.current);
|
|
@@ -986,7 +831,7 @@ function useHoverReferenceInteraction(context, props = {}) {
|
|
|
986
831
|
}
|
|
987
832
|
const latestOpen = store.select('open');
|
|
988
833
|
if (!instance.blockMouseMove && (!latestOpen || isOverInactive)) {
|
|
989
|
-
store.setOpen(true,
|
|
834
|
+
store.setOpen(true, clamp.createChangeEventDetails(clamp.triggerHover, nativeEvent, trigger));
|
|
990
835
|
}
|
|
991
836
|
}
|
|
992
837
|
if (instance.pointerType === 'touch') {
|
|
@@ -1016,23 +861,23 @@ function doSwitch(orientation, vertical, horizontal) {
|
|
|
1016
861
|
}
|
|
1017
862
|
}
|
|
1018
863
|
function isMainOrientationKey(key, orientation) {
|
|
1019
|
-
const vertical = key ===
|
|
1020
|
-
const horizontal = key ===
|
|
864
|
+
const vertical = key === ScrollAreaViewport.ARROW_UP || key === ScrollAreaViewport.ARROW_DOWN;
|
|
865
|
+
const horizontal = key === ScrollAreaViewport.ARROW_LEFT || key === ScrollAreaViewport.ARROW_RIGHT;
|
|
1021
866
|
return doSwitch(orientation, vertical, horizontal);
|
|
1022
867
|
}
|
|
1023
868
|
function isMainOrientationToEndKey(key, orientation, rtl) {
|
|
1024
|
-
const vertical = key ===
|
|
1025
|
-
const horizontal = rtl ? key ===
|
|
869
|
+
const vertical = key === ScrollAreaViewport.ARROW_DOWN;
|
|
870
|
+
const horizontal = rtl ? key === ScrollAreaViewport.ARROW_LEFT : key === ScrollAreaViewport.ARROW_RIGHT;
|
|
1026
871
|
return doSwitch(orientation, vertical, horizontal) || key === 'Enter' || key === ' ' || key === '';
|
|
1027
872
|
}
|
|
1028
873
|
function isCrossOrientationOpenKey(key, orientation, rtl) {
|
|
1029
|
-
const vertical = rtl ? key ===
|
|
1030
|
-
const horizontal = key ===
|
|
874
|
+
const vertical = rtl ? key === ScrollAreaViewport.ARROW_LEFT : key === ScrollAreaViewport.ARROW_RIGHT;
|
|
875
|
+
const horizontal = key === ScrollAreaViewport.ARROW_DOWN;
|
|
1031
876
|
return doSwitch(orientation, vertical, horizontal);
|
|
1032
877
|
}
|
|
1033
878
|
function isCrossOrientationCloseKey(key, orientation, rtl, cols) {
|
|
1034
|
-
const vertical = rtl ? key ===
|
|
1035
|
-
const horizontal = key ===
|
|
879
|
+
const vertical = rtl ? key === ScrollAreaViewport.ARROW_RIGHT : key === ScrollAreaViewport.ARROW_LEFT;
|
|
880
|
+
const horizontal = key === ScrollAreaViewport.ARROW_UP;
|
|
1036
881
|
if (orientation === 'both' || orientation === 'horizontal' && cols && cols > 1) {
|
|
1037
882
|
return key === ESCAPE;
|
|
1038
883
|
}
|
|
@@ -1084,19 +929,19 @@ function useListNavigation(context, props) {
|
|
|
1084
929
|
console.warn('In grid list navigation mode (`cols` > 1), the `orientation` should', 'be either "horizontal" or "both".');
|
|
1085
930
|
}
|
|
1086
931
|
}
|
|
1087
|
-
const floatingFocusElement =
|
|
1088
|
-
const floatingFocusElementRef =
|
|
1089
|
-
const parentId =
|
|
1090
|
-
const tree =
|
|
1091
|
-
|
|
932
|
+
const floatingFocusElement = ScrollAreaViewport.getFloatingFocusElement(floatingElement);
|
|
933
|
+
const floatingFocusElementRef = clamp.useValueAsRef(floatingFocusElement);
|
|
934
|
+
const parentId = ScrollAreaViewport.useFloatingParentNodeId();
|
|
935
|
+
const tree = ScrollAreaViewport.useFloatingTree(externalTree);
|
|
936
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1092
937
|
dataRef.current.orientation = orientation;
|
|
1093
938
|
}, [dataRef, orientation]);
|
|
1094
|
-
const typeableComboboxReference =
|
|
939
|
+
const typeableComboboxReference = ScrollAreaViewport.isTypeableCombobox(domReferenceElement);
|
|
1095
940
|
const focusItemOnOpenRef = React__namespace.useRef(focusItemOnOpen);
|
|
1096
941
|
const indexRef = React__namespace.useRef(selectedIndex ?? -1);
|
|
1097
942
|
const keyRef = React__namespace.useRef(null);
|
|
1098
943
|
const isPointerModalityRef = React__namespace.useRef(true);
|
|
1099
|
-
const onNavigate =
|
|
944
|
+
const onNavigate = clamp.useStableCallback(event => {
|
|
1100
945
|
onNavigateProp(indexRef.current === -1 ? null : indexRef.current, event);
|
|
1101
946
|
});
|
|
1102
947
|
const previousOnNavigateRef = React__namespace.useRef(onNavigate);
|
|
@@ -1104,16 +949,16 @@ function useListNavigation(context, props) {
|
|
|
1104
949
|
const previousOpenRef = React__namespace.useRef(open);
|
|
1105
950
|
const forceSyncFocusRef = React__namespace.useRef(false);
|
|
1106
951
|
const forceScrollIntoViewRef = React__namespace.useRef(false);
|
|
1107
|
-
const disabledIndicesRef =
|
|
1108
|
-
const latestOpenRef =
|
|
1109
|
-
const selectedIndexRef =
|
|
1110
|
-
const resetOnPointerLeaveRef =
|
|
1111
|
-
const focusItem =
|
|
952
|
+
const disabledIndicesRef = clamp.useValueAsRef(disabledIndices);
|
|
953
|
+
const latestOpenRef = clamp.useValueAsRef(open);
|
|
954
|
+
const selectedIndexRef = clamp.useValueAsRef(selectedIndex);
|
|
955
|
+
const resetOnPointerLeaveRef = clamp.useValueAsRef(resetOnPointerLeave);
|
|
956
|
+
const focusItem = clamp.useStableCallback(() => {
|
|
1112
957
|
function runFocus(item) {
|
|
1113
958
|
if (virtual) {
|
|
1114
959
|
tree?.events.emit('virtualfocus', item);
|
|
1115
960
|
} else {
|
|
1116
|
-
|
|
961
|
+
ScrollAreaViewport.enqueueFocus(item, {
|
|
1117
962
|
sync: forceSyncFocusRef.current,
|
|
1118
963
|
preventScroll: true
|
|
1119
964
|
});
|
|
@@ -1149,7 +994,7 @@ function useListNavigation(context, props) {
|
|
|
1149
994
|
|
|
1150
995
|
// Sync `selectedIndex` to be the `activeIndex` upon opening the floating
|
|
1151
996
|
// element. Also, reset `activeIndex` upon closing the floating element.
|
|
1152
|
-
|
|
997
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1153
998
|
if (!enabled) {
|
|
1154
999
|
return;
|
|
1155
1000
|
}
|
|
@@ -1172,7 +1017,7 @@ function useListNavigation(context, props) {
|
|
|
1172
1017
|
|
|
1173
1018
|
// Sync `activeIndex` to be the focused item while the floating element is
|
|
1174
1019
|
// open.
|
|
1175
|
-
|
|
1020
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1176
1021
|
if (!enabled) {
|
|
1177
1022
|
return;
|
|
1178
1023
|
}
|
|
@@ -1210,14 +1055,14 @@ function useListNavigation(context, props) {
|
|
|
1210
1055
|
runs += 1;
|
|
1211
1056
|
} else {
|
|
1212
1057
|
// initially focus the first non-disabled item
|
|
1213
|
-
indexRef.current = keyRef.current == null || isMainOrientationToEndKey(keyRef.current, orientation, rtl) || nested ?
|
|
1058
|
+
indexRef.current = keyRef.current == null || isMainOrientationToEndKey(keyRef.current, orientation, rtl) || nested ? ScrollAreaViewport.getMinListIndex(listRef) : ScrollAreaViewport.getMaxListIndex(listRef);
|
|
1214
1059
|
keyRef.current = null;
|
|
1215
1060
|
onNavigate();
|
|
1216
1061
|
}
|
|
1217
1062
|
};
|
|
1218
1063
|
waitForListPopulated();
|
|
1219
1064
|
}
|
|
1220
|
-
} else if (!
|
|
1065
|
+
} else if (!ScrollAreaViewport.isIndexOutOfListBounds(listRef, activeIndex)) {
|
|
1221
1066
|
indexRef.current = activeIndex;
|
|
1222
1067
|
focusItem();
|
|
1223
1068
|
forceScrollIntoViewRef.current = false;
|
|
@@ -1226,26 +1071,26 @@ function useListNavigation(context, props) {
|
|
|
1226
1071
|
|
|
1227
1072
|
// Ensure the parent floating element has focus when a nested child closes
|
|
1228
1073
|
// to allow arrow key navigation to work after the pointer leaves the child.
|
|
1229
|
-
|
|
1074
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1230
1075
|
if (!enabled || floatingElement || !tree || virtual || !previousMountedRef.current) {
|
|
1231
1076
|
return;
|
|
1232
1077
|
}
|
|
1233
1078
|
const nodes = tree.nodesRef.current;
|
|
1234
1079
|
const parent = nodes.find(node => node.id === parentId)?.context?.elements.floating;
|
|
1235
|
-
const activeEl =
|
|
1236
|
-
const treeContainsActiveEl = nodes.some(node => node.context &&
|
|
1080
|
+
const activeEl = ScrollAreaViewport.activeElement(clamp.ownerDocument(floatingElement));
|
|
1081
|
+
const treeContainsActiveEl = nodes.some(node => node.context && ScrollAreaViewport.contains(node.context.elements.floating, activeEl));
|
|
1237
1082
|
if (parent && !treeContainsActiveEl && isPointerModalityRef.current) {
|
|
1238
1083
|
parent.focus({
|
|
1239
1084
|
preventScroll: true
|
|
1240
1085
|
});
|
|
1241
1086
|
}
|
|
1242
1087
|
}, [enabled, floatingElement, tree, parentId, virtual]);
|
|
1243
|
-
|
|
1088
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1244
1089
|
previousOnNavigateRef.current = onNavigate;
|
|
1245
1090
|
previousOpenRef.current = open;
|
|
1246
1091
|
previousMountedRef.current = !!floatingElement;
|
|
1247
1092
|
});
|
|
1248
|
-
|
|
1093
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1249
1094
|
if (!open) {
|
|
1250
1095
|
keyRef.current = null;
|
|
1251
1096
|
focusItemOnOpenRef.current = focusItemOnOpen;
|
|
@@ -1293,15 +1138,15 @@ function useListNavigation(context, props) {
|
|
|
1293
1138
|
if (!resetOnPointerLeaveRef.current) {
|
|
1294
1139
|
return;
|
|
1295
1140
|
}
|
|
1296
|
-
|
|
1141
|
+
ScrollAreaViewport.enqueueFocus(null, {
|
|
1297
1142
|
sync: true
|
|
1298
1143
|
});
|
|
1299
1144
|
indexRef.current = -1;
|
|
1300
1145
|
onNavigate(event);
|
|
1301
1146
|
if (!virtual) {
|
|
1302
1147
|
const floatingFocusEl = floatingFocusElementRef.current;
|
|
1303
|
-
const activeEl =
|
|
1304
|
-
if (floatingFocusEl &&
|
|
1148
|
+
const activeEl = ScrollAreaViewport.activeElement(clamp.ownerDocument(floatingFocusEl));
|
|
1149
|
+
if (floatingFocusEl && ScrollAreaViewport.contains(floatingFocusEl, activeEl)) {
|
|
1305
1150
|
floatingFocusEl.focus({
|
|
1306
1151
|
preventScroll: true
|
|
1307
1152
|
});
|
|
@@ -1314,7 +1159,7 @@ function useListNavigation(context, props) {
|
|
|
1314
1159
|
const getParentOrientation = React__namespace.useCallback(() => {
|
|
1315
1160
|
return parentOrientation ?? tree?.nodesRef.current.find(node => node.id === parentId)?.context?.dataRef?.current.orientation;
|
|
1316
1161
|
}, [parentId, tree, parentOrientation]);
|
|
1317
|
-
const commonOnKeyDown =
|
|
1162
|
+
const commonOnKeyDown = clamp.useStableCallback(event => {
|
|
1318
1163
|
isPointerModalityRef.current = false;
|
|
1319
1164
|
forceSyncFocusRef.current = true;
|
|
1320
1165
|
|
|
@@ -1336,9 +1181,9 @@ function useListNavigation(context, props) {
|
|
|
1336
1181
|
// If the nested list's close key is also the parent navigation key,
|
|
1337
1182
|
// let the parent navigate. Otherwise, stop propagating the event.
|
|
1338
1183
|
if (!isMainOrientationKey(event.key, getParentOrientation())) {
|
|
1339
|
-
|
|
1184
|
+
clamp.stopEvent(event);
|
|
1340
1185
|
}
|
|
1341
|
-
store.setOpen(false,
|
|
1186
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.listNavigation, event.nativeEvent));
|
|
1342
1187
|
if (floatingUi_utils_dom.isHTMLElement(domReferenceElement)) {
|
|
1343
1188
|
if (virtual) {
|
|
1344
1189
|
tree?.events.emit('virtualfocus', domReferenceElement);
|
|
@@ -1349,16 +1194,16 @@ function useListNavigation(context, props) {
|
|
|
1349
1194
|
return;
|
|
1350
1195
|
}
|
|
1351
1196
|
const currentIndex = indexRef.current;
|
|
1352
|
-
const minIndex =
|
|
1353
|
-
const maxIndex =
|
|
1197
|
+
const minIndex = ScrollAreaViewport.getMinListIndex(listRef, disabledIndices);
|
|
1198
|
+
const maxIndex = ScrollAreaViewport.getMaxListIndex(listRef, disabledIndices);
|
|
1354
1199
|
if (!typeableComboboxReference) {
|
|
1355
1200
|
if (event.key === 'Home') {
|
|
1356
|
-
|
|
1201
|
+
clamp.stopEvent(event);
|
|
1357
1202
|
indexRef.current = minIndex;
|
|
1358
1203
|
onNavigate(event);
|
|
1359
1204
|
}
|
|
1360
1205
|
if (event.key === 'End') {
|
|
1361
|
-
|
|
1206
|
+
clamp.stopEvent(event);
|
|
1362
1207
|
indexRef.current = maxIndex;
|
|
1363
1208
|
onNavigate(event);
|
|
1364
1209
|
}
|
|
@@ -1374,11 +1219,11 @@ function useListNavigation(context, props) {
|
|
|
1374
1219
|
}));
|
|
1375
1220
|
// To calculate movements on the grid, we use hypothetical cell indices
|
|
1376
1221
|
// as if every item was 1x1, then convert back to real indices.
|
|
1377
|
-
const cellMap =
|
|
1378
|
-
const minGridIndex = cellMap.findIndex(index => index != null && !
|
|
1222
|
+
const cellMap = ScrollAreaViewport.createGridCellMap(sizes, cols);
|
|
1223
|
+
const minGridIndex = cellMap.findIndex(index => index != null && !ScrollAreaViewport.isListIndexDisabled(listRef, index, disabledIndices));
|
|
1379
1224
|
// last enabled index
|
|
1380
|
-
const maxGridIndex = cellMap.reduce((foundIndex, index, cellIndex) => index != null && !
|
|
1381
|
-
const index = cellMap[
|
|
1225
|
+
const maxGridIndex = cellMap.reduce((foundIndex, index, cellIndex) => index != null && !ScrollAreaViewport.isListIndexDisabled(listRef, index, disabledIndices) ? cellIndex : foundIndex, -1);
|
|
1226
|
+
const index = cellMap[ScrollAreaViewport.getGridNavigatedIndex({
|
|
1382
1227
|
current: cellMap.map(itemIndex => itemIndex != null ? listRef.current[itemIndex] : null)
|
|
1383
1228
|
}, {
|
|
1384
1229
|
event,
|
|
@@ -1388,15 +1233,15 @@ function useListNavigation(context, props) {
|
|
|
1388
1233
|
cols,
|
|
1389
1234
|
// treat undefined (empty grid spaces) as disabled indices so we
|
|
1390
1235
|
// don't end up in them
|
|
1391
|
-
disabledIndices:
|
|
1236
|
+
disabledIndices: ScrollAreaViewport.getGridCellIndices([...((typeof disabledIndices !== 'function' ? disabledIndices : null) || listRef.current.map((_, listIndex) => ScrollAreaViewport.isListIndexDisabled(listRef, listIndex, disabledIndices) ? listIndex : undefined)), undefined], cellMap),
|
|
1392
1237
|
minIndex: minGridIndex,
|
|
1393
1238
|
maxIndex: maxGridIndex,
|
|
1394
|
-
prevIndex:
|
|
1239
|
+
prevIndex: ScrollAreaViewport.getGridCellIndexOfCorner(indexRef.current > maxIndex ? minIndex : indexRef.current, sizes, cellMap, cols,
|
|
1395
1240
|
// use a corner matching the edge closest to the direction
|
|
1396
1241
|
// we're moving in so we don't end up in the same item. Prefer
|
|
1397
1242
|
// top/left over bottom/right.
|
|
1398
1243
|
// eslint-disable-next-line no-nested-ternary
|
|
1399
|
-
event.key ===
|
|
1244
|
+
event.key === ScrollAreaViewport.ARROW_DOWN ? 'bl' : event.key === (rtl ? ScrollAreaViewport.ARROW_LEFT : ScrollAreaViewport.ARROW_RIGHT) ? 'tr' : 'tl'),
|
|
1400
1245
|
stopEvent: true
|
|
1401
1246
|
})];
|
|
1402
1247
|
if (index != null) {
|
|
@@ -1408,10 +1253,10 @@ function useListNavigation(context, props) {
|
|
|
1408
1253
|
}
|
|
1409
1254
|
}
|
|
1410
1255
|
if (isMainOrientationKey(event.key, orientation)) {
|
|
1411
|
-
|
|
1256
|
+
clamp.stopEvent(event);
|
|
1412
1257
|
|
|
1413
1258
|
// Reset the index if no item is focused.
|
|
1414
|
-
if (open && !virtual &&
|
|
1259
|
+
if (open && !virtual && ScrollAreaViewport.activeElement(event.currentTarget.ownerDocument) === event.currentTarget) {
|
|
1415
1260
|
indexRef.current = isMainOrientationToEndKey(event.key, orientation, rtl) ? minIndex : maxIndex;
|
|
1416
1261
|
onNavigate(event);
|
|
1417
1262
|
return;
|
|
@@ -1427,13 +1272,13 @@ function useListNavigation(context, props) {
|
|
|
1427
1272
|
indexRef.current = minIndex;
|
|
1428
1273
|
}
|
|
1429
1274
|
} else {
|
|
1430
|
-
indexRef.current =
|
|
1275
|
+
indexRef.current = ScrollAreaViewport.findNonDisabledListIndex(listRef, {
|
|
1431
1276
|
startingIndex: currentIndex,
|
|
1432
1277
|
disabledIndices
|
|
1433
1278
|
});
|
|
1434
1279
|
}
|
|
1435
1280
|
} else {
|
|
1436
|
-
indexRef.current = Math.min(maxIndex,
|
|
1281
|
+
indexRef.current = Math.min(maxIndex, ScrollAreaViewport.findNonDisabledListIndex(listRef, {
|
|
1437
1282
|
startingIndex: currentIndex,
|
|
1438
1283
|
disabledIndices
|
|
1439
1284
|
}));
|
|
@@ -1448,20 +1293,20 @@ function useListNavigation(context, props) {
|
|
|
1448
1293
|
indexRef.current = maxIndex;
|
|
1449
1294
|
}
|
|
1450
1295
|
} else {
|
|
1451
|
-
indexRef.current =
|
|
1296
|
+
indexRef.current = ScrollAreaViewport.findNonDisabledListIndex(listRef, {
|
|
1452
1297
|
startingIndex: currentIndex,
|
|
1453
1298
|
decrement: true,
|
|
1454
1299
|
disabledIndices
|
|
1455
1300
|
});
|
|
1456
1301
|
}
|
|
1457
1302
|
} else {
|
|
1458
|
-
indexRef.current = Math.max(minIndex,
|
|
1303
|
+
indexRef.current = Math.max(minIndex, ScrollAreaViewport.findNonDisabledListIndex(listRef, {
|
|
1459
1304
|
startingIndex: currentIndex,
|
|
1460
1305
|
decrement: true,
|
|
1461
1306
|
disabledIndices
|
|
1462
1307
|
}));
|
|
1463
1308
|
}
|
|
1464
|
-
if (
|
|
1309
|
+
if (ScrollAreaViewport.isIndexOutOfListBounds(listRef, indexRef.current)) {
|
|
1465
1310
|
indexRef.current = -1;
|
|
1466
1311
|
}
|
|
1467
1312
|
onNavigate(event);
|
|
@@ -1482,12 +1327,12 @@ function useListNavigation(context, props) {
|
|
|
1482
1327
|
// If the event originated from within a nested element (e.g., a Dialog opened from
|
|
1483
1328
|
// within the menu), don't close the menu. The nested element has its own focus
|
|
1484
1329
|
// management and should handle the Tab key.
|
|
1485
|
-
const target =
|
|
1486
|
-
if (target && !
|
|
1330
|
+
const target = ScrollAreaViewport.getTarget(event.nativeEvent);
|
|
1331
|
+
if (target && !ScrollAreaViewport.contains(floatingFocusElementRef.current, target)) {
|
|
1487
1332
|
return;
|
|
1488
1333
|
}
|
|
1489
|
-
|
|
1490
|
-
store.setOpen(false,
|
|
1334
|
+
clamp.stopEvent(event);
|
|
1335
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.focusOut, event.nativeEvent));
|
|
1491
1336
|
if (floatingUi_utils_dom.isHTMLElement(domReferenceElement)) {
|
|
1492
1337
|
domReferenceElement.focus();
|
|
1493
1338
|
}
|
|
@@ -1502,14 +1347,14 @@ function useListNavigation(context, props) {
|
|
|
1502
1347
|
}, [ariaActiveDescendantProp, commonOnKeyDown, floatingFocusElementRef, orientation, typeableComboboxReference, store, open, virtual, domReferenceElement]);
|
|
1503
1348
|
const trigger = React__namespace.useMemo(() => {
|
|
1504
1349
|
function checkVirtualMouse(event) {
|
|
1505
|
-
if (focusItemOnOpen === 'auto' &&
|
|
1350
|
+
if (focusItemOnOpen === 'auto' && clamp.isVirtualClick(event.nativeEvent)) {
|
|
1506
1351
|
focusItemOnOpenRef.current = !virtual;
|
|
1507
1352
|
}
|
|
1508
1353
|
}
|
|
1509
1354
|
function checkVirtualPointer(event) {
|
|
1510
1355
|
// `pointerdown` fires first, reset the state then perform the checks.
|
|
1511
1356
|
focusItemOnOpenRef.current = focusItemOnOpen;
|
|
1512
|
-
if (focusItemOnOpen === 'auto' &&
|
|
1357
|
+
if (focusItemOnOpen === 'auto' && clamp.isVirtualPointerEvent(event.nativeEvent)) {
|
|
1513
1358
|
focusItemOnOpenRef.current = true;
|
|
1514
1359
|
}
|
|
1515
1360
|
}
|
|
@@ -1537,12 +1382,12 @@ function useListNavigation(context, props) {
|
|
|
1537
1382
|
}
|
|
1538
1383
|
if (nested) {
|
|
1539
1384
|
if (isParentCrossOpenKey) {
|
|
1540
|
-
|
|
1385
|
+
clamp.stopEvent(event);
|
|
1541
1386
|
if (currentOpen) {
|
|
1542
|
-
indexRef.current =
|
|
1387
|
+
indexRef.current = ScrollAreaViewport.getMinListIndex(listRef, disabledIndicesRef.current);
|
|
1543
1388
|
onNavigate(event);
|
|
1544
1389
|
} else {
|
|
1545
|
-
store.setOpen(true,
|
|
1390
|
+
store.setOpen(true, clamp.createChangeEventDetails(clamp.listNavigation, event.nativeEvent, event.currentTarget));
|
|
1546
1391
|
}
|
|
1547
1392
|
}
|
|
1548
1393
|
return undefined;
|
|
@@ -1551,9 +1396,9 @@ function useListNavigation(context, props) {
|
|
|
1551
1396
|
if (selectedIndexRef.current != null) {
|
|
1552
1397
|
indexRef.current = selectedIndexRef.current;
|
|
1553
1398
|
}
|
|
1554
|
-
|
|
1399
|
+
clamp.stopEvent(event);
|
|
1555
1400
|
if (!currentOpen && openOnArrowKeyDown) {
|
|
1556
|
-
store.setOpen(true,
|
|
1401
|
+
store.setOpen(true, clamp.createChangeEventDetails(clamp.listNavigation, event.nativeEvent, event.currentTarget));
|
|
1557
1402
|
} else {
|
|
1558
1403
|
commonOnKeyDown(event);
|
|
1559
1404
|
}
|
|
@@ -1608,11 +1453,11 @@ function useTypeahead(context, props) {
|
|
|
1608
1453
|
resetMs = 750,
|
|
1609
1454
|
selectedIndex = null
|
|
1610
1455
|
} = props;
|
|
1611
|
-
const timeout =
|
|
1456
|
+
const timeout = clamp.useTimeout();
|
|
1612
1457
|
const stringRef = React__namespace.useRef('');
|
|
1613
1458
|
const prevIndexRef = React__namespace.useRef(selectedIndex ?? activeIndex ?? -1);
|
|
1614
1459
|
const matchIndexRef = React__namespace.useRef(null);
|
|
1615
|
-
|
|
1460
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1616
1461
|
if (!open && selectedIndex !== null) {
|
|
1617
1462
|
return;
|
|
1618
1463
|
}
|
|
@@ -1622,13 +1467,13 @@ function useTypeahead(context, props) {
|
|
|
1622
1467
|
stringRef.current = '';
|
|
1623
1468
|
}
|
|
1624
1469
|
}, [open, selectedIndex, timeout]);
|
|
1625
|
-
|
|
1470
|
+
clamp.useIsoLayoutEffect(() => {
|
|
1626
1471
|
// Sync arrow key navigation but not typeahead navigation.
|
|
1627
1472
|
if (open && stringRef.current === '') {
|
|
1628
1473
|
prevIndexRef.current = selectedIndex ?? activeIndex ?? -1;
|
|
1629
1474
|
}
|
|
1630
1475
|
}, [open, selectedIndex, activeIndex]);
|
|
1631
|
-
const setTypingChange =
|
|
1476
|
+
const setTypingChange = clamp.useStableCallback(value => {
|
|
1632
1477
|
if (value) {
|
|
1633
1478
|
if (!dataRef.current.typing) {
|
|
1634
1479
|
dataRef.current.typing = value;
|
|
@@ -1639,10 +1484,10 @@ function useTypeahead(context, props) {
|
|
|
1639
1484
|
onTypingChange?.(value);
|
|
1640
1485
|
}
|
|
1641
1486
|
});
|
|
1642
|
-
const onKeyDown =
|
|
1487
|
+
const onKeyDown = clamp.useStableCallback(event => {
|
|
1643
1488
|
function isVisible(index) {
|
|
1644
1489
|
const element = elementsRef?.current[index];
|
|
1645
|
-
return !element ||
|
|
1490
|
+
return !element || ScrollAreaViewport.isElementVisible(element);
|
|
1646
1491
|
}
|
|
1647
1492
|
function getMatchingIndex(list, string, startIndex = 0) {
|
|
1648
1493
|
if (list.length === 0) {
|
|
@@ -1663,7 +1508,7 @@ function useTypeahead(context, props) {
|
|
|
1663
1508
|
const listContent = listRef.current;
|
|
1664
1509
|
if (stringRef.current.length > 0 && event.key === ' ') {
|
|
1665
1510
|
// Space should continue the in-progress typeahead session.
|
|
1666
|
-
|
|
1511
|
+
clamp.stopEvent(event);
|
|
1667
1512
|
setTypingChange(true);
|
|
1668
1513
|
}
|
|
1669
1514
|
if (stringRef.current.length > 0 && stringRef.current[0] !== ' ') {
|
|
@@ -1679,7 +1524,7 @@ function useTypeahead(context, props) {
|
|
|
1679
1524
|
return;
|
|
1680
1525
|
}
|
|
1681
1526
|
if (open && event.key !== ' ') {
|
|
1682
|
-
|
|
1527
|
+
clamp.stopEvent(event);
|
|
1683
1528
|
setTypingChange(true);
|
|
1684
1529
|
}
|
|
1685
1530
|
|
|
@@ -1720,12 +1565,12 @@ function useTypeahead(context, props) {
|
|
|
1720
1565
|
setTypingChange(false);
|
|
1721
1566
|
}
|
|
1722
1567
|
});
|
|
1723
|
-
const onBlur =
|
|
1568
|
+
const onBlur = clamp.useStableCallback(event => {
|
|
1724
1569
|
const next = event.relatedTarget;
|
|
1725
1570
|
const currentDomReferenceElement = store.select('domReferenceElement');
|
|
1726
1571
|
const currentFloatingElement = store.select('floatingElement');
|
|
1727
|
-
const withinReference =
|
|
1728
|
-
const withinFloating =
|
|
1572
|
+
const withinReference = ScrollAreaViewport.contains(currentDomReferenceElement, next);
|
|
1573
|
+
const withinFloating = ScrollAreaViewport.contains(currentFloatingElement, next);
|
|
1729
1574
|
|
|
1730
1575
|
// Keep the session if focus moves within the composite (reference <-> floating).
|
|
1731
1576
|
if (withinReference || withinFloating) {
|
|
@@ -1797,7 +1642,7 @@ function safePolygon(options = {}) {
|
|
|
1797
1642
|
const {
|
|
1798
1643
|
blockPointerEvents = false
|
|
1799
1644
|
} = options;
|
|
1800
|
-
const timeout = new
|
|
1645
|
+
const timeout = new clamp.Timeout();
|
|
1801
1646
|
const fn = ({
|
|
1802
1647
|
x,
|
|
1803
1648
|
y,
|
|
@@ -1845,10 +1690,10 @@ function safePolygon(options = {}) {
|
|
|
1845
1690
|
clientX,
|
|
1846
1691
|
clientY
|
|
1847
1692
|
} = event;
|
|
1848
|
-
const target =
|
|
1693
|
+
const target = ScrollAreaViewport.getTarget(event);
|
|
1849
1694
|
const isLeave = event.type === 'mouseleave';
|
|
1850
|
-
const isOverFloatingEl =
|
|
1851
|
-
const isOverReferenceEl =
|
|
1695
|
+
const isOverFloatingEl = ScrollAreaViewport.contains(floating, target);
|
|
1696
|
+
const isOverReferenceEl = ScrollAreaViewport.contains(domReference, target);
|
|
1852
1697
|
if (isOverFloatingEl) {
|
|
1853
1698
|
hasLanded = true;
|
|
1854
1699
|
if (!isLeave) {
|
|
@@ -1865,11 +1710,11 @@ function safePolygon(options = {}) {
|
|
|
1865
1710
|
|
|
1866
1711
|
// Prevent overlapping floating element from being stuck in an open-close
|
|
1867
1712
|
// loop: https://github.com/floating-ui/floating-ui/issues/1910
|
|
1868
|
-
if (isLeave && floatingUi_utils_dom.isElement(event.relatedTarget) &&
|
|
1713
|
+
if (isLeave && floatingUi_utils_dom.isElement(event.relatedTarget) && ScrollAreaViewport.contains(floating, event.relatedTarget)) {
|
|
1869
1714
|
return undefined;
|
|
1870
1715
|
}
|
|
1871
1716
|
function hasOpenChildNode() {
|
|
1872
|
-
return Boolean(tree &&
|
|
1717
|
+
return Boolean(tree && ScrollAreaViewport.getNodeChildren(tree.nodesRef.current, nodeId).length > 0);
|
|
1873
1718
|
}
|
|
1874
1719
|
function closeIfNoOpenChild() {
|
|
1875
1720
|
if (!hasOpenChildNode()) {
|
|
@@ -1995,1452 +1840,1460 @@ function safePolygon(options = {}) {
|
|
|
1995
1840
|
return fn;
|
|
1996
1841
|
}
|
|
1997
1842
|
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
* Renders an `<h2>` element.
|
|
2001
|
-
*
|
|
2002
|
-
* Documentation: [Base UI Dialog](https://base-ui.com/react/components/dialog)
|
|
2003
|
-
*/
|
|
2004
|
-
const DialogTitle = /*#__PURE__*/React__namespace.forwardRef(function DialogTitle(componentProps, forwardedRef) {
|
|
2005
|
-
const {
|
|
2006
|
-
render,
|
|
2007
|
-
className,
|
|
2008
|
-
id: idProp,
|
|
2009
|
-
...elementProps
|
|
2010
|
-
} = componentProps;
|
|
2011
|
-
const {
|
|
2012
|
-
store
|
|
2013
|
-
} = DrawerRoot.useDialogRootContext();
|
|
2014
|
-
const id = useBaseUiId.useBaseUiId(idProp);
|
|
2015
|
-
store.useSyncedValueWithCleanup('titleElementId', id);
|
|
2016
|
-
return useRenderElement.useRenderElement('h2', componentProps, {
|
|
2017
|
-
ref: forwardedRef,
|
|
2018
|
-
props: [{
|
|
2019
|
-
id
|
|
2020
|
-
}, elementProps]
|
|
2021
|
-
});
|
|
2022
|
-
});
|
|
2023
|
-
if (process.env.NODE_ENV !== "production") DialogTitle.displayName = "DialogTitle";
|
|
1843
|
+
function getPseudoElementBounds(element) {
|
|
1844
|
+
const elementRect = element.getBoundingClientRect();
|
|
2024
1845
|
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
const
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
className,
|
|
2035
|
-
disabled = false,
|
|
2036
|
-
nativeButton = true,
|
|
2037
|
-
id: idProp,
|
|
2038
|
-
payload,
|
|
2039
|
-
handle,
|
|
2040
|
-
...elementProps
|
|
2041
|
-
} = componentProps;
|
|
2042
|
-
const dialogRootContext = DrawerRoot.useDialogRootContext(true);
|
|
2043
|
-
const store = handle?.store ?? dialogRootContext?.store;
|
|
2044
|
-
if (!store) {
|
|
2045
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: <Dialog.Trigger> must be used within <Dialog.Root> or provided with a handle.' : useRenderElement.formatErrorMessage(79));
|
|
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;
|
|
2046
1855
|
}
|
|
2047
|
-
const thisTriggerId = useBaseUiId.useBaseUiId(idProp);
|
|
2048
|
-
const floatingContext = store.useState('floatingRootContext');
|
|
2049
|
-
const isOpenedByThisTrigger = store.useState('isOpenedByTrigger', thisTriggerId);
|
|
2050
|
-
const triggerElementRef = React__namespace.useRef(null);
|
|
2051
|
-
const {
|
|
2052
|
-
registerTrigger,
|
|
2053
|
-
isMountedByThisTrigger
|
|
2054
|
-
} = DrawerRoot.useTriggerDataForwarding(thisTriggerId, triggerElementRef, store, {
|
|
2055
|
-
payload
|
|
2056
|
-
});
|
|
2057
|
-
const {
|
|
2058
|
-
getButtonProps,
|
|
2059
|
-
buttonRef
|
|
2060
|
-
} = useBaseUiId.useButton({
|
|
2061
|
-
disabled,
|
|
2062
|
-
native: nativeButton
|
|
2063
|
-
});
|
|
2064
|
-
const click = useClick(floatingContext, {
|
|
2065
|
-
enabled: floatingContext != null
|
|
2066
|
-
});
|
|
2067
|
-
const localInteractionProps = DrawerRoot.useInteractions([click]);
|
|
2068
|
-
const state = {
|
|
2069
|
-
disabled,
|
|
2070
|
-
open: isOpenedByThisTrigger
|
|
2071
|
-
};
|
|
2072
|
-
const rootTriggerProps = store.useState('triggerProps', isMountedByThisTrigger);
|
|
2073
|
-
return useRenderElement.useRenderElement('button', componentProps, {
|
|
2074
|
-
state,
|
|
2075
|
-
ref: [buttonRef, forwardedRef, registerTrigger, triggerElementRef],
|
|
2076
|
-
props: [localInteractionProps.getReferenceProps(), rootTriggerProps, {
|
|
2077
|
-
[DrawerRoot.CLICK_TRIGGER_IDENTIFIER]: '',
|
|
2078
|
-
id: thisTriggerId
|
|
2079
|
-
}, elementProps, getButtonProps],
|
|
2080
|
-
stateAttributesMapping: DrawerRoot.triggerOpenStateMapping
|
|
2081
|
-
});
|
|
2082
|
-
});
|
|
2083
|
-
if (process.env.NODE_ENV !== "production") DialogTrigger.displayName = "DialogTrigger";
|
|
2084
|
-
|
|
2085
|
-
/**
|
|
2086
|
-
* A heading that labels the drawer.
|
|
2087
|
-
* Renders an `<h2>` element.
|
|
2088
|
-
*
|
|
2089
|
-
* Documentation: [Base UI Drawer](https://base-ui.com/react/components/drawer)
|
|
2090
|
-
*/
|
|
2091
|
-
const DrawerTitle = DialogTitle;
|
|
2092
1856
|
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
*/
|
|
2099
|
-
const DrawerTrigger = DialogTrigger;
|
|
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;
|
|
2100
1862
|
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
const context = React__namespace.useContext(MenuPositionerContext);
|
|
2105
|
-
if (context === undefined && !optional) {
|
|
2106
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: MenuPositionerContext is missing. MenuPositioner parts must be placed within <Menu.Positioner>.' : useRenderElement.formatErrorMessage(33));
|
|
2107
|
-
}
|
|
2108
|
-
return context;
|
|
2109
|
-
}
|
|
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);
|
|
2110
1866
|
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
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
|
+
};
|
|
2119
1876
|
}
|
|
2120
1877
|
|
|
2121
|
-
const
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
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
|
|
2127
1889
|
}
|
|
2128
|
-
|
|
1890
|
+
});
|
|
1891
|
+
if (process.env.NODE_ENV !== "production") CompositeListContext.displayName = "CompositeListContext";
|
|
1892
|
+
function useCompositeListContext() {
|
|
1893
|
+
return React__namespace.useContext(CompositeListContext);
|
|
2129
1894
|
}
|
|
2130
1895
|
|
|
1896
|
+
/* eslint-disable no-bitwise */
|
|
2131
1897
|
/**
|
|
2132
|
-
*
|
|
2133
|
-
*
|
|
2134
|
-
* onMouseMove, onClick, and onMouseUp handlers.
|
|
1898
|
+
* Provides context for a list of items in a composite component.
|
|
1899
|
+
* @internal
|
|
2135
1900
|
*/
|
|
2136
|
-
function
|
|
2137
|
-
const {
|
|
2138
|
-
closeOnClick,
|
|
2139
|
-
highlighted,
|
|
2140
|
-
id,
|
|
2141
|
-
nodeId,
|
|
2142
|
-
store,
|
|
2143
|
-
typingRef,
|
|
2144
|
-
itemRef,
|
|
2145
|
-
itemMetadata
|
|
2146
|
-
} = params;
|
|
1901
|
+
function CompositeList(props) {
|
|
2147
1902
|
const {
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
onKeyDown(event) {
|
|
2157
|
-
if (event.key === ' ' && typingRef?.current) {
|
|
2158
|
-
event.preventDefault();
|
|
2159
|
-
}
|
|
2160
|
-
},
|
|
2161
|
-
onMouseMove(event) {
|
|
2162
|
-
if (!nodeId) {
|
|
2163
|
-
return;
|
|
2164
|
-
}
|
|
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;
|
|
2165
1911
|
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
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
|
|
2171
1944
|
});
|
|
2172
|
-
}
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
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
|
|
2178
1968
|
});
|
|
2179
1969
|
}
|
|
2180
|
-
}
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
// that opened the context menu, so it must not activate an item.
|
|
2191
|
-
if (isContextMenu && !useValueChanged.isMac && event.button === 2) {
|
|
2192
|
-
return;
|
|
2193
|
-
}
|
|
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;
|
|
2194
1980
|
}
|
|
2195
|
-
if (
|
|
2196
|
-
|
|
2197
|
-
// We trigger the click and override the `closeOnClick` preference to always close the menu.
|
|
2198
|
-
if (!itemMetadata || itemMetadata.type === 'regular-item') {
|
|
2199
|
-
itemRef.current.click();
|
|
2200
|
-
}
|
|
1981
|
+
if (labelsRef && labelsRef.current.length !== sortedMap.size) {
|
|
1982
|
+
labelsRef.current.length = sortedMap.size;
|
|
2201
1983
|
}
|
|
1984
|
+
nextIndexRef.current = sortedMap.size;
|
|
2202
1985
|
}
|
|
2203
|
-
|
|
2204
|
-
}
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
};
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
const {
|
|
2223
|
-
getButtonProps,
|
|
2224
|
-
buttonRef
|
|
2225
|
-
} = useBaseUiId.useButton({
|
|
2226
|
-
disabled,
|
|
2227
|
-
focusableWhenDisabled: true,
|
|
2228
|
-
native: nativeButton,
|
|
2229
|
-
composite: true
|
|
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
|
+
};
|
|
2230
2005
|
});
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
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
|
|
2240
2020
|
});
|
|
2241
|
-
const getItemProps = React__namespace.useCallback(externalProps => {
|
|
2242
|
-
return useRenderElement.mergeProps(commonProps, {
|
|
2243
|
-
onMouseEnter() {
|
|
2244
|
-
if (itemMetadata.type !== 'submenu-trigger') {
|
|
2245
|
-
return;
|
|
2246
|
-
}
|
|
2247
|
-
itemMetadata.setActive();
|
|
2248
|
-
}
|
|
2249
|
-
}, externalProps, getButtonProps);
|
|
2250
|
-
}, [commonProps, getButtonProps, itemMetadata]);
|
|
2251
|
-
const mergedRef = useRenderElement.useMergedRefs(itemRef, buttonRef);
|
|
2252
|
-
return React__namespace.useMemo(() => ({
|
|
2253
|
-
getItemProps,
|
|
2254
|
-
itemRef: mergedRef
|
|
2255
|
-
}), [getItemProps, mergedRef]);
|
|
2256
2021
|
}
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
nextIndexRef: {
|
|
2268
|
-
current: 0
|
|
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;
|
|
2269
2032
|
}
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
return
|
|
2033
|
+
if (position & Node.DOCUMENT_POSITION_PRECEDING || position & Node.DOCUMENT_POSITION_CONTAINS) {
|
|
2034
|
+
return 1;
|
|
2035
|
+
}
|
|
2036
|
+
return 0;
|
|
2274
2037
|
}
|
|
2275
2038
|
|
|
2276
|
-
let IndexGuessBehavior = /*#__PURE__*/function (IndexGuessBehavior) {
|
|
2277
|
-
IndexGuessBehavior[IndexGuessBehavior["None"] = 0] = "None";
|
|
2278
|
-
IndexGuessBehavior[IndexGuessBehavior["GuessFromOrder"] = 1] = "GuessFromOrder";
|
|
2279
|
-
return IndexGuessBehavior;
|
|
2280
|
-
}({});
|
|
2281
|
-
|
|
2282
2039
|
/**
|
|
2283
|
-
*
|
|
2040
|
+
* Fork of the original `arrow` middleware from Floating UI that allows
|
|
2041
|
+
* configuring the offset parent.
|
|
2284
2042
|
*/
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
indexRef.current = newIndex;
|
|
2307
|
-
}
|
|
2308
|
-
return indexRef.current;
|
|
2309
|
-
} : -1));
|
|
2310
|
-
const componentRef = React__namespace.useRef(null);
|
|
2311
|
-
const ref = React__namespace.useCallback(node => {
|
|
2312
|
-
componentRef.current = node;
|
|
2313
|
-
if (index !== -1 && node !== null) {
|
|
2314
|
-
elementsRef.current[index] = node;
|
|
2315
|
-
if (labelsRef) {
|
|
2316
|
-
const isLabelDefined = label !== undefined;
|
|
2317
|
-
labelsRef.current[index] = isLabelDefined ? label : textRef?.current?.textContent ?? node.textContent;
|
|
2318
|
-
}
|
|
2319
|
-
}
|
|
2320
|
-
}, [index, elementsRef, labelsRef, label, textRef]);
|
|
2321
|
-
useValueChanged.useIsoLayoutEffect(() => {
|
|
2322
|
-
if (externalIndex != null) {
|
|
2323
|
-
return undefined;
|
|
2324
|
-
}
|
|
2325
|
-
const node = componentRef.current;
|
|
2326
|
-
if (node) {
|
|
2327
|
-
register(node, metadata);
|
|
2328
|
-
return () => {
|
|
2329
|
-
unregister(node);
|
|
2330
|
-
};
|
|
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 {};
|
|
2331
2064
|
}
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
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];
|
|
2337
2085
|
}
|
|
2338
|
-
|
|
2339
|
-
const i = componentRef.current ? map.get(componentRef.current)?.index : null;
|
|
2340
|
-
if (i != null) {
|
|
2341
|
-
setIndex(i);
|
|
2342
|
-
}
|
|
2343
|
-
});
|
|
2344
|
-
}, [externalIndex, subscribeMapChange, setIndex]);
|
|
2345
|
-
return React__namespace.useMemo(() => ({
|
|
2346
|
-
ref,
|
|
2347
|
-
index
|
|
2348
|
-
}), [index, ref]);
|
|
2349
|
-
}
|
|
2086
|
+
const centerToReference = endDiff / 2 - startDiff / 2;
|
|
2350
2087
|
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
/**
|
|
2357
|
-
* Present when the menu checkbox item is not checked.
|
|
2358
|
-
*/
|
|
2359
|
-
MenuCheckboxItemDataAttributes["unchecked"] = "data-unchecked";
|
|
2360
|
-
/**
|
|
2361
|
-
* Present when the menu checkbox item is disabled.
|
|
2362
|
-
*/
|
|
2363
|
-
MenuCheckboxItemDataAttributes["disabled"] = "data-disabled";
|
|
2364
|
-
/**
|
|
2365
|
-
* Present when the menu checkbox item is highlighted.
|
|
2366
|
-
*/
|
|
2367
|
-
MenuCheckboxItemDataAttributes["highlighted"] = "data-highlighted";
|
|
2368
|
-
return MenuCheckboxItemDataAttributes;
|
|
2369
|
-
}({});
|
|
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);
|
|
2370
2093
|
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
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;
|
|
2378
2108
|
return {
|
|
2379
|
-
[
|
|
2109
|
+
[axis]: coords[axis] + alignmentOffset,
|
|
2110
|
+
data: {
|
|
2111
|
+
[axis]: offset,
|
|
2112
|
+
centerOffset: center - offset - alignmentOffset,
|
|
2113
|
+
...(shouldAddOffset && {
|
|
2114
|
+
alignmentOffset
|
|
2115
|
+
})
|
|
2116
|
+
},
|
|
2117
|
+
reset: shouldAddOffset
|
|
2380
2118
|
};
|
|
2381
|
-
},
|
|
2382
|
-
...useValueChanged.transitionStatusMapping
|
|
2383
|
-
};
|
|
2384
|
-
|
|
2385
|
-
const MenuGroupContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
2386
|
-
if (process.env.NODE_ENV !== "production") MenuGroupContext.displayName = "MenuGroupContext";
|
|
2387
|
-
function useMenuGroupRootContext() {
|
|
2388
|
-
const context = React__namespace.useContext(MenuGroupContext);
|
|
2389
|
-
if (context === undefined) {
|
|
2390
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: MenuGroupRootContext is missing. Menu group parts must be used within <Menu.Group>.' : useRenderElement.formatErrorMessage(31));
|
|
2391
2119
|
}
|
|
2392
|
-
return context;
|
|
2393
|
-
}
|
|
2394
|
-
|
|
2395
|
-
const MenuGroup = /*#__PURE__*/React__namespace.forwardRef(function MenuGroup(componentProps, forwardedRef) {
|
|
2396
|
-
const {
|
|
2397
|
-
render,
|
|
2398
|
-
className,
|
|
2399
|
-
...elementProps
|
|
2400
|
-
} = componentProps;
|
|
2401
|
-
const [labelId, setLabelId] = React__namespace.useState(undefined);
|
|
2402
|
-
const context = React__namespace.useMemo(() => ({
|
|
2403
|
-
setLabelId
|
|
2404
|
-
}), [setLabelId]);
|
|
2405
|
-
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
2406
|
-
ref: forwardedRef,
|
|
2407
|
-
props: {
|
|
2408
|
-
role: 'group',
|
|
2409
|
-
'aria-labelledby': labelId,
|
|
2410
|
-
...elementProps
|
|
2411
|
-
}
|
|
2412
|
-
});
|
|
2413
|
-
return /*#__PURE__*/jsxRuntime.jsx(MenuGroupContext.Provider, {
|
|
2414
|
-
value: context,
|
|
2415
|
-
children: element
|
|
2416
|
-
});
|
|
2417
2120
|
});
|
|
2418
|
-
if (process.env.NODE_ENV !== "production") MenuGroup.displayName = "MenuGroup";
|
|
2419
2121
|
|
|
2420
2122
|
/**
|
|
2421
|
-
*
|
|
2422
|
-
*
|
|
2423
|
-
*
|
|
2424
|
-
*
|
|
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
|
|
2425
2127
|
*/
|
|
2426
|
-
const
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
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
|
+
}
|
|
2441
2148
|
};
|
|
2442
|
-
}
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
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
|
+
};
|
|
2449
2181
|
}
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2182
|
+
const offsetParent = await platform.getOffsetParent?.(floating);
|
|
2183
|
+
let offsetDimensions = {
|
|
2184
|
+
width: 0,
|
|
2185
|
+
height: 0
|
|
2186
|
+
};
|
|
2453
2187
|
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
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) {
|
|
2481
2237
|
const {
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
} =
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
highlighted
|
|
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
|
+
}
|
|
2497
2252
|
};
|
|
2498
|
-
return
|
|
2499
|
-
|
|
2500
|
-
props: [itemProps, elementProps, getItemProps],
|
|
2501
|
-
ref: [itemRef, forwardedRef, listItem.ref]
|
|
2502
|
-
});
|
|
2503
|
-
});
|
|
2504
|
-
if (process.env.NODE_ENV !== "production") MenuItem.displayName = "MenuItem";
|
|
2505
|
-
|
|
2253
|
+
return data;
|
|
2254
|
+
}
|
|
2506
2255
|
/**
|
|
2507
|
-
*
|
|
2508
|
-
*
|
|
2509
|
-
*
|
|
2510
|
-
* Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
|
|
2256
|
+
* Provides standardized anchor positioning behavior for floating elements. Wraps Floating UI's
|
|
2257
|
+
* `useFloating` hook.
|
|
2511
2258
|
*/
|
|
2512
|
-
|
|
2513
|
-
const {
|
|
2514
|
-
render,
|
|
2515
|
-
className,
|
|
2516
|
-
id: idProp,
|
|
2517
|
-
label,
|
|
2518
|
-
closeOnClick = false,
|
|
2519
|
-
...elementProps
|
|
2520
|
-
} = componentProps;
|
|
2521
|
-
const linkRef = React__namespace.useRef(null);
|
|
2522
|
-
const listItem = useCompositeListItem({
|
|
2523
|
-
label
|
|
2524
|
-
});
|
|
2525
|
-
const menuPositionerContext = useMenuPositionerContext(true);
|
|
2526
|
-
const nodeId = menuPositionerContext?.nodeId;
|
|
2527
|
-
const id = useBaseUiId.useBaseUiId(idProp);
|
|
2528
|
-
const {
|
|
2529
|
-
store
|
|
2530
|
-
} = useMenuRootContext();
|
|
2531
|
-
const highlighted = store.useState('isActive', listItem.index);
|
|
2532
|
-
const itemProps = store.useState('itemProps');
|
|
2533
|
-
const typingRef = store.context.typingRef;
|
|
2259
|
+
function useAnchorPositioning(params) {
|
|
2534
2260
|
const {
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
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,
|
|
2545
2279
|
nodeId,
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
}
|
|
2550
|
-
|
|
2551
|
-
|
|
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);
|
|
2552
2287
|
}
|
|
2553
|
-
const
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
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;
|
|
2563
2307
|
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
const
|
|
2568
|
-
|
|
2569
|
-
|
|
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
|
+
};
|
|
2570
2330
|
}
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
return transitionStatus === 'starting' ? DrawerRoot.DISABLED_TRANSITIONS_STYLE : useRenderElement.EMPTY_OBJECT;
|
|
2576
|
-
}
|
|
2331
|
+
const commonCollisionProps = {
|
|
2332
|
+
boundary: collisionBoundary === 'clipping-ancestors' ? 'clippingAncestors' : collisionBoundary,
|
|
2333
|
+
padding: collisionPadding
|
|
2334
|
+
};
|
|
2577
2335
|
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
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);
|
|
2582
2340
|
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
const
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
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]);
|
|
2596
2492
|
const {
|
|
2597
|
-
|
|
2598
|
-
|
|
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
|
+
});
|
|
2599
2512
|
const {
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
} =
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
const
|
|
2607
|
-
const
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
useValueChanged.useOpenChangeComplete({
|
|
2619
|
-
open,
|
|
2620
|
-
ref: store.context.popupRef,
|
|
2621
|
-
onComplete() {
|
|
2622
|
-
if (open) {
|
|
2623
|
-
store.context.onOpenChangeComplete?.(true);
|
|
2624
|
-
}
|
|
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;
|
|
2625
2531
|
}
|
|
2626
|
-
|
|
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]);
|
|
2627
2548
|
React__namespace.useEffect(() => {
|
|
2628
|
-
|
|
2629
|
-
|
|
2549
|
+
if (!mounted) {
|
|
2550
|
+
return;
|
|
2630
2551
|
}
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
const
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
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);
|
|
2662
2680
|
}
|
|
2663
|
-
}
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
returnFocus = true;
|
|
2670
|
-
}
|
|
2671
|
-
return /*#__PURE__*/jsxRuntime.jsx(DrawerRoot.FloatingFocusManager, {
|
|
2672
|
-
context: floatingContext,
|
|
2673
|
-
modal: isContextMenu,
|
|
2674
|
-
disabled: !mounted,
|
|
2675
|
-
returnFocus: finalFocus === undefined ? returnFocus : finalFocus,
|
|
2676
|
-
initialFocus: parent.type !== 'menu',
|
|
2677
|
-
restoreFocus: true,
|
|
2678
|
-
externalTree: parent.type !== 'menubar' ? floatingTreeRoot : undefined,
|
|
2679
|
-
previousFocusableElement: activeTriggerElement,
|
|
2680
|
-
nextFocusableElement: parent.type === undefined ? store.context.triggerFocusTargetRef : undefined,
|
|
2681
|
-
beforeContentFocusGuardRef: parent.type === undefined ? store.context.beforeContentFocusGuardRef : undefined,
|
|
2682
|
-
children: element
|
|
2683
|
-
});
|
|
2684
|
-
});
|
|
2685
|
-
if (process.env.NODE_ENV !== "production") MenuPopup.displayName = "MenuPopup";
|
|
2686
|
-
|
|
2687
|
-
const MenuPortalContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
2688
|
-
if (process.env.NODE_ENV !== "production") MenuPortalContext.displayName = "MenuPortalContext";
|
|
2689
|
-
function useMenuPortalContext() {
|
|
2690
|
-
const value = React__namespace.useContext(MenuPortalContext);
|
|
2691
|
-
if (value === undefined) {
|
|
2692
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: <Menu.Portal> is missing.' : useRenderElement.formatErrorMessage(32));
|
|
2693
|
-
}
|
|
2694
|
-
return value;
|
|
2681
|
+
});
|
|
2682
|
+
}, [externalIndex, subscribeMapChange, setIndex]);
|
|
2683
|
+
return React__namespace.useMemo(() => ({
|
|
2684
|
+
ref,
|
|
2685
|
+
index
|
|
2686
|
+
}), [index, ref]);
|
|
2695
2687
|
}
|
|
2696
2688
|
|
|
2697
|
-
|
|
2689
|
+
/**
|
|
2690
|
+
* A button that closes the dialog.
|
|
2691
|
+
* Renders a `<button>` element.
|
|
2692
|
+
*
|
|
2693
|
+
* Documentation: [Base UI Dialog](https://base-ui.com/react/components/dialog)
|
|
2694
|
+
*/
|
|
2695
|
+
const DialogClose = /*#__PURE__*/React__namespace.forwardRef(function DialogClose(componentProps, forwardedRef) {
|
|
2698
2696
|
const {
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2697
|
+
render,
|
|
2698
|
+
className,
|
|
2699
|
+
disabled = false,
|
|
2700
|
+
nativeButton = true,
|
|
2701
|
+
...elementProps
|
|
2702
|
+
} = componentProps;
|
|
2702
2703
|
const {
|
|
2703
2704
|
store
|
|
2704
|
-
} =
|
|
2705
|
-
const
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2705
|
+
} = ScrollAreaViewport.useDialogRootContext();
|
|
2706
|
+
const open = store.useState('open');
|
|
2707
|
+
function handleClick(event) {
|
|
2708
|
+
if (open) {
|
|
2709
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.closePress, event.nativeEvent));
|
|
2710
|
+
}
|
|
2709
2711
|
}
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2712
|
+
const {
|
|
2713
|
+
getButtonProps,
|
|
2714
|
+
buttonRef
|
|
2715
|
+
} = clamp.useButton({
|
|
2716
|
+
disabled,
|
|
2717
|
+
native: nativeButton
|
|
2718
|
+
});
|
|
2719
|
+
const state = {
|
|
2720
|
+
disabled
|
|
2721
|
+
};
|
|
2722
|
+
return useRenderElement.useRenderElement('button', componentProps, {
|
|
2723
|
+
state,
|
|
2724
|
+
ref: [forwardedRef, buttonRef],
|
|
2725
|
+
props: [{
|
|
2726
|
+
onClick: handleClick
|
|
2727
|
+
}, elementProps, getButtonProps]
|
|
2716
2728
|
});
|
|
2717
2729
|
});
|
|
2718
|
-
if (process.env.NODE_ENV !== "production")
|
|
2719
|
-
|
|
2720
|
-
/**
|
|
2721
|
-
* @internal
|
|
2722
|
-
*/
|
|
2723
|
-
const DirectionContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
2724
|
-
if (process.env.NODE_ENV !== "production") DirectionContext.displayName = "DirectionContext";
|
|
2725
|
-
function useDirection() {
|
|
2726
|
-
const context = React__namespace.useContext(DirectionContext);
|
|
2727
|
-
return context?.direction ?? 'ltr';
|
|
2728
|
-
}
|
|
2730
|
+
if (process.env.NODE_ENV !== "production") DialogClose.displayName = "DialogClose";
|
|
2729
2731
|
|
|
2730
2732
|
/**
|
|
2731
|
-
*
|
|
2732
|
-
*
|
|
2733
|
+
* A button that closes the drawer.
|
|
2734
|
+
* Renders a `<button>` element.
|
|
2735
|
+
*
|
|
2736
|
+
* Documentation: [Base UI Drawer](https://base-ui.com/react/components/drawer)
|
|
2733
2737
|
*/
|
|
2734
|
-
const
|
|
2735
|
-
name: 'arrow',
|
|
2736
|
-
options,
|
|
2737
|
-
async fn(state) {
|
|
2738
|
-
const {
|
|
2739
|
-
x,
|
|
2740
|
-
y,
|
|
2741
|
-
placement,
|
|
2742
|
-
rects,
|
|
2743
|
-
platform,
|
|
2744
|
-
elements,
|
|
2745
|
-
middlewareData
|
|
2746
|
-
} = state;
|
|
2747
|
-
// Since `element` is required, we don't Partial<> the type.
|
|
2748
|
-
const {
|
|
2749
|
-
element,
|
|
2750
|
-
padding = 0,
|
|
2751
|
-
offsetParent = 'real'
|
|
2752
|
-
} = index_esm.evaluate(options, state) || {};
|
|
2753
|
-
if (element == null) {
|
|
2754
|
-
return {};
|
|
2755
|
-
}
|
|
2756
|
-
const paddingObject = index_esm.getPaddingObject(padding);
|
|
2757
|
-
const coords = {
|
|
2758
|
-
x,
|
|
2759
|
-
y
|
|
2760
|
-
};
|
|
2761
|
-
const axis = index_esm.getAlignmentAxis(placement);
|
|
2762
|
-
const length = index_esm.getAxisLength(axis);
|
|
2763
|
-
const arrowDimensions = await platform.getDimensions(element);
|
|
2764
|
-
const isYAxis = axis === 'y';
|
|
2765
|
-
const minProp = isYAxis ? 'top' : 'left';
|
|
2766
|
-
const maxProp = isYAxis ? 'bottom' : 'right';
|
|
2767
|
-
const clientProp = isYAxis ? 'clientHeight' : 'clientWidth';
|
|
2768
|
-
const endDiff = rects.reference[length] + rects.reference[axis] - coords[axis] - rects.floating[length];
|
|
2769
|
-
const startDiff = coords[axis] - rects.reference[axis];
|
|
2770
|
-
const arrowOffsetParent = offsetParent === 'real' ? await platform.getOffsetParent?.(element) : elements.floating;
|
|
2771
|
-
let clientSize = elements.floating[clientProp] || rects.floating[length];
|
|
2772
|
-
|
|
2773
|
-
// DOM platform can return `window` as the `offsetParent`.
|
|
2774
|
-
if (!clientSize || !(await platform.isElement?.(arrowOffsetParent))) {
|
|
2775
|
-
clientSize = elements.floating[clientProp] || rects.floating[length];
|
|
2776
|
-
}
|
|
2777
|
-
const centerToReference = endDiff / 2 - startDiff / 2;
|
|
2778
|
-
|
|
2779
|
-
// If the padding is large enough that it causes the arrow to no longer be
|
|
2780
|
-
// centered, modify the padding so that it is centered.
|
|
2781
|
-
const largestPossiblePadding = clientSize / 2 - arrowDimensions[length] / 2 - 1;
|
|
2782
|
-
const minPadding = Math.min(paddingObject[minProp], largestPossiblePadding);
|
|
2783
|
-
const maxPadding = Math.min(paddingObject[maxProp], largestPossiblePadding);
|
|
2784
|
-
|
|
2785
|
-
// Make sure the arrow doesn't overflow the floating element if the center
|
|
2786
|
-
// point is outside the floating element's bounds.
|
|
2787
|
-
const min = minPadding;
|
|
2788
|
-
const max = clientSize - arrowDimensions[length] - maxPadding;
|
|
2789
|
-
const center = clientSize / 2 - arrowDimensions[length] / 2 + centerToReference;
|
|
2790
|
-
const offset = index_esm.clamp(min, center, max);
|
|
2791
|
-
|
|
2792
|
-
// If the reference is small enough that the arrow's padding causes it to
|
|
2793
|
-
// to point to nothing for an aligned placement, adjust the offset of the
|
|
2794
|
-
// floating element itself. To ensure `shift()` continues to take action,
|
|
2795
|
-
// a single reset is performed when this is true.
|
|
2796
|
-
const shouldAddOffset = !middlewareData.arrow && index_esm.getAlignment(placement) != null && center !== offset && rects.reference[length] / 2 - (center < min ? minPadding : maxPadding) - arrowDimensions[length] / 2 < 0;
|
|
2797
|
-
// eslint-disable-next-line no-nested-ternary
|
|
2798
|
-
const alignmentOffset = shouldAddOffset ? center < min ? center - min : center - max : 0;
|
|
2799
|
-
return {
|
|
2800
|
-
[axis]: coords[axis] + alignmentOffset,
|
|
2801
|
-
data: {
|
|
2802
|
-
[axis]: offset,
|
|
2803
|
-
centerOffset: center - offset - alignmentOffset,
|
|
2804
|
-
...(shouldAddOffset && {
|
|
2805
|
-
alignmentOffset
|
|
2806
|
-
})
|
|
2807
|
-
},
|
|
2808
|
-
reset: shouldAddOffset
|
|
2809
|
-
};
|
|
2810
|
-
}
|
|
2811
|
-
});
|
|
2738
|
+
const DrawerClose = DialogClose;
|
|
2812
2739
|
|
|
2813
2740
|
/**
|
|
2814
|
-
*
|
|
2815
|
-
*
|
|
2816
|
-
*
|
|
2817
|
-
*
|
|
2741
|
+
* A heading that labels the dialog.
|
|
2742
|
+
* Renders an `<h2>` element.
|
|
2743
|
+
*
|
|
2744
|
+
* Documentation: [Base UI Dialog](https://base-ui.com/react/components/dialog)
|
|
2818
2745
|
*/
|
|
2819
|
-
const
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
};
|
|
2840
|
-
}
|
|
2841
|
-
};
|
|
2842
|
-
|
|
2843
|
-
const DEFAULT_SIDES = {
|
|
2844
|
-
sideX: 'left',
|
|
2845
|
-
sideY: 'top'
|
|
2846
|
-
};
|
|
2847
|
-
const adaptiveOrigin = {
|
|
2848
|
-
name: 'adaptiveOrigin',
|
|
2849
|
-
async fn(state) {
|
|
2850
|
-
const {
|
|
2851
|
-
x: rawX,
|
|
2852
|
-
y: rawY,
|
|
2853
|
-
rects: {
|
|
2854
|
-
floating: floatRect
|
|
2855
|
-
},
|
|
2856
|
-
elements: {
|
|
2857
|
-
floating
|
|
2858
|
-
},
|
|
2859
|
-
platform,
|
|
2860
|
-
strategy,
|
|
2861
|
-
placement
|
|
2862
|
-
} = state;
|
|
2863
|
-
const win = floatingUi_utils_dom.getWindow(floating);
|
|
2864
|
-
const styles = win.getComputedStyle(floating);
|
|
2865
|
-
const hasTransition = styles.transitionDuration !== '0s' && styles.transitionDuration !== '';
|
|
2866
|
-
if (!hasTransition) {
|
|
2867
|
-
return {
|
|
2868
|
-
x: rawX,
|
|
2869
|
-
y: rawY,
|
|
2870
|
-
data: DEFAULT_SIDES
|
|
2871
|
-
};
|
|
2872
|
-
}
|
|
2873
|
-
const offsetParent = await platform.getOffsetParent?.(floating);
|
|
2874
|
-
let offsetDimensions = {
|
|
2875
|
-
width: 0,
|
|
2876
|
-
height: 0
|
|
2877
|
-
};
|
|
2746
|
+
const DialogTitle = /*#__PURE__*/React__namespace.forwardRef(function DialogTitle(componentProps, forwardedRef) {
|
|
2747
|
+
const {
|
|
2748
|
+
render,
|
|
2749
|
+
className,
|
|
2750
|
+
id: idProp,
|
|
2751
|
+
...elementProps
|
|
2752
|
+
} = componentProps;
|
|
2753
|
+
const {
|
|
2754
|
+
store
|
|
2755
|
+
} = ScrollAreaViewport.useDialogRootContext();
|
|
2756
|
+
const id = clamp.useBaseUiId(idProp);
|
|
2757
|
+
store.useSyncedValueWithCleanup('titleElementId', id);
|
|
2758
|
+
return useRenderElement.useRenderElement('h2', componentProps, {
|
|
2759
|
+
ref: forwardedRef,
|
|
2760
|
+
props: [{
|
|
2761
|
+
id
|
|
2762
|
+
}, elementProps]
|
|
2763
|
+
});
|
|
2764
|
+
});
|
|
2765
|
+
if (process.env.NODE_ENV !== "production") DialogTitle.displayName = "DialogTitle";
|
|
2878
2766
|
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
}
|
|
2894
|
-
const currentSide = index_esm.getSide(placement);
|
|
2895
|
-
let x = rawX;
|
|
2896
|
-
let y = rawY;
|
|
2897
|
-
if (currentSide === 'left') {
|
|
2898
|
-
x = offsetDimensions.width - (rawX + floatRect.width);
|
|
2899
|
-
}
|
|
2900
|
-
if (currentSide === 'top') {
|
|
2901
|
-
y = offsetDimensions.height - (rawY + floatRect.height);
|
|
2902
|
-
}
|
|
2903
|
-
const sideX = currentSide === 'left' ? 'right' : DEFAULT_SIDES.sideX;
|
|
2904
|
-
const sideY = currentSide === 'top' ? 'bottom' : DEFAULT_SIDES.sideY;
|
|
2905
|
-
return {
|
|
2906
|
-
x,
|
|
2907
|
-
y,
|
|
2908
|
-
data: {
|
|
2909
|
-
sideX,
|
|
2910
|
-
sideY
|
|
2911
|
-
}
|
|
2912
|
-
};
|
|
2767
|
+
/**
|
|
2768
|
+
* A heading that labels the drawer.
|
|
2769
|
+
* Renders an `<h2>` element.
|
|
2770
|
+
*
|
|
2771
|
+
* Documentation: [Base UI Drawer](https://base-ui.com/react/components/drawer)
|
|
2772
|
+
*/
|
|
2773
|
+
const DrawerTitle = DialogTitle;
|
|
2774
|
+
|
|
2775
|
+
const MenuPositionerContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
2776
|
+
if (process.env.NODE_ENV !== "production") MenuPositionerContext.displayName = "MenuPositionerContext";
|
|
2777
|
+
function useMenuPositionerContext(optional) {
|
|
2778
|
+
const context = React__namespace.useContext(MenuPositionerContext);
|
|
2779
|
+
if (context === undefined && !optional) {
|
|
2780
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: MenuPositionerContext is missing. MenuPositioner parts must be placed within <Menu.Positioner>.' : useRenderElement.formatErrorMessage(33));
|
|
2913
2781
|
}
|
|
2914
|
-
|
|
2782
|
+
return context;
|
|
2783
|
+
}
|
|
2915
2784
|
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
const
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
left: isLogicalSideParam ? logicalLeft : 'left'
|
|
2925
|
-
}[renderedSide];
|
|
2785
|
+
const MenuRootContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
2786
|
+
if (process.env.NODE_ENV !== "production") MenuRootContext.displayName = "MenuRootContext";
|
|
2787
|
+
function useMenuRootContext(optional) {
|
|
2788
|
+
const context = React__namespace.useContext(MenuRootContext);
|
|
2789
|
+
if (context === undefined && !optional) {
|
|
2790
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: MenuRootContext is missing. Menu parts must be placed within <Menu.Root>.' : useRenderElement.formatErrorMessage(36));
|
|
2791
|
+
}
|
|
2792
|
+
return context;
|
|
2926
2793
|
}
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
width: rects.reference.width,
|
|
2937
|
-
height: rects.reference.height
|
|
2938
|
-
},
|
|
2939
|
-
positioner: {
|
|
2940
|
-
width: rects.floating.width,
|
|
2941
|
-
height: rects.floating.height
|
|
2942
|
-
}
|
|
2943
|
-
};
|
|
2944
|
-
return data;
|
|
2794
|
+
|
|
2795
|
+
const ContextMenuRootContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
2796
|
+
if (process.env.NODE_ENV !== "production") ContextMenuRootContext.displayName = "ContextMenuRootContext";
|
|
2797
|
+
function useContextMenuRootContext(optional = true) {
|
|
2798
|
+
const context = React__namespace.useContext(ContextMenuRootContext);
|
|
2799
|
+
if (context === undefined && !optional) {
|
|
2800
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: ContextMenuRootContext is missing. ContextMenu parts must be placed within <ContextMenu.Root>.' : useRenderElement.formatErrorMessage(25));
|
|
2801
|
+
}
|
|
2802
|
+
return context;
|
|
2945
2803
|
}
|
|
2804
|
+
|
|
2946
2805
|
/**
|
|
2947
|
-
*
|
|
2948
|
-
*
|
|
2806
|
+
* Returns common props shared by all menu item types.
|
|
2807
|
+
* This hook extracts the shared logic for id, role, tabIndex, onKeyDown,
|
|
2808
|
+
* onMouseMove, onClick, and onMouseUp handlers.
|
|
2949
2809
|
*/
|
|
2950
|
-
function
|
|
2810
|
+
function useMenuItemCommonProps(params) {
|
|
2951
2811
|
const {
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
side: sideParam = 'bottom',
|
|
2956
|
-
sideOffset = 0,
|
|
2957
|
-
align = 'center',
|
|
2958
|
-
alignOffset = 0,
|
|
2959
|
-
collisionBoundary,
|
|
2960
|
-
collisionPadding: collisionPaddingParam = 5,
|
|
2961
|
-
sticky = false,
|
|
2962
|
-
arrowPadding = 5,
|
|
2963
|
-
disableAnchorTracking = false,
|
|
2964
|
-
// Private parameters
|
|
2965
|
-
keepMounted = false,
|
|
2966
|
-
floatingRootContext,
|
|
2967
|
-
mounted,
|
|
2968
|
-
collisionAvoidance,
|
|
2969
|
-
shiftCrossAxis = false,
|
|
2812
|
+
closeOnClick,
|
|
2813
|
+
highlighted,
|
|
2814
|
+
id,
|
|
2970
2815
|
nodeId,
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2816
|
+
store,
|
|
2817
|
+
typingRef,
|
|
2818
|
+
itemRef,
|
|
2819
|
+
itemMetadata
|
|
2974
2820
|
} = params;
|
|
2975
|
-
const
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
const
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
'inline-end': isRtl ? 'left' : 'right',
|
|
2994
|
-
'inline-start': isRtl ? 'right' : 'left'
|
|
2995
|
-
}[sideParam];
|
|
2996
|
-
const placement = align === 'center' ? side : `${side}-${align}`;
|
|
2997
|
-
let collisionPadding = collisionPaddingParam;
|
|
2821
|
+
const {
|
|
2822
|
+
events: menuEvents
|
|
2823
|
+
} = store.useState('floatingTreeRoot');
|
|
2824
|
+
const contextMenuContext = useContextMenuRootContext(true);
|
|
2825
|
+
const isContextMenu = contextMenuContext !== undefined;
|
|
2826
|
+
return React__namespace.useMemo(() => ({
|
|
2827
|
+
id,
|
|
2828
|
+
role: 'menuitem',
|
|
2829
|
+
tabIndex: highlighted ? 0 : -1,
|
|
2830
|
+
onKeyDown(event) {
|
|
2831
|
+
if (event.key === ' ' && typingRef?.current) {
|
|
2832
|
+
event.preventDefault();
|
|
2833
|
+
}
|
|
2834
|
+
},
|
|
2835
|
+
onMouseMove(event) {
|
|
2836
|
+
if (!nodeId) {
|
|
2837
|
+
return;
|
|
2838
|
+
}
|
|
2998
2839
|
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
}
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
2840
|
+
// Inform the floating tree that a menu item within this menu was hovered/moved over
|
|
2841
|
+
// so unrelated descendant submenus can be closed.
|
|
2842
|
+
menuEvents.emit('itemhover', {
|
|
2843
|
+
nodeId,
|
|
2844
|
+
target: event.currentTarget
|
|
2845
|
+
});
|
|
2846
|
+
},
|
|
2847
|
+
onClick(event) {
|
|
2848
|
+
if (closeOnClick) {
|
|
2849
|
+
menuEvents.emit('close', {
|
|
2850
|
+
domEvent: event,
|
|
2851
|
+
reason: clamp.itemPress
|
|
2852
|
+
});
|
|
2853
|
+
}
|
|
2854
|
+
},
|
|
2855
|
+
onMouseUp(event) {
|
|
2856
|
+
if (contextMenuContext) {
|
|
2857
|
+
const initialCursorPoint = contextMenuContext.initialCursorPointRef.current;
|
|
2858
|
+
contextMenuContext.initialCursorPointRef.current = null;
|
|
2859
|
+
if (isContextMenu && initialCursorPoint && Math.abs(event.clientX - initialCursorPoint.x) <= 1 && Math.abs(event.clientY - initialCursorPoint.y) <= 1) {
|
|
2860
|
+
return;
|
|
2861
|
+
}
|
|
2862
|
+
|
|
2863
|
+
// On non-macOS platforms, this mouseup belongs to the right-click gesture
|
|
2864
|
+
// that opened the context menu, so it must not activate an item.
|
|
2865
|
+
if (isContextMenu && !clamp.isMac && event.button === 2) {
|
|
2866
|
+
return;
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
if (itemRef.current && store.context.allowMouseUpTriggerRef.current && (!isContextMenu || event.button === 2)) {
|
|
2870
|
+
// This fires whenever the user clicks on the trigger, moves the cursor, and releases it over the item.
|
|
2871
|
+
// We trigger the click and override the `closeOnClick` preference to always close the menu.
|
|
2872
|
+
if (!itemMetadata || itemMetadata.type === 'regular-item') {
|
|
2873
|
+
itemRef.current.click();
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
}), [closeOnClick, highlighted, id, menuEvents, nodeId, store, typingRef, itemRef, contextMenuContext, isContextMenu, itemMetadata]);
|
|
2878
|
+
}
|
|
2879
|
+
|
|
2880
|
+
const REGULAR_ITEM = {
|
|
2881
|
+
type: 'regular-item'
|
|
2882
|
+
};
|
|
2883
|
+
function useMenuItem(params) {
|
|
2884
|
+
const {
|
|
2885
|
+
closeOnClick,
|
|
2886
|
+
disabled = false,
|
|
2887
|
+
highlighted,
|
|
2888
|
+
id,
|
|
2889
|
+
store,
|
|
2890
|
+
typingRef = store.context.typingRef,
|
|
2891
|
+
nativeButton,
|
|
2892
|
+
itemMetadata,
|
|
2893
|
+
nodeId
|
|
2894
|
+
} = params;
|
|
2895
|
+
const itemRef = React__namespace.useRef(null);
|
|
2896
|
+
const {
|
|
2897
|
+
getButtonProps,
|
|
2898
|
+
buttonRef
|
|
2899
|
+
} = clamp.useButton({
|
|
2900
|
+
disabled,
|
|
2901
|
+
focusableWhenDisabled: true,
|
|
2902
|
+
native: nativeButton,
|
|
2903
|
+
composite: true
|
|
2904
|
+
});
|
|
2905
|
+
const commonProps = useMenuItemCommonProps({
|
|
2906
|
+
closeOnClick,
|
|
2907
|
+
highlighted,
|
|
2908
|
+
id,
|
|
2909
|
+
nodeId,
|
|
2910
|
+
store,
|
|
2911
|
+
typingRef,
|
|
2912
|
+
itemRef,
|
|
2913
|
+
itemMetadata
|
|
2914
|
+
});
|
|
2915
|
+
const getItemProps = React__namespace.useCallback(externalProps => {
|
|
2916
|
+
return useRenderElement.mergeProps(commonProps, {
|
|
2917
|
+
onMouseEnter() {
|
|
2918
|
+
if (itemMetadata.type !== 'submenu-trigger') {
|
|
2919
|
+
return;
|
|
2920
|
+
}
|
|
2921
|
+
itemMetadata.setActive();
|
|
2922
|
+
}
|
|
2923
|
+
}, externalProps, getButtonProps);
|
|
2924
|
+
}, [commonProps, getButtonProps, itemMetadata]);
|
|
2925
|
+
const mergedRef = useRenderElement.useMergedRefs(itemRef, buttonRef);
|
|
2926
|
+
return React__namespace.useMemo(() => ({
|
|
2927
|
+
getItemProps,
|
|
2928
|
+
itemRef: mergedRef
|
|
2929
|
+
}), [getItemProps, mergedRef]);
|
|
2930
|
+
}
|
|
3026
2931
|
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
2932
|
+
let MenuCheckboxItemDataAttributes = /*#__PURE__*/function (MenuCheckboxItemDataAttributes) {
|
|
2933
|
+
/**
|
|
2934
|
+
* Present when the menu checkbox item is checked.
|
|
2935
|
+
*/
|
|
2936
|
+
MenuCheckboxItemDataAttributes["checked"] = "data-checked";
|
|
2937
|
+
/**
|
|
2938
|
+
* Present when the menu checkbox item is not checked.
|
|
2939
|
+
*/
|
|
2940
|
+
MenuCheckboxItemDataAttributes["unchecked"] = "data-unchecked";
|
|
2941
|
+
/**
|
|
2942
|
+
* Present when the menu checkbox item is disabled.
|
|
2943
|
+
*/
|
|
2944
|
+
MenuCheckboxItemDataAttributes["disabled"] = "data-disabled";
|
|
2945
|
+
/**
|
|
2946
|
+
* Present when the menu checkbox item is highlighted.
|
|
2947
|
+
*/
|
|
2948
|
+
MenuCheckboxItemDataAttributes["highlighted"] = "data-highlighted";
|
|
2949
|
+
return MenuCheckboxItemDataAttributes;
|
|
2950
|
+
}({});
|
|
3031
2951
|
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
const sideAxis = typeof sideOffsetRef.current === 'function' ? sideOffsetRef.current(data) : sideOffsetRef.current;
|
|
3040
|
-
const alignAxis = typeof alignOffsetRef.current === 'function' ? alignOffsetRef.current(data) : alignOffsetRef.current;
|
|
3041
|
-
return {
|
|
3042
|
-
mainAxis: sideAxis,
|
|
3043
|
-
crossAxis: alignAxis,
|
|
3044
|
-
alignmentAxis: alignAxis
|
|
3045
|
-
};
|
|
3046
|
-
}, [sideOffsetDep, alignOffsetDep, isRtl, sideParam])];
|
|
3047
|
-
const shiftDisabled = collisionAvoidanceAlign === 'none' && collisionAvoidanceSide !== 'shift';
|
|
3048
|
-
const crossAxisShiftEnabled = !shiftDisabled && (sticky || shiftCrossAxis || collisionAvoidanceSide === 'shift');
|
|
3049
|
-
const flipMiddleware = collisionAvoidanceSide === 'none' ? null : floatingUi_reactDom.flip({
|
|
3050
|
-
...commonCollisionProps,
|
|
3051
|
-
// Ensure the popup flips if it's been limited by its --available-height and it resizes.
|
|
3052
|
-
// Since the size() padding is smaller than the flip() padding, flip() will take precedence.
|
|
3053
|
-
padding: {
|
|
3054
|
-
top: collisionPadding.top + bias,
|
|
3055
|
-
right: collisionPadding.right + bias,
|
|
3056
|
-
bottom: collisionPadding.bottom + bias,
|
|
3057
|
-
left: collisionPadding.left + bias
|
|
3058
|
-
},
|
|
3059
|
-
mainAxis: !shiftCrossAxis && collisionAvoidanceSide === 'flip',
|
|
3060
|
-
crossAxis: collisionAvoidanceAlign === 'flip' ? 'alignment' : false,
|
|
3061
|
-
fallbackAxisSideDirection: collisionAvoidanceFallbackAxisSide
|
|
3062
|
-
});
|
|
3063
|
-
const shiftMiddleware = shiftDisabled ? null : floatingUi_reactDom.shift(data => {
|
|
3064
|
-
const html = useValueChanged.ownerDocument(data.elements.floating).documentElement;
|
|
2952
|
+
const itemMapping = {
|
|
2953
|
+
checked(value) {
|
|
2954
|
+
if (value) {
|
|
2955
|
+
return {
|
|
2956
|
+
[MenuCheckboxItemDataAttributes.checked]: ''
|
|
2957
|
+
};
|
|
2958
|
+
}
|
|
3065
2959
|
return {
|
|
3066
|
-
|
|
3067
|
-
// Use the Layout Viewport to avoid shifting around when pinch-zooming
|
|
3068
|
-
// for context menus.
|
|
3069
|
-
rootBoundary: shiftCrossAxis ? {
|
|
3070
|
-
x: 0,
|
|
3071
|
-
y: 0,
|
|
3072
|
-
width: html.clientWidth,
|
|
3073
|
-
height: html.clientHeight
|
|
3074
|
-
} : undefined,
|
|
3075
|
-
mainAxis: collisionAvoidanceAlign !== 'none',
|
|
3076
|
-
crossAxis: crossAxisShiftEnabled,
|
|
3077
|
-
limiter: sticky || shiftCrossAxis ? undefined : floatingUi_reactDom.limitShift(limitData => {
|
|
3078
|
-
if (!arrowRef.current) {
|
|
3079
|
-
return {};
|
|
3080
|
-
}
|
|
3081
|
-
const {
|
|
3082
|
-
width,
|
|
3083
|
-
height
|
|
3084
|
-
} = arrowRef.current.getBoundingClientRect();
|
|
3085
|
-
const sideAxis = index_esm.getSideAxis(index_esm.getSide(limitData.placement));
|
|
3086
|
-
const arrowSize = sideAxis === 'y' ? width : height;
|
|
3087
|
-
const offsetAmount = sideAxis === 'y' ? collisionPadding.left + collisionPadding.right : collisionPadding.top + collisionPadding.bottom;
|
|
3088
|
-
return {
|
|
3089
|
-
offset: arrowSize / 2 + offsetAmount / 2
|
|
3090
|
-
};
|
|
3091
|
-
})
|
|
2960
|
+
[MenuCheckboxItemDataAttributes.unchecked]: ''
|
|
3092
2961
|
};
|
|
3093
|
-
},
|
|
2962
|
+
},
|
|
2963
|
+
...clamp.transitionStatusMapping
|
|
2964
|
+
};
|
|
3094
2965
|
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
2966
|
+
const MenuGroupContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
2967
|
+
if (process.env.NODE_ENV !== "production") MenuGroupContext.displayName = "MenuGroupContext";
|
|
2968
|
+
function useMenuGroupRootContext() {
|
|
2969
|
+
const context = React__namespace.useContext(MenuGroupContext);
|
|
2970
|
+
if (context === undefined) {
|
|
2971
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: MenuGroupRootContext is missing. Menu group parts must be used within <Menu.Group>.' : useRenderElement.formatErrorMessage(31));
|
|
3100
2972
|
}
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
apply({
|
|
3104
|
-
elements: {
|
|
3105
|
-
floating
|
|
3106
|
-
},
|
|
3107
|
-
availableWidth,
|
|
3108
|
-
availableHeight,
|
|
3109
|
-
rects
|
|
3110
|
-
}) {
|
|
3111
|
-
const floatingStyle = floating.style;
|
|
3112
|
-
floatingStyle.setProperty('--available-width', `${availableWidth}px`);
|
|
3113
|
-
floatingStyle.setProperty('--available-height', `${availableHeight}px`);
|
|
2973
|
+
return context;
|
|
2974
|
+
}
|
|
3114
2975
|
|
|
3115
|
-
|
|
3116
|
-
const dpr = window.devicePixelRatio || 1;
|
|
3117
|
-
const {
|
|
3118
|
-
x,
|
|
3119
|
-
y,
|
|
3120
|
-
width,
|
|
3121
|
-
height
|
|
3122
|
-
} = rects.reference;
|
|
3123
|
-
const anchorWidth = (Math.round((x + width) * dpr) - Math.round(x * dpr)) / dpr;
|
|
3124
|
-
const anchorHeight = (Math.round((y + height) * dpr) - Math.round(y * dpr)) / dpr;
|
|
3125
|
-
floatingStyle.setProperty('--anchor-width', `${anchorWidth}px`);
|
|
3126
|
-
floatingStyle.setProperty('--anchor-height', `${anchorHeight}px`);
|
|
3127
|
-
}
|
|
3128
|
-
}), arrow(() => ({
|
|
3129
|
-
// `transform-origin` calculations rely on an element existing. If the arrow hasn't been set,
|
|
3130
|
-
// we'll create a fake element.
|
|
3131
|
-
element: arrowRef.current || document.createElement('div'),
|
|
3132
|
-
padding: arrowPadding,
|
|
3133
|
-
offsetParent: 'floating'
|
|
3134
|
-
}), [arrowPadding]), {
|
|
3135
|
-
name: 'transformOrigin',
|
|
3136
|
-
fn(state) {
|
|
3137
|
-
const {
|
|
3138
|
-
elements,
|
|
3139
|
-
middlewareData,
|
|
3140
|
-
placement: renderedPlacement,
|
|
3141
|
-
rects,
|
|
3142
|
-
y
|
|
3143
|
-
} = state;
|
|
3144
|
-
const currentRenderedSide = index_esm.getSide(renderedPlacement);
|
|
3145
|
-
const currentRenderedAxis = index_esm.getSideAxis(currentRenderedSide);
|
|
3146
|
-
const arrowEl = arrowRef.current;
|
|
3147
|
-
const arrowX = middlewareData.arrow?.x || 0;
|
|
3148
|
-
const arrowY = middlewareData.arrow?.y || 0;
|
|
3149
|
-
const arrowWidth = arrowEl?.clientWidth || 0;
|
|
3150
|
-
const arrowHeight = arrowEl?.clientHeight || 0;
|
|
3151
|
-
const transformX = arrowX + arrowWidth / 2;
|
|
3152
|
-
const transformY = arrowY + arrowHeight / 2;
|
|
3153
|
-
const shiftY = Math.abs(middlewareData.shift?.y || 0);
|
|
3154
|
-
const halfAnchorHeight = rects.reference.height / 2;
|
|
3155
|
-
const sideOffsetValue = typeof sideOffset === 'function' ? sideOffset(getOffsetData(state, sideParam, isRtl)) : sideOffset;
|
|
3156
|
-
const isOverlappingAnchor = shiftY > sideOffsetValue;
|
|
3157
|
-
const adjacentTransformOrigin = {
|
|
3158
|
-
top: `${transformX}px calc(100% + ${sideOffsetValue}px)`,
|
|
3159
|
-
bottom: `${transformX}px ${-sideOffsetValue}px`,
|
|
3160
|
-
left: `calc(100% + ${sideOffsetValue}px) ${transformY}px`,
|
|
3161
|
-
right: `${-sideOffsetValue}px ${transformY}px`
|
|
3162
|
-
}[currentRenderedSide];
|
|
3163
|
-
const overlapTransformOrigin = `${transformX}px ${rects.reference.y + halfAnchorHeight - y}px`;
|
|
3164
|
-
elements.floating.style.setProperty('--transform-origin', crossAxisShiftEnabled && currentRenderedAxis === 'y' && isOverlappingAnchor ? overlapTransformOrigin : adjacentTransformOrigin);
|
|
3165
|
-
return {};
|
|
3166
|
-
}
|
|
3167
|
-
}, hide, adaptiveOrigin);
|
|
3168
|
-
useValueChanged.useIsoLayoutEffect(() => {
|
|
3169
|
-
// Ensure positioning doesn't run initially for `keepMounted` elements that
|
|
3170
|
-
// aren't initially open.
|
|
3171
|
-
if (!mounted && floatingRootContext) {
|
|
3172
|
-
floatingRootContext.update({
|
|
3173
|
-
referenceElement: null,
|
|
3174
|
-
floatingElement: null,
|
|
3175
|
-
domReferenceElement: null
|
|
3176
|
-
});
|
|
3177
|
-
}
|
|
3178
|
-
}, [mounted, floatingRootContext]);
|
|
3179
|
-
const autoUpdateOptions = React__namespace.useMemo(() => ({
|
|
3180
|
-
elementResize: !disableAnchorTracking && typeof ResizeObserver !== 'undefined',
|
|
3181
|
-
layoutShift: !disableAnchorTracking && typeof IntersectionObserver !== 'undefined'
|
|
3182
|
-
}), [disableAnchorTracking]);
|
|
2976
|
+
const MenuGroup = /*#__PURE__*/React__namespace.forwardRef(function MenuGroup(componentProps, forwardedRef) {
|
|
3183
2977
|
const {
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
2978
|
+
render,
|
|
2979
|
+
className,
|
|
2980
|
+
...elementProps
|
|
2981
|
+
} = componentProps;
|
|
2982
|
+
const [labelId, setLabelId] = React__namespace.useState(undefined);
|
|
2983
|
+
const context = React__namespace.useMemo(() => ({
|
|
2984
|
+
setLabelId
|
|
2985
|
+
}), [setLabelId]);
|
|
2986
|
+
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
2987
|
+
ref: forwardedRef,
|
|
2988
|
+
props: {
|
|
2989
|
+
role: 'group',
|
|
2990
|
+
'aria-labelledby': labelId,
|
|
2991
|
+
...elementProps
|
|
2992
|
+
}
|
|
2993
|
+
});
|
|
2994
|
+
return /*#__PURE__*/jsxRuntime.jsx(MenuGroupContext.Provider, {
|
|
2995
|
+
value: context,
|
|
2996
|
+
children: element
|
|
3202
2997
|
});
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
sideY
|
|
3206
|
-
} = middlewareData.adaptiveOrigin || DEFAULT_SIDES;
|
|
2998
|
+
});
|
|
2999
|
+
if (process.env.NODE_ENV !== "production") MenuGroup.displayName = "MenuGroup";
|
|
3207
3000
|
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3001
|
+
/**
|
|
3002
|
+
* An accessible label that is automatically associated with its parent group.
|
|
3003
|
+
* Renders a `<div>` element.
|
|
3004
|
+
*
|
|
3005
|
+
* Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
|
|
3006
|
+
*/
|
|
3007
|
+
const MenuGroupLabel = /*#__PURE__*/React__namespace.forwardRef(function MenuGroupLabelComponent(componentProps, forwardedRef) {
|
|
3008
|
+
const {
|
|
3009
|
+
className,
|
|
3010
|
+
render,
|
|
3011
|
+
id: idProp,
|
|
3012
|
+
...elementProps
|
|
3013
|
+
} = componentProps;
|
|
3014
|
+
const id = clamp.useBaseUiId(idProp);
|
|
3015
|
+
const {
|
|
3016
|
+
setLabelId
|
|
3017
|
+
} = useMenuGroupRootContext();
|
|
3018
|
+
clamp.useIsoLayoutEffect(() => {
|
|
3019
|
+
setLabelId(id);
|
|
3020
|
+
return () => {
|
|
3021
|
+
setLabelId(undefined);
|
|
3219
3022
|
};
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
if (!mounted) {
|
|
3228
|
-
return;
|
|
3229
|
-
}
|
|
3230
|
-
const anchorValue = anchorValueRef.current;
|
|
3231
|
-
const resolvedAnchor = typeof anchorValue === 'function' ? anchorValue() : anchorValue;
|
|
3232
|
-
const unwrappedElement = (isRef(resolvedAnchor) ? resolvedAnchor.current : resolvedAnchor) || null;
|
|
3233
|
-
const finalAnchor = unwrappedElement || null;
|
|
3234
|
-
if (finalAnchor !== registeredPositionReferenceRef.current) {
|
|
3235
|
-
refs.setPositionReference(finalAnchor);
|
|
3236
|
-
registeredPositionReferenceRef.current = finalAnchor;
|
|
3237
|
-
}
|
|
3238
|
-
}, [mounted, refs, anchorDep, anchorValueRef]);
|
|
3239
|
-
React__namespace.useEffect(() => {
|
|
3240
|
-
if (!mounted) {
|
|
3241
|
-
return;
|
|
3023
|
+
}, [setLabelId, id]);
|
|
3024
|
+
return useRenderElement.useRenderElement('div', componentProps, {
|
|
3025
|
+
ref: forwardedRef,
|
|
3026
|
+
props: {
|
|
3027
|
+
id,
|
|
3028
|
+
role: 'presentation',
|
|
3029
|
+
...elementProps
|
|
3242
3030
|
}
|
|
3243
|
-
|
|
3031
|
+
});
|
|
3032
|
+
});
|
|
3033
|
+
if (process.env.NODE_ENV !== "production") MenuGroupLabel.displayName = "MenuGroupLabel";
|
|
3244
3034
|
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
const
|
|
3263
|
-
|
|
3264
|
-
|
|
3035
|
+
/**
|
|
3036
|
+
* An individual interactive item in the menu.
|
|
3037
|
+
* Renders a `<div>` element.
|
|
3038
|
+
*
|
|
3039
|
+
* Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
|
|
3040
|
+
*/
|
|
3041
|
+
const MenuItem = /*#__PURE__*/React__namespace.forwardRef(function MenuItem(componentProps, forwardedRef) {
|
|
3042
|
+
const {
|
|
3043
|
+
render,
|
|
3044
|
+
className,
|
|
3045
|
+
id: idProp,
|
|
3046
|
+
label,
|
|
3047
|
+
nativeButton = false,
|
|
3048
|
+
disabled = false,
|
|
3049
|
+
closeOnClick = true,
|
|
3050
|
+
...elementProps
|
|
3051
|
+
} = componentProps;
|
|
3052
|
+
const listItem = useCompositeListItem({
|
|
3053
|
+
label
|
|
3054
|
+
});
|
|
3055
|
+
const menuPositionerContext = useMenuPositionerContext(true);
|
|
3056
|
+
const id = clamp.useBaseUiId(idProp);
|
|
3057
|
+
const {
|
|
3058
|
+
store
|
|
3059
|
+
} = useMenuRootContext();
|
|
3060
|
+
const highlighted = store.useState('isActive', listItem.index);
|
|
3061
|
+
const itemProps = store.useState('itemProps');
|
|
3062
|
+
const {
|
|
3063
|
+
getItemProps,
|
|
3064
|
+
itemRef
|
|
3065
|
+
} = useMenuItem({
|
|
3066
|
+
closeOnClick,
|
|
3067
|
+
disabled,
|
|
3068
|
+
highlighted,
|
|
3069
|
+
id,
|
|
3070
|
+
store,
|
|
3071
|
+
nativeButton,
|
|
3072
|
+
nodeId: menuPositionerContext?.nodeId,
|
|
3073
|
+
itemMetadata: REGULAR_ITEM
|
|
3074
|
+
});
|
|
3075
|
+
const state = {
|
|
3076
|
+
disabled,
|
|
3077
|
+
highlighted
|
|
3078
|
+
};
|
|
3079
|
+
return useRenderElement.useRenderElement('div', componentProps, {
|
|
3080
|
+
state,
|
|
3081
|
+
props: [itemProps, elementProps, getItemProps],
|
|
3082
|
+
ref: [itemRef, forwardedRef, listItem.ref]
|
|
3083
|
+
});
|
|
3084
|
+
});
|
|
3085
|
+
if (process.env.NODE_ENV !== "production") MenuItem.displayName = "MenuItem";
|
|
3265
3086
|
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
}
|
|
3281
|
-
const
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3087
|
+
/**
|
|
3088
|
+
* A link in the menu that can be used to navigate to a different page or section.
|
|
3089
|
+
* Renders an `<a>` element.
|
|
3090
|
+
*
|
|
3091
|
+
* Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
|
|
3092
|
+
*/
|
|
3093
|
+
const MenuLinkItem = /*#__PURE__*/React__namespace.forwardRef(function MenuLinkItem(componentProps, forwardedRef) {
|
|
3094
|
+
const {
|
|
3095
|
+
render,
|
|
3096
|
+
className,
|
|
3097
|
+
id: idProp,
|
|
3098
|
+
label,
|
|
3099
|
+
closeOnClick = false,
|
|
3100
|
+
...elementProps
|
|
3101
|
+
} = componentProps;
|
|
3102
|
+
const linkRef = React__namespace.useRef(null);
|
|
3103
|
+
const listItem = useCompositeListItem({
|
|
3104
|
+
label
|
|
3105
|
+
});
|
|
3106
|
+
const menuPositionerContext = useMenuPositionerContext(true);
|
|
3107
|
+
const nodeId = menuPositionerContext?.nodeId;
|
|
3108
|
+
const id = clamp.useBaseUiId(idProp);
|
|
3109
|
+
const {
|
|
3110
|
+
store
|
|
3111
|
+
} = useMenuRootContext();
|
|
3112
|
+
const highlighted = store.useState('isActive', listItem.index);
|
|
3113
|
+
const itemProps = store.useState('itemProps');
|
|
3114
|
+
const typingRef = store.context.typingRef;
|
|
3115
|
+
const {
|
|
3116
|
+
getButtonProps,
|
|
3117
|
+
buttonRef
|
|
3118
|
+
} = clamp.useButton({
|
|
3119
|
+
native: false,
|
|
3120
|
+
composite: true
|
|
3121
|
+
});
|
|
3122
|
+
const commonProps = useMenuItemCommonProps({
|
|
3123
|
+
closeOnClick,
|
|
3124
|
+
highlighted,
|
|
3125
|
+
id,
|
|
3126
|
+
nodeId,
|
|
3127
|
+
store,
|
|
3128
|
+
typingRef,
|
|
3129
|
+
itemRef: linkRef
|
|
3130
|
+
});
|
|
3131
|
+
function getItemProps(externalProps) {
|
|
3132
|
+
return useRenderElement.mergeProps(commonProps, externalProps, getButtonProps);
|
|
3133
|
+
}
|
|
3134
|
+
const state = React__namespace.useMemo(() => ({
|
|
3135
|
+
highlighted
|
|
3136
|
+
}), [highlighted]);
|
|
3137
|
+
return useRenderElement.useRenderElement('a', componentProps, {
|
|
3138
|
+
state,
|
|
3139
|
+
props: [itemProps, elementProps, getItemProps],
|
|
3140
|
+
ref: [linkRef, buttonRef, forwardedRef, listItem.ref]
|
|
3141
|
+
});
|
|
3142
|
+
});
|
|
3143
|
+
if (process.env.NODE_ENV !== "production") MenuLinkItem.displayName = "MenuLinkItem";
|
|
3144
|
+
|
|
3145
|
+
const ToolbarRootContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
3146
|
+
if (process.env.NODE_ENV !== "production") ToolbarRootContext.displayName = "ToolbarRootContext";
|
|
3147
|
+
function useToolbarRootContext(optional) {
|
|
3148
|
+
const context = React__namespace.useContext(ToolbarRootContext);
|
|
3149
|
+
if (context === undefined && !optional) {
|
|
3150
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: ToolbarRootContext is missing. Toolbar parts must be placed within <Toolbar.Root>.' : useRenderElement.formatErrorMessage(69));
|
|
3151
|
+
}
|
|
3152
|
+
return context;
|
|
3299
3153
|
}
|
|
3300
3154
|
|
|
3301
|
-
|
|
3155
|
+
const stateAttributesMapping = {
|
|
3156
|
+
...ScrollAreaViewport.popupStateMapping,
|
|
3157
|
+
...clamp.transitionStatusMapping
|
|
3158
|
+
};
|
|
3159
|
+
|
|
3302
3160
|
/**
|
|
3303
|
-
*
|
|
3304
|
-
*
|
|
3161
|
+
* A container for the menu items.
|
|
3162
|
+
* Renders a `<div>` element.
|
|
3163
|
+
*
|
|
3164
|
+
* Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
|
|
3305
3165
|
*/
|
|
3306
|
-
function
|
|
3166
|
+
const MenuPopup = /*#__PURE__*/React__namespace.forwardRef(function MenuPopup(componentProps, forwardedRef) {
|
|
3167
|
+
const {
|
|
3168
|
+
render,
|
|
3169
|
+
className,
|
|
3170
|
+
finalFocus,
|
|
3171
|
+
...elementProps
|
|
3172
|
+
} = componentProps;
|
|
3173
|
+
const {
|
|
3174
|
+
store
|
|
3175
|
+
} = useMenuRootContext();
|
|
3307
3176
|
const {
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
const
|
|
3314
|
-
const
|
|
3315
|
-
const
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
const
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
setMapTick(lastTickRef.current);
|
|
3333
|
-
});
|
|
3334
|
-
const unregister = useValueChanged.useStableCallback(node => {
|
|
3335
|
-
map.delete(node);
|
|
3336
|
-
lastTickRef.current += 1;
|
|
3337
|
-
setMapTick(lastTickRef.current);
|
|
3338
|
-
});
|
|
3339
|
-
const sortedMap = React__namespace.useMemo(() => {
|
|
3340
|
-
const newMap = new Map();
|
|
3341
|
-
// Filter out disconnected elements before sorting to avoid inconsistent
|
|
3342
|
-
// compareDocumentPosition results when elements are detached from the DOM.
|
|
3343
|
-
const sortedNodes = Array.from(map.keys()).filter(node => node.isConnected).sort(sortByDocumentPosition);
|
|
3344
|
-
sortedNodes.forEach((node, index) => {
|
|
3345
|
-
const metadata = map.get(node) ?? {};
|
|
3346
|
-
newMap.set(node, {
|
|
3347
|
-
...metadata,
|
|
3348
|
-
index
|
|
3349
|
-
});
|
|
3350
|
-
});
|
|
3351
|
-
return newMap;
|
|
3352
|
-
}, [map, mapTick]);
|
|
3353
|
-
useValueChanged.useIsoLayoutEffect(() => {
|
|
3354
|
-
if (typeof MutationObserver !== 'function' || sortedMap.size === 0) {
|
|
3355
|
-
return undefined;
|
|
3356
|
-
}
|
|
3357
|
-
const mutationObserver = new MutationObserver(entries => {
|
|
3358
|
-
const diff = new Set();
|
|
3359
|
-
const updateDiff = node => diff.has(node) ? diff.delete(node) : diff.add(node);
|
|
3360
|
-
entries.forEach(entry => {
|
|
3361
|
-
entry.removedNodes.forEach(updateDiff);
|
|
3362
|
-
entry.addedNodes.forEach(updateDiff);
|
|
3363
|
-
});
|
|
3364
|
-
if (diff.size === 0) {
|
|
3365
|
-
lastTickRef.current += 1;
|
|
3366
|
-
setMapTick(lastTickRef.current);
|
|
3367
|
-
}
|
|
3368
|
-
});
|
|
3369
|
-
sortedMap.forEach((_, node) => {
|
|
3370
|
-
if (node.parentElement) {
|
|
3371
|
-
mutationObserver.observe(node.parentElement, {
|
|
3372
|
-
childList: true
|
|
3373
|
-
});
|
|
3374
|
-
}
|
|
3375
|
-
});
|
|
3376
|
-
return () => {
|
|
3377
|
-
mutationObserver.disconnect();
|
|
3378
|
-
};
|
|
3379
|
-
}, [sortedMap]);
|
|
3380
|
-
useValueChanged.useIsoLayoutEffect(() => {
|
|
3381
|
-
const shouldUpdateLengths = lastTickRef.current === mapTick;
|
|
3382
|
-
if (shouldUpdateLengths) {
|
|
3383
|
-
if (elementsRef.current.length !== sortedMap.size) {
|
|
3384
|
-
elementsRef.current.length = sortedMap.size;
|
|
3385
|
-
}
|
|
3386
|
-
if (labelsRef && labelsRef.current.length !== sortedMap.size) {
|
|
3387
|
-
labelsRef.current.length = sortedMap.size;
|
|
3177
|
+
side,
|
|
3178
|
+
align
|
|
3179
|
+
} = useMenuPositionerContext();
|
|
3180
|
+
const insideToolbar = useToolbarRootContext(true) != null;
|
|
3181
|
+
const open = store.useState('open');
|
|
3182
|
+
const transitionStatus = store.useState('transitionStatus');
|
|
3183
|
+
const popupProps = store.useState('popupProps');
|
|
3184
|
+
const mounted = store.useState('mounted');
|
|
3185
|
+
const instantType = store.useState('instantType');
|
|
3186
|
+
const triggerElement = store.useState('activeTriggerElement');
|
|
3187
|
+
const parent = store.useState('parent');
|
|
3188
|
+
const lastOpenChangeReason = store.useState('lastOpenChangeReason');
|
|
3189
|
+
const rootId = store.useState('rootId');
|
|
3190
|
+
const floatingContext = store.useState('floatingRootContext');
|
|
3191
|
+
const floatingTreeRoot = store.useState('floatingTreeRoot');
|
|
3192
|
+
const closeDelay = store.useState('closeDelay');
|
|
3193
|
+
const activeTriggerElement = store.useState('activeTriggerElement');
|
|
3194
|
+
const isContextMenu = parent.type === 'context-menu';
|
|
3195
|
+
clamp.useOpenChangeComplete({
|
|
3196
|
+
open,
|
|
3197
|
+
ref: store.context.popupRef,
|
|
3198
|
+
onComplete() {
|
|
3199
|
+
if (open) {
|
|
3200
|
+
store.context.onOpenChangeComplete?.(true);
|
|
3388
3201
|
}
|
|
3389
|
-
nextIndexRef.current = sortedMap.size;
|
|
3390
3202
|
}
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
}, [elementsRef]);
|
|
3398
|
-
useValueChanged.useIsoLayoutEffect(() => {
|
|
3399
|
-
return () => {
|
|
3400
|
-
if (labelsRef) {
|
|
3401
|
-
labelsRef.current = [];
|
|
3402
|
-
}
|
|
3403
|
-
};
|
|
3404
|
-
}, [labelsRef]);
|
|
3405
|
-
const subscribeMapChange = useValueChanged.useStableCallback(fn => {
|
|
3406
|
-
listeners.add(fn);
|
|
3203
|
+
});
|
|
3204
|
+
React__namespace.useEffect(() => {
|
|
3205
|
+
function handleClose(event) {
|
|
3206
|
+
store.setOpen(false, clamp.createChangeEventDetails(event.reason, event.domEvent));
|
|
3207
|
+
}
|
|
3208
|
+
floatingTreeRoot.events.on('close', handleClose);
|
|
3407
3209
|
return () => {
|
|
3408
|
-
|
|
3210
|
+
floatingTreeRoot.events.off('close', handleClose);
|
|
3409
3211
|
};
|
|
3212
|
+
}, [floatingTreeRoot.events, store]);
|
|
3213
|
+
const hoverEnabled = store.useState('hoverEnabled');
|
|
3214
|
+
const disabled = store.useState('disabled');
|
|
3215
|
+
useHoverFloatingInteraction(floatingContext, {
|
|
3216
|
+
enabled: hoverEnabled && !disabled && !isContextMenu && parent.type !== 'menubar',
|
|
3217
|
+
closeDelay
|
|
3410
3218
|
});
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
}
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3219
|
+
const state = {
|
|
3220
|
+
transitionStatus,
|
|
3221
|
+
side,
|
|
3222
|
+
align,
|
|
3223
|
+
open,
|
|
3224
|
+
nested: parent.type === 'menu',
|
|
3225
|
+
instant: instantType
|
|
3226
|
+
};
|
|
3227
|
+
const setPopupElement = React__namespace.useCallback(element => {
|
|
3228
|
+
store.set('popupElement', element);
|
|
3229
|
+
}, [store]);
|
|
3230
|
+
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
3231
|
+
state,
|
|
3232
|
+
ref: [forwardedRef, store.context.popupRef, setPopupElement],
|
|
3233
|
+
stateAttributesMapping,
|
|
3234
|
+
props: [popupProps, {
|
|
3235
|
+
onKeyDown(event) {
|
|
3236
|
+
if (insideToolbar && ScrollAreaViewport.COMPOSITE_KEYS.has(event.key)) {
|
|
3237
|
+
event.stopPropagation();
|
|
3238
|
+
}
|
|
3239
|
+
}
|
|
3240
|
+
}, getDisabledMountTransitionStyles(transitionStatus), elementProps, {
|
|
3241
|
+
'data-rootownerid': rootId
|
|
3242
|
+
}]
|
|
3425
3243
|
});
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
}
|
|
3430
|
-
function createListeners() {
|
|
3431
|
-
return new Set();
|
|
3432
|
-
}
|
|
3433
|
-
function sortByDocumentPosition(a, b) {
|
|
3434
|
-
const position = a.compareDocumentPosition(b);
|
|
3435
|
-
if (position & Node.DOCUMENT_POSITION_FOLLOWING || position & Node.DOCUMENT_POSITION_CONTAINED_BY) {
|
|
3436
|
-
return -1;
|
|
3244
|
+
let returnFocus = parent.type === undefined || isContextMenu;
|
|
3245
|
+
if (triggerElement || parent.type === 'menubar' && lastOpenChangeReason !== clamp.outsidePress) {
|
|
3246
|
+
returnFocus = true;
|
|
3437
3247
|
}
|
|
3438
|
-
|
|
3439
|
-
|
|
3248
|
+
return /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.FloatingFocusManager, {
|
|
3249
|
+
context: floatingContext,
|
|
3250
|
+
modal: isContextMenu,
|
|
3251
|
+
disabled: !mounted,
|
|
3252
|
+
returnFocus: finalFocus === undefined ? returnFocus : finalFocus,
|
|
3253
|
+
initialFocus: parent.type !== 'menu',
|
|
3254
|
+
restoreFocus: true,
|
|
3255
|
+
externalTree: parent.type !== 'menubar' ? floatingTreeRoot : undefined,
|
|
3256
|
+
previousFocusableElement: activeTriggerElement,
|
|
3257
|
+
nextFocusableElement: parent.type === undefined ? store.context.triggerFocusTargetRef : undefined,
|
|
3258
|
+
beforeContentFocusGuardRef: parent.type === undefined ? store.context.beforeContentFocusGuardRef : undefined,
|
|
3259
|
+
children: element
|
|
3260
|
+
});
|
|
3261
|
+
});
|
|
3262
|
+
if (process.env.NODE_ENV !== "production") MenuPopup.displayName = "MenuPopup";
|
|
3263
|
+
|
|
3264
|
+
const MenuPortalContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
3265
|
+
if (process.env.NODE_ENV !== "production") MenuPortalContext.displayName = "MenuPortalContext";
|
|
3266
|
+
function useMenuPortalContext() {
|
|
3267
|
+
const value = React__namespace.useContext(MenuPortalContext);
|
|
3268
|
+
if (value === undefined) {
|
|
3269
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: <Menu.Portal> is missing.' : useRenderElement.formatErrorMessage(32));
|
|
3440
3270
|
}
|
|
3441
|
-
return
|
|
3271
|
+
return value;
|
|
3442
3272
|
}
|
|
3443
3273
|
|
|
3274
|
+
const MenuPortal = /*#__PURE__*/React__namespace.forwardRef(function MenuPortal(props, forwardedRef) {
|
|
3275
|
+
const {
|
|
3276
|
+
keepMounted = false,
|
|
3277
|
+
...portalProps
|
|
3278
|
+
} = props;
|
|
3279
|
+
const {
|
|
3280
|
+
store
|
|
3281
|
+
} = useMenuRootContext();
|
|
3282
|
+
const mounted = store.useState('mounted');
|
|
3283
|
+
const shouldRender = mounted || keepMounted;
|
|
3284
|
+
if (!shouldRender) {
|
|
3285
|
+
return null;
|
|
3286
|
+
}
|
|
3287
|
+
return /*#__PURE__*/jsxRuntime.jsx(MenuPortalContext.Provider, {
|
|
3288
|
+
value: keepMounted,
|
|
3289
|
+
children: /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.FloatingPortal, {
|
|
3290
|
+
ref: forwardedRef,
|
|
3291
|
+
...portalProps
|
|
3292
|
+
})
|
|
3293
|
+
});
|
|
3294
|
+
});
|
|
3295
|
+
if (process.env.NODE_ENV !== "production") MenuPortal.displayName = "MenuPortal";
|
|
3296
|
+
|
|
3444
3297
|
const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPositioner(componentProps, forwardedRef) {
|
|
3445
3298
|
const {
|
|
3446
3299
|
anchor: anchorProp,
|
|
@@ -3456,7 +3309,7 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
|
|
|
3456
3309
|
arrowPadding = 5,
|
|
3457
3310
|
sticky = false,
|
|
3458
3311
|
disableAnchorTracking = false,
|
|
3459
|
-
collisionAvoidance: collisionAvoidanceProp =
|
|
3312
|
+
collisionAvoidance: collisionAvoidanceProp = ScrollAreaViewport.DROPDOWN_COLLISION_AVOIDANCE,
|
|
3460
3313
|
...elementProps
|
|
3461
3314
|
} = componentProps;
|
|
3462
3315
|
const {
|
|
@@ -3480,7 +3333,7 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
|
|
|
3480
3333
|
const floatingParentNodeId = store.useState('floatingParentNodeId');
|
|
3481
3334
|
const domReference = floatingRootContext.useState('domReferenceElement');
|
|
3482
3335
|
const previousTriggerRef = React__namespace.useRef(null);
|
|
3483
|
-
const runOnceAnimationsFinish =
|
|
3336
|
+
const runOnceAnimationsFinish = clamp.useAnimationsFinished(positionerElement, false, false);
|
|
3484
3337
|
let anchor = anchorProp;
|
|
3485
3338
|
let sideOffset = sideOffsetProp;
|
|
3486
3339
|
let alignOffset = alignOffsetProp;
|
|
@@ -3499,7 +3352,7 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
|
|
|
3499
3352
|
if (parent.type === 'menu') {
|
|
3500
3353
|
computedSide = computedSide ?? 'inline-end';
|
|
3501
3354
|
computedAlign = computedAlign ?? 'start';
|
|
3502
|
-
collisionAvoidance = componentProps.collisionAvoidance ??
|
|
3355
|
+
collisionAvoidance = componentProps.collisionAvoidance ?? ScrollAreaViewport.POPUP_COLLISION_AVOIDANCE;
|
|
3503
3356
|
} else if (parent.type === 'menubar') {
|
|
3504
3357
|
computedSide = computedSide ?? 'bottom';
|
|
3505
3358
|
computedAlign = computedAlign ?? 'start';
|
|
@@ -3547,7 +3400,7 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
|
|
|
3547
3400
|
store.set('hoverEnabled', false);
|
|
3548
3401
|
}
|
|
3549
3402
|
if (details.nodeId !== floatingNodeId && details.parentNodeId === store.select('floatingParentNodeId')) {
|
|
3550
|
-
store.setOpen(false,
|
|
3403
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.siblingOpen));
|
|
3551
3404
|
}
|
|
3552
3405
|
}
|
|
3553
3406
|
}
|
|
@@ -3564,15 +3417,15 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
|
|
|
3564
3417
|
if (details.open || details.nodeId !== store.select('floatingParentNodeId')) {
|
|
3565
3418
|
return;
|
|
3566
3419
|
}
|
|
3567
|
-
const reason = details.reason ??
|
|
3568
|
-
store.setOpen(false,
|
|
3420
|
+
const reason = details.reason ?? clamp.siblingOpen;
|
|
3421
|
+
store.setOpen(false, clamp.createChangeEventDetails(reason));
|
|
3569
3422
|
}
|
|
3570
3423
|
floatingTreeRoot.events.on('menuopenchange', onParentClose);
|
|
3571
3424
|
return () => {
|
|
3572
3425
|
floatingTreeRoot.events.off('menuopenchange', onParentClose);
|
|
3573
3426
|
};
|
|
3574
3427
|
}, [floatingTreeRoot.events, store]);
|
|
3575
|
-
const closeTimeout =
|
|
3428
|
+
const closeTimeout = clamp.useTimeout();
|
|
3576
3429
|
|
|
3577
3430
|
// Clear pending close timeout when the menu closes.
|
|
3578
3431
|
React__namespace.useEffect(() => {
|
|
@@ -3594,11 +3447,11 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
|
|
|
3594
3447
|
if (delay > 0) {
|
|
3595
3448
|
if (!closeTimeout.isStarted()) {
|
|
3596
3449
|
closeTimeout.start(delay, () => {
|
|
3597
|
-
store.setOpen(false,
|
|
3450
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.siblingOpen));
|
|
3598
3451
|
});
|
|
3599
3452
|
}
|
|
3600
3453
|
} else {
|
|
3601
|
-
store.setOpen(false,
|
|
3454
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.siblingOpen));
|
|
3602
3455
|
}
|
|
3603
3456
|
} else {
|
|
3604
3457
|
// User re-hovered the submenu trigger, cancel pending close.
|
|
@@ -3621,7 +3474,7 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
|
|
|
3621
3474
|
}, [floatingTreeRoot.events, open, store, floatingNodeId, floatingParentNodeId]);
|
|
3622
3475
|
|
|
3623
3476
|
// Keep positioner transition behavior aligned with Popover when switching detached triggers.
|
|
3624
|
-
|
|
3477
|
+
clamp.useIsoLayoutEffect(() => {
|
|
3625
3478
|
const currentTrigger = domReference;
|
|
3626
3479
|
const previousTrigger = previousTriggerRef.current;
|
|
3627
3480
|
if (currentTrigger) {
|
|
@@ -3657,11 +3510,11 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
|
|
|
3657
3510
|
}), [positioner.side, positioner.align, positioner.arrowRef, positioner.arrowUncentered, positioner.arrowStyles, positioner.context.nodeId]);
|
|
3658
3511
|
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
3659
3512
|
state,
|
|
3660
|
-
stateAttributesMapping:
|
|
3513
|
+
stateAttributesMapping: ScrollAreaViewport.popupStateMapping,
|
|
3661
3514
|
ref: [forwardedRef, store.useStateSetter('positionerElement')],
|
|
3662
3515
|
props: [positionerProps, getDisabledMountTransitionStyles(transitionStatus), elementProps]
|
|
3663
3516
|
});
|
|
3664
|
-
const shouldRenderBackdrop = mounted && parent.type !== 'menu' && (parent.type !== 'menubar' && modal && lastOpenChangeReason !==
|
|
3517
|
+
const shouldRenderBackdrop = mounted && parent.type !== 'menu' && (parent.type !== 'menubar' && modal && lastOpenChangeReason !== clamp.triggerHover || parent.type === 'menubar' && parent.context.modal);
|
|
3665
3518
|
|
|
3666
3519
|
// cuts a hole in the backdrop to allow pointer interaction with the menubar or dropdown menu trigger element
|
|
3667
3520
|
let backdropCutout = null;
|
|
@@ -3672,11 +3525,11 @@ const MenuPositioner = /*#__PURE__*/React__namespace.forwardRef(function MenuPos
|
|
|
3672
3525
|
}
|
|
3673
3526
|
return /*#__PURE__*/jsxRuntime.jsxs(MenuPositionerContext.Provider, {
|
|
3674
3527
|
value: contextValue,
|
|
3675
|
-
children: [shouldRenderBackdrop && /*#__PURE__*/jsxRuntime.jsx(
|
|
3528
|
+
children: [shouldRenderBackdrop && /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.InternalBackdrop, {
|
|
3676
3529
|
ref: parent.type === 'context-menu' || parent.type === 'nested-context-menu' ? parent.context.internalBackdropRef : null,
|
|
3677
|
-
inert:
|
|
3530
|
+
inert: ScrollAreaViewport.inertValue(!open),
|
|
3678
3531
|
cutout: backdropCutout
|
|
3679
|
-
}), /*#__PURE__*/jsxRuntime.jsx(
|
|
3532
|
+
}), /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.FloatingNode, {
|
|
3680
3533
|
id: floatingNodeId,
|
|
3681
3534
|
children: /*#__PURE__*/jsxRuntime.jsx(CompositeList, {
|
|
3682
3535
|
elementsRef: store.context.itemDomElements,
|
|
@@ -3714,13 +3567,13 @@ const MenuRadioGroup = /*#__PURE__*/React__namespace.memo(/*#__PURE__*/React__na
|
|
|
3714
3567
|
disabled = false,
|
|
3715
3568
|
...elementProps
|
|
3716
3569
|
} = componentProps;
|
|
3717
|
-
const [value, setValueUnwrapped] =
|
|
3570
|
+
const [value, setValueUnwrapped] = clamp.useControlled({
|
|
3718
3571
|
controlled: valueProp,
|
|
3719
3572
|
default: defaultValue,
|
|
3720
3573
|
name: 'MenuRadioGroup'
|
|
3721
3574
|
});
|
|
3722
|
-
const onValueChange =
|
|
3723
|
-
const setValue =
|
|
3575
|
+
const onValueChange = clamp.useStableCallback(onValueChangeProp);
|
|
3576
|
+
const setValue = clamp.useStableCallback((newValue, eventDetails) => {
|
|
3724
3577
|
onValueChange?.(newValue, eventDetails);
|
|
3725
3578
|
if (eventDetails.isCanceled) {
|
|
3726
3579
|
return;
|
|
@@ -3777,7 +3630,7 @@ const MenuRadioItem = /*#__PURE__*/React__namespace.forwardRef(function MenuRadi
|
|
|
3777
3630
|
label
|
|
3778
3631
|
});
|
|
3779
3632
|
const menuPositionerContext = useMenuPositionerContext(true);
|
|
3780
|
-
const id =
|
|
3633
|
+
const id = clamp.useBaseUiId(idProp);
|
|
3781
3634
|
const {
|
|
3782
3635
|
store
|
|
3783
3636
|
} = useMenuRootContext();
|
|
@@ -3808,9 +3661,9 @@ const MenuRadioItem = /*#__PURE__*/React__namespace.forwardRef(function MenuRadi
|
|
|
3808
3661
|
highlighted,
|
|
3809
3662
|
checked
|
|
3810
3663
|
}), [disabled, highlighted, checked]);
|
|
3811
|
-
const handleClick =
|
|
3664
|
+
const handleClick = clamp.useStableCallback(event => {
|
|
3812
3665
|
const details = {
|
|
3813
|
-
...
|
|
3666
|
+
...clamp.createChangeEventDetails(clamp.itemPress, event.nativeEvent),
|
|
3814
3667
|
preventUnmountOnClose: () => {}
|
|
3815
3668
|
};
|
|
3816
3669
|
setSelectedValue(value, details);
|
|
@@ -3850,8 +3703,8 @@ const MenuRadioItemIndicator = /*#__PURE__*/React__namespace.forwardRef(function
|
|
|
3850
3703
|
const {
|
|
3851
3704
|
transitionStatus,
|
|
3852
3705
|
setMounted
|
|
3853
|
-
} =
|
|
3854
|
-
|
|
3706
|
+
} = clamp.useTransitionStatus(item.checked);
|
|
3707
|
+
clamp.useOpenChangeComplete({
|
|
3855
3708
|
open: item.checked,
|
|
3856
3709
|
ref: indicatorRef,
|
|
3857
3710
|
onComplete() {
|
|
@@ -3891,35 +3744,35 @@ function useMenubarContext(optional) {
|
|
|
3891
3744
|
}
|
|
3892
3745
|
|
|
3893
3746
|
const selectors = {
|
|
3894
|
-
...
|
|
3895
|
-
disabled:
|
|
3896
|
-
modal:
|
|
3897
|
-
allowMouseEnter:
|
|
3898
|
-
stickIfOpen:
|
|
3899
|
-
parent:
|
|
3900
|
-
rootId:
|
|
3747
|
+
...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 => {
|
|
3901
3754
|
if (state.parent.type === 'menu') {
|
|
3902
3755
|
return state.parent.store.select('rootId');
|
|
3903
3756
|
}
|
|
3904
3757
|
return state.parent.type !== undefined ? state.parent.context.rootId : state.rootId;
|
|
3905
3758
|
}),
|
|
3906
|
-
activeIndex:
|
|
3907
|
-
isActive:
|
|
3908
|
-
hoverEnabled:
|
|
3909
|
-
instantType:
|
|
3910
|
-
lastOpenChangeReason:
|
|
3911
|
-
floatingTreeRoot:
|
|
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 => {
|
|
3912
3765
|
if (state.parent.type === 'menu') {
|
|
3913
3766
|
return state.parent.store.select('floatingTreeRoot');
|
|
3914
3767
|
}
|
|
3915
3768
|
return state.floatingTreeRoot;
|
|
3916
3769
|
}),
|
|
3917
|
-
floatingNodeId:
|
|
3918
|
-
floatingParentNodeId:
|
|
3919
|
-
itemProps:
|
|
3920
|
-
closeDelay:
|
|
3921
|
-
hasViewport:
|
|
3922
|
-
keyboardEventRelay:
|
|
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 => {
|
|
3923
3776
|
if (state.keyboardEventRelay) {
|
|
3924
3777
|
return state.keyboardEventRelay;
|
|
3925
3778
|
}
|
|
@@ -3929,7 +3782,7 @@ const selectors = {
|
|
|
3929
3782
|
return undefined;
|
|
3930
3783
|
})
|
|
3931
3784
|
};
|
|
3932
|
-
class MenuStore extends
|
|
3785
|
+
class MenuStore extends ScrollAreaViewport.ReactStore {
|
|
3933
3786
|
constructor(initialState) {
|
|
3934
3787
|
super({
|
|
3935
3788
|
...createInitialState(),
|
|
@@ -3952,7 +3805,7 @@ class MenuStore extends DrawerRoot.ReactStore {
|
|
|
3952
3805
|
triggerFocusTargetRef: /*#__PURE__*/React__namespace.createRef(),
|
|
3953
3806
|
beforeContentFocusGuardRef: /*#__PURE__*/React__namespace.createRef(),
|
|
3954
3807
|
onOpenChangeComplete: undefined,
|
|
3955
|
-
triggerElements: new
|
|
3808
|
+
triggerElements: new ScrollAreaViewport.PopupTriggerMap()
|
|
3956
3809
|
}, selectors);
|
|
3957
3810
|
|
|
3958
3811
|
// Set up propagation of state from parent menu if applicable.
|
|
@@ -4000,7 +3853,7 @@ class MenuStore extends DrawerRoot.ReactStore {
|
|
|
4000
3853
|
}
|
|
4001
3854
|
function createInitialState() {
|
|
4002
3855
|
return {
|
|
4003
|
-
...
|
|
3856
|
+
...ScrollAreaViewport.createInitialPopupStoreState(),
|
|
4004
3857
|
disabled: false,
|
|
4005
3858
|
modal: true,
|
|
4006
3859
|
allowMouseEnter: false,
|
|
@@ -4013,7 +3866,7 @@ function createInitialState() {
|
|
|
4013
3866
|
hoverEnabled: true,
|
|
4014
3867
|
instantType: undefined,
|
|
4015
3868
|
openChangeReason: null,
|
|
4016
|
-
floatingTreeRoot: new
|
|
3869
|
+
floatingTreeRoot: new ScrollAreaViewport.FloatingTreeStore(),
|
|
4017
3870
|
floatingNodeId: undefined,
|
|
4018
3871
|
floatingParentNodeId: null,
|
|
4019
3872
|
itemProps: useRenderElement.EMPTY_OBJECT,
|
|
@@ -4029,7 +3882,7 @@ function useMenuSubmenuRootContext() {
|
|
|
4029
3882
|
return React__namespace.useContext(MenuSubmenuRootContext);
|
|
4030
3883
|
}
|
|
4031
3884
|
|
|
4032
|
-
const MenuRoot =
|
|
3885
|
+
const MenuRoot = ScrollAreaViewport.fastComponent(function MenuRoot(props) {
|
|
4033
3886
|
const {
|
|
4034
3887
|
children,
|
|
4035
3888
|
open: openProp,
|
|
@@ -4087,7 +3940,7 @@ const MenuRoot = DrawerRoot.fastComponent(function MenuRoot(props) {
|
|
|
4087
3940
|
});
|
|
4088
3941
|
|
|
4089
3942
|
// Support initially open state when uncontrolled
|
|
4090
|
-
|
|
3943
|
+
ScrollAreaViewport.useOnFirstRender(() => {
|
|
4091
3944
|
if (openProp === undefined && store.state.open === false && defaultOpen === true) {
|
|
4092
3945
|
store.update({
|
|
4093
3946
|
open: true,
|
|
@@ -4099,9 +3952,9 @@ const MenuRoot = DrawerRoot.fastComponent(function MenuRoot(props) {
|
|
|
4099
3952
|
store.useControlledProp('triggerIdProp', triggerIdProp);
|
|
4100
3953
|
store.useContextCallback('onOpenChangeComplete', onOpenChangeComplete);
|
|
4101
3954
|
const floatingTreeRoot = store.useState('floatingTreeRoot');
|
|
4102
|
-
const floatingNodeIdFromContext =
|
|
4103
|
-
const floatingParentNodeIdFromContext =
|
|
4104
|
-
|
|
3955
|
+
const floatingNodeIdFromContext = ScrollAreaViewport.useFloatingNodeId(floatingTreeRoot);
|
|
3956
|
+
const floatingParentNodeIdFromContext = ScrollAreaViewport.useFloatingParentNodeId();
|
|
3957
|
+
clamp.useIsoLayoutEffect(() => {
|
|
4105
3958
|
if (contextMenuContext && !parentMenuRootContext) {
|
|
4106
3959
|
// This is a context menu root.
|
|
4107
3960
|
// It doesn't support detached triggers yet, so we have to sync the parent context manually.
|
|
@@ -4142,23 +3995,23 @@ const MenuRoot = DrawerRoot.fastComponent(function MenuRoot(props) {
|
|
|
4142
3995
|
store.useSyncedValues({
|
|
4143
3996
|
disabled: disabledProp,
|
|
4144
3997
|
modal: parent.type === undefined ? modalProp : undefined,
|
|
4145
|
-
rootId:
|
|
3998
|
+
rootId: clamp.useId()
|
|
4146
3999
|
});
|
|
4147
4000
|
const {
|
|
4148
4001
|
openMethod,
|
|
4149
4002
|
triggerProps: interactionTypeProps
|
|
4150
|
-
} =
|
|
4151
|
-
|
|
4003
|
+
} = ScrollAreaViewport.useOpenInteractionType(open);
|
|
4004
|
+
ScrollAreaViewport.useImplicitActiveTrigger(store);
|
|
4152
4005
|
const {
|
|
4153
4006
|
forceUnmount
|
|
4154
|
-
} =
|
|
4007
|
+
} = ScrollAreaViewport.useOpenStateTransitions(open, store, () => {
|
|
4155
4008
|
store.update({
|
|
4156
4009
|
allowMouseEnter: false,
|
|
4157
4010
|
stickIfOpen: true
|
|
4158
4011
|
});
|
|
4159
4012
|
});
|
|
4160
4013
|
const allowOutsidePressDismissalRef = React__namespace.useRef(parent.type !== 'context-menu');
|
|
4161
|
-
const allowOutsidePressDismissalTimeout =
|
|
4014
|
+
const allowOutsidePressDismissalTimeout = clamp.useTimeout();
|
|
4162
4015
|
React__namespace.useEffect(() => {
|
|
4163
4016
|
if (!open) {
|
|
4164
4017
|
openEventRef.current = null;
|
|
@@ -4179,15 +4032,15 @@ const MenuRoot = DrawerRoot.fastComponent(function MenuRoot(props) {
|
|
|
4179
4032
|
allowOutsidePressDismissalRef.current = true;
|
|
4180
4033
|
});
|
|
4181
4034
|
}, [allowOutsidePressDismissalTimeout, open, parent.type]);
|
|
4182
|
-
|
|
4183
|
-
|
|
4035
|
+
ScrollAreaViewport.useScrollLock(open && modal && lastOpenChangeReason !== clamp.triggerHover && openMethod !== 'touch', positionerElement);
|
|
4036
|
+
clamp.useIsoLayoutEffect(() => {
|
|
4184
4037
|
if (!open && !hoverEnabled) {
|
|
4185
4038
|
store.set('hoverEnabled', true);
|
|
4186
4039
|
}
|
|
4187
4040
|
}, [open, hoverEnabled, store]);
|
|
4188
4041
|
const allowTouchToCloseRef = React__namespace.useRef(true);
|
|
4189
|
-
const allowTouchToCloseTimeout =
|
|
4190
|
-
const setOpen =
|
|
4042
|
+
const allowTouchToCloseTimeout = clamp.useTimeout();
|
|
4043
|
+
const setOpen = clamp.useStableCallback((nextOpen, eventDetails) => {
|
|
4191
4044
|
const reason = eventDetails.reason;
|
|
4192
4045
|
if (open === nextOpen && eventDetails.trigger === activeTriggerElement && lastOpenChangeReason === reason) {
|
|
4193
4046
|
return;
|
|
@@ -4233,7 +4086,7 @@ const MenuRoot = DrawerRoot.fastComponent(function MenuRoot(props) {
|
|
|
4233
4086
|
// Prevent the menu from closing on mobile devices that have a delayed click event.
|
|
4234
4087
|
// In some cases the menu, when tapped, will fire the focus event first and then the click event.
|
|
4235
4088
|
// Without this guard, the menu will close immediately after opening.
|
|
4236
|
-
if (nextOpen && reason ===
|
|
4089
|
+
if (nextOpen && reason === clamp.triggerFocus) {
|
|
4237
4090
|
allowTouchToCloseRef.current = false;
|
|
4238
4091
|
allowTouchToCloseTimeout.start(300, () => {
|
|
4239
4092
|
allowTouchToCloseRef.current = true;
|
|
@@ -4242,8 +4095,8 @@ const MenuRoot = DrawerRoot.fastComponent(function MenuRoot(props) {
|
|
|
4242
4095
|
allowTouchToCloseRef.current = true;
|
|
4243
4096
|
allowTouchToCloseTimeout.clear();
|
|
4244
4097
|
}
|
|
4245
|
-
const isKeyboardClick = (reason ===
|
|
4246
|
-
const isDismissClose = !nextOpen && (reason ===
|
|
4098
|
+
const isKeyboardClick = (reason === clamp.triggerPress || reason === clamp.itemPress) && nativeEvent.detail === 0 && nativeEvent?.isTrusted;
|
|
4099
|
+
const isDismissClose = !nextOpen && (reason === clamp.escapeKey || reason == null);
|
|
4247
4100
|
const updatedState = {
|
|
4248
4101
|
open: nextOpen,
|
|
4249
4102
|
openChangeReason: reason
|
|
@@ -4258,7 +4111,7 @@ const MenuRoot = DrawerRoot.fastComponent(function MenuRoot(props) {
|
|
|
4258
4111
|
updatedState.activeTriggerElement = eventDetails.trigger ?? null;
|
|
4259
4112
|
}
|
|
4260
4113
|
store.update(updatedState);
|
|
4261
|
-
if (parent.type === 'menubar' && (reason ===
|
|
4114
|
+
if (parent.type === 'menubar' && (reason === clamp.triggerFocus || reason === clamp.focusOut || reason === clamp.triggerHover || reason === clamp.listNavigation || reason === clamp.siblingOpen)) {
|
|
4262
4115
|
store.set('instantType', 'group');
|
|
4263
4116
|
} else if (isKeyboardClick || isDismissClose) {
|
|
4264
4117
|
store.set('instantType', isKeyboardClick ? 'click' : 'dismiss');
|
|
@@ -4267,14 +4120,14 @@ const MenuRoot = DrawerRoot.fastComponent(function MenuRoot(props) {
|
|
|
4267
4120
|
}
|
|
4268
4121
|
});
|
|
4269
4122
|
const createMenuEventDetails = React__namespace.useCallback(reason => {
|
|
4270
|
-
const details =
|
|
4123
|
+
const details = clamp.createChangeEventDetails(reason);
|
|
4271
4124
|
details.preventUnmountOnClose = () => {
|
|
4272
4125
|
store.set('preventUnmountingOnClose', true);
|
|
4273
4126
|
};
|
|
4274
4127
|
return details;
|
|
4275
4128
|
}, [store]);
|
|
4276
4129
|
const handleImperativeClose = React__namespace.useCallback(() => {
|
|
4277
|
-
store.setOpen(false, createMenuEventDetails(
|
|
4130
|
+
store.setOpen(false, createMenuEventDetails(clamp.imperativeAction));
|
|
4278
4131
|
}, [store, createMenuEventDetails]);
|
|
4279
4132
|
React__namespace.useImperativeHandle(actionsRef, () => ({
|
|
4280
4133
|
unmount: forceUnmount,
|
|
@@ -4288,7 +4141,7 @@ const MenuRoot = DrawerRoot.fastComponent(function MenuRoot(props) {
|
|
|
4288
4141
|
React__namespace.useImperativeHandle(ctx?.actionsRef, () => ({
|
|
4289
4142
|
setOpen
|
|
4290
4143
|
}), [setOpen]);
|
|
4291
|
-
const floatingRootContext =
|
|
4144
|
+
const floatingRootContext = ScrollAreaViewport.useSyncedFloatingRootContext({
|
|
4292
4145
|
popupStore: store,
|
|
4293
4146
|
onOpenChange: setOpen
|
|
4294
4147
|
});
|
|
@@ -4303,7 +4156,7 @@ const MenuRoot = DrawerRoot.fastComponent(function MenuRoot(props) {
|
|
|
4303
4156
|
floatingEvents?.off('setOpen', handleSetOpenEvent);
|
|
4304
4157
|
};
|
|
4305
4158
|
}, [floatingEvents, setOpen]);
|
|
4306
|
-
const dismiss =
|
|
4159
|
+
const dismiss = ScrollAreaViewport.useDismiss(floatingRootContext, {
|
|
4307
4160
|
enabled: !disabled,
|
|
4308
4161
|
bubbles: {
|
|
4309
4162
|
escapeKey: closeParentOnEsc && parent.type === 'menu'
|
|
@@ -4316,10 +4169,10 @@ const MenuRoot = DrawerRoot.fastComponent(function MenuRoot(props) {
|
|
|
4316
4169
|
},
|
|
4317
4170
|
externalTree: nested ? floatingTreeRoot : undefined
|
|
4318
4171
|
});
|
|
4319
|
-
const role =
|
|
4172
|
+
const role = ScrollAreaViewport.useRole(floatingRootContext, {
|
|
4320
4173
|
role: 'menu'
|
|
4321
4174
|
});
|
|
4322
|
-
const direction = useDirection();
|
|
4175
|
+
const direction = ScrollAreaViewport.useDirection();
|
|
4323
4176
|
const setActiveIndex = React__namespace.useCallback(index => {
|
|
4324
4177
|
if (store.select('activeIndex') === index) {
|
|
4325
4178
|
return;
|
|
@@ -4348,7 +4201,7 @@ const MenuRoot = DrawerRoot.fastComponent(function MenuRoot(props) {
|
|
|
4348
4201
|
listRef: store.context.itemLabels,
|
|
4349
4202
|
elementsRef: store.context.itemDomElements,
|
|
4350
4203
|
activeIndex,
|
|
4351
|
-
resetMs:
|
|
4204
|
+
resetMs: ScrollAreaViewport.TYPEAHEAD_RESET_MS,
|
|
4352
4205
|
onMatch: index => {
|
|
4353
4206
|
if (open && index !== activeIndex) {
|
|
4354
4207
|
store.set('activeIndex', index);
|
|
@@ -4361,7 +4214,7 @@ const MenuRoot = DrawerRoot.fastComponent(function MenuRoot(props) {
|
|
|
4361
4214
|
getFloatingProps,
|
|
4362
4215
|
getItemProps,
|
|
4363
4216
|
getTriggerProps
|
|
4364
|
-
} =
|
|
4217
|
+
} = ScrollAreaViewport.useInteractions([dismiss, role, listNavigation, typeahead]);
|
|
4365
4218
|
const activeTriggerProps = React__namespace.useMemo(() => {
|
|
4366
4219
|
const mergedProps = useRenderElement.mergeProps(getReferenceProps(), {
|
|
4367
4220
|
onMouseMove() {
|
|
@@ -4423,7 +4276,7 @@ const MenuRoot = DrawerRoot.fastComponent(function MenuRoot(props) {
|
|
|
4423
4276
|
});
|
|
4424
4277
|
if (parent.type === undefined || parent.type === 'context-menu') {
|
|
4425
4278
|
// set up a FloatingTree to provide the context to nested menus
|
|
4426
|
-
return /*#__PURE__*/jsxRuntime.jsx(
|
|
4279
|
+
return /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.FloatingTree, {
|
|
4427
4280
|
externalTree: floatingTreeRoot,
|
|
4428
4281
|
children: content
|
|
4429
4282
|
});
|
|
@@ -4451,47 +4304,12 @@ function MenuSubmenuRoot(props) {
|
|
|
4451
4304
|
});
|
|
4452
4305
|
}
|
|
4453
4306
|
|
|
4454
|
-
function getPseudoElementBounds(element) {
|
|
4455
|
-
const elementRect = element.getBoundingClientRect();
|
|
4456
|
-
|
|
4457
|
-
// Avoid "Not implemented: window.getComputedStyle(elt, pseudoElt)"
|
|
4458
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
4459
|
-
return elementRect;
|
|
4460
|
-
}
|
|
4461
|
-
const beforeStyles = window.getComputedStyle(element, '::before');
|
|
4462
|
-
const afterStyles = window.getComputedStyle(element, '::after');
|
|
4463
|
-
const hasPseudoElements = beforeStyles.content !== 'none' || afterStyles.content !== 'none';
|
|
4464
|
-
if (!hasPseudoElements) {
|
|
4465
|
-
return elementRect;
|
|
4466
|
-
}
|
|
4467
|
-
|
|
4468
|
-
// Get dimensions of pseudo-elements
|
|
4469
|
-
const beforeWidth = parseFloat(beforeStyles.width) || 0;
|
|
4470
|
-
const beforeHeight = parseFloat(beforeStyles.height) || 0;
|
|
4471
|
-
const afterWidth = parseFloat(afterStyles.width) || 0;
|
|
4472
|
-
const afterHeight = parseFloat(afterStyles.height) || 0;
|
|
4473
|
-
|
|
4474
|
-
// Calculate max dimensions including pseudo-elements
|
|
4475
|
-
const totalWidth = Math.max(elementRect.width, beforeWidth, afterWidth);
|
|
4476
|
-
const totalHeight = Math.max(elementRect.height, beforeHeight, afterHeight);
|
|
4477
|
-
|
|
4478
|
-
// Calculate the differences to extend the bounds
|
|
4479
|
-
const widthDiff = totalWidth - elementRect.width;
|
|
4480
|
-
const heightDiff = totalHeight - elementRect.height;
|
|
4481
|
-
return {
|
|
4482
|
-
left: elementRect.left - widthDiff / 2,
|
|
4483
|
-
right: elementRect.right + widthDiff / 2,
|
|
4484
|
-
top: elementRect.top - heightDiff / 2,
|
|
4485
|
-
bottom: elementRect.bottom + heightDiff / 2
|
|
4486
|
-
};
|
|
4487
|
-
}
|
|
4488
|
-
|
|
4489
4307
|
function useCompositeItem(params = {}) {
|
|
4490
4308
|
const {
|
|
4491
4309
|
highlightItemOnHover,
|
|
4492
4310
|
highlightedIndex,
|
|
4493
4311
|
onHighlightedIndexChange
|
|
4494
|
-
} =
|
|
4312
|
+
} = clamp.useCompositeRootContext();
|
|
4495
4313
|
const {
|
|
4496
4314
|
ref,
|
|
4497
4315
|
index
|
|
@@ -4581,7 +4399,7 @@ function useMixedToggleClickHandler(params) {
|
|
|
4581
4399
|
onMouseDown: event => {
|
|
4582
4400
|
if (mouseDownAction === 'open' && !open || mouseDownAction === 'close' && open) {
|
|
4583
4401
|
ignoreClickRef.current = true;
|
|
4584
|
-
|
|
4402
|
+
clamp.ownerDocument(event.currentTarget).addEventListener('click', () => {
|
|
4585
4403
|
ignoreClickRef.current = false;
|
|
4586
4404
|
}, {
|
|
4587
4405
|
once: true
|
|
@@ -4606,7 +4424,7 @@ const BOUNDARY_OFFSET = 2;
|
|
|
4606
4424
|
*
|
|
4607
4425
|
* Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
|
|
4608
4426
|
*/
|
|
4609
|
-
const MenuTrigger =
|
|
4427
|
+
const MenuTrigger = ScrollAreaViewport.fastComponentRef(function MenuTrigger(componentProps, forwardedRef) {
|
|
4610
4428
|
const {
|
|
4611
4429
|
render,
|
|
4612
4430
|
className,
|
|
@@ -4625,23 +4443,23 @@ const MenuTrigger = DrawerRoot.fastComponentRef(function MenuTrigger(componentPr
|
|
|
4625
4443
|
if (!store) {
|
|
4626
4444
|
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: <Menu.Trigger> must be either used within a <Menu.Root> component or provided with a handle.' : useRenderElement.formatErrorMessage(85));
|
|
4627
4445
|
}
|
|
4628
|
-
const thisTriggerId =
|
|
4446
|
+
const thisTriggerId = clamp.useBaseUiId(idProp);
|
|
4629
4447
|
const isTriggerActive = store.useState('isTriggerActive', thisTriggerId);
|
|
4630
4448
|
const floatingRootContext = store.useState('floatingRootContext');
|
|
4631
4449
|
const isOpenedByThisTrigger = store.useState('isOpenedByTrigger', thisTriggerId);
|
|
4632
4450
|
const triggerElementRef = React__namespace.useRef(null);
|
|
4633
4451
|
const parent = useMenuParent();
|
|
4634
|
-
const compositeRootContext =
|
|
4635
|
-
const floatingTreeRootFromContext =
|
|
4452
|
+
const compositeRootContext = clamp.useCompositeRootContext(true);
|
|
4453
|
+
const floatingTreeRootFromContext = ScrollAreaViewport.useFloatingTree();
|
|
4636
4454
|
const floatingTreeRoot = React__namespace.useMemo(() => {
|
|
4637
|
-
return floatingTreeRootFromContext ?? new
|
|
4455
|
+
return floatingTreeRootFromContext ?? new ScrollAreaViewport.FloatingTreeStore();
|
|
4638
4456
|
}, [floatingTreeRootFromContext]);
|
|
4639
|
-
const floatingNodeId =
|
|
4640
|
-
const floatingParentNodeId =
|
|
4457
|
+
const floatingNodeId = ScrollAreaViewport.useFloatingNodeId(floatingTreeRoot);
|
|
4458
|
+
const floatingParentNodeId = ScrollAreaViewport.useFloatingParentNodeId();
|
|
4641
4459
|
const {
|
|
4642
4460
|
registerTrigger,
|
|
4643
4461
|
isMountedByThisTrigger
|
|
4644
|
-
} =
|
|
4462
|
+
} = ScrollAreaViewport.useTriggerDataForwarding(thisTriggerId, triggerElementRef, store, {
|
|
4645
4463
|
payload,
|
|
4646
4464
|
closeDelay,
|
|
4647
4465
|
parent,
|
|
@@ -4656,7 +4474,7 @@ const MenuTrigger = DrawerRoot.fastComponentRef(function MenuTrigger(componentPr
|
|
|
4656
4474
|
const {
|
|
4657
4475
|
getButtonProps,
|
|
4658
4476
|
buttonRef
|
|
4659
|
-
} =
|
|
4477
|
+
} = clamp.useButton({
|
|
4660
4478
|
disabled,
|
|
4661
4479
|
native: nativeButton
|
|
4662
4480
|
});
|
|
@@ -4666,15 +4484,15 @@ const MenuTrigger = DrawerRoot.fastComponentRef(function MenuTrigger(componentPr
|
|
|
4666
4484
|
}
|
|
4667
4485
|
}, [store, isOpenedByThisTrigger, parent.type]);
|
|
4668
4486
|
const triggerRef = React__namespace.useRef(null);
|
|
4669
|
-
const allowMouseUpTriggerTimeout =
|
|
4670
|
-
const handleDocumentMouseUp =
|
|
4487
|
+
const allowMouseUpTriggerTimeout = clamp.useTimeout();
|
|
4488
|
+
const handleDocumentMouseUp = clamp.useStableCallback(mouseEvent => {
|
|
4671
4489
|
if (!triggerRef.current) {
|
|
4672
4490
|
return;
|
|
4673
4491
|
}
|
|
4674
4492
|
allowMouseUpTriggerTimeout.clear();
|
|
4675
4493
|
store.context.allowMouseUpTriggerRef.current = false;
|
|
4676
4494
|
const mouseUpTarget = mouseEvent.target;
|
|
4677
|
-
if (
|
|
4495
|
+
if (ScrollAreaViewport.contains(triggerRef.current, mouseUpTarget) || ScrollAreaViewport.contains(store.select('positionerElement'), mouseUpTarget) || mouseUpTarget === triggerRef.current) {
|
|
4678
4496
|
return;
|
|
4679
4497
|
}
|
|
4680
4498
|
if (mouseUpTarget != null && findRootOwnerId(mouseUpTarget) === store.select('rootId')) {
|
|
@@ -4686,12 +4504,12 @@ const MenuTrigger = DrawerRoot.fastComponentRef(function MenuTrigger(componentPr
|
|
|
4686
4504
|
}
|
|
4687
4505
|
floatingTreeRoot.events.emit('close', {
|
|
4688
4506
|
domEvent: mouseEvent,
|
|
4689
|
-
reason:
|
|
4507
|
+
reason: clamp.cancelOpen
|
|
4690
4508
|
});
|
|
4691
4509
|
});
|
|
4692
4510
|
React__namespace.useEffect(() => {
|
|
4693
|
-
if (isOpenedByThisTrigger && store.select('lastOpenChangeReason') ===
|
|
4694
|
-
const doc =
|
|
4511
|
+
if (isOpenedByThisTrigger && store.select('lastOpenChangeReason') === clamp.triggerHover) {
|
|
4512
|
+
const doc = clamp.ownerDocument(triggerRef.current);
|
|
4695
4513
|
doc.addEventListener('mouseup', handleDocumentMouseUp, {
|
|
4696
4514
|
once: true
|
|
4697
4515
|
});
|
|
@@ -4719,7 +4537,7 @@ const MenuTrigger = DrawerRoot.fastComponentRef(function MenuTrigger(componentPr
|
|
|
4719
4537
|
// `lastOpenChangeReason` doesn't need to be reactive here, as we need to run this
|
|
4720
4538
|
// only when `isOpenedByThisTrigger` changes.
|
|
4721
4539
|
const stickIfOpen = useStickIfOpen(isOpenedByThisTrigger, store.select('lastOpenChangeReason'));
|
|
4722
|
-
const click = useClick(floatingRootContext, {
|
|
4540
|
+
const click = ScrollAreaViewport.useClick(floatingRootContext, {
|
|
4723
4541
|
enabled: !disabled && parent.type !== 'context-menu',
|
|
4724
4542
|
event: isOpenedByThisTrigger && isInMenubar ? 'click' : 'mousedown',
|
|
4725
4543
|
toggle: true,
|
|
@@ -4734,7 +4552,7 @@ const MenuTrigger = DrawerRoot.fastComponentRef(function MenuTrigger(componentPr
|
|
|
4734
4552
|
enabled: isInMenubar,
|
|
4735
4553
|
mouseDownAction: 'open'
|
|
4736
4554
|
});
|
|
4737
|
-
const localInteractionProps =
|
|
4555
|
+
const localInteractionProps = ScrollAreaViewport.useInteractions([click, focus]);
|
|
4738
4556
|
const state = {
|
|
4739
4557
|
disabled,
|
|
4740
4558
|
open: isOpenedByThisTrigger
|
|
@@ -4753,7 +4571,7 @@ const MenuTrigger = DrawerRoot.fastComponentRef(function MenuTrigger(componentPr
|
|
|
4753
4571
|
allowMouseUpTriggerTimeout.start(200, () => {
|
|
4754
4572
|
store.context.allowMouseUpTriggerRef.current = true;
|
|
4755
4573
|
});
|
|
4756
|
-
const doc =
|
|
4574
|
+
const doc = clamp.ownerDocument(event.currentTarget);
|
|
4757
4575
|
doc.addEventListener('mouseup', handleDocumentMouseUp, {
|
|
4758
4576
|
once: true
|
|
4759
4577
|
});
|
|
@@ -4762,25 +4580,25 @@ const MenuTrigger = DrawerRoot.fastComponentRef(function MenuTrigger(componentPr
|
|
|
4762
4580
|
role: 'menuitem'
|
|
4763
4581
|
} : {}, mixedToggleHandlers, elementProps, getButtonProps];
|
|
4764
4582
|
const preFocusGuardRef = React__namespace.useRef(null);
|
|
4765
|
-
const handlePreFocusGuardFocus =
|
|
4583
|
+
const handlePreFocusGuardFocus = clamp.useStableCallback(event => {
|
|
4766
4584
|
ReactDOM__namespace.flushSync(() => {
|
|
4767
|
-
store.setOpen(false,
|
|
4585
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.focusOut, event.nativeEvent, event.currentTarget));
|
|
4768
4586
|
});
|
|
4769
|
-
const previousTabbable =
|
|
4587
|
+
const previousTabbable = ScrollAreaViewport.getTabbableBeforeElement(preFocusGuardRef.current);
|
|
4770
4588
|
previousTabbable?.focus();
|
|
4771
4589
|
});
|
|
4772
|
-
const handleFocusTargetFocus =
|
|
4590
|
+
const handleFocusTargetFocus = clamp.useStableCallback(event => {
|
|
4773
4591
|
const currentPositionerElement = store.select('positionerElement');
|
|
4774
|
-
if (currentPositionerElement &&
|
|
4592
|
+
if (currentPositionerElement && ScrollAreaViewport.isOutsideEvent(event, currentPositionerElement)) {
|
|
4775
4593
|
store.context.beforeContentFocusGuardRef.current?.focus();
|
|
4776
4594
|
} else {
|
|
4777
4595
|
ReactDOM__namespace.flushSync(() => {
|
|
4778
|
-
store.setOpen(false,
|
|
4596
|
+
store.setOpen(false, clamp.createChangeEventDetails(clamp.focusOut, event.nativeEvent, event.currentTarget));
|
|
4779
4597
|
});
|
|
4780
|
-
let nextTabbable =
|
|
4781
|
-
while (nextTabbable !== null &&
|
|
4598
|
+
let nextTabbable = ScrollAreaViewport.getTabbableAfterElement(store.context.triggerFocusTargetRef.current || triggerElementRef.current);
|
|
4599
|
+
while (nextTabbable !== null && ScrollAreaViewport.contains(currentPositionerElement, nextTabbable)) {
|
|
4782
4600
|
const prevTabbable = nextTabbable;
|
|
4783
|
-
nextTabbable =
|
|
4601
|
+
nextTabbable = ScrollAreaViewport.getNextTabbable(nextTabbable);
|
|
4784
4602
|
if (nextTabbable === prevTabbable) {
|
|
4785
4603
|
break;
|
|
4786
4604
|
}
|
|
@@ -4790,7 +4608,7 @@ const MenuTrigger = DrawerRoot.fastComponentRef(function MenuTrigger(componentPr
|
|
|
4790
4608
|
});
|
|
4791
4609
|
const element = useRenderElement.useRenderElement('button', componentProps, {
|
|
4792
4610
|
enabled: !isInMenubar,
|
|
4793
|
-
stateAttributesMapping:
|
|
4611
|
+
stateAttributesMapping: ScrollAreaViewport.pressableTriggerOpenStateMapping,
|
|
4794
4612
|
state,
|
|
4795
4613
|
ref,
|
|
4796
4614
|
props
|
|
@@ -4803,7 +4621,7 @@ const MenuTrigger = DrawerRoot.fastComponentRef(function MenuTrigger(componentPr
|
|
|
4803
4621
|
state: state,
|
|
4804
4622
|
refs: ref,
|
|
4805
4623
|
props: props,
|
|
4806
|
-
stateAttributesMapping:
|
|
4624
|
+
stateAttributesMapping: ScrollAreaViewport.pressableTriggerOpenStateMapping
|
|
4807
4625
|
});
|
|
4808
4626
|
}
|
|
4809
4627
|
|
|
@@ -4812,12 +4630,12 @@ const MenuTrigger = DrawerRoot.fastComponentRef(function MenuTrigger(componentPr
|
|
|
4812
4630
|
|
|
4813
4631
|
if (isOpenedByThisTrigger) {
|
|
4814
4632
|
return /*#__PURE__*/jsxRuntime.jsxs(React__namespace.Fragment, {
|
|
4815
|
-
children: [/*#__PURE__*/jsxRuntime.jsx(
|
|
4633
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.FocusGuard, {
|
|
4816
4634
|
ref: preFocusGuardRef,
|
|
4817
4635
|
onFocus: handlePreFocusGuardFocus
|
|
4818
4636
|
}, `${thisTriggerId}-pre-focus-guard`), /*#__PURE__*/jsxRuntime.jsx(React__namespace.Fragment, {
|
|
4819
4637
|
children: element
|
|
4820
|
-
}, thisTriggerId), /*#__PURE__*/jsxRuntime.jsx(
|
|
4638
|
+
}, thisTriggerId), /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.FocusGuard, {
|
|
4821
4639
|
ref: store.context.triggerFocusTargetRef,
|
|
4822
4640
|
onFocus: handleFocusTargetFocus
|
|
4823
4641
|
}, `${thisTriggerId}-post-focus-guard`)]
|
|
@@ -4832,14 +4650,14 @@ if (process.env.NODE_ENV !== "production") MenuTrigger.displayName = "MenuTrigge
|
|
|
4832
4650
|
* Determines whether to ignore clicks after a hover-open.
|
|
4833
4651
|
*/
|
|
4834
4652
|
function useStickIfOpen(open, openReason) {
|
|
4835
|
-
const stickIfOpenTimeout =
|
|
4653
|
+
const stickIfOpenTimeout = clamp.useTimeout();
|
|
4836
4654
|
const [stickIfOpen, setStickIfOpen] = React__namespace.useState(false);
|
|
4837
|
-
|
|
4655
|
+
clamp.useIsoLayoutEffect(() => {
|
|
4838
4656
|
if (open && openReason === 'trigger-hover') {
|
|
4839
4657
|
// Only allow "patient" clicks to close the menu if it's open.
|
|
4840
4658
|
// If they clicked within 500ms of the menu opening, keep it open.
|
|
4841
4659
|
setStickIfOpen(true);
|
|
4842
|
-
stickIfOpenTimeout.start(
|
|
4660
|
+
stickIfOpenTimeout.start(ScrollAreaViewport.PATIENT_CLICK_THRESHOLD, () => {
|
|
4843
4661
|
setStickIfOpen(false);
|
|
4844
4662
|
});
|
|
4845
4663
|
} else if (!open) {
|
|
@@ -4901,11 +4719,11 @@ const MenuSubmenuTrigger = /*#__PURE__*/React__namespace.forwardRef(function Sub
|
|
|
4901
4719
|
const {
|
|
4902
4720
|
store
|
|
4903
4721
|
} = useMenuRootContext();
|
|
4904
|
-
const thisTriggerId =
|
|
4722
|
+
const thisTriggerId = clamp.useBaseUiId(idProp);
|
|
4905
4723
|
const open = store.useState('open');
|
|
4906
4724
|
const floatingRootContext = store.useState('floatingRootContext');
|
|
4907
4725
|
const floatingTreeRoot = store.useState('floatingTreeRoot');
|
|
4908
|
-
const baseRegisterTrigger =
|
|
4726
|
+
const baseRegisterTrigger = ScrollAreaViewport.useTriggerRegistration(thisTriggerId, store);
|
|
4909
4727
|
const registerTrigger = React__namespace.useCallback(element => {
|
|
4910
4728
|
const cleanup = baseRegisterTrigger(element);
|
|
4911
4729
|
if (element !== null && store.select('open') && store.select('activeTriggerId') == null) {
|
|
@@ -4969,14 +4787,14 @@ const MenuSubmenuTrigger = /*#__PURE__*/React__namespace.forwardRef(function Sub
|
|
|
4969
4787
|
triggerElementRef,
|
|
4970
4788
|
externalTree: floatingTreeRoot
|
|
4971
4789
|
});
|
|
4972
|
-
const click = useClick(floatingRootContext, {
|
|
4790
|
+
const click = ScrollAreaViewport.useClick(floatingRootContext, {
|
|
4973
4791
|
enabled: !disabled,
|
|
4974
4792
|
event: 'mousedown',
|
|
4975
4793
|
toggle: !openOnHover,
|
|
4976
4794
|
ignoreMouse: openOnHover,
|
|
4977
4795
|
stickIfOpen: false
|
|
4978
4796
|
});
|
|
4979
|
-
const localInteractionProps =
|
|
4797
|
+
const localInteractionProps = ScrollAreaViewport.useInteractions([click]);
|
|
4980
4798
|
const rootTriggerProps = store.useState('triggerProps', true);
|
|
4981
4799
|
delete rootTriggerProps.id;
|
|
4982
4800
|
const state = {
|
|
@@ -4986,7 +4804,7 @@ const MenuSubmenuTrigger = /*#__PURE__*/React__namespace.forwardRef(function Sub
|
|
|
4986
4804
|
};
|
|
4987
4805
|
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
4988
4806
|
state,
|
|
4989
|
-
stateAttributesMapping:
|
|
4807
|
+
stateAttributesMapping: ScrollAreaViewport.triggerOpenStateMapping,
|
|
4990
4808
|
props: [localInteractionProps.getReferenceProps(), hoverProps, rootTriggerProps, itemProps, {
|
|
4991
4809
|
tabIndex: open || highlighted ? 0 : -1,
|
|
4992
4810
|
onBlur() {
|
|
@@ -5004,7 +4822,6 @@ if (process.env.NODE_ENV !== "production") MenuSubmenuTrigger.displayName = "Men
|
|
|
5004
4822
|
exports.CompositeList = CompositeList;
|
|
5005
4823
|
exports.DrawerClose = DrawerClose;
|
|
5006
4824
|
exports.DrawerTitle = DrawerTitle;
|
|
5007
|
-
exports.DrawerTrigger = DrawerTrigger;
|
|
5008
4825
|
exports.IndexGuessBehavior = IndexGuessBehavior;
|
|
5009
4826
|
exports.MenuGroup = MenuGroup;
|
|
5010
4827
|
exports.MenuGroupLabel = MenuGroupLabel;
|
|
@@ -5026,10 +4843,8 @@ exports.getDisabledMountTransitionStyles = getDisabledMountTransitionStyles;
|
|
|
5026
4843
|
exports.getPseudoElementBounds = getPseudoElementBounds;
|
|
5027
4844
|
exports.itemMapping = itemMapping;
|
|
5028
4845
|
exports.useAnchorPositioning = useAnchorPositioning;
|
|
5029
|
-
exports.useClick = useClick;
|
|
5030
4846
|
exports.useCompositeListItem = useCompositeListItem;
|
|
5031
4847
|
exports.useContextMenuRootContext = useContextMenuRootContext;
|
|
5032
|
-
exports.useDirection = useDirection;
|
|
5033
4848
|
exports.useFloatingRootContext = useFloatingRootContext;
|
|
5034
4849
|
exports.useListNavigation = useListNavigation;
|
|
5035
4850
|
exports.useMenuItem = useMenuItem;
|