@jobber/components 7.8.0 → 7.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Autocomplete/index.mjs +1 -1
- package/dist/Button/buttonRenderAdapter.d.ts +304 -0
- package/dist/Card/index.cjs +7 -4
- package/dist/Card/index.mjs +7 -4
- package/dist/Countdown/index.cjs +1 -1
- package/dist/Countdown/index.mjs +1 -1
- package/dist/Countdown-cjs.js +1 -1
- package/dist/Countdown-es.js +1 -1
- package/dist/DataDump/index.cjs +7 -4
- package/dist/DataDump/index.mjs +7 -4
- package/dist/DrawerRoot-cjs.js +2634 -2142
- package/dist/DrawerRoot-es.js +2523 -2065
- package/dist/InputAvatar/index.cjs +1 -1
- package/dist/InputAvatar/index.mjs +1 -1
- package/dist/InputFile/index.cjs +1 -1
- package/dist/InputFile/index.mjs +1 -1
- package/dist/InputFile-cjs.js +1 -1
- package/dist/InputFile-es.js +1 -1
- package/dist/InputNumber/index.cjs +2441 -186
- package/dist/InputNumber/index.mjs +2361 -106
- package/dist/Menu/Menu.Legacy.d.ts +3 -0
- package/dist/Menu/Menu.d.ts +66 -24
- package/dist/Menu/Menu.types.d.ts +8 -108
- package/dist/Menu/MenuBottomSheet.d.ts +29 -0
- package/dist/Menu/MenuDropdown.d.ts +29 -0
- package/dist/Menu/index.cjs +7 -4
- package/dist/Menu/index.mjs +7 -4
- package/dist/Menu/menuComposableShared.d.ts +27 -0
- package/dist/Menu/menuComposableTypes.d.ts +99 -0
- package/dist/Menu-cjs.js +828 -8419
- package/dist/Menu-es.js +823 -8414
- package/dist/MenuSubmenuTrigger-cjs.js +5283 -0
- package/dist/MenuSubmenuTrigger-es.js +5224 -0
- package/dist/Modal/index.mjs +1 -1
- package/dist/Page/index.cjs +6 -3
- package/dist/Page/index.mjs +6 -3
- package/dist/Page-cjs.js +1 -1
- package/dist/Page-es.js +1 -1
- package/dist/RecurringSelect/index.cjs +0 -1
- package/dist/RecurringSelect/index.mjs +0 -1
- package/dist/docs/Menu/Menu.md +7 -62
- package/dist/floating-ui.react-dom-es.js +1 -1
- package/dist/floating-ui.react-es.js +2 -2
- package/dist/index-cjs.js +1161 -166
- package/dist/index-es.js +1160 -166
- package/dist/index.cjs +7 -3
- package/dist/index.esm-es.js +1 -1
- package/dist/index.mjs +7 -3
- package/dist/primitives/BottomSheet/index.cjs +0 -1
- package/dist/primitives/BottomSheet/index.mjs +0 -1
- package/dist/primitives/index.cjs +0 -1
- package/dist/primitives/index.mjs +0 -1
- package/dist/styles.css +540 -31
- package/dist/unstyledPrimitives/index.cjs +6662 -8039
- package/dist/unstyledPrimitives/index.d.ts +2 -1
- package/dist/unstyledPrimitives/index.mjs +6733 -8111
- package/dist/useRenderElement-cjs.js +212 -212
- package/dist/useRenderElement-es.js +213 -213
- package/dist/utils/meta/meta.json +9 -0
- package/package.json +2 -2
- package/dist/Text-cjs2.js +0 -2484
- package/dist/Text-es2.js +0 -2417
- package/dist/index-cjs2.js +0 -1189
- package/dist/index-es2.js +0 -1186
package/dist/DrawerRoot-es.js
CHANGED
|
@@ -1,90 +1,22 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import React__default from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { f as formatErrorMessage, u as useRenderElement, b as useRefWithInit, E as EMPTY_OBJECT, c as useMergedRefs, i as isReactVersionAtLeast, N as NOOP } from './useRenderElement-es.js';
|
|
4
4
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
|
-
import { i as isShadowRoot, a as isHTMLElement,
|
|
5
|
+
import { i as isShadowRoot, b as isElement, a as isHTMLElement, k as getComputedStyle$1, f as floor, t as tabbable, g as getNodeName, c as isNode, I as getWindow, d as isTabbable, e as focusable, m as isWebKit$1, h as isLastTraversableNode, j as getParentNode, N as isOverflowElement } from './index.esm-es.js';
|
|
6
6
|
import * as ReactDOM from 'react-dom';
|
|
7
|
-
import { s as shimExports } from './index-es.js';
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// isControlled is ignored in the hook dependency lists as it should never change.
|
|
16
|
-
const {
|
|
17
|
-
current: isControlled
|
|
18
|
-
} = React.useRef(controlled !== undefined);
|
|
19
|
-
const [valueState, setValue] = React.useState(defaultProp);
|
|
20
|
-
const value = isControlled ? controlled : valueState;
|
|
21
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
22
|
-
React.useEffect(() => {
|
|
23
|
-
if (isControlled !== (controlled !== undefined)) {
|
|
24
|
-
console.error([`Base UI: A component is changing the ${isControlled ? '' : 'un'}controlled ${state} state of ${name} to be ${isControlled ? 'un' : ''}controlled.`, 'Elements should not switch from uncontrolled to controlled (or vice versa).', `Decide between using a controlled or uncontrolled ${name} ` + 'element for the lifetime of the component.', "The nature of the state is determined during the first render. It's considered controlled if the value is not `undefined`.", 'More info: https://fb.me/react-controlled-components'].join('\n'));
|
|
25
|
-
}
|
|
26
|
-
}, [state, name, controlled]);
|
|
27
|
-
const {
|
|
28
|
-
current: defaultValue
|
|
29
|
-
} = React.useRef(defaultProp);
|
|
30
|
-
React.useEffect(() => {
|
|
31
|
-
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is for more details.
|
|
32
|
-
if (!isControlled && JSON.stringify(defaultValue) !== JSON.stringify(defaultProp)) {
|
|
33
|
-
console.error([`Base UI: A component is changing the default ${state} state of an uncontrolled ${name} after being initialized. ` + `To suppress this warning opt to use a controlled ${name}.`].join('\n'));
|
|
34
|
-
}
|
|
35
|
-
}, [JSON.stringify(defaultProp)]);
|
|
36
|
-
}
|
|
37
|
-
const setValueIfUncontrolled = React.useCallback(newValue => {
|
|
38
|
-
if (!isControlled) {
|
|
39
|
-
setValue(newValue);
|
|
40
|
-
}
|
|
41
|
-
}, []);
|
|
42
|
-
return [value, setValueIfUncontrolled];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// https://github.com/mui/material-ui/issues/41190#issuecomment-2040873379
|
|
46
|
-
const useInsertionEffect = React[`useInsertionEffect${Math.random().toFixed(1)}`.slice(0, -3)];
|
|
47
|
-
const useSafeInsertionEffect =
|
|
48
|
-
// React 17 doesn't have useInsertionEffect.
|
|
49
|
-
useInsertionEffect &&
|
|
50
|
-
// Preact replaces useInsertionEffect with useLayoutEffect and fires too late.
|
|
51
|
-
useInsertionEffect !== React.useLayoutEffect ? useInsertionEffect : fn => fn();
|
|
52
|
-
/**
|
|
53
|
-
* Stabilizes the function passed so it's always the same between renders.
|
|
54
|
-
*
|
|
55
|
-
* The function becomes non-reactive to any values it captures.
|
|
56
|
-
* It can safely be passed as a dependency of `React.useMemo` and `React.useEffect` without re-triggering them if its captured values change.
|
|
57
|
-
*
|
|
58
|
-
* The function must only be called inside effects and event handlers, never during render (which throws an error).
|
|
59
|
-
*
|
|
60
|
-
* This hook is a more permissive version of React 19.2's `React.useEffectEvent` in that it can be passed through contexts and called in event handler props, not just effects.
|
|
61
|
-
*/
|
|
62
|
-
function useStableCallback(callback) {
|
|
63
|
-
const stable = useRefWithInit(createStableCallback).current;
|
|
64
|
-
stable.next = callback;
|
|
65
|
-
useSafeInsertionEffect(stable.effect);
|
|
66
|
-
return stable.trampoline;
|
|
67
|
-
}
|
|
68
|
-
function createStableCallback() {
|
|
69
|
-
const stable = {
|
|
70
|
-
next: undefined,
|
|
71
|
-
callback: assertNotCalled,
|
|
72
|
-
trampoline: (...args) => stable.callback?.(...args),
|
|
73
|
-
effect: () => {
|
|
74
|
-
stable.callback = stable.next;
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
return stable;
|
|
78
|
-
}
|
|
79
|
-
function assertNotCalled() {
|
|
80
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
81
|
-
throw /* minify-error-disabled */new Error('Base UI: Cannot call an event handler while rendering.');
|
|
8
|
+
const DialogRootContext = /*#__PURE__*/React.createContext(undefined);
|
|
9
|
+
if (process.env.NODE_ENV !== "production") DialogRootContext.displayName = "DialogRootContext";
|
|
10
|
+
function useDialogRootContext(optional) {
|
|
11
|
+
const dialogRootContext = React.useContext(DialogRootContext);
|
|
12
|
+
if (optional === false && dialogRootContext === undefined) {
|
|
13
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: DialogRootContext is missing. Dialog parts must be placed within <Dialog.Root>.' : formatErrorMessage(27));
|
|
82
14
|
}
|
|
15
|
+
return dialogRootContext;
|
|
83
16
|
}
|
|
84
17
|
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
|
|
18
|
+
const TYPEAHEAD_RESET_MS = 500;
|
|
19
|
+
const PATIENT_CLICK_THRESHOLD = 500;
|
|
88
20
|
const DISABLED_TRANSITIONS_STYLE = {
|
|
89
21
|
style: {
|
|
90
22
|
transition: 'none'
|
|
@@ -102,6 +34,14 @@ const DROPDOWN_COLLISION_AVOIDANCE = {
|
|
|
102
34
|
fallbackAxisSide: 'none'
|
|
103
35
|
};
|
|
104
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Used by regular popups that usually aren't scrollable and are allowed to
|
|
39
|
+
* freely flip to any axis of placement.
|
|
40
|
+
*/
|
|
41
|
+
const POPUP_COLLISION_AVOIDANCE = {
|
|
42
|
+
fallbackAxisSide: 'end'
|
|
43
|
+
};
|
|
44
|
+
|
|
105
45
|
/**
|
|
106
46
|
* Special visually hidden styles for the aria-owns owner element to ensure owned element
|
|
107
47
|
* accessibility in iOS/Safari/VoiceControl.
|
|
@@ -115,618 +55,691 @@ const ownerVisuallyHidden = {
|
|
|
115
55
|
left: 0
|
|
116
56
|
};
|
|
117
57
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
const inputPaste = 'input-paste';
|
|
132
|
-
const inputPress = 'input-press';
|
|
133
|
-
const focusOut = 'focus-out';
|
|
134
|
-
const escapeKey = 'escape-key';
|
|
135
|
-
const closeWatcher = 'close-watcher';
|
|
136
|
-
const listNavigation = 'list-navigation';
|
|
137
|
-
const keyboard = 'keyboard';
|
|
138
|
-
const scrub = 'scrub';
|
|
139
|
-
const imperativeAction = 'imperative-action';
|
|
140
|
-
const swipe = 'swipe';
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Maps a change `reason` string to the corresponding native event type.
|
|
144
|
-
*/
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Details of custom change events emitted by Base UI components.
|
|
148
|
-
*/
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Details of custom generic events emitted by Base UI components.
|
|
152
|
-
*/
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Creates a Base UI event details object with the given reason and utilities
|
|
156
|
-
* for preventing Base UI's internal event handling.
|
|
157
|
-
*/
|
|
158
|
-
function createChangeEventDetails(reason, event, trigger, customProperties) {
|
|
159
|
-
let canceled = false;
|
|
160
|
-
let allowPropagation = false;
|
|
161
|
-
const custom = customProperties ?? EMPTY_OBJECT;
|
|
162
|
-
const details = {
|
|
163
|
-
reason,
|
|
164
|
-
event: event ?? new Event('base-ui'),
|
|
165
|
-
cancel() {
|
|
166
|
-
canceled = true;
|
|
167
|
-
},
|
|
168
|
-
allowPropagation() {
|
|
169
|
-
allowPropagation = true;
|
|
170
|
-
},
|
|
171
|
-
get isCanceled() {
|
|
172
|
-
return canceled;
|
|
173
|
-
},
|
|
174
|
-
get isPropagationAllowed() {
|
|
175
|
-
return allowPropagation;
|
|
176
|
-
},
|
|
177
|
-
trigger,
|
|
178
|
-
...custom
|
|
179
|
-
};
|
|
180
|
-
return details;
|
|
181
|
-
}
|
|
182
|
-
function createGenericEventDetails(reason, event, customProperties) {
|
|
183
|
-
const custom = customProperties ?? EMPTY_OBJECT;
|
|
184
|
-
const details = {
|
|
185
|
-
reason,
|
|
186
|
-
event: event ?? new Event('base-ui'),
|
|
187
|
-
...custom
|
|
188
|
-
};
|
|
189
|
-
return details;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// https://github.com/mui/material-ui/issues/41190#issuecomment-2040873379
|
|
193
|
-
const SafeReact = {
|
|
194
|
-
...React
|
|
58
|
+
let TransitionStatusDataAttributes = /*#__PURE__*/function (TransitionStatusDataAttributes) {
|
|
59
|
+
/**
|
|
60
|
+
* Present when the component is animating in.
|
|
61
|
+
*/
|
|
62
|
+
TransitionStatusDataAttributes["startingStyle"] = "data-starting-style";
|
|
63
|
+
/**
|
|
64
|
+
* Present when the component is animating out.
|
|
65
|
+
*/
|
|
66
|
+
TransitionStatusDataAttributes["endingStyle"] = "data-ending-style";
|
|
67
|
+
return TransitionStatusDataAttributes;
|
|
68
|
+
}({});
|
|
69
|
+
const STARTING_HOOK = {
|
|
70
|
+
[TransitionStatusDataAttributes.startingStyle]: ''
|
|
195
71
|
};
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
React.useEffect(() => {
|
|
204
|
-
if (defaultId == null) {
|
|
205
|
-
// Fallback to this default id when possible.
|
|
206
|
-
// Use the incrementing value for client-side rendering only.
|
|
207
|
-
// We can't use it server-side.
|
|
208
|
-
// If you want to use random values please consider the Birthday Problem: https://en.wikipedia.org/wiki/Birthday_problem
|
|
209
|
-
globalId += 1;
|
|
210
|
-
setDefaultId(`${prefix}-${globalId}`);
|
|
72
|
+
const ENDING_HOOK = {
|
|
73
|
+
[TransitionStatusDataAttributes.endingStyle]: ''
|
|
74
|
+
};
|
|
75
|
+
const transitionStatusMapping = {
|
|
76
|
+
transitionStatus(value) {
|
|
77
|
+
if (value === 'starting') {
|
|
78
|
+
return STARTING_HOOK;
|
|
211
79
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
*
|
|
219
|
-
* @example <div id={useId()} />
|
|
220
|
-
* @param idOverride
|
|
221
|
-
* @returns {string}
|
|
222
|
-
*/
|
|
223
|
-
function useId(idOverride, prefix) {
|
|
224
|
-
// React.useId() is only available from React 17.0.0.
|
|
225
|
-
if (maybeReactUseId !== undefined) {
|
|
226
|
-
const reactId = maybeReactUseId();
|
|
227
|
-
return idOverride ?? (prefix ? `${prefix}-${reactId}` : reactId);
|
|
80
|
+
if (value === 'ending') {
|
|
81
|
+
return ENDING_HOOK;
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
228
84
|
}
|
|
85
|
+
};
|
|
229
86
|
|
|
230
|
-
|
|
231
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks -- `React.useId` is invariant at runtime.
|
|
232
|
-
return useGlobalId(idOverride, prefix);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const EMPTY$2 = [];
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* A React.useEffect equivalent that runs once, when the component is mounted.
|
|
239
|
-
*/
|
|
240
|
-
function useOnMount(fn) {
|
|
241
|
-
// TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler -- no need to put `fn` in the dependency array
|
|
242
|
-
/* eslint-disable react-hooks/exhaustive-deps */
|
|
243
|
-
React.useEffect(fn, EMPTY$2);
|
|
244
|
-
/* eslint-enable react-hooks/exhaustive-deps */
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/** Unlike `setTimeout`, rAF doesn't guarantee a positive integer return value, so we can't have
|
|
248
|
-
* a monomorphic `uint` type with `0` meaning empty.
|
|
249
|
-
* See warning note at:
|
|
250
|
-
* https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame#return_value */
|
|
251
|
-
const EMPTY$1 = null;
|
|
252
|
-
let LAST_RAF = globalThis.requestAnimationFrame;
|
|
253
|
-
class Scheduler {
|
|
254
|
-
/* This implementation uses an array as a backing data-structure for frame callbacks.
|
|
255
|
-
* It allows `O(1)` callback cancelling by inserting a `null` in the array, though it
|
|
256
|
-
* never calls the native `cancelAnimationFrame` if there are no frames left. This can
|
|
257
|
-
* be much more efficient if there is a call pattern that alterns as
|
|
258
|
-
* "request-cancel-request-cancel-…".
|
|
259
|
-
* But in the case of "request-request-…-cancel-cancel-…", it leaves the final animation
|
|
260
|
-
* frame to run anyway. We turn that frame into a `O(1)` no-op via `callbacksCount`. */
|
|
261
|
-
|
|
262
|
-
callbacks = [];
|
|
263
|
-
callbacksCount = 0;
|
|
264
|
-
nextId = 1;
|
|
265
|
-
startId = 1;
|
|
266
|
-
isScheduled = false;
|
|
267
|
-
tick = timestamp => {
|
|
268
|
-
this.isScheduled = false;
|
|
269
|
-
const currentCallbacks = this.callbacks;
|
|
270
|
-
const currentCallbacksCount = this.callbacksCount;
|
|
271
|
-
|
|
272
|
-
// Update these before iterating, callbacks could call `requestAnimationFrame` again.
|
|
273
|
-
this.callbacks = [];
|
|
274
|
-
this.callbacksCount = 0;
|
|
275
|
-
this.startId = this.nextId;
|
|
276
|
-
if (currentCallbacksCount > 0) {
|
|
277
|
-
for (let i = 0; i < currentCallbacks.length; i += 1) {
|
|
278
|
-
currentCallbacks[i]?.(timestamp);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
};
|
|
282
|
-
request(fn) {
|
|
283
|
-
const id = this.nextId;
|
|
284
|
-
this.nextId += 1;
|
|
285
|
-
this.callbacks.push(fn);
|
|
286
|
-
this.callbacksCount += 1;
|
|
287
|
-
|
|
288
|
-
/* In a test environment with fake timers, a fake `requestAnimationFrame` can be called
|
|
289
|
-
* but there's no guarantee that the animation frame will actually run before the fake
|
|
290
|
-
* timers are teared, which leaves `isScheduled` set, but won't run our `tick()`. */
|
|
291
|
-
const didRAFChange = process.env.NODE_ENV !== 'production' && LAST_RAF !== requestAnimationFrame && (LAST_RAF = requestAnimationFrame, true);
|
|
292
|
-
if (!this.isScheduled || didRAFChange) {
|
|
293
|
-
requestAnimationFrame(this.tick);
|
|
294
|
-
this.isScheduled = true;
|
|
295
|
-
}
|
|
296
|
-
return id;
|
|
297
|
-
}
|
|
298
|
-
cancel(id) {
|
|
299
|
-
const index = id - this.startId;
|
|
300
|
-
if (index < 0 || index >= this.callbacks.length) {
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
this.callbacks[index] = null;
|
|
304
|
-
this.callbacksCount -= 1;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
const scheduler = new Scheduler();
|
|
308
|
-
class AnimationFrame {
|
|
309
|
-
static create() {
|
|
310
|
-
return new AnimationFrame();
|
|
311
|
-
}
|
|
312
|
-
static request(fn) {
|
|
313
|
-
return scheduler.request(fn);
|
|
314
|
-
}
|
|
315
|
-
static cancel(id) {
|
|
316
|
-
return scheduler.cancel(id);
|
|
317
|
-
}
|
|
318
|
-
currentId = EMPTY$1;
|
|
319
|
-
|
|
87
|
+
let CommonPopupDataAttributes = function (CommonPopupDataAttributes) {
|
|
320
88
|
/**
|
|
321
|
-
*
|
|
89
|
+
* Present when the popup is open.
|
|
322
90
|
*/
|
|
323
|
-
|
|
324
|
-
this.cancel();
|
|
325
|
-
this.currentId = scheduler.request(() => {
|
|
326
|
-
this.currentId = EMPTY$1;
|
|
327
|
-
fn();
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
cancel = () => {
|
|
331
|
-
if (this.currentId !== EMPTY$1) {
|
|
332
|
-
scheduler.cancel(this.currentId);
|
|
333
|
-
this.currentId = EMPTY$1;
|
|
334
|
-
}
|
|
335
|
-
};
|
|
336
|
-
disposeEffect = () => {
|
|
337
|
-
return this.cancel;
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* A `requestAnimationFrame` with automatic cleanup and guard.
|
|
343
|
-
*/
|
|
344
|
-
function useAnimationFrame() {
|
|
345
|
-
const timeout = useRefWithInit(AnimationFrame.create).current;
|
|
346
|
-
useOnMount(timeout.disposeEffect);
|
|
347
|
-
return timeout;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* If the provided argument is a ref object, returns its `current` value.
|
|
352
|
-
* Otherwise, returns the argument itself.
|
|
353
|
-
*/
|
|
354
|
-
function resolveRef(maybeRef) {
|
|
355
|
-
if (maybeRef == null) {
|
|
356
|
-
return maybeRef;
|
|
357
|
-
}
|
|
358
|
-
return 'current' in maybeRef ? maybeRef.current : maybeRef;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
let TransitionStatusDataAttributes = /*#__PURE__*/function (TransitionStatusDataAttributes) {
|
|
91
|
+
CommonPopupDataAttributes["open"] = "data-open";
|
|
362
92
|
/**
|
|
363
|
-
* Present when the
|
|
93
|
+
* Present when the popup is closed.
|
|
364
94
|
*/
|
|
365
|
-
|
|
95
|
+
CommonPopupDataAttributes["closed"] = "data-closed";
|
|
366
96
|
/**
|
|
367
|
-
* Present when the
|
|
97
|
+
* Present when the popup is animating in.
|
|
368
98
|
*/
|
|
369
|
-
|
|
370
|
-
|
|
99
|
+
CommonPopupDataAttributes[CommonPopupDataAttributes["startingStyle"] = TransitionStatusDataAttributes.startingStyle] = "startingStyle";
|
|
100
|
+
/**
|
|
101
|
+
* Present when the popup is animating out.
|
|
102
|
+
*/
|
|
103
|
+
CommonPopupDataAttributes[CommonPopupDataAttributes["endingStyle"] = TransitionStatusDataAttributes.endingStyle] = "endingStyle";
|
|
104
|
+
/**
|
|
105
|
+
* Present when the anchor is hidden.
|
|
106
|
+
*/
|
|
107
|
+
CommonPopupDataAttributes["anchorHidden"] = "data-anchor-hidden";
|
|
108
|
+
/**
|
|
109
|
+
* Indicates which side the popup is positioned relative to the trigger.
|
|
110
|
+
* @type { 'top' | 'bottom' | 'left' | 'right' | 'inline-end' | 'inline-start'}
|
|
111
|
+
*/
|
|
112
|
+
CommonPopupDataAttributes["side"] = "data-side";
|
|
113
|
+
/**
|
|
114
|
+
* Indicates how the popup is aligned relative to specified side.
|
|
115
|
+
* @type {'start' | 'center' | 'end'}
|
|
116
|
+
*/
|
|
117
|
+
CommonPopupDataAttributes["align"] = "data-align";
|
|
118
|
+
return CommonPopupDataAttributes;
|
|
371
119
|
}({});
|
|
372
|
-
|
|
373
|
-
|
|
120
|
+
let CommonTriggerDataAttributes = /*#__PURE__*/function (CommonTriggerDataAttributes) {
|
|
121
|
+
/**
|
|
122
|
+
* Present when the popup is open.
|
|
123
|
+
*/
|
|
124
|
+
CommonTriggerDataAttributes["popupOpen"] = "data-popup-open";
|
|
125
|
+
/**
|
|
126
|
+
* Present when a pressable trigger is pressed.
|
|
127
|
+
*/
|
|
128
|
+
CommonTriggerDataAttributes["pressed"] = "data-pressed";
|
|
129
|
+
return CommonTriggerDataAttributes;
|
|
130
|
+
}({});
|
|
131
|
+
const TRIGGER_HOOK = {
|
|
132
|
+
[CommonTriggerDataAttributes.popupOpen]: ''
|
|
374
133
|
};
|
|
375
|
-
const
|
|
376
|
-
[
|
|
134
|
+
const PRESSABLE_TRIGGER_HOOK = {
|
|
135
|
+
[CommonTriggerDataAttributes.popupOpen]: '',
|
|
136
|
+
[CommonTriggerDataAttributes.pressed]: ''
|
|
377
137
|
};
|
|
378
|
-
const
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
138
|
+
const POPUP_OPEN_HOOK = {
|
|
139
|
+
[CommonPopupDataAttributes.open]: ''
|
|
140
|
+
};
|
|
141
|
+
const POPUP_CLOSED_HOOK = {
|
|
142
|
+
[CommonPopupDataAttributes.closed]: ''
|
|
143
|
+
};
|
|
144
|
+
const ANCHOR_HIDDEN_HOOK = {
|
|
145
|
+
[CommonPopupDataAttributes.anchorHidden]: ''
|
|
146
|
+
};
|
|
147
|
+
const triggerOpenStateMapping = {
|
|
148
|
+
open(value) {
|
|
149
|
+
if (value) {
|
|
150
|
+
return TRIGGER_HOOK;
|
|
382
151
|
}
|
|
383
|
-
|
|
384
|
-
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
const pressableTriggerOpenStateMapping = {
|
|
156
|
+
open(value) {
|
|
157
|
+
if (value) {
|
|
158
|
+
return PRESSABLE_TRIGGER_HOOK;
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
const popupStateMapping = {
|
|
164
|
+
open(value) {
|
|
165
|
+
if (value) {
|
|
166
|
+
return POPUP_OPEN_HOOK;
|
|
167
|
+
}
|
|
168
|
+
return POPUP_CLOSED_HOOK;
|
|
169
|
+
},
|
|
170
|
+
anchorHidden(value) {
|
|
171
|
+
if (value) {
|
|
172
|
+
return ANCHOR_HIDDEN_HOOK;
|
|
385
173
|
}
|
|
386
174
|
return null;
|
|
387
175
|
}
|
|
388
176
|
};
|
|
389
177
|
|
|
390
|
-
|
|
391
|
-
* Executes a function once all animations have finished on the provided element.
|
|
392
|
-
* @param elementOrRef - The element to watch for animations.
|
|
393
|
-
* @param waitForStartingStyleRemoved - Whether to wait for [data-starting-style] to be removed before checking for animations.
|
|
394
|
-
* @param treatAbortedAsFinished - Whether to treat aborted animations as finished. If `false`, and there are aborted animations,
|
|
395
|
-
* the function will check again if any new animations have started and wait for them to finish.
|
|
396
|
-
* @returns A function that takes a callback to execute once all animations have finished, and an optional AbortSignal to abort the callback
|
|
397
|
-
*/
|
|
398
|
-
function useAnimationsFinished(elementOrRef, waitForStartingStyleRemoved = false, treatAbortedAsFinished = true) {
|
|
399
|
-
const frame = useAnimationFrame();
|
|
400
|
-
return useStableCallback((fnToExecute,
|
|
178
|
+
let DrawerPopupCssVars = /*#__PURE__*/function (DrawerPopupCssVars) {
|
|
401
179
|
/**
|
|
402
|
-
*
|
|
403
|
-
*
|
|
404
|
-
* @default null
|
|
180
|
+
* The number of nested drawers that are currently open.
|
|
181
|
+
* @type {number}
|
|
405
182
|
*/
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
183
|
+
DrawerPopupCssVars["nestedDrawers"] = "--nested-drawers";
|
|
184
|
+
/**
|
|
185
|
+
* The height of the drawer popup.
|
|
186
|
+
* @type {CSS length}
|
|
187
|
+
*/
|
|
188
|
+
DrawerPopupCssVars["height"] = "--drawer-height";
|
|
189
|
+
/**
|
|
190
|
+
* The height of the frontmost open drawer in the current nested drawer stack.
|
|
191
|
+
* @type {CSS length}
|
|
192
|
+
*/
|
|
193
|
+
DrawerPopupCssVars["frontmostHeight"] = "--drawer-frontmost-height";
|
|
194
|
+
/**
|
|
195
|
+
* The swipe movement on the X axis.
|
|
196
|
+
* @type {CSS length}
|
|
197
|
+
*/
|
|
198
|
+
DrawerPopupCssVars["swipeMovementX"] = "--drawer-swipe-movement-x";
|
|
199
|
+
/**
|
|
200
|
+
* The swipe movement on the Y axis.
|
|
201
|
+
* @type {CSS length}
|
|
202
|
+
*/
|
|
203
|
+
DrawerPopupCssVars["swipeMovementY"] = "--drawer-swipe-movement-y";
|
|
204
|
+
/**
|
|
205
|
+
* The snap point offset used for translating the drawer.
|
|
206
|
+
* @type {CSS length}
|
|
207
|
+
*/
|
|
208
|
+
DrawerPopupCssVars["snapPointOffset"] = "--drawer-snap-point-offset";
|
|
209
|
+
/**
|
|
210
|
+
* A scalar (0.1-1) used to scale the swipe release transition duration in CSS.
|
|
211
|
+
* @type {number}
|
|
212
|
+
*/
|
|
213
|
+
DrawerPopupCssVars["swipeStrength"] = "--drawer-swipe-strength";
|
|
214
|
+
return DrawerPopupCssVars;
|
|
215
|
+
}({});
|
|
423
216
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
217
|
+
let DrawerBackdropCssVars = /*#__PURE__*/function (DrawerBackdropCssVars) {
|
|
218
|
+
/**
|
|
219
|
+
* The swipe progress of the drawer gesture.
|
|
220
|
+
* @type {number}
|
|
221
|
+
*/
|
|
222
|
+
DrawerBackdropCssVars["swipeProgress"] = "--drawer-swipe-progress";
|
|
223
|
+
return DrawerBackdropCssVars;
|
|
224
|
+
}({});
|
|
430
225
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
226
|
+
const stateAttributesMapping$1 = {
|
|
227
|
+
...popupStateMapping,
|
|
228
|
+
...transitionStatusMapping
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* An overlay displayed beneath the popup.
|
|
233
|
+
* Renders a `<div>` element.
|
|
234
|
+
*
|
|
235
|
+
* Documentation: [Base UI Drawer](https://base-ui.com/react/components/drawer)
|
|
236
|
+
*/
|
|
237
|
+
const DrawerBackdrop = /*#__PURE__*/React.forwardRef(function DrawerBackdrop(componentProps, forwardedRef) {
|
|
238
|
+
const {
|
|
239
|
+
render,
|
|
240
|
+
className,
|
|
241
|
+
forceRender = false,
|
|
242
|
+
...elementProps
|
|
243
|
+
} = componentProps;
|
|
244
|
+
const {
|
|
245
|
+
store
|
|
246
|
+
} = useDialogRootContext();
|
|
247
|
+
const open = store.useState('open');
|
|
248
|
+
const nested = store.useState('nested');
|
|
249
|
+
const mounted = store.useState('mounted');
|
|
250
|
+
const transitionStatus = store.useState('transitionStatus');
|
|
251
|
+
const state = {
|
|
252
|
+
open,
|
|
253
|
+
transitionStatus
|
|
254
|
+
};
|
|
255
|
+
return useRenderElement('div', componentProps, {
|
|
256
|
+
state,
|
|
257
|
+
ref: [store.context.backdropRef, forwardedRef],
|
|
258
|
+
stateAttributesMapping: stateAttributesMapping$1,
|
|
259
|
+
props: [{
|
|
260
|
+
role: 'presentation',
|
|
261
|
+
hidden: !mounted,
|
|
262
|
+
style: {
|
|
263
|
+
pointerEvents: !open ? 'none' : undefined,
|
|
264
|
+
userSelect: 'none',
|
|
265
|
+
WebkitUserSelect: 'none',
|
|
266
|
+
[DrawerBackdropCssVars.swipeProgress]: '0',
|
|
267
|
+
[DrawerPopupCssVars.swipeStrength]: '1'
|
|
469
268
|
}
|
|
470
|
-
|
|
471
|
-
|
|
269
|
+
}, elementProps],
|
|
270
|
+
enabled: forceRender || !nested
|
|
472
271
|
});
|
|
473
|
-
}
|
|
272
|
+
});
|
|
273
|
+
if (process.env.NODE_ENV !== "production") DrawerBackdrop.displayName = "DrawerBackdrop";
|
|
474
274
|
|
|
275
|
+
// https://github.com/mui/material-ui/issues/41190#issuecomment-2040873379
|
|
276
|
+
const useInsertionEffect = React[`useInsertionEffect${Math.random().toFixed(1)}`.slice(0, -3)];
|
|
277
|
+
const useSafeInsertionEffect =
|
|
278
|
+
// React 17 doesn't have useInsertionEffect.
|
|
279
|
+
useInsertionEffect &&
|
|
280
|
+
// Preact replaces useInsertionEffect with useLayoutEffect and fires too late.
|
|
281
|
+
useInsertionEffect !== React.useLayoutEffect ? useInsertionEffect : fn => fn();
|
|
475
282
|
/**
|
|
476
|
-
*
|
|
477
|
-
*
|
|
478
|
-
*
|
|
283
|
+
* Stabilizes the function passed so it's always the same between renders.
|
|
284
|
+
*
|
|
285
|
+
* The function becomes non-reactive to any values it captures.
|
|
286
|
+
* It can safely be passed as a dependency of `React.useMemo` and `React.useEffect` without re-triggering them if its captured values change.
|
|
287
|
+
*
|
|
288
|
+
* The function must only be called inside effects and event handlers, never during render (which throws an error).
|
|
289
|
+
*
|
|
290
|
+
* This hook is a more permissive version of React 19.2's `React.useEffectEvent` in that it can be passed through contexts and called in event handler props, not just effects.
|
|
479
291
|
*/
|
|
480
|
-
function
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
setTransitionStatus('starting');
|
|
486
|
-
}
|
|
487
|
-
if (!open && mounted && transitionStatus !== 'ending' && !deferEndingState) {
|
|
488
|
-
setTransitionStatus('ending');
|
|
489
|
-
}
|
|
490
|
-
if (!open && !mounted && transitionStatus === 'ending') {
|
|
491
|
-
setTransitionStatus(undefined);
|
|
492
|
-
}
|
|
493
|
-
useIsoLayoutEffect(() => {
|
|
494
|
-
if (!open && mounted && transitionStatus !== 'ending' && deferEndingState) {
|
|
495
|
-
const frame = AnimationFrame.request(() => {
|
|
496
|
-
setTransitionStatus('ending');
|
|
497
|
-
});
|
|
498
|
-
return () => {
|
|
499
|
-
AnimationFrame.cancel(frame);
|
|
500
|
-
};
|
|
501
|
-
}
|
|
502
|
-
return undefined;
|
|
503
|
-
}, [open, mounted, transitionStatus, deferEndingState]);
|
|
504
|
-
useIsoLayoutEffect(() => {
|
|
505
|
-
if (!open || enableIdleState) {
|
|
506
|
-
return undefined;
|
|
507
|
-
}
|
|
508
|
-
const frame = AnimationFrame.request(() => {
|
|
509
|
-
// Avoid `flushSync` here due to Firefox.
|
|
510
|
-
// See https://github.com/mui/base-ui/pull/3424
|
|
511
|
-
setTransitionStatus(undefined);
|
|
512
|
-
});
|
|
513
|
-
return () => {
|
|
514
|
-
AnimationFrame.cancel(frame);
|
|
515
|
-
};
|
|
516
|
-
}, [enableIdleState, open]);
|
|
517
|
-
useIsoLayoutEffect(() => {
|
|
518
|
-
if (!open || !enableIdleState) {
|
|
519
|
-
return undefined;
|
|
520
|
-
}
|
|
521
|
-
if (open && mounted && transitionStatus !== 'idle') {
|
|
522
|
-
setTransitionStatus('starting');
|
|
523
|
-
}
|
|
524
|
-
const frame = AnimationFrame.request(() => {
|
|
525
|
-
setTransitionStatus('idle');
|
|
526
|
-
});
|
|
527
|
-
return () => {
|
|
528
|
-
AnimationFrame.cancel(frame);
|
|
529
|
-
};
|
|
530
|
-
}, [enableIdleState, open, mounted, setTransitionStatus, transitionStatus]);
|
|
531
|
-
return React.useMemo(() => ({
|
|
532
|
-
mounted,
|
|
533
|
-
setMounted,
|
|
534
|
-
transitionStatus
|
|
535
|
-
}), [mounted, transitionStatus]);
|
|
292
|
+
function useStableCallback(callback) {
|
|
293
|
+
const stable = useRefWithInit(createStableCallback).current;
|
|
294
|
+
stable.next = callback;
|
|
295
|
+
useSafeInsertionEffect(stable.effect);
|
|
296
|
+
return stable.trampoline;
|
|
536
297
|
}
|
|
537
|
-
|
|
538
|
-
const
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
nav.platform === 'MacIntel' && nav.maxTouchPoints > 1 ? true : /iP(hone|ad|od)|iOS/.test(nav.platform);
|
|
546
|
-
const isFirefox = hasNavigator && /firefox/i.test(userAgent);
|
|
547
|
-
const isSafari = hasNavigator && /apple/i.test(navigator.vendor);
|
|
548
|
-
const isAndroid = hasNavigator && /android/i.test(platform) || /android/i.test(userAgent);
|
|
549
|
-
hasNavigator && platform.toLowerCase().startsWith('mac') && !navigator.maxTouchPoints;
|
|
550
|
-
const isJSDOM = userAgent.includes('jsdom/');
|
|
551
|
-
|
|
552
|
-
// Avoid Chrome DevTools blue warning.
|
|
553
|
-
function getNavigatorData() {
|
|
554
|
-
if (!hasNavigator) {
|
|
555
|
-
return {
|
|
556
|
-
platform: '',
|
|
557
|
-
maxTouchPoints: -1
|
|
558
|
-
};
|
|
559
|
-
}
|
|
560
|
-
const uaData = navigator.userAgentData;
|
|
561
|
-
if (uaData?.platform) {
|
|
562
|
-
return {
|
|
563
|
-
platform: uaData.platform,
|
|
564
|
-
maxTouchPoints: navigator.maxTouchPoints
|
|
565
|
-
};
|
|
566
|
-
}
|
|
567
|
-
return {
|
|
568
|
-
platform: navigator.platform ?? '',
|
|
569
|
-
maxTouchPoints: navigator.maxTouchPoints ?? -1
|
|
298
|
+
function createStableCallback() {
|
|
299
|
+
const stable = {
|
|
300
|
+
next: undefined,
|
|
301
|
+
callback: assertNotCalled,
|
|
302
|
+
trampoline: (...args) => stable.callback?.(...args),
|
|
303
|
+
effect: () => {
|
|
304
|
+
stable.callback = stable.next;
|
|
305
|
+
}
|
|
570
306
|
};
|
|
307
|
+
return stable;
|
|
571
308
|
}
|
|
572
|
-
function
|
|
573
|
-
if (
|
|
574
|
-
|
|
575
|
-
}
|
|
576
|
-
const uaData = navigator.userAgentData;
|
|
577
|
-
if (uaData && Array.isArray(uaData.brands)) {
|
|
578
|
-
return uaData.brands.map(({
|
|
579
|
-
brand,
|
|
580
|
-
version
|
|
581
|
-
}) => `${brand}/${version}`).join(' ');
|
|
582
|
-
}
|
|
583
|
-
return navigator.userAgent;
|
|
584
|
-
}
|
|
585
|
-
function getPlatform() {
|
|
586
|
-
if (!hasNavigator) {
|
|
587
|
-
return '';
|
|
588
|
-
}
|
|
589
|
-
const uaData = navigator.userAgentData;
|
|
590
|
-
if (uaData?.platform) {
|
|
591
|
-
return uaData.platform;
|
|
309
|
+
function assertNotCalled() {
|
|
310
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
311
|
+
throw /* minify-error-disabled */new Error('Base UI: Cannot call an event handler while rendering.');
|
|
592
312
|
}
|
|
593
|
-
return navigator.platform ?? '';
|
|
594
313
|
}
|
|
595
314
|
|
|
596
|
-
|
|
597
|
-
const
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
const ARROW_LEFT$1 = 'ArrowLeft';
|
|
601
|
-
const ARROW_RIGHT$1 = 'ArrowRight';
|
|
602
|
-
const ARROW_UP$1 = 'ArrowUp';
|
|
603
|
-
const ARROW_DOWN$1 = 'ArrowDown';
|
|
315
|
+
// https://github.com/mui/material-ui/issues/41190#issuecomment-2040873379
|
|
316
|
+
const SafeReact = {
|
|
317
|
+
...React
|
|
318
|
+
};
|
|
604
319
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
while (element?.shadowRoot?.activeElement != null) {
|
|
608
|
-
element = element.shadowRoot.activeElement;
|
|
609
|
-
}
|
|
610
|
-
return element;
|
|
611
|
-
}
|
|
612
|
-
function contains(parent, child) {
|
|
613
|
-
if (!parent || !child) {
|
|
614
|
-
return false;
|
|
615
|
-
}
|
|
616
|
-
const rootNode = child.getRootNode?.();
|
|
320
|
+
const noop = () => {};
|
|
321
|
+
const useIsoLayoutEffect = typeof document !== 'undefined' ? React.useLayoutEffect : noop;
|
|
617
322
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
323
|
+
const none = 'none';
|
|
324
|
+
const triggerPress = 'trigger-press';
|
|
325
|
+
const triggerHover = 'trigger-hover';
|
|
326
|
+
const triggerFocus = 'trigger-focus';
|
|
327
|
+
const outsidePress = 'outside-press';
|
|
328
|
+
const itemPress = 'item-press';
|
|
329
|
+
const closePress = 'close-press';
|
|
330
|
+
const clearPress = 'clear-press';
|
|
331
|
+
const chipRemovePress = 'chip-remove-press';
|
|
332
|
+
const incrementPress = 'increment-press';
|
|
333
|
+
const decrementPress = 'decrement-press';
|
|
334
|
+
const inputChange = 'input-change';
|
|
335
|
+
const inputClear = 'input-clear';
|
|
336
|
+
const inputBlur = 'input-blur';
|
|
337
|
+
const inputPaste = 'input-paste';
|
|
338
|
+
const inputPress = 'input-press';
|
|
339
|
+
const focusOut = 'focus-out';
|
|
340
|
+
const escapeKey = 'escape-key';
|
|
341
|
+
const closeWatcher = 'close-watcher';
|
|
342
|
+
const listNavigation = 'list-navigation';
|
|
343
|
+
const keyboard = 'keyboard';
|
|
344
|
+
const scrub = 'scrub';
|
|
345
|
+
const cancelOpen = 'cancel-open';
|
|
346
|
+
const siblingOpen = 'sibling-open';
|
|
347
|
+
const imperativeAction = 'imperative-action';
|
|
348
|
+
const swipe = 'swipe';
|
|
622
349
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
while (next) {
|
|
627
|
-
if (parent === next) {
|
|
628
|
-
return true;
|
|
629
|
-
}
|
|
630
|
-
next = next.parentNode || next.host;
|
|
631
|
-
}
|
|
632
|
-
}
|
|
350
|
+
/**
|
|
351
|
+
* Maps a change `reason` string to the corresponding native event type.
|
|
352
|
+
*/
|
|
633
353
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
function getTarget(event) {
|
|
638
|
-
if ('composedPath' in event) {
|
|
639
|
-
return event.composedPath()[0];
|
|
640
|
-
}
|
|
354
|
+
/**
|
|
355
|
+
* Details of custom change events emitted by Base UI components.
|
|
356
|
+
*/
|
|
641
357
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
}
|
|
646
|
-
function isEventTargetWithin(event, node) {
|
|
647
|
-
if (node == null) {
|
|
648
|
-
return false;
|
|
649
|
-
}
|
|
650
|
-
if ('composedPath' in event) {
|
|
651
|
-
return event.composedPath().includes(node);
|
|
652
|
-
}
|
|
358
|
+
/**
|
|
359
|
+
* Details of custom generic events emitted by Base UI components.
|
|
360
|
+
*/
|
|
653
361
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
function
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
362
|
+
/**
|
|
363
|
+
* Creates a Base UI event details object with the given reason and utilities
|
|
364
|
+
* for preventing Base UI's internal event handling.
|
|
365
|
+
*/
|
|
366
|
+
function createChangeEventDetails(reason, event, trigger, customProperties) {
|
|
367
|
+
let canceled = false;
|
|
368
|
+
let allowPropagation = false;
|
|
369
|
+
const custom = customProperties ?? EMPTY_OBJECT;
|
|
370
|
+
const details = {
|
|
371
|
+
reason,
|
|
372
|
+
event: event ?? new Event('base-ui'),
|
|
373
|
+
cancel() {
|
|
374
|
+
canceled = true;
|
|
375
|
+
},
|
|
376
|
+
allowPropagation() {
|
|
377
|
+
allowPropagation = true;
|
|
378
|
+
},
|
|
379
|
+
get isCanceled() {
|
|
380
|
+
return canceled;
|
|
381
|
+
},
|
|
382
|
+
get isPropagationAllowed() {
|
|
383
|
+
return allowPropagation;
|
|
384
|
+
},
|
|
385
|
+
trigger,
|
|
386
|
+
...custom
|
|
387
|
+
};
|
|
388
|
+
return details;
|
|
669
389
|
}
|
|
670
|
-
function
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
return floatingElement.hasAttribute(FOCUSABLE_ATTRIBUTE) ? floatingElement : floatingElement.querySelector(`[${FOCUSABLE_ATTRIBUTE}]`) || floatingElement;
|
|
390
|
+
function createGenericEventDetails(reason, event, customProperties) {
|
|
391
|
+
const custom = customProperties ?? EMPTY_OBJECT;
|
|
392
|
+
const details = {
|
|
393
|
+
reason,
|
|
394
|
+
event: event ?? new Event('base-ui'),
|
|
395
|
+
...custom
|
|
396
|
+
};
|
|
397
|
+
return details;
|
|
679
398
|
}
|
|
680
399
|
|
|
681
|
-
|
|
400
|
+
const DRAWER_CONTENT_ATTRIBUTE = 'data-drawer-content';
|
|
682
401
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
402
|
+
/**
|
|
403
|
+
* A container for the drawer contents.
|
|
404
|
+
* Renders a `<div>` element.
|
|
405
|
+
*
|
|
406
|
+
* Documentation: [Base UI Drawer](https://base-ui.com/react/components/drawer)
|
|
407
|
+
*/
|
|
408
|
+
const DrawerContent = /*#__PURE__*/React.forwardRef(function DrawerContent(componentProps, forwardedRef) {
|
|
409
|
+
const {
|
|
410
|
+
render,
|
|
411
|
+
className,
|
|
412
|
+
...elementProps
|
|
413
|
+
} = componentProps;
|
|
414
|
+
useDialogRootContext();
|
|
415
|
+
return useRenderElement('div', componentProps, {
|
|
416
|
+
ref: forwardedRef,
|
|
417
|
+
props: [{
|
|
418
|
+
[DRAWER_CONTENT_ATTRIBUTE]: ''
|
|
419
|
+
}, elementProps]
|
|
420
|
+
});
|
|
421
|
+
});
|
|
422
|
+
if (process.env.NODE_ENV !== "production") DrawerContent.displayName = "DrawerContent";
|
|
423
|
+
|
|
424
|
+
let globalId = 0;
|
|
425
|
+
|
|
426
|
+
// TODO React 17: Remove `useGlobalId` once React 17 support is removed
|
|
427
|
+
function useGlobalId(idOverride, prefix = 'mui') {
|
|
428
|
+
const [defaultId, setDefaultId] = React.useState(idOverride);
|
|
429
|
+
const id = idOverride || defaultId;
|
|
430
|
+
React.useEffect(() => {
|
|
431
|
+
if (defaultId == null) {
|
|
432
|
+
// Fallback to this default id when possible.
|
|
433
|
+
// Use the incrementing value for client-side rendering only.
|
|
434
|
+
// We can't use it server-side.
|
|
435
|
+
// If you want to use random values please consider the Birthday Problem: https://en.wikipedia.org/wiki/Birthday_problem
|
|
436
|
+
globalId += 1;
|
|
437
|
+
setDefaultId(`${prefix}-${globalId}`);
|
|
695
438
|
}
|
|
439
|
+
}, [defaultId, prefix]);
|
|
440
|
+
return id;
|
|
441
|
+
}
|
|
442
|
+
const maybeReactUseId = SafeReact.useId;
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
*
|
|
446
|
+
* @example <div id={useId()} />
|
|
447
|
+
* @param idOverride
|
|
448
|
+
* @returns {string}
|
|
449
|
+
*/
|
|
450
|
+
function useId(idOverride, prefix) {
|
|
451
|
+
// React.useId() is only available from React 17.0.0.
|
|
452
|
+
if (maybeReactUseId !== undefined) {
|
|
453
|
+
const reactId = maybeReactUseId();
|
|
454
|
+
return idOverride ?? (prefix ? `${prefix}-${reactId}` : reactId);
|
|
696
455
|
}
|
|
697
|
-
|
|
456
|
+
|
|
457
|
+
// TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler
|
|
458
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks -- `React.useId` is invariant at runtime.
|
|
459
|
+
return useGlobalId(idOverride, prefix);
|
|
698
460
|
}
|
|
699
461
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
462
|
+
const DrawerProviderContext = /*#__PURE__*/React.createContext(undefined);
|
|
463
|
+
if (process.env.NODE_ENV !== "production") DrawerProviderContext.displayName = "DrawerProviderContext";
|
|
464
|
+
function useDrawerProviderContext(optional) {
|
|
465
|
+
const context = React.useContext(DrawerProviderContext);
|
|
466
|
+
return context;
|
|
703
467
|
}
|
|
704
|
-
|
|
705
|
-
|
|
468
|
+
|
|
469
|
+
const EMPTY$2 = [];
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* A React.useEffect equivalent that runs once, when the component is mounted.
|
|
473
|
+
*/
|
|
474
|
+
function useOnMount(fn) {
|
|
475
|
+
// TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler -- no need to put `fn` in the dependency array
|
|
476
|
+
/* eslint-disable react-hooks/exhaustive-deps */
|
|
477
|
+
React.useEffect(fn, EMPTY$2);
|
|
478
|
+
/* eslint-enable react-hooks/exhaustive-deps */
|
|
706
479
|
}
|
|
707
480
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
return
|
|
481
|
+
const EMPTY$1 = 0;
|
|
482
|
+
class Timeout {
|
|
483
|
+
static create() {
|
|
484
|
+
return new Timeout();
|
|
712
485
|
}
|
|
713
|
-
|
|
714
|
-
|
|
486
|
+
currentId = EMPTY$1;
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Executes `fn` after `delay`, clearing any previously scheduled call.
|
|
490
|
+
*/
|
|
491
|
+
start(delay, fn) {
|
|
492
|
+
this.clear();
|
|
493
|
+
this.currentId = setTimeout(() => {
|
|
494
|
+
this.currentId = EMPTY$1;
|
|
495
|
+
fn();
|
|
496
|
+
}, delay); /* Node.js types are enabled in development */
|
|
715
497
|
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
function isVirtualPointerEvent(event) {
|
|
719
|
-
if (isJSDOM) {
|
|
720
|
-
return false;
|
|
498
|
+
isStarted() {
|
|
499
|
+
return this.currentId !== EMPTY$1;
|
|
721
500
|
}
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
501
|
+
clear = () => {
|
|
502
|
+
if (this.currentId !== EMPTY$1) {
|
|
503
|
+
clearTimeout(this.currentId);
|
|
504
|
+
this.currentId = EMPTY$1;
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
disposeEffect = () => {
|
|
508
|
+
return this.clear;
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* A `setTimeout` with automatic cleanup and guard.
|
|
514
|
+
*/
|
|
515
|
+
function useTimeout() {
|
|
516
|
+
const timeout = useRefWithInit(Timeout.create).current;
|
|
517
|
+
useOnMount(timeout.disposeEffect);
|
|
518
|
+
return timeout;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const hasNavigator = typeof navigator !== 'undefined';
|
|
522
|
+
const nav = getNavigatorData();
|
|
523
|
+
const platform = getPlatform();
|
|
524
|
+
const userAgent = getUserAgent();
|
|
525
|
+
const isWebKit = typeof CSS === 'undefined' || !CSS.supports ? false : CSS.supports('-webkit-backdrop-filter:none');
|
|
526
|
+
const isIOS =
|
|
527
|
+
// iPads can claim to be MacIntel
|
|
528
|
+
nav.platform === 'MacIntel' && nav.maxTouchPoints > 1 ? true : /iP(hone|ad|od)|iOS/.test(nav.platform);
|
|
529
|
+
const isFirefox = hasNavigator && /firefox/i.test(userAgent);
|
|
530
|
+
const isSafari = hasNavigator && /apple/i.test(navigator.vendor);
|
|
531
|
+
const isAndroid = hasNavigator && /android/i.test(platform) || /android/i.test(userAgent);
|
|
532
|
+
const isMac = hasNavigator && platform.toLowerCase().startsWith('mac') && !navigator.maxTouchPoints;
|
|
533
|
+
const isJSDOM = userAgent.includes('jsdom/');
|
|
534
|
+
|
|
535
|
+
// Avoid Chrome DevTools blue warning.
|
|
536
|
+
function getNavigatorData() {
|
|
537
|
+
if (!hasNavigator) {
|
|
538
|
+
return {
|
|
539
|
+
platform: '',
|
|
540
|
+
maxTouchPoints: -1
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
const uaData = navigator.userAgentData;
|
|
544
|
+
if (uaData?.platform) {
|
|
545
|
+
return {
|
|
546
|
+
platform: uaData.platform,
|
|
547
|
+
maxTouchPoints: navigator.maxTouchPoints
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
return {
|
|
551
|
+
platform: navigator.platform ?? '',
|
|
552
|
+
maxTouchPoints: navigator.maxTouchPoints ?? -1
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
function getUserAgent() {
|
|
556
|
+
if (!hasNavigator) {
|
|
557
|
+
return '';
|
|
558
|
+
}
|
|
559
|
+
const uaData = navigator.userAgentData;
|
|
560
|
+
if (uaData && Array.isArray(uaData.brands)) {
|
|
561
|
+
return uaData.brands.map(({
|
|
562
|
+
brand,
|
|
563
|
+
version
|
|
564
|
+
}) => `${brand}/${version}`).join(' ');
|
|
565
|
+
}
|
|
566
|
+
return navigator.userAgent;
|
|
567
|
+
}
|
|
568
|
+
function getPlatform() {
|
|
569
|
+
if (!hasNavigator) {
|
|
570
|
+
return '';
|
|
571
|
+
}
|
|
572
|
+
const uaData = navigator.userAgentData;
|
|
573
|
+
if (uaData?.platform) {
|
|
574
|
+
return uaData.platform;
|
|
575
|
+
}
|
|
576
|
+
return navigator.platform ?? '';
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
const FOCUSABLE_ATTRIBUTE = 'data-base-ui-focusable';
|
|
580
|
+
const ACTIVE_KEY = 'active';
|
|
581
|
+
const SELECTED_KEY = 'selected';
|
|
582
|
+
const TYPEABLE_SELECTOR = "input:not([type='hidden']):not([disabled])," + "[contenteditable]:not([contenteditable='false']),textarea:not([disabled])";
|
|
583
|
+
const ARROW_LEFT$1 = 'ArrowLeft';
|
|
584
|
+
const ARROW_RIGHT$1 = 'ArrowRight';
|
|
585
|
+
const ARROW_UP$1 = 'ArrowUp';
|
|
586
|
+
const ARROW_DOWN$1 = 'ArrowDown';
|
|
587
|
+
|
|
588
|
+
function activeElement(doc) {
|
|
589
|
+
let element = doc.activeElement;
|
|
590
|
+
while (element?.shadowRoot?.activeElement != null) {
|
|
591
|
+
element = element.shadowRoot.activeElement;
|
|
592
|
+
}
|
|
593
|
+
return element;
|
|
594
|
+
}
|
|
595
|
+
function contains(parent, child) {
|
|
596
|
+
if (!parent || !child) {
|
|
597
|
+
return false;
|
|
598
|
+
}
|
|
599
|
+
const rootNode = child.getRootNode?.();
|
|
600
|
+
|
|
601
|
+
// First, attempt with faster native method
|
|
602
|
+
if (parent.contains(child)) {
|
|
603
|
+
return true;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// then fallback to custom implementation with Shadow DOM support
|
|
607
|
+
if (rootNode && isShadowRoot(rootNode)) {
|
|
608
|
+
let next = child;
|
|
609
|
+
while (next) {
|
|
610
|
+
if (parent === next) {
|
|
611
|
+
return true;
|
|
612
|
+
}
|
|
613
|
+
next = next.parentNode || next.host;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// Give up, the result is false
|
|
618
|
+
return false;
|
|
619
|
+
}
|
|
620
|
+
function isTargetInsideEnabledTrigger(target, triggerElements) {
|
|
621
|
+
if (!isElement(target)) {
|
|
622
|
+
return false;
|
|
623
|
+
}
|
|
624
|
+
const targetElement = target;
|
|
625
|
+
if (triggerElements.hasElement(targetElement)) {
|
|
626
|
+
return !targetElement.hasAttribute('data-trigger-disabled');
|
|
627
|
+
}
|
|
628
|
+
for (const [, trigger] of triggerElements.entries()) {
|
|
629
|
+
if (contains(trigger, targetElement)) {
|
|
630
|
+
return !trigger.hasAttribute('data-trigger-disabled');
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
return false;
|
|
634
|
+
}
|
|
635
|
+
function getTarget(event) {
|
|
636
|
+
if ('composedPath' in event) {
|
|
637
|
+
return event.composedPath()[0];
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// TS thinks `event` is of type never as it assumes all browsers support
|
|
641
|
+
// `composedPath()`, but browsers without shadow DOM don't.
|
|
642
|
+
return event.target;
|
|
643
|
+
}
|
|
644
|
+
function isEventTargetWithin(event, node) {
|
|
645
|
+
if (node == null) {
|
|
646
|
+
return false;
|
|
647
|
+
}
|
|
648
|
+
if ('composedPath' in event) {
|
|
649
|
+
return event.composedPath().includes(node);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// TS thinks `event` is of type never as it assumes all browsers support composedPath, but browsers without shadow dom don't
|
|
653
|
+
const eventAgain = event;
|
|
654
|
+
return eventAgain.target != null && node.contains(eventAgain.target);
|
|
655
|
+
}
|
|
656
|
+
function isRootElement(element) {
|
|
657
|
+
return element.matches('html,body');
|
|
658
|
+
}
|
|
659
|
+
function isTypeableElement(element) {
|
|
660
|
+
return isHTMLElement(element) && element.matches(TYPEABLE_SELECTOR);
|
|
661
|
+
}
|
|
662
|
+
function isTypeableCombobox(element) {
|
|
663
|
+
if (!element) {
|
|
664
|
+
return false;
|
|
665
|
+
}
|
|
666
|
+
return element.getAttribute('role') === 'combobox' && isTypeableElement(element);
|
|
667
|
+
}
|
|
668
|
+
function matchesFocusVisible(element) {
|
|
669
|
+
// We don't want to block focus from working with `visibleOnly`
|
|
670
|
+
// (JSDOM doesn't match `:focus-visible` when the element has `:focus`)
|
|
671
|
+
if (!element || isJSDOM) {
|
|
672
|
+
return true;
|
|
673
|
+
}
|
|
674
|
+
try {
|
|
675
|
+
return element.matches(':focus-visible');
|
|
676
|
+
} catch (_e) {
|
|
677
|
+
return true;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
function getFloatingFocusElement(floatingElement) {
|
|
681
|
+
if (!floatingElement) {
|
|
682
|
+
return null;
|
|
683
|
+
}
|
|
684
|
+
// Try to find the element that has `{...getFloatingProps()}` spread on it.
|
|
685
|
+
// This indicates the floating element is acting as a positioning wrapper, and
|
|
686
|
+
// so focus should be managed on the child element with the event handlers and
|
|
687
|
+
// aria props.
|
|
688
|
+
return floatingElement.hasAttribute(FOCUSABLE_ATTRIBUTE) ? floatingElement : floatingElement.querySelector(`[${FOCUSABLE_ATTRIBUTE}]`) || floatingElement;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
/* eslint-disable @typescript-eslint/no-loop-func */
|
|
692
|
+
|
|
693
|
+
function getNodeChildren(nodes, id, onlyOpenChildren = true) {
|
|
694
|
+
const directChildren = nodes.filter(node => node.parentId === id && (!onlyOpenChildren || node.context?.open));
|
|
695
|
+
return directChildren.flatMap(child => [child, ...getNodeChildren(nodes, child.id, onlyOpenChildren)]);
|
|
696
|
+
}
|
|
697
|
+
function getNodeAncestors(nodes, id) {
|
|
698
|
+
let allAncestors = [];
|
|
699
|
+
let currentParentId = nodes.find(node => node.id === id)?.parentId;
|
|
700
|
+
while (currentParentId) {
|
|
701
|
+
const currentNode = nodes.find(node => node.id === currentParentId);
|
|
702
|
+
currentParentId = currentNode?.parentId;
|
|
703
|
+
if (currentNode) {
|
|
704
|
+
allAncestors = allAncestors.concat(currentNode);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
return allAncestors;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
function stopEvent(event) {
|
|
711
|
+
event.preventDefault();
|
|
712
|
+
event.stopPropagation();
|
|
713
|
+
}
|
|
714
|
+
function isReactEvent(event) {
|
|
715
|
+
return 'nativeEvent' in event;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// License: https://github.com/adobe/react-spectrum/blob/main/packages/@react-aria/utils/src/isVirtualEvent.ts
|
|
719
|
+
function isVirtualClick(event) {
|
|
720
|
+
if (event.pointerType === '' && event.isTrusted) {
|
|
721
|
+
return true;
|
|
722
|
+
}
|
|
723
|
+
if (isAndroid && event.pointerType) {
|
|
724
|
+
return event.type === 'click' && event.buttons === 1;
|
|
725
|
+
}
|
|
726
|
+
return event.detail === 0 && !event.pointerType;
|
|
727
|
+
}
|
|
728
|
+
function isVirtualPointerEvent(event) {
|
|
729
|
+
if (isJSDOM) {
|
|
730
|
+
return false;
|
|
731
|
+
}
|
|
732
|
+
return !isAndroid && event.width === 0 && event.height === 0 || isAndroid && event.width === 1 && event.height === 1 && event.pressure === 0 && event.detail === 0 && event.pointerType === 'mouse' ||
|
|
733
|
+
// iOS VoiceOver returns 0.333• for width/height.
|
|
734
|
+
event.width < 1 && event.height < 1 && event.pressure === 0 && event.detail === 0 && event.pointerType === 'touch';
|
|
735
|
+
}
|
|
736
|
+
function isMouseLikePointerType(pointerType, strict) {
|
|
727
737
|
// On some Linux machines with Chromium, mouse inputs return a `pointerType`
|
|
728
738
|
// of "pen": https://github.com/floating-ui/floating-ui/issues/2015
|
|
729
739
|
const values = ['mouse', 'pen'];
|
|
740
|
+
if (!strict) {
|
|
741
|
+
values.push('', undefined);
|
|
742
|
+
}
|
|
730
743
|
return values.includes(pointerType);
|
|
731
744
|
}
|
|
732
745
|
function isClickLikeEvent(event) {
|
|
@@ -1105,6 +1118,28 @@ function getNextTabbable(referenceElement) {
|
|
|
1105
1118
|
function getPreviousTabbable(referenceElement) {
|
|
1106
1119
|
return getTabbableIn(ownerDocument(referenceElement).body, -1) || referenceElement;
|
|
1107
1120
|
}
|
|
1121
|
+
function getTabbableNearElement(referenceElement, dir) {
|
|
1122
|
+
if (!referenceElement) {
|
|
1123
|
+
return null;
|
|
1124
|
+
}
|
|
1125
|
+
const list = tabbable(ownerDocument(referenceElement).body, getTabbableOptions());
|
|
1126
|
+
const elementCount = list.length;
|
|
1127
|
+
if (elementCount === 0) {
|
|
1128
|
+
return null;
|
|
1129
|
+
}
|
|
1130
|
+
const index = list.indexOf(referenceElement);
|
|
1131
|
+
if (index === -1) {
|
|
1132
|
+
return null;
|
|
1133
|
+
}
|
|
1134
|
+
const nextIndex = (index + dir + elementCount) % elementCount;
|
|
1135
|
+
return list[nextIndex];
|
|
1136
|
+
}
|
|
1137
|
+
function getTabbableAfterElement(referenceElement) {
|
|
1138
|
+
return getTabbableNearElement(referenceElement, 1);
|
|
1139
|
+
}
|
|
1140
|
+
function getTabbableBeforeElement(referenceElement) {
|
|
1141
|
+
return getTabbableNearElement(referenceElement, -1);
|
|
1142
|
+
}
|
|
1108
1143
|
function isOutsideEvent(event, container) {
|
|
1109
1144
|
const containerElement = container || event.currentTarget;
|
|
1110
1145
|
const relatedTarget = event.relatedTarget;
|
|
@@ -1130,412 +1165,203 @@ function enableFocusInside(container) {
|
|
|
1130
1165
|
});
|
|
1131
1166
|
}
|
|
1132
1167
|
|
|
1133
|
-
const ARROW_UP = 'ArrowUp';
|
|
1134
|
-
const ARROW_DOWN = 'ArrowDown';
|
|
1135
|
-
const ARROW_LEFT = 'ArrowLeft';
|
|
1136
|
-
const ARROW_RIGHT = 'ArrowRight';
|
|
1137
|
-
const HOME = 'Home';
|
|
1138
|
-
const END = 'End';
|
|
1139
|
-
const HORIZONTAL_KEYS = new Set([ARROW_LEFT, ARROW_RIGHT]);
|
|
1140
|
-
const VERTICAL_KEYS = new Set([ARROW_UP, ARROW_DOWN]);
|
|
1141
|
-
const ARROW_KEYS = new Set([...HORIZONTAL_KEYS, ...VERTICAL_KEYS]);
|
|
1142
|
-
new Set([...ARROW_KEYS, HOME, END]);
|
|
1143
|
-
const COMPOSITE_KEYS = new Set([ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT, HOME, END]);
|
|
1144
|
-
|
|
1145
1168
|
/**
|
|
1146
|
-
*
|
|
1169
|
+
* Untracks the provided value by turning it into a ref to remove its reactivity.
|
|
1170
|
+
*
|
|
1171
|
+
* Used to access the passed value inside `React.useEffect` without causing the effect to re-run when the value changes.
|
|
1147
1172
|
*/
|
|
1148
|
-
function
|
|
1149
|
-
const
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1173
|
+
function useValueAsRef(value) {
|
|
1174
|
+
const latest = useRefWithInit(createLatestRef, value).current;
|
|
1175
|
+
latest.next = value;
|
|
1176
|
+
|
|
1177
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1178
|
+
useIsoLayoutEffect(latest.effect);
|
|
1179
|
+
return latest;
|
|
1180
|
+
}
|
|
1181
|
+
function createLatestRef(value) {
|
|
1182
|
+
const latest = {
|
|
1183
|
+
current: value,
|
|
1184
|
+
next: value,
|
|
1185
|
+
effect: () => {
|
|
1186
|
+
latest.current = latest.next;
|
|
1160
1187
|
}
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
return () => {
|
|
1164
|
-
abortController.abort();
|
|
1165
|
-
};
|
|
1166
|
-
}, [enabled, open, onComplete, runOnceAnimationsFinish]);
|
|
1188
|
+
};
|
|
1189
|
+
return latest;
|
|
1167
1190
|
}
|
|
1168
1191
|
|
|
1169
|
-
|
|
1170
|
-
|
|
1192
|
+
/** Unlike `setTimeout`, rAF doesn't guarantee a positive integer return value, so we can't have
|
|
1193
|
+
* a monomorphic `uint` type with `0` meaning empty.
|
|
1194
|
+
* See warning note at:
|
|
1195
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame#return_value */
|
|
1196
|
+
const EMPTY = null;
|
|
1197
|
+
let LAST_RAF = globalThis.requestAnimationFrame;
|
|
1198
|
+
class Scheduler {
|
|
1199
|
+
/* This implementation uses an array as a backing data-structure for frame callbacks.
|
|
1200
|
+
* It allows `O(1)` callback cancelling by inserting a `null` in the array, though it
|
|
1201
|
+
* never calls the native `cancelAnimationFrame` if there are no frames left. This can
|
|
1202
|
+
* be much more efficient if there is a call pattern that alterns as
|
|
1203
|
+
* "request-cancel-request-cancel-…".
|
|
1204
|
+
* But in the case of "request-request-…-cancel-cancel-…", it leaves the final animation
|
|
1205
|
+
* frame to run anyway. We turn that frame into a `O(1)` no-op via `callbacksCount`. */
|
|
1206
|
+
|
|
1207
|
+
callbacks = [];
|
|
1208
|
+
callbacksCount = 0;
|
|
1209
|
+
nextId = 1;
|
|
1210
|
+
startId = 1;
|
|
1211
|
+
isScheduled = false;
|
|
1212
|
+
tick = timestamp => {
|
|
1213
|
+
this.isScheduled = false;
|
|
1214
|
+
const currentCallbacks = this.callbacks;
|
|
1215
|
+
const currentCallbacksCount = this.callbacksCount;
|
|
1216
|
+
|
|
1217
|
+
// Update these before iterating, callbacks could call `requestAnimationFrame` again.
|
|
1218
|
+
this.callbacks = [];
|
|
1219
|
+
this.callbacksCount = 0;
|
|
1220
|
+
this.startId = this.nextId;
|
|
1221
|
+
if (currentCallbacksCount > 0) {
|
|
1222
|
+
for (let i = 0; i < currentCallbacks.length; i += 1) {
|
|
1223
|
+
currentCallbacks[i]?.(timestamp);
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
request(fn) {
|
|
1228
|
+
const id = this.nextId;
|
|
1229
|
+
this.nextId += 1;
|
|
1230
|
+
this.callbacks.push(fn);
|
|
1231
|
+
this.callbacksCount += 1;
|
|
1232
|
+
|
|
1233
|
+
/* In a test environment with fake timers, a fake `requestAnimationFrame` can be called
|
|
1234
|
+
* but there's no guarantee that the animation frame will actually run before the fake
|
|
1235
|
+
* timers are teared, which leaves `isScheduled` set, but won't run our `tick()`. */
|
|
1236
|
+
const didRAFChange = process.env.NODE_ENV !== 'production' && LAST_RAF !== requestAnimationFrame && (LAST_RAF = requestAnimationFrame, true);
|
|
1237
|
+
if (!this.isScheduled || didRAFChange) {
|
|
1238
|
+
requestAnimationFrame(this.tick);
|
|
1239
|
+
this.isScheduled = true;
|
|
1240
|
+
}
|
|
1241
|
+
return id;
|
|
1242
|
+
}
|
|
1243
|
+
cancel(id) {
|
|
1244
|
+
const index = id - this.startId;
|
|
1245
|
+
if (index < 0 || index >= this.callbacks.length) {
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
this.callbacks[index] = null;
|
|
1249
|
+
this.callbacksCount -= 1;
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
const scheduler = new Scheduler();
|
|
1253
|
+
class AnimationFrame {
|
|
1171
1254
|
static create() {
|
|
1172
|
-
return new
|
|
1255
|
+
return new AnimationFrame();
|
|
1256
|
+
}
|
|
1257
|
+
static request(fn) {
|
|
1258
|
+
return scheduler.request(fn);
|
|
1259
|
+
}
|
|
1260
|
+
static cancel(id) {
|
|
1261
|
+
return scheduler.cancel(id);
|
|
1173
1262
|
}
|
|
1174
1263
|
currentId = EMPTY;
|
|
1175
1264
|
|
|
1176
1265
|
/**
|
|
1177
1266
|
* Executes `fn` after `delay`, clearing any previously scheduled call.
|
|
1178
1267
|
*/
|
|
1179
|
-
|
|
1180
|
-
this.
|
|
1181
|
-
this.currentId =
|
|
1268
|
+
request(fn) {
|
|
1269
|
+
this.cancel();
|
|
1270
|
+
this.currentId = scheduler.request(() => {
|
|
1182
1271
|
this.currentId = EMPTY;
|
|
1183
1272
|
fn();
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
isStarted() {
|
|
1187
|
-
return this.currentId !== EMPTY;
|
|
1273
|
+
});
|
|
1188
1274
|
}
|
|
1189
|
-
|
|
1275
|
+
cancel = () => {
|
|
1190
1276
|
if (this.currentId !== EMPTY) {
|
|
1191
|
-
|
|
1277
|
+
scheduler.cancel(this.currentId);
|
|
1192
1278
|
this.currentId = EMPTY;
|
|
1193
1279
|
}
|
|
1194
1280
|
};
|
|
1195
1281
|
disposeEffect = () => {
|
|
1196
|
-
return this.
|
|
1282
|
+
return this.cancel;
|
|
1197
1283
|
};
|
|
1198
1284
|
}
|
|
1199
1285
|
|
|
1200
1286
|
/**
|
|
1201
|
-
* A `
|
|
1287
|
+
* A `requestAnimationFrame` with automatic cleanup and guard.
|
|
1202
1288
|
*/
|
|
1203
|
-
function
|
|
1204
|
-
const timeout = useRefWithInit(
|
|
1289
|
+
function useAnimationFrame() {
|
|
1290
|
+
const timeout = useRefWithInit(AnimationFrame.create).current;
|
|
1205
1291
|
useOnMount(timeout.disposeEffect);
|
|
1206
1292
|
return timeout;
|
|
1207
1293
|
}
|
|
1208
1294
|
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
const originalScrollContainerOverflowY = scrollContainer.style.overflowY;
|
|
1230
|
-
const originalHtmlStyleGutter = html.style.scrollbarGutter;
|
|
1231
|
-
html.style.scrollbarGutter = 'stable';
|
|
1232
|
-
scrollContainer.style.overflowY = 'scroll';
|
|
1233
|
-
const before = scrollContainer.offsetWidth;
|
|
1234
|
-
scrollContainer.style.overflowY = 'hidden';
|
|
1235
|
-
const after = scrollContainer.offsetWidth;
|
|
1236
|
-
scrollContainer.style.overflowY = originalScrollContainerOverflowY;
|
|
1237
|
-
html.style.scrollbarGutter = originalHtmlStyleGutter;
|
|
1238
|
-
return before === after;
|
|
1239
|
-
}
|
|
1240
|
-
function preventScrollOverlayScrollbars(referenceElement) {
|
|
1241
|
-
const doc = ownerDocument(referenceElement);
|
|
1242
|
-
const html = doc.documentElement;
|
|
1243
|
-
const body = doc.body;
|
|
1295
|
+
const visuallyHiddenBase = {
|
|
1296
|
+
clipPath: 'inset(50%)',
|
|
1297
|
+
overflow: 'hidden',
|
|
1298
|
+
whiteSpace: 'nowrap',
|
|
1299
|
+
border: 0,
|
|
1300
|
+
padding: 0,
|
|
1301
|
+
width: 1,
|
|
1302
|
+
height: 1,
|
|
1303
|
+
margin: -1
|
|
1304
|
+
};
|
|
1305
|
+
const visuallyHidden = {
|
|
1306
|
+
...visuallyHiddenBase,
|
|
1307
|
+
position: 'fixed',
|
|
1308
|
+
top: 0,
|
|
1309
|
+
left: 0
|
|
1310
|
+
};
|
|
1311
|
+
const visuallyHiddenInput = {
|
|
1312
|
+
...visuallyHiddenBase,
|
|
1313
|
+
position: 'absolute'
|
|
1314
|
+
};
|
|
1244
1315
|
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1316
|
+
const FocusGuard = /*#__PURE__*/React.forwardRef(function FocusGuard(props, ref) {
|
|
1317
|
+
const [role, setRole] = React.useState();
|
|
1318
|
+
useIsoLayoutEffect(() => {
|
|
1319
|
+
if (isSafari) {
|
|
1320
|
+
// Unlike other screen readers such as NVDA and JAWS, the virtual cursor
|
|
1321
|
+
// on VoiceOver does trigger the onFocus event, so we can use the focus
|
|
1322
|
+
// trap element. On Safari, only buttons trigger the onFocus event.
|
|
1323
|
+
setRole('button');
|
|
1324
|
+
}
|
|
1325
|
+
}, []);
|
|
1326
|
+
const restProps = {
|
|
1327
|
+
tabIndex: 0,
|
|
1328
|
+
// Role is only for VoiceOver
|
|
1329
|
+
role
|
|
1253
1330
|
};
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1331
|
+
return /*#__PURE__*/jsx("span", {
|
|
1332
|
+
...props,
|
|
1333
|
+
ref: ref,
|
|
1334
|
+
style: visuallyHidden,
|
|
1335
|
+
"aria-hidden": role ? undefined : true,
|
|
1336
|
+
...restProps,
|
|
1337
|
+
"data-base-ui-focus-guard": ""
|
|
1257
1338
|
});
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1339
|
+
});
|
|
1340
|
+
if (process.env.NODE_ENV !== "production") FocusGuard.displayName = "FocusGuard";
|
|
1341
|
+
|
|
1342
|
+
function createAttribute(name) {
|
|
1343
|
+
return `data-base-ui-${name}`;
|
|
1261
1344
|
}
|
|
1262
|
-
function preventScrollInsetScrollbars(referenceElement) {
|
|
1263
|
-
const doc = ownerDocument(referenceElement);
|
|
1264
|
-
const html = doc.documentElement;
|
|
1265
|
-
const body = doc.body;
|
|
1266
|
-
const win = getWindow(html);
|
|
1267
|
-
let scrollTop = 0;
|
|
1268
|
-
let scrollLeft = 0;
|
|
1269
|
-
let updateGutterOnly = false;
|
|
1270
|
-
const resizeFrame = AnimationFrame.create();
|
|
1271
1345
|
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1346
|
+
let rafId = 0;
|
|
1347
|
+
function enqueueFocus(el, options = {}) {
|
|
1348
|
+
const {
|
|
1349
|
+
preventScroll = false,
|
|
1350
|
+
cancelPrevious = true,
|
|
1351
|
+
sync = false
|
|
1352
|
+
} = options;
|
|
1353
|
+
if (cancelPrevious) {
|
|
1354
|
+
cancelAnimationFrame(rafId);
|
|
1275
1355
|
}
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
scrollLeft = html.scrollLeft;
|
|
1286
|
-
originalHtmlStyles = {
|
|
1287
|
-
scrollbarGutter: html.style.scrollbarGutter,
|
|
1288
|
-
overflowY: html.style.overflowY,
|
|
1289
|
-
overflowX: html.style.overflowX
|
|
1290
|
-
};
|
|
1291
|
-
originalHtmlScrollBehavior = html.style.scrollBehavior;
|
|
1292
|
-
originalBodyStyles = {
|
|
1293
|
-
position: body.style.position,
|
|
1294
|
-
height: body.style.height,
|
|
1295
|
-
width: body.style.width,
|
|
1296
|
-
boxSizing: body.style.boxSizing,
|
|
1297
|
-
overflowY: body.style.overflowY,
|
|
1298
|
-
overflowX: body.style.overflowX,
|
|
1299
|
-
scrollBehavior: body.style.scrollBehavior
|
|
1300
|
-
};
|
|
1301
|
-
const isScrollableY = html.scrollHeight > html.clientHeight;
|
|
1302
|
-
const isScrollableX = html.scrollWidth > html.clientWidth;
|
|
1303
|
-
const hasConstantOverflowY = htmlStyles.overflowY === 'scroll' || bodyStyles.overflowY === 'scroll';
|
|
1304
|
-
const hasConstantOverflowX = htmlStyles.overflowX === 'scroll' || bodyStyles.overflowX === 'scroll';
|
|
1305
|
-
|
|
1306
|
-
// Values can be negative in Firefox
|
|
1307
|
-
const scrollbarWidth = Math.max(0, win.innerWidth - body.clientWidth);
|
|
1308
|
-
const scrollbarHeight = Math.max(0, win.innerHeight - body.clientHeight);
|
|
1309
|
-
|
|
1310
|
-
// Avoid shift due to the default <body> margin. This does cause elements to be clipped
|
|
1311
|
-
// with whitespace. Warn if <body> has margins?
|
|
1312
|
-
const marginY = parseFloat(bodyStyles.marginTop) + parseFloat(bodyStyles.marginBottom);
|
|
1313
|
-
const marginX = parseFloat(bodyStyles.marginLeft) + parseFloat(bodyStyles.marginRight);
|
|
1314
|
-
const elementToLock = isOverflowElement(html) ? html : body;
|
|
1315
|
-
updateGutterOnly = supportsStableScrollbarGutter(referenceElement);
|
|
1316
|
-
|
|
1317
|
-
/*
|
|
1318
|
-
* DOM writes:
|
|
1319
|
-
* Do not read the DOM past this point!
|
|
1320
|
-
*/
|
|
1321
|
-
|
|
1322
|
-
if (updateGutterOnly) {
|
|
1323
|
-
html.style.scrollbarGutter = scrollbarGutterValue;
|
|
1324
|
-
elementToLock.style.overflowY = 'hidden';
|
|
1325
|
-
elementToLock.style.overflowX = 'hidden';
|
|
1326
|
-
return;
|
|
1327
|
-
}
|
|
1328
|
-
Object.assign(html.style, {
|
|
1329
|
-
scrollbarGutter: scrollbarGutterValue,
|
|
1330
|
-
overflowY: 'hidden',
|
|
1331
|
-
overflowX: 'hidden'
|
|
1332
|
-
});
|
|
1333
|
-
if (isScrollableY || hasConstantOverflowY) {
|
|
1334
|
-
html.style.overflowY = 'scroll';
|
|
1335
|
-
}
|
|
1336
|
-
if (isScrollableX || hasConstantOverflowX) {
|
|
1337
|
-
html.style.overflowX = 'scroll';
|
|
1338
|
-
}
|
|
1339
|
-
Object.assign(body.style, {
|
|
1340
|
-
position: 'relative',
|
|
1341
|
-
height: marginY || scrollbarHeight ? `calc(100dvh - ${marginY + scrollbarHeight}px)` : '100dvh',
|
|
1342
|
-
width: marginX || scrollbarWidth ? `calc(100vw - ${marginX + scrollbarWidth}px)` : '100vw',
|
|
1343
|
-
boxSizing: 'border-box',
|
|
1344
|
-
overflow: 'hidden',
|
|
1345
|
-
scrollBehavior: 'unset'
|
|
1346
|
-
});
|
|
1347
|
-
body.scrollTop = scrollTop;
|
|
1348
|
-
body.scrollLeft = scrollLeft;
|
|
1349
|
-
html.setAttribute('data-base-ui-scroll-locked', '');
|
|
1350
|
-
html.style.scrollBehavior = 'unset';
|
|
1351
|
-
}
|
|
1352
|
-
function cleanup() {
|
|
1353
|
-
Object.assign(html.style, originalHtmlStyles);
|
|
1354
|
-
Object.assign(body.style, originalBodyStyles);
|
|
1355
|
-
if (!updateGutterOnly) {
|
|
1356
|
-
html.scrollTop = scrollTop;
|
|
1357
|
-
html.scrollLeft = scrollLeft;
|
|
1358
|
-
html.removeAttribute('data-base-ui-scroll-locked');
|
|
1359
|
-
html.style.scrollBehavior = originalHtmlScrollBehavior;
|
|
1360
|
-
}
|
|
1361
|
-
}
|
|
1362
|
-
function handleResize() {
|
|
1363
|
-
cleanup();
|
|
1364
|
-
resizeFrame.request(lockScroll);
|
|
1365
|
-
}
|
|
1366
|
-
lockScroll();
|
|
1367
|
-
win.addEventListener('resize', handleResize);
|
|
1368
|
-
return () => {
|
|
1369
|
-
resizeFrame.cancel();
|
|
1370
|
-
cleanup();
|
|
1371
|
-
// Sometimes this cleanup can be run after test teardown
|
|
1372
|
-
// because it is called in a `setTimeout(fn, 0)`,
|
|
1373
|
-
// in which case `removeEventListener` wouldn't be available,
|
|
1374
|
-
// so we check for it to avoid test failures.
|
|
1375
|
-
if (typeof win.removeEventListener === 'function') {
|
|
1376
|
-
win.removeEventListener('resize', handleResize);
|
|
1377
|
-
}
|
|
1378
|
-
};
|
|
1379
|
-
}
|
|
1380
|
-
class ScrollLocker {
|
|
1381
|
-
lockCount = 0;
|
|
1382
|
-
restore = null;
|
|
1383
|
-
timeoutLock = Timeout.create();
|
|
1384
|
-
timeoutUnlock = Timeout.create();
|
|
1385
|
-
acquire(referenceElement) {
|
|
1386
|
-
this.lockCount += 1;
|
|
1387
|
-
if (this.lockCount === 1 && this.restore === null) {
|
|
1388
|
-
this.timeoutLock.start(0, () => this.lock(referenceElement));
|
|
1389
|
-
}
|
|
1390
|
-
return this.release;
|
|
1391
|
-
}
|
|
1392
|
-
release = () => {
|
|
1393
|
-
this.lockCount -= 1;
|
|
1394
|
-
if (this.lockCount === 0 && this.restore) {
|
|
1395
|
-
this.timeoutUnlock.start(0, this.unlock);
|
|
1396
|
-
}
|
|
1397
|
-
};
|
|
1398
|
-
unlock = () => {
|
|
1399
|
-
if (this.lockCount === 0 && this.restore) {
|
|
1400
|
-
this.restore?.();
|
|
1401
|
-
this.restore = null;
|
|
1402
|
-
}
|
|
1403
|
-
};
|
|
1404
|
-
lock(referenceElement) {
|
|
1405
|
-
if (this.lockCount === 0 || this.restore !== null) {
|
|
1406
|
-
return;
|
|
1407
|
-
}
|
|
1408
|
-
const doc = ownerDocument(referenceElement);
|
|
1409
|
-
const html = doc.documentElement;
|
|
1410
|
-
const htmlOverflowY = getWindow(html).getComputedStyle(html).overflowY;
|
|
1411
|
-
|
|
1412
|
-
// If the site author already hid overflow on <html>, respect it and bail out.
|
|
1413
|
-
if (htmlOverflowY === 'hidden' || htmlOverflowY === 'clip') {
|
|
1414
|
-
this.restore = NOOP;
|
|
1415
|
-
return;
|
|
1416
|
-
}
|
|
1417
|
-
const hasOverlayScrollbars = isIOS || !hasInsetScrollbars(referenceElement);
|
|
1418
|
-
|
|
1419
|
-
// On iOS, scroll locking does not work if the navbar is collapsed. Due to numerous
|
|
1420
|
-
// side effects and bugs that arise on iOS, it must be researched extensively before
|
|
1421
|
-
// being enabled to ensure it doesn't cause the following issues:
|
|
1422
|
-
// - Textboxes must scroll into view when focused, nor cause a glitchy scroll animation.
|
|
1423
|
-
// - The navbar must not force itself into view and cause layout shift.
|
|
1424
|
-
// - Scroll containers must not flicker upon closing a popup when it has an exit animation.
|
|
1425
|
-
this.restore = hasOverlayScrollbars ? preventScrollOverlayScrollbars(referenceElement) : preventScrollInsetScrollbars(referenceElement);
|
|
1426
|
-
}
|
|
1427
|
-
}
|
|
1428
|
-
const SCROLL_LOCKER = new ScrollLocker();
|
|
1429
|
-
|
|
1430
|
-
/**
|
|
1431
|
-
* Locks the scroll of the document when enabled.
|
|
1432
|
-
*
|
|
1433
|
-
* @param enabled - Whether to enable the scroll lock.
|
|
1434
|
-
* @param referenceElement - Element to use as a reference for lock calculations.
|
|
1435
|
-
*/
|
|
1436
|
-
function useScrollLock(enabled = true, referenceElement = null) {
|
|
1437
|
-
useIsoLayoutEffect(() => {
|
|
1438
|
-
if (!enabled) {
|
|
1439
|
-
return undefined;
|
|
1440
|
-
}
|
|
1441
|
-
return SCROLL_LOCKER.acquire(referenceElement);
|
|
1442
|
-
}, [enabled, referenceElement]);
|
|
1443
|
-
}
|
|
1444
|
-
|
|
1445
|
-
/**
|
|
1446
|
-
* Untracks the provided value by turning it into a ref to remove its reactivity.
|
|
1447
|
-
*
|
|
1448
|
-
* Used to access the passed value inside `React.useEffect` without causing the effect to re-run when the value changes.
|
|
1449
|
-
*/
|
|
1450
|
-
function useValueAsRef(value) {
|
|
1451
|
-
const latest = useRefWithInit(createLatestRef, value).current;
|
|
1452
|
-
latest.next = value;
|
|
1453
|
-
|
|
1454
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1455
|
-
useIsoLayoutEffect(latest.effect);
|
|
1456
|
-
return latest;
|
|
1457
|
-
}
|
|
1458
|
-
function createLatestRef(value) {
|
|
1459
|
-
const latest = {
|
|
1460
|
-
current: value,
|
|
1461
|
-
next: value,
|
|
1462
|
-
effect: () => {
|
|
1463
|
-
latest.current = latest.next;
|
|
1464
|
-
}
|
|
1465
|
-
};
|
|
1466
|
-
return latest;
|
|
1467
|
-
}
|
|
1468
|
-
|
|
1469
|
-
const visuallyHiddenBase = {
|
|
1470
|
-
clipPath: 'inset(50%)',
|
|
1471
|
-
overflow: 'hidden',
|
|
1472
|
-
whiteSpace: 'nowrap',
|
|
1473
|
-
border: 0,
|
|
1474
|
-
padding: 0,
|
|
1475
|
-
width: 1,
|
|
1476
|
-
height: 1,
|
|
1477
|
-
margin: -1
|
|
1478
|
-
};
|
|
1479
|
-
const visuallyHidden = {
|
|
1480
|
-
...visuallyHiddenBase,
|
|
1481
|
-
position: 'fixed',
|
|
1482
|
-
top: 0,
|
|
1483
|
-
left: 0
|
|
1484
|
-
};
|
|
1485
|
-
const visuallyHiddenInput = {
|
|
1486
|
-
...visuallyHiddenBase,
|
|
1487
|
-
position: 'absolute'
|
|
1488
|
-
};
|
|
1489
|
-
|
|
1490
|
-
const FocusGuard = /*#__PURE__*/React.forwardRef(function FocusGuard(props, ref) {
|
|
1491
|
-
const [role, setRole] = React.useState();
|
|
1492
|
-
useIsoLayoutEffect(() => {
|
|
1493
|
-
if (isSafari) {
|
|
1494
|
-
// Unlike other screen readers such as NVDA and JAWS, the virtual cursor
|
|
1495
|
-
// on VoiceOver does trigger the onFocus event, so we can use the focus
|
|
1496
|
-
// trap element. On Safari, only buttons trigger the onFocus event.
|
|
1497
|
-
setRole('button');
|
|
1498
|
-
}
|
|
1499
|
-
}, []);
|
|
1500
|
-
const restProps = {
|
|
1501
|
-
tabIndex: 0,
|
|
1502
|
-
// Role is only for VoiceOver
|
|
1503
|
-
role
|
|
1504
|
-
};
|
|
1505
|
-
return /*#__PURE__*/jsx("span", {
|
|
1506
|
-
...props,
|
|
1507
|
-
ref: ref,
|
|
1508
|
-
style: visuallyHidden,
|
|
1509
|
-
"aria-hidden": role ? undefined : true,
|
|
1510
|
-
...restProps,
|
|
1511
|
-
"data-base-ui-focus-guard": ""
|
|
1512
|
-
});
|
|
1513
|
-
});
|
|
1514
|
-
if (process.env.NODE_ENV !== "production") FocusGuard.displayName = "FocusGuard";
|
|
1515
|
-
|
|
1516
|
-
function createAttribute(name) {
|
|
1517
|
-
return `data-base-ui-${name}`;
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
let rafId = 0;
|
|
1521
|
-
function enqueueFocus(el, options = {}) {
|
|
1522
|
-
const {
|
|
1523
|
-
preventScroll = false,
|
|
1524
|
-
cancelPrevious = true,
|
|
1525
|
-
sync = false
|
|
1526
|
-
} = options;
|
|
1527
|
-
if (cancelPrevious) {
|
|
1528
|
-
cancelAnimationFrame(rafId);
|
|
1529
|
-
}
|
|
1530
|
-
const exec = () => el?.focus({
|
|
1531
|
-
preventScroll
|
|
1532
|
-
});
|
|
1533
|
-
if (sync) {
|
|
1534
|
-
exec();
|
|
1535
|
-
} else {
|
|
1536
|
-
rafId = requestAnimationFrame(exec);
|
|
1537
|
-
}
|
|
1538
|
-
}
|
|
1356
|
+
const exec = () => el?.focus({
|
|
1357
|
+
preventScroll
|
|
1358
|
+
});
|
|
1359
|
+
if (sync) {
|
|
1360
|
+
exec();
|
|
1361
|
+
} else {
|
|
1362
|
+
rafId = requestAnimationFrame(exec);
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1539
1365
|
|
|
1540
1366
|
// Modified to add conditional `aria-hidden` support:
|
|
1541
1367
|
// https://github.com/theKashey/aria-hidden/blob/9220c8f4a4fd35f63bee5510a9f41a37264382d4/src/index.ts
|
|
@@ -1899,13 +1725,33 @@ function createEventEmitter() {
|
|
|
1899
1725
|
};
|
|
1900
1726
|
}
|
|
1901
1727
|
|
|
1902
|
-
const FloatingNodeContext = /*#__PURE__*/React.createContext(null);
|
|
1903
|
-
if (process.env.NODE_ENV !== "production") FloatingNodeContext.displayName = "FloatingNodeContext";
|
|
1904
|
-
const FloatingTreeContext = /*#__PURE__*/React.createContext(null);
|
|
1905
|
-
|
|
1906
1728
|
/**
|
|
1907
|
-
*
|
|
1908
|
-
*
|
|
1729
|
+
* Stores and manages floating elements in a tree structure.
|
|
1730
|
+
* This is a backing store for the `FloatingTree` component.
|
|
1731
|
+
*/
|
|
1732
|
+
class FloatingTreeStore {
|
|
1733
|
+
nodesRef = {
|
|
1734
|
+
current: []
|
|
1735
|
+
};
|
|
1736
|
+
events = createEventEmitter();
|
|
1737
|
+
addNode(node) {
|
|
1738
|
+
this.nodesRef.current.push(node);
|
|
1739
|
+
}
|
|
1740
|
+
removeNode(node) {
|
|
1741
|
+
const index = this.nodesRef.current.findIndex(n => n === node);
|
|
1742
|
+
if (index !== -1) {
|
|
1743
|
+
this.nodesRef.current.splice(index, 1);
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
const FloatingNodeContext = /*#__PURE__*/React.createContext(null);
|
|
1749
|
+
if (process.env.NODE_ENV !== "production") FloatingNodeContext.displayName = "FloatingNodeContext";
|
|
1750
|
+
const FloatingTreeContext = /*#__PURE__*/React.createContext(null);
|
|
1751
|
+
|
|
1752
|
+
/**
|
|
1753
|
+
* Returns the parent node id for nested floating elements, if available.
|
|
1754
|
+
* Returns `null` for top-level floating elements.
|
|
1909
1755
|
*/
|
|
1910
1756
|
if (process.env.NODE_ENV !== "production") FloatingTreeContext.displayName = "FloatingTreeContext";
|
|
1911
1757
|
const useFloatingParentNodeId = () => React.useContext(FloatingNodeContext)?.id || null;
|
|
@@ -1918,6 +1764,82 @@ const useFloatingTree = externalTree => {
|
|
|
1918
1764
|
return externalTree ?? contextTree;
|
|
1919
1765
|
};
|
|
1920
1766
|
|
|
1767
|
+
/**
|
|
1768
|
+
* Registers a node into the `FloatingTree`, returning its id.
|
|
1769
|
+
* @see https://floating-ui.com/docs/FloatingTree
|
|
1770
|
+
*/
|
|
1771
|
+
function useFloatingNodeId(externalTree) {
|
|
1772
|
+
const id = useId();
|
|
1773
|
+
const tree = useFloatingTree(externalTree);
|
|
1774
|
+
const parentId = useFloatingParentNodeId();
|
|
1775
|
+
useIsoLayoutEffect(() => {
|
|
1776
|
+
if (!id) {
|
|
1777
|
+
return undefined;
|
|
1778
|
+
}
|
|
1779
|
+
const node = {
|
|
1780
|
+
id,
|
|
1781
|
+
parentId
|
|
1782
|
+
};
|
|
1783
|
+
tree?.addNode(node);
|
|
1784
|
+
return () => {
|
|
1785
|
+
tree?.removeNode(node);
|
|
1786
|
+
};
|
|
1787
|
+
}, [tree, id, parentId]);
|
|
1788
|
+
return id;
|
|
1789
|
+
}
|
|
1790
|
+
/**
|
|
1791
|
+
* Provides parent node context for nested floating elements.
|
|
1792
|
+
* @see https://floating-ui.com/docs/FloatingTree
|
|
1793
|
+
* @internal
|
|
1794
|
+
*/
|
|
1795
|
+
function FloatingNode(props) {
|
|
1796
|
+
const {
|
|
1797
|
+
children,
|
|
1798
|
+
id
|
|
1799
|
+
} = props;
|
|
1800
|
+
const parentId = useFloatingParentNodeId();
|
|
1801
|
+
return /*#__PURE__*/jsx(FloatingNodeContext.Provider, {
|
|
1802
|
+
value: React.useMemo(() => ({
|
|
1803
|
+
id,
|
|
1804
|
+
parentId
|
|
1805
|
+
}), [id, parentId]),
|
|
1806
|
+
children: children
|
|
1807
|
+
});
|
|
1808
|
+
}
|
|
1809
|
+
/**
|
|
1810
|
+
* Provides context for nested floating elements when they are not children of
|
|
1811
|
+
* each other on the DOM.
|
|
1812
|
+
* This is not necessary in all cases, except when there must be explicit communication between parent and child floating elements. It is necessary for:
|
|
1813
|
+
* - The `bubbles` option in the `useDismiss()` Hook
|
|
1814
|
+
* - Nested virtual list navigation
|
|
1815
|
+
* - Nested floating elements that each open on hover
|
|
1816
|
+
* - Custom communication between parent and child floating elements
|
|
1817
|
+
* @see https://floating-ui.com/docs/FloatingTree
|
|
1818
|
+
* @internal
|
|
1819
|
+
*/
|
|
1820
|
+
function FloatingTree(props) {
|
|
1821
|
+
const {
|
|
1822
|
+
children,
|
|
1823
|
+
externalTree
|
|
1824
|
+
} = props;
|
|
1825
|
+
const tree = useRefWithInit(() => externalTree ?? new FloatingTreeStore()).current;
|
|
1826
|
+
return /*#__PURE__*/jsx(FloatingTreeContext.Provider, {
|
|
1827
|
+
value: tree,
|
|
1828
|
+
children: children
|
|
1829
|
+
});
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
/**
|
|
1833
|
+
* If the provided argument is a ref object, returns its `current` value.
|
|
1834
|
+
* Otherwise, returns the argument itself.
|
|
1835
|
+
*/
|
|
1836
|
+
function resolveRef(maybeRef) {
|
|
1837
|
+
if (maybeRef == null) {
|
|
1838
|
+
return maybeRef;
|
|
1839
|
+
}
|
|
1840
|
+
return 'current' in maybeRef ? maybeRef.current : maybeRef;
|
|
1841
|
+
}
|
|
1842
|
+
|
|
1921
1843
|
function getEventType(event, lastInteractionType) {
|
|
1922
1844
|
const win = getWindow(event.target);
|
|
1923
1845
|
if (event instanceof win.KeyboardEvent) {
|
|
@@ -3476,6 +3398,195 @@ const createSelector = (a, b, c, d, e, f, ...other) => {
|
|
|
3476
3398
|
return selector;
|
|
3477
3399
|
};
|
|
3478
3400
|
|
|
3401
|
+
var shim = {exports: {}};
|
|
3402
|
+
|
|
3403
|
+
var useSyncExternalStoreShim_production = {};
|
|
3404
|
+
|
|
3405
|
+
/**
|
|
3406
|
+
* @license React
|
|
3407
|
+
* use-sync-external-store-shim.production.js
|
|
3408
|
+
*
|
|
3409
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3410
|
+
*
|
|
3411
|
+
* This source code is licensed under the MIT license found in the
|
|
3412
|
+
* LICENSE file in the root directory of this source tree.
|
|
3413
|
+
*/
|
|
3414
|
+
|
|
3415
|
+
var hasRequiredUseSyncExternalStoreShim_production;
|
|
3416
|
+
|
|
3417
|
+
function requireUseSyncExternalStoreShim_production () {
|
|
3418
|
+
if (hasRequiredUseSyncExternalStoreShim_production) return useSyncExternalStoreShim_production;
|
|
3419
|
+
hasRequiredUseSyncExternalStoreShim_production = 1;
|
|
3420
|
+
var React = React__default;
|
|
3421
|
+
function is(x, y) {
|
|
3422
|
+
return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y);
|
|
3423
|
+
}
|
|
3424
|
+
var objectIs = "function" === typeof Object.is ? Object.is : is,
|
|
3425
|
+
useState = React.useState,
|
|
3426
|
+
useEffect = React.useEffect,
|
|
3427
|
+
useLayoutEffect = React.useLayoutEffect,
|
|
3428
|
+
useDebugValue = React.useDebugValue;
|
|
3429
|
+
function useSyncExternalStore$2(subscribe, getSnapshot) {
|
|
3430
|
+
var value = getSnapshot(),
|
|
3431
|
+
_useState = useState({ inst: { value: value, getSnapshot: getSnapshot } }),
|
|
3432
|
+
inst = _useState[0].inst,
|
|
3433
|
+
forceUpdate = _useState[1];
|
|
3434
|
+
useLayoutEffect(
|
|
3435
|
+
function () {
|
|
3436
|
+
inst.value = value;
|
|
3437
|
+
inst.getSnapshot = getSnapshot;
|
|
3438
|
+
checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
|
|
3439
|
+
},
|
|
3440
|
+
[subscribe, value, getSnapshot]
|
|
3441
|
+
);
|
|
3442
|
+
useEffect(
|
|
3443
|
+
function () {
|
|
3444
|
+
checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
|
|
3445
|
+
return subscribe(function () {
|
|
3446
|
+
checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
|
|
3447
|
+
});
|
|
3448
|
+
},
|
|
3449
|
+
[subscribe]
|
|
3450
|
+
);
|
|
3451
|
+
useDebugValue(value);
|
|
3452
|
+
return value;
|
|
3453
|
+
}
|
|
3454
|
+
function checkIfSnapshotChanged(inst) {
|
|
3455
|
+
var latestGetSnapshot = inst.getSnapshot;
|
|
3456
|
+
inst = inst.value;
|
|
3457
|
+
try {
|
|
3458
|
+
var nextValue = latestGetSnapshot();
|
|
3459
|
+
return !objectIs(inst, nextValue);
|
|
3460
|
+
} catch (error) {
|
|
3461
|
+
return !0;
|
|
3462
|
+
}
|
|
3463
|
+
}
|
|
3464
|
+
function useSyncExternalStore$1(subscribe, getSnapshot) {
|
|
3465
|
+
return getSnapshot();
|
|
3466
|
+
}
|
|
3467
|
+
var shim =
|
|
3468
|
+
"undefined" === typeof window ||
|
|
3469
|
+
"undefined" === typeof window.document ||
|
|
3470
|
+
"undefined" === typeof window.document.createElement
|
|
3471
|
+
? useSyncExternalStore$1
|
|
3472
|
+
: useSyncExternalStore$2;
|
|
3473
|
+
useSyncExternalStoreShim_production.useSyncExternalStore =
|
|
3474
|
+
void 0 !== React.useSyncExternalStore ? React.useSyncExternalStore : shim;
|
|
3475
|
+
return useSyncExternalStoreShim_production;
|
|
3476
|
+
}
|
|
3477
|
+
|
|
3478
|
+
var useSyncExternalStoreShim_development = {};
|
|
3479
|
+
|
|
3480
|
+
/**
|
|
3481
|
+
* @license React
|
|
3482
|
+
* use-sync-external-store-shim.development.js
|
|
3483
|
+
*
|
|
3484
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3485
|
+
*
|
|
3486
|
+
* This source code is licensed under the MIT license found in the
|
|
3487
|
+
* LICENSE file in the root directory of this source tree.
|
|
3488
|
+
*/
|
|
3489
|
+
|
|
3490
|
+
var hasRequiredUseSyncExternalStoreShim_development;
|
|
3491
|
+
|
|
3492
|
+
function requireUseSyncExternalStoreShim_development () {
|
|
3493
|
+
if (hasRequiredUseSyncExternalStoreShim_development) return useSyncExternalStoreShim_development;
|
|
3494
|
+
hasRequiredUseSyncExternalStoreShim_development = 1;
|
|
3495
|
+
"production" !== process.env.NODE_ENV &&
|
|
3496
|
+
(function () {
|
|
3497
|
+
function is(x, y) {
|
|
3498
|
+
return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y);
|
|
3499
|
+
}
|
|
3500
|
+
function useSyncExternalStore$2(subscribe, getSnapshot) {
|
|
3501
|
+
didWarnOld18Alpha ||
|
|
3502
|
+
void 0 === React.startTransition ||
|
|
3503
|
+
((didWarnOld18Alpha = !0),
|
|
3504
|
+
console.error(
|
|
3505
|
+
"You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."
|
|
3506
|
+
));
|
|
3507
|
+
var value = getSnapshot();
|
|
3508
|
+
if (!didWarnUncachedGetSnapshot) {
|
|
3509
|
+
var cachedValue = getSnapshot();
|
|
3510
|
+
objectIs(value, cachedValue) ||
|
|
3511
|
+
(console.error(
|
|
3512
|
+
"The result of getSnapshot should be cached to avoid an infinite loop"
|
|
3513
|
+
),
|
|
3514
|
+
(didWarnUncachedGetSnapshot = !0));
|
|
3515
|
+
}
|
|
3516
|
+
cachedValue = useState({
|
|
3517
|
+
inst: { value: value, getSnapshot: getSnapshot }
|
|
3518
|
+
});
|
|
3519
|
+
var inst = cachedValue[0].inst,
|
|
3520
|
+
forceUpdate = cachedValue[1];
|
|
3521
|
+
useLayoutEffect(
|
|
3522
|
+
function () {
|
|
3523
|
+
inst.value = value;
|
|
3524
|
+
inst.getSnapshot = getSnapshot;
|
|
3525
|
+
checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
|
|
3526
|
+
},
|
|
3527
|
+
[subscribe, value, getSnapshot]
|
|
3528
|
+
);
|
|
3529
|
+
useEffect(
|
|
3530
|
+
function () {
|
|
3531
|
+
checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
|
|
3532
|
+
return subscribe(function () {
|
|
3533
|
+
checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
|
|
3534
|
+
});
|
|
3535
|
+
},
|
|
3536
|
+
[subscribe]
|
|
3537
|
+
);
|
|
3538
|
+
useDebugValue(value);
|
|
3539
|
+
return value;
|
|
3540
|
+
}
|
|
3541
|
+
function checkIfSnapshotChanged(inst) {
|
|
3542
|
+
var latestGetSnapshot = inst.getSnapshot;
|
|
3543
|
+
inst = inst.value;
|
|
3544
|
+
try {
|
|
3545
|
+
var nextValue = latestGetSnapshot();
|
|
3546
|
+
return !objectIs(inst, nextValue);
|
|
3547
|
+
} catch (error) {
|
|
3548
|
+
return !0;
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3551
|
+
function useSyncExternalStore$1(subscribe, getSnapshot) {
|
|
3552
|
+
return getSnapshot();
|
|
3553
|
+
}
|
|
3554
|
+
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
|
|
3555
|
+
"function" ===
|
|
3556
|
+
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart &&
|
|
3557
|
+
__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
|
|
3558
|
+
var React = React__default,
|
|
3559
|
+
objectIs = "function" === typeof Object.is ? Object.is : is,
|
|
3560
|
+
useState = React.useState,
|
|
3561
|
+
useEffect = React.useEffect,
|
|
3562
|
+
useLayoutEffect = React.useLayoutEffect,
|
|
3563
|
+
useDebugValue = React.useDebugValue,
|
|
3564
|
+
didWarnOld18Alpha = !1,
|
|
3565
|
+
didWarnUncachedGetSnapshot = !1,
|
|
3566
|
+
shim =
|
|
3567
|
+
"undefined" === typeof window ||
|
|
3568
|
+
"undefined" === typeof window.document ||
|
|
3569
|
+
"undefined" === typeof window.document.createElement
|
|
3570
|
+
? useSyncExternalStore$1
|
|
3571
|
+
: useSyncExternalStore$2;
|
|
3572
|
+
useSyncExternalStoreShim_development.useSyncExternalStore =
|
|
3573
|
+
void 0 !== React.useSyncExternalStore ? React.useSyncExternalStore : shim;
|
|
3574
|
+
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
|
|
3575
|
+
"function" ===
|
|
3576
|
+
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&
|
|
3577
|
+
__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
|
|
3578
|
+
})();
|
|
3579
|
+
return useSyncExternalStoreShim_development;
|
|
3580
|
+
}
|
|
3581
|
+
|
|
3582
|
+
if (process.env.NODE_ENV === 'production') {
|
|
3583
|
+
shim.exports = requireUseSyncExternalStoreShim_production();
|
|
3584
|
+
} else {
|
|
3585
|
+
shim.exports = requireUseSyncExternalStoreShim_development();
|
|
3586
|
+
}
|
|
3587
|
+
|
|
3588
|
+
var shimExports = shim.exports;
|
|
3589
|
+
|
|
3479
3590
|
var withSelector = {exports: {}};
|
|
3480
3591
|
|
|
3481
3592
|
var withSelector_production = {};
|
|
@@ -3686,6 +3797,45 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
3686
3797
|
|
|
3687
3798
|
var withSelectorExports = withSelector.exports;
|
|
3688
3799
|
|
|
3800
|
+
const hooks = [];
|
|
3801
|
+
let currentInstance = undefined;
|
|
3802
|
+
function getInstance() {
|
|
3803
|
+
return currentInstance;
|
|
3804
|
+
}
|
|
3805
|
+
function register(hook) {
|
|
3806
|
+
hooks.push(hook);
|
|
3807
|
+
}
|
|
3808
|
+
function fastComponent(fn) {
|
|
3809
|
+
const FastComponent = (props, forwardedRef) => {
|
|
3810
|
+
const instance = useRefWithInit(createInstance).current;
|
|
3811
|
+
let result;
|
|
3812
|
+
try {
|
|
3813
|
+
currentInstance = instance;
|
|
3814
|
+
for (const hook of hooks) {
|
|
3815
|
+
hook.before(instance);
|
|
3816
|
+
}
|
|
3817
|
+
result = fn(props, forwardedRef);
|
|
3818
|
+
for (const hook of hooks) {
|
|
3819
|
+
hook.after(instance);
|
|
3820
|
+
}
|
|
3821
|
+
instance.didInitialize = true;
|
|
3822
|
+
} finally {
|
|
3823
|
+
currentInstance = undefined;
|
|
3824
|
+
}
|
|
3825
|
+
return result;
|
|
3826
|
+
};
|
|
3827
|
+
FastComponent.displayName = fn.displayName || fn.name;
|
|
3828
|
+
return FastComponent;
|
|
3829
|
+
}
|
|
3830
|
+
function fastComponentRef(fn) {
|
|
3831
|
+
return /*#__PURE__*/React.forwardRef(fastComponent(fn));
|
|
3832
|
+
}
|
|
3833
|
+
function createInstance() {
|
|
3834
|
+
return {
|
|
3835
|
+
didInitialize: false
|
|
3836
|
+
};
|
|
3837
|
+
}
|
|
3838
|
+
|
|
3689
3839
|
/* Some tests fail in R18 with the raw useSyncExternalStore. It may be possible to make it work
|
|
3690
3840
|
* but for now we only enable it for R19+. */
|
|
3691
3841
|
const canUseRawUseSyncExternalStore = isReactVersionAtLeast(19);
|
|
@@ -3697,11 +3847,91 @@ function useStoreR19(store, selector, a1, a2, a3) {
|
|
|
3697
3847
|
const getSelection = React.useCallback(() => selector(store.getSnapshot(), a1, a2, a3), [store, selector, a1, a2, a3]);
|
|
3698
3848
|
return shimExports.useSyncExternalStore(store.subscribe, getSelection, getSelection);
|
|
3699
3849
|
}
|
|
3850
|
+
register({
|
|
3851
|
+
before(instance) {
|
|
3852
|
+
instance.syncIndex = 0;
|
|
3853
|
+
if (!instance.didInitialize) {
|
|
3854
|
+
instance.syncTick = 1;
|
|
3855
|
+
instance.syncHooks = [];
|
|
3856
|
+
instance.didChangeStore = true;
|
|
3857
|
+
instance.getSnapshot = () => {
|
|
3858
|
+
let didChange = false;
|
|
3859
|
+
for (let i = 0; i < instance.syncHooks.length; i += 1) {
|
|
3860
|
+
const hook = instance.syncHooks[i];
|
|
3861
|
+
const value = hook.selector(hook.store.state, hook.a1, hook.a2, hook.a3);
|
|
3862
|
+
if (hook.didChange || !Object.is(hook.value, value)) {
|
|
3863
|
+
didChange = true;
|
|
3864
|
+
hook.value = value;
|
|
3865
|
+
hook.didChange = false;
|
|
3866
|
+
}
|
|
3867
|
+
}
|
|
3868
|
+
if (didChange) {
|
|
3869
|
+
instance.syncTick += 1;
|
|
3870
|
+
}
|
|
3871
|
+
return instance.syncTick;
|
|
3872
|
+
};
|
|
3873
|
+
}
|
|
3874
|
+
},
|
|
3875
|
+
after(instance) {
|
|
3876
|
+
if (instance.syncHooks.length > 0) {
|
|
3877
|
+
if (instance.didChangeStore) {
|
|
3878
|
+
instance.didChangeStore = false;
|
|
3879
|
+
instance.subscribe = onStoreChange => {
|
|
3880
|
+
const stores = new Set();
|
|
3881
|
+
for (const hook of instance.syncHooks) {
|
|
3882
|
+
stores.add(hook.store);
|
|
3883
|
+
}
|
|
3884
|
+
const unsubscribes = [];
|
|
3885
|
+
for (const store of stores) {
|
|
3886
|
+
unsubscribes.push(store.subscribe(onStoreChange));
|
|
3887
|
+
}
|
|
3888
|
+
return () => {
|
|
3889
|
+
for (const unsubscribe of unsubscribes) {
|
|
3890
|
+
unsubscribe();
|
|
3891
|
+
}
|
|
3892
|
+
};
|
|
3893
|
+
};
|
|
3894
|
+
}
|
|
3895
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
3896
|
+
shimExports.useSyncExternalStore(instance.subscribe, instance.getSnapshot, instance.getSnapshot);
|
|
3897
|
+
}
|
|
3898
|
+
}
|
|
3899
|
+
});
|
|
3700
3900
|
function useStoreFast(store, selector, a1, a2, a3) {
|
|
3701
|
-
|
|
3901
|
+
const instance = getInstance();
|
|
3902
|
+
if (!instance) {
|
|
3702
3903
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
3703
3904
|
return useStoreR19(store, selector, a1, a2, a3);
|
|
3704
3905
|
}
|
|
3906
|
+
const index = instance.syncIndex;
|
|
3907
|
+
instance.syncIndex += 1;
|
|
3908
|
+
let hook;
|
|
3909
|
+
if (!instance.didInitialize) {
|
|
3910
|
+
hook = {
|
|
3911
|
+
store,
|
|
3912
|
+
selector,
|
|
3913
|
+
a1,
|
|
3914
|
+
a2,
|
|
3915
|
+
a3,
|
|
3916
|
+
value: selector(store.getSnapshot(), a1, a2, a3),
|
|
3917
|
+
didChange: false
|
|
3918
|
+
};
|
|
3919
|
+
instance.syncHooks.push(hook);
|
|
3920
|
+
} else {
|
|
3921
|
+
hook = instance.syncHooks[index];
|
|
3922
|
+
if (hook.store !== store || hook.selector !== selector || !Object.is(hook.a1, a1) || !Object.is(hook.a2, a2) || !Object.is(hook.a3, a3)) {
|
|
3923
|
+
if (hook.store !== store) {
|
|
3924
|
+
instance.didChangeStore = true;
|
|
3925
|
+
}
|
|
3926
|
+
hook.store = store;
|
|
3927
|
+
hook.selector = selector;
|
|
3928
|
+
hook.a1 = a1;
|
|
3929
|
+
hook.a2 = a2;
|
|
3930
|
+
hook.a3 = a3;
|
|
3931
|
+
hook.didChange = true;
|
|
3932
|
+
}
|
|
3933
|
+
}
|
|
3934
|
+
return hook.value;
|
|
3705
3935
|
}
|
|
3706
3936
|
function useStoreLegacy(store, selector, a1, a2, a3) {
|
|
3707
3937
|
return withSelectorExports.useSyncExternalStoreWithSelector(store.subscribe, store.getSnapshot, store.getSnapshot, state => selector(state, a1, a2, a3));
|
|
@@ -4070,40 +4300,212 @@ class FloatingRootStore extends ReactStore {
|
|
|
4070
4300
|
}
|
|
4071
4301
|
|
|
4072
4302
|
/**
|
|
4073
|
-
*
|
|
4074
|
-
*
|
|
4075
|
-
* @param
|
|
4303
|
+
* Provides a status string for CSS animations.
|
|
4304
|
+
* @param open - a boolean that determines if the element is open.
|
|
4305
|
+
* @param enableIdleState - a boolean that enables the `'idle'` state between `'starting'` and `'ending'`
|
|
4076
4306
|
*/
|
|
4077
|
-
function
|
|
4078
|
-
|
|
4079
|
-
const
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4307
|
+
function useTransitionStatus(open, enableIdleState = false, deferEndingState = false) {
|
|
4308
|
+
const [transitionStatus, setTransitionStatus] = React.useState(open && enableIdleState ? 'idle' : undefined);
|
|
4309
|
+
const [mounted, setMounted] = React.useState(open);
|
|
4310
|
+
if (open && !mounted) {
|
|
4311
|
+
setMounted(true);
|
|
4312
|
+
setTransitionStatus('starting');
|
|
4313
|
+
}
|
|
4314
|
+
if (!open && mounted && transitionStatus !== 'ending' && !deferEndingState) {
|
|
4315
|
+
setTransitionStatus('ending');
|
|
4316
|
+
}
|
|
4317
|
+
if (!open && !mounted && transitionStatus === 'ending') {
|
|
4318
|
+
setTransitionStatus(undefined);
|
|
4319
|
+
}
|
|
4320
|
+
useIsoLayoutEffect(() => {
|
|
4321
|
+
if (!open && mounted && transitionStatus !== 'ending' && deferEndingState) {
|
|
4322
|
+
const frame = AnimationFrame.request(() => {
|
|
4323
|
+
setTransitionStatus('ending');
|
|
4324
|
+
});
|
|
4325
|
+
return () => {
|
|
4326
|
+
AnimationFrame.cancel(frame);
|
|
4327
|
+
};
|
|
4084
4328
|
}
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
store.context.triggerElements.delete(registeredId);
|
|
4091
|
-
}
|
|
4092
|
-
registeredElementIdRef.current = null;
|
|
4093
|
-
registeredElementRef.current = null;
|
|
4329
|
+
return undefined;
|
|
4330
|
+
}, [open, mounted, transitionStatus, deferEndingState]);
|
|
4331
|
+
useIsoLayoutEffect(() => {
|
|
4332
|
+
if (!open || enableIdleState) {
|
|
4333
|
+
return undefined;
|
|
4094
4334
|
}
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4335
|
+
const frame = AnimationFrame.request(() => {
|
|
4336
|
+
// Avoid `flushSync` here due to Firefox.
|
|
4337
|
+
// See https://github.com/mui/base-ui/pull/3424
|
|
4338
|
+
setTransitionStatus(undefined);
|
|
4339
|
+
});
|
|
4340
|
+
return () => {
|
|
4341
|
+
AnimationFrame.cancel(frame);
|
|
4342
|
+
};
|
|
4343
|
+
}, [enableIdleState, open]);
|
|
4344
|
+
useIsoLayoutEffect(() => {
|
|
4345
|
+
if (!open || !enableIdleState) {
|
|
4346
|
+
return undefined;
|
|
4099
4347
|
}
|
|
4100
|
-
|
|
4348
|
+
if (open && mounted && transitionStatus !== 'idle') {
|
|
4349
|
+
setTransitionStatus('starting');
|
|
4350
|
+
}
|
|
4351
|
+
const frame = AnimationFrame.request(() => {
|
|
4352
|
+
setTransitionStatus('idle');
|
|
4353
|
+
});
|
|
4354
|
+
return () => {
|
|
4355
|
+
AnimationFrame.cancel(frame);
|
|
4356
|
+
};
|
|
4357
|
+
}, [enableIdleState, open, mounted, setTransitionStatus, transitionStatus]);
|
|
4358
|
+
return React.useMemo(() => ({
|
|
4359
|
+
mounted,
|
|
4360
|
+
setMounted,
|
|
4361
|
+
transitionStatus
|
|
4362
|
+
}), [mounted, transitionStatus]);
|
|
4101
4363
|
}
|
|
4102
4364
|
|
|
4103
4365
|
/**
|
|
4104
|
-
*
|
|
4105
|
-
*
|
|
4106
|
-
* @param
|
|
4366
|
+
* Executes a function once all animations have finished on the provided element.
|
|
4367
|
+
* @param elementOrRef - The element to watch for animations.
|
|
4368
|
+
* @param waitForStartingStyleRemoved - Whether to wait for [data-starting-style] to be removed before checking for animations.
|
|
4369
|
+
* @param treatAbortedAsFinished - Whether to treat aborted animations as finished. If `false`, and there are aborted animations,
|
|
4370
|
+
* the function will check again if any new animations have started and wait for them to finish.
|
|
4371
|
+
* @returns A function that takes a callback to execute once all animations have finished, and an optional AbortSignal to abort the callback
|
|
4372
|
+
*/
|
|
4373
|
+
function useAnimationsFinished(elementOrRef, waitForStartingStyleRemoved = false, treatAbortedAsFinished = true) {
|
|
4374
|
+
const frame = useAnimationFrame();
|
|
4375
|
+
return useStableCallback((fnToExecute,
|
|
4376
|
+
/**
|
|
4377
|
+
* An optional [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) that
|
|
4378
|
+
* can be used to abort `fnToExecute` before all the animations have finished.
|
|
4379
|
+
* @default null
|
|
4380
|
+
*/
|
|
4381
|
+
signal = null) => {
|
|
4382
|
+
frame.cancel();
|
|
4383
|
+
function done() {
|
|
4384
|
+
// Synchronously flush the unmounting of the component so that the browser doesn't
|
|
4385
|
+
// paint: https://github.com/mui/base-ui/issues/979
|
|
4386
|
+
ReactDOM.flushSync(fnToExecute);
|
|
4387
|
+
}
|
|
4388
|
+
const element = resolveRef(elementOrRef);
|
|
4389
|
+
if (element == null) {
|
|
4390
|
+
return;
|
|
4391
|
+
}
|
|
4392
|
+
const resolvedElement = element;
|
|
4393
|
+
if (typeof resolvedElement.getAnimations !== 'function' || globalThis.BASE_UI_ANIMATIONS_DISABLED) {
|
|
4394
|
+
fnToExecute();
|
|
4395
|
+
} else {
|
|
4396
|
+
function execWaitForStartingStyleRemoved() {
|
|
4397
|
+
const startingStyleAttribute = TransitionStatusDataAttributes.startingStyle;
|
|
4398
|
+
|
|
4399
|
+
// If `[data-starting-style]` isn't present, fall back to waiting one more frame
|
|
4400
|
+
// to give "open" animations a chance to be registered.
|
|
4401
|
+
if (!resolvedElement.hasAttribute(startingStyleAttribute)) {
|
|
4402
|
+
frame.request(exec);
|
|
4403
|
+
return;
|
|
4404
|
+
}
|
|
4405
|
+
|
|
4406
|
+
// Wait for `[data-starting-style]` to have been removed.
|
|
4407
|
+
const attributeObserver = new MutationObserver(() => {
|
|
4408
|
+
if (!resolvedElement.hasAttribute(startingStyleAttribute)) {
|
|
4409
|
+
attributeObserver.disconnect();
|
|
4410
|
+
exec();
|
|
4411
|
+
}
|
|
4412
|
+
});
|
|
4413
|
+
attributeObserver.observe(resolvedElement, {
|
|
4414
|
+
attributes: true,
|
|
4415
|
+
attributeFilter: [startingStyleAttribute]
|
|
4416
|
+
});
|
|
4417
|
+
signal?.addEventListener('abort', () => attributeObserver.disconnect(), {
|
|
4418
|
+
once: true
|
|
4419
|
+
});
|
|
4420
|
+
}
|
|
4421
|
+
function exec() {
|
|
4422
|
+
Promise.all(resolvedElement.getAnimations().map(anim => anim.finished)).then(() => {
|
|
4423
|
+
if (signal?.aborted) {
|
|
4424
|
+
return;
|
|
4425
|
+
}
|
|
4426
|
+
done();
|
|
4427
|
+
}).catch(() => {
|
|
4428
|
+
const currentAnimations = resolvedElement.getAnimations();
|
|
4429
|
+
if (treatAbortedAsFinished) {
|
|
4430
|
+
if (signal?.aborted) {
|
|
4431
|
+
return;
|
|
4432
|
+
}
|
|
4433
|
+
done();
|
|
4434
|
+
} else if (currentAnimations.length > 0 && currentAnimations.some(anim => anim.pending || anim.playState !== 'finished')) {
|
|
4435
|
+
// Sometimes animations can be aborted because a property they depend on changes while the animation plays.
|
|
4436
|
+
// In such cases, we need to re-check if any new animations have started.
|
|
4437
|
+
exec();
|
|
4438
|
+
}
|
|
4439
|
+
});
|
|
4440
|
+
}
|
|
4441
|
+
if (waitForStartingStyleRemoved) {
|
|
4442
|
+
execWaitForStartingStyleRemoved();
|
|
4443
|
+
return;
|
|
4444
|
+
}
|
|
4445
|
+
frame.request(exec);
|
|
4446
|
+
}
|
|
4447
|
+
});
|
|
4448
|
+
}
|
|
4449
|
+
|
|
4450
|
+
/**
|
|
4451
|
+
* Calls the provided function when the CSS open/close animation or transition completes.
|
|
4452
|
+
*/
|
|
4453
|
+
function useOpenChangeComplete(parameters) {
|
|
4454
|
+
const {
|
|
4455
|
+
enabled = true,
|
|
4456
|
+
open,
|
|
4457
|
+
ref,
|
|
4458
|
+
onComplete: onCompleteParam
|
|
4459
|
+
} = parameters;
|
|
4460
|
+
const onComplete = useStableCallback(onCompleteParam);
|
|
4461
|
+
const runOnceAnimationsFinish = useAnimationsFinished(ref, open, false);
|
|
4462
|
+
React.useEffect(() => {
|
|
4463
|
+
if (!enabled) {
|
|
4464
|
+
return undefined;
|
|
4465
|
+
}
|
|
4466
|
+
const abortController = new AbortController();
|
|
4467
|
+
runOnceAnimationsFinish(onComplete, abortController.signal);
|
|
4468
|
+
return () => {
|
|
4469
|
+
abortController.abort();
|
|
4470
|
+
};
|
|
4471
|
+
}, [enabled, open, onComplete, runOnceAnimationsFinish]);
|
|
4472
|
+
}
|
|
4473
|
+
|
|
4474
|
+
/**
|
|
4475
|
+
* Returns a callback ref that registers/unregisters the trigger element in the store.
|
|
4476
|
+
*
|
|
4477
|
+
* @param store The Store instance where the trigger should be registered.
|
|
4478
|
+
*/
|
|
4479
|
+
function useTriggerRegistration(id, store) {
|
|
4480
|
+
// Keep track of the currently registered element to unregister it on unmount or id change.
|
|
4481
|
+
const registeredElementIdRef = React.useRef(null);
|
|
4482
|
+
const registeredElementRef = React.useRef(null);
|
|
4483
|
+
return React.useCallback(element => {
|
|
4484
|
+
if (id === undefined) {
|
|
4485
|
+
return;
|
|
4486
|
+
}
|
|
4487
|
+
if (registeredElementIdRef.current !== null) {
|
|
4488
|
+
const registeredId = registeredElementIdRef.current;
|
|
4489
|
+
const registeredElement = registeredElementRef.current;
|
|
4490
|
+
const currentElement = store.context.triggerElements.getById(registeredId);
|
|
4491
|
+
if (registeredElement && currentElement === registeredElement) {
|
|
4492
|
+
store.context.triggerElements.delete(registeredId);
|
|
4493
|
+
}
|
|
4494
|
+
registeredElementIdRef.current = null;
|
|
4495
|
+
registeredElementRef.current = null;
|
|
4496
|
+
}
|
|
4497
|
+
if (element !== null) {
|
|
4498
|
+
registeredElementIdRef.current = id;
|
|
4499
|
+
registeredElementRef.current = element;
|
|
4500
|
+
store.context.triggerElements.add(id, element);
|
|
4501
|
+
}
|
|
4502
|
+
}, [store, id]);
|
|
4503
|
+
}
|
|
4504
|
+
|
|
4505
|
+
/**
|
|
4506
|
+
* Sets up trigger data forwarding to the store.
|
|
4507
|
+
*
|
|
4508
|
+
* @param triggerId Id of the trigger.
|
|
4107
4509
|
* @param triggerElement The trigger DOM element.
|
|
4108
4510
|
* @param store The Store instance managing the popup state.
|
|
4109
4511
|
* @param stateUpdates An object with state updates to apply when the trigger is active.
|
|
@@ -4204,6 +4606,7 @@ function useOpenStateTransitions(open, store, onUnmount) {
|
|
|
4204
4606
|
activeTriggerElement: null,
|
|
4205
4607
|
mounted: false
|
|
4206
4608
|
});
|
|
4609
|
+
onUnmount?.();
|
|
4207
4610
|
store.context.onOpenChangeComplete?.(false);
|
|
4208
4611
|
});
|
|
4209
4612
|
const preventUnmountingOnClose = store.useState('preventUnmountingOnClose');
|
|
@@ -4625,1083 +5028,426 @@ function useRole(context, props = {}) {
|
|
|
4625
5028
|
}), [reference, floating, trigger, item]);
|
|
4626
5029
|
}
|
|
4627
5030
|
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
5031
|
+
let DrawerPopupDataAttributes = function (DrawerPopupDataAttributes) {
|
|
5032
|
+
/**
|
|
5033
|
+
* Present when the drawer is open.
|
|
5034
|
+
*/
|
|
5035
|
+
DrawerPopupDataAttributes[DrawerPopupDataAttributes["open"] = CommonPopupDataAttributes.open] = "open";
|
|
5036
|
+
/**
|
|
5037
|
+
* Present when the drawer is closed.
|
|
5038
|
+
*/
|
|
5039
|
+
DrawerPopupDataAttributes[DrawerPopupDataAttributes["closed"] = CommonPopupDataAttributes.closed] = "closed";
|
|
5040
|
+
/**
|
|
5041
|
+
* Present when the drawer is animating in.
|
|
5042
|
+
*/
|
|
5043
|
+
DrawerPopupDataAttributes[DrawerPopupDataAttributes["startingStyle"] = CommonPopupDataAttributes.startingStyle] = "startingStyle";
|
|
5044
|
+
/**
|
|
5045
|
+
* Present when the drawer is animating out.
|
|
5046
|
+
*/
|
|
5047
|
+
DrawerPopupDataAttributes[DrawerPopupDataAttributes["endingStyle"] = CommonPopupDataAttributes.endingStyle] = "endingStyle";
|
|
5048
|
+
/**
|
|
5049
|
+
* Present when the drawer is at the expanded (full-height) snap point.
|
|
5050
|
+
*/
|
|
5051
|
+
DrawerPopupDataAttributes["expanded"] = "data-expanded";
|
|
5052
|
+
/**
|
|
5053
|
+
* Present when a nested drawer is open.
|
|
5054
|
+
*/
|
|
5055
|
+
DrawerPopupDataAttributes["nestedDrawerOpen"] = "data-nested-drawer-open";
|
|
5056
|
+
/**
|
|
5057
|
+
* Present when a nested drawer is being swiped.
|
|
5058
|
+
*/
|
|
5059
|
+
DrawerPopupDataAttributes["nestedDrawerSwiping"] = "data-nested-drawer-swiping";
|
|
5060
|
+
/**
|
|
5061
|
+
* Present when the drawer is dismissed by swiping.
|
|
5062
|
+
*/
|
|
5063
|
+
DrawerPopupDataAttributes["swipeDismiss"] = "data-swipe-dismiss";
|
|
5064
|
+
/**
|
|
5065
|
+
* Indicates the swipe direction.
|
|
5066
|
+
* @type {'up' | 'down' | 'left' | 'right'}
|
|
5067
|
+
*/
|
|
5068
|
+
DrawerPopupDataAttributes["swipeDirection"] = "data-swipe-direction";
|
|
5069
|
+
/**
|
|
5070
|
+
* Present when the drawer is being swiped.
|
|
5071
|
+
*/
|
|
5072
|
+
DrawerPopupDataAttributes["swiping"] = "data-swiping";
|
|
5073
|
+
return DrawerPopupDataAttributes;
|
|
5074
|
+
}({});
|
|
4663
5075
|
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
}, [value, onChangeCallback]);
|
|
4673
|
-
useIsoLayoutEffect(() => {
|
|
4674
|
-
valueRef.current = value;
|
|
4675
|
-
}, [value]);
|
|
5076
|
+
const DialogPortalContext = /*#__PURE__*/React.createContext(undefined);
|
|
5077
|
+
if (process.env.NODE_ENV !== "production") DialogPortalContext.displayName = "DialogPortalContext";
|
|
5078
|
+
function useDialogPortalContext() {
|
|
5079
|
+
const value = React.useContext(DialogPortalContext);
|
|
5080
|
+
if (value === undefined) {
|
|
5081
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: <Dialog.Portal> is missing.' : formatErrorMessage(26));
|
|
5082
|
+
}
|
|
5083
|
+
return value;
|
|
4676
5084
|
}
|
|
4677
5085
|
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
5086
|
+
const ARROW_UP = 'ArrowUp';
|
|
5087
|
+
const ARROW_DOWN = 'ArrowDown';
|
|
5088
|
+
const ARROW_LEFT = 'ArrowLeft';
|
|
5089
|
+
const ARROW_RIGHT = 'ArrowRight';
|
|
5090
|
+
const HOME = 'Home';
|
|
5091
|
+
const END = 'End';
|
|
5092
|
+
const HORIZONTAL_KEYS = new Set([ARROW_LEFT, ARROW_RIGHT]);
|
|
5093
|
+
const VERTICAL_KEYS = new Set([ARROW_UP, ARROW_DOWN]);
|
|
5094
|
+
const ARROW_KEYS = new Set([...HORIZONTAL_KEYS, ...VERTICAL_KEYS]);
|
|
5095
|
+
new Set([...ARROW_KEYS, HOME, END]);
|
|
5096
|
+
const COMPOSITE_KEYS = new Set([ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT, HOME, END]);
|
|
5097
|
+
|
|
5098
|
+
const DrawerRootContext = /*#__PURE__*/React.createContext(undefined);
|
|
5099
|
+
if (process.env.NODE_ENV !== "production") DrawerRootContext.displayName = "DrawerRootContext";
|
|
5100
|
+
function useDrawerRootContext(optional) {
|
|
5101
|
+
const drawerRootContext = React.useContext(DrawerRootContext);
|
|
5102
|
+
if (optional === false && drawerRootContext === undefined) {
|
|
5103
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: DrawerRootContext is missing. Drawer parts must be placed within <Drawer.Root>.' : formatErrorMessage(90));
|
|
5104
|
+
}
|
|
5105
|
+
return drawerRootContext;
|
|
5106
|
+
}
|
|
5107
|
+
|
|
5108
|
+
function clamp(val, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) {
|
|
5109
|
+
return Math.max(min, Math.min(val, max));
|
|
5110
|
+
}
|
|
5111
|
+
|
|
5112
|
+
function resolveSnapPointValue(snapPoint, viewportHeight, rootFontSize) {
|
|
5113
|
+
if (!Number.isFinite(viewportHeight) || viewportHeight <= 0) {
|
|
5114
|
+
return null;
|
|
5115
|
+
}
|
|
5116
|
+
if (typeof snapPoint === 'number') {
|
|
5117
|
+
if (!Number.isFinite(snapPoint)) {
|
|
5118
|
+
return null;
|
|
4692
5119
|
}
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
if (previousOpen && !open) {
|
|
4696
|
-
setOpenMethod(null);
|
|
5120
|
+
if (snapPoint <= 1) {
|
|
5121
|
+
return clamp(snapPoint, 0, 1) * viewportHeight;
|
|
4697
5122
|
}
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
5123
|
+
return snapPoint;
|
|
5124
|
+
}
|
|
5125
|
+
const trimmed = snapPoint.trim();
|
|
5126
|
+
if (trimmed.endsWith('px')) {
|
|
5127
|
+
const value = Number.parseFloat(trimmed);
|
|
5128
|
+
return Number.isFinite(value) ? value : null;
|
|
5129
|
+
}
|
|
5130
|
+
if (trimmed.endsWith('rem')) {
|
|
5131
|
+
const value = Number.parseFloat(trimmed);
|
|
5132
|
+
return Number.isFinite(value) ? value * rootFontSize : null;
|
|
5133
|
+
}
|
|
5134
|
+
return null;
|
|
5135
|
+
}
|
|
5136
|
+
function findClosestSnapPoint(height, points) {
|
|
5137
|
+
let closest = null;
|
|
5138
|
+
let closestDistance = Infinity;
|
|
5139
|
+
for (const point of points) {
|
|
5140
|
+
const distance = Math.abs(point.height - height);
|
|
5141
|
+
if (distance < closestDistance) {
|
|
5142
|
+
closestDistance = distance;
|
|
5143
|
+
closest = point;
|
|
4708
5144
|
}
|
|
4709
|
-
}
|
|
5145
|
+
}
|
|
5146
|
+
return closest;
|
|
4710
5147
|
}
|
|
4711
|
-
|
|
4712
|
-
function useDialogRoot(params) {
|
|
4713
|
-
const {
|
|
4714
|
-
store,
|
|
4715
|
-
parentContext,
|
|
4716
|
-
actionsRef
|
|
4717
|
-
} = params;
|
|
4718
|
-
const open = store.useState('open');
|
|
4719
|
-
const disablePointerDismissal = store.useState('disablePointerDismissal');
|
|
4720
|
-
const modal = store.useState('modal');
|
|
4721
|
-
const popupElement = store.useState('popupElement');
|
|
5148
|
+
function useDrawerSnapPoints() {
|
|
4722
5149
|
const {
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
} = useOpenInteractionType(open);
|
|
4726
|
-
useImplicitActiveTrigger(store);
|
|
5150
|
+
store
|
|
5151
|
+
} = useDialogRootContext();
|
|
4727
5152
|
const {
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
5153
|
+
snapPoints,
|
|
5154
|
+
activeSnapPoint,
|
|
5155
|
+
setActiveSnapPoint,
|
|
5156
|
+
popupHeight
|
|
5157
|
+
} = useDrawerRootContext();
|
|
5158
|
+
const viewportElement = store.useState('viewportElement');
|
|
5159
|
+
const [viewportHeight, setViewportHeight] = React.useState(0);
|
|
5160
|
+
const [rootFontSize, setRootFontSize] = React.useState(16);
|
|
5161
|
+
const measureViewportHeight = useStableCallback(() => {
|
|
5162
|
+
const doc = ownerDocument(viewportElement);
|
|
5163
|
+
const html = doc.documentElement;
|
|
5164
|
+
if (viewportElement) {
|
|
5165
|
+
setViewportHeight(viewportElement.offsetHeight);
|
|
5166
|
+
}
|
|
5167
|
+
if (!viewportElement) {
|
|
5168
|
+
setViewportHeight(html.clientHeight);
|
|
5169
|
+
}
|
|
5170
|
+
const fontSize = parseFloat(getComputedStyle(html).fontSize);
|
|
5171
|
+
if (Number.isFinite(fontSize)) {
|
|
5172
|
+
setRootFontSize(fontSize);
|
|
5173
|
+
}
|
|
4749
5174
|
});
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
5175
|
+
useIsoLayoutEffect(() => {
|
|
5176
|
+
measureViewportHeight();
|
|
5177
|
+
if (!viewportElement || typeof ResizeObserver !== 'function') {
|
|
5178
|
+
return undefined;
|
|
5179
|
+
}
|
|
5180
|
+
const resizeObserver = new ResizeObserver(measureViewportHeight);
|
|
5181
|
+
resizeObserver.observe(viewportElement);
|
|
5182
|
+
return () => {
|
|
5183
|
+
resizeObserver.disconnect();
|
|
5184
|
+
};
|
|
5185
|
+
}, [measureViewportHeight, viewportElement]);
|
|
5186
|
+
const resolvedSnapPoints = React.useMemo(() => {
|
|
5187
|
+
if (!snapPoints || snapPoints.length === 0 || viewportHeight <= 0 || popupHeight <= 0) {
|
|
5188
|
+
return [];
|
|
5189
|
+
}
|
|
5190
|
+
const maxHeight = Math.min(popupHeight, viewportHeight);
|
|
5191
|
+
if (!Number.isFinite(maxHeight) || maxHeight <= 0) {
|
|
5192
|
+
return [];
|
|
5193
|
+
}
|
|
5194
|
+
const resolved = snapPoints.map(value => {
|
|
5195
|
+
const resolvedHeight = resolveSnapPointValue(value, viewportHeight, rootFontSize);
|
|
5196
|
+
if (resolvedHeight === null || !Number.isFinite(resolvedHeight)) {
|
|
5197
|
+
return null;
|
|
4757
5198
|
}
|
|
4758
|
-
|
|
4759
|
-
// on outside press when trapping focus.
|
|
5199
|
+
const clampedHeight = clamp(resolvedHeight, 0, maxHeight);
|
|
4760
5200
|
return {
|
|
4761
|
-
|
|
4762
|
-
|
|
5201
|
+
value,
|
|
5202
|
+
height: clampedHeight,
|
|
5203
|
+
offset: Math.max(0, popupHeight - clampedHeight)
|
|
4763
5204
|
};
|
|
4764
|
-
}
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
if ('touches' in event && event.touches.length !== 1) {
|
|
4776
|
-
return false;
|
|
4777
|
-
}
|
|
4778
|
-
const target = getTarget(event);
|
|
4779
|
-
if (isTopmost && !disablePointerDismissal) {
|
|
4780
|
-
const eventTarget = target;
|
|
4781
|
-
// Only close if the click occurred on the dialog's owning backdrop.
|
|
4782
|
-
// This supports multiple modal dialogs that aren't nested in the React tree:
|
|
4783
|
-
// https://github.com/mui/base-ui/issues/1320
|
|
4784
|
-
if (modal) {
|
|
4785
|
-
return store.context.internalBackdropRef.current || store.context.backdropRef.current ? store.context.internalBackdropRef.current === eventTarget || store.context.backdropRef.current === eventTarget || contains(eventTarget, popupElement) && !eventTarget?.hasAttribute('data-base-ui-portal') : true;
|
|
4786
|
-
}
|
|
4787
|
-
return true;
|
|
5205
|
+
}).filter(point => Boolean(point));
|
|
5206
|
+
if (resolved.length <= 1) {
|
|
5207
|
+
return resolved;
|
|
5208
|
+
}
|
|
5209
|
+
const deduped = [];
|
|
5210
|
+
const seenHeights = [];
|
|
5211
|
+
for (let index = resolved.length - 1; index >= 0; index -= 1) {
|
|
5212
|
+
const point = resolved[index];
|
|
5213
|
+
const isDuplicate = seenHeights.some(height => Math.abs(height - point.height) <= 1);
|
|
5214
|
+
if (isDuplicate) {
|
|
5215
|
+
continue;
|
|
4788
5216
|
}
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
escapeKey: isTopmost
|
|
4792
|
-
});
|
|
4793
|
-
useScrollLock(open && modal === true, popupElement);
|
|
4794
|
-
const {
|
|
4795
|
-
getReferenceProps,
|
|
4796
|
-
getFloatingProps,
|
|
4797
|
-
getTriggerProps
|
|
4798
|
-
} = useInteractions([role, dismiss]);
|
|
4799
|
-
|
|
4800
|
-
// Listen for nested open/close events on this store to maintain the count
|
|
4801
|
-
store.useContextCallback('onNestedDialogOpen', ownChildrenCount => {
|
|
4802
|
-
setOwnNestedOpenDialogs(ownChildrenCount + 1);
|
|
4803
|
-
});
|
|
4804
|
-
store.useContextCallback('onNestedDialogClose', () => {
|
|
4805
|
-
setOwnNestedOpenDialogs(0);
|
|
4806
|
-
});
|
|
4807
|
-
|
|
4808
|
-
// Notify parent of our open/close state using parent callbacks, if any
|
|
4809
|
-
React.useEffect(() => {
|
|
4810
|
-
if (parentContext?.onNestedDialogOpen && open) {
|
|
4811
|
-
parentContext.onNestedDialogOpen(ownNestedOpenDialogs);
|
|
5217
|
+
seenHeights.push(point.height);
|
|
5218
|
+
deduped.push(point);
|
|
4812
5219
|
}
|
|
4813
|
-
|
|
4814
|
-
|
|
5220
|
+
deduped.reverse();
|
|
5221
|
+
return deduped;
|
|
5222
|
+
}, [popupHeight, rootFontSize, snapPoints, viewportHeight]);
|
|
5223
|
+
const resolvedActiveSnapPoint = React.useMemo(() => {
|
|
5224
|
+
if (activeSnapPoint === undefined) {
|
|
5225
|
+
return resolvedSnapPoints[0];
|
|
4815
5226
|
}
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
parentContext.onNestedDialogClose();
|
|
4819
|
-
}
|
|
4820
|
-
};
|
|
4821
|
-
}, [open, parentContext, ownNestedOpenDialogs]);
|
|
4822
|
-
const activeTriggerProps = React.useMemo(() => getReferenceProps(triggerProps), [getReferenceProps, triggerProps]);
|
|
4823
|
-
const inactiveTriggerProps = React.useMemo(() => getTriggerProps(triggerProps), [getTriggerProps, triggerProps]);
|
|
4824
|
-
const popupProps = React.useMemo(() => getFloatingProps(), [getFloatingProps]);
|
|
4825
|
-
store.useSyncedValues({
|
|
4826
|
-
openMethod,
|
|
4827
|
-
activeTriggerProps,
|
|
4828
|
-
inactiveTriggerProps,
|
|
4829
|
-
popupProps,
|
|
4830
|
-
floatingRootContext,
|
|
4831
|
-
nestedOpenDialogCount: ownNestedOpenDialogs
|
|
4832
|
-
});
|
|
4833
|
-
}
|
|
4834
|
-
|
|
4835
|
-
const DialogRootContext = /*#__PURE__*/React.createContext(undefined);
|
|
4836
|
-
if (process.env.NODE_ENV !== "production") DialogRootContext.displayName = "DialogRootContext";
|
|
4837
|
-
function useDialogRootContext(optional) {
|
|
4838
|
-
const dialogRootContext = React.useContext(DialogRootContext);
|
|
4839
|
-
if (optional === false && dialogRootContext === undefined) {
|
|
4840
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: DialogRootContext is missing. Dialog parts must be placed within <Dialog.Root>.' : formatErrorMessage(27));
|
|
4841
|
-
}
|
|
4842
|
-
return dialogRootContext;
|
|
4843
|
-
}
|
|
4844
|
-
|
|
4845
|
-
const selectors = {
|
|
4846
|
-
...popupStoreSelectors,
|
|
4847
|
-
modal: createSelector(state => state.modal),
|
|
4848
|
-
nested: createSelector(state => state.nested),
|
|
4849
|
-
nestedOpenDialogCount: createSelector(state => state.nestedOpenDialogCount),
|
|
4850
|
-
disablePointerDismissal: createSelector(state => state.disablePointerDismissal),
|
|
4851
|
-
openMethod: createSelector(state => state.openMethod),
|
|
4852
|
-
descriptionElementId: createSelector(state => state.descriptionElementId),
|
|
4853
|
-
titleElementId: createSelector(state => state.titleElementId),
|
|
4854
|
-
viewportElement: createSelector(state => state.viewportElement),
|
|
4855
|
-
role: createSelector(state => state.role)
|
|
4856
|
-
};
|
|
4857
|
-
class DialogStore extends ReactStore {
|
|
4858
|
-
constructor(initialState) {
|
|
4859
|
-
super(createInitialState(initialState), {
|
|
4860
|
-
popupRef: /*#__PURE__*/React.createRef(),
|
|
4861
|
-
backdropRef: /*#__PURE__*/React.createRef(),
|
|
4862
|
-
internalBackdropRef: /*#__PURE__*/React.createRef(),
|
|
4863
|
-
outsidePressEnabledRef: {
|
|
4864
|
-
current: true
|
|
4865
|
-
},
|
|
4866
|
-
triggerElements: new PopupTriggerMap(),
|
|
4867
|
-
onOpenChange: undefined,
|
|
4868
|
-
onOpenChangeComplete: undefined
|
|
4869
|
-
}, selectors);
|
|
4870
|
-
}
|
|
4871
|
-
setOpen = (nextOpen, eventDetails) => {
|
|
4872
|
-
eventDetails.preventUnmountOnClose = () => {
|
|
4873
|
-
this.set('preventUnmountingOnClose', true);
|
|
4874
|
-
};
|
|
4875
|
-
if (!nextOpen && eventDetails.trigger == null && this.state.activeTriggerId != null) {
|
|
4876
|
-
// When closing the dialog, pass the old trigger to the onOpenChange event
|
|
4877
|
-
// so it's not reset too early (potentially causing focus issues in controlled scenarios).
|
|
4878
|
-
eventDetails.trigger = this.state.activeTriggerElement ?? undefined;
|
|
5227
|
+
if (activeSnapPoint === null) {
|
|
5228
|
+
return undefined;
|
|
4879
5229
|
}
|
|
4880
|
-
|
|
4881
|
-
if (
|
|
4882
|
-
return;
|
|
5230
|
+
const exactMatch = resolvedSnapPoints.find(point => Object.is(point.value, activeSnapPoint));
|
|
5231
|
+
if (exactMatch) {
|
|
5232
|
+
return exactMatch;
|
|
4883
5233
|
}
|
|
4884
|
-
const
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
nested: this.state.nested
|
|
4889
|
-
};
|
|
4890
|
-
this.state.floatingRootContext.context.events?.emit('openchange', details);
|
|
4891
|
-
const updatedState = {
|
|
4892
|
-
open: nextOpen
|
|
4893
|
-
};
|
|
4894
|
-
|
|
4895
|
-
// If a popup is closing, the `trigger` may be null.
|
|
4896
|
-
// We want to keep the previous value so that exit animations are played and focus is returned correctly.
|
|
4897
|
-
const newTriggerId = eventDetails.trigger?.id ?? null;
|
|
4898
|
-
if (newTriggerId || nextOpen) {
|
|
4899
|
-
updatedState.activeTriggerId = newTriggerId;
|
|
4900
|
-
updatedState.activeTriggerElement = eventDetails.trigger ?? null;
|
|
5234
|
+
const maxHeight = Math.min(popupHeight, viewportHeight);
|
|
5235
|
+
const resolvedHeight = resolveSnapPointValue(activeSnapPoint, viewportHeight, rootFontSize);
|
|
5236
|
+
if (resolvedHeight === null || !Number.isFinite(resolvedHeight)) {
|
|
5237
|
+
return undefined;
|
|
4901
5238
|
}
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
}
|
|
4905
|
-
function createInitialState(initialState = {}) {
|
|
5239
|
+
const clampedHeight = clamp(resolvedHeight, 0, maxHeight);
|
|
5240
|
+
return findClosestSnapPoint(clampedHeight, resolvedSnapPoints) ?? undefined;
|
|
5241
|
+
}, [activeSnapPoint, popupHeight, resolvedSnapPoints, rootFontSize, viewportHeight]);
|
|
4906
5242
|
return {
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
openMethod: null,
|
|
4915
|
-
nested: false,
|
|
4916
|
-
nestedOpenDialogCount: 0,
|
|
4917
|
-
role: 'dialog',
|
|
4918
|
-
...initialState
|
|
5243
|
+
snapPoints,
|
|
5244
|
+
activeSnapPoint,
|
|
5245
|
+
setActiveSnapPoint,
|
|
5246
|
+
popupHeight,
|
|
5247
|
+
viewportHeight,
|
|
5248
|
+
resolvedSnapPoints,
|
|
5249
|
+
activeSnapPointOffset: resolvedActiveSnapPoint?.offset ?? null
|
|
4919
5250
|
};
|
|
4920
5251
|
}
|
|
4921
5252
|
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
/**
|
|
4928
|
-
* Present when the popup is closed.
|
|
4929
|
-
*/
|
|
4930
|
-
CommonPopupDataAttributes["closed"] = "data-closed";
|
|
4931
|
-
/**
|
|
4932
|
-
* Present when the popup is animating in.
|
|
4933
|
-
*/
|
|
4934
|
-
CommonPopupDataAttributes[CommonPopupDataAttributes["startingStyle"] = TransitionStatusDataAttributes.startingStyle] = "startingStyle";
|
|
4935
|
-
/**
|
|
4936
|
-
* Present when the popup is animating out.
|
|
4937
|
-
*/
|
|
4938
|
-
CommonPopupDataAttributes[CommonPopupDataAttributes["endingStyle"] = TransitionStatusDataAttributes.endingStyle] = "endingStyle";
|
|
4939
|
-
/**
|
|
4940
|
-
* Present when the anchor is hidden.
|
|
4941
|
-
*/
|
|
4942
|
-
CommonPopupDataAttributes["anchorHidden"] = "data-anchor-hidden";
|
|
4943
|
-
/**
|
|
4944
|
-
* Indicates which side the popup is positioned relative to the trigger.
|
|
4945
|
-
* @type { 'top' | 'bottom' | 'left' | 'right' | 'inline-end' | 'inline-start'}
|
|
4946
|
-
*/
|
|
4947
|
-
CommonPopupDataAttributes["side"] = "data-side";
|
|
4948
|
-
/**
|
|
4949
|
-
* Indicates how the popup is aligned relative to specified side.
|
|
4950
|
-
* @type {'start' | 'center' | 'end'}
|
|
4951
|
-
*/
|
|
4952
|
-
CommonPopupDataAttributes["align"] = "data-align";
|
|
4953
|
-
return CommonPopupDataAttributes;
|
|
4954
|
-
}({});
|
|
4955
|
-
let CommonTriggerDataAttributes = /*#__PURE__*/function (CommonTriggerDataAttributes) {
|
|
4956
|
-
/**
|
|
4957
|
-
* Present when the popup is open.
|
|
4958
|
-
*/
|
|
4959
|
-
CommonTriggerDataAttributes["popupOpen"] = "data-popup-open";
|
|
4960
|
-
/**
|
|
4961
|
-
* Present when a pressable trigger is pressed.
|
|
4962
|
-
*/
|
|
4963
|
-
CommonTriggerDataAttributes["pressed"] = "data-pressed";
|
|
4964
|
-
return CommonTriggerDataAttributes;
|
|
4965
|
-
}({});
|
|
4966
|
-
const TRIGGER_HOOK = {
|
|
4967
|
-
[CommonTriggerDataAttributes.popupOpen]: ''
|
|
4968
|
-
};
|
|
4969
|
-
const PRESSABLE_TRIGGER_HOOK = {
|
|
4970
|
-
[CommonTriggerDataAttributes.popupOpen]: '',
|
|
4971
|
-
[CommonTriggerDataAttributes.pressed]: ''
|
|
4972
|
-
};
|
|
4973
|
-
const POPUP_OPEN_HOOK = {
|
|
4974
|
-
[CommonPopupDataAttributes.open]: ''
|
|
4975
|
-
};
|
|
4976
|
-
const POPUP_CLOSED_HOOK = {
|
|
4977
|
-
[CommonPopupDataAttributes.closed]: ''
|
|
4978
|
-
};
|
|
4979
|
-
const ANCHOR_HIDDEN_HOOK = {
|
|
4980
|
-
[CommonPopupDataAttributes.anchorHidden]: ''
|
|
4981
|
-
};
|
|
4982
|
-
const triggerOpenStateMapping = {
|
|
4983
|
-
open(value) {
|
|
4984
|
-
if (value) {
|
|
4985
|
-
return TRIGGER_HOOK;
|
|
4986
|
-
}
|
|
4987
|
-
return null;
|
|
4988
|
-
}
|
|
4989
|
-
};
|
|
4990
|
-
const pressableTriggerOpenStateMapping = {
|
|
4991
|
-
open(value) {
|
|
4992
|
-
if (value) {
|
|
4993
|
-
return PRESSABLE_TRIGGER_HOOK;
|
|
4994
|
-
}
|
|
4995
|
-
return null;
|
|
4996
|
-
}
|
|
4997
|
-
};
|
|
4998
|
-
const popupStateMapping = {
|
|
4999
|
-
open(value) {
|
|
5000
|
-
if (value) {
|
|
5001
|
-
return POPUP_OPEN_HOOK;
|
|
5002
|
-
}
|
|
5003
|
-
return POPUP_CLOSED_HOOK;
|
|
5004
|
-
},
|
|
5005
|
-
anchorHidden(value) {
|
|
5006
|
-
if (value) {
|
|
5007
|
-
return ANCHOR_HIDDEN_HOOK;
|
|
5008
|
-
}
|
|
5009
|
-
return null;
|
|
5010
|
-
}
|
|
5011
|
-
};
|
|
5012
|
-
|
|
5013
|
-
const DialogPortalContext = /*#__PURE__*/React.createContext(undefined);
|
|
5014
|
-
if (process.env.NODE_ENV !== "production") DialogPortalContext.displayName = "DialogPortalContext";
|
|
5015
|
-
function useDialogPortalContext() {
|
|
5016
|
-
const value = React.useContext(DialogPortalContext);
|
|
5017
|
-
if (value === undefined) {
|
|
5018
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: <Dialog.Portal> is missing.' : formatErrorMessage(26));
|
|
5019
|
-
}
|
|
5020
|
-
return value;
|
|
5253
|
+
const DrawerViewportContext = /*#__PURE__*/React.createContext(null);
|
|
5254
|
+
if (process.env.NODE_ENV !== "production") DrawerViewportContext.displayName = "DrawerViewportContext";
|
|
5255
|
+
function useDrawerViewportContext(optional) {
|
|
5256
|
+
const context = React.useContext(DrawerViewportContext);
|
|
5257
|
+
return context;
|
|
5021
5258
|
}
|
|
5022
5259
|
|
|
5023
|
-
|
|
5024
|
-
if (isReactVersionAtLeast(19)) {
|
|
5025
|
-
return value;
|
|
5026
|
-
}
|
|
5027
|
-
// compatibility with React < 19
|
|
5028
|
-
return value ? 'true' : undefined;
|
|
5029
|
-
}
|
|
5260
|
+
let drawerSwipeVarsRegistered = false;
|
|
5030
5261
|
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
100% 0%,
|
|
5042
|
-
100% 100%,
|
|
5043
|
-
0% 100%,
|
|
5044
|
-
0% 0%,
|
|
5045
|
-
${rect.left}px ${rect.top}px,
|
|
5046
|
-
${rect.left}px ${rect.bottom}px,
|
|
5047
|
-
${rect.right}px ${rect.bottom}px,
|
|
5048
|
-
${rect.right}px ${rect.top}px,
|
|
5049
|
-
${rect.left}px ${rect.top}px
|
|
5050
|
-
)`;
|
|
5262
|
+
/**
|
|
5263
|
+
* Removes inheritance of high-frequency drawer swipe CSS variables, which
|
|
5264
|
+
* reduces style recalculation cost in complex drawers with deep subtrees.
|
|
5265
|
+
* Child elements that need these values can still opt-in by using `inherit`.
|
|
5266
|
+
* See https://motion.dev/blog/web-animation-performance-tier-list
|
|
5267
|
+
* under the "Improving CSS variable performance" section.
|
|
5268
|
+
*/
|
|
5269
|
+
function removeCSSVariableInheritance() {
|
|
5270
|
+
if (drawerSwipeVarsRegistered) {
|
|
5271
|
+
return;
|
|
5051
5272
|
}
|
|
5052
|
-
return /*#__PURE__*/jsx("div", {
|
|
5053
|
-
ref: ref,
|
|
5054
|
-
role: "presentation"
|
|
5055
|
-
// Ensures Floating UI's outside press detection runs, as it considers
|
|
5056
|
-
// it an element that existed when the popup rendered.
|
|
5057
|
-
,
|
|
5058
|
-
"data-base-ui-inert": "",
|
|
5059
|
-
...otherProps,
|
|
5060
|
-
style: {
|
|
5061
|
-
position: 'fixed',
|
|
5062
|
-
inset: 0,
|
|
5063
|
-
userSelect: 'none',
|
|
5064
|
-
WebkitUserSelect: 'none',
|
|
5065
|
-
clipPath
|
|
5066
|
-
}
|
|
5067
|
-
});
|
|
5068
|
-
});
|
|
5069
|
-
if (process.env.NODE_ENV !== "production") InternalBackdrop.displayName = "InternalBackdrop";
|
|
5070
|
-
|
|
5071
|
-
const DialogPortal = /*#__PURE__*/React.forwardRef(function DialogPortal(props, forwardedRef) {
|
|
5072
|
-
const {
|
|
5073
|
-
keepMounted = false,
|
|
5074
|
-
...portalProps
|
|
5075
|
-
} = props;
|
|
5076
|
-
const {
|
|
5077
|
-
store
|
|
5078
|
-
} = useDialogRootContext();
|
|
5079
|
-
const mounted = store.useState('mounted');
|
|
5080
|
-
const modal = store.useState('modal');
|
|
5081
|
-
const open = store.useState('open');
|
|
5082
|
-
const shouldRender = mounted || keepMounted;
|
|
5083
|
-
if (!shouldRender) {
|
|
5084
|
-
return null;
|
|
5085
|
-
}
|
|
5086
|
-
return /*#__PURE__*/jsx(DialogPortalContext.Provider, {
|
|
5087
|
-
value: keepMounted,
|
|
5088
|
-
children: /*#__PURE__*/jsxs(FloatingPortal, {
|
|
5089
|
-
ref: forwardedRef,
|
|
5090
|
-
...portalProps,
|
|
5091
|
-
children: [mounted && modal === true && /*#__PURE__*/jsx(InternalBackdrop, {
|
|
5092
|
-
ref: store.context.internalBackdropRef,
|
|
5093
|
-
inert: inertValue(!open)
|
|
5094
|
-
}), props.children]
|
|
5095
|
-
})
|
|
5096
|
-
});
|
|
5097
|
-
});
|
|
5098
|
-
if (process.env.NODE_ENV !== "production") DialogPortal.displayName = "DialogPortal";
|
|
5099
|
-
|
|
5100
|
-
function useOnFirstRender(fn) {
|
|
5101
|
-
const ref = React.useRef(true);
|
|
5102
|
-
if (ref.current) {
|
|
5103
|
-
ref.current = false;
|
|
5104
|
-
fn();
|
|
5105
|
-
}
|
|
5106
|
-
}
|
|
5107
5273
|
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
handle,
|
|
5125
|
-
triggerId: triggerIdProp,
|
|
5126
|
-
defaultTriggerId: defaultTriggerIdProp = null
|
|
5127
|
-
} = props;
|
|
5128
|
-
const parentDialogRootContext = useDialogRootContext(true);
|
|
5129
|
-
const nested = Boolean(parentDialogRootContext);
|
|
5130
|
-
const store = useRefWithInit(() => {
|
|
5131
|
-
return handle?.store ?? new DialogStore({
|
|
5132
|
-
open: defaultOpen,
|
|
5133
|
-
openProp,
|
|
5134
|
-
activeTriggerId: defaultTriggerIdProp,
|
|
5135
|
-
triggerIdProp,
|
|
5136
|
-
modal,
|
|
5137
|
-
disablePointerDismissal,
|
|
5138
|
-
nested
|
|
5274
|
+
// Intentionally keep inheritance disabled on WebKit as well. Safari doesn't support
|
|
5275
|
+
// opting descendants back in via `--var: inherit` for custom properties registered
|
|
5276
|
+
// with `inherits: false`, but Drawer does not rely on descendant access to these vars
|
|
5277
|
+
// (unlike ScrollArea), so we keep the performance optimization enabled.
|
|
5278
|
+
if (typeof CSS !== 'undefined' && 'registerProperty' in CSS) {
|
|
5279
|
+
[DrawerPopupCssVars.swipeMovementX, DrawerPopupCssVars.swipeMovementY, DrawerPopupCssVars.snapPointOffset].forEach(name => {
|
|
5280
|
+
try {
|
|
5281
|
+
CSS.registerProperty({
|
|
5282
|
+
name,
|
|
5283
|
+
syntax: '<length>',
|
|
5284
|
+
inherits: false,
|
|
5285
|
+
initialValue: '0px'
|
|
5286
|
+
});
|
|
5287
|
+
} catch {
|
|
5288
|
+
/* ignore already-registered */
|
|
5289
|
+
}
|
|
5139
5290
|
});
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
}
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
actionsRef,
|
|
5164
|
-
parentContext: parentDialogRootContext?.store.context,
|
|
5165
|
-
onOpenChange,
|
|
5166
|
-
triggerIdProp
|
|
5167
|
-
});
|
|
5168
|
-
const contextValue = React.useMemo(() => ({
|
|
5169
|
-
store
|
|
5170
|
-
}), [store]);
|
|
5171
|
-
return /*#__PURE__*/jsx(DialogRootContext.Provider, {
|
|
5172
|
-
value: contextValue,
|
|
5173
|
-
children: typeof children === 'function' ? children({
|
|
5174
|
-
payload
|
|
5175
|
-
}) : children
|
|
5176
|
-
});
|
|
5291
|
+
[{
|
|
5292
|
+
name: DrawerBackdropCssVars.swipeProgress,
|
|
5293
|
+
initialValue: '0'
|
|
5294
|
+
}, {
|
|
5295
|
+
name: DrawerPopupCssVars.swipeStrength,
|
|
5296
|
+
initialValue: '1'
|
|
5297
|
+
}].forEach(({
|
|
5298
|
+
name,
|
|
5299
|
+
initialValue
|
|
5300
|
+
}) => {
|
|
5301
|
+
try {
|
|
5302
|
+
CSS.registerProperty({
|
|
5303
|
+
name,
|
|
5304
|
+
syntax: '<number>',
|
|
5305
|
+
inherits: false,
|
|
5306
|
+
initialValue
|
|
5307
|
+
});
|
|
5308
|
+
} catch {
|
|
5309
|
+
/* ignore already-registered */
|
|
5310
|
+
}
|
|
5311
|
+
});
|
|
5312
|
+
}
|
|
5313
|
+
drawerSwipeVarsRegistered = true;
|
|
5177
5314
|
}
|
|
5178
|
-
|
|
5179
|
-
let DrawerPopupCssVars = /*#__PURE__*/function (DrawerPopupCssVars) {
|
|
5180
|
-
/**
|
|
5181
|
-
* The number of nested drawers that are currently open.
|
|
5182
|
-
* @type {number}
|
|
5183
|
-
*/
|
|
5184
|
-
DrawerPopupCssVars["nestedDrawers"] = "--nested-drawers";
|
|
5185
|
-
/**
|
|
5186
|
-
* The height of the drawer popup.
|
|
5187
|
-
* @type {CSS length}
|
|
5188
|
-
*/
|
|
5189
|
-
DrawerPopupCssVars["height"] = "--drawer-height";
|
|
5190
|
-
/**
|
|
5191
|
-
* The height of the frontmost open drawer in the current nested drawer stack.
|
|
5192
|
-
* @type {CSS length}
|
|
5193
|
-
*/
|
|
5194
|
-
DrawerPopupCssVars["frontmostHeight"] = "--drawer-frontmost-height";
|
|
5195
|
-
/**
|
|
5196
|
-
* The swipe movement on the X axis.
|
|
5197
|
-
* @type {CSS length}
|
|
5198
|
-
*/
|
|
5199
|
-
DrawerPopupCssVars["swipeMovementX"] = "--drawer-swipe-movement-x";
|
|
5200
|
-
/**
|
|
5201
|
-
* The swipe movement on the Y axis.
|
|
5202
|
-
* @type {CSS length}
|
|
5203
|
-
*/
|
|
5204
|
-
DrawerPopupCssVars["swipeMovementY"] = "--drawer-swipe-movement-y";
|
|
5205
|
-
/**
|
|
5206
|
-
* The snap point offset used for translating the drawer.
|
|
5207
|
-
* @type {CSS length}
|
|
5208
|
-
*/
|
|
5209
|
-
DrawerPopupCssVars["snapPointOffset"] = "--drawer-snap-point-offset";
|
|
5210
|
-
/**
|
|
5211
|
-
* A scalar (0.1-1) used to scale the swipe release transition duration in CSS.
|
|
5212
|
-
* @type {number}
|
|
5213
|
-
*/
|
|
5214
|
-
DrawerPopupCssVars["swipeStrength"] = "--drawer-swipe-strength";
|
|
5215
|
-
return DrawerPopupCssVars;
|
|
5216
|
-
}({});
|
|
5217
|
-
|
|
5218
|
-
let DrawerBackdropCssVars = /*#__PURE__*/function (DrawerBackdropCssVars) {
|
|
5219
|
-
/**
|
|
5220
|
-
* The swipe progress of the drawer gesture.
|
|
5221
|
-
* @type {number}
|
|
5222
|
-
*/
|
|
5223
|
-
DrawerBackdropCssVars["swipeProgress"] = "--drawer-swipe-progress";
|
|
5224
|
-
return DrawerBackdropCssVars;
|
|
5225
|
-
}({});
|
|
5226
|
-
|
|
5227
|
-
const stateAttributesMapping$1 = {
|
|
5315
|
+
const stateAttributesMapping = {
|
|
5228
5316
|
...popupStateMapping,
|
|
5229
|
-
...transitionStatusMapping
|
|
5317
|
+
...transitionStatusMapping,
|
|
5318
|
+
expanded(value) {
|
|
5319
|
+
return value ? {
|
|
5320
|
+
[DrawerPopupDataAttributes.expanded]: ''
|
|
5321
|
+
} : null;
|
|
5322
|
+
},
|
|
5323
|
+
nestedDrawerOpen(value) {
|
|
5324
|
+
return value ? {
|
|
5325
|
+
[DrawerPopupDataAttributes.nestedDrawerOpen]: ''
|
|
5326
|
+
} : null;
|
|
5327
|
+
},
|
|
5328
|
+
nestedDrawerSwiping(value) {
|
|
5329
|
+
return value ? {
|
|
5330
|
+
[DrawerPopupDataAttributes.nestedDrawerSwiping]: ''
|
|
5331
|
+
} : null;
|
|
5332
|
+
},
|
|
5333
|
+
swipeDirection(value) {
|
|
5334
|
+
return value ? {
|
|
5335
|
+
[DrawerPopupDataAttributes.swipeDirection]: value
|
|
5336
|
+
} : null;
|
|
5337
|
+
},
|
|
5338
|
+
swiping(value) {
|
|
5339
|
+
return value ? {
|
|
5340
|
+
[DrawerPopupDataAttributes.swiping]: ''
|
|
5341
|
+
} : null;
|
|
5342
|
+
}
|
|
5230
5343
|
};
|
|
5231
5344
|
|
|
5232
5345
|
/**
|
|
5233
|
-
*
|
|
5346
|
+
* A container for the drawer contents.
|
|
5234
5347
|
* Renders a `<div>` element.
|
|
5235
5348
|
*
|
|
5236
5349
|
* Documentation: [Base UI Drawer](https://base-ui.com/react/components/drawer)
|
|
5237
5350
|
*/
|
|
5238
|
-
const
|
|
5351
|
+
const DrawerPopup = /*#__PURE__*/React.forwardRef(function DrawerPopup(componentProps, forwardedRef) {
|
|
5239
5352
|
const {
|
|
5240
|
-
render,
|
|
5241
5353
|
className,
|
|
5242
|
-
|
|
5354
|
+
finalFocus,
|
|
5355
|
+
initialFocus,
|
|
5356
|
+
render,
|
|
5243
5357
|
...elementProps
|
|
5244
5358
|
} = componentProps;
|
|
5245
5359
|
const {
|
|
5246
5360
|
store
|
|
5247
5361
|
} = useDialogRootContext();
|
|
5248
|
-
const
|
|
5249
|
-
|
|
5362
|
+
const {
|
|
5363
|
+
swipeDirection,
|
|
5364
|
+
frontmostHeight,
|
|
5365
|
+
hasNestedDrawer,
|
|
5366
|
+
nestedSwiping,
|
|
5367
|
+
nestedSwipeProgressStore,
|
|
5368
|
+
onPopupHeightChange,
|
|
5369
|
+
notifyParentFrontmostHeight,
|
|
5370
|
+
notifyParentHasNestedDrawer
|
|
5371
|
+
} = useDrawerRootContext();
|
|
5372
|
+
const descriptionElementId = store.useState('descriptionElementId');
|
|
5373
|
+
const disablePointerDismissal = store.useState('disablePointerDismissal');
|
|
5374
|
+
const floatingRootContext = store.useState('floatingRootContext');
|
|
5375
|
+
const rootPopupProps = store.useState('popupProps');
|
|
5376
|
+
const modal = store.useState('modal');
|
|
5250
5377
|
const mounted = store.useState('mounted');
|
|
5378
|
+
const nested = store.useState('nested');
|
|
5379
|
+
const nestedOpenDialogCount = store.useState('nestedOpenDialogCount');
|
|
5251
5380
|
const transitionStatus = store.useState('transitionStatus');
|
|
5252
|
-
const
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
props: [{
|
|
5261
|
-
role: 'presentation',
|
|
5262
|
-
hidden: !mounted,
|
|
5263
|
-
style: {
|
|
5264
|
-
pointerEvents: !open ? 'none' : undefined,
|
|
5265
|
-
userSelect: 'none',
|
|
5266
|
-
WebkitUserSelect: 'none',
|
|
5267
|
-
[DrawerBackdropCssVars.swipeProgress]: '0',
|
|
5268
|
-
[DrawerPopupCssVars.swipeStrength]: '1'
|
|
5269
|
-
}
|
|
5270
|
-
}, elementProps],
|
|
5271
|
-
enabled: forceRender || !nested
|
|
5272
|
-
});
|
|
5273
|
-
});
|
|
5274
|
-
if (process.env.NODE_ENV !== "production") DrawerBackdrop.displayName = "DrawerBackdrop";
|
|
5275
|
-
|
|
5276
|
-
const DRAWER_CONTENT_ATTRIBUTE = 'data-drawer-content';
|
|
5277
|
-
|
|
5278
|
-
/**
|
|
5279
|
-
* A container for the drawer contents.
|
|
5280
|
-
* Renders a `<div>` element.
|
|
5281
|
-
*
|
|
5282
|
-
* Documentation: [Base UI Drawer](https://base-ui.com/react/components/drawer)
|
|
5283
|
-
*/
|
|
5284
|
-
const DrawerContent = /*#__PURE__*/React.forwardRef(function DrawerContent(componentProps, forwardedRef) {
|
|
5285
|
-
const {
|
|
5286
|
-
render,
|
|
5287
|
-
className,
|
|
5288
|
-
...elementProps
|
|
5289
|
-
} = componentProps;
|
|
5290
|
-
useDialogRootContext();
|
|
5291
|
-
return useRenderElement('div', componentProps, {
|
|
5292
|
-
ref: forwardedRef,
|
|
5293
|
-
props: [{
|
|
5294
|
-
[DRAWER_CONTENT_ATTRIBUTE]: ''
|
|
5295
|
-
}, elementProps]
|
|
5296
|
-
});
|
|
5297
|
-
});
|
|
5298
|
-
if (process.env.NODE_ENV !== "production") DrawerContent.displayName = "DrawerContent";
|
|
5299
|
-
|
|
5300
|
-
const DrawerProviderContext = /*#__PURE__*/React.createContext(undefined);
|
|
5301
|
-
if (process.env.NODE_ENV !== "production") DrawerProviderContext.displayName = "DrawerProviderContext";
|
|
5302
|
-
function useDrawerProviderContext(optional) {
|
|
5303
|
-
const context = React.useContext(DrawerProviderContext);
|
|
5304
|
-
return context;
|
|
5305
|
-
}
|
|
5306
|
-
|
|
5307
|
-
let DrawerPopupDataAttributes = function (DrawerPopupDataAttributes) {
|
|
5308
|
-
/**
|
|
5309
|
-
* Present when the drawer is open.
|
|
5310
|
-
*/
|
|
5311
|
-
DrawerPopupDataAttributes[DrawerPopupDataAttributes["open"] = CommonPopupDataAttributes.open] = "open";
|
|
5312
|
-
/**
|
|
5313
|
-
* Present when the drawer is closed.
|
|
5314
|
-
*/
|
|
5315
|
-
DrawerPopupDataAttributes[DrawerPopupDataAttributes["closed"] = CommonPopupDataAttributes.closed] = "closed";
|
|
5316
|
-
/**
|
|
5317
|
-
* Present when the drawer is animating in.
|
|
5318
|
-
*/
|
|
5319
|
-
DrawerPopupDataAttributes[DrawerPopupDataAttributes["startingStyle"] = CommonPopupDataAttributes.startingStyle] = "startingStyle";
|
|
5320
|
-
/**
|
|
5321
|
-
* Present when the drawer is animating out.
|
|
5322
|
-
*/
|
|
5323
|
-
DrawerPopupDataAttributes[DrawerPopupDataAttributes["endingStyle"] = CommonPopupDataAttributes.endingStyle] = "endingStyle";
|
|
5324
|
-
/**
|
|
5325
|
-
* Present when the drawer is at the expanded (full-height) snap point.
|
|
5326
|
-
*/
|
|
5327
|
-
DrawerPopupDataAttributes["expanded"] = "data-expanded";
|
|
5328
|
-
/**
|
|
5329
|
-
* Present when a nested drawer is open.
|
|
5330
|
-
*/
|
|
5331
|
-
DrawerPopupDataAttributes["nestedDrawerOpen"] = "data-nested-drawer-open";
|
|
5332
|
-
/**
|
|
5333
|
-
* Present when a nested drawer is being swiped.
|
|
5334
|
-
*/
|
|
5335
|
-
DrawerPopupDataAttributes["nestedDrawerSwiping"] = "data-nested-drawer-swiping";
|
|
5336
|
-
/**
|
|
5337
|
-
* Present when the drawer is dismissed by swiping.
|
|
5338
|
-
*/
|
|
5339
|
-
DrawerPopupDataAttributes["swipeDismiss"] = "data-swipe-dismiss";
|
|
5340
|
-
/**
|
|
5341
|
-
* Indicates the swipe direction.
|
|
5342
|
-
* @type {'up' | 'down' | 'left' | 'right'}
|
|
5343
|
-
*/
|
|
5344
|
-
DrawerPopupDataAttributes["swipeDirection"] = "data-swipe-direction";
|
|
5345
|
-
/**
|
|
5346
|
-
* Present when the drawer is being swiped.
|
|
5347
|
-
*/
|
|
5348
|
-
DrawerPopupDataAttributes["swiping"] = "data-swiping";
|
|
5349
|
-
return DrawerPopupDataAttributes;
|
|
5350
|
-
}({});
|
|
5351
|
-
|
|
5352
|
-
const DrawerRootContext = /*#__PURE__*/React.createContext(undefined);
|
|
5353
|
-
if (process.env.NODE_ENV !== "production") DrawerRootContext.displayName = "DrawerRootContext";
|
|
5354
|
-
function useDrawerRootContext(optional) {
|
|
5355
|
-
const drawerRootContext = React.useContext(DrawerRootContext);
|
|
5356
|
-
if (optional === false && drawerRootContext === undefined) {
|
|
5357
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: DrawerRootContext is missing. Drawer parts must be placed within <Drawer.Root>.' : formatErrorMessage(90));
|
|
5358
|
-
}
|
|
5359
|
-
return drawerRootContext;
|
|
5360
|
-
}
|
|
5361
|
-
|
|
5362
|
-
function clamp(val, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) {
|
|
5363
|
-
return Math.max(min, Math.min(val, max));
|
|
5364
|
-
}
|
|
5365
|
-
|
|
5366
|
-
function resolveSnapPointValue(snapPoint, viewportHeight, rootFontSize) {
|
|
5367
|
-
if (!Number.isFinite(viewportHeight) || viewportHeight <= 0) {
|
|
5368
|
-
return null;
|
|
5369
|
-
}
|
|
5370
|
-
if (typeof snapPoint === 'number') {
|
|
5371
|
-
if (!Number.isFinite(snapPoint)) {
|
|
5372
|
-
return null;
|
|
5373
|
-
}
|
|
5374
|
-
if (snapPoint <= 1) {
|
|
5375
|
-
return clamp(snapPoint, 0, 1) * viewportHeight;
|
|
5376
|
-
}
|
|
5377
|
-
return snapPoint;
|
|
5378
|
-
}
|
|
5379
|
-
const trimmed = snapPoint.trim();
|
|
5380
|
-
if (trimmed.endsWith('px')) {
|
|
5381
|
-
const value = Number.parseFloat(trimmed);
|
|
5382
|
-
return Number.isFinite(value) ? value : null;
|
|
5383
|
-
}
|
|
5384
|
-
if (trimmed.endsWith('rem')) {
|
|
5385
|
-
const value = Number.parseFloat(trimmed);
|
|
5386
|
-
return Number.isFinite(value) ? value * rootFontSize : null;
|
|
5387
|
-
}
|
|
5388
|
-
return null;
|
|
5389
|
-
}
|
|
5390
|
-
function findClosestSnapPoint(height, points) {
|
|
5391
|
-
let closest = null;
|
|
5392
|
-
let closestDistance = Infinity;
|
|
5393
|
-
for (const point of points) {
|
|
5394
|
-
const distance = Math.abs(point.height - height);
|
|
5395
|
-
if (distance < closestDistance) {
|
|
5396
|
-
closestDistance = distance;
|
|
5397
|
-
closest = point;
|
|
5398
|
-
}
|
|
5399
|
-
}
|
|
5400
|
-
return closest;
|
|
5401
|
-
}
|
|
5402
|
-
function useDrawerSnapPoints() {
|
|
5403
|
-
const {
|
|
5404
|
-
store
|
|
5405
|
-
} = useDialogRootContext();
|
|
5381
|
+
const open = store.useState('open');
|
|
5382
|
+
const openMethod = store.useState('openMethod');
|
|
5383
|
+
const titleElementId = store.useState('titleElementId');
|
|
5384
|
+
const role = store.useState('role');
|
|
5385
|
+
const nestedDrawerOpen = nestedOpenDialogCount > 0;
|
|
5386
|
+
const swipe = useDrawerViewportContext();
|
|
5387
|
+
const swiping = swipe?.swiping ?? false;
|
|
5388
|
+
const swipeStrength = swipe?.swipeStrength ?? null;
|
|
5406
5389
|
const {
|
|
5407
5390
|
snapPoints,
|
|
5408
5391
|
activeSnapPoint,
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
const
|
|
5413
|
-
const
|
|
5414
|
-
const
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
if (viewportElement) {
|
|
5419
|
-
setViewportHeight(viewportElement.offsetHeight);
|
|
5392
|
+
activeSnapPointOffset
|
|
5393
|
+
} = useDrawerSnapPoints();
|
|
5394
|
+
useDialogPortalContext();
|
|
5395
|
+
const [popupHeight, setPopupHeight] = React.useState(0);
|
|
5396
|
+
const popupHeightRef = React.useRef(0);
|
|
5397
|
+
const measureHeight = useStableCallback(() => {
|
|
5398
|
+
const popupElement = store.context.popupRef.current;
|
|
5399
|
+
if (!popupElement) {
|
|
5400
|
+
return;
|
|
5420
5401
|
}
|
|
5421
|
-
|
|
5422
|
-
|
|
5402
|
+
const offsetHeight = popupElement.offsetHeight;
|
|
5403
|
+
|
|
5404
|
+
// Only skip while the element is still actually stretched beyond its last measured height.
|
|
5405
|
+
if (popupHeightRef.current > 0 && frontmostHeight > popupHeightRef.current && offsetHeight > popupHeightRef.current) {
|
|
5406
|
+
return;
|
|
5423
5407
|
}
|
|
5424
|
-
const
|
|
5425
|
-
if (
|
|
5426
|
-
|
|
5408
|
+
const keepHeightWhileNested = popupHeightRef.current > 0 && hasNestedDrawer;
|
|
5409
|
+
if (keepHeightWhileNested) {
|
|
5410
|
+
const oldHeight = popupHeightRef.current;
|
|
5411
|
+
setPopupHeight(oldHeight);
|
|
5412
|
+
onPopupHeightChange(oldHeight);
|
|
5413
|
+
return;
|
|
5414
|
+
}
|
|
5415
|
+
const nextHeight = offsetHeight;
|
|
5416
|
+
if (nextHeight === popupHeightRef.current) {
|
|
5417
|
+
return;
|
|
5427
5418
|
}
|
|
5419
|
+
popupHeightRef.current = nextHeight;
|
|
5420
|
+
setPopupHeight(nextHeight);
|
|
5421
|
+
onPopupHeightChange(nextHeight);
|
|
5428
5422
|
});
|
|
5429
5423
|
useIsoLayoutEffect(() => {
|
|
5430
|
-
|
|
5431
|
-
|
|
5424
|
+
if (!mounted) {
|
|
5425
|
+
popupHeightRef.current = 0;
|
|
5426
|
+
setPopupHeight(0);
|
|
5427
|
+
onPopupHeightChange(0);
|
|
5432
5428
|
return undefined;
|
|
5433
5429
|
}
|
|
5434
|
-
const
|
|
5435
|
-
|
|
5430
|
+
const popupElement = store.context.popupRef.current;
|
|
5431
|
+
if (!popupElement) {
|
|
5432
|
+
return undefined;
|
|
5433
|
+
}
|
|
5434
|
+
removeCSSVariableInheritance();
|
|
5435
|
+
measureHeight();
|
|
5436
|
+
if (typeof ResizeObserver !== 'function') {
|
|
5437
|
+
return undefined;
|
|
5438
|
+
}
|
|
5439
|
+
const resizeObserver = new ResizeObserver(measureHeight);
|
|
5440
|
+
resizeObserver.observe(popupElement);
|
|
5436
5441
|
return () => {
|
|
5437
5442
|
resizeObserver.disconnect();
|
|
5438
5443
|
};
|
|
5439
|
-
}, [
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
return [];
|
|
5447
|
-
}
|
|
5448
|
-
const resolved = snapPoints.map(value => {
|
|
5449
|
-
const resolvedHeight = resolveSnapPointValue(value, viewportHeight, rootFontSize);
|
|
5450
|
-
if (resolvedHeight === null || !Number.isFinite(resolvedHeight)) {
|
|
5451
|
-
return null;
|
|
5452
|
-
}
|
|
5453
|
-
const clampedHeight = clamp(resolvedHeight, 0, maxHeight);
|
|
5454
|
-
return {
|
|
5455
|
-
value,
|
|
5456
|
-
height: clampedHeight,
|
|
5457
|
-
offset: Math.max(0, popupHeight - clampedHeight)
|
|
5458
|
-
};
|
|
5459
|
-
}).filter(point => Boolean(point));
|
|
5460
|
-
if (resolved.length <= 1) {
|
|
5461
|
-
return resolved;
|
|
5462
|
-
}
|
|
5463
|
-
const deduped = [];
|
|
5464
|
-
const seenHeights = [];
|
|
5465
|
-
for (let index = resolved.length - 1; index >= 0; index -= 1) {
|
|
5466
|
-
const point = resolved[index];
|
|
5467
|
-
const isDuplicate = seenHeights.some(height => Math.abs(height - point.height) <= 1);
|
|
5468
|
-
if (isDuplicate) {
|
|
5469
|
-
continue;
|
|
5470
|
-
}
|
|
5471
|
-
seenHeights.push(point.height);
|
|
5472
|
-
deduped.push(point);
|
|
5473
|
-
}
|
|
5474
|
-
deduped.reverse();
|
|
5475
|
-
return deduped;
|
|
5476
|
-
}, [popupHeight, rootFontSize, snapPoints, viewportHeight]);
|
|
5477
|
-
const resolvedActiveSnapPoint = React.useMemo(() => {
|
|
5478
|
-
if (activeSnapPoint === undefined) {
|
|
5479
|
-
return resolvedSnapPoints[0];
|
|
5480
|
-
}
|
|
5481
|
-
if (activeSnapPoint === null) {
|
|
5482
|
-
return undefined;
|
|
5483
|
-
}
|
|
5484
|
-
const exactMatch = resolvedSnapPoints.find(point => Object.is(point.value, activeSnapPoint));
|
|
5485
|
-
if (exactMatch) {
|
|
5486
|
-
return exactMatch;
|
|
5487
|
-
}
|
|
5488
|
-
const maxHeight = Math.min(popupHeight, viewportHeight);
|
|
5489
|
-
const resolvedHeight = resolveSnapPointValue(activeSnapPoint, viewportHeight, rootFontSize);
|
|
5490
|
-
if (resolvedHeight === null || !Number.isFinite(resolvedHeight)) {
|
|
5491
|
-
return undefined;
|
|
5492
|
-
}
|
|
5493
|
-
const clampedHeight = clamp(resolvedHeight, 0, maxHeight);
|
|
5494
|
-
return findClosestSnapPoint(clampedHeight, resolvedSnapPoints) ?? undefined;
|
|
5495
|
-
}, [activeSnapPoint, popupHeight, resolvedSnapPoints, rootFontSize, viewportHeight]);
|
|
5496
|
-
return {
|
|
5497
|
-
snapPoints,
|
|
5498
|
-
activeSnapPoint,
|
|
5499
|
-
setActiveSnapPoint,
|
|
5500
|
-
popupHeight,
|
|
5501
|
-
viewportHeight,
|
|
5502
|
-
resolvedSnapPoints,
|
|
5503
|
-
activeSnapPointOffset: resolvedActiveSnapPoint?.offset ?? null
|
|
5504
|
-
};
|
|
5505
|
-
}
|
|
5506
|
-
|
|
5507
|
-
const DrawerViewportContext = /*#__PURE__*/React.createContext(null);
|
|
5508
|
-
if (process.env.NODE_ENV !== "production") DrawerViewportContext.displayName = "DrawerViewportContext";
|
|
5509
|
-
function useDrawerViewportContext(optional) {
|
|
5510
|
-
const context = React.useContext(DrawerViewportContext);
|
|
5511
|
-
return context;
|
|
5512
|
-
}
|
|
5513
|
-
|
|
5514
|
-
let drawerSwipeVarsRegistered = false;
|
|
5515
|
-
|
|
5516
|
-
/**
|
|
5517
|
-
* Removes inheritance of high-frequency drawer swipe CSS variables, which
|
|
5518
|
-
* reduces style recalculation cost in complex drawers with deep subtrees.
|
|
5519
|
-
* Child elements that need these values can still opt-in by using `inherit`.
|
|
5520
|
-
* See https://motion.dev/blog/web-animation-performance-tier-list
|
|
5521
|
-
* under the "Improving CSS variable performance" section.
|
|
5522
|
-
*/
|
|
5523
|
-
function removeCSSVariableInheritance() {
|
|
5524
|
-
if (drawerSwipeVarsRegistered) {
|
|
5525
|
-
return;
|
|
5526
|
-
}
|
|
5527
|
-
|
|
5528
|
-
// Intentionally keep inheritance disabled on WebKit as well. Safari doesn't support
|
|
5529
|
-
// opting descendants back in via `--var: inherit` for custom properties registered
|
|
5530
|
-
// with `inherits: false`, but Drawer does not rely on descendant access to these vars
|
|
5531
|
-
// (unlike ScrollArea), so we keep the performance optimization enabled.
|
|
5532
|
-
if (typeof CSS !== 'undefined' && 'registerProperty' in CSS) {
|
|
5533
|
-
[DrawerPopupCssVars.swipeMovementX, DrawerPopupCssVars.swipeMovementY, DrawerPopupCssVars.snapPointOffset].forEach(name => {
|
|
5534
|
-
try {
|
|
5535
|
-
CSS.registerProperty({
|
|
5536
|
-
name,
|
|
5537
|
-
syntax: '<length>',
|
|
5538
|
-
inherits: false,
|
|
5539
|
-
initialValue: '0px'
|
|
5540
|
-
});
|
|
5541
|
-
} catch {
|
|
5542
|
-
/* ignore already-registered */
|
|
5543
|
-
}
|
|
5544
|
-
});
|
|
5545
|
-
[{
|
|
5546
|
-
name: DrawerBackdropCssVars.swipeProgress,
|
|
5547
|
-
initialValue: '0'
|
|
5548
|
-
}, {
|
|
5549
|
-
name: DrawerPopupCssVars.swipeStrength,
|
|
5550
|
-
initialValue: '1'
|
|
5551
|
-
}].forEach(({
|
|
5552
|
-
name,
|
|
5553
|
-
initialValue
|
|
5554
|
-
}) => {
|
|
5555
|
-
try {
|
|
5556
|
-
CSS.registerProperty({
|
|
5557
|
-
name,
|
|
5558
|
-
syntax: '<number>',
|
|
5559
|
-
inherits: false,
|
|
5560
|
-
initialValue
|
|
5561
|
-
});
|
|
5562
|
-
} catch {
|
|
5563
|
-
/* ignore already-registered */
|
|
5564
|
-
}
|
|
5565
|
-
});
|
|
5566
|
-
}
|
|
5567
|
-
drawerSwipeVarsRegistered = true;
|
|
5568
|
-
}
|
|
5569
|
-
const stateAttributesMapping = {
|
|
5570
|
-
...popupStateMapping,
|
|
5571
|
-
...transitionStatusMapping,
|
|
5572
|
-
expanded(value) {
|
|
5573
|
-
return value ? {
|
|
5574
|
-
[DrawerPopupDataAttributes.expanded]: ''
|
|
5575
|
-
} : null;
|
|
5576
|
-
},
|
|
5577
|
-
nestedDrawerOpen(value) {
|
|
5578
|
-
return value ? {
|
|
5579
|
-
[DrawerPopupDataAttributes.nestedDrawerOpen]: ''
|
|
5580
|
-
} : null;
|
|
5581
|
-
},
|
|
5582
|
-
nestedDrawerSwiping(value) {
|
|
5583
|
-
return value ? {
|
|
5584
|
-
[DrawerPopupDataAttributes.nestedDrawerSwiping]: ''
|
|
5585
|
-
} : null;
|
|
5586
|
-
},
|
|
5587
|
-
swipeDirection(value) {
|
|
5588
|
-
return value ? {
|
|
5589
|
-
[DrawerPopupDataAttributes.swipeDirection]: value
|
|
5590
|
-
} : null;
|
|
5591
|
-
},
|
|
5592
|
-
swiping(value) {
|
|
5593
|
-
return value ? {
|
|
5594
|
-
[DrawerPopupDataAttributes.swiping]: ''
|
|
5595
|
-
} : null;
|
|
5596
|
-
}
|
|
5597
|
-
};
|
|
5598
|
-
|
|
5599
|
-
/**
|
|
5600
|
-
* A container for the drawer contents.
|
|
5601
|
-
* Renders a `<div>` element.
|
|
5602
|
-
*
|
|
5603
|
-
* Documentation: [Base UI Drawer](https://base-ui.com/react/components/drawer)
|
|
5604
|
-
*/
|
|
5605
|
-
const DrawerPopup = /*#__PURE__*/React.forwardRef(function DrawerPopup(componentProps, forwardedRef) {
|
|
5606
|
-
const {
|
|
5607
|
-
className,
|
|
5608
|
-
finalFocus,
|
|
5609
|
-
initialFocus,
|
|
5610
|
-
render,
|
|
5611
|
-
...elementProps
|
|
5612
|
-
} = componentProps;
|
|
5613
|
-
const {
|
|
5614
|
-
store
|
|
5615
|
-
} = useDialogRootContext();
|
|
5616
|
-
const {
|
|
5617
|
-
swipeDirection,
|
|
5618
|
-
frontmostHeight,
|
|
5619
|
-
hasNestedDrawer,
|
|
5620
|
-
nestedSwiping,
|
|
5621
|
-
nestedSwipeProgressStore,
|
|
5622
|
-
onPopupHeightChange,
|
|
5623
|
-
notifyParentFrontmostHeight,
|
|
5624
|
-
notifyParentHasNestedDrawer
|
|
5625
|
-
} = useDrawerRootContext();
|
|
5626
|
-
const descriptionElementId = store.useState('descriptionElementId');
|
|
5627
|
-
const disablePointerDismissal = store.useState('disablePointerDismissal');
|
|
5628
|
-
const floatingRootContext = store.useState('floatingRootContext');
|
|
5629
|
-
const rootPopupProps = store.useState('popupProps');
|
|
5630
|
-
const modal = store.useState('modal');
|
|
5631
|
-
const mounted = store.useState('mounted');
|
|
5632
|
-
const nested = store.useState('nested');
|
|
5633
|
-
const nestedOpenDialogCount = store.useState('nestedOpenDialogCount');
|
|
5634
|
-
const transitionStatus = store.useState('transitionStatus');
|
|
5635
|
-
const open = store.useState('open');
|
|
5636
|
-
const openMethod = store.useState('openMethod');
|
|
5637
|
-
const titleElementId = store.useState('titleElementId');
|
|
5638
|
-
const role = store.useState('role');
|
|
5639
|
-
const nestedDrawerOpen = nestedOpenDialogCount > 0;
|
|
5640
|
-
const swipe = useDrawerViewportContext();
|
|
5641
|
-
const swiping = swipe?.swiping ?? false;
|
|
5642
|
-
const swipeStrength = swipe?.swipeStrength ?? null;
|
|
5643
|
-
const {
|
|
5644
|
-
snapPoints,
|
|
5645
|
-
activeSnapPoint,
|
|
5646
|
-
activeSnapPointOffset
|
|
5647
|
-
} = useDrawerSnapPoints();
|
|
5648
|
-
useDialogPortalContext();
|
|
5649
|
-
const [popupHeight, setPopupHeight] = React.useState(0);
|
|
5650
|
-
const popupHeightRef = React.useRef(0);
|
|
5651
|
-
const measureHeight = useStableCallback(() => {
|
|
5652
|
-
const popupElement = store.context.popupRef.current;
|
|
5653
|
-
if (!popupElement) {
|
|
5654
|
-
return;
|
|
5655
|
-
}
|
|
5656
|
-
const offsetHeight = popupElement.offsetHeight;
|
|
5657
|
-
|
|
5658
|
-
// Only skip while the element is still actually stretched beyond its last measured height.
|
|
5659
|
-
if (popupHeightRef.current > 0 && frontmostHeight > popupHeightRef.current && offsetHeight > popupHeightRef.current) {
|
|
5660
|
-
return;
|
|
5661
|
-
}
|
|
5662
|
-
const keepHeightWhileNested = popupHeightRef.current > 0 && hasNestedDrawer;
|
|
5663
|
-
if (keepHeightWhileNested) {
|
|
5664
|
-
const oldHeight = popupHeightRef.current;
|
|
5665
|
-
setPopupHeight(oldHeight);
|
|
5666
|
-
onPopupHeightChange(oldHeight);
|
|
5667
|
-
return;
|
|
5668
|
-
}
|
|
5669
|
-
const nextHeight = offsetHeight;
|
|
5670
|
-
if (nextHeight === popupHeightRef.current) {
|
|
5671
|
-
return;
|
|
5672
|
-
}
|
|
5673
|
-
popupHeightRef.current = nextHeight;
|
|
5674
|
-
setPopupHeight(nextHeight);
|
|
5675
|
-
onPopupHeightChange(nextHeight);
|
|
5676
|
-
});
|
|
5677
|
-
useIsoLayoutEffect(() => {
|
|
5678
|
-
if (!mounted) {
|
|
5679
|
-
popupHeightRef.current = 0;
|
|
5680
|
-
setPopupHeight(0);
|
|
5681
|
-
onPopupHeightChange(0);
|
|
5682
|
-
return undefined;
|
|
5683
|
-
}
|
|
5684
|
-
const popupElement = store.context.popupRef.current;
|
|
5685
|
-
if (!popupElement) {
|
|
5686
|
-
return undefined;
|
|
5687
|
-
}
|
|
5688
|
-
removeCSSVariableInheritance();
|
|
5689
|
-
measureHeight();
|
|
5690
|
-
if (typeof ResizeObserver !== 'function') {
|
|
5691
|
-
return undefined;
|
|
5692
|
-
}
|
|
5693
|
-
const resizeObserver = new ResizeObserver(measureHeight);
|
|
5694
|
-
resizeObserver.observe(popupElement);
|
|
5695
|
-
return () => {
|
|
5696
|
-
resizeObserver.disconnect();
|
|
5697
|
-
};
|
|
5698
|
-
}, [measureHeight, mounted, nestedDrawerOpen, onPopupHeightChange, store.context.popupRef]);
|
|
5699
|
-
useIsoLayoutEffect(() => {
|
|
5700
|
-
const popupRef = store.context.popupRef;
|
|
5701
|
-
const syncNestedSwipeProgress = () => {
|
|
5702
|
-
const popupElement = popupRef.current;
|
|
5703
|
-
if (!popupElement) {
|
|
5704
|
-
return;
|
|
5444
|
+
}, [measureHeight, mounted, nestedDrawerOpen, onPopupHeightChange, store.context.popupRef]);
|
|
5445
|
+
useIsoLayoutEffect(() => {
|
|
5446
|
+
const popupRef = store.context.popupRef;
|
|
5447
|
+
const syncNestedSwipeProgress = () => {
|
|
5448
|
+
const popupElement = popupRef.current;
|
|
5449
|
+
if (!popupElement) {
|
|
5450
|
+
return;
|
|
5705
5451
|
}
|
|
5706
5452
|
const progress = nestedSwipeProgressStore.getSnapshot();
|
|
5707
5453
|
if (progress > 0) {
|
|
@@ -5831,14 +5577,726 @@ const DrawerPopup = /*#__PURE__*/React.forwardRef(function DrawerPopup(component
|
|
|
5831
5577
|
});
|
|
5832
5578
|
if (process.env.NODE_ENV !== "production") DrawerPopup.displayName = "DrawerPopup";
|
|
5833
5579
|
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5580
|
+
function inertValue(value) {
|
|
5581
|
+
if (isReactVersionAtLeast(19)) {
|
|
5582
|
+
return value;
|
|
5583
|
+
}
|
|
5584
|
+
// compatibility with React < 19
|
|
5585
|
+
return value ? 'true' : undefined;
|
|
5586
|
+
}
|
|
5587
|
+
|
|
5588
|
+
const InternalBackdrop = /*#__PURE__*/React.forwardRef(function InternalBackdrop(props, ref) {
|
|
5589
|
+
const {
|
|
5590
|
+
cutout,
|
|
5591
|
+
...otherProps
|
|
5592
|
+
} = props;
|
|
5593
|
+
let clipPath;
|
|
5594
|
+
if (cutout) {
|
|
5595
|
+
const rect = cutout?.getBoundingClientRect();
|
|
5596
|
+
clipPath = `polygon(
|
|
5597
|
+
0% 0%,
|
|
5598
|
+
100% 0%,
|
|
5599
|
+
100% 100%,
|
|
5600
|
+
0% 100%,
|
|
5601
|
+
0% 0%,
|
|
5602
|
+
${rect.left}px ${rect.top}px,
|
|
5603
|
+
${rect.left}px ${rect.bottom}px,
|
|
5604
|
+
${rect.right}px ${rect.bottom}px,
|
|
5605
|
+
${rect.right}px ${rect.top}px,
|
|
5606
|
+
${rect.left}px ${rect.top}px
|
|
5607
|
+
)`;
|
|
5608
|
+
}
|
|
5609
|
+
return /*#__PURE__*/jsx("div", {
|
|
5610
|
+
ref: ref,
|
|
5611
|
+
role: "presentation"
|
|
5612
|
+
// Ensures Floating UI's outside press detection runs, as it considers
|
|
5613
|
+
// it an element that existed when the popup rendered.
|
|
5614
|
+
,
|
|
5615
|
+
"data-base-ui-inert": "",
|
|
5616
|
+
...otherProps,
|
|
5617
|
+
style: {
|
|
5618
|
+
position: 'fixed',
|
|
5619
|
+
inset: 0,
|
|
5620
|
+
userSelect: 'none',
|
|
5621
|
+
WebkitUserSelect: 'none',
|
|
5622
|
+
clipPath
|
|
5623
|
+
}
|
|
5624
|
+
});
|
|
5625
|
+
});
|
|
5626
|
+
if (process.env.NODE_ENV !== "production") InternalBackdrop.displayName = "InternalBackdrop";
|
|
5627
|
+
|
|
5628
|
+
const DialogPortal = /*#__PURE__*/React.forwardRef(function DialogPortal(props, forwardedRef) {
|
|
5629
|
+
const {
|
|
5630
|
+
keepMounted = false,
|
|
5631
|
+
...portalProps
|
|
5632
|
+
} = props;
|
|
5633
|
+
const {
|
|
5634
|
+
store
|
|
5635
|
+
} = useDialogRootContext();
|
|
5636
|
+
const mounted = store.useState('mounted');
|
|
5637
|
+
const modal = store.useState('modal');
|
|
5638
|
+
const open = store.useState('open');
|
|
5639
|
+
const shouldRender = mounted || keepMounted;
|
|
5640
|
+
if (!shouldRender) {
|
|
5641
|
+
return null;
|
|
5642
|
+
}
|
|
5643
|
+
return /*#__PURE__*/jsx(DialogPortalContext.Provider, {
|
|
5644
|
+
value: keepMounted,
|
|
5645
|
+
children: /*#__PURE__*/jsxs(FloatingPortal, {
|
|
5646
|
+
ref: forwardedRef,
|
|
5647
|
+
...portalProps,
|
|
5648
|
+
children: [mounted && modal === true && /*#__PURE__*/jsx(InternalBackdrop, {
|
|
5649
|
+
ref: store.context.internalBackdropRef,
|
|
5650
|
+
inert: inertValue(!open)
|
|
5651
|
+
}), props.children]
|
|
5652
|
+
})
|
|
5653
|
+
});
|
|
5654
|
+
});
|
|
5655
|
+
if (process.env.NODE_ENV !== "production") DialogPortal.displayName = "DialogPortal";
|
|
5656
|
+
|
|
5657
|
+
/**
|
|
5658
|
+
* A portal element that moves the popup to a different part of the DOM.
|
|
5659
|
+
* By default, the portal element is appended to `<body>`.
|
|
5660
|
+
* Renders a `<div>` element.
|
|
5661
|
+
*
|
|
5662
|
+
* Documentation: [Base UI Drawer](https://base-ui.com/react/components/drawer)
|
|
5663
|
+
*/
|
|
5664
|
+
const DrawerPortal = DialogPortal;
|
|
5665
|
+
|
|
5666
|
+
function useControlled({
|
|
5667
|
+
controlled,
|
|
5668
|
+
default: defaultProp,
|
|
5669
|
+
name,
|
|
5670
|
+
state = 'value'
|
|
5671
|
+
}) {
|
|
5672
|
+
// isControlled is ignored in the hook dependency lists as it should never change.
|
|
5673
|
+
const {
|
|
5674
|
+
current: isControlled
|
|
5675
|
+
} = React.useRef(controlled !== undefined);
|
|
5676
|
+
const [valueState, setValue] = React.useState(defaultProp);
|
|
5677
|
+
const value = isControlled ? controlled : valueState;
|
|
5678
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
5679
|
+
React.useEffect(() => {
|
|
5680
|
+
if (isControlled !== (controlled !== undefined)) {
|
|
5681
|
+
console.error([`Base UI: A component is changing the ${isControlled ? '' : 'un'}controlled ${state} state of ${name} to be ${isControlled ? 'un' : ''}controlled.`, 'Elements should not switch from uncontrolled to controlled (or vice versa).', `Decide between using a controlled or uncontrolled ${name} ` + 'element for the lifetime of the component.', "The nature of the state is determined during the first render. It's considered controlled if the value is not `undefined`.", 'More info: https://fb.me/react-controlled-components'].join('\n'));
|
|
5682
|
+
}
|
|
5683
|
+
}, [state, name, controlled]);
|
|
5684
|
+
const {
|
|
5685
|
+
current: defaultValue
|
|
5686
|
+
} = React.useRef(defaultProp);
|
|
5687
|
+
React.useEffect(() => {
|
|
5688
|
+
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is for more details.
|
|
5689
|
+
if (!isControlled && JSON.stringify(defaultValue) !== JSON.stringify(defaultProp)) {
|
|
5690
|
+
console.error([`Base UI: A component is changing the default ${state} state of an uncontrolled ${name} after being initialized. ` + `To suppress this warning opt to use a controlled ${name}.`].join('\n'));
|
|
5691
|
+
}
|
|
5692
|
+
}, [JSON.stringify(defaultProp)]);
|
|
5693
|
+
}
|
|
5694
|
+
const setValueIfUncontrolled = React.useCallback(newValue => {
|
|
5695
|
+
if (!isControlled) {
|
|
5696
|
+
setValue(newValue);
|
|
5697
|
+
}
|
|
5698
|
+
}, []);
|
|
5699
|
+
return [value, setValueIfUncontrolled];
|
|
5700
|
+
}
|
|
5701
|
+
|
|
5702
|
+
function useOnFirstRender(fn) {
|
|
5703
|
+
const ref = React.useRef(true);
|
|
5704
|
+
if (ref.current) {
|
|
5705
|
+
ref.current = false;
|
|
5706
|
+
fn();
|
|
5707
|
+
}
|
|
5708
|
+
}
|
|
5709
|
+
|
|
5710
|
+
let originalHtmlStyles = {};
|
|
5711
|
+
let originalBodyStyles = {};
|
|
5712
|
+
let originalHtmlScrollBehavior = '';
|
|
5713
|
+
function hasInsetScrollbars(referenceElement) {
|
|
5714
|
+
if (typeof document === 'undefined') {
|
|
5715
|
+
return false;
|
|
5716
|
+
}
|
|
5717
|
+
const doc = ownerDocument(referenceElement);
|
|
5718
|
+
const win = getWindow(doc);
|
|
5719
|
+
return win.innerWidth - doc.documentElement.clientWidth > 0;
|
|
5720
|
+
}
|
|
5721
|
+
function supportsStableScrollbarGutter(referenceElement) {
|
|
5722
|
+
const supported = typeof CSS !== 'undefined' && CSS.supports && CSS.supports('scrollbar-gutter', 'stable');
|
|
5723
|
+
if (!supported || typeof document === 'undefined') {
|
|
5724
|
+
return false;
|
|
5725
|
+
}
|
|
5726
|
+
const doc = ownerDocument(referenceElement);
|
|
5727
|
+
const html = doc.documentElement;
|
|
5728
|
+
const body = doc.body;
|
|
5729
|
+
const scrollContainer = isOverflowElement(html) ? html : body;
|
|
5730
|
+
const originalScrollContainerOverflowY = scrollContainer.style.overflowY;
|
|
5731
|
+
const originalHtmlStyleGutter = html.style.scrollbarGutter;
|
|
5732
|
+
html.style.scrollbarGutter = 'stable';
|
|
5733
|
+
scrollContainer.style.overflowY = 'scroll';
|
|
5734
|
+
const before = scrollContainer.offsetWidth;
|
|
5735
|
+
scrollContainer.style.overflowY = 'hidden';
|
|
5736
|
+
const after = scrollContainer.offsetWidth;
|
|
5737
|
+
scrollContainer.style.overflowY = originalScrollContainerOverflowY;
|
|
5738
|
+
html.style.scrollbarGutter = originalHtmlStyleGutter;
|
|
5739
|
+
return before === after;
|
|
5740
|
+
}
|
|
5741
|
+
function preventScrollOverlayScrollbars(referenceElement) {
|
|
5742
|
+
const doc = ownerDocument(referenceElement);
|
|
5743
|
+
const html = doc.documentElement;
|
|
5744
|
+
const body = doc.body;
|
|
5745
|
+
|
|
5746
|
+
// If an `overflow` style is present on <html>, we need to lock it, because a lock on <body>
|
|
5747
|
+
// won't have any effect.
|
|
5748
|
+
// But if <body> has an `overflow` style (like `overflow-x: hidden`), we need to lock it
|
|
5749
|
+
// instead, as sticky elements shift otherwise.
|
|
5750
|
+
const elementToLock = isOverflowElement(html) ? html : body;
|
|
5751
|
+
const originalElementToLockStyles = {
|
|
5752
|
+
overflowY: elementToLock.style.overflowY,
|
|
5753
|
+
overflowX: elementToLock.style.overflowX
|
|
5754
|
+
};
|
|
5755
|
+
Object.assign(elementToLock.style, {
|
|
5756
|
+
overflowY: 'hidden',
|
|
5757
|
+
overflowX: 'hidden'
|
|
5758
|
+
});
|
|
5759
|
+
return () => {
|
|
5760
|
+
Object.assign(elementToLock.style, originalElementToLockStyles);
|
|
5761
|
+
};
|
|
5762
|
+
}
|
|
5763
|
+
function preventScrollInsetScrollbars(referenceElement) {
|
|
5764
|
+
const doc = ownerDocument(referenceElement);
|
|
5765
|
+
const html = doc.documentElement;
|
|
5766
|
+
const body = doc.body;
|
|
5767
|
+
const win = getWindow(html);
|
|
5768
|
+
let scrollTop = 0;
|
|
5769
|
+
let scrollLeft = 0;
|
|
5770
|
+
let updateGutterOnly = false;
|
|
5771
|
+
const resizeFrame = AnimationFrame.create();
|
|
5772
|
+
|
|
5773
|
+
// Pinch-zoom in Safari causes a shift. Just don't lock scroll if there's any pinch-zoom.
|
|
5774
|
+
if (isWebKit && (win.visualViewport?.scale ?? 1) !== 1) {
|
|
5775
|
+
return () => {};
|
|
5776
|
+
}
|
|
5777
|
+
function lockScroll() {
|
|
5778
|
+
/* DOM reads: */
|
|
5779
|
+
|
|
5780
|
+
const htmlStyles = win.getComputedStyle(html);
|
|
5781
|
+
const bodyStyles = win.getComputedStyle(body);
|
|
5782
|
+
const htmlScrollbarGutterValue = htmlStyles.scrollbarGutter || '';
|
|
5783
|
+
const hasBothEdges = htmlScrollbarGutterValue.includes('both-edges');
|
|
5784
|
+
const scrollbarGutterValue = hasBothEdges ? 'stable both-edges' : 'stable';
|
|
5785
|
+
scrollTop = html.scrollTop;
|
|
5786
|
+
scrollLeft = html.scrollLeft;
|
|
5787
|
+
originalHtmlStyles = {
|
|
5788
|
+
scrollbarGutter: html.style.scrollbarGutter,
|
|
5789
|
+
overflowY: html.style.overflowY,
|
|
5790
|
+
overflowX: html.style.overflowX
|
|
5791
|
+
};
|
|
5792
|
+
originalHtmlScrollBehavior = html.style.scrollBehavior;
|
|
5793
|
+
originalBodyStyles = {
|
|
5794
|
+
position: body.style.position,
|
|
5795
|
+
height: body.style.height,
|
|
5796
|
+
width: body.style.width,
|
|
5797
|
+
boxSizing: body.style.boxSizing,
|
|
5798
|
+
overflowY: body.style.overflowY,
|
|
5799
|
+
overflowX: body.style.overflowX,
|
|
5800
|
+
scrollBehavior: body.style.scrollBehavior
|
|
5801
|
+
};
|
|
5802
|
+
const isScrollableY = html.scrollHeight > html.clientHeight;
|
|
5803
|
+
const isScrollableX = html.scrollWidth > html.clientWidth;
|
|
5804
|
+
const hasConstantOverflowY = htmlStyles.overflowY === 'scroll' || bodyStyles.overflowY === 'scroll';
|
|
5805
|
+
const hasConstantOverflowX = htmlStyles.overflowX === 'scroll' || bodyStyles.overflowX === 'scroll';
|
|
5806
|
+
|
|
5807
|
+
// Values can be negative in Firefox
|
|
5808
|
+
const scrollbarWidth = Math.max(0, win.innerWidth - body.clientWidth);
|
|
5809
|
+
const scrollbarHeight = Math.max(0, win.innerHeight - body.clientHeight);
|
|
5810
|
+
|
|
5811
|
+
// Avoid shift due to the default <body> margin. This does cause elements to be clipped
|
|
5812
|
+
// with whitespace. Warn if <body> has margins?
|
|
5813
|
+
const marginY = parseFloat(bodyStyles.marginTop) + parseFloat(bodyStyles.marginBottom);
|
|
5814
|
+
const marginX = parseFloat(bodyStyles.marginLeft) + parseFloat(bodyStyles.marginRight);
|
|
5815
|
+
const elementToLock = isOverflowElement(html) ? html : body;
|
|
5816
|
+
updateGutterOnly = supportsStableScrollbarGutter(referenceElement);
|
|
5817
|
+
|
|
5818
|
+
/*
|
|
5819
|
+
* DOM writes:
|
|
5820
|
+
* Do not read the DOM past this point!
|
|
5821
|
+
*/
|
|
5822
|
+
|
|
5823
|
+
if (updateGutterOnly) {
|
|
5824
|
+
html.style.scrollbarGutter = scrollbarGutterValue;
|
|
5825
|
+
elementToLock.style.overflowY = 'hidden';
|
|
5826
|
+
elementToLock.style.overflowX = 'hidden';
|
|
5827
|
+
return;
|
|
5828
|
+
}
|
|
5829
|
+
Object.assign(html.style, {
|
|
5830
|
+
scrollbarGutter: scrollbarGutterValue,
|
|
5831
|
+
overflowY: 'hidden',
|
|
5832
|
+
overflowX: 'hidden'
|
|
5833
|
+
});
|
|
5834
|
+
if (isScrollableY || hasConstantOverflowY) {
|
|
5835
|
+
html.style.overflowY = 'scroll';
|
|
5836
|
+
}
|
|
5837
|
+
if (isScrollableX || hasConstantOverflowX) {
|
|
5838
|
+
html.style.overflowX = 'scroll';
|
|
5839
|
+
}
|
|
5840
|
+
Object.assign(body.style, {
|
|
5841
|
+
position: 'relative',
|
|
5842
|
+
height: marginY || scrollbarHeight ? `calc(100dvh - ${marginY + scrollbarHeight}px)` : '100dvh',
|
|
5843
|
+
width: marginX || scrollbarWidth ? `calc(100vw - ${marginX + scrollbarWidth}px)` : '100vw',
|
|
5844
|
+
boxSizing: 'border-box',
|
|
5845
|
+
overflow: 'hidden',
|
|
5846
|
+
scrollBehavior: 'unset'
|
|
5847
|
+
});
|
|
5848
|
+
body.scrollTop = scrollTop;
|
|
5849
|
+
body.scrollLeft = scrollLeft;
|
|
5850
|
+
html.setAttribute('data-base-ui-scroll-locked', '');
|
|
5851
|
+
html.style.scrollBehavior = 'unset';
|
|
5852
|
+
}
|
|
5853
|
+
function cleanup() {
|
|
5854
|
+
Object.assign(html.style, originalHtmlStyles);
|
|
5855
|
+
Object.assign(body.style, originalBodyStyles);
|
|
5856
|
+
if (!updateGutterOnly) {
|
|
5857
|
+
html.scrollTop = scrollTop;
|
|
5858
|
+
html.scrollLeft = scrollLeft;
|
|
5859
|
+
html.removeAttribute('data-base-ui-scroll-locked');
|
|
5860
|
+
html.style.scrollBehavior = originalHtmlScrollBehavior;
|
|
5861
|
+
}
|
|
5862
|
+
}
|
|
5863
|
+
function handleResize() {
|
|
5864
|
+
cleanup();
|
|
5865
|
+
resizeFrame.request(lockScroll);
|
|
5866
|
+
}
|
|
5867
|
+
lockScroll();
|
|
5868
|
+
win.addEventListener('resize', handleResize);
|
|
5869
|
+
return () => {
|
|
5870
|
+
resizeFrame.cancel();
|
|
5871
|
+
cleanup();
|
|
5872
|
+
// Sometimes this cleanup can be run after test teardown
|
|
5873
|
+
// because it is called in a `setTimeout(fn, 0)`,
|
|
5874
|
+
// in which case `removeEventListener` wouldn't be available,
|
|
5875
|
+
// so we check for it to avoid test failures.
|
|
5876
|
+
if (typeof win.removeEventListener === 'function') {
|
|
5877
|
+
win.removeEventListener('resize', handleResize);
|
|
5878
|
+
}
|
|
5879
|
+
};
|
|
5880
|
+
}
|
|
5881
|
+
class ScrollLocker {
|
|
5882
|
+
lockCount = 0;
|
|
5883
|
+
restore = null;
|
|
5884
|
+
timeoutLock = Timeout.create();
|
|
5885
|
+
timeoutUnlock = Timeout.create();
|
|
5886
|
+
acquire(referenceElement) {
|
|
5887
|
+
this.lockCount += 1;
|
|
5888
|
+
if (this.lockCount === 1 && this.restore === null) {
|
|
5889
|
+
this.timeoutLock.start(0, () => this.lock(referenceElement));
|
|
5890
|
+
}
|
|
5891
|
+
return this.release;
|
|
5892
|
+
}
|
|
5893
|
+
release = () => {
|
|
5894
|
+
this.lockCount -= 1;
|
|
5895
|
+
if (this.lockCount === 0 && this.restore) {
|
|
5896
|
+
this.timeoutUnlock.start(0, this.unlock);
|
|
5897
|
+
}
|
|
5898
|
+
};
|
|
5899
|
+
unlock = () => {
|
|
5900
|
+
if (this.lockCount === 0 && this.restore) {
|
|
5901
|
+
this.restore?.();
|
|
5902
|
+
this.restore = null;
|
|
5903
|
+
}
|
|
5904
|
+
};
|
|
5905
|
+
lock(referenceElement) {
|
|
5906
|
+
if (this.lockCount === 0 || this.restore !== null) {
|
|
5907
|
+
return;
|
|
5908
|
+
}
|
|
5909
|
+
const doc = ownerDocument(referenceElement);
|
|
5910
|
+
const html = doc.documentElement;
|
|
5911
|
+
const htmlOverflowY = getWindow(html).getComputedStyle(html).overflowY;
|
|
5912
|
+
|
|
5913
|
+
// If the site author already hid overflow on <html>, respect it and bail out.
|
|
5914
|
+
if (htmlOverflowY === 'hidden' || htmlOverflowY === 'clip') {
|
|
5915
|
+
this.restore = NOOP;
|
|
5916
|
+
return;
|
|
5917
|
+
}
|
|
5918
|
+
const hasOverlayScrollbars = isIOS || !hasInsetScrollbars(referenceElement);
|
|
5919
|
+
|
|
5920
|
+
// On iOS, scroll locking does not work if the navbar is collapsed. Due to numerous
|
|
5921
|
+
// side effects and bugs that arise on iOS, it must be researched extensively before
|
|
5922
|
+
// being enabled to ensure it doesn't cause the following issues:
|
|
5923
|
+
// - Textboxes must scroll into view when focused, nor cause a glitchy scroll animation.
|
|
5924
|
+
// - The navbar must not force itself into view and cause layout shift.
|
|
5925
|
+
// - Scroll containers must not flicker upon closing a popup when it has an exit animation.
|
|
5926
|
+
this.restore = hasOverlayScrollbars ? preventScrollOverlayScrollbars(referenceElement) : preventScrollInsetScrollbars(referenceElement);
|
|
5927
|
+
}
|
|
5928
|
+
}
|
|
5929
|
+
const SCROLL_LOCKER = new ScrollLocker();
|
|
5930
|
+
|
|
5931
|
+
/**
|
|
5932
|
+
* Locks the scroll of the document when enabled.
|
|
5933
|
+
*
|
|
5934
|
+
* @param enabled - Whether to enable the scroll lock.
|
|
5935
|
+
* @param referenceElement - Element to use as a reference for lock calculations.
|
|
5936
|
+
*/
|
|
5937
|
+
function useScrollLock(enabled = true, referenceElement = null) {
|
|
5938
|
+
useIsoLayoutEffect(() => {
|
|
5939
|
+
if (!enabled) {
|
|
5940
|
+
return undefined;
|
|
5941
|
+
}
|
|
5942
|
+
return SCROLL_LOCKER.acquire(referenceElement);
|
|
5943
|
+
}, [enabled, referenceElement]);
|
|
5944
|
+
}
|
|
5945
|
+
|
|
5946
|
+
/**
|
|
5947
|
+
* Provides a cross-browser way to determine the type of the pointer used to click.
|
|
5948
|
+
* Safari and Firefox do not provide the PointerEvent to the click handler (they use MouseEvent) yet.
|
|
5949
|
+
* Additionally, this implementation detects if the click was triggered by the keyboard.
|
|
5950
|
+
*
|
|
5951
|
+
* @param handler The function to be called when the button is clicked. The first parameter is the original event and the second parameter is the pointer type.
|
|
5952
|
+
*/
|
|
5953
|
+
function useEnhancedClickHandler(handler) {
|
|
5954
|
+
const lastClickInteractionTypeRef = React.useRef('');
|
|
5955
|
+
const handlePointerDown = React.useCallback(event => {
|
|
5956
|
+
if (event.defaultPrevented) {
|
|
5957
|
+
return;
|
|
5958
|
+
}
|
|
5959
|
+
lastClickInteractionTypeRef.current = event.pointerType;
|
|
5960
|
+
handler(event, event.pointerType);
|
|
5961
|
+
}, [handler]);
|
|
5962
|
+
const handleClick = React.useCallback(event => {
|
|
5963
|
+
// event.detail has the number of clicks performed on the element. 0 means it was triggered by the keyboard.
|
|
5964
|
+
if (event.detail === 0) {
|
|
5965
|
+
handler(event, 'keyboard');
|
|
5966
|
+
return;
|
|
5967
|
+
}
|
|
5968
|
+
if ('pointerType' in event) {
|
|
5969
|
+
// Chrome and Edge correctly use PointerEvent
|
|
5970
|
+
handler(event, event.pointerType);
|
|
5971
|
+
} else {
|
|
5972
|
+
handler(event, lastClickInteractionTypeRef.current);
|
|
5973
|
+
}
|
|
5974
|
+
lastClickInteractionTypeRef.current = '';
|
|
5975
|
+
}, [handler]);
|
|
5976
|
+
return {
|
|
5977
|
+
onClick: handleClick,
|
|
5978
|
+
onPointerDown: handlePointerDown
|
|
5979
|
+
};
|
|
5980
|
+
}
|
|
5981
|
+
|
|
5982
|
+
function useValueChanged(value, onChange) {
|
|
5983
|
+
const valueRef = React.useRef(value);
|
|
5984
|
+
const onChangeCallback = useStableCallback(onChange);
|
|
5985
|
+
useIsoLayoutEffect(() => {
|
|
5986
|
+
if (valueRef.current === value) {
|
|
5987
|
+
return;
|
|
5988
|
+
}
|
|
5989
|
+
onChangeCallback(valueRef.current);
|
|
5990
|
+
}, [value, onChangeCallback]);
|
|
5991
|
+
useIsoLayoutEffect(() => {
|
|
5992
|
+
valueRef.current = value;
|
|
5993
|
+
}, [value]);
|
|
5994
|
+
}
|
|
5995
|
+
|
|
5996
|
+
/**
|
|
5997
|
+
* Determines the interaction type (keyboard, mouse, touch, etc.) that opened the component.
|
|
5998
|
+
*
|
|
5999
|
+
* @param open The open state of the component.
|
|
6000
|
+
*/
|
|
6001
|
+
function useOpenInteractionType(open) {
|
|
6002
|
+
const [openMethod, setOpenMethod] = React.useState(null);
|
|
6003
|
+
const handleTriggerClick = useStableCallback((_, interactionType) => {
|
|
6004
|
+
if (!open) {
|
|
6005
|
+
setOpenMethod(interactionType || (
|
|
6006
|
+
// On iOS Safari, the hitslop around touch targets means tapping outside an element's
|
|
6007
|
+
// bounds does not fire `pointerdown` but does fire `mousedown`. The `interactionType`
|
|
6008
|
+
// will be "" in that case.
|
|
6009
|
+
isIOS ? 'touch' : ''));
|
|
6010
|
+
}
|
|
6011
|
+
});
|
|
6012
|
+
useValueChanged(open, previousOpen => {
|
|
6013
|
+
if (previousOpen && !open) {
|
|
6014
|
+
setOpenMethod(null);
|
|
6015
|
+
}
|
|
6016
|
+
});
|
|
6017
|
+
const {
|
|
6018
|
+
onClick,
|
|
6019
|
+
onPointerDown
|
|
6020
|
+
} = useEnhancedClickHandler(handleTriggerClick);
|
|
6021
|
+
return React.useMemo(() => ({
|
|
6022
|
+
openMethod,
|
|
6023
|
+
triggerProps: {
|
|
6024
|
+
onClick,
|
|
6025
|
+
onPointerDown
|
|
6026
|
+
}
|
|
6027
|
+
}), [openMethod, onClick, onPointerDown]);
|
|
6028
|
+
}
|
|
6029
|
+
|
|
6030
|
+
function useDialogRoot(params) {
|
|
6031
|
+
const {
|
|
6032
|
+
store,
|
|
6033
|
+
parentContext,
|
|
6034
|
+
actionsRef
|
|
6035
|
+
} = params;
|
|
6036
|
+
const open = store.useState('open');
|
|
6037
|
+
const disablePointerDismissal = store.useState('disablePointerDismissal');
|
|
6038
|
+
const modal = store.useState('modal');
|
|
6039
|
+
const popupElement = store.useState('popupElement');
|
|
6040
|
+
const {
|
|
6041
|
+
openMethod,
|
|
6042
|
+
triggerProps
|
|
6043
|
+
} = useOpenInteractionType(open);
|
|
6044
|
+
useImplicitActiveTrigger(store);
|
|
6045
|
+
const {
|
|
6046
|
+
forceUnmount
|
|
6047
|
+
} = useOpenStateTransitions(open, store);
|
|
6048
|
+
const createDialogEventDetails = useStableCallback(reason => {
|
|
6049
|
+
const details = createChangeEventDetails(reason);
|
|
6050
|
+
details.preventUnmountOnClose = () => {
|
|
6051
|
+
store.set('preventUnmountingOnClose', true);
|
|
6052
|
+
};
|
|
6053
|
+
return details;
|
|
6054
|
+
});
|
|
6055
|
+
const handleImperativeClose = React.useCallback(() => {
|
|
6056
|
+
store.setOpen(false, createDialogEventDetails(imperativeAction));
|
|
6057
|
+
}, [store, createDialogEventDetails]);
|
|
6058
|
+
React.useImperativeHandle(actionsRef, () => ({
|
|
6059
|
+
unmount: forceUnmount,
|
|
6060
|
+
close: handleImperativeClose
|
|
6061
|
+
}), [forceUnmount, handleImperativeClose]);
|
|
6062
|
+
const floatingRootContext = useSyncedFloatingRootContext({
|
|
6063
|
+
popupStore: store,
|
|
6064
|
+
onOpenChange: store.setOpen,
|
|
6065
|
+
treatPopupAsFloatingElement: true,
|
|
6066
|
+
noEmit: true
|
|
6067
|
+
});
|
|
6068
|
+
const [ownNestedOpenDialogs, setOwnNestedOpenDialogs] = React.useState(0);
|
|
6069
|
+
const isTopmost = ownNestedOpenDialogs === 0;
|
|
6070
|
+
const role = useRole(floatingRootContext);
|
|
6071
|
+
const dismiss = useDismiss(floatingRootContext, {
|
|
6072
|
+
outsidePressEvent() {
|
|
6073
|
+
if (store.context.internalBackdropRef.current || store.context.backdropRef.current) {
|
|
6074
|
+
return 'intentional';
|
|
6075
|
+
}
|
|
6076
|
+
// Ensure `aria-hidden` on outside elements is removed immediately
|
|
6077
|
+
// on outside press when trapping focus.
|
|
6078
|
+
return {
|
|
6079
|
+
mouse: modal === 'trap-focus' ? 'sloppy' : 'intentional',
|
|
6080
|
+
touch: 'sloppy'
|
|
6081
|
+
};
|
|
6082
|
+
},
|
|
6083
|
+
outsidePress(event) {
|
|
6084
|
+
if (!store.context.outsidePressEnabledRef.current) {
|
|
6085
|
+
return false;
|
|
6086
|
+
}
|
|
6087
|
+
|
|
6088
|
+
// For mouse events, only accept left button (button 0)
|
|
6089
|
+
// For touch events, a single touch is equivalent to left button
|
|
6090
|
+
if ('button' in event && event.button !== 0) {
|
|
6091
|
+
return false;
|
|
6092
|
+
}
|
|
6093
|
+
if ('touches' in event && event.touches.length !== 1) {
|
|
6094
|
+
return false;
|
|
6095
|
+
}
|
|
6096
|
+
const target = getTarget(event);
|
|
6097
|
+
if (isTopmost && !disablePointerDismissal) {
|
|
6098
|
+
const eventTarget = target;
|
|
6099
|
+
// Only close if the click occurred on the dialog's owning backdrop.
|
|
6100
|
+
// This supports multiple modal dialogs that aren't nested in the React tree:
|
|
6101
|
+
// https://github.com/mui/base-ui/issues/1320
|
|
6102
|
+
if (modal) {
|
|
6103
|
+
return store.context.internalBackdropRef.current || store.context.backdropRef.current ? store.context.internalBackdropRef.current === eventTarget || store.context.backdropRef.current === eventTarget || contains(eventTarget, popupElement) && !eventTarget?.hasAttribute('data-base-ui-portal') : true;
|
|
6104
|
+
}
|
|
6105
|
+
return true;
|
|
6106
|
+
}
|
|
6107
|
+
return false;
|
|
6108
|
+
},
|
|
6109
|
+
escapeKey: isTopmost
|
|
6110
|
+
});
|
|
6111
|
+
useScrollLock(open && modal === true, popupElement);
|
|
6112
|
+
const {
|
|
6113
|
+
getReferenceProps,
|
|
6114
|
+
getFloatingProps,
|
|
6115
|
+
getTriggerProps
|
|
6116
|
+
} = useInteractions([role, dismiss]);
|
|
6117
|
+
|
|
6118
|
+
// Listen for nested open/close events on this store to maintain the count
|
|
6119
|
+
store.useContextCallback('onNestedDialogOpen', ownChildrenCount => {
|
|
6120
|
+
setOwnNestedOpenDialogs(ownChildrenCount + 1);
|
|
6121
|
+
});
|
|
6122
|
+
store.useContextCallback('onNestedDialogClose', () => {
|
|
6123
|
+
setOwnNestedOpenDialogs(0);
|
|
6124
|
+
});
|
|
6125
|
+
|
|
6126
|
+
// Notify parent of our open/close state using parent callbacks, if any
|
|
6127
|
+
React.useEffect(() => {
|
|
6128
|
+
if (parentContext?.onNestedDialogOpen && open) {
|
|
6129
|
+
parentContext.onNestedDialogOpen(ownNestedOpenDialogs);
|
|
6130
|
+
}
|
|
6131
|
+
if (parentContext?.onNestedDialogClose && !open) {
|
|
6132
|
+
parentContext.onNestedDialogClose();
|
|
6133
|
+
}
|
|
6134
|
+
return () => {
|
|
6135
|
+
if (parentContext?.onNestedDialogClose && open) {
|
|
6136
|
+
parentContext.onNestedDialogClose();
|
|
6137
|
+
}
|
|
6138
|
+
};
|
|
6139
|
+
}, [open, parentContext, ownNestedOpenDialogs]);
|
|
6140
|
+
const activeTriggerProps = React.useMemo(() => getReferenceProps(triggerProps), [getReferenceProps, triggerProps]);
|
|
6141
|
+
const inactiveTriggerProps = React.useMemo(() => getTriggerProps(triggerProps), [getTriggerProps, triggerProps]);
|
|
6142
|
+
const popupProps = React.useMemo(() => getFloatingProps(), [getFloatingProps]);
|
|
6143
|
+
store.useSyncedValues({
|
|
6144
|
+
openMethod,
|
|
6145
|
+
activeTriggerProps,
|
|
6146
|
+
inactiveTriggerProps,
|
|
6147
|
+
popupProps,
|
|
6148
|
+
floatingRootContext,
|
|
6149
|
+
nestedOpenDialogCount: ownNestedOpenDialogs
|
|
6150
|
+
});
|
|
6151
|
+
}
|
|
6152
|
+
|
|
6153
|
+
const selectors = {
|
|
6154
|
+
...popupStoreSelectors,
|
|
6155
|
+
modal: createSelector(state => state.modal),
|
|
6156
|
+
nested: createSelector(state => state.nested),
|
|
6157
|
+
nestedOpenDialogCount: createSelector(state => state.nestedOpenDialogCount),
|
|
6158
|
+
disablePointerDismissal: createSelector(state => state.disablePointerDismissal),
|
|
6159
|
+
openMethod: createSelector(state => state.openMethod),
|
|
6160
|
+
descriptionElementId: createSelector(state => state.descriptionElementId),
|
|
6161
|
+
titleElementId: createSelector(state => state.titleElementId),
|
|
6162
|
+
viewportElement: createSelector(state => state.viewportElement),
|
|
6163
|
+
role: createSelector(state => state.role)
|
|
6164
|
+
};
|
|
6165
|
+
class DialogStore extends ReactStore {
|
|
6166
|
+
constructor(initialState) {
|
|
6167
|
+
super(createInitialState(initialState), {
|
|
6168
|
+
popupRef: /*#__PURE__*/React.createRef(),
|
|
6169
|
+
backdropRef: /*#__PURE__*/React.createRef(),
|
|
6170
|
+
internalBackdropRef: /*#__PURE__*/React.createRef(),
|
|
6171
|
+
outsidePressEnabledRef: {
|
|
6172
|
+
current: true
|
|
6173
|
+
},
|
|
6174
|
+
triggerElements: new PopupTriggerMap(),
|
|
6175
|
+
onOpenChange: undefined,
|
|
6176
|
+
onOpenChangeComplete: undefined
|
|
6177
|
+
}, selectors);
|
|
6178
|
+
}
|
|
6179
|
+
setOpen = (nextOpen, eventDetails) => {
|
|
6180
|
+
eventDetails.preventUnmountOnClose = () => {
|
|
6181
|
+
this.set('preventUnmountingOnClose', true);
|
|
6182
|
+
};
|
|
6183
|
+
if (!nextOpen && eventDetails.trigger == null && this.state.activeTriggerId != null) {
|
|
6184
|
+
// When closing the dialog, pass the old trigger to the onOpenChange event
|
|
6185
|
+
// so it's not reset too early (potentially causing focus issues in controlled scenarios).
|
|
6186
|
+
eventDetails.trigger = this.state.activeTriggerElement ?? undefined;
|
|
6187
|
+
}
|
|
6188
|
+
this.context.onOpenChange?.(nextOpen, eventDetails);
|
|
6189
|
+
if (eventDetails.isCanceled) {
|
|
6190
|
+
return;
|
|
6191
|
+
}
|
|
6192
|
+
const details = {
|
|
6193
|
+
open: nextOpen,
|
|
6194
|
+
nativeEvent: eventDetails.event,
|
|
6195
|
+
reason: eventDetails.reason,
|
|
6196
|
+
nested: this.state.nested
|
|
6197
|
+
};
|
|
6198
|
+
this.state.floatingRootContext.context.events?.emit('openchange', details);
|
|
6199
|
+
const updatedState = {
|
|
6200
|
+
open: nextOpen
|
|
6201
|
+
};
|
|
6202
|
+
|
|
6203
|
+
// If a popup is closing, the `trigger` may be null.
|
|
6204
|
+
// We want to keep the previous value so that exit animations are played and focus is returned correctly.
|
|
6205
|
+
const newTriggerId = eventDetails.trigger?.id ?? null;
|
|
6206
|
+
if (newTriggerId || nextOpen) {
|
|
6207
|
+
updatedState.activeTriggerId = newTriggerId;
|
|
6208
|
+
updatedState.activeTriggerElement = eventDetails.trigger ?? null;
|
|
6209
|
+
}
|
|
6210
|
+
this.update(updatedState);
|
|
6211
|
+
};
|
|
6212
|
+
}
|
|
6213
|
+
function createInitialState(initialState = {}) {
|
|
6214
|
+
return {
|
|
6215
|
+
...createInitialPopupStoreState(),
|
|
6216
|
+
modal: true,
|
|
6217
|
+
disablePointerDismissal: false,
|
|
6218
|
+
popupElement: null,
|
|
6219
|
+
viewportElement: null,
|
|
6220
|
+
descriptionElementId: undefined,
|
|
6221
|
+
titleElementId: undefined,
|
|
6222
|
+
openMethod: null,
|
|
6223
|
+
nested: false,
|
|
6224
|
+
nestedOpenDialogCount: 0,
|
|
6225
|
+
role: 'dialog',
|
|
6226
|
+
...initialState
|
|
6227
|
+
};
|
|
6228
|
+
}
|
|
6229
|
+
|
|
6230
|
+
/**
|
|
6231
|
+
* Groups all parts of the dialog.
|
|
6232
|
+
* Doesn’t render its own HTML element.
|
|
6233
|
+
*
|
|
6234
|
+
* Documentation: [Base UI Dialog](https://base-ui.com/react/components/dialog)
|
|
6235
|
+
*/
|
|
6236
|
+
function DialogRoot(props) {
|
|
6237
|
+
const {
|
|
6238
|
+
children,
|
|
6239
|
+
open: openProp,
|
|
6240
|
+
defaultOpen = false,
|
|
6241
|
+
onOpenChange,
|
|
6242
|
+
onOpenChangeComplete,
|
|
6243
|
+
disablePointerDismissal = false,
|
|
6244
|
+
modal = true,
|
|
6245
|
+
actionsRef,
|
|
6246
|
+
handle,
|
|
6247
|
+
triggerId: triggerIdProp,
|
|
6248
|
+
defaultTriggerId: defaultTriggerIdProp = null
|
|
6249
|
+
} = props;
|
|
6250
|
+
const parentDialogRootContext = useDialogRootContext(true);
|
|
6251
|
+
const nested = Boolean(parentDialogRootContext);
|
|
6252
|
+
const store = useRefWithInit(() => {
|
|
6253
|
+
return handle?.store ?? new DialogStore({
|
|
6254
|
+
open: defaultOpen,
|
|
6255
|
+
openProp,
|
|
6256
|
+
activeTriggerId: defaultTriggerIdProp,
|
|
6257
|
+
triggerIdProp,
|
|
6258
|
+
modal,
|
|
6259
|
+
disablePointerDismissal,
|
|
6260
|
+
nested
|
|
6261
|
+
});
|
|
6262
|
+
}).current;
|
|
6263
|
+
|
|
6264
|
+
// Support initially open state when uncontrolled
|
|
6265
|
+
useOnFirstRender(() => {
|
|
6266
|
+
if (openProp === undefined && store.state.open === false && defaultOpen === true) {
|
|
6267
|
+
store.update({
|
|
6268
|
+
open: true,
|
|
6269
|
+
activeTriggerId: defaultTriggerIdProp
|
|
6270
|
+
});
|
|
6271
|
+
}
|
|
6272
|
+
});
|
|
6273
|
+
store.useControlledProp('openProp', openProp);
|
|
6274
|
+
store.useControlledProp('triggerIdProp', triggerIdProp);
|
|
6275
|
+
store.useSyncedValues({
|
|
6276
|
+
disablePointerDismissal,
|
|
6277
|
+
nested,
|
|
6278
|
+
modal
|
|
6279
|
+
});
|
|
6280
|
+
store.useContextCallback('onOpenChange', onOpenChange);
|
|
6281
|
+
store.useContextCallback('onOpenChangeComplete', onOpenChangeComplete);
|
|
6282
|
+
const payload = store.useState('payload');
|
|
6283
|
+
useDialogRoot({
|
|
6284
|
+
store,
|
|
6285
|
+
actionsRef,
|
|
6286
|
+
parentContext: parentDialogRootContext?.store.context,
|
|
6287
|
+
onOpenChange,
|
|
6288
|
+
triggerIdProp
|
|
6289
|
+
});
|
|
6290
|
+
const contextValue = React.useMemo(() => ({
|
|
6291
|
+
store
|
|
6292
|
+
}), [store]);
|
|
6293
|
+
return /*#__PURE__*/jsx(DialogRootContext.Provider, {
|
|
6294
|
+
value: contextValue,
|
|
6295
|
+
children: typeof children === 'function' ? children({
|
|
6296
|
+
payload
|
|
6297
|
+
}) : children
|
|
6298
|
+
});
|
|
6299
|
+
}
|
|
5842
6300
|
|
|
5843
6301
|
var _DrawerProviderReport, _DrawerProviderReport2;
|
|
5844
6302
|
/**
|
|
@@ -6059,4 +6517,4 @@ function DrawerProviderReporter() {
|
|
|
6059
6517
|
return null;
|
|
6060
6518
|
}
|
|
6061
6519
|
|
|
6062
|
-
export {
|
|
6520
|
+
export { ARROW_RIGHT$1 as $, isSafari as A, ownerDocument as B, escapeKey as C, DrawerPortal as D, useOnMount as E, FloatingRootStore as F, Timeout as G, triggerHover as H, getNodeChildren as I, useValueAsRef as J, getFloatingFocusElement as K, isTypeableCombobox as L, isIndexOutOfListBounds as M, getMinListIndex as N, getMaxListIndex as O, PopupTriggerMap as P, stopEvent as Q, listNavigation as R, SafeReact as S, TYPEABLE_SELECTOR as T, createGridCellMap as U, isListIndexDisabled as V, getGridNavigatedIndex as W, getGridCellIndices as X, getGridCellIndexOfCorner as Y, ARROW_DOWN$1 as Z, ARROW_LEFT$1 as _, DrawerBackdrop as a, DialogStore as a$, findNonDisabledListIndex as a0, focusOut as a1, enqueueFocus as a2, isVirtualClick as a3, isVirtualPointerEvent as a4, ARROW_UP$1 as a5, isElementVisible as a6, useTriggerDataForwarding as a7, useInteractions as a8, CLICK_TRIGGER_IDENTIFIER as a9, useFloatingNodeId as aA, useOpenInteractionType as aB, useImplicitActiveTrigger as aC, useOpenStateTransitions as aD, useScrollLock as aE, imperativeAction as aF, useSyncedFloatingRootContext as aG, useDismiss as aH, useRole as aI, TYPEAHEAD_RESET_MS as aJ, FloatingTree as aK, fastComponentRef as aL, cancelOpen as aM, getTabbableBeforeElement as aN, isOutsideEvent as aO, getTabbableAfterElement as aP, getNextTabbable as aQ, pressableTriggerOpenStateMapping as aR, FocusGuard as aS, PATIENT_CLICK_THRESHOLD as aT, useTriggerRegistration as aU, useDrawerProviderContext as aV, DrawerBackdropCssVars as aW, DrawerPopupCssVars as aX, DrawerProviderContext as aY, CommonPopupDataAttributes as aZ, useDialogPortalContext as a_, triggerOpenStateMapping as aa, itemPress as ab, transitionStatusMapping as ac, DISABLED_TRANSITIONS_STYLE as ad, popupStateMapping as ae, useOpenChangeComplete as af, COMPOSITE_KEYS as ag, outsidePress as ah, FloatingFocusManager as ai, FloatingPortal as aj, useAnimationsFinished as ak, POPUP_COLLISION_AVOIDANCE as al, InternalBackdrop as am, inertValue as an, FloatingNode as ao, DROPDOWN_COLLISION_AVOIDANCE as ap, siblingOpen as aq, useControlled as ar, useTransitionStatus as as, popupStoreSelectors as at, createSelector as au, ReactStore as av, createInitialPopupStoreState as aw, FloatingTreeStore as ax, fastComponent as ay, useOnFirstRender as az, DrawerPopup as b, clamp as b0, useDrawerRootContext as b1, DrawerPopupDataAttributes as b2, swipe as b3, useDrawerSnapPoints as b4, DrawerViewportContext as b5, BASE_UI_SWIPE_IGNORE_SELECTOR as b6, TransitionStatusDataAttributes as b7, DRAWER_CONTENT_ATTRIBUTE as b8, useStore as b9, createGenericEventDetails as ba, inputClear as bb, inputChange as bc, useValueChanged as bd, none as be, inputPress as bf, visuallyHiddenInput as bg, visuallyHidden as bh, Store as bi, isAndroid as bj, isFirefox as bk, clearPress as bl, chipRemovePress as bm, isIOS as bn, inputBlur as bo, inputPaste as bp, incrementPress as bq, decrementPress as br, keyboard as bs, scrub as bt, isWebKit as bu, DrawerContent as c, DrawerRoot as d, useStableCallback as e, useDialogRootContext as f, createChangeEventDetails as g, closePress as h, useId as i, isMouseLikePointerType as j, useAnimationFrame as k, useTimeout as l, isTypeableElement as m, isClickLikeEvent as n, useFloatingParentNodeId as o, useFloatingTree as p, getTarget as q, matchesFocusVisible as r, isTargetInsideEnabledTrigger as s, triggerPress as t, useIsoLayoutEffect as u, triggerFocus as v, createAttribute as w, activeElement as x, contains as y, isMac as z };
|