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