@jobber/components 9.3.0 → 9.5.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.cjs +0 -1
- package/dist/Autocomplete/index.mjs +0 -1
- package/dist/Card/index.cjs +7 -7
- package/dist/Card/index.mjs +7 -7
- package/dist/Chip/index.cjs +0 -1
- package/dist/Chip/index.mjs +0 -1
- package/dist/Chips/InternalChipDismissible/hooks/index.cjs +0 -1
- package/dist/Chips/InternalChipDismissible/hooks/index.mjs +0 -1
- package/dist/Chips/InternalChipDismissible/index.cjs +0 -1
- package/dist/Chips/InternalChipDismissible/index.mjs +0 -1
- package/dist/Chips/index.cjs +0 -1
- package/dist/Chips/index.mjs +0 -1
- package/dist/ComboboxChipRemove-cjs.js +181 -184
- package/dist/ComboboxChipRemove-es.js +4 -7
- package/dist/ConfirmationModal/index.cjs +0 -1
- package/dist/ConfirmationModal/index.mjs +0 -1
- package/dist/DataDump/DataDump.d.ts +1 -1
- package/dist/DataDump/DataDump.messages.d.ts +6 -0
- package/dist/DataDump/index.cjs +9 -9
- package/dist/DataDump/index.mjs +9 -9
- package/dist/DataDump-cjs.js +11 -1
- package/dist/DataDump-es.js +11 -1
- package/dist/DataList/components/DataListActions/index.cjs +0 -1
- package/dist/DataList/components/DataListActions/index.mjs +0 -1
- package/dist/DataList/components/DataListBulkActions/index.cjs +0 -1
- package/dist/DataList/components/DataListBulkActions/index.mjs +0 -1
- package/dist/DataList/components/DataListFilters/components/DataListSort/index.cjs +0 -1
- package/dist/DataList/components/DataListFilters/components/DataListSort/index.mjs +0 -1
- package/dist/DataList/components/DataListFilters/index.cjs +0 -1
- package/dist/DataList/components/DataListFilters/index.mjs +0 -1
- package/dist/DataList/components/DataListHeader/index.cjs +0 -1
- package/dist/DataList/components/DataListHeader/index.mjs +0 -1
- package/dist/DataList/components/DataListItem/index.cjs +0 -1
- package/dist/DataList/components/DataListItem/index.mjs +0 -1
- package/dist/DataList/components/DataListItemActions/index.cjs +0 -1
- package/dist/DataList/components/DataListItemActions/index.mjs +0 -1
- package/dist/DataList/components/DataListItemActionsOverflow/index.cjs +0 -1
- package/dist/DataList/components/DataListItemActionsOverflow/index.mjs +0 -1
- package/dist/DataList/components/DataListItems/index.cjs +0 -1
- package/dist/DataList/components/DataListItems/index.mjs +0 -1
- package/dist/DataList/components/DataListLayout/index.cjs +0 -1
- package/dist/DataList/components/DataListLayout/index.mjs +0 -1
- package/dist/DataList/components/DataListLayoutActions/index.cjs +0 -1
- package/dist/DataList/components/DataListLayoutActions/index.mjs +0 -1
- package/dist/DataList/index.cjs +0 -1
- package/dist/DataList/index.mjs +0 -1
- package/dist/DataTable/DataTable.messages.d.ts +22 -0
- package/dist/DataTable/index.cjs +2 -2
- package/dist/DataTable/index.mjs +2 -2
- package/dist/DataTable-cjs.js +34 -5
- package/dist/DataTable-es.js +34 -5
- package/dist/DatePicker/index.cjs +0 -2
- package/dist/DatePicker/index.mjs +0 -2
- package/dist/DatePicker-cjs.js +19 -18
- package/dist/DatePicker-es.js +2 -1
- package/dist/Dialog/index.cjs +11 -6
- package/dist/Dialog/index.mjs +11 -6
- package/dist/DrawerDescription-cjs.js +7 -8
- package/dist/DrawerDescription-es.js +1 -2
- package/dist/DrawerTitle-cjs.js +4 -4
- package/dist/DrawerTitle-es.js +1 -1
- package/dist/FeatureSwitch/FeatureSwitch.messages.d.ts +10 -0
- package/dist/FeatureSwitch/index.cjs +2 -0
- package/dist/FeatureSwitch/index.mjs +2 -0
- package/dist/FeatureSwitch-cjs.js +15 -2
- package/dist/FeatureSwitch-es.js +15 -2
- package/dist/FieldDescription-cjs.js +49 -49
- package/dist/FieldDescription-es.js +2 -2
- package/dist/FilterPicker/components/FilterPickerActivator/index.cjs +0 -1
- package/dist/FilterPicker/components/FilterPickerActivator/index.mjs +0 -1
- package/dist/FilterPicker/components/FilterPickerContent/index.cjs +0 -1
- package/dist/FilterPicker/components/FilterPickerContent/index.mjs +0 -1
- package/dist/FilterPicker/components/FilterPickerTrigger/index.cjs +0 -1
- package/dist/FilterPicker/components/FilterPickerTrigger/index.mjs +0 -1
- package/dist/FilterPicker/index.cjs +0 -1
- package/dist/FilterPicker/index.mjs +0 -1
- package/dist/FormatFile/FormatFile.messages.d.ts +18 -0
- package/dist/FormatFile/index.cjs +2 -3
- package/dist/FormatFile/index.mjs +2 -3
- package/dist/FormatFile-cjs.js +24 -2
- package/dist/FormatFile-es.js +24 -2
- package/dist/Gallery/index.cjs +0 -1
- package/dist/Gallery/index.mjs +0 -1
- package/dist/HelperText-cjs.js +3 -2
- package/dist/HelperText-es.js +3 -2
- package/dist/InputDate/index.cjs +0 -2
- package/dist/InputDate/index.mjs +0 -2
- package/dist/InputNumber/InputNumber.d.ts +75 -5
- package/dist/InputNumber/index.cjs +27 -3
- package/dist/InputNumber/index.d.ts +2 -2
- package/dist/InputNumber/index.mjs +27 -3
- package/dist/{primitives/InputNumberExperimental → InputNumber}/types.d.ts +48 -35
- package/dist/InputNumber-cjs.js +267 -4986
- package/dist/InputNumber-es.js +268 -4987
- package/dist/LightBox/index.cjs +0 -1
- package/dist/LightBox/index.mjs +0 -1
- package/dist/Menu/index.cjs +7 -7
- package/dist/Menu/index.mjs +7 -7
- package/dist/Menu-cjs.js +5 -1
- package/dist/Menu-es.js +5 -2
- package/dist/MenuSubmenuTrigger-cjs.js +142 -143
- package/dist/MenuSubmenuTrigger-es.js +5 -6
- package/dist/Modal/index.cjs +0 -1
- package/dist/Modal/index.mjs +0 -1
- package/dist/NumberFieldInput-cjs.js +63 -63
- package/dist/NumberFieldInput-es.js +5 -5
- package/dist/Page/index.cjs +18 -19
- package/dist/Page/index.mjs +18 -19
- package/dist/Page-cjs.js +6 -3
- package/dist/Page-es.js +6 -3
- package/dist/Popover/index.cjs +0 -1
- package/dist/Popover/index.mjs +0 -1
- package/dist/ProgressBar/ProgressBar.messages.d.ts +6 -0
- package/dist/ProgressBar/index.cjs +2 -0
- package/dist/ProgressBar/index.mjs +2 -0
- package/dist/ProgressBar-cjs.js +13 -1
- package/dist/ProgressBar-es.js +13 -1
- package/dist/ScrollAreaViewport-cjs.js +119 -121
- package/dist/ScrollAreaViewport-es.js +3 -5
- package/dist/Select/index.cjs +3 -9
- package/dist/Select/index.mjs +3 -9
- package/dist/SelectGroupLabel-cjs.js +117 -107
- package/dist/SelectGroupLabel-es.js +20 -12
- package/dist/Toast/Toast.messages.d.ts +6 -0
- package/dist/Toast/index.cjs +3 -1
- package/dist/Toast/index.mjs +3 -1
- package/dist/Toast/showToast.d.ts +12 -1
- package/dist/Tooltip/index.cjs +0 -1
- package/dist/Tooltip/index.mjs +0 -1
- package/dist/dialogReturnFocus-cjs.js +4 -1
- package/dist/dialogReturnFocus-es.js +4 -1
- package/dist/docs/DataDump/DataDump.md +1 -1
- package/dist/docs/InputNumber/InputNumber.md +564 -56
- package/dist/docs/Page/Page.md +1 -1
- package/dist/docs/index.md +0 -1
- package/dist/floating-ui.react-cjs.js +34 -35
- package/dist/floating-ui.react-dom-cjs.js +64 -65
- package/dist/floating-ui.react-dom-es.js +1 -2
- package/dist/floating-ui.react-es.js +1 -2
- package/dist/floating-ui.utils-cjs.js +183 -0
- package/dist/floating-ui.utils-es.js +165 -1
- package/dist/index.cjs +10 -15
- package/dist/index.mjs +10 -15
- package/dist/primitives/BottomSheet/index.cjs +2 -5
- package/dist/primitives/BottomSheet/index.mjs +2 -5
- package/dist/primitives/ComboboxPrimitive/index.cjs +3 -7
- package/dist/primitives/ComboboxPrimitive/index.mjs +3 -7
- package/dist/primitives/HelperText/HelperText.d.ts +4 -1
- package/dist/primitives/HelperText/index.cjs +1 -1
- package/dist/primitives/HelperText/index.mjs +1 -1
- package/dist/primitives/SelectPrimitive/index.cjs +3 -9
- package/dist/primitives/SelectPrimitive/index.mjs +3 -9
- package/dist/primitives/index.cjs +2 -16
- package/dist/primitives/index.d.ts +0 -2
- package/dist/primitives/index.mjs +2 -15
- package/dist/scrollEdges-cjs.js +6 -2
- package/dist/scrollEdges-es.js +5 -2
- package/dist/sharedHelpers/i18n/renderWithLocale.d.ts +11 -0
- package/dist/showToast-cjs.js +20 -6
- package/dist/showToast-es.js +20 -6
- package/dist/styles.css +573 -902
- package/dist/unstyledPrimitives/index.cjs +105 -111
- package/dist/unstyledPrimitives/index.mjs +5 -11
- package/dist/useCompositeListItem-cjs.js +516 -90
- package/dist/useCompositeListItem-es.js +407 -6
- package/dist/useLabel-cjs.js +10 -10
- package/dist/useLabel-es.js +3 -3
- package/dist/useRenderElement-es.js +1 -1
- package/dist/useScrollLock-cjs.js +1332 -203
- package/dist/useScrollLock-es.js +1068 -5
- package/dist/utils/meta/meta.json +12 -0
- package/package.json +2 -3
- package/dist/InputNumber/InputNumber.types.d.ts +0 -20
- package/dist/InputNumberExperimental-cjs.js +0 -277
- package/dist/InputNumberExperimental-es.js +0 -275
- package/dist/clamp-cjs.js +0 -7
- package/dist/clamp-es.js +0 -5
- package/dist/clsx-cjs.js +0 -5
- package/dist/clsx-es.js +0 -3
- package/dist/docs/InputNumberExperimental/InputNumberExperimental.md +0 -578
- package/dist/floating-ui.utils.dom-cjs.js +0 -185
- package/dist/floating-ui.utils.dom-es.js +0 -165
- package/dist/isElementDisabled-cjs.js +0 -40
- package/dist/isElementDisabled-es.js +0 -18
- package/dist/primitives/InputNumberExperimental/InputNumberExperimental.d.ts +0 -77
- package/dist/primitives/InputNumberExperimental/index.cjs +0 -30
- package/dist/primitives/InputNumberExperimental/index.d.ts +0 -2
- package/dist/primitives/InputNumberExperimental/index.mjs +0 -24
- package/dist/resolveAriaLabelledBy-cjs.js +0 -200
- package/dist/resolveAriaLabelledBy-es.js +0 -166
- package/dist/useButton-cjs.js +0 -1164
- package/dist/useButton-es.js +0 -1071
- package/dist/useLabelableId-cjs.js +0 -278
- package/dist/useLabelableId-es.js +0 -247
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var React = require('react');
|
|
4
|
-
var
|
|
5
|
-
var useButton = require('./useButton-cjs.js');
|
|
4
|
+
var floatingUi_utils = require('./floating-ui.utils-cjs.js');
|
|
6
5
|
var useRenderElement = require('./useRenderElement-cjs.js');
|
|
7
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
-
var floatingUi_utils = require('./floating-ui.utils-cjs.js');
|
|
9
7
|
var ReactDOM = require('react-dom');
|
|
10
8
|
|
|
11
9
|
function _interopNamespaceDefault(e) {
|
|
@@ -28,6 +26,84 @@ function _interopNamespaceDefault(e) {
|
|
|
28
26
|
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
|
29
27
|
var ReactDOM__namespace = /*#__PURE__*/_interopNamespaceDefault(ReactDOM);
|
|
30
28
|
|
|
29
|
+
let set;
|
|
30
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
31
|
+
set = new Set();
|
|
32
|
+
}
|
|
33
|
+
function error(...messages) {
|
|
34
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
35
|
+
const messageKey = messages.join(' ');
|
|
36
|
+
if (!set.has(messageKey)) {
|
|
37
|
+
set.add(messageKey);
|
|
38
|
+
console.error(`Base UI: ${messageKey}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function useControlled({
|
|
44
|
+
controlled,
|
|
45
|
+
default: defaultProp,
|
|
46
|
+
name,
|
|
47
|
+
state = 'value'
|
|
48
|
+
}) {
|
|
49
|
+
// isControlled is ignored in the hook dependency lists as it should never change.
|
|
50
|
+
const {
|
|
51
|
+
current: isControlled
|
|
52
|
+
} = React__namespace.useRef(controlled !== undefined);
|
|
53
|
+
const [valueState, setValue] = React__namespace.useState(defaultProp);
|
|
54
|
+
const value = isControlled ? controlled : valueState;
|
|
55
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
56
|
+
React__namespace.useEffect(() => {
|
|
57
|
+
if (isControlled !== (controlled !== undefined)) {
|
|
58
|
+
error([`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'));
|
|
59
|
+
}
|
|
60
|
+
}, [state, name, controlled]);
|
|
61
|
+
const {
|
|
62
|
+
current: defaultValue
|
|
63
|
+
} = React__namespace.useRef(defaultProp);
|
|
64
|
+
React__namespace.useEffect(() => {
|
|
65
|
+
if (!isControlled && serializeToDevModeString(defaultValue) !== serializeToDevModeString(defaultProp)) {
|
|
66
|
+
error([`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'));
|
|
67
|
+
}
|
|
68
|
+
}, [defaultProp]);
|
|
69
|
+
}
|
|
70
|
+
const setValueIfUncontrolled = React__namespace.useCallback(newValue => {
|
|
71
|
+
if (!isControlled) {
|
|
72
|
+
setValue(newValue);
|
|
73
|
+
}
|
|
74
|
+
}, []);
|
|
75
|
+
return [value, setValueIfUncontrolled];
|
|
76
|
+
}
|
|
77
|
+
function serializeToDevModeString(input) {
|
|
78
|
+
let nextId = 0;
|
|
79
|
+
const seen = new WeakMap();
|
|
80
|
+
try {
|
|
81
|
+
const result = JSON.stringify(input, function replacer(key, value) {
|
|
82
|
+
if (key === '_owner' && this != null && typeof this === 'object' && '$$typeof' in this) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
if (typeof value === 'bigint') {
|
|
86
|
+
return `__bigint__:${value}`;
|
|
87
|
+
}
|
|
88
|
+
if (value !== null && typeof value === 'object') {
|
|
89
|
+
const id = seen.get(value);
|
|
90
|
+
if (id !== undefined) {
|
|
91
|
+
return `__object__:${id}`;
|
|
92
|
+
}
|
|
93
|
+
seen.set(value, nextId);
|
|
94
|
+
nextId += 1;
|
|
95
|
+
}
|
|
96
|
+
return value;
|
|
97
|
+
});
|
|
98
|
+
return result ?? `__top__:${typeof input}`;
|
|
99
|
+
} catch {
|
|
100
|
+
return '__unserializable__';
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const noop = () => {};
|
|
105
|
+
const useIsoLayoutEffect = typeof document !== 'undefined' ? React__namespace.useLayoutEffect : noop;
|
|
106
|
+
|
|
31
107
|
function useOnFirstRender(fn) {
|
|
32
108
|
const ref = React__namespace.useRef(true);
|
|
33
109
|
if (ref.current) {
|
|
@@ -36,6 +112,104 @@ function useOnFirstRender(fn) {
|
|
|
36
112
|
}
|
|
37
113
|
}
|
|
38
114
|
|
|
115
|
+
/**
|
|
116
|
+
* A clone of the React namespace for reading APIs that may be missing in older
|
|
117
|
+
* supported React versions. Bundlers can rewrite direct `React.someNewApi`
|
|
118
|
+
* reads into named imports, which breaks React 17. Reading from this cloned
|
|
119
|
+
* object keeps those lookups optional.
|
|
120
|
+
*
|
|
121
|
+
* @see https://github.com/mui/material-ui/issues/41190#issuecomment-2040873379
|
|
122
|
+
*/
|
|
123
|
+
const SafeReact = {
|
|
124
|
+
...React__namespace
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const useInsertionEffect = SafeReact.useInsertionEffect;
|
|
128
|
+
const useSafeInsertionEffect =
|
|
129
|
+
// React 17 doesn't have useInsertionEffect.
|
|
130
|
+
useInsertionEffect &&
|
|
131
|
+
// Preact replaces useInsertionEffect with useLayoutEffect and fires too late.
|
|
132
|
+
useInsertionEffect !== SafeReact.useLayoutEffect ? useInsertionEffect : fn => fn();
|
|
133
|
+
/**
|
|
134
|
+
* Stabilizes the function passed so it's always the same between renders.
|
|
135
|
+
*
|
|
136
|
+
* The function becomes non-reactive to any values it captures.
|
|
137
|
+
* It can safely be passed as a dependency of `React.useMemo` and `React.useEffect` without re-triggering them if its captured values change.
|
|
138
|
+
*
|
|
139
|
+
* The function must only be called inside effects and event handlers, never during render (which throws an error).
|
|
140
|
+
*
|
|
141
|
+
* 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.
|
|
142
|
+
*/
|
|
143
|
+
function useStableCallback(callback) {
|
|
144
|
+
const stable = useRenderElement.useRefWithInit(createStableCallback).current;
|
|
145
|
+
stable.next = callback;
|
|
146
|
+
useSafeInsertionEffect(stable.effect);
|
|
147
|
+
return stable.trampoline;
|
|
148
|
+
}
|
|
149
|
+
function createStableCallback() {
|
|
150
|
+
const stable = {
|
|
151
|
+
next: undefined,
|
|
152
|
+
callback: assertNotCalled,
|
|
153
|
+
trampoline: (...args) => stable.callback?.(...args),
|
|
154
|
+
effect: () => {
|
|
155
|
+
stable.callback = stable.next;
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
return stable;
|
|
159
|
+
}
|
|
160
|
+
function assertNotCalled() {
|
|
161
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
162
|
+
// TODO: fix mui/no-guarded-throw
|
|
163
|
+
// eslint-disable-next-line mui/no-guarded-throw
|
|
164
|
+
throw /* minify-error-disabled */new Error('Base UI: Cannot call an event handler while rendering.');
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Untracks the provided value by turning it into a ref to remove its reactivity.
|
|
170
|
+
*
|
|
171
|
+
* Used to access the passed value inside `React.useEffect` without causing the effect to re-run when the value changes.
|
|
172
|
+
*/
|
|
173
|
+
function useValueAsRef(value) {
|
|
174
|
+
const latest = useRenderElement.useRefWithInit(createLatestRef, value).current;
|
|
175
|
+
latest.next = value;
|
|
176
|
+
|
|
177
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
178
|
+
useIsoLayoutEffect(latest.effect);
|
|
179
|
+
return latest;
|
|
180
|
+
}
|
|
181
|
+
function createLatestRef(value) {
|
|
182
|
+
const latest = {
|
|
183
|
+
current: value,
|
|
184
|
+
next: value,
|
|
185
|
+
effect: () => {
|
|
186
|
+
latest.current = latest.next;
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
return latest;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const visuallyHiddenBase = {
|
|
193
|
+
clipPath: 'inset(50%)',
|
|
194
|
+
overflow: 'hidden',
|
|
195
|
+
whiteSpace: 'nowrap',
|
|
196
|
+
border: 0,
|
|
197
|
+
padding: 0,
|
|
198
|
+
width: 1,
|
|
199
|
+
height: 1,
|
|
200
|
+
margin: -1
|
|
201
|
+
};
|
|
202
|
+
const visuallyHidden = {
|
|
203
|
+
...visuallyHiddenBase,
|
|
204
|
+
position: 'fixed',
|
|
205
|
+
top: 0,
|
|
206
|
+
left: 0
|
|
207
|
+
};
|
|
208
|
+
const visuallyHiddenInput = {
|
|
209
|
+
...visuallyHiddenBase,
|
|
210
|
+
position: 'absolute'
|
|
211
|
+
};
|
|
212
|
+
|
|
39
213
|
/**
|
|
40
214
|
* The NoOptionalParams type is a utility type that checks if a function has optional or default parameters.
|
|
41
215
|
* If the function has optional or default parameters, it returns a string literal type with an error message.
|
|
@@ -799,7 +973,7 @@ class ReactStore extends Store {
|
|
|
799
973
|
React__namespace.useDebugValue(key);
|
|
800
974
|
// eslint-disable-next-line consistent-this
|
|
801
975
|
const store = this;
|
|
802
|
-
|
|
976
|
+
useIsoLayoutEffect(() => {
|
|
803
977
|
if (store.state[key] !== value) {
|
|
804
978
|
store.set(key, value);
|
|
805
979
|
}
|
|
@@ -816,7 +990,7 @@ class ReactStore extends Store {
|
|
|
816
990
|
useSyncedValueWithCleanup(key, value) {
|
|
817
991
|
// eslint-disable-next-line consistent-this
|
|
818
992
|
const store = this;
|
|
819
|
-
|
|
993
|
+
useIsoLayoutEffect(() => {
|
|
820
994
|
if (store.state[key] !== value) {
|
|
821
995
|
store.set(key, value);
|
|
822
996
|
}
|
|
@@ -845,7 +1019,7 @@ class ReactStore extends Store {
|
|
|
845
1019
|
}
|
|
846
1020
|
}
|
|
847
1021
|
const dependencies = Object.values(statePart);
|
|
848
|
-
|
|
1022
|
+
useIsoLayoutEffect(() => {
|
|
849
1023
|
store.update(statePart);
|
|
850
1024
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
851
1025
|
}, [store, ...dependencies]);
|
|
@@ -860,7 +1034,7 @@ class ReactStore extends Store {
|
|
|
860
1034
|
// eslint-disable-next-line consistent-this
|
|
861
1035
|
const store = this;
|
|
862
1036
|
const isControlled = controlled !== undefined;
|
|
863
|
-
|
|
1037
|
+
useIsoLayoutEffect(() => {
|
|
864
1038
|
if (isControlled && !Object.is(store.state[key], controlled)) {
|
|
865
1039
|
// Set the internal state to match the controlled value.
|
|
866
1040
|
store.setState({
|
|
@@ -914,7 +1088,7 @@ class ReactStore extends Store {
|
|
|
914
1088
|
*/
|
|
915
1089
|
useContextCallback(key, fn) {
|
|
916
1090
|
React__namespace.useDebugValue(key);
|
|
917
|
-
const stableFunction =
|
|
1091
|
+
const stableFunction = useStableCallback(fn ?? useRenderElement.NOOP);
|
|
918
1092
|
this.context[key] = stableFunction;
|
|
919
1093
|
}
|
|
920
1094
|
|
|
@@ -975,6 +1149,240 @@ function mergeCleanups(...cleanups) {
|
|
|
975
1149
|
};
|
|
976
1150
|
}
|
|
977
1151
|
|
|
1152
|
+
function ownerDocument(node) {
|
|
1153
|
+
return node?.ownerDocument || document;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
/**
|
|
1157
|
+
* Adds an event listener and returns a cleanup function to remove it.
|
|
1158
|
+
*/
|
|
1159
|
+
|
|
1160
|
+
function addEventListener(target, type, listener, options) {
|
|
1161
|
+
target.addEventListener(type, listener, options);
|
|
1162
|
+
return () => {
|
|
1163
|
+
target.removeEventListener(type, listener, options);
|
|
1164
|
+
};
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
const EMPTY$2 = [];
|
|
1168
|
+
|
|
1169
|
+
/**
|
|
1170
|
+
* A React.useEffect equivalent that runs once, when the component is mounted.
|
|
1171
|
+
*/
|
|
1172
|
+
function useOnMount(fn) {
|
|
1173
|
+
// 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
|
|
1174
|
+
/* eslint-disable react-hooks/exhaustive-deps */
|
|
1175
|
+
React__namespace.useEffect(fn, EMPTY$2);
|
|
1176
|
+
/* eslint-enable react-hooks/exhaustive-deps */
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
/** Unlike `setTimeout`, rAF doesn't guarantee a positive integer return value, so we can't have
|
|
1180
|
+
* a monomorphic `uint` type with `0` meaning empty.
|
|
1181
|
+
* See warning note at:
|
|
1182
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame#return_value */
|
|
1183
|
+
const EMPTY$1 = null;
|
|
1184
|
+
let LAST_RAF = globalThis.requestAnimationFrame;
|
|
1185
|
+
class Scheduler {
|
|
1186
|
+
/* This implementation uses an array as a backing data-structure for frame callbacks.
|
|
1187
|
+
* It allows `O(1)` callback cancelling by inserting a `null` in the array, though it
|
|
1188
|
+
* never calls the native `cancelAnimationFrame` if there are no frames left. This can
|
|
1189
|
+
* be much more efficient if there is a call pattern that alterns as
|
|
1190
|
+
* "request-cancel-request-cancel-…".
|
|
1191
|
+
* But in the case of "request-request-…-cancel-cancel-…", it leaves the final animation
|
|
1192
|
+
* frame to run anyway. We turn that frame into a `O(1)` no-op via `callbacksCount`. */
|
|
1193
|
+
|
|
1194
|
+
callbacks = [];
|
|
1195
|
+
callbacksCount = 0;
|
|
1196
|
+
nextId = 1;
|
|
1197
|
+
startId = 1;
|
|
1198
|
+
isScheduled = false;
|
|
1199
|
+
tick = timestamp => {
|
|
1200
|
+
this.isScheduled = false;
|
|
1201
|
+
const currentCallbacks = this.callbacks;
|
|
1202
|
+
const currentCallbacksCount = this.callbacksCount;
|
|
1203
|
+
|
|
1204
|
+
// Update these before iterating, callbacks could call `requestAnimationFrame` again.
|
|
1205
|
+
this.callbacks = [];
|
|
1206
|
+
this.callbacksCount = 0;
|
|
1207
|
+
this.startId = this.nextId;
|
|
1208
|
+
if (currentCallbacksCount > 0) {
|
|
1209
|
+
for (let i = 0; i < currentCallbacks.length; i += 1) {
|
|
1210
|
+
currentCallbacks[i]?.(timestamp);
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
};
|
|
1214
|
+
request(fn) {
|
|
1215
|
+
const id = this.nextId;
|
|
1216
|
+
this.nextId += 1;
|
|
1217
|
+
this.callbacks.push(fn);
|
|
1218
|
+
this.callbacksCount += 1;
|
|
1219
|
+
|
|
1220
|
+
/* In a test environment with fake timers, a fake `requestAnimationFrame` can be called
|
|
1221
|
+
* but there's no guarantee that the animation frame will actually run before the fake
|
|
1222
|
+
* timers are teared, which leaves `isScheduled` set, but won't run our `tick()`. */
|
|
1223
|
+
const didRAFChange = process.env.NODE_ENV !== 'production' && LAST_RAF !== requestAnimationFrame && (LAST_RAF = requestAnimationFrame, true);
|
|
1224
|
+
if (!this.isScheduled || didRAFChange) {
|
|
1225
|
+
requestAnimationFrame(this.tick);
|
|
1226
|
+
this.isScheduled = true;
|
|
1227
|
+
}
|
|
1228
|
+
return id;
|
|
1229
|
+
}
|
|
1230
|
+
cancel(id) {
|
|
1231
|
+
const index = id - this.startId;
|
|
1232
|
+
if (index < 0 || index >= this.callbacks.length) {
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
this.callbacks[index] = null;
|
|
1236
|
+
this.callbacksCount -= 1;
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
const scheduler = new Scheduler();
|
|
1240
|
+
class AnimationFrame {
|
|
1241
|
+
static create() {
|
|
1242
|
+
return new AnimationFrame();
|
|
1243
|
+
}
|
|
1244
|
+
static request(fn) {
|
|
1245
|
+
return scheduler.request(fn);
|
|
1246
|
+
}
|
|
1247
|
+
static cancel(id) {
|
|
1248
|
+
return scheduler.cancel(id);
|
|
1249
|
+
}
|
|
1250
|
+
currentId = EMPTY$1;
|
|
1251
|
+
|
|
1252
|
+
/**
|
|
1253
|
+
* Executes `fn` after `delay`, clearing any previously scheduled call.
|
|
1254
|
+
*/
|
|
1255
|
+
request(fn) {
|
|
1256
|
+
this.cancel();
|
|
1257
|
+
this.currentId = scheduler.request(() => {
|
|
1258
|
+
this.currentId = EMPTY$1;
|
|
1259
|
+
fn();
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
cancel = () => {
|
|
1263
|
+
if (this.currentId !== EMPTY$1) {
|
|
1264
|
+
scheduler.cancel(this.currentId);
|
|
1265
|
+
this.currentId = EMPTY$1;
|
|
1266
|
+
}
|
|
1267
|
+
};
|
|
1268
|
+
disposeEffect = () => {
|
|
1269
|
+
return this.cancel;
|
|
1270
|
+
};
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
/**
|
|
1274
|
+
* A `requestAnimationFrame` with automatic cleanup and guard.
|
|
1275
|
+
*/
|
|
1276
|
+
function useAnimationFrame() {
|
|
1277
|
+
const timeout = useRenderElement.useRefWithInit(AnimationFrame.create).current;
|
|
1278
|
+
useOnMount(timeout.disposeEffect);
|
|
1279
|
+
return timeout;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
const EMPTY = 0;
|
|
1283
|
+
class Timeout {
|
|
1284
|
+
static create() {
|
|
1285
|
+
return new Timeout();
|
|
1286
|
+
}
|
|
1287
|
+
currentId = EMPTY;
|
|
1288
|
+
|
|
1289
|
+
/**
|
|
1290
|
+
* Executes `fn` after `delay`, clearing any previously scheduled call.
|
|
1291
|
+
*/
|
|
1292
|
+
start(delay, fn) {
|
|
1293
|
+
this.clear();
|
|
1294
|
+
this.currentId = setTimeout(() => {
|
|
1295
|
+
this.currentId = EMPTY;
|
|
1296
|
+
fn();
|
|
1297
|
+
}, delay); /* Node.js types are enabled in development */
|
|
1298
|
+
}
|
|
1299
|
+
isStarted() {
|
|
1300
|
+
return this.currentId !== EMPTY;
|
|
1301
|
+
}
|
|
1302
|
+
clear = () => {
|
|
1303
|
+
if (this.currentId !== EMPTY) {
|
|
1304
|
+
clearTimeout(this.currentId);
|
|
1305
|
+
this.currentId = EMPTY;
|
|
1306
|
+
}
|
|
1307
|
+
};
|
|
1308
|
+
disposeEffect = () => {
|
|
1309
|
+
return this.clear;
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
/**
|
|
1314
|
+
* A `setTimeout` with automatic cleanup and guard.
|
|
1315
|
+
*/
|
|
1316
|
+
function useTimeout() {
|
|
1317
|
+
const timeout = useRenderElement.useRefWithInit(Timeout.create).current;
|
|
1318
|
+
useOnMount(timeout.disposeEffect);
|
|
1319
|
+
return timeout;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
/**
|
|
1323
|
+
* Reads `navigator.userAgent` / `navigator.platform` (legacy but universally
|
|
1324
|
+
* supported) into a normalized shape. In development, prefers the modern
|
|
1325
|
+
* `navigator.userAgentData` API on Chromium to avoid DevTools warnings about
|
|
1326
|
+
* the deprecated reads; that branch is dead-code-eliminated in production
|
|
1327
|
+
* builds to keep the bundle small.
|
|
1328
|
+
*
|
|
1329
|
+
* Returns empty/zero values when `navigator` is undefined (SSR), so every
|
|
1330
|
+
* derived flag safely evaluates to `false`.
|
|
1331
|
+
*/
|
|
1332
|
+
function readRawData() {
|
|
1333
|
+
if (typeof navigator === 'undefined') {
|
|
1334
|
+
return {
|
|
1335
|
+
userAgent: '',
|
|
1336
|
+
platform: '',
|
|
1337
|
+
maxTouchPoints: 0
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1340
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1341
|
+
const uaData = navigator.userAgentData;
|
|
1342
|
+
if (uaData && Array.isArray(uaData.brands)) {
|
|
1343
|
+
return {
|
|
1344
|
+
userAgent: uaData.brands.map(({
|
|
1345
|
+
brand,
|
|
1346
|
+
version
|
|
1347
|
+
}) => `${brand}/${version}`).join(' '),
|
|
1348
|
+
platform: uaData.platform ?? navigator.platform ?? '',
|
|
1349
|
+
maxTouchPoints: navigator.maxTouchPoints ?? 0
|
|
1350
|
+
};
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
return {
|
|
1354
|
+
userAgent: navigator.userAgent,
|
|
1355
|
+
platform: navigator.platform ?? '',
|
|
1356
|
+
maxTouchPoints: navigator.maxTouchPoints ?? 0
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
const {
|
|
1360
|
+
userAgent,
|
|
1361
|
+
platform,
|
|
1362
|
+
maxTouchPoints
|
|
1363
|
+
} = readRawData();
|
|
1364
|
+
const lowerUserAgent = userAgent.toLowerCase();
|
|
1365
|
+
const lowerPlatform = platform.toLowerCase();
|
|
1366
|
+
|
|
1367
|
+
// iPadOS 13+ reports `MacIntel` for `navigator.platform`; disambiguated via
|
|
1368
|
+
// `maxTouchPoints` so iPad is classified as iOS, not macOS.
|
|
1369
|
+
// https://github.com/mui/base-ui/issues/1309
|
|
1370
|
+
/** iPhone, iPad (including iPadOS 13+ reporting as macOS), iPod. */
|
|
1371
|
+
const ios = /^i(os$|p)/.test(lowerPlatform) || lowerPlatform === 'macintel' && maxTouchPoints > 1;
|
|
1372
|
+
|
|
1373
|
+
/** Android phones, tablets, and embedded Android browsers. */
|
|
1374
|
+
const ANDROID_STRING = 'android';
|
|
1375
|
+
const android = lowerPlatform === ANDROID_STRING || lowerUserAgent.includes(ANDROID_STRING);
|
|
1376
|
+
|
|
1377
|
+
/** macOS desktop. Excludes iPadOS, which reports as `MacIntel`. */
|
|
1378
|
+
const mac = !ios && lowerPlatform.startsWith('mac');
|
|
1379
|
+
|
|
1380
|
+
/** Windows desktop. */
|
|
1381
|
+
lowerPlatform.startsWith('win');
|
|
1382
|
+
|
|
1383
|
+
/** Any Apple OS (`mac || ios`). */
|
|
1384
|
+
const apple = mac || ios;
|
|
1385
|
+
|
|
978
1386
|
// WebKit (Safari, all iOS browsers, GNOME Web). Distinguished from Blink by
|
|
979
1387
|
// the legacy `-webkit-backdrop-filter` name — Blink forked from WebKit in 2013
|
|
980
1388
|
// and only ships the unprefixed `backdrop-filter`.
|
|
@@ -986,14 +1394,14 @@ const webkit = typeof CSS !== 'undefined' && !!CSS.supports?.('-webkit-backdrop-
|
|
|
986
1394
|
// `!webkit` prefix also defends against future iOS-browser UA changes that
|
|
987
1395
|
// might inject `Firefox` into a WebKit-based UA.
|
|
988
1396
|
/** Gecko: Firefox. */
|
|
989
|
-
const gecko = !webkit &&
|
|
1397
|
+
const gecko = !webkit && lowerUserAgent.includes('firefox');
|
|
990
1398
|
|
|
991
1399
|
// All Chromium-based browsers ship `Chrome/` or `Chromium/` in their UA — both
|
|
992
1400
|
// share the `chrom` prefix, so a single substring check covers Chrome, Edge,
|
|
993
1401
|
// Opera, Brave, etc. Chrome-on-iOS uses `CriOS/` and stays WebKit. The positive
|
|
994
1402
|
// UA check also makes this SSR-safe — an empty UA matches nothing.
|
|
995
1403
|
/** Blink: Chrome, Edge, Opera, Brave, and other Chromium-based browsers. */
|
|
996
|
-
!webkit &&
|
|
1404
|
+
!webkit && lowerUserAgent.includes('chrom');
|
|
997
1405
|
|
|
998
1406
|
// Whether a screen reader is *actually* running cannot be detected. These flags
|
|
999
1407
|
// identify platforms where a specific screen reader could be active. VoiceOver
|
|
@@ -1004,7 +1412,50 @@ const gecko = !webkit && useButton.lowerUserAgent.includes('firefox');
|
|
|
1004
1412
|
* The user *may* be using VoiceOver — actual activation is not detectable.
|
|
1005
1413
|
* True on any Apple platform (macOS, iOS, iPadOS).
|
|
1006
1414
|
*/
|
|
1007
|
-
const voiceOver =
|
|
1415
|
+
const voiceOver = apple;
|
|
1416
|
+
|
|
1417
|
+
/** Running in jsdom or HappyDOM (used by unit tests). */
|
|
1418
|
+
const jsdom = /jsdom|happydom/.test(lowerUserAgent);
|
|
1419
|
+
|
|
1420
|
+
function stopEvent(event) {
|
|
1421
|
+
event.preventDefault();
|
|
1422
|
+
event.stopPropagation();
|
|
1423
|
+
}
|
|
1424
|
+
function isReactEvent(event) {
|
|
1425
|
+
return 'nativeEvent' in event;
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
// License: https://github.com/adobe/react-spectrum/blob/main/packages/@react-aria/utils/src/isVirtualEvent.ts
|
|
1429
|
+
function isVirtualClick(event) {
|
|
1430
|
+
if (event.pointerType === '' && event.isTrusted) {
|
|
1431
|
+
return true;
|
|
1432
|
+
}
|
|
1433
|
+
if (android && event.pointerType) {
|
|
1434
|
+
return event.type === 'click' && event.buttons === 1;
|
|
1435
|
+
}
|
|
1436
|
+
return event.detail === 0 && !event.pointerType;
|
|
1437
|
+
}
|
|
1438
|
+
function isVirtualPointerEvent(event) {
|
|
1439
|
+
if (jsdom) {
|
|
1440
|
+
return false;
|
|
1441
|
+
}
|
|
1442
|
+
return !android && event.width === 0 && event.height === 0 || android && event.width === 1 && event.height === 1 && event.pressure === 0 && event.detail === 0 && event.pointerType === 'mouse' ||
|
|
1443
|
+
// iOS VoiceOver returns 0.333• for width/height.
|
|
1444
|
+
event.width < 1 && event.height < 1 && event.pressure === 0 && event.detail === 0 && event.pointerType === 'touch';
|
|
1445
|
+
}
|
|
1446
|
+
function isMouseLikePointerType(pointerType, strict) {
|
|
1447
|
+
// On some Linux machines with Chromium, mouse inputs return a `pointerType`
|
|
1448
|
+
// of "pen": https://github.com/floating-ui/floating-ui/issues/2015
|
|
1449
|
+
const values = ['mouse', 'pen'];
|
|
1450
|
+
if (!strict) {
|
|
1451
|
+
values.push('', undefined);
|
|
1452
|
+
}
|
|
1453
|
+
return values.includes(pointerType);
|
|
1454
|
+
}
|
|
1455
|
+
function isClickLikeEvent(event) {
|
|
1456
|
+
const type = event.type;
|
|
1457
|
+
return type === 'click' || type === 'mousedown' || type === 'keydown' || type === 'keyup';
|
|
1458
|
+
}
|
|
1008
1459
|
|
|
1009
1460
|
const FOCUSABLE_ATTRIBUTE = 'data-base-ui-focusable';
|
|
1010
1461
|
const TYPEABLE_SELECTOR = "input:not([type='hidden']):not([disabled])," + "[contenteditable]:not([contenteditable='false']),textarea:not([disabled])";
|
|
@@ -1013,8 +1464,48 @@ const ARROW_RIGHT = 'ArrowRight';
|
|
|
1013
1464
|
const ARROW_UP = 'ArrowUp';
|
|
1014
1465
|
const ARROW_DOWN = 'ArrowDown';
|
|
1015
1466
|
|
|
1467
|
+
function activeElement(doc) {
|
|
1468
|
+
let element = doc.activeElement;
|
|
1469
|
+
while (element?.shadowRoot?.activeElement != null) {
|
|
1470
|
+
element = element.shadowRoot.activeElement;
|
|
1471
|
+
}
|
|
1472
|
+
return element;
|
|
1473
|
+
}
|
|
1474
|
+
function contains(parent, child) {
|
|
1475
|
+
if (!parent || !child) {
|
|
1476
|
+
return false;
|
|
1477
|
+
}
|
|
1478
|
+
const rootNode = child.getRootNode?.();
|
|
1479
|
+
|
|
1480
|
+
// First, attempt with the faster native method.
|
|
1481
|
+
if (parent.contains(child)) {
|
|
1482
|
+
return true;
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
// Then fall back to traversing out of shadow roots when needed.
|
|
1486
|
+
if (rootNode && floatingUi_utils.isShadowRoot(rootNode)) {
|
|
1487
|
+
let next = child;
|
|
1488
|
+
while (next) {
|
|
1489
|
+
if (parent === next) {
|
|
1490
|
+
return true;
|
|
1491
|
+
}
|
|
1492
|
+
next = next.parentNode || next.host;
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
return false;
|
|
1496
|
+
}
|
|
1497
|
+
function getTarget(event) {
|
|
1498
|
+
if ('composedPath' in event) {
|
|
1499
|
+
return event.composedPath()[0];
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
// TS assumes `composedPath()` always exists, but older browsers without
|
|
1503
|
+
// shadow DOM support still fall back to `target`.
|
|
1504
|
+
return event.target;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1016
1507
|
function isTargetInsideEnabledTrigger(target, triggerElements) {
|
|
1017
|
-
if (!
|
|
1508
|
+
if (!floatingUi_utils.isElement(target)) {
|
|
1018
1509
|
return false;
|
|
1019
1510
|
}
|
|
1020
1511
|
const targetElement = target;
|
|
@@ -1022,7 +1513,7 @@ function isTargetInsideEnabledTrigger(target, triggerElements) {
|
|
|
1022
1513
|
return !targetElement.hasAttribute('data-trigger-disabled');
|
|
1023
1514
|
}
|
|
1024
1515
|
for (const [, trigger] of triggerElements.entries()) {
|
|
1025
|
-
if (
|
|
1516
|
+
if (contains(trigger, targetElement)) {
|
|
1026
1517
|
return !trigger.hasAttribute('data-trigger-disabled');
|
|
1027
1518
|
}
|
|
1028
1519
|
}
|
|
@@ -1044,7 +1535,7 @@ function isRootElement(element) {
|
|
|
1044
1535
|
return element.matches('html,body');
|
|
1045
1536
|
}
|
|
1046
1537
|
function isTypeableElement(element) {
|
|
1047
|
-
return
|
|
1538
|
+
return floatingUi_utils.isHTMLElement(element) && element.matches(TYPEABLE_SELECTOR);
|
|
1048
1539
|
}
|
|
1049
1540
|
function isInteractiveElement(element) {
|
|
1050
1541
|
return element?.closest(`button,a[href],[role="button"],select,[tabindex]:not([tabindex="-1"]),${TYPEABLE_SELECTOR}`) != null;
|
|
@@ -1058,7 +1549,7 @@ function isTypeableCombobox(element) {
|
|
|
1058
1549
|
function matchesFocusVisible(element) {
|
|
1059
1550
|
// We don't want to block focus from working with `visibleOnly`
|
|
1060
1551
|
// (JSDOM doesn't match `:focus-visible` when the element has `:focus`)
|
|
1061
|
-
if (!element ||
|
|
1552
|
+
if (!element || jsdom) {
|
|
1062
1553
|
return true;
|
|
1063
1554
|
}
|
|
1064
1555
|
try {
|
|
@@ -1078,9 +1569,89 @@ function getFloatingFocusElement(floatingElement) {
|
|
|
1078
1569
|
return floatingElement.hasAttribute(FOCUSABLE_ATTRIBUTE) ? floatingElement : floatingElement.querySelector(`[${FOCUSABLE_ATTRIBUTE}]`) || floatingElement;
|
|
1079
1570
|
}
|
|
1080
1571
|
|
|
1572
|
+
const none = 'none';
|
|
1573
|
+
const triggerPress = 'trigger-press';
|
|
1574
|
+
const triggerHover = 'trigger-hover';
|
|
1575
|
+
const triggerFocus = 'trigger-focus';
|
|
1576
|
+
const outsidePress = 'outside-press';
|
|
1577
|
+
const itemPress = 'item-press';
|
|
1578
|
+
const closePress = 'close-press';
|
|
1579
|
+
const clearPress = 'clear-press';
|
|
1580
|
+
const chipRemovePress = 'chip-remove-press';
|
|
1581
|
+
const incrementPress = 'increment-press';
|
|
1582
|
+
const decrementPress = 'decrement-press';
|
|
1583
|
+
const inputChange = 'input-change';
|
|
1584
|
+
const inputClear = 'input-clear';
|
|
1585
|
+
const inputBlur = 'input-blur';
|
|
1586
|
+
const inputPaste = 'input-paste';
|
|
1587
|
+
const inputPress = 'input-press';
|
|
1588
|
+
const focusOut = 'focus-out';
|
|
1589
|
+
const escapeKey = 'escape-key';
|
|
1590
|
+
const closeWatcher = 'close-watcher';
|
|
1591
|
+
const listNavigation = 'list-navigation';
|
|
1592
|
+
const keyboard = 'keyboard';
|
|
1593
|
+
const pointer = 'pointer';
|
|
1594
|
+
const wheel = 'wheel';
|
|
1595
|
+
const scrub = 'scrub';
|
|
1596
|
+
const cancelOpen = 'cancel-open';
|
|
1597
|
+
const siblingOpen = 'sibling-open';
|
|
1598
|
+
const imperativeAction = 'imperative-action';
|
|
1599
|
+
const swipe = 'swipe';
|
|
1600
|
+
const windowResize = 'window-resize';
|
|
1601
|
+
|
|
1602
|
+
/**
|
|
1603
|
+
* Maps a change `reason` string to the corresponding native event type.
|
|
1604
|
+
*/
|
|
1605
|
+
|
|
1606
|
+
/**
|
|
1607
|
+
* Details of custom change events emitted by Base UI components.
|
|
1608
|
+
*/
|
|
1609
|
+
|
|
1610
|
+
/**
|
|
1611
|
+
* Details of custom generic events emitted by Base UI components.
|
|
1612
|
+
*/
|
|
1613
|
+
|
|
1614
|
+
/**
|
|
1615
|
+
* Creates a Base UI event details object with the given reason and utilities
|
|
1616
|
+
* for preventing Base UI's internal event handling.
|
|
1617
|
+
*/
|
|
1618
|
+
function createChangeEventDetails(reason, event, trigger, customProperties) {
|
|
1619
|
+
let canceled = false;
|
|
1620
|
+
let allowPropagation = false;
|
|
1621
|
+
const custom = customProperties ?? useRenderElement.EMPTY_OBJECT;
|
|
1622
|
+
const details = {
|
|
1623
|
+
reason,
|
|
1624
|
+
event: event ?? new Event('base-ui'),
|
|
1625
|
+
cancel() {
|
|
1626
|
+
canceled = true;
|
|
1627
|
+
},
|
|
1628
|
+
allowPropagation() {
|
|
1629
|
+
allowPropagation = true;
|
|
1630
|
+
},
|
|
1631
|
+
get isCanceled() {
|
|
1632
|
+
return canceled;
|
|
1633
|
+
},
|
|
1634
|
+
get isPropagationAllowed() {
|
|
1635
|
+
return allowPropagation;
|
|
1636
|
+
},
|
|
1637
|
+
trigger,
|
|
1638
|
+
...custom
|
|
1639
|
+
};
|
|
1640
|
+
return details;
|
|
1641
|
+
}
|
|
1642
|
+
function createGenericEventDetails(reason, event, customProperties) {
|
|
1643
|
+
const custom = customProperties ?? useRenderElement.EMPTY_OBJECT;
|
|
1644
|
+
const details = {
|
|
1645
|
+
reason,
|
|
1646
|
+
event: event ?? new Event('base-ui'),
|
|
1647
|
+
...custom
|
|
1648
|
+
};
|
|
1649
|
+
return details;
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1081
1652
|
const FocusGuard = /*#__PURE__*/React__namespace.forwardRef(function FocusGuard(props, ref) {
|
|
1082
1653
|
const [role, setRole] = React__namespace.useState();
|
|
1083
|
-
|
|
1654
|
+
useIsoLayoutEffect(() => {
|
|
1084
1655
|
// Unlike NVDA and JAWS, VoiceOver's virtual cursor triggers `onFocus` as
|
|
1085
1656
|
// it moves — but only on focusable/role-button elements through WebKit's
|
|
1086
1657
|
// NSAccessibility path. Setting `role="button"` lets the focus trap catch
|
|
@@ -1097,7 +1668,7 @@ const FocusGuard = /*#__PURE__*/React__namespace.forwardRef(function FocusGuard(
|
|
|
1097
1668
|
return /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
1098
1669
|
...props,
|
|
1099
1670
|
ref: ref,
|
|
1100
|
-
style:
|
|
1671
|
+
style: visuallyHidden,
|
|
1101
1672
|
"aria-hidden": role ? undefined : true,
|
|
1102
1673
|
...restProps,
|
|
1103
1674
|
"data-base-ui-focus-guard": ""
|
|
@@ -1258,7 +1829,7 @@ function getGridNavigatedIndex(list, {
|
|
|
1258
1829
|
return undefined;
|
|
1259
1830
|
};
|
|
1260
1831
|
if (stop) {
|
|
1261
|
-
|
|
1832
|
+
stopEvent(event);
|
|
1262
1833
|
}
|
|
1263
1834
|
const verticalCandidate = navigateVertically(verticalDirection) ?? navigateVerticallyWithInferredRows(verticalDirection);
|
|
1264
1835
|
if (verticalCandidate !== undefined) {
|
|
@@ -1308,7 +1879,7 @@ function getGridNavigatedIndex(list, {
|
|
|
1308
1879
|
const prevRow = floatingUi_utils.floor(prevIndex / cols);
|
|
1309
1880
|
if (event.key === (rtl ? ARROW_LEFT : ARROW_RIGHT)) {
|
|
1310
1881
|
if (stop) {
|
|
1311
|
-
|
|
1882
|
+
stopEvent(event);
|
|
1312
1883
|
}
|
|
1313
1884
|
if (prevIndex % cols !== cols - 1) {
|
|
1314
1885
|
nextIndex = findNonDisabledListIndex(list, {
|
|
@@ -1339,7 +1910,7 @@ function getGridNavigatedIndex(list, {
|
|
|
1339
1910
|
}
|
|
1340
1911
|
if (event.key === (rtl ? ARROW_RIGHT : ARROW_LEFT)) {
|
|
1341
1912
|
if (stop) {
|
|
1342
|
-
|
|
1913
|
+
stopEvent(event);
|
|
1343
1914
|
}
|
|
1344
1915
|
if (prevIndex % cols !== 0) {
|
|
1345
1916
|
nextIndex = findNonDisabledListIndex(list, {
|
|
@@ -1405,7 +1976,7 @@ function isListIndexDisabled(list, index, disabledIndices) {
|
|
|
1405
1976
|
function isHiddenByStyles(styles) {
|
|
1406
1977
|
return styles.visibility === 'hidden' || styles.visibility === 'collapse';
|
|
1407
1978
|
}
|
|
1408
|
-
function isElementVisible(element, styles = element ?
|
|
1979
|
+
function isElementVisible(element, styles = element ? floatingUi_utils.getComputedStyle(element) : null) {
|
|
1409
1980
|
if (!element || !element.isConnected || !styles || isHiddenByStyles(styles)) {
|
|
1410
1981
|
return false;
|
|
1411
1982
|
}
|
|
@@ -1425,11 +1996,11 @@ function getParentElement(element) {
|
|
|
1425
1996
|
return element.parentElement;
|
|
1426
1997
|
}
|
|
1427
1998
|
const rootNode = element.getRootNode();
|
|
1428
|
-
return
|
|
1999
|
+
return floatingUi_utils.isShadowRoot(rootNode) ? rootNode.host : null;
|
|
1429
2000
|
}
|
|
1430
2001
|
function getDetailsSummary(details) {
|
|
1431
2002
|
for (const child of Array.from(details.children)) {
|
|
1432
|
-
if (
|
|
2003
|
+
if (floatingUi_utils.getNodeName(child) === 'summary') {
|
|
1433
2004
|
return child;
|
|
1434
2005
|
}
|
|
1435
2006
|
}
|
|
@@ -1437,11 +2008,11 @@ function getDetailsSummary(details) {
|
|
|
1437
2008
|
}
|
|
1438
2009
|
function isWithinOpenDetailsSummary(element, details) {
|
|
1439
2010
|
const summary = getDetailsSummary(details);
|
|
1440
|
-
return !!summary && (element === summary ||
|
|
2011
|
+
return !!summary && (element === summary || contains(summary, element));
|
|
1441
2012
|
}
|
|
1442
2013
|
function isFocusableCandidate(element) {
|
|
1443
|
-
const nodeName = element ?
|
|
1444
|
-
return element != null && element.matches(CANDIDATE_SELECTOR) && (nodeName !== 'summary' || element.parentElement != null &&
|
|
2014
|
+
const nodeName = element ? floatingUi_utils.getNodeName(element) : '';
|
|
2015
|
+
return element != null && element.matches(CANDIDATE_SELECTOR) && (nodeName !== 'summary' || element.parentElement != null && floatingUi_utils.getNodeName(element.parentElement) === 'details' && getDetailsSummary(element.parentElement) === element) && (nodeName !== 'details' || getDetailsSummary(element) == null) && (nodeName !== 'input' || element.type !== 'hidden');
|
|
1445
2016
|
}
|
|
1446
2017
|
function isFocusableElement(element) {
|
|
1447
2018
|
if (!isFocusableCandidate(element) || !element.isConnected || element.matches(':disabled')) {
|
|
@@ -1449,18 +2020,18 @@ function isFocusableElement(element) {
|
|
|
1449
2020
|
}
|
|
1450
2021
|
for (let current = element; current; current = getParentElement(current)) {
|
|
1451
2022
|
const isAncestor = current !== element;
|
|
1452
|
-
const isSlot =
|
|
2023
|
+
const isSlot = floatingUi_utils.getNodeName(current) === 'slot';
|
|
1453
2024
|
if (current.hasAttribute('inert')) {
|
|
1454
2025
|
return false;
|
|
1455
2026
|
}
|
|
1456
|
-
if (isAncestor &&
|
|
2027
|
+
if (isAncestor && floatingUi_utils.getNodeName(current) === 'details' && !current.open && !isWithinOpenDetailsSummary(element, current) || current.hasAttribute('hidden') || !isSlot && !isVisibleInTabbableTree(current, isAncestor)) {
|
|
1457
2028
|
return false;
|
|
1458
2029
|
}
|
|
1459
2030
|
}
|
|
1460
2031
|
return true;
|
|
1461
2032
|
}
|
|
1462
2033
|
function isVisibleInTabbableTree(element, isAncestor) {
|
|
1463
|
-
const styles =
|
|
2034
|
+
const styles = floatingUi_utils.getComputedStyle(element);
|
|
1464
2035
|
if (!isAncestor) {
|
|
1465
2036
|
return isElementVisible(element, styles);
|
|
1466
2037
|
}
|
|
@@ -1469,15 +2040,15 @@ function isVisibleInTabbableTree(element, isAncestor) {
|
|
|
1469
2040
|
function getTabIndex(element) {
|
|
1470
2041
|
const tabIndex = element.tabIndex;
|
|
1471
2042
|
if (tabIndex < 0) {
|
|
1472
|
-
const nodeName =
|
|
1473
|
-
if (nodeName === 'details' || nodeName === 'audio' || nodeName === 'video' ||
|
|
2043
|
+
const nodeName = floatingUi_utils.getNodeName(element);
|
|
2044
|
+
if (nodeName === 'details' || nodeName === 'audio' || nodeName === 'video' || floatingUi_utils.isHTMLElement(element) && element.isContentEditable) {
|
|
1474
2045
|
return 0;
|
|
1475
2046
|
}
|
|
1476
2047
|
}
|
|
1477
2048
|
return tabIndex;
|
|
1478
2049
|
}
|
|
1479
2050
|
function getNamedRadioInput(element) {
|
|
1480
|
-
if (
|
|
2051
|
+
if (floatingUi_utils.getNodeName(element) !== 'input') {
|
|
1481
2052
|
return null;
|
|
1482
2053
|
}
|
|
1483
2054
|
const input = element;
|
|
@@ -1501,7 +2072,7 @@ function isTabbableRadio(element, candidates) {
|
|
|
1501
2072
|
}) === input;
|
|
1502
2073
|
}
|
|
1503
2074
|
function getComposedChildren(container) {
|
|
1504
|
-
if (
|
|
2075
|
+
if (floatingUi_utils.isHTMLElement(container) && floatingUi_utils.getNodeName(container) === 'slot') {
|
|
1505
2076
|
const assignedElements = container.assignedElements({
|
|
1506
2077
|
flatten: true
|
|
1507
2078
|
});
|
|
@@ -1509,7 +2080,7 @@ function getComposedChildren(container) {
|
|
|
1509
2080
|
return assignedElements;
|
|
1510
2081
|
}
|
|
1511
2082
|
}
|
|
1512
|
-
if (
|
|
2083
|
+
if (floatingUi_utils.isHTMLElement(container) && container.shadowRoot) {
|
|
1513
2084
|
return Array.from(container.shadowRoot.children);
|
|
1514
2085
|
}
|
|
1515
2086
|
return Array.from(container.children);
|
|
@@ -1524,7 +2095,7 @@ function appendCandidates(container, list) {
|
|
|
1524
2095
|
}
|
|
1525
2096
|
function appendMatchingElements(container, selector, list) {
|
|
1526
2097
|
getComposedChildren(container).forEach(child => {
|
|
1527
|
-
if (
|
|
2098
|
+
if (floatingUi_utils.isHTMLElement(child) && child.matches(selector)) {
|
|
1528
2099
|
list.push(child);
|
|
1529
2100
|
}
|
|
1530
2101
|
appendMatchingElements(child, selector, list);
|
|
@@ -1548,23 +2119,23 @@ function getTabbableIn(container, dir) {
|
|
|
1548
2119
|
if (len === 0) {
|
|
1549
2120
|
return undefined;
|
|
1550
2121
|
}
|
|
1551
|
-
const active =
|
|
2122
|
+
const active = activeElement(ownerDocument(container));
|
|
1552
2123
|
const index = list.indexOf(active);
|
|
1553
2124
|
// eslint-disable-next-line no-nested-ternary
|
|
1554
2125
|
const nextIndex = index === -1 ? dir === 1 ? 0 : len - 1 : index + dir;
|
|
1555
2126
|
return list[nextIndex];
|
|
1556
2127
|
}
|
|
1557
2128
|
function getNextTabbable(referenceElement) {
|
|
1558
|
-
return getTabbableIn(
|
|
2129
|
+
return getTabbableIn(ownerDocument(referenceElement).body, 1) || referenceElement;
|
|
1559
2130
|
}
|
|
1560
2131
|
function getPreviousTabbable(referenceElement) {
|
|
1561
|
-
return getTabbableIn(
|
|
2132
|
+
return getTabbableIn(ownerDocument(referenceElement).body, -1) || referenceElement;
|
|
1562
2133
|
}
|
|
1563
2134
|
function getTabbableNearElement(referenceElement, dir) {
|
|
1564
2135
|
if (!referenceElement) {
|
|
1565
2136
|
return null;
|
|
1566
2137
|
}
|
|
1567
|
-
const list = tabbable(
|
|
2138
|
+
const list = tabbable(ownerDocument(referenceElement).body);
|
|
1568
2139
|
const elementCount = list.length;
|
|
1569
2140
|
if (elementCount === 0) {
|
|
1570
2141
|
return null;
|
|
@@ -1585,7 +2156,7 @@ function getTabbableBeforeElement(referenceElement) {
|
|
|
1585
2156
|
function isOutsideEvent(event, container) {
|
|
1586
2157
|
const containerElement = container || event.currentTarget;
|
|
1587
2158
|
const relatedTarget = event.relatedTarget;
|
|
1588
|
-
return !relatedTarget || !
|
|
2159
|
+
return !relatedTarget || !contains(containerElement, relatedTarget);
|
|
1589
2160
|
}
|
|
1590
2161
|
function disableFocusInside(container) {
|
|
1591
2162
|
const tabbableElements = tabbable(container);
|
|
@@ -1681,7 +2252,7 @@ function unwrapHost(node) {
|
|
|
1681
2252
|
if (!node) {
|
|
1682
2253
|
return null;
|
|
1683
2254
|
}
|
|
1684
|
-
return
|
|
2255
|
+
return floatingUi_utils.isShadowRoot(node) ? node.host : unwrapHost(node.parentNode);
|
|
1685
2256
|
}
|
|
1686
2257
|
const correctElements = (parent, targets) => targets.map(target => {
|
|
1687
2258
|
if (parent.contains(target)) {
|
|
@@ -1711,7 +2282,7 @@ const collectOutsideElements = (root, keepElements, stopElements) => {
|
|
|
1711
2282
|
return;
|
|
1712
2283
|
}
|
|
1713
2284
|
Array.from(parent.children).forEach(node => {
|
|
1714
|
-
if (
|
|
2285
|
+
if (floatingUi_utils.getNodeName(node) === 'script') {
|
|
1715
2286
|
return;
|
|
1716
2287
|
}
|
|
1717
2288
|
if (keepElements.has(node)) {
|
|
@@ -1811,12 +2382,50 @@ function markOthers(avoidElements, options = {}) {
|
|
|
1811
2382
|
inert = false,
|
|
1812
2383
|
mark = true
|
|
1813
2384
|
} = options;
|
|
1814
|
-
const body =
|
|
2385
|
+
const body = ownerDocument(avoidElements[0]).body;
|
|
1815
2386
|
return applyAttributeToOthers(avoidElements, body, ariaHidden, inert, {
|
|
1816
2387
|
mark
|
|
1817
2388
|
});
|
|
1818
2389
|
}
|
|
1819
2390
|
|
|
2391
|
+
let globalId = 0;
|
|
2392
|
+
|
|
2393
|
+
// TODO React 17: Remove `useGlobalId` once React 17 support is removed
|
|
2394
|
+
function useGlobalId(idOverride, prefix = 'mui') {
|
|
2395
|
+
const [defaultId, setDefaultId] = React__namespace.useState(idOverride);
|
|
2396
|
+
const id = idOverride || defaultId;
|
|
2397
|
+
React__namespace.useEffect(() => {
|
|
2398
|
+
if (defaultId == null) {
|
|
2399
|
+
// Fallback to this default id when possible.
|
|
2400
|
+
// Use the incrementing value for client-side rendering only.
|
|
2401
|
+
// We can't use it server-side.
|
|
2402
|
+
// If you want to use random values please consider the Birthday Problem: https://en.wikipedia.org/wiki/Birthday_problem
|
|
2403
|
+
globalId += 1;
|
|
2404
|
+
setDefaultId(`${prefix}-${globalId}`);
|
|
2405
|
+
}
|
|
2406
|
+
}, [defaultId, prefix]);
|
|
2407
|
+
return id;
|
|
2408
|
+
}
|
|
2409
|
+
const maybeReactUseId = SafeReact.useId;
|
|
2410
|
+
|
|
2411
|
+
/**
|
|
2412
|
+
*
|
|
2413
|
+
* @example <div id={useId()} />
|
|
2414
|
+
* @param idOverride
|
|
2415
|
+
* @returns {string}
|
|
2416
|
+
*/
|
|
2417
|
+
function useId(idOverride, prefix) {
|
|
2418
|
+
// React.useId() is only available from React 17.0.0.
|
|
2419
|
+
if (maybeReactUseId !== undefined) {
|
|
2420
|
+
const reactId = maybeReactUseId();
|
|
2421
|
+
return idOverride ?? (prefix ? `${prefix}-${reactId}` : reactId);
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2424
|
+
// TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler
|
|
2425
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks -- `React.useId` is invariant at runtime.
|
|
2426
|
+
return useGlobalId(idOverride, prefix);
|
|
2427
|
+
}
|
|
2428
|
+
|
|
1820
2429
|
const TYPEAHEAD_RESET_MS = 500;
|
|
1821
2430
|
const PATIENT_CLICK_THRESHOLD = 500;
|
|
1822
2431
|
const DISABLED_TRANSITIONS_STYLE = {
|
|
@@ -1868,12 +2477,12 @@ function useFloatingPortalNode(props = {}) {
|
|
|
1868
2477
|
componentProps = useRenderElement.EMPTY_OBJECT,
|
|
1869
2478
|
elementProps
|
|
1870
2479
|
} = props;
|
|
1871
|
-
const uniqueId =
|
|
2480
|
+
const uniqueId = useId();
|
|
1872
2481
|
const portalContext = usePortalContext();
|
|
1873
2482
|
const parentPortalNode = portalContext?.portalNode;
|
|
1874
2483
|
const [containerElement, setContainerElement] = React__namespace.useState(null);
|
|
1875
2484
|
const [portalNode, setPortalNode] = React__namespace.useState(null);
|
|
1876
|
-
const setPortalNodeRef =
|
|
2485
|
+
const setPortalNodeRef = useStableCallback(node => {
|
|
1877
2486
|
if (node !== null) {
|
|
1878
2487
|
// the useIsoLayoutEffect below watching containerProp / parentPortalNode
|
|
1879
2488
|
// sets setPortalNode(null) when the container becomes null or changes.
|
|
@@ -1882,7 +2491,7 @@ function useFloatingPortalNode(props = {}) {
|
|
|
1882
2491
|
}
|
|
1883
2492
|
});
|
|
1884
2493
|
const containerRef = React__namespace.useRef(null);
|
|
1885
|
-
|
|
2494
|
+
useIsoLayoutEffect(() => {
|
|
1886
2495
|
// Wait for the container to be resolved if explicitly `null`.
|
|
1887
2496
|
if (containerProp === null) {
|
|
1888
2497
|
if (containerRef.current) {
|
|
@@ -1897,7 +2506,7 @@ function useFloatingPortalNode(props = {}) {
|
|
|
1897
2506
|
if (uniqueId == null) {
|
|
1898
2507
|
return;
|
|
1899
2508
|
}
|
|
1900
|
-
const resolvedContainer = (containerProp && (
|
|
2509
|
+
const resolvedContainer = (containerProp && (floatingUi_utils.isNode(containerProp) ? containerProp : containerProp.current)) ?? parentPortalNode ?? document.body;
|
|
1901
2510
|
if (resolvedContainer == null) {
|
|
1902
2511
|
if (containerRef.current) {
|
|
1903
2512
|
containerRef.current = null;
|
|
@@ -1992,9 +2601,9 @@ const FloatingPortal = /*#__PURE__*/React__namespace.forwardRef(function Floatin
|
|
|
1992
2601
|
|
|
1993
2602
|
// Listen to the event on the capture phase so they run before the focus
|
|
1994
2603
|
// trap elements onFocus prop is called.
|
|
1995
|
-
return mergeCleanups(
|
|
2604
|
+
return mergeCleanups(addEventListener(portalNode, 'focusin', onFocus, true), addEventListener(portalNode, 'focusout', onFocus, true));
|
|
1996
2605
|
}, [portalNode, modal]);
|
|
1997
|
-
|
|
2606
|
+
useIsoLayoutEffect(() => {
|
|
1998
2607
|
if (!portalNode || open !== true || !focusInsideDisabledRef.current) {
|
|
1999
2608
|
return;
|
|
2000
2609
|
}
|
|
@@ -2040,7 +2649,7 @@ const FloatingPortal = /*#__PURE__*/React__namespace.forwardRef(function Floatin
|
|
|
2040
2649
|
const nextTabbable = getNextTabbable(domReference);
|
|
2041
2650
|
nextTabbable?.focus();
|
|
2042
2651
|
if (focusManagerState?.closeOnFocusOut) {
|
|
2043
|
-
focusManagerState?.onOpenChange(false,
|
|
2652
|
+
focusManagerState?.onOpenChange(false, createChangeEventDetails(focusOut, event.nativeEvent));
|
|
2044
2653
|
}
|
|
2045
2654
|
}
|
|
2046
2655
|
}
|
|
@@ -2112,10 +2721,10 @@ const useFloatingTree = externalTree => {
|
|
|
2112
2721
|
* @see https://floating-ui.com/docs/FloatingTree
|
|
2113
2722
|
*/
|
|
2114
2723
|
function useFloatingNodeId(externalTree) {
|
|
2115
|
-
const id =
|
|
2724
|
+
const id = useId();
|
|
2116
2725
|
const tree = useFloatingTree(externalTree);
|
|
2117
2726
|
const parentId = useFloatingParentNodeId();
|
|
2118
|
-
|
|
2727
|
+
useIsoLayoutEffect(() => {
|
|
2119
2728
|
if (!id) {
|
|
2120
2729
|
return undefined;
|
|
2121
2730
|
}
|
|
@@ -2172,8 +2781,19 @@ function FloatingTree(props) {
|
|
|
2172
2781
|
});
|
|
2173
2782
|
}
|
|
2174
2783
|
|
|
2784
|
+
/**
|
|
2785
|
+
* If the provided argument is a ref object, returns its `current` value.
|
|
2786
|
+
* Otherwise, returns the argument itself.
|
|
2787
|
+
*/
|
|
2788
|
+
function resolveRef(maybeRef) {
|
|
2789
|
+
if (maybeRef == null) {
|
|
2790
|
+
return maybeRef;
|
|
2791
|
+
}
|
|
2792
|
+
return 'current' in maybeRef ? maybeRef.current : maybeRef;
|
|
2793
|
+
}
|
|
2794
|
+
|
|
2175
2795
|
function getEventType(event, lastInteractionType) {
|
|
2176
|
-
const win =
|
|
2796
|
+
const win = floatingUi_utils.getWindow(getTarget(event));
|
|
2177
2797
|
if (event instanceof win.KeyboardEvent) {
|
|
2178
2798
|
return 'keyboard';
|
|
2179
2799
|
}
|
|
@@ -2203,7 +2823,7 @@ function clearDisconnectedPreviouslyFocusedElements() {
|
|
|
2203
2823
|
}
|
|
2204
2824
|
function addPreviouslyFocusedElement(element) {
|
|
2205
2825
|
clearDisconnectedPreviouslyFocusedElements();
|
|
2206
|
-
if (element &&
|
|
2826
|
+
if (element && floatingUi_utils.getNodeName(element) !== 'body') {
|
|
2207
2827
|
previouslyFocusedElements.push(new WeakRef(element));
|
|
2208
2828
|
if (previouslyFocusedElements.length > LIST_LIMIT) {
|
|
2209
2829
|
previouslyFocusedElements = previouslyFocusedElements.slice(-LIST_LIMIT);
|
|
@@ -2278,7 +2898,7 @@ function FloatingFocusManager(props) {
|
|
|
2278
2898
|
events,
|
|
2279
2899
|
dataRef
|
|
2280
2900
|
} = store.context;
|
|
2281
|
-
const getNodeId =
|
|
2901
|
+
const getNodeId = useStableCallback(() => dataRef.current.floatingContext?.nodeId);
|
|
2282
2902
|
const ignoreInitialFocus = initialFocus === false;
|
|
2283
2903
|
// If the reference is a combobox and is typeable (e.g. input/textarea),
|
|
2284
2904
|
// there are different focus semantics. The guards should not be rendered, but
|
|
@@ -2286,10 +2906,10 @@ function FloatingFocusManager(props) {
|
|
|
2286
2906
|
// hidden dismiss button should only appear at the end of the list, not the
|
|
2287
2907
|
// start.
|
|
2288
2908
|
const isUntrappedTypeableCombobox = isTypeableCombobox(domReference) && ignoreInitialFocus;
|
|
2289
|
-
const initialFocusRef =
|
|
2290
|
-
const returnFocusRef =
|
|
2291
|
-
const openInteractionTypeRef =
|
|
2292
|
-
const openRef =
|
|
2909
|
+
const initialFocusRef = useValueAsRef(initialFocus);
|
|
2910
|
+
const returnFocusRef = useValueAsRef(returnFocus);
|
|
2911
|
+
const openInteractionTypeRef = useValueAsRef(openInteractionType);
|
|
2912
|
+
const openRef = useValueAsRef(open);
|
|
2293
2913
|
const tree = useFloatingTree(externalTree);
|
|
2294
2914
|
const portalContext = usePortalContext();
|
|
2295
2915
|
const preventReturnFocusRef = React__namespace.useRef(false);
|
|
@@ -2302,15 +2922,15 @@ function FloatingFocusManager(props) {
|
|
|
2302
2922
|
const afterGuardRef = React__namespace.useRef(null);
|
|
2303
2923
|
const mergedBeforeGuardRef = useRenderElement.useMergedRefs(beforeGuardRef, beforeContentFocusGuardRef, portalContext?.beforeInsideRef);
|
|
2304
2924
|
const mergedAfterGuardRef = useRenderElement.useMergedRefs(afterGuardRef, portalContext?.afterInsideRef);
|
|
2305
|
-
const blurTimeout =
|
|
2306
|
-
const pointerDownTimeout =
|
|
2307
|
-
const restoreFocusFrame =
|
|
2925
|
+
const blurTimeout = useTimeout();
|
|
2926
|
+
const pointerDownTimeout = useTimeout();
|
|
2927
|
+
const restoreFocusFrame = useAnimationFrame();
|
|
2308
2928
|
const isInsidePortal = portalContext != null;
|
|
2309
2929
|
const floatingFocusElement = getFloatingFocusElement(floating);
|
|
2310
|
-
const getTabbableContent =
|
|
2930
|
+
const getTabbableContent = useStableCallback((container = floatingFocusElement) => {
|
|
2311
2931
|
return container ? tabbable(container) : [];
|
|
2312
2932
|
});
|
|
2313
|
-
const getResolvedInsideElements =
|
|
2933
|
+
const getResolvedInsideElements = useStableCallback(() => getInsideElements?.().filter(element => element != null) ?? []);
|
|
2314
2934
|
|
|
2315
2935
|
// Prevent Tab from escaping the modal when there are no tabbable elements.
|
|
2316
2936
|
React__namespace.useEffect(() => {
|
|
@@ -2320,13 +2940,13 @@ function FloatingFocusManager(props) {
|
|
|
2320
2940
|
function onKeyDown(event) {
|
|
2321
2941
|
if (event.key === 'Tab') {
|
|
2322
2942
|
// The focus guards have nothing to focus, so we need to stop the event.
|
|
2323
|
-
if (
|
|
2324
|
-
|
|
2943
|
+
if (contains(floatingFocusElement, activeElement(ownerDocument(floatingFocusElement))) && getTabbableContent().length === 0 && !isUntrappedTypeableCombobox) {
|
|
2944
|
+
stopEvent(event);
|
|
2325
2945
|
}
|
|
2326
2946
|
}
|
|
2327
2947
|
}
|
|
2328
|
-
const doc =
|
|
2329
|
-
return
|
|
2948
|
+
const doc = ownerDocument(floatingFocusElement);
|
|
2949
|
+
return addEventListener(doc, 'keydown', onKeyDown);
|
|
2330
2950
|
}, [disabled, floatingFocusElement, modal, isUntrappedTypeableCombobox, getTabbableContent]);
|
|
2331
2951
|
|
|
2332
2952
|
// Track pointer/keyboard interactions to disambiguate focus and outside presses.
|
|
@@ -2334,14 +2954,14 @@ function FloatingFocusManager(props) {
|
|
|
2334
2954
|
if (disabled || !open) {
|
|
2335
2955
|
return undefined;
|
|
2336
2956
|
}
|
|
2337
|
-
const doc =
|
|
2957
|
+
const doc = ownerDocument(floatingFocusElement);
|
|
2338
2958
|
function clearPointerDownOutside() {
|
|
2339
2959
|
pointerDownOutsideRef.current = false;
|
|
2340
2960
|
}
|
|
2341
2961
|
function onPointerDown(event) {
|
|
2342
|
-
const target =
|
|
2962
|
+
const target = getTarget(event);
|
|
2343
2963
|
const insideElements = getResolvedInsideElements();
|
|
2344
|
-
const pointerTargetInside =
|
|
2964
|
+
const pointerTargetInside = contains(floating, target) || contains(domReference, target) || contains(portalContext?.portalNode, target) || insideElements.some(element => element === target || contains(element, target));
|
|
2345
2965
|
pointerDownOutsideRef.current = !pointerTargetInside;
|
|
2346
2966
|
lastInteractionTypeRef.current = event.pointerType || 'keyboard';
|
|
2347
2967
|
if (target?.closest(`[${CLICK_TRIGGER_IDENTIFIER}]`)) {
|
|
@@ -2356,7 +2976,7 @@ function FloatingFocusManager(props) {
|
|
|
2356
2976
|
function onKeyDown() {
|
|
2357
2977
|
lastInteractionTypeRef.current = 'keyboard';
|
|
2358
2978
|
}
|
|
2359
|
-
return mergeCleanups(
|
|
2979
|
+
return mergeCleanups(addEventListener(doc, 'pointerdown', onPointerDown, true), addEventListener(doc, 'pointerup', clearPointerDownOutside, true), addEventListener(doc, 'pointercancel', clearPointerDownOutside, true), addEventListener(doc, 'keydown', onKeyDown, true),
|
|
2360
2980
|
// Avoid a stale `true` leaking into the next open (e.g. keep-mounted popups)
|
|
2361
2981
|
// if the popup dismissed between pointerdown and pointerup.
|
|
2362
2982
|
clearPointerDownOutside);
|
|
@@ -2367,7 +2987,7 @@ function FloatingFocusManager(props) {
|
|
|
2367
2987
|
if (disabled || !closeOnFocusOut) {
|
|
2368
2988
|
return undefined;
|
|
2369
2989
|
}
|
|
2370
|
-
const doc =
|
|
2990
|
+
const doc = ownerDocument(floatingFocusElement);
|
|
2371
2991
|
|
|
2372
2992
|
// In Safari, buttons lose focus when pressing them.
|
|
2373
2993
|
function handlePointerDown() {
|
|
@@ -2377,7 +2997,7 @@ function FloatingFocusManager(props) {
|
|
|
2377
2997
|
});
|
|
2378
2998
|
}
|
|
2379
2999
|
function handleFocusIn(event) {
|
|
2380
|
-
const target =
|
|
3000
|
+
const target = getTarget(event);
|
|
2381
3001
|
if (isTabbable(target)) {
|
|
2382
3002
|
lastFocusedTabbableRef.current = target;
|
|
2383
3003
|
}
|
|
@@ -2385,30 +3005,30 @@ function FloatingFocusManager(props) {
|
|
|
2385
3005
|
function handleFocusOutside(event) {
|
|
2386
3006
|
const relatedTarget = event.relatedTarget;
|
|
2387
3007
|
const currentTarget = event.currentTarget;
|
|
2388
|
-
const target =
|
|
3008
|
+
const target = getTarget(event);
|
|
2389
3009
|
|
|
2390
3010
|
// When focus is lost to the body (e.g. on a backdrop press), record the element that
|
|
2391
3011
|
// had focus so a confirmation dialog opened while the body is focused can return focus
|
|
2392
3012
|
// to it. Scoped to `modal` to avoid non-modal popups polluting the shared stack.
|
|
2393
|
-
if (modal && relatedTarget == null && target != null &&
|
|
3013
|
+
if (modal && relatedTarget == null && target != null && contains(floating, target)) {
|
|
2394
3014
|
addPreviouslyFocusedElement(target);
|
|
2395
3015
|
}
|
|
2396
3016
|
queueMicrotask(() => {
|
|
2397
3017
|
const nodeId = getNodeId();
|
|
2398
3018
|
const triggers = store.context.triggerElements;
|
|
2399
3019
|
const insideElements = getResolvedInsideElements();
|
|
2400
|
-
const isRelatedFocusGuard = relatedTarget?.hasAttribute(createAttribute('focus-guard')) && [beforeGuardRef.current, afterGuardRef.current, portalContext?.beforeInsideRef.current, portalContext?.afterInsideRef.current, portalContext?.beforeOutsideRef.current, portalContext?.afterOutsideRef.current,
|
|
2401
|
-
const movedToUnrelatedNode = !(
|
|
3020
|
+
const isRelatedFocusGuard = relatedTarget?.hasAttribute(createAttribute('focus-guard')) && [beforeGuardRef.current, afterGuardRef.current, portalContext?.beforeInsideRef.current, portalContext?.afterInsideRef.current, portalContext?.beforeOutsideRef.current, portalContext?.afterOutsideRef.current, resolveRef(previousFocusableElement), resolveRef(nextFocusableElement)].includes(relatedTarget);
|
|
3021
|
+
const movedToUnrelatedNode = !(contains(domReference, relatedTarget) || contains(floating, relatedTarget) || contains(relatedTarget, floating) || contains(portalContext?.portalNode, relatedTarget) || insideElements.some(element => element === relatedTarget || contains(element, relatedTarget)) || relatedTarget != null && triggers.hasElement(relatedTarget) || triggers.hasMatchingElement(trigger => contains(trigger, relatedTarget)) || isRelatedFocusGuard || tree && (getNodeChildren(tree.nodesRef.current, nodeId).find(node => contains(node.context?.elements.floating, relatedTarget) || contains(node.context?.elements.domReference, relatedTarget)) || getNodeAncestors(tree.nodesRef.current, nodeId).find(node => [node.context?.elements.floating, getFloatingFocusElement(node.context?.elements.floating)].includes(relatedTarget) || node.context?.elements.domReference === relatedTarget)));
|
|
2402
3022
|
if (currentTarget === domReference && floatingFocusElement) {
|
|
2403
3023
|
handleTabIndex(floatingFocusElement);
|
|
2404
3024
|
}
|
|
2405
3025
|
|
|
2406
3026
|
// Restore focus to the previous tabbable element index to prevent
|
|
2407
3027
|
// focus from being lost outside the floating tree.
|
|
2408
|
-
if (restoreFocus && currentTarget !== domReference && !isElementVisible(target) &&
|
|
3028
|
+
if (restoreFocus && currentTarget !== domReference && !isElementVisible(target) && activeElement(doc) === doc.body) {
|
|
2409
3029
|
// Let `FloatingPortal` effect knows that focus is still inside the
|
|
2410
3030
|
// floating tree.
|
|
2411
|
-
if (
|
|
3031
|
+
if (floatingUi_utils.isHTMLElement(floatingFocusElement)) {
|
|
2412
3032
|
floatingFocusElement.focus();
|
|
2413
3033
|
// If explicitly requested to restore focus to the popup container, do not search
|
|
2414
3034
|
// for the next/previous tabbable element.
|
|
@@ -2426,7 +3046,7 @@ function FloatingFocusManager(props) {
|
|
|
2426
3046
|
const tabbableContent = getTabbableContent();
|
|
2427
3047
|
const prevTabbable = lastFocusedTabbableRef.current;
|
|
2428
3048
|
const nodeToFocus = (prevTabbable && tabbableContent.includes(prevTabbable) ? prevTabbable : null) || tabbableContent[tabbableContent.length - 1] || floatingFocusElement;
|
|
2429
|
-
if (
|
|
3049
|
+
if (floatingUi_utils.isHTMLElement(nodeToFocus)) {
|
|
2430
3050
|
nodeToFocus.focus();
|
|
2431
3051
|
}
|
|
2432
3052
|
}
|
|
@@ -2449,7 +3069,7 @@ function FloatingFocusManager(props) {
|
|
|
2449
3069
|
// Allow closing when `isUntrappedTypeableCombobox` regardless of the previously focused element.
|
|
2450
3070
|
isUntrappedTypeableCombobox || relatedTarget !== getPreviouslyFocusedElement())) {
|
|
2451
3071
|
preventReturnFocusRef.current = true;
|
|
2452
|
-
store.setOpen(false,
|
|
3072
|
+
store.setOpen(false, createChangeEventDetails(focusOut, event));
|
|
2453
3073
|
}
|
|
2454
3074
|
});
|
|
2455
3075
|
}
|
|
@@ -2462,11 +3082,11 @@ function FloatingFocusManager(props) {
|
|
|
2462
3082
|
dataRef.current.insideReactTree = false;
|
|
2463
3083
|
});
|
|
2464
3084
|
}
|
|
2465
|
-
const domReferenceElement =
|
|
3085
|
+
const domReferenceElement = floatingUi_utils.isHTMLElement(domReference) ? domReference : null;
|
|
2466
3086
|
if (!floating && !domReferenceElement) {
|
|
2467
3087
|
return undefined;
|
|
2468
3088
|
}
|
|
2469
|
-
return mergeCleanups(domReferenceElement &&
|
|
3089
|
+
return mergeCleanups(domReferenceElement && addEventListener(domReferenceElement, 'focusout', handleFocusOutside), domReferenceElement && addEventListener(domReferenceElement, 'pointerdown', handlePointerDown), floating && addEventListener(floating, 'focusin', handleFocusIn), floating && addEventListener(floating, 'focusout', handleFocusOutside), floating && portalContext && addEventListener(floating, 'focusout', markInsideReactTree, true));
|
|
2470
3090
|
}, [disabled, domReference, floating, floatingFocusElement, modal, tree, portalContext, store, closeOnFocusOut, restoreFocus, getTabbableContent, isUntrappedTypeableCombobox, getNodeId, dataRef, blurTimeout, pointerDownTimeout, restoreFocusFrame, nextFocusableElement, previousFocusableElement, getResolvedInsideElements]);
|
|
2471
3091
|
|
|
2472
3092
|
// Hide everything outside the floating tree from assistive tech while open.
|
|
@@ -2480,7 +3100,7 @@ function FloatingFocusManager(props) {
|
|
|
2480
3100
|
const ancestors = tree ? getNodeAncestors(tree.nodesRef.current, getNodeId()) : [];
|
|
2481
3101
|
const rootAncestorComboboxDomReference = ancestors.find(node => isTypeableCombobox(node.context?.elements.domReference || null))?.context?.elements.domReference;
|
|
2482
3102
|
const controlInsideElements = [floating, ...portalNodes, beforeGuardRef.current, afterGuardRef.current, portalContext?.beforeOutsideRef.current, portalContext?.afterOutsideRef.current, ...getResolvedInsideElements()];
|
|
2483
|
-
const insideElements = [...controlInsideElements, rootAncestorComboboxDomReference,
|
|
3103
|
+
const insideElements = [...controlInsideElements, rootAncestorComboboxDomReference, resolveRef(previousFocusableElement), resolveRef(nextFocusableElement), isUntrappedTypeableCombobox ? domReference : null].filter(x => x != null);
|
|
2484
3104
|
const ariaHiddenCleanup = markOthers(insideElements, {
|
|
2485
3105
|
ariaHidden: modal || isUntrappedTypeableCombobox,
|
|
2486
3106
|
mark: false
|
|
@@ -2494,12 +3114,12 @@ function FloatingFocusManager(props) {
|
|
|
2494
3114
|
}, [open, disabled, domReference, floating, modal, portalContext, isUntrappedTypeableCombobox, tree, getNodeId, nextFocusableElement, previousFocusableElement, getResolvedInsideElements]);
|
|
2495
3115
|
|
|
2496
3116
|
// Focus the initial element when the floating element opens.
|
|
2497
|
-
|
|
2498
|
-
if (!open || disabled || !
|
|
3117
|
+
useIsoLayoutEffect(() => {
|
|
3118
|
+
if (!open || disabled || !floatingUi_utils.isHTMLElement(floatingFocusElement)) {
|
|
2499
3119
|
return;
|
|
2500
3120
|
}
|
|
2501
|
-
const doc =
|
|
2502
|
-
const previouslyFocusedElement =
|
|
3121
|
+
const doc = ownerDocument(floatingFocusElement);
|
|
3122
|
+
const previouslyFocusedElement = activeElement(doc);
|
|
2503
3123
|
|
|
2504
3124
|
// Wait for any layout effect state setters to execute to set `tabIndex`.
|
|
2505
3125
|
queueMicrotask(() => {
|
|
@@ -2510,7 +3130,7 @@ function FloatingFocusManager(props) {
|
|
|
2510
3130
|
if (resolvedInitialFocus === undefined || resolvedInitialFocus === false) {
|
|
2511
3131
|
return;
|
|
2512
3132
|
}
|
|
2513
|
-
const focusAlreadyInsideFloatingEl =
|
|
3133
|
+
const focusAlreadyInsideFloatingEl = contains(floatingFocusElement, previouslyFocusedElement);
|
|
2514
3134
|
if (focusAlreadyInsideFloatingEl) {
|
|
2515
3135
|
return;
|
|
2516
3136
|
}
|
|
@@ -2525,10 +3145,10 @@ function FloatingFocusManager(props) {
|
|
|
2525
3145
|
if (resolvedInitialFocus === true || resolvedInitialFocus === null) {
|
|
2526
3146
|
elToFocus = getDefaultFocusElement();
|
|
2527
3147
|
} else {
|
|
2528
|
-
elToFocus =
|
|
3148
|
+
elToFocus = resolveRef(resolvedInitialFocus);
|
|
2529
3149
|
}
|
|
2530
3150
|
elToFocus = elToFocus || getDefaultFocusElement();
|
|
2531
|
-
const hadFocusInside =
|
|
3151
|
+
const hadFocusInside = contains(floatingFocusElement, activeElement(doc));
|
|
2532
3152
|
enqueueFocus(elToFocus, {
|
|
2533
3153
|
preventScroll: elToFocus === floatingFocusElement,
|
|
2534
3154
|
shouldFocus() {
|
|
@@ -2541,8 +3161,8 @@ function FloatingFocusManager(props) {
|
|
|
2541
3161
|
if (hadFocusInside) {
|
|
2542
3162
|
return true;
|
|
2543
3163
|
}
|
|
2544
|
-
const currentActiveElement =
|
|
2545
|
-
const focusMovedInside = currentActiveElement !== elToFocus &&
|
|
3164
|
+
const currentActiveElement = activeElement(doc);
|
|
3165
|
+
const focusMovedInside = currentActiveElement !== elToFocus && contains(floatingFocusElement, currentActiveElement);
|
|
2546
3166
|
return !focusMovedInside;
|
|
2547
3167
|
}
|
|
2548
3168
|
});
|
|
@@ -2550,12 +3170,12 @@ function FloatingFocusManager(props) {
|
|
|
2550
3170
|
}, [disabled, open, floatingFocusElement, getTabbableContent, initialFocusRef, openInteractionTypeRef, openRef]);
|
|
2551
3171
|
|
|
2552
3172
|
// Track return focus targets and restore focus on unmount/close.
|
|
2553
|
-
|
|
3173
|
+
useIsoLayoutEffect(() => {
|
|
2554
3174
|
if (disabled || !floatingFocusElement) {
|
|
2555
3175
|
return undefined;
|
|
2556
3176
|
}
|
|
2557
|
-
const doc =
|
|
2558
|
-
const elementFocusedBeforeOpen =
|
|
3177
|
+
const doc = ownerDocument(floatingFocusElement);
|
|
3178
|
+
const elementFocusedBeforeOpen = activeElement(doc);
|
|
2559
3179
|
// Only nullish interaction types represent programmatic opens. The empty
|
|
2560
3180
|
// string default is intentionally not treated as programmatic.
|
|
2561
3181
|
const preferPreviousFocus = openInteractionTypeRef.current == null;
|
|
@@ -2567,19 +3187,19 @@ function FloatingFocusManager(props) {
|
|
|
2567
3187
|
if (!details.open) {
|
|
2568
3188
|
closeTypeRef.current = getEventType(details.nativeEvent, lastInteractionTypeRef.current);
|
|
2569
3189
|
}
|
|
2570
|
-
if (details.reason ===
|
|
3190
|
+
if (details.reason === triggerHover && details.nativeEvent.type === 'mouseleave') {
|
|
2571
3191
|
preventReturnFocusRef.current = true;
|
|
2572
3192
|
}
|
|
2573
|
-
if (details.reason !==
|
|
3193
|
+
if (details.reason !== outsidePress) {
|
|
2574
3194
|
return;
|
|
2575
3195
|
}
|
|
2576
3196
|
if (details.nested) {
|
|
2577
3197
|
preventReturnFocusRef.current = false;
|
|
2578
|
-
} else if (
|
|
3198
|
+
} else if (isVirtualClick(details.nativeEvent) || isVirtualPointerEvent(details.nativeEvent)) {
|
|
2579
3199
|
preventReturnFocusRef.current = false;
|
|
2580
3200
|
} else {
|
|
2581
3201
|
let isPreventScrollSupported = false;
|
|
2582
|
-
|
|
3202
|
+
ownerDocument(floatingFocusElement).createElement('div').focus({
|
|
2583
3203
|
get preventScroll() {
|
|
2584
3204
|
isPreventScrollSupported = true;
|
|
2585
3205
|
return false;
|
|
@@ -2605,7 +3225,7 @@ function FloatingFocusManager(props) {
|
|
|
2605
3225
|
resolvedReturnFocusValue = true;
|
|
2606
3226
|
}
|
|
2607
3227
|
const referenceReturnElement = domReference?.isConnected ? domReference : null;
|
|
2608
|
-
const previousReturnElement = elementFocusedBeforeOpen?.isConnected &&
|
|
3228
|
+
const previousReturnElement = elementFocusedBeforeOpen?.isConnected && floatingUi_utils.getNodeName(elementFocusedBeforeOpen) !== 'body' ? elementFocusedBeforeOpen : null;
|
|
2609
3229
|
let defaultReturnElement = preferPreviousFocus ? previousReturnElement || referenceReturnElement : referenceReturnElement || previousReturnElement;
|
|
2610
3230
|
if (!defaultReturnElement) {
|
|
2611
3231
|
defaultReturnElement = getPreviouslyFocusedElement() || null;
|
|
@@ -2613,13 +3233,13 @@ function FloatingFocusManager(props) {
|
|
|
2613
3233
|
if (typeof resolvedReturnFocusValue === 'boolean') {
|
|
2614
3234
|
return defaultReturnElement;
|
|
2615
3235
|
}
|
|
2616
|
-
return
|
|
3236
|
+
return resolveRef(resolvedReturnFocusValue) || defaultReturnElement || null;
|
|
2617
3237
|
}
|
|
2618
3238
|
return () => {
|
|
2619
3239
|
events.off('openchange', onOpenChangeLocal);
|
|
2620
|
-
const activeEl =
|
|
3240
|
+
const activeEl = activeElement(doc);
|
|
2621
3241
|
const insideElements = getResolvedInsideElements();
|
|
2622
|
-
const isFocusInsideFloatingTree =
|
|
3242
|
+
const isFocusInsideFloatingTree = contains(floating, activeEl) || insideElements.some(element => element === activeEl || contains(element, activeEl)) || tree && getNodeChildren(tree.nodesRef.current, getNodeId(), false).some(node => contains(node.context?.elements.floating, activeEl));
|
|
2623
3243
|
|
|
2624
3244
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2625
3245
|
const returnFocusValueOrFn = returnFocusRef.current;
|
|
@@ -2628,7 +3248,7 @@ function FloatingFocusManager(props) {
|
|
|
2628
3248
|
// This is `returnElement`, if it's tabbable, or its first tabbable child.
|
|
2629
3249
|
const tabbableReturnElement = getFirstTabbableElement(returnElement);
|
|
2630
3250
|
const hasExplicitReturnFocus = typeof returnFocusValueOrFn !== 'boolean';
|
|
2631
|
-
if (returnFocusValueOrFn && !preventReturnFocusRef.current &&
|
|
3251
|
+
if (returnFocusValueOrFn && !preventReturnFocusRef.current && floatingUi_utils.isHTMLElement(tabbableReturnElement) && (
|
|
2632
3252
|
// If the focus moved somewhere else after mount, avoid returning focus
|
|
2633
3253
|
// since it likely entered a different element which should be
|
|
2634
3254
|
// respected: https://github.com/floating-ui/floating-ui/issues/2607
|
|
@@ -2645,22 +3265,22 @@ function FloatingFocusManager(props) {
|
|
|
2645
3265
|
// Safari may randomly scroll to the bottom of the page if an input inside a popup has focus
|
|
2646
3266
|
// when the popup unmounts from the DOM.
|
|
2647
3267
|
// By blurring it before the popup unmounts, we can prevent this behavior.
|
|
2648
|
-
|
|
3268
|
+
useIsoLayoutEffect(() => {
|
|
2649
3269
|
if (!webkit || open || !floating) {
|
|
2650
3270
|
return;
|
|
2651
3271
|
}
|
|
2652
|
-
const activeEl =
|
|
2653
|
-
if (!
|
|
3272
|
+
const activeEl = activeElement(ownerDocument(floating));
|
|
3273
|
+
if (!floatingUi_utils.isHTMLElement(activeEl) || !isTypeableElement(activeEl)) {
|
|
2654
3274
|
return;
|
|
2655
3275
|
}
|
|
2656
|
-
if (
|
|
3276
|
+
if (contains(floating, activeEl)) {
|
|
2657
3277
|
activeEl.blur();
|
|
2658
3278
|
}
|
|
2659
3279
|
}, [open, floating]);
|
|
2660
3280
|
|
|
2661
3281
|
// Synchronize the `context` & `modal` value to the FloatingPortal context.
|
|
2662
3282
|
// It will decide whether or not it needs to render its own guards.
|
|
2663
|
-
|
|
3283
|
+
useIsoLayoutEffect(() => {
|
|
2664
3284
|
if (disabled || !portalContext) {
|
|
2665
3285
|
return undefined;
|
|
2666
3286
|
}
|
|
@@ -2677,7 +3297,7 @@ function FloatingFocusManager(props) {
|
|
|
2677
3297
|
}, [disabled, portalContext, modal, open, store, closeOnFocusOut, domReference]);
|
|
2678
3298
|
|
|
2679
3299
|
// Keep the floating element tabIndex in sync and clear stale focus records.
|
|
2680
|
-
|
|
3300
|
+
useIsoLayoutEffect(() => {
|
|
2681
3301
|
if (disabled || !floatingFocusElement) {
|
|
2682
3302
|
return undefined;
|
|
2683
3303
|
}
|
|
@@ -2701,7 +3321,7 @@ function FloatingFocusManager(props) {
|
|
|
2701
3321
|
const nextTabbable = getNextTabbable(domReference);
|
|
2702
3322
|
nextTabbable?.focus();
|
|
2703
3323
|
} else {
|
|
2704
|
-
|
|
3324
|
+
resolveRef(previousFocusableElement ?? portalContext.beforeOutsideRef)?.focus();
|
|
2705
3325
|
}
|
|
2706
3326
|
}
|
|
2707
3327
|
}
|
|
@@ -2719,7 +3339,7 @@ function FloatingFocusManager(props) {
|
|
|
2719
3339
|
const prevTabbable = getPreviousTabbable(domReference);
|
|
2720
3340
|
prevTabbable?.focus();
|
|
2721
3341
|
} else {
|
|
2722
|
-
|
|
3342
|
+
resolveRef(nextFocusableElement ?? portalContext.afterOutsideRef)?.focus();
|
|
2723
3343
|
}
|
|
2724
3344
|
}
|
|
2725
3345
|
}
|
|
@@ -2739,16 +3359,16 @@ function useClick(context, props = {}) {
|
|
|
2739
3359
|
ignoreMouse = false,
|
|
2740
3360
|
stickIfOpen = true,
|
|
2741
3361
|
touchOpenDelay = 0,
|
|
2742
|
-
reason =
|
|
3362
|
+
reason = triggerPress
|
|
2743
3363
|
} = props;
|
|
2744
3364
|
const store = 'rootStore' in context ? context.rootStore : context;
|
|
2745
3365
|
const dataRef = store.context.dataRef;
|
|
2746
3366
|
const pointerTypeRef = React__namespace.useRef(undefined);
|
|
2747
|
-
const frame =
|
|
2748
|
-
const touchOpenTimeout =
|
|
3367
|
+
const frame = useAnimationFrame();
|
|
3368
|
+
const touchOpenTimeout = useTimeout();
|
|
2749
3369
|
const reference = React__namespace.useMemo(() => {
|
|
2750
3370
|
function setOpenWithTouchDelay(nextOpen, nativeEvent, target, pointerType) {
|
|
2751
|
-
const details =
|
|
3371
|
+
const details = createChangeEventDetails(reason, nativeEvent, target);
|
|
2752
3372
|
if (nextOpen && pointerType === 'touch' && touchOpenDelay > 0) {
|
|
2753
3373
|
touchOpenTimeout.start(touchOpenDelay, () => {
|
|
2754
3374
|
store.setOpen(true, details);
|
|
@@ -2791,14 +3411,14 @@ function useClick(context, props = {}) {
|
|
|
2791
3411
|
|
|
2792
3412
|
// Ignore all buttons except for the "main" button.
|
|
2793
3413
|
// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button
|
|
2794
|
-
if (event.button !== 0 || eventOption === 'click' ||
|
|
3414
|
+
if (event.button !== 0 || eventOption === 'click' || isMouseLikePointerType(pointerType, true) && ignoreMouse) {
|
|
2795
3415
|
return;
|
|
2796
3416
|
}
|
|
2797
3417
|
const nextOpen = getNextOpen(open, event.currentTarget, openEventType => openEventType === 'click' || openEventType === 'mousedown');
|
|
2798
3418
|
|
|
2799
3419
|
// Animations sometimes won't run on a typeable element if using a rAF.
|
|
2800
3420
|
// Focus is always set on these elements. For touch, we may delay opening.
|
|
2801
|
-
const target =
|
|
3421
|
+
const target = getTarget(nativeEvent);
|
|
2802
3422
|
if (isTypeableElement(target)) {
|
|
2803
3423
|
setOpenWithTouchDelay(nextOpen, nativeEvent, target, pointerType);
|
|
2804
3424
|
return;
|
|
@@ -2823,7 +3443,7 @@ function useClick(context, props = {}) {
|
|
|
2823
3443
|
pointerTypeRef.current = undefined;
|
|
2824
3444
|
return;
|
|
2825
3445
|
}
|
|
2826
|
-
if (
|
|
3446
|
+
if (isMouseLikePointerType(pointerType, true) && ignoreMouse) {
|
|
2827
3447
|
return;
|
|
2828
3448
|
}
|
|
2829
3449
|
const open = store.select('open');
|
|
@@ -2857,7 +3477,7 @@ function normalizeProp(normalizable) {
|
|
|
2857
3477
|
function useDismiss(context, props = {}) {
|
|
2858
3478
|
const {
|
|
2859
3479
|
enabled = true,
|
|
2860
|
-
escapeKey = true,
|
|
3480
|
+
escapeKey: escapeKey$1 = true,
|
|
2861
3481
|
outsidePress: outsidePressProp = true,
|
|
2862
3482
|
outsidePressEvent = 'sloppy',
|
|
2863
3483
|
referencePress = alwaysFalse,
|
|
@@ -2871,10 +3491,10 @@ function useDismiss(context, props = {}) {
|
|
|
2871
3491
|
dataRef
|
|
2872
3492
|
} = store.context;
|
|
2873
3493
|
const tree = useFloatingTree(externalTree);
|
|
2874
|
-
const outsidePressFn =
|
|
2875
|
-
const outsidePress = typeof outsidePressProp === 'function' ? outsidePressFn : outsidePressProp;
|
|
2876
|
-
const outsidePressEnabled = outsidePress !== false;
|
|
2877
|
-
const getOutsidePressEventProp =
|
|
3494
|
+
const outsidePressFn = useStableCallback(typeof outsidePressProp === 'function' ? outsidePressProp : () => false);
|
|
3495
|
+
const outsidePress$1 = typeof outsidePressProp === 'function' ? outsidePressFn : outsidePressProp;
|
|
3496
|
+
const outsidePressEnabled = outsidePress$1 !== false;
|
|
3497
|
+
const getOutsidePressEventProp = useStableCallback(() => outsidePressEvent);
|
|
2878
3498
|
const {
|
|
2879
3499
|
escapeKey: escapeKeyBubbles,
|
|
2880
3500
|
outsidePress: outsidePressBubbles
|
|
@@ -2886,28 +3506,28 @@ function useDismiss(context, props = {}) {
|
|
|
2886
3506
|
const isComposingRef = React__namespace.useRef(false);
|
|
2887
3507
|
const currentPointerTypeRef = React__namespace.useRef('');
|
|
2888
3508
|
const touchStateRef = React__namespace.useRef(null);
|
|
2889
|
-
const cancelDismissOnEndTimeout =
|
|
2890
|
-
const clearInsideReactTreeTimeout =
|
|
2891
|
-
const clearInsideReactTree =
|
|
3509
|
+
const cancelDismissOnEndTimeout = useTimeout();
|
|
3510
|
+
const clearInsideReactTreeTimeout = useTimeout();
|
|
3511
|
+
const clearInsideReactTree = useStableCallback(() => {
|
|
2892
3512
|
clearInsideReactTreeTimeout.clear();
|
|
2893
3513
|
dataRef.current.insideReactTree = false;
|
|
2894
3514
|
});
|
|
2895
|
-
const hasBlockingChild =
|
|
3515
|
+
const hasBlockingChild = useStableCallback(bubbleKey => {
|
|
2896
3516
|
const nodeId = dataRef.current.floatingContext?.nodeId;
|
|
2897
3517
|
const children = tree ? getNodeChildren(tree.nodesRef.current, nodeId) : [];
|
|
2898
3518
|
return children.some(child => child.context?.open && !child.context.dataRef.current[bubbleKey]);
|
|
2899
3519
|
});
|
|
2900
|
-
const isEventWithinOwnElements =
|
|
3520
|
+
const isEventWithinOwnElements = useStableCallback(event => {
|
|
2901
3521
|
return isEventTargetWithin(event, store.select('floatingElement')) || isEventTargetWithin(event, store.select('domReferenceElement'));
|
|
2902
3522
|
});
|
|
2903
|
-
const closeOnReferencePress =
|
|
3523
|
+
const closeOnReferencePress = useStableCallback(event => {
|
|
2904
3524
|
if (!referencePress()) {
|
|
2905
3525
|
return;
|
|
2906
3526
|
}
|
|
2907
|
-
store.setOpen(false,
|
|
3527
|
+
store.setOpen(false, createChangeEventDetails(triggerPress, event.nativeEvent));
|
|
2908
3528
|
});
|
|
2909
|
-
const closeOnEscapeKeyDown =
|
|
2910
|
-
if (!open || !enabled || !escapeKey || event.key !== 'Escape') {
|
|
3529
|
+
const closeOnEscapeKeyDown = useStableCallback(event => {
|
|
3530
|
+
if (!open || !enabled || !escapeKey$1 || event.key !== 'Escape') {
|
|
2911
3531
|
return;
|
|
2912
3532
|
}
|
|
2913
3533
|
|
|
@@ -2919,8 +3539,8 @@ function useDismiss(context, props = {}) {
|
|
|
2919
3539
|
if (!escapeKeyBubbles && hasBlockingChild('__escapeKeyBubbles')) {
|
|
2920
3540
|
return;
|
|
2921
3541
|
}
|
|
2922
|
-
const native =
|
|
2923
|
-
const eventDetails =
|
|
3542
|
+
const native = isReactEvent(event) ? event.nativeEvent : event;
|
|
3543
|
+
const eventDetails = createChangeEventDetails(escapeKey, native);
|
|
2924
3544
|
store.setOpen(false, eventDetails);
|
|
2925
3545
|
if (!eventDetails.isCanceled) {
|
|
2926
3546
|
event.preventDefault();
|
|
@@ -2929,19 +3549,19 @@ function useDismiss(context, props = {}) {
|
|
|
2929
3549
|
event.stopPropagation();
|
|
2930
3550
|
}
|
|
2931
3551
|
});
|
|
2932
|
-
const markInsideReactTree =
|
|
3552
|
+
const markInsideReactTree = useStableCallback(() => {
|
|
2933
3553
|
dataRef.current.insideReactTree = true;
|
|
2934
3554
|
clearInsideReactTreeTimeout.start(0, clearInsideReactTree);
|
|
2935
3555
|
});
|
|
2936
|
-
const markPressStartedInsideReactTree =
|
|
3556
|
+
const markPressStartedInsideReactTree = useStableCallback(event => {
|
|
2937
3557
|
if (!open || !enabled || event.button !== 0) {
|
|
2938
3558
|
return;
|
|
2939
3559
|
}
|
|
2940
|
-
const target =
|
|
3560
|
+
const target = getTarget(event.nativeEvent);
|
|
2941
3561
|
|
|
2942
3562
|
// Only treat presses that start within the floating DOM subtree as inside.
|
|
2943
3563
|
// This avoids suppressing parent dismissal when interacting with nested portals.
|
|
2944
|
-
if (!
|
|
3564
|
+
if (!contains(store.select('floatingElement'), target)) {
|
|
2945
3565
|
return;
|
|
2946
3566
|
}
|
|
2947
3567
|
if (!pressStartedInsideRef.current) {
|
|
@@ -2949,7 +3569,7 @@ function useDismiss(context, props = {}) {
|
|
|
2949
3569
|
pressStartPreventedRef.current = false;
|
|
2950
3570
|
}
|
|
2951
3571
|
});
|
|
2952
|
-
const markInsidePressStartPrevented =
|
|
3572
|
+
const markInsidePressStartPrevented = useStableCallback(event => {
|
|
2953
3573
|
if (!open || !enabled) {
|
|
2954
3574
|
return;
|
|
2955
3575
|
}
|
|
@@ -2966,8 +3586,8 @@ function useDismiss(context, props = {}) {
|
|
|
2966
3586
|
}
|
|
2967
3587
|
dataRef.current.__escapeKeyBubbles = escapeKeyBubbles;
|
|
2968
3588
|
dataRef.current.__outsidePressBubbles = outsidePressBubbles;
|
|
2969
|
-
const compositionTimeout = new
|
|
2970
|
-
const preventedPressSuppressionTimeout = new
|
|
3589
|
+
const compositionTimeout = new Timeout();
|
|
3590
|
+
const preventedPressSuppressionTimeout = new Timeout();
|
|
2971
3591
|
function handleCompositionStart() {
|
|
2972
3592
|
compositionTimeout.clear();
|
|
2973
3593
|
isComposingRef.current = true;
|
|
@@ -3029,20 +3649,20 @@ function useDismiss(context, props = {}) {
|
|
|
3029
3649
|
clearInsideReactTree();
|
|
3030
3650
|
return;
|
|
3031
3651
|
}
|
|
3032
|
-
const target =
|
|
3652
|
+
const target = getTarget(event);
|
|
3033
3653
|
const inertSelector = `[${createAttribute('inert')}]`;
|
|
3034
|
-
const targetRoot =
|
|
3035
|
-
const markers = Array.from((
|
|
3654
|
+
const targetRoot = floatingUi_utils.isElement(target) ? target.getRootNode() : null;
|
|
3655
|
+
const markers = Array.from((floatingUi_utils.isShadowRoot(targetRoot) ? targetRoot : ownerDocument(store.select('floatingElement'))).querySelectorAll(inertSelector));
|
|
3036
3656
|
const triggers = store.context.triggerElements;
|
|
3037
3657
|
|
|
3038
3658
|
// If another trigger is clicked, don't close the floating element.
|
|
3039
|
-
if (target && (triggers.hasElement(target) || triggers.hasMatchingElement(trigger =>
|
|
3659
|
+
if (target && (triggers.hasElement(target) || triggers.hasMatchingElement(trigger => contains(trigger, target)))) {
|
|
3040
3660
|
return;
|
|
3041
3661
|
}
|
|
3042
|
-
let targetRootAncestor =
|
|
3043
|
-
while (targetRootAncestor && !
|
|
3044
|
-
const nextParent =
|
|
3045
|
-
if (
|
|
3662
|
+
let targetRootAncestor = floatingUi_utils.isElement(target) ? target : null;
|
|
3663
|
+
while (targetRootAncestor && !floatingUi_utils.isLastTraversableNode(targetRootAncestor)) {
|
|
3664
|
+
const nextParent = floatingUi_utils.getParentNode(targetRootAncestor);
|
|
3665
|
+
if (floatingUi_utils.isLastTraversableNode(nextParent) || !floatingUi_utils.isElement(nextParent)) {
|
|
3046
3666
|
break;
|
|
3047
3667
|
}
|
|
3048
3668
|
targetRootAncestor = nextParent;
|
|
@@ -3050,20 +3670,20 @@ function useDismiss(context, props = {}) {
|
|
|
3050
3670
|
|
|
3051
3671
|
// Check if the click occurred on a third-party element injected after the
|
|
3052
3672
|
// floating element rendered.
|
|
3053
|
-
if (markers.length &&
|
|
3673
|
+
if (markers.length && floatingUi_utils.isElement(target) && !isRootElement(target) &&
|
|
3054
3674
|
// Clicked on a direct ancestor (e.g. FloatingOverlay).
|
|
3055
|
-
!
|
|
3675
|
+
!contains(target, store.select('floatingElement')) &&
|
|
3056
3676
|
// If the target root element contains none of the markers, then the
|
|
3057
3677
|
// element was injected after the floating element rendered.
|
|
3058
|
-
markers.every(marker => !
|
|
3678
|
+
markers.every(marker => !contains(targetRootAncestor, marker))) {
|
|
3059
3679
|
return;
|
|
3060
3680
|
}
|
|
3061
3681
|
|
|
3062
3682
|
// Check if the click occurred on the scrollbar
|
|
3063
3683
|
// Skip for touch events: scrollbars don't receive touch events on most platforms
|
|
3064
|
-
if (
|
|
3065
|
-
const lastTraversableNode =
|
|
3066
|
-
const style =
|
|
3684
|
+
if (floatingUi_utils.isHTMLElement(target) && !('touches' in event)) {
|
|
3685
|
+
const lastTraversableNode = floatingUi_utils.isLastTraversableNode(target);
|
|
3686
|
+
const style = floatingUi_utils.getComputedStyle(target);
|
|
3067
3687
|
const scrollRe = /auto|scroll/;
|
|
3068
3688
|
const isScrollableX = lastTraversableNode || scrollRe.test(style.overflowX);
|
|
3069
3689
|
const isScrollableY = lastTraversableNode || scrollRe.test(style.overflowY);
|
|
@@ -3094,13 +3714,13 @@ function useDismiss(context, props = {}) {
|
|
|
3094
3714
|
suppressNextOutsideClickRef.current = false;
|
|
3095
3715
|
return;
|
|
3096
3716
|
}
|
|
3097
|
-
if (typeof outsidePress === 'function' && !outsidePress(event)) {
|
|
3717
|
+
if (typeof outsidePress$1 === 'function' && !outsidePress$1(event)) {
|
|
3098
3718
|
return;
|
|
3099
3719
|
}
|
|
3100
3720
|
if (hasBlockingChild('__outsidePressBubbles')) {
|
|
3101
3721
|
return;
|
|
3102
3722
|
}
|
|
3103
|
-
store.setOpen(false,
|
|
3723
|
+
store.setOpen(false, createChangeEventDetails(outsidePress, event));
|
|
3104
3724
|
clearInsideReactTree();
|
|
3105
3725
|
}
|
|
3106
3726
|
function handlePointerDown(event) {
|
|
@@ -3131,11 +3751,11 @@ function useDismiss(context, props = {}) {
|
|
|
3131
3751
|
}
|
|
3132
3752
|
}
|
|
3133
3753
|
function addTargetEventListenerOnce(event, listener) {
|
|
3134
|
-
const target =
|
|
3754
|
+
const target = getTarget(event);
|
|
3135
3755
|
if (!target) {
|
|
3136
3756
|
return;
|
|
3137
3757
|
}
|
|
3138
|
-
const unsubscribe =
|
|
3758
|
+
const unsubscribe = addEventListener(target, event.type, () => {
|
|
3139
3759
|
listener(event);
|
|
3140
3760
|
unsubscribe();
|
|
3141
3761
|
});
|
|
@@ -3189,7 +3809,7 @@ function useDismiss(context, props = {}) {
|
|
|
3189
3809
|
}
|
|
3190
3810
|
|
|
3191
3811
|
// Avoid suppressing when outsidePress explicitly ignores this target.
|
|
3192
|
-
if (typeof outsidePress === 'function' && !outsidePress(event)) {
|
|
3812
|
+
if (typeof outsidePress$1 === 'function' && !outsidePress$1(event)) {
|
|
3193
3813
|
return;
|
|
3194
3814
|
}
|
|
3195
3815
|
preventedPressSuppressionTimeout.clear();
|
|
@@ -3232,8 +3852,8 @@ function useDismiss(context, props = {}) {
|
|
|
3232
3852
|
function handleTouchEndCapture(event) {
|
|
3233
3853
|
addTargetEventListenerOnce(event, handleTouchEnd);
|
|
3234
3854
|
}
|
|
3235
|
-
const doc =
|
|
3236
|
-
const unsubscribe = mergeCleanups(escapeKey && mergeCleanups(
|
|
3855
|
+
const doc = ownerDocument(floatingElement);
|
|
3856
|
+
const unsubscribe = mergeCleanups(escapeKey$1 && mergeCleanups(addEventListener(doc, 'keydown', closeOnEscapeKeyDown), addEventListener(doc, 'compositionstart', handleCompositionStart), addEventListener(doc, 'compositionend', handleCompositionEnd)), outsidePressEnabled && mergeCleanups(addEventListener(doc, 'click', closeOnPressOutsideCapture, true), addEventListener(doc, 'pointerdown', closeOnPressOutsideCapture, true), addEventListener(doc, 'pointerup', handlePressEndCapture, true), addEventListener(doc, 'pointercancel', handlePressEndCapture, true), addEventListener(doc, 'mousedown', closeOnPressOutsideCapture, true), addEventListener(doc, 'mouseup', handlePressEndCapture, true), addEventListener(doc, 'touchstart', handleTouchStartCapture, true), addEventListener(doc, 'touchmove', handleTouchMoveCapture, true), addEventListener(doc, 'touchend', handleTouchEndCapture, true)));
|
|
3237
3857
|
return () => {
|
|
3238
3858
|
unsubscribe();
|
|
3239
3859
|
compositionTimeout.clear();
|
|
@@ -3241,8 +3861,8 @@ function useDismiss(context, props = {}) {
|
|
|
3241
3861
|
resetPressStartState();
|
|
3242
3862
|
suppressNextOutsideClickRef.current = false;
|
|
3243
3863
|
};
|
|
3244
|
-
}, [dataRef, floatingElement, escapeKey, outsidePressEnabled, outsidePress, open, enabled, escapeKeyBubbles, outsidePressBubbles, closeOnEscapeKeyDown, clearInsideReactTree, getOutsidePressEventProp, hasBlockingChild, isEventWithinOwnElements, tree, store, cancelDismissOnEndTimeout]);
|
|
3245
|
-
React__namespace.useEffect(clearInsideReactTree, [outsidePress, clearInsideReactTree]);
|
|
3864
|
+
}, [dataRef, floatingElement, escapeKey$1, outsidePressEnabled, outsidePress$1, open, enabled, escapeKeyBubbles, outsidePressBubbles, closeOnEscapeKeyDown, clearInsideReactTree, getOutsidePressEventProp, hasBlockingChild, isEventWithinOwnElements, tree, store, cancelDismissOnEndTimeout]);
|
|
3865
|
+
React__namespace.useEffect(clearInsideReactTree, [outsidePress$1, clearInsideReactTree]);
|
|
3246
3866
|
const reference = React__namespace.useMemo(() => ({
|
|
3247
3867
|
onKeyDown: closeOnEscapeKeyDown,
|
|
3248
3868
|
onPointerDown: closeOnReferencePress,
|
|
@@ -3315,7 +3935,7 @@ class FloatingRootStore extends ReactStore {
|
|
|
3315
3935
|
if (!newOpen || !this.state.open ||
|
|
3316
3936
|
// Prevent a pending hover-open from overwriting a click-open event, while allowing
|
|
3317
3937
|
// click events to upgrade a hover-open.
|
|
3318
|
-
event != null &&
|
|
3938
|
+
event != null && isClickLikeEvent(event)) {
|
|
3319
3939
|
this.context.dataRef.current.openEvent = newOpen ? event : undefined;
|
|
3320
3940
|
}
|
|
3321
3941
|
};
|
|
@@ -3385,14 +4005,14 @@ function useSyncedFloatingRootContext(options) {
|
|
|
3385
4005
|
}
|
|
3386
4006
|
const store = floatingRootContextProp ?? internalStoreRef.current;
|
|
3387
4007
|
popupStore.useSyncedValue('floatingId', floatingId);
|
|
3388
|
-
|
|
4008
|
+
useIsoLayoutEffect(() => {
|
|
3389
4009
|
const valuesToSync = {
|
|
3390
4010
|
open,
|
|
3391
4011
|
floatingId,
|
|
3392
4012
|
referenceElement,
|
|
3393
4013
|
floatingElement
|
|
3394
4014
|
};
|
|
3395
|
-
if (
|
|
4015
|
+
if (floatingUi_utils.isElement(referenceElement)) {
|
|
3396
4016
|
valuesToSync.domReferenceElement = referenceElement;
|
|
3397
4017
|
}
|
|
3398
4018
|
if (store.state.positionReference === store.state.referenceElement) {
|
|
@@ -3407,6 +4027,204 @@ function useSyncedFloatingRootContext(options) {
|
|
|
3407
4027
|
return store;
|
|
3408
4028
|
}
|
|
3409
4029
|
|
|
4030
|
+
/**
|
|
4031
|
+
* Provides a status string for CSS animations.
|
|
4032
|
+
* @param open - a boolean that determines if the element is open.
|
|
4033
|
+
* @param enableIdleState - a boolean that enables the `'idle'` state between `'starting'` and `'ending'`
|
|
4034
|
+
*/
|
|
4035
|
+
function useTransitionStatus(open, enableIdleState = false, deferEndingState = false) {
|
|
4036
|
+
const [transitionStatus, setTransitionStatus] = React__namespace.useState(open && enableIdleState ? 'idle' : undefined);
|
|
4037
|
+
const [mounted, setMounted] = React__namespace.useState(open);
|
|
4038
|
+
if (open && !mounted) {
|
|
4039
|
+
setMounted(true);
|
|
4040
|
+
setTransitionStatus('starting');
|
|
4041
|
+
}
|
|
4042
|
+
if (!open && mounted && transitionStatus !== 'ending' && !deferEndingState) {
|
|
4043
|
+
setTransitionStatus('ending');
|
|
4044
|
+
}
|
|
4045
|
+
if (!open && !mounted && transitionStatus === 'ending') {
|
|
4046
|
+
setTransitionStatus(undefined);
|
|
4047
|
+
}
|
|
4048
|
+
useIsoLayoutEffect(() => {
|
|
4049
|
+
if (!open && mounted && transitionStatus !== 'ending' && deferEndingState) {
|
|
4050
|
+
const frame = AnimationFrame.request(() => {
|
|
4051
|
+
setTransitionStatus('ending');
|
|
4052
|
+
});
|
|
4053
|
+
return () => {
|
|
4054
|
+
AnimationFrame.cancel(frame);
|
|
4055
|
+
};
|
|
4056
|
+
}
|
|
4057
|
+
return undefined;
|
|
4058
|
+
}, [open, mounted, transitionStatus, deferEndingState]);
|
|
4059
|
+
useIsoLayoutEffect(() => {
|
|
4060
|
+
if (!open || enableIdleState) {
|
|
4061
|
+
return undefined;
|
|
4062
|
+
}
|
|
4063
|
+
const frame = AnimationFrame.request(() => {
|
|
4064
|
+
// Avoid `flushSync` here due to Firefox.
|
|
4065
|
+
// See https://github.com/mui/base-ui/pull/3424
|
|
4066
|
+
setTransitionStatus(undefined);
|
|
4067
|
+
});
|
|
4068
|
+
return () => {
|
|
4069
|
+
AnimationFrame.cancel(frame);
|
|
4070
|
+
};
|
|
4071
|
+
}, [enableIdleState, open]);
|
|
4072
|
+
useIsoLayoutEffect(() => {
|
|
4073
|
+
if (!open || !enableIdleState) {
|
|
4074
|
+
return undefined;
|
|
4075
|
+
}
|
|
4076
|
+
if (open && mounted && transitionStatus !== 'idle') {
|
|
4077
|
+
setTransitionStatus('starting');
|
|
4078
|
+
}
|
|
4079
|
+
const frame = AnimationFrame.request(() => {
|
|
4080
|
+
setTransitionStatus('idle');
|
|
4081
|
+
});
|
|
4082
|
+
return () => {
|
|
4083
|
+
AnimationFrame.cancel(frame);
|
|
4084
|
+
};
|
|
4085
|
+
}, [enableIdleState, open, mounted, transitionStatus]);
|
|
4086
|
+
return {
|
|
4087
|
+
mounted,
|
|
4088
|
+
setMounted,
|
|
4089
|
+
transitionStatus
|
|
4090
|
+
};
|
|
4091
|
+
}
|
|
4092
|
+
|
|
4093
|
+
let TransitionStatusDataAttributes = /*#__PURE__*/function (TransitionStatusDataAttributes) {
|
|
4094
|
+
/**
|
|
4095
|
+
* Present when the component is animating in.
|
|
4096
|
+
*/
|
|
4097
|
+
TransitionStatusDataAttributes["startingStyle"] = "data-starting-style";
|
|
4098
|
+
/**
|
|
4099
|
+
* Present when the component is animating out.
|
|
4100
|
+
*/
|
|
4101
|
+
TransitionStatusDataAttributes["endingStyle"] = "data-ending-style";
|
|
4102
|
+
return TransitionStatusDataAttributes;
|
|
4103
|
+
}({});
|
|
4104
|
+
const STARTING_HOOK = {
|
|
4105
|
+
[TransitionStatusDataAttributes.startingStyle]: ''
|
|
4106
|
+
};
|
|
4107
|
+
const ENDING_HOOK = {
|
|
4108
|
+
[TransitionStatusDataAttributes.endingStyle]: ''
|
|
4109
|
+
};
|
|
4110
|
+
const transitionStatusMapping = {
|
|
4111
|
+
transitionStatus(value) {
|
|
4112
|
+
if (value === 'starting') {
|
|
4113
|
+
return STARTING_HOOK;
|
|
4114
|
+
}
|
|
4115
|
+
if (value === 'ending') {
|
|
4116
|
+
return ENDING_HOOK;
|
|
4117
|
+
}
|
|
4118
|
+
return null;
|
|
4119
|
+
}
|
|
4120
|
+
};
|
|
4121
|
+
|
|
4122
|
+
/**
|
|
4123
|
+
* Executes a function once all animations have finished on the provided element.
|
|
4124
|
+
* @param elementOrRef - The element to watch for animations.
|
|
4125
|
+
* @param waitForStartingStyleRemoved - Whether to wait for [data-starting-style] to be removed before checking for animations.
|
|
4126
|
+
* @param treatAbortedAsFinished - Whether to treat aborted animations as finished. If `false`, and there are aborted animations,
|
|
4127
|
+
* the function will check again if any new animations have started and wait for them to finish.
|
|
4128
|
+
* @returns A function that takes a callback to execute once all animations have finished, and an optional AbortSignal to abort the callback
|
|
4129
|
+
*/
|
|
4130
|
+
function useAnimationsFinished(elementOrRef, waitForStartingStyleRemoved = false, treatAbortedAsFinished = true) {
|
|
4131
|
+
const frame = useAnimationFrame();
|
|
4132
|
+
return useStableCallback((fnToExecute,
|
|
4133
|
+
/**
|
|
4134
|
+
* An optional [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) that
|
|
4135
|
+
* can be used to abort `fnToExecute` before all the animations have finished.
|
|
4136
|
+
* @default null
|
|
4137
|
+
*/
|
|
4138
|
+
signal = null) => {
|
|
4139
|
+
frame.cancel();
|
|
4140
|
+
const element = resolveRef(elementOrRef);
|
|
4141
|
+
if (element == null) {
|
|
4142
|
+
return;
|
|
4143
|
+
}
|
|
4144
|
+
const resolvedElement = element;
|
|
4145
|
+
const done = () => {
|
|
4146
|
+
// Synchronously flush the unmounting of the component so that the browser doesn't
|
|
4147
|
+
// paint: https://github.com/mui/base-ui/issues/979
|
|
4148
|
+
ReactDOM__namespace.flushSync(fnToExecute);
|
|
4149
|
+
};
|
|
4150
|
+
if (typeof resolvedElement.getAnimations !== 'function' || globalThis.BASE_UI_ANIMATIONS_DISABLED) {
|
|
4151
|
+
fnToExecute();
|
|
4152
|
+
return;
|
|
4153
|
+
}
|
|
4154
|
+
function exec() {
|
|
4155
|
+
Promise.all(resolvedElement.getAnimations().map(animation => animation.finished)).then(() => {
|
|
4156
|
+
if (!signal?.aborted) {
|
|
4157
|
+
done();
|
|
4158
|
+
}
|
|
4159
|
+
}).catch(() => {
|
|
4160
|
+
if (treatAbortedAsFinished) {
|
|
4161
|
+
if (!signal?.aborted) {
|
|
4162
|
+
done();
|
|
4163
|
+
}
|
|
4164
|
+
return;
|
|
4165
|
+
}
|
|
4166
|
+
const currentAnimations = resolvedElement.getAnimations();
|
|
4167
|
+
if (!signal?.aborted && currentAnimations.length > 0 && currentAnimations.some(animation => animation.pending || animation.playState !== 'finished')) {
|
|
4168
|
+
// Sometimes animations can be aborted because a property they depend on changes while the animation plays.
|
|
4169
|
+
// In such cases, we need to re-check if any new animations have started.
|
|
4170
|
+
exec();
|
|
4171
|
+
}
|
|
4172
|
+
});
|
|
4173
|
+
}
|
|
4174
|
+
if (waitForStartingStyleRemoved) {
|
|
4175
|
+
const startingStyleAttribute = TransitionStatusDataAttributes.startingStyle;
|
|
4176
|
+
|
|
4177
|
+
// If `[data-starting-style]` isn't present, fall back to waiting one more frame
|
|
4178
|
+
// to give "open" animations a chance to be registered.
|
|
4179
|
+
if (!resolvedElement.hasAttribute(startingStyleAttribute)) {
|
|
4180
|
+
frame.request(exec);
|
|
4181
|
+
return;
|
|
4182
|
+
}
|
|
4183
|
+
|
|
4184
|
+
// Wait for `[data-starting-style]` to have been removed.
|
|
4185
|
+
const attributeObserver = new MutationObserver(() => {
|
|
4186
|
+
if (!resolvedElement.hasAttribute(startingStyleAttribute)) {
|
|
4187
|
+
attributeObserver.disconnect();
|
|
4188
|
+
exec();
|
|
4189
|
+
}
|
|
4190
|
+
});
|
|
4191
|
+
attributeObserver.observe(resolvedElement, {
|
|
4192
|
+
attributes: true,
|
|
4193
|
+
attributeFilter: [startingStyleAttribute]
|
|
4194
|
+
});
|
|
4195
|
+
signal?.addEventListener('abort', () => attributeObserver.disconnect(), {
|
|
4196
|
+
once: true
|
|
4197
|
+
});
|
|
4198
|
+
return;
|
|
4199
|
+
}
|
|
4200
|
+
frame.request(exec);
|
|
4201
|
+
});
|
|
4202
|
+
}
|
|
4203
|
+
|
|
4204
|
+
/**
|
|
4205
|
+
* Calls the provided function when the CSS open/close animation or transition completes.
|
|
4206
|
+
*/
|
|
4207
|
+
function useOpenChangeComplete(parameters) {
|
|
4208
|
+
const {
|
|
4209
|
+
enabled = true,
|
|
4210
|
+
open,
|
|
4211
|
+
ref,
|
|
4212
|
+
onComplete: onCompleteParam
|
|
4213
|
+
} = parameters;
|
|
4214
|
+
const onComplete = useStableCallback(onCompleteParam);
|
|
4215
|
+
const runOnceAnimationsFinish = useAnimationsFinished(ref, open, false);
|
|
4216
|
+
React__namespace.useEffect(() => {
|
|
4217
|
+
if (!enabled) {
|
|
4218
|
+
return undefined;
|
|
4219
|
+
}
|
|
4220
|
+
const abortController = new AbortController();
|
|
4221
|
+
runOnceAnimationsFinish(onComplete, abortController.signal);
|
|
4222
|
+
return () => {
|
|
4223
|
+
abortController.abort();
|
|
4224
|
+
};
|
|
4225
|
+
}, [enabled, open, onComplete, runOnceAnimationsFinish]);
|
|
4226
|
+
}
|
|
4227
|
+
|
|
3410
4228
|
const FOCUSABLE_POPUP_PROPS = {
|
|
3411
4229
|
tabIndex: -1,
|
|
3412
4230
|
[FOCUSABLE_ATTRIBUTE]: ''
|
|
@@ -3421,7 +4239,7 @@ function createDefaultInitialFocus(popupRef) {
|
|
|
3421
4239
|
return interactionType => interactionType === 'touch' ? popupRef.current : true;
|
|
3422
4240
|
}
|
|
3423
4241
|
function usePopupStore(externalStore, createStore, treatPopupAsFloatingElement = false) {
|
|
3424
|
-
const floatingId =
|
|
4242
|
+
const floatingId = useId();
|
|
3425
4243
|
const nested = useFloatingParentNodeId() != null;
|
|
3426
4244
|
const internalStoreRef = React__namespace.useRef(null);
|
|
3427
4245
|
if (externalStore === undefined && internalStoreRef.current === null) {
|
|
@@ -3529,7 +4347,7 @@ function useInitialOpenSync(store, openProp, defaultOpen, defaultTriggerId) {
|
|
|
3529
4347
|
function useTriggerDataForwarding(triggerId, triggerElementRef, store, stateUpdates) {
|
|
3530
4348
|
const isMountedByThisTrigger = store.useState('isMountedByTrigger', triggerId);
|
|
3531
4349
|
const baseRegisterTrigger = useTriggerRegistration(triggerId, store);
|
|
3532
|
-
const registerTrigger =
|
|
4350
|
+
const registerTrigger = useStableCallback(element => {
|
|
3533
4351
|
baseRegisterTrigger(element);
|
|
3534
4352
|
if (!element) {
|
|
3535
4353
|
return;
|
|
@@ -3554,7 +4372,7 @@ function useTriggerDataForwarding(triggerId, triggerElementRef, store, stateUpda
|
|
|
3554
4372
|
});
|
|
3555
4373
|
}
|
|
3556
4374
|
});
|
|
3557
|
-
|
|
4375
|
+
useIsoLayoutEffect(() => {
|
|
3558
4376
|
if (isMountedByThisTrigger) {
|
|
3559
4377
|
store.update({
|
|
3560
4378
|
activeTriggerElement: triggerElementRef.current,
|
|
@@ -3591,7 +4409,7 @@ function useImplicitActiveTrigger(store, options = {}) {
|
|
|
3591
4409
|
} = options;
|
|
3592
4410
|
const open = store.useState('open');
|
|
3593
4411
|
const reactiveTriggerCount = store.useState('triggerCount');
|
|
3594
|
-
|
|
4412
|
+
useIsoLayoutEffect(() => {
|
|
3595
4413
|
if (!open) {
|
|
3596
4414
|
if (store.state.triggerCount !== 0) {
|
|
3597
4415
|
store.set('triggerCount', 0);
|
|
@@ -3629,7 +4447,7 @@ function useImplicitActiveTrigger(store, options = {}) {
|
|
|
3629
4447
|
// Defer so a same-tick replacement trigger with the same id can register first.
|
|
3630
4448
|
queueMicrotask(() => {
|
|
3631
4449
|
if (store.select('open') && store.select('activeTriggerId') === lostActiveTriggerId && !store.context.triggerElements.getById(lostActiveTriggerId)) {
|
|
3632
|
-
const eventDetails =
|
|
4450
|
+
const eventDetails = createChangeEventDetails(none);
|
|
3633
4451
|
store.setOpen(false, eventDetails);
|
|
3634
4452
|
// If closing is canceled, keep the previous active trigger ownership for the
|
|
3635
4453
|
// still-open popup instead of claiming another trigger implicitly.
|
|
@@ -3662,7 +4480,7 @@ function useOpenStateTransitions(open, store, onUnmount) {
|
|
|
3662
4480
|
mounted,
|
|
3663
4481
|
setMounted,
|
|
3664
4482
|
transitionStatus
|
|
3665
|
-
} =
|
|
4483
|
+
} = useTransitionStatus(open);
|
|
3666
4484
|
const preventUnmountingOnClose = store.useState('preventUnmountingOnClose');
|
|
3667
4485
|
// Opening starts a new close cycle. Clear during render so the close-completion hook below
|
|
3668
4486
|
// reads the synchronized value on the same pass.
|
|
@@ -3672,7 +4490,7 @@ function useOpenStateTransitions(open, store, onUnmount) {
|
|
|
3672
4490
|
transitionStatus,
|
|
3673
4491
|
preventUnmountingOnClose: syncedPreventUnmountingOnClose
|
|
3674
4492
|
});
|
|
3675
|
-
const forceUnmount =
|
|
4493
|
+
const forceUnmount = useStableCallback(() => {
|
|
3676
4494
|
setMounted(false);
|
|
3677
4495
|
store.update({
|
|
3678
4496
|
activeTriggerId: null,
|
|
@@ -3683,7 +4501,7 @@ function useOpenStateTransitions(open, store, onUnmount) {
|
|
|
3683
4501
|
onUnmount?.();
|
|
3684
4502
|
store.context.onOpenChangeComplete?.(false);
|
|
3685
4503
|
});
|
|
3686
|
-
|
|
4504
|
+
useOpenChangeComplete({
|
|
3687
4505
|
enabled: mounted && !open && !syncedPreventUnmountingOnClose,
|
|
3688
4506
|
open,
|
|
3689
4507
|
ref: store.context.popupRef,
|
|
@@ -3700,7 +4518,7 @@ function useOpenStateTransitions(open, store, onUnmount) {
|
|
|
3700
4518
|
}
|
|
3701
4519
|
function usePopupInteractionProps(store, statePart) {
|
|
3702
4520
|
store.useSyncedValues(statePart);
|
|
3703
|
-
|
|
4521
|
+
useIsoLayoutEffect(() => () => {
|
|
3704
4522
|
store.update({
|
|
3705
4523
|
activeTriggerProps: useRenderElement.EMPTY_OBJECT,
|
|
3706
4524
|
inactiveTriggerProps: useRenderElement.EMPTY_OBJECT,
|
|
@@ -3709,12 +4527,12 @@ function usePopupInteractionProps(store, statePart) {
|
|
|
3709
4527
|
}, [store]);
|
|
3710
4528
|
}
|
|
3711
4529
|
function usePopupRootSync(store, open) {
|
|
3712
|
-
|
|
4530
|
+
useIsoLayoutEffect(() => {
|
|
3713
4531
|
if (!open && store.state.openMethod !== null) {
|
|
3714
4532
|
store.set('openMethod', null);
|
|
3715
4533
|
}
|
|
3716
4534
|
}, [open, store]);
|
|
3717
|
-
|
|
4535
|
+
useIsoLayoutEffect(() => () => {
|
|
3718
4536
|
if (store.state.openMethod !== null) {
|
|
3719
4537
|
store.set('openMethod', null);
|
|
3720
4538
|
}
|
|
@@ -3816,6 +4634,15 @@ class PopupTriggerMap {
|
|
|
3816
4634
|
}
|
|
3817
4635
|
}
|
|
3818
4636
|
|
|
4637
|
+
/**
|
|
4638
|
+
* Wraps `useId` and prefixes generated `id`s with `base-ui-`
|
|
4639
|
+
* @param {string | undefined} idOverride overrides the generated id when provided
|
|
4640
|
+
* @returns {string | undefined}
|
|
4641
|
+
*/
|
|
4642
|
+
function useBaseUiId(idOverride) {
|
|
4643
|
+
return useId(idOverride, 'base-ui');
|
|
4644
|
+
}
|
|
4645
|
+
|
|
3819
4646
|
/**
|
|
3820
4647
|
* Provides a cross-browser way to determine the type of the pointer used to click.
|
|
3821
4648
|
* Safari and Firefox do not provide the PointerEvent to the click handler (they use MouseEvent) yet.
|
|
@@ -3852,15 +4679,29 @@ function useEnhancedClickHandler(handler) {
|
|
|
3852
4679
|
};
|
|
3853
4680
|
}
|
|
3854
4681
|
|
|
4682
|
+
function useValueChanged(value, onChange) {
|
|
4683
|
+
const valueRef = React__namespace.useRef(value);
|
|
4684
|
+
const onChangeCallback = useStableCallback(onChange);
|
|
4685
|
+
useIsoLayoutEffect(() => {
|
|
4686
|
+
if (valueRef.current === value) {
|
|
4687
|
+
return;
|
|
4688
|
+
}
|
|
4689
|
+
onChangeCallback(valueRef.current);
|
|
4690
|
+
}, [value, onChangeCallback]);
|
|
4691
|
+
useIsoLayoutEffect(() => {
|
|
4692
|
+
valueRef.current = value;
|
|
4693
|
+
}, [value]);
|
|
4694
|
+
}
|
|
4695
|
+
|
|
3855
4696
|
function useOpenMethodTriggerProps(open, setOpenMethod) {
|
|
3856
|
-
const handleTriggerClick =
|
|
4697
|
+
const handleTriggerClick = useStableCallback((_, interactionType) => {
|
|
3857
4698
|
const isOpen = typeof open === 'function' ? open() : open;
|
|
3858
4699
|
if (!isOpen) {
|
|
3859
4700
|
setOpenMethod(interactionType || (
|
|
3860
4701
|
// On iOS Safari, the hitslop around touch targets means tapping outside an element's
|
|
3861
4702
|
// bounds does not fire `pointerdown` but does fire `mousedown`. The `interactionType`
|
|
3862
4703
|
// will be "" in that case.
|
|
3863
|
-
|
|
4704
|
+
ios ? 'touch' : ''));
|
|
3864
4705
|
}
|
|
3865
4706
|
});
|
|
3866
4707
|
const {
|
|
@@ -3881,7 +4722,7 @@ function useOpenMethodTriggerProps(open, setOpenMethod) {
|
|
|
3881
4722
|
function useOpenInteractionType(open) {
|
|
3882
4723
|
const [openMethod, setOpenMethod] = React__namespace.useState(null);
|
|
3883
4724
|
const triggerProps = useOpenMethodTriggerProps(open, setOpenMethod);
|
|
3884
|
-
|
|
4725
|
+
useValueChanged(open, previousOpen => {
|
|
3885
4726
|
if (previousOpen && !open) {
|
|
3886
4727
|
setOpenMethod(null);
|
|
3887
4728
|
}
|
|
@@ -3902,6 +4743,228 @@ function useDirection() {
|
|
|
3902
4743
|
return context?.direction ?? 'ltr';
|
|
3903
4744
|
}
|
|
3904
4745
|
|
|
4746
|
+
const CompositeRootContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
4747
|
+
if (process.env.NODE_ENV !== "production") CompositeRootContext.displayName = "CompositeRootContext";
|
|
4748
|
+
function useCompositeRootContext(optional = false) {
|
|
4749
|
+
const context = React__namespace.useContext(CompositeRootContext);
|
|
4750
|
+
if (context === undefined && !optional) {
|
|
4751
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: CompositeRootContext is missing. Composite parts must be placed within <Composite.Root>.' : useRenderElement.formatErrorMessage(16));
|
|
4752
|
+
}
|
|
4753
|
+
return context;
|
|
4754
|
+
}
|
|
4755
|
+
|
|
4756
|
+
function useFocusableWhenDisabled(parameters) {
|
|
4757
|
+
const {
|
|
4758
|
+
focusableWhenDisabled,
|
|
4759
|
+
disabled,
|
|
4760
|
+
composite = false,
|
|
4761
|
+
tabIndex: tabIndexProp = 0,
|
|
4762
|
+
isNativeButton
|
|
4763
|
+
} = parameters;
|
|
4764
|
+
const isFocusableComposite = composite && focusableWhenDisabled !== false;
|
|
4765
|
+
const isNonFocusableComposite = composite && focusableWhenDisabled === false;
|
|
4766
|
+
|
|
4767
|
+
// we can't explicitly assign `undefined` to any of these props because it
|
|
4768
|
+
// would otherwise prevent subsequently merged props from setting them
|
|
4769
|
+
const props = React__namespace.useMemo(() => {
|
|
4770
|
+
const additionalProps = {
|
|
4771
|
+
// allow Tabbing away from focusableWhenDisabled elements
|
|
4772
|
+
onKeyDown(event) {
|
|
4773
|
+
if (disabled && focusableWhenDisabled && event.key !== 'Tab') {
|
|
4774
|
+
event.preventDefault();
|
|
4775
|
+
}
|
|
4776
|
+
}
|
|
4777
|
+
};
|
|
4778
|
+
if (!composite) {
|
|
4779
|
+
additionalProps.tabIndex = tabIndexProp;
|
|
4780
|
+
if (!isNativeButton && disabled) {
|
|
4781
|
+
additionalProps.tabIndex = focusableWhenDisabled ? tabIndexProp : -1;
|
|
4782
|
+
}
|
|
4783
|
+
}
|
|
4784
|
+
if (isNativeButton && (focusableWhenDisabled || isFocusableComposite) || !isNativeButton && disabled) {
|
|
4785
|
+
additionalProps['aria-disabled'] = disabled;
|
|
4786
|
+
}
|
|
4787
|
+
if (isNativeButton && (!focusableWhenDisabled || isNonFocusableComposite)) {
|
|
4788
|
+
additionalProps.disabled = disabled;
|
|
4789
|
+
}
|
|
4790
|
+
return additionalProps;
|
|
4791
|
+
}, [composite, disabled, focusableWhenDisabled, isFocusableComposite, isNonFocusableComposite, isNativeButton, tabIndexProp]);
|
|
4792
|
+
return {
|
|
4793
|
+
props
|
|
4794
|
+
};
|
|
4795
|
+
}
|
|
4796
|
+
|
|
4797
|
+
function useButton(parameters = {}) {
|
|
4798
|
+
const {
|
|
4799
|
+
disabled = false,
|
|
4800
|
+
focusableWhenDisabled,
|
|
4801
|
+
tabIndex = 0,
|
|
4802
|
+
native: isNativeButton = true,
|
|
4803
|
+
composite: compositeProp
|
|
4804
|
+
} = parameters;
|
|
4805
|
+
const elementRef = React__namespace.useRef(null);
|
|
4806
|
+
const compositeRootContext = useCompositeRootContext(true);
|
|
4807
|
+
const isCompositeItem = compositeProp ?? compositeRootContext !== undefined;
|
|
4808
|
+
const {
|
|
4809
|
+
props: focusableWhenDisabledProps
|
|
4810
|
+
} = useFocusableWhenDisabled({
|
|
4811
|
+
focusableWhenDisabled,
|
|
4812
|
+
disabled,
|
|
4813
|
+
composite: isCompositeItem,
|
|
4814
|
+
tabIndex,
|
|
4815
|
+
isNativeButton
|
|
4816
|
+
});
|
|
4817
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
4818
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
4819
|
+
React__namespace.useEffect(() => {
|
|
4820
|
+
if (!elementRef.current) {
|
|
4821
|
+
return;
|
|
4822
|
+
}
|
|
4823
|
+
const isButtonTag = isButtonElement(elementRef.current);
|
|
4824
|
+
if (isNativeButton) {
|
|
4825
|
+
if (!isButtonTag) {
|
|
4826
|
+
const ownerStackMessage = SafeReact.captureOwnerStack?.() || '';
|
|
4827
|
+
const message = 'A component that acts as a button expected a native <button> because the ' + '`nativeButton` prop is true. Rendering a non-<button> removes native button ' + 'semantics, which can impact forms and accessibility. Use a real <button> in the ' + '`render` prop, or set `nativeButton` to `false`.';
|
|
4828
|
+
error(`${message}${ownerStackMessage}`);
|
|
4829
|
+
}
|
|
4830
|
+
} else if (isButtonTag) {
|
|
4831
|
+
const ownerStackMessage = SafeReact.captureOwnerStack?.() || '';
|
|
4832
|
+
const message = 'A component that acts as a button expected a non-<button> because the `nativeButton` ' + 'prop is false. Rendering a <button> keeps native behavior while Base UI applies ' + 'non-native attributes and handlers, which can add unintended extra attributes (such ' + 'as `role` or `aria-disabled`). Use a non-<button> in the `render` prop, or set ' + '`nativeButton` to `true`.';
|
|
4833
|
+
error(`${message}${ownerStackMessage}`);
|
|
4834
|
+
}
|
|
4835
|
+
}, [isNativeButton]);
|
|
4836
|
+
}
|
|
4837
|
+
|
|
4838
|
+
// handles a disabled composite button rendering another button, e.g.
|
|
4839
|
+
// <Toolbar.Button disabled render={<Menu.Trigger />} />
|
|
4840
|
+
// the `disabled` prop needs to pass through 2 `useButton`s then finally
|
|
4841
|
+
// delete the `disabled` attribute from DOM
|
|
4842
|
+
const updateDisabled = React__namespace.useCallback(() => {
|
|
4843
|
+
const element = elementRef.current;
|
|
4844
|
+
if (!isButtonElement(element)) {
|
|
4845
|
+
return;
|
|
4846
|
+
}
|
|
4847
|
+
if (isCompositeItem && disabled && focusableWhenDisabledProps.disabled === undefined && element.disabled) {
|
|
4848
|
+
element.disabled = false;
|
|
4849
|
+
}
|
|
4850
|
+
}, [disabled, focusableWhenDisabledProps.disabled, isCompositeItem]);
|
|
4851
|
+
useIsoLayoutEffect(updateDisabled, [updateDisabled]);
|
|
4852
|
+
const getButtonProps = React__namespace.useCallback((externalProps = {}) => {
|
|
4853
|
+
const {
|
|
4854
|
+
onClick: externalOnClick,
|
|
4855
|
+
onMouseDown: externalOnMouseDown,
|
|
4856
|
+
onKeyUp: externalOnKeyUp,
|
|
4857
|
+
onKeyDown: externalOnKeyDown,
|
|
4858
|
+
onPointerDown: externalOnPointerDown,
|
|
4859
|
+
...otherExternalProps
|
|
4860
|
+
} = externalProps;
|
|
4861
|
+
return useRenderElement.mergeProps({
|
|
4862
|
+
onClick(event) {
|
|
4863
|
+
if (disabled) {
|
|
4864
|
+
event.preventDefault();
|
|
4865
|
+
return;
|
|
4866
|
+
}
|
|
4867
|
+
externalOnClick?.(event);
|
|
4868
|
+
},
|
|
4869
|
+
onMouseDown(event) {
|
|
4870
|
+
if (!disabled) {
|
|
4871
|
+
externalOnMouseDown?.(event);
|
|
4872
|
+
}
|
|
4873
|
+
},
|
|
4874
|
+
onKeyDown(event) {
|
|
4875
|
+
if (disabled) {
|
|
4876
|
+
return;
|
|
4877
|
+
}
|
|
4878
|
+
useRenderElement.makeEventPreventable(event);
|
|
4879
|
+
externalOnKeyDown?.(event);
|
|
4880
|
+
if (event.baseUIHandlerPrevented) {
|
|
4881
|
+
return;
|
|
4882
|
+
}
|
|
4883
|
+
const isCurrentTarget = event.target === event.currentTarget;
|
|
4884
|
+
const currentTarget = event.currentTarget;
|
|
4885
|
+
const isButton = isButtonElement(currentTarget);
|
|
4886
|
+
const isLink = !isNativeButton && isValidLinkElement(currentTarget);
|
|
4887
|
+
const shouldClick = isCurrentTarget && (isNativeButton ? isButton : !isLink);
|
|
4888
|
+
const isEnterKey = event.key === 'Enter';
|
|
4889
|
+
const isSpaceKey = event.key === ' ';
|
|
4890
|
+
const role = currentTarget.getAttribute('role');
|
|
4891
|
+
const isTextNavigationRole = role?.startsWith('menuitem') || role === 'option' || role === 'gridcell';
|
|
4892
|
+
if (isCurrentTarget && isCompositeItem && isSpaceKey) {
|
|
4893
|
+
if (event.defaultPrevented && isTextNavigationRole) {
|
|
4894
|
+
return;
|
|
4895
|
+
}
|
|
4896
|
+
event.preventDefault();
|
|
4897
|
+
if (isLink || isNativeButton && isButton) {
|
|
4898
|
+
currentTarget.click();
|
|
4899
|
+
event.preventBaseUIHandler();
|
|
4900
|
+
} else if (shouldClick) {
|
|
4901
|
+
externalOnClick?.(event);
|
|
4902
|
+
event.preventBaseUIHandler();
|
|
4903
|
+
}
|
|
4904
|
+
return;
|
|
4905
|
+
}
|
|
4906
|
+
|
|
4907
|
+
// Keyboard accessibility for native and non-native elements.
|
|
4908
|
+
if (shouldClick) {
|
|
4909
|
+
if (!isNativeButton && (isSpaceKey || isEnterKey)) {
|
|
4910
|
+
event.preventDefault();
|
|
4911
|
+
}
|
|
4912
|
+
if (!isNativeButton && isEnterKey) {
|
|
4913
|
+
externalOnClick?.(event);
|
|
4914
|
+
}
|
|
4915
|
+
}
|
|
4916
|
+
},
|
|
4917
|
+
onKeyUp(event) {
|
|
4918
|
+
if (disabled) {
|
|
4919
|
+
return;
|
|
4920
|
+
}
|
|
4921
|
+
|
|
4922
|
+
// calling preventDefault in keyUp on a <button> will not dispatch a click event if Space is pressed
|
|
4923
|
+
// https://codesandbox.io/p/sandbox/button-keyup-preventdefault-dn7f0
|
|
4924
|
+
useRenderElement.makeEventPreventable(event);
|
|
4925
|
+
externalOnKeyUp?.(event);
|
|
4926
|
+
if (event.target === event.currentTarget && isNativeButton && isCompositeItem && isButtonElement(event.currentTarget) && event.key === ' ') {
|
|
4927
|
+
event.preventDefault();
|
|
4928
|
+
return;
|
|
4929
|
+
}
|
|
4930
|
+
if (event.baseUIHandlerPrevented) {
|
|
4931
|
+
return;
|
|
4932
|
+
}
|
|
4933
|
+
|
|
4934
|
+
// Keyboard accessibility for non interactive elements
|
|
4935
|
+
if (event.target === event.currentTarget && !isNativeButton && !isCompositeItem && event.key === ' ') {
|
|
4936
|
+
externalOnClick?.(event);
|
|
4937
|
+
}
|
|
4938
|
+
},
|
|
4939
|
+
onPointerDown(event) {
|
|
4940
|
+
if (disabled) {
|
|
4941
|
+
event.preventDefault();
|
|
4942
|
+
return;
|
|
4943
|
+
}
|
|
4944
|
+
externalOnPointerDown?.(event);
|
|
4945
|
+
}
|
|
4946
|
+
}, isNativeButton ? {
|
|
4947
|
+
type: 'button'
|
|
4948
|
+
} : {
|
|
4949
|
+
role: 'button'
|
|
4950
|
+
}, focusableWhenDisabledProps, otherExternalProps);
|
|
4951
|
+
}, [disabled, focusableWhenDisabledProps, isCompositeItem, isNativeButton]);
|
|
4952
|
+
const buttonRef = useStableCallback(element => {
|
|
4953
|
+
elementRef.current = element;
|
|
4954
|
+
updateDisabled();
|
|
4955
|
+
});
|
|
4956
|
+
return {
|
|
4957
|
+
getButtonProps,
|
|
4958
|
+
buttonRef
|
|
4959
|
+
};
|
|
4960
|
+
}
|
|
4961
|
+
function isButtonElement(elem) {
|
|
4962
|
+
return floatingUi_utils.isHTMLElement(elem) && elem.tagName === 'BUTTON';
|
|
4963
|
+
}
|
|
4964
|
+
function isValidLinkElement(elem) {
|
|
4965
|
+
return Boolean(elem?.tagName === 'A' && elem?.href);
|
|
4966
|
+
}
|
|
4967
|
+
|
|
3905
4968
|
let CommonPopupDataAttributes = function (CommonPopupDataAttributes) {
|
|
3906
4969
|
/**
|
|
3907
4970
|
* Present when the popup is open.
|
|
@@ -3914,11 +4977,11 @@ let CommonPopupDataAttributes = function (CommonPopupDataAttributes) {
|
|
|
3914
4977
|
/**
|
|
3915
4978
|
* Present when the popup is animating in.
|
|
3916
4979
|
*/
|
|
3917
|
-
CommonPopupDataAttributes[CommonPopupDataAttributes["startingStyle"] =
|
|
4980
|
+
CommonPopupDataAttributes[CommonPopupDataAttributes["startingStyle"] = TransitionStatusDataAttributes.startingStyle] = "startingStyle";
|
|
3918
4981
|
/**
|
|
3919
4982
|
* Present when the popup is animating out.
|
|
3920
4983
|
*/
|
|
3921
|
-
CommonPopupDataAttributes[CommonPopupDataAttributes["endingStyle"] =
|
|
4984
|
+
CommonPopupDataAttributes[CommonPopupDataAttributes["endingStyle"] = TransitionStatusDataAttributes.endingStyle] = "endingStyle";
|
|
3922
4985
|
/**
|
|
3923
4986
|
* Present when the anchor is hidden.
|
|
3924
4987
|
*/
|
|
@@ -4037,8 +5100,8 @@ function hasInsetScrollbars(referenceElement) {
|
|
|
4037
5100
|
if (typeof document === 'undefined') {
|
|
4038
5101
|
return false;
|
|
4039
5102
|
}
|
|
4040
|
-
const doc =
|
|
4041
|
-
const win =
|
|
5103
|
+
const doc = ownerDocument(referenceElement);
|
|
5104
|
+
const win = floatingUi_utils.getWindow(doc);
|
|
4042
5105
|
return win.innerWidth - doc.documentElement.clientWidth > 0;
|
|
4043
5106
|
}
|
|
4044
5107
|
function supportsStableScrollbarGutter(referenceElement) {
|
|
@@ -4046,10 +5109,10 @@ function supportsStableScrollbarGutter(referenceElement) {
|
|
|
4046
5109
|
if (!supported || typeof document === 'undefined') {
|
|
4047
5110
|
return false;
|
|
4048
5111
|
}
|
|
4049
|
-
const doc =
|
|
5112
|
+
const doc = ownerDocument(referenceElement);
|
|
4050
5113
|
const html = doc.documentElement;
|
|
4051
5114
|
const body = doc.body;
|
|
4052
|
-
const scrollContainer =
|
|
5115
|
+
const scrollContainer = floatingUi_utils.isOverflowElement(html) ? html : body;
|
|
4053
5116
|
const originalScrollContainerOverflowY = scrollContainer.style.overflowY;
|
|
4054
5117
|
const originalHtmlStyleGutter = html.style.scrollbarGutter;
|
|
4055
5118
|
html.style.scrollbarGutter = 'stable';
|
|
@@ -4062,7 +5125,7 @@ function supportsStableScrollbarGutter(referenceElement) {
|
|
|
4062
5125
|
return before === after;
|
|
4063
5126
|
}
|
|
4064
5127
|
function preventScrollOverlayScrollbars(referenceElement) {
|
|
4065
|
-
const doc =
|
|
5128
|
+
const doc = ownerDocument(referenceElement);
|
|
4066
5129
|
const html = doc.documentElement;
|
|
4067
5130
|
const body = doc.body;
|
|
4068
5131
|
|
|
@@ -4070,7 +5133,7 @@ function preventScrollOverlayScrollbars(referenceElement) {
|
|
|
4070
5133
|
// won't have any effect.
|
|
4071
5134
|
// But if <body> has an `overflow` style (like `overflow-x: hidden`), we need to lock it
|
|
4072
5135
|
// instead, as sticky elements shift otherwise.
|
|
4073
|
-
const elementToLock =
|
|
5136
|
+
const elementToLock = floatingUi_utils.isOverflowElement(html) ? html : body;
|
|
4074
5137
|
const originalElementToLockStyles = {
|
|
4075
5138
|
overflowY: elementToLock.style.overflowY,
|
|
4076
5139
|
overflowX: elementToLock.style.overflowX
|
|
@@ -4084,14 +5147,14 @@ function preventScrollOverlayScrollbars(referenceElement) {
|
|
|
4084
5147
|
};
|
|
4085
5148
|
}
|
|
4086
5149
|
function preventScrollInsetScrollbars(referenceElement) {
|
|
4087
|
-
const doc =
|
|
5150
|
+
const doc = ownerDocument(referenceElement);
|
|
4088
5151
|
const html = doc.documentElement;
|
|
4089
5152
|
const body = doc.body;
|
|
4090
|
-
const win =
|
|
5153
|
+
const win = floatingUi_utils.getWindow(html);
|
|
4091
5154
|
let scrollTop = 0;
|
|
4092
5155
|
let scrollLeft = 0;
|
|
4093
5156
|
let updateGutterOnly = false;
|
|
4094
|
-
const resizeFrame =
|
|
5157
|
+
const resizeFrame = AnimationFrame.create();
|
|
4095
5158
|
|
|
4096
5159
|
// Pinch-zoom in Safari causes a shift. Just don't lock scroll if there's any pinch-zoom.
|
|
4097
5160
|
if (webkit && (win.visualViewport?.scale ?? 1) !== 1) {
|
|
@@ -4135,7 +5198,7 @@ function preventScrollInsetScrollbars(referenceElement) {
|
|
|
4135
5198
|
// with whitespace. Warn if <body> has margins?
|
|
4136
5199
|
const marginY = parseFloat(bodyStyles.marginTop) + parseFloat(bodyStyles.marginBottom);
|
|
4137
5200
|
const marginX = parseFloat(bodyStyles.marginLeft) + parseFloat(bodyStyles.marginRight);
|
|
4138
|
-
const elementToLock =
|
|
5201
|
+
const elementToLock = floatingUi_utils.isOverflowElement(html) ? html : body;
|
|
4139
5202
|
updateGutterOnly = supportsStableScrollbarGutter(referenceElement);
|
|
4140
5203
|
|
|
4141
5204
|
/*
|
|
@@ -4188,7 +5251,7 @@ function preventScrollInsetScrollbars(referenceElement) {
|
|
|
4188
5251
|
resizeFrame.request(lockScroll);
|
|
4189
5252
|
}
|
|
4190
5253
|
lockScroll();
|
|
4191
|
-
const unsubscribeResize =
|
|
5254
|
+
const unsubscribeResize = addEventListener(win, 'resize', handleResize);
|
|
4192
5255
|
return () => {
|
|
4193
5256
|
resizeFrame.cancel();
|
|
4194
5257
|
cleanup();
|
|
@@ -4203,8 +5266,8 @@ function preventScrollInsetScrollbars(referenceElement) {
|
|
|
4203
5266
|
class ScrollLocker {
|
|
4204
5267
|
lockCount = 0;
|
|
4205
5268
|
restore = null;
|
|
4206
|
-
timeoutLock =
|
|
4207
|
-
timeoutUnlock =
|
|
5269
|
+
timeoutLock = Timeout.create();
|
|
5270
|
+
timeoutUnlock = Timeout.create();
|
|
4208
5271
|
acquire(referenceElement) {
|
|
4209
5272
|
this.lockCount += 1;
|
|
4210
5273
|
if (this.lockCount === 1 && this.restore === null) {
|
|
@@ -4228,16 +5291,16 @@ class ScrollLocker {
|
|
|
4228
5291
|
if (this.lockCount === 0 || this.restore !== null) {
|
|
4229
5292
|
return;
|
|
4230
5293
|
}
|
|
4231
|
-
const doc =
|
|
5294
|
+
const doc = ownerDocument(referenceElement);
|
|
4232
5295
|
const html = doc.documentElement;
|
|
4233
|
-
const htmlOverflowY =
|
|
5296
|
+
const htmlOverflowY = floatingUi_utils.getWindow(html).getComputedStyle(html).overflowY;
|
|
4234
5297
|
|
|
4235
5298
|
// If the site author already hid overflow on <html>, respect it and bail out.
|
|
4236
5299
|
if (htmlOverflowY === 'hidden' || htmlOverflowY === 'clip') {
|
|
4237
5300
|
this.restore = useRenderElement.NOOP;
|
|
4238
5301
|
return;
|
|
4239
5302
|
}
|
|
4240
|
-
const hasOverlayScrollbars =
|
|
5303
|
+
const hasOverlayScrollbars = ios || !hasInsetScrollbars(referenceElement);
|
|
4241
5304
|
|
|
4242
5305
|
// On iOS, scroll locking does not work if the navbar is collapsed. Due to numerous
|
|
4243
5306
|
// side effects and bugs that arise on iOS, it must be researched extensively before
|
|
@@ -4257,7 +5320,7 @@ const SCROLL_LOCKER = new ScrollLocker();
|
|
|
4257
5320
|
* @param referenceElement - Element to use as a reference for lock calculations.
|
|
4258
5321
|
*/
|
|
4259
5322
|
function useScrollLock(enabled = true, referenceElement = null) {
|
|
4260
|
-
|
|
5323
|
+
useIsoLayoutEffect(() => {
|
|
4261
5324
|
if (!enabled) {
|
|
4262
5325
|
return undefined;
|
|
4263
5326
|
}
|
|
@@ -4287,16 +5350,34 @@ exports.PATIENT_CLICK_THRESHOLD = PATIENT_CLICK_THRESHOLD;
|
|
|
4287
5350
|
exports.POPUP_COLLISION_AVOIDANCE = POPUP_COLLISION_AVOIDANCE;
|
|
4288
5351
|
exports.PopupTriggerMap = PopupTriggerMap;
|
|
4289
5352
|
exports.ReactStore = ReactStore;
|
|
5353
|
+
exports.SafeReact = SafeReact;
|
|
4290
5354
|
exports.Store = Store;
|
|
4291
5355
|
exports.TYPEAHEAD_RESET_MS = TYPEAHEAD_RESET_MS;
|
|
5356
|
+
exports.Timeout = Timeout;
|
|
5357
|
+
exports.TransitionStatusDataAttributes = TransitionStatusDataAttributes;
|
|
5358
|
+
exports.activeElement = activeElement;
|
|
5359
|
+
exports.addEventListener = addEventListener;
|
|
5360
|
+
exports.android = android;
|
|
4292
5361
|
exports.attachPreventUnmountOnClose = attachPreventUnmountOnClose;
|
|
5362
|
+
exports.cancelOpen = cancelOpen;
|
|
5363
|
+
exports.chipRemovePress = chipRemovePress;
|
|
5364
|
+
exports.clearPress = clearPress;
|
|
5365
|
+
exports.closePress = closePress;
|
|
5366
|
+
exports.closeWatcher = closeWatcher;
|
|
5367
|
+
exports.contains = contains;
|
|
4293
5368
|
exports.createAttribute = createAttribute;
|
|
5369
|
+
exports.createChangeEventDetails = createChangeEventDetails;
|
|
4294
5370
|
exports.createDefaultInitialFocus = createDefaultInitialFocus;
|
|
5371
|
+
exports.createGenericEventDetails = createGenericEventDetails;
|
|
4295
5372
|
exports.createSelector = createSelector;
|
|
5373
|
+
exports.decrementPress = decrementPress;
|
|
4296
5374
|
exports.enqueueFocus = enqueueFocus;
|
|
5375
|
+
exports.error = error;
|
|
5376
|
+
exports.escapeKey = escapeKey;
|
|
4297
5377
|
exports.fastComponent = fastComponent;
|
|
4298
5378
|
exports.fastComponentRef = fastComponentRef;
|
|
4299
5379
|
exports.findNonDisabledListIndex = findNonDisabledListIndex;
|
|
5380
|
+
exports.focusOut = focusOut;
|
|
4300
5381
|
exports.gecko = gecko;
|
|
4301
5382
|
exports.getFloatingFocusElement = getFloatingFocusElement;
|
|
4302
5383
|
exports.getGridNavigatedIndex = getGridNavigatedIndex;
|
|
@@ -4306,30 +5387,69 @@ exports.getNextTabbable = getNextTabbable;
|
|
|
4306
5387
|
exports.getNodeChildren = getNodeChildren;
|
|
4307
5388
|
exports.getTabbableAfterElement = getTabbableAfterElement;
|
|
4308
5389
|
exports.getTabbableBeforeElement = getTabbableBeforeElement;
|
|
5390
|
+
exports.getTarget = getTarget;
|
|
5391
|
+
exports.imperativeAction = imperativeAction;
|
|
5392
|
+
exports.incrementPress = incrementPress;
|
|
4309
5393
|
exports.inertValue = inertValue;
|
|
5394
|
+
exports.inputBlur = inputBlur;
|
|
5395
|
+
exports.inputChange = inputChange;
|
|
5396
|
+
exports.inputClear = inputClear;
|
|
5397
|
+
exports.inputPaste = inputPaste;
|
|
5398
|
+
exports.inputPress = inputPress;
|
|
5399
|
+
exports.ios = ios;
|
|
4310
5400
|
exports.isElementVisible = isElementVisible;
|
|
4311
5401
|
exports.isIndexOutOfListBounds = isIndexOutOfListBounds;
|
|
4312
5402
|
exports.isInteractiveElement = isInteractiveElement;
|
|
4313
5403
|
exports.isListIndexDisabled = isListIndexDisabled;
|
|
5404
|
+
exports.isMouseLikePointerType = isMouseLikePointerType;
|
|
4314
5405
|
exports.isOutsideEvent = isOutsideEvent;
|
|
4315
5406
|
exports.isTargetInsideEnabledTrigger = isTargetInsideEnabledTrigger;
|
|
4316
5407
|
exports.isTypeableCombobox = isTypeableCombobox;
|
|
4317
5408
|
exports.isTypeableElement = isTypeableElement;
|
|
5409
|
+
exports.isVirtualClick = isVirtualClick;
|
|
5410
|
+
exports.isVirtualPointerEvent = isVirtualPointerEvent;
|
|
5411
|
+
exports.itemPress = itemPress;
|
|
5412
|
+
exports.jsdom = jsdom;
|
|
5413
|
+
exports.keyboard = keyboard;
|
|
5414
|
+
exports.listNavigation = listNavigation;
|
|
5415
|
+
exports.mac = mac;
|
|
4318
5416
|
exports.matchesFocusVisible = matchesFocusVisible;
|
|
4319
5417
|
exports.mergeCleanups = mergeCleanups;
|
|
5418
|
+
exports.none = none;
|
|
5419
|
+
exports.outsidePress = outsidePress;
|
|
5420
|
+
exports.ownerDocument = ownerDocument;
|
|
5421
|
+
exports.pointer = pointer;
|
|
4320
5422
|
exports.popupStateMapping = popupStateMapping;
|
|
4321
5423
|
exports.pressableTriggerOpenStateMapping = pressableTriggerOpenStateMapping;
|
|
5424
|
+
exports.scrub = scrub;
|
|
4322
5425
|
exports.setPopupOpenState = setPopupOpenState;
|
|
5426
|
+
exports.siblingOpen = siblingOpen;
|
|
5427
|
+
exports.stopEvent = stopEvent;
|
|
5428
|
+
exports.swipe = swipe;
|
|
5429
|
+
exports.transitionStatusMapping = transitionStatusMapping;
|
|
5430
|
+
exports.triggerFocus = triggerFocus;
|
|
5431
|
+
exports.triggerHover = triggerHover;
|
|
4323
5432
|
exports.triggerOpenStateMapping = triggerOpenStateMapping;
|
|
5433
|
+
exports.triggerPress = triggerPress;
|
|
5434
|
+
exports.useAnimationFrame = useAnimationFrame;
|
|
5435
|
+
exports.useAnimationsFinished = useAnimationsFinished;
|
|
5436
|
+
exports.useBaseUiId = useBaseUiId;
|
|
5437
|
+
exports.useButton = useButton;
|
|
4324
5438
|
exports.useClick = useClick;
|
|
5439
|
+
exports.useCompositeRootContext = useCompositeRootContext;
|
|
5440
|
+
exports.useControlled = useControlled;
|
|
4325
5441
|
exports.useDirection = useDirection;
|
|
4326
5442
|
exports.useDismiss = useDismiss;
|
|
4327
5443
|
exports.useFloatingNodeId = useFloatingNodeId;
|
|
4328
5444
|
exports.useFloatingParentNodeId = useFloatingParentNodeId;
|
|
4329
5445
|
exports.useFloatingTree = useFloatingTree;
|
|
5446
|
+
exports.useId = useId;
|
|
4330
5447
|
exports.useImplicitActiveTrigger = useImplicitActiveTrigger;
|
|
4331
5448
|
exports.useInitialOpenSync = useInitialOpenSync;
|
|
5449
|
+
exports.useIsoLayoutEffect = useIsoLayoutEffect;
|
|
4332
5450
|
exports.useOnFirstRender = useOnFirstRender;
|
|
5451
|
+
exports.useOnMount = useOnMount;
|
|
5452
|
+
exports.useOpenChangeComplete = useOpenChangeComplete;
|
|
4333
5453
|
exports.useOpenInteractionType = useOpenInteractionType;
|
|
4334
5454
|
exports.useOpenMethodTriggerProps = useOpenMethodTriggerProps;
|
|
4335
5455
|
exports.useOpenStateTransitions = useOpenStateTransitions;
|
|
@@ -4337,8 +5457,17 @@ exports.usePopupInteractionProps = usePopupInteractionProps;
|
|
|
4337
5457
|
exports.usePopupRootSync = usePopupRootSync;
|
|
4338
5458
|
exports.usePopupStore = usePopupStore;
|
|
4339
5459
|
exports.useScrollLock = useScrollLock;
|
|
5460
|
+
exports.useStableCallback = useStableCallback;
|
|
4340
5461
|
exports.useStore = useStore;
|
|
4341
5462
|
exports.useSyncedFloatingRootContext = useSyncedFloatingRootContext;
|
|
5463
|
+
exports.useTimeout = useTimeout;
|
|
5464
|
+
exports.useTransitionStatus = useTransitionStatus;
|
|
4342
5465
|
exports.useTriggerDataForwarding = useTriggerDataForwarding;
|
|
4343
5466
|
exports.useTriggerRegistration = useTriggerRegistration;
|
|
5467
|
+
exports.useValueAsRef = useValueAsRef;
|
|
5468
|
+
exports.useValueChanged = useValueChanged;
|
|
5469
|
+
exports.visuallyHidden = visuallyHidden;
|
|
5470
|
+
exports.visuallyHiddenInput = visuallyHiddenInput;
|
|
4344
5471
|
exports.webkit = webkit;
|
|
5472
|
+
exports.wheel = wheel;
|
|
5473
|
+
exports.windowResize = windowResize;
|