@jobber/components 9.5.3 → 9.6.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/Combobox.d.ts +1 -0
- package/Combobox.js +17 -0
- package/dist/Autocomplete/index.cjs +0 -2
- package/dist/Autocomplete/index.mjs +0 -2
- package/dist/Autocomplete-cjs.js +4 -5
- package/dist/Autocomplete-es.js +1 -2
- package/dist/Card/index.cjs +2 -2
- package/dist/Card/index.mjs +2 -2
- package/dist/Chip/index.cjs +0 -2
- package/dist/Chip/index.mjs +0 -2
- package/dist/Chips/InternalChipDismissible/hooks/index.cjs +0 -2
- package/dist/Chips/InternalChipDismissible/hooks/index.mjs +0 -2
- package/dist/Chips/InternalChipDismissible/index.cjs +0 -2
- package/dist/Chips/InternalChipDismissible/index.mjs +0 -2
- package/dist/Chips/index.cjs +0 -2
- package/dist/Chips/index.mjs +0 -2
- package/dist/Combobox/Combobox.contentSlots.d.ts +5 -0
- package/dist/Combobox/Combobox.context.d.ts +34 -0
- package/dist/Combobox/Combobox.d.ts +69 -0
- package/dist/Combobox/Combobox.footer.d.ts +7 -0
- package/dist/Combobox/Combobox.items.d.ts +25 -0
- package/dist/Combobox/Combobox.responsive.d.ts +54 -0
- package/dist/Combobox/Combobox.selectAll.d.ts +4 -0
- package/dist/Combobox/Combobox.slotFactory.d.ts +7 -0
- package/dist/Combobox/Combobox.testUtils.d.ts +12 -0
- package/dist/Combobox/Combobox.types.d.ts +166 -0
- package/dist/Combobox/index.cjs +35 -0
- package/dist/Combobox/index.d.ts +2 -0
- package/dist/Combobox/index.mjs +29 -0
- package/dist/Combobox-cjs.js +675 -0
- package/dist/Combobox-es.js +673 -0
- package/dist/ComboboxPrimitive-cjs.js +88 -47
- package/dist/ComboboxPrimitive-es.js +39 -23
- package/dist/{ComboboxChipRemove-cjs.js → ComboboxSeparator-cjs.js} +501 -455
- package/dist/{ComboboxChipRemove-es.js → ComboboxSeparator-es.js} +500 -456
- package/dist/ConfirmationModal/index.cjs +0 -2
- package/dist/ConfirmationModal/index.mjs +0 -2
- package/dist/ContentBlock/index.cjs +1 -0
- package/dist/ContentBlock/index.mjs +1 -0
- package/dist/ContentBlock-cjs.js +2 -18
- package/dist/ContentBlock-es.js +1 -17
- package/dist/DataDump/index.cjs +2 -2
- package/dist/DataDump/index.mjs +2 -2
- package/dist/DataList/components/DataListActions/index.cjs +0 -2
- package/dist/DataList/components/DataListActions/index.mjs +0 -2
- package/dist/DataList/components/DataListBulkActions/index.cjs +0 -2
- package/dist/DataList/components/DataListBulkActions/index.mjs +0 -2
- package/dist/DataList/components/DataListFilters/components/DataListSort/index.cjs +0 -2
- package/dist/DataList/components/DataListFilters/components/DataListSort/index.mjs +0 -2
- package/dist/DataList/components/DataListFilters/index.cjs +0 -2
- package/dist/DataList/components/DataListFilters/index.mjs +0 -2
- package/dist/DataList/components/DataListHeader/index.cjs +0 -2
- package/dist/DataList/components/DataListHeader/index.mjs +0 -2
- package/dist/DataList/components/DataListItem/index.cjs +0 -2
- package/dist/DataList/components/DataListItem/index.mjs +0 -2
- package/dist/DataList/components/DataListItemActions/index.cjs +0 -2
- package/dist/DataList/components/DataListItemActions/index.mjs +0 -2
- package/dist/DataList/components/DataListItemActionsOverflow/index.cjs +0 -2
- package/dist/DataList/components/DataListItemActionsOverflow/index.mjs +0 -2
- package/dist/DataList/components/DataListItems/index.cjs +0 -2
- package/dist/DataList/components/DataListItems/index.mjs +0 -2
- package/dist/DataList/components/DataListLayout/index.cjs +0 -2
- package/dist/DataList/components/DataListLayout/index.mjs +0 -2
- package/dist/DataList/components/DataListLayoutActions/index.cjs +0 -2
- package/dist/DataList/components/DataListLayoutActions/index.mjs +0 -2
- package/dist/DataList/index.cjs +0 -2
- package/dist/DataList/index.mjs +0 -2
- package/dist/DatePicker/index.cjs +0 -2
- package/dist/DatePicker/index.mjs +0 -2
- package/dist/DatePicker-cjs.js +4 -5
- package/dist/DatePicker-es.js +1 -2
- package/dist/Dialog/index.cjs +2 -2
- package/dist/Dialog/index.mjs +2 -2
- package/dist/DrawerDescription-cjs.js +268 -99
- package/dist/DrawerDescription-es.js +270 -103
- package/dist/DrawerTitle-cjs.js +2 -6
- package/dist/DrawerTitle-es.js +3 -7
- package/dist/FieldDescription-cjs.js +184 -181
- package/dist/FieldDescription-es.js +187 -184
- package/dist/FilterPicker/components/FilterPickerActivator/index.cjs +0 -2
- package/dist/FilterPicker/components/FilterPickerActivator/index.mjs +0 -2
- package/dist/FilterPicker/components/FilterPickerContent/index.cjs +0 -2
- package/dist/FilterPicker/components/FilterPickerContent/index.mjs +0 -2
- package/dist/FilterPicker/components/FilterPickerTrigger/index.cjs +0 -2
- package/dist/FilterPicker/components/FilterPickerTrigger/index.mjs +0 -2
- package/dist/FilterPicker/index.cjs +0 -2
- package/dist/FilterPicker/index.mjs +0 -2
- package/dist/FilterPickerContent-cjs.js +4 -5
- package/dist/FilterPickerContent-es.js +1 -2
- package/dist/FormatFile/index.cjs +0 -2
- package/dist/FormatFile/index.mjs +0 -2
- package/dist/Gallery/index.cjs +0 -2
- package/dist/Gallery/index.mjs +0 -2
- package/dist/InputDate/index.cjs +0 -2
- package/dist/InputDate/index.mjs +0 -2
- package/dist/InputNumber/index.cjs +2 -2
- package/dist/InputNumber/index.mjs +2 -2
- package/dist/InputNumber/types.d.ts +5 -0
- package/dist/InputNumber-cjs.js +2 -2
- package/dist/InputNumber-es.js +2 -2
- package/dist/LightBox/index.cjs +0 -2
- package/dist/LightBox/index.mjs +0 -2
- package/dist/Menu/index.cjs +2 -2
- package/dist/Menu/index.mjs +2 -2
- package/dist/Menu-cjs.js +4 -5
- package/dist/Menu-es.js +1 -2
- package/dist/MenuSubmenuTrigger-cjs.js +206 -164
- package/dist/MenuSubmenuTrigger-es.js +194 -152
- package/dist/Modal/index.cjs +0 -2
- package/dist/Modal/index.mjs +1 -3
- package/dist/NumberFieldInput-cjs.js +187 -308
- package/dist/NumberFieldInput-es.js +187 -308
- package/dist/Page/index.cjs +2 -2
- package/dist/Page/index.mjs +2 -2
- package/dist/Popover/index.cjs +0 -2
- package/dist/Popover/index.mjs +0 -2
- package/dist/Popover-cjs.js +7 -8
- package/dist/Popover-es.js +1 -2
- package/dist/ScrollAreaViewport-cjs.js +747 -1093
- package/dist/ScrollAreaViewport-es.js +734 -1081
- package/dist/Select/index.cjs +2 -2
- package/dist/Select/index.mjs +2 -2
- package/dist/SelectGroupLabel-cjs.js +207 -306
- package/dist/SelectGroupLabel-es.js +203 -302
- package/dist/SelectPrimitive-cjs.js +11 -17
- package/dist/SelectPrimitive-es.js +1 -7
- package/dist/Tooltip/index.cjs +0 -2
- package/dist/Tooltip/index.mjs +0 -2
- package/dist/Tooltip-cjs.js +6 -7
- package/dist/Tooltip-es.js +1 -2
- package/dist/buttonRenderAdapter-cjs.js +2 -1
- package/dist/buttonRenderAdapter-es.js +2 -1
- package/dist/dialogReturnFocus-cjs.js +1 -1
- package/dist/dialogReturnFocus-es.js +2 -2
- package/dist/docs/InputNumber/InputNumber.md +2 -2
- package/dist/docs/SelectPrimitive/SelectPrimitive.md +1 -1
- package/dist/floating-ui.react-cjs.js +2557 -185
- package/dist/floating-ui.react-es.js +2512 -149
- package/dist/getMappedBreakpointWidth-cjs.js +21 -0
- package/dist/getMappedBreakpointWidth-es.js +18 -0
- package/dist/index.cjs +15 -10
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +14 -10
- package/dist/mergeClassName-cjs.js +12 -0
- package/dist/mergeClassName-es.js +10 -0
- package/dist/primitives/BottomSheet/index.cjs +1 -1
- package/dist/primitives/BottomSheet/index.mjs +1 -1
- package/dist/primitives/ComboboxPrimitive/ComboboxPrimitive.d.ts +2 -2
- package/dist/primitives/ComboboxPrimitive/index.cjs +4 -5
- package/dist/primitives/ComboboxPrimitive/index.mjs +4 -5
- package/dist/primitives/SelectPrimitive/index.cjs +1 -2
- package/dist/primitives/SelectPrimitive/index.mjs +1 -2
- package/dist/primitives/index.cjs +3 -3
- package/dist/primitives/index.mjs +3 -3
- package/dist/scrollEdges-cjs.js +1 -11
- package/dist/scrollEdges-es.js +1 -11
- package/dist/scrollable-cjs.js +58 -0
- package/dist/scrollable-es.js +54 -0
- package/dist/styles.css +759 -42
- package/dist/unstyledPrimitives/index.cjs +720 -478
- package/dist/unstyledPrimitives/index.mjs +663 -421
- package/dist/useCompositeListItem-cjs.js +2108 -361
- package/dist/useCompositeListItem-es.js +2076 -331
- package/dist/useLabel-cjs.js +2 -3
- package/dist/useLabel-es.js +2 -3
- package/dist/useRenderElement-cjs.js +9 -7
- package/dist/useRenderElement-es.js +9 -7
- package/dist/useScrollLock-cjs.js +819 -344
- package/dist/useScrollLock-es.js +732 -296
- package/dist/useScrollToActive-cjs.js +4 -5
- package/dist/useScrollToActive-es.js +1 -2
- package/dist/utils/meta/meta.json +43 -1
- package/package.json +8 -3
- package/dist/floating-ui.react-dom-cjs.js +0 -2103
- package/dist/floating-ui.react-dom-es.js +0 -2072
- package/dist/floating-ui.utils-cjs.js +0 -342
- package/dist/floating-ui.utils-es.js +0 -300
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var React = require('react');
|
|
4
|
-
var floatingUi_utils = require('./floating-ui.utils-cjs.js');
|
|
5
4
|
var useRenderElement = require('./useRenderElement-cjs.js');
|
|
6
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
6
|
var ReactDOM = require('react-dom');
|
|
@@ -104,14 +103,6 @@ function serializeToDevModeString(input) {
|
|
|
104
103
|
const noop = () => {};
|
|
105
104
|
const useIsoLayoutEffect = typeof document !== 'undefined' ? React__namespace.useLayoutEffect : noop;
|
|
106
105
|
|
|
107
|
-
function useOnFirstRender(fn) {
|
|
108
|
-
const ref = React__namespace.useRef(true);
|
|
109
|
-
if (ref.current) {
|
|
110
|
-
ref.current = false;
|
|
111
|
-
fn();
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
106
|
/**
|
|
116
107
|
* A clone of the React namespace for reading APIs that may be missing in older
|
|
117
108
|
* supported React versions. Bundlers can rewrite direct `React.someNewApi`
|
|
@@ -210,87 +201,6 @@ const visuallyHiddenInput = {
|
|
|
210
201
|
position: 'absolute'
|
|
211
202
|
};
|
|
212
203
|
|
|
213
|
-
/**
|
|
214
|
-
* The NoOptionalParams type is a utility type that checks if a function has optional or default parameters.
|
|
215
|
-
* If the function has optional or default parameters, it returns a string literal type with an error message.
|
|
216
|
-
* Otherwise, it returns the original function type.
|
|
217
|
-
*
|
|
218
|
-
* This is used to enforce that the combiner function passed to createSelector does not have optional or default parameters,
|
|
219
|
-
* as memoization relies on the Function.length property, which does not account for optional or default parameters.
|
|
220
|
-
*/
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Creates a selector function that can be used to derive values from the store's state.
|
|
224
|
-
*
|
|
225
|
-
* The combiner function can have up to three additional parameters, but it **cannot have optional or default parameters**.
|
|
226
|
-
*
|
|
227
|
-
* This function accepts up to six functions and combines them into a single selector function.
|
|
228
|
-
* The resulting selector will take the state from the combined selectors and any additional parameters required by the combiner.
|
|
229
|
-
*
|
|
230
|
-
* The return type of the resulting selector is determined by the return type of the combiner function.
|
|
231
|
-
*
|
|
232
|
-
* @example
|
|
233
|
-
* const selector = createSelector(
|
|
234
|
-
* (state) => state.disabled
|
|
235
|
-
* );
|
|
236
|
-
*
|
|
237
|
-
* @example
|
|
238
|
-
* const selector = createSelector(
|
|
239
|
-
* (state) => state.disabled,
|
|
240
|
-
* (state) => state.open,
|
|
241
|
-
* (disabled, open) => ({ disabled, open })
|
|
242
|
-
* );
|
|
243
|
-
*/
|
|
244
|
-
/* eslint-disable id-denylist */
|
|
245
|
-
const createSelector = (a, b, c, d, e, f, ...other) => {
|
|
246
|
-
if (other.length > 0) {
|
|
247
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Unsupported number of selectors' : useRenderElement.formatErrorMessage(1));
|
|
248
|
-
}
|
|
249
|
-
let selector;
|
|
250
|
-
if (a && b && c && d && e && f) {
|
|
251
|
-
selector = (state, a1, a2, a3) => {
|
|
252
|
-
const va = a(state, a1, a2, a3);
|
|
253
|
-
const vb = b(state, a1, a2, a3);
|
|
254
|
-
const vc = c(state, a1, a2, a3);
|
|
255
|
-
const vd = d(state, a1, a2, a3);
|
|
256
|
-
const ve = e(state, a1, a2, a3);
|
|
257
|
-
return f(va, vb, vc, vd, ve, a1, a2, a3);
|
|
258
|
-
};
|
|
259
|
-
} else if (a && b && c && d && e) {
|
|
260
|
-
selector = (state, a1, a2, a3) => {
|
|
261
|
-
const va = a(state, a1, a2, a3);
|
|
262
|
-
const vb = b(state, a1, a2, a3);
|
|
263
|
-
const vc = c(state, a1, a2, a3);
|
|
264
|
-
const vd = d(state, a1, a2, a3);
|
|
265
|
-
return e(va, vb, vc, vd, a1, a2, a3);
|
|
266
|
-
};
|
|
267
|
-
} else if (a && b && c && d) {
|
|
268
|
-
selector = (state, a1, a2, a3) => {
|
|
269
|
-
const va = a(state, a1, a2, a3);
|
|
270
|
-
const vb = b(state, a1, a2, a3);
|
|
271
|
-
const vc = c(state, a1, a2, a3);
|
|
272
|
-
return d(va, vb, vc, a1, a2, a3);
|
|
273
|
-
};
|
|
274
|
-
} else if (a && b && c) {
|
|
275
|
-
selector = (state, a1, a2, a3) => {
|
|
276
|
-
const va = a(state, a1, a2, a3);
|
|
277
|
-
const vb = b(state, a1, a2, a3);
|
|
278
|
-
return c(va, vb, a1, a2, a3);
|
|
279
|
-
};
|
|
280
|
-
} else if (a && b) {
|
|
281
|
-
selector = (state, a1, a2, a3) => {
|
|
282
|
-
const va = a(state, a1, a2, a3);
|
|
283
|
-
return b(va, a1, a2, a3);
|
|
284
|
-
};
|
|
285
|
-
} else if (a) {
|
|
286
|
-
selector = a;
|
|
287
|
-
} else {
|
|
288
|
-
throw /* minify-error-disabled */new Error('Missing arguments');
|
|
289
|
-
}
|
|
290
|
-
return selector;
|
|
291
|
-
};
|
|
292
|
-
/* eslint-enable id-denylist */
|
|
293
|
-
|
|
294
204
|
var shim = {exports: {}};
|
|
295
205
|
|
|
296
206
|
var useSyncExternalStoreShim_production = {};
|
|
@@ -698,6 +608,41 @@ function getInstance() {
|
|
|
698
608
|
function register(hook) {
|
|
699
609
|
hooks.push(hook);
|
|
700
610
|
}
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Wraps a component function to enable performance optimizations for internal hooks.
|
|
614
|
+
*
|
|
615
|
+
* **Performance Optimization:**
|
|
616
|
+
* Components wrapped with `fastComponent` have access to a shared "instance" context that enables
|
|
617
|
+
* specialized hook implementations to batch operations and reduce overhead. The wrapper creates a
|
|
618
|
+
* stable instance object that persists across renders, sets it as the current context, calls
|
|
619
|
+
* registered hooks before and after rendering, then clears the context. The primary benefit is
|
|
620
|
+
* with `useStore`, where multiple store subscriptions within the same component are collapsed into
|
|
621
|
+
* a single `useSyncExternalStore` subscription per store, significantly reducing re-render overhead.
|
|
622
|
+
* This optimization is only active on React 19+; on earlier versions `useStore` falls back to a
|
|
623
|
+
* separate subscription per call.
|
|
624
|
+
*
|
|
625
|
+
* **Requirements:**
|
|
626
|
+
* - The component function should follow standard React component patterns
|
|
627
|
+
* - `useStore` calls must keep a stable order and count across renders, as batched hooks are
|
|
628
|
+
* matched by call index
|
|
629
|
+
* - Do not rely on the instance context outside of specialized hooks
|
|
630
|
+
*
|
|
631
|
+
* @param fn - The component function to wrap
|
|
632
|
+
* @returns A wrapped component with the same signature as the input function
|
|
633
|
+
*
|
|
634
|
+
* @example
|
|
635
|
+
* ```tsx
|
|
636
|
+
* // Wrapping a component to enable optimized useStore batching
|
|
637
|
+
* export const TooltipRoot = fastComponent(function TooltipRoot(props) {
|
|
638
|
+
* // These useStore calls share a single subscription
|
|
639
|
+
* const open = useStore(store, (state) => state.open);
|
|
640
|
+
* const disabled = useStore(store, (state) => state.disabled);
|
|
641
|
+
* const value = useStore(store, (state) => state.value);
|
|
642
|
+
* // ...
|
|
643
|
+
* });
|
|
644
|
+
* ```
|
|
645
|
+
*/
|
|
701
646
|
function fastComponent(fn) {
|
|
702
647
|
const FastComponent = (props, forwardedRef) => {
|
|
703
648
|
const instance = useRenderElement.useRefWithInit(createInstance).current;
|
|
@@ -720,6 +665,31 @@ function fastComponent(fn) {
|
|
|
720
665
|
FastComponent.displayName = fn.displayName || fn.name;
|
|
721
666
|
return FastComponent;
|
|
722
667
|
}
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Wraps a component function with ref forwarding to enable performance optimizations for internal hooks.
|
|
671
|
+
*
|
|
672
|
+
* This is a convenience wrapper that combines `fastComponent` with `React.forwardRef`, enabling
|
|
673
|
+
* both performance optimizations and proper ref forwarding. See `fastComponent` for details on
|
|
674
|
+
* the performance benefits.
|
|
675
|
+
*
|
|
676
|
+
* @param fn - The component function that accepts props and a forwarded ref
|
|
677
|
+
* @returns A wrapped component with ref forwarding enabled
|
|
678
|
+
*
|
|
679
|
+
* @example
|
|
680
|
+
* ```tsx
|
|
681
|
+
* // Wrapping a component with ref forwarding and optimized hooks
|
|
682
|
+
* export const TooltipTrigger = fastComponentRef(function TooltipTrigger(
|
|
683
|
+
* props,
|
|
684
|
+
* forwardedRef
|
|
685
|
+
* ) {
|
|
686
|
+
* const store = useContext(TooltipContext);
|
|
687
|
+
* const open = useStore(store, (state) => state.open);
|
|
688
|
+
* // ... component logic with ref
|
|
689
|
+
* return <button ref={forwardedRef} {...props} />;
|
|
690
|
+
* });
|
|
691
|
+
* ```
|
|
692
|
+
*/
|
|
723
693
|
function fastComponentRef(fn) {
|
|
724
694
|
return /*#__PURE__*/React__namespace.forwardRef(fastComponent(fn));
|
|
725
695
|
}
|
|
@@ -1135,6 +1105,170 @@ class ReactStore extends Store {
|
|
|
1135
1105
|
}
|
|
1136
1106
|
}
|
|
1137
1107
|
|
|
1108
|
+
function hasWindow() {
|
|
1109
|
+
return typeof window !== 'undefined';
|
|
1110
|
+
}
|
|
1111
|
+
function getNodeName(node) {
|
|
1112
|
+
if (isNode(node)) {
|
|
1113
|
+
return (node.nodeName || '').toLowerCase();
|
|
1114
|
+
}
|
|
1115
|
+
// Mocked nodes in testing environments may not be instances of Node. By
|
|
1116
|
+
// returning `#document` an infinite loop won't occur.
|
|
1117
|
+
// https://github.com/floating-ui/floating-ui/issues/2317
|
|
1118
|
+
return '#document';
|
|
1119
|
+
}
|
|
1120
|
+
function getWindow(node) {
|
|
1121
|
+
var _node$ownerDocument;
|
|
1122
|
+
return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window;
|
|
1123
|
+
}
|
|
1124
|
+
function getDocumentElement(node) {
|
|
1125
|
+
var _ref;
|
|
1126
|
+
return (_ref = (isNode(node) ? node.ownerDocument : node.document) || window.document) == null ? void 0 : _ref.documentElement;
|
|
1127
|
+
}
|
|
1128
|
+
function isNode(value) {
|
|
1129
|
+
if (!hasWindow()) {
|
|
1130
|
+
return false;
|
|
1131
|
+
}
|
|
1132
|
+
return value instanceof Node || value instanceof getWindow(value).Node;
|
|
1133
|
+
}
|
|
1134
|
+
function isElement(value) {
|
|
1135
|
+
if (!hasWindow()) {
|
|
1136
|
+
return false;
|
|
1137
|
+
}
|
|
1138
|
+
return value instanceof Element || value instanceof getWindow(value).Element;
|
|
1139
|
+
}
|
|
1140
|
+
function isHTMLElement(value) {
|
|
1141
|
+
if (!hasWindow()) {
|
|
1142
|
+
return false;
|
|
1143
|
+
}
|
|
1144
|
+
return value instanceof HTMLElement || value instanceof getWindow(value).HTMLElement;
|
|
1145
|
+
}
|
|
1146
|
+
function isShadowRoot(value) {
|
|
1147
|
+
if (!hasWindow() || typeof ShadowRoot === 'undefined') {
|
|
1148
|
+
return false;
|
|
1149
|
+
}
|
|
1150
|
+
return value instanceof ShadowRoot || value instanceof getWindow(value).ShadowRoot;
|
|
1151
|
+
}
|
|
1152
|
+
function isOverflowElement(element) {
|
|
1153
|
+
const {
|
|
1154
|
+
overflow,
|
|
1155
|
+
overflowX,
|
|
1156
|
+
overflowY,
|
|
1157
|
+
display
|
|
1158
|
+
} = getComputedStyle(element);
|
|
1159
|
+
return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && display !== 'inline' && display !== 'contents';
|
|
1160
|
+
}
|
|
1161
|
+
function isTableElement(element) {
|
|
1162
|
+
return /^(table|td|th)$/.test(getNodeName(element));
|
|
1163
|
+
}
|
|
1164
|
+
function isTopLayer(element) {
|
|
1165
|
+
try {
|
|
1166
|
+
if (element.matches(':popover-open')) {
|
|
1167
|
+
return true;
|
|
1168
|
+
}
|
|
1169
|
+
} catch (_e) {
|
|
1170
|
+
// no-op
|
|
1171
|
+
}
|
|
1172
|
+
try {
|
|
1173
|
+
return element.matches(':modal');
|
|
1174
|
+
} catch (_e) {
|
|
1175
|
+
return false;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
const willChangeRe = /transform|translate|scale|rotate|perspective|filter/;
|
|
1179
|
+
const containRe = /paint|layout|strict|content/;
|
|
1180
|
+
const isNotNone = value => !!value && value !== 'none';
|
|
1181
|
+
let isWebKitValue;
|
|
1182
|
+
function isContainingBlock(elementOrCss) {
|
|
1183
|
+
const css = isElement(elementOrCss) ? getComputedStyle(elementOrCss) : elementOrCss;
|
|
1184
|
+
|
|
1185
|
+
// https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
|
|
1186
|
+
// https://drafts.csswg.org/css-transforms-2/#individual-transforms
|
|
1187
|
+
return isNotNone(css.transform) || isNotNone(css.translate) || isNotNone(css.scale) || isNotNone(css.rotate) || isNotNone(css.perspective) || !isWebKit() && (isNotNone(css.backdropFilter) || isNotNone(css.filter)) || willChangeRe.test(css.willChange || '') || containRe.test(css.contain || '');
|
|
1188
|
+
}
|
|
1189
|
+
function getContainingBlock(element) {
|
|
1190
|
+
let currentNode = getParentNode(element);
|
|
1191
|
+
while (isHTMLElement(currentNode) && !isLastTraversableNode(currentNode)) {
|
|
1192
|
+
if (isContainingBlock(currentNode)) {
|
|
1193
|
+
return currentNode;
|
|
1194
|
+
} else if (isTopLayer(currentNode)) {
|
|
1195
|
+
return null;
|
|
1196
|
+
}
|
|
1197
|
+
currentNode = getParentNode(currentNode);
|
|
1198
|
+
}
|
|
1199
|
+
return null;
|
|
1200
|
+
}
|
|
1201
|
+
function isWebKit() {
|
|
1202
|
+
if (isWebKitValue == null) {
|
|
1203
|
+
isWebKitValue = typeof CSS !== 'undefined' && CSS.supports && CSS.supports('-webkit-backdrop-filter', 'none');
|
|
1204
|
+
}
|
|
1205
|
+
return isWebKitValue;
|
|
1206
|
+
}
|
|
1207
|
+
function isLastTraversableNode(node) {
|
|
1208
|
+
return /^(html|body|#document)$/.test(getNodeName(node));
|
|
1209
|
+
}
|
|
1210
|
+
function getComputedStyle(element) {
|
|
1211
|
+
return getWindow(element).getComputedStyle(element);
|
|
1212
|
+
}
|
|
1213
|
+
function getNodeScroll(element) {
|
|
1214
|
+
if (isElement(element)) {
|
|
1215
|
+
return {
|
|
1216
|
+
scrollLeft: element.scrollLeft,
|
|
1217
|
+
scrollTop: element.scrollTop
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
return {
|
|
1221
|
+
scrollLeft: element.scrollX,
|
|
1222
|
+
scrollTop: element.scrollY
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
function getParentNode(node) {
|
|
1226
|
+
if (getNodeName(node) === 'html') {
|
|
1227
|
+
return node;
|
|
1228
|
+
}
|
|
1229
|
+
const result =
|
|
1230
|
+
// Step into the shadow DOM of the parent of a slotted node.
|
|
1231
|
+
node.assignedSlot ||
|
|
1232
|
+
// DOM Element detected.
|
|
1233
|
+
node.parentNode ||
|
|
1234
|
+
// ShadowRoot detected.
|
|
1235
|
+
isShadowRoot(node) && node.host ||
|
|
1236
|
+
// Fallback.
|
|
1237
|
+
getDocumentElement(node);
|
|
1238
|
+
return isShadowRoot(result) ? result.host : result;
|
|
1239
|
+
}
|
|
1240
|
+
function getNearestOverflowAncestor(node) {
|
|
1241
|
+
const parentNode = getParentNode(node);
|
|
1242
|
+
if (isLastTraversableNode(parentNode)) {
|
|
1243
|
+
return (node.ownerDocument || node).body;
|
|
1244
|
+
}
|
|
1245
|
+
if (isHTMLElement(parentNode) && isOverflowElement(parentNode)) {
|
|
1246
|
+
return parentNode;
|
|
1247
|
+
}
|
|
1248
|
+
return getNearestOverflowAncestor(parentNode);
|
|
1249
|
+
}
|
|
1250
|
+
function getOverflowAncestors(node, list, traverseIframes) {
|
|
1251
|
+
var _node$ownerDocument2;
|
|
1252
|
+
if (list === void 0) {
|
|
1253
|
+
list = [];
|
|
1254
|
+
}
|
|
1255
|
+
if (traverseIframes === void 0) {
|
|
1256
|
+
traverseIframes = true;
|
|
1257
|
+
}
|
|
1258
|
+
const scrollableAncestor = getNearestOverflowAncestor(node);
|
|
1259
|
+
const isBody = scrollableAncestor === ((_node$ownerDocument2 = node.ownerDocument) == null ? void 0 : _node$ownerDocument2.body);
|
|
1260
|
+
const win = getWindow(scrollableAncestor);
|
|
1261
|
+
if (isBody) {
|
|
1262
|
+
const frameElement = getFrameElement(win);
|
|
1263
|
+
return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], frameElement && traverseIframes ? getOverflowAncestors(frameElement) : []);
|
|
1264
|
+
} else {
|
|
1265
|
+
return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes));
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
function getFrameElement(win) {
|
|
1269
|
+
return win.parent && Object.getPrototypeOf(win.parent) ? win.frameElement : null;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1138
1272
|
/**
|
|
1139
1273
|
* Combines multiple cleanup functions into a single cleanup function.
|
|
1140
1274
|
*/
|
|
@@ -1164,15 +1298,13 @@ function addEventListener(target, type, listener, options) {
|
|
|
1164
1298
|
};
|
|
1165
1299
|
}
|
|
1166
1300
|
|
|
1167
|
-
const EMPTY$2 = [];
|
|
1168
|
-
|
|
1169
1301
|
/**
|
|
1170
1302
|
* A React.useEffect equivalent that runs once, when the component is mounted.
|
|
1171
1303
|
*/
|
|
1172
1304
|
function useOnMount(fn) {
|
|
1173
1305
|
// 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
1306
|
/* eslint-disable react-hooks/exhaustive-deps */
|
|
1175
|
-
React__namespace.useEffect(fn,
|
|
1307
|
+
React__namespace.useEffect(fn, useRenderElement.EMPTY_ARRAY);
|
|
1176
1308
|
/* eslint-enable react-hooks/exhaustive-deps */
|
|
1177
1309
|
}
|
|
1178
1310
|
|
|
@@ -1236,7 +1368,7 @@ class Scheduler {
|
|
|
1236
1368
|
this.callbacksCount -= 1;
|
|
1237
1369
|
}
|
|
1238
1370
|
}
|
|
1239
|
-
|
|
1371
|
+
let scheduler = new Scheduler();
|
|
1240
1372
|
class AnimationFrame {
|
|
1241
1373
|
static create() {
|
|
1242
1374
|
return new AnimationFrame();
|
|
@@ -1483,7 +1615,7 @@ function contains(parent, child) {
|
|
|
1483
1615
|
}
|
|
1484
1616
|
|
|
1485
1617
|
// Then fall back to traversing out of shadow roots when needed.
|
|
1486
|
-
if (rootNode &&
|
|
1618
|
+
if (rootNode && isShadowRoot(rootNode)) {
|
|
1487
1619
|
let next = child;
|
|
1488
1620
|
while (next) {
|
|
1489
1621
|
if (parent === next) {
|
|
@@ -1505,7 +1637,7 @@ function getTarget(event) {
|
|
|
1505
1637
|
}
|
|
1506
1638
|
|
|
1507
1639
|
function isTargetInsideEnabledTrigger(target, triggerElements) {
|
|
1508
|
-
if (!
|
|
1640
|
+
if (!isElement(target)) {
|
|
1509
1641
|
return false;
|
|
1510
1642
|
}
|
|
1511
1643
|
const targetElement = target;
|
|
@@ -1535,7 +1667,7 @@ function isRootElement(element) {
|
|
|
1535
1667
|
return element.matches('html,body');
|
|
1536
1668
|
}
|
|
1537
1669
|
function isTypeableElement(element) {
|
|
1538
|
-
return
|
|
1670
|
+
return isHTMLElement(element) && element.matches(TYPEABLE_SELECTOR);
|
|
1539
1671
|
}
|
|
1540
1672
|
function isInteractiveElement(element) {
|
|
1541
1673
|
return element?.closest(`button,a[href],[role="button"],select,[tabindex]:not([tabindex="-1"]),${TYPEABLE_SELECTOR}`) != null;
|
|
@@ -1676,6 +1808,138 @@ const FocusGuard = /*#__PURE__*/React__namespace.forwardRef(function FocusGuard(
|
|
|
1676
1808
|
});
|
|
1677
1809
|
if (process.env.NODE_ENV !== "production") FocusGuard.displayName = "FocusGuard";
|
|
1678
1810
|
|
|
1811
|
+
/**
|
|
1812
|
+
* Custom positioning reference element.
|
|
1813
|
+
* @see https://floating-ui.com/docs/virtual-elements
|
|
1814
|
+
*/
|
|
1815
|
+
|
|
1816
|
+
const min = Math.min;
|
|
1817
|
+
const max = Math.max;
|
|
1818
|
+
const round = Math.round;
|
|
1819
|
+
const floor = Math.floor;
|
|
1820
|
+
const createCoords = v => ({
|
|
1821
|
+
x: v,
|
|
1822
|
+
y: v
|
|
1823
|
+
});
|
|
1824
|
+
const oppositeSideMap = {
|
|
1825
|
+
left: 'right',
|
|
1826
|
+
right: 'left',
|
|
1827
|
+
bottom: 'top',
|
|
1828
|
+
top: 'bottom'
|
|
1829
|
+
};
|
|
1830
|
+
function clamp(start, value, end) {
|
|
1831
|
+
return max(start, min(value, end));
|
|
1832
|
+
}
|
|
1833
|
+
function evaluate(value, param) {
|
|
1834
|
+
return typeof value === 'function' ? value(param) : value;
|
|
1835
|
+
}
|
|
1836
|
+
function getSide(placement) {
|
|
1837
|
+
return placement.split('-')[0];
|
|
1838
|
+
}
|
|
1839
|
+
function getAlignment(placement) {
|
|
1840
|
+
return placement.split('-')[1];
|
|
1841
|
+
}
|
|
1842
|
+
function getOppositeAxis(axis) {
|
|
1843
|
+
return axis === 'x' ? 'y' : 'x';
|
|
1844
|
+
}
|
|
1845
|
+
function getAxisLength(axis) {
|
|
1846
|
+
return axis === 'y' ? 'height' : 'width';
|
|
1847
|
+
}
|
|
1848
|
+
function getSideAxis(placement) {
|
|
1849
|
+
const firstChar = placement[0];
|
|
1850
|
+
return firstChar === 't' || firstChar === 'b' ? 'y' : 'x';
|
|
1851
|
+
}
|
|
1852
|
+
function getAlignmentAxis(placement) {
|
|
1853
|
+
return getOppositeAxis(getSideAxis(placement));
|
|
1854
|
+
}
|
|
1855
|
+
function getAlignmentSides(placement, rects, rtl) {
|
|
1856
|
+
if (rtl === void 0) {
|
|
1857
|
+
rtl = false;
|
|
1858
|
+
}
|
|
1859
|
+
const alignment = getAlignment(placement);
|
|
1860
|
+
const alignmentAxis = getAlignmentAxis(placement);
|
|
1861
|
+
const length = getAxisLength(alignmentAxis);
|
|
1862
|
+
let mainAlignmentSide = alignmentAxis === 'x' ? alignment === (rtl ? 'end' : 'start') ? 'right' : 'left' : alignment === 'start' ? 'bottom' : 'top';
|
|
1863
|
+
if (rects.reference[length] > rects.floating[length]) {
|
|
1864
|
+
mainAlignmentSide = getOppositePlacement(mainAlignmentSide);
|
|
1865
|
+
}
|
|
1866
|
+
return [mainAlignmentSide, getOppositePlacement(mainAlignmentSide)];
|
|
1867
|
+
}
|
|
1868
|
+
function getExpandedPlacements(placement) {
|
|
1869
|
+
const oppositePlacement = getOppositePlacement(placement);
|
|
1870
|
+
return [getOppositeAlignmentPlacement(placement), oppositePlacement, getOppositeAlignmentPlacement(oppositePlacement)];
|
|
1871
|
+
}
|
|
1872
|
+
function getOppositeAlignmentPlacement(placement) {
|
|
1873
|
+
return placement.includes('start') ? placement.replace('start', 'end') : placement.replace('end', 'start');
|
|
1874
|
+
}
|
|
1875
|
+
const lrPlacement = ['left', 'right'];
|
|
1876
|
+
const rlPlacement = ['right', 'left'];
|
|
1877
|
+
const tbPlacement = ['top', 'bottom'];
|
|
1878
|
+
const btPlacement = ['bottom', 'top'];
|
|
1879
|
+
function getSideList(side, isStart, rtl) {
|
|
1880
|
+
switch (side) {
|
|
1881
|
+
case 'top':
|
|
1882
|
+
case 'bottom':
|
|
1883
|
+
if (rtl) return isStart ? rlPlacement : lrPlacement;
|
|
1884
|
+
return isStart ? lrPlacement : rlPlacement;
|
|
1885
|
+
case 'left':
|
|
1886
|
+
case 'right':
|
|
1887
|
+
return isStart ? tbPlacement : btPlacement;
|
|
1888
|
+
default:
|
|
1889
|
+
return [];
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
function getOppositeAxisPlacements(placement, flipAlignment, direction, rtl) {
|
|
1893
|
+
const alignment = getAlignment(placement);
|
|
1894
|
+
let list = getSideList(getSide(placement), direction === 'start', rtl);
|
|
1895
|
+
if (alignment) {
|
|
1896
|
+
list = list.map(side => side + "-" + alignment);
|
|
1897
|
+
if (flipAlignment) {
|
|
1898
|
+
list = list.concat(list.map(getOppositeAlignmentPlacement));
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
return list;
|
|
1902
|
+
}
|
|
1903
|
+
function getOppositePlacement(placement) {
|
|
1904
|
+
const side = getSide(placement);
|
|
1905
|
+
return oppositeSideMap[side] + placement.slice(side.length);
|
|
1906
|
+
}
|
|
1907
|
+
function expandPaddingObject(padding) {
|
|
1908
|
+
var _padding$top, _padding$right, _padding$bottom, _padding$left;
|
|
1909
|
+
return {
|
|
1910
|
+
top: (_padding$top = padding.top) != null ? _padding$top : 0,
|
|
1911
|
+
right: (_padding$right = padding.right) != null ? _padding$right : 0,
|
|
1912
|
+
bottom: (_padding$bottom = padding.bottom) != null ? _padding$bottom : 0,
|
|
1913
|
+
left: (_padding$left = padding.left) != null ? _padding$left : 0
|
|
1914
|
+
};
|
|
1915
|
+
}
|
|
1916
|
+
function getPaddingObject(padding) {
|
|
1917
|
+
return typeof padding !== 'number' ? expandPaddingObject(padding) : {
|
|
1918
|
+
top: padding,
|
|
1919
|
+
right: padding,
|
|
1920
|
+
bottom: padding,
|
|
1921
|
+
left: padding
|
|
1922
|
+
};
|
|
1923
|
+
}
|
|
1924
|
+
function rectToClientRect(rect) {
|
|
1925
|
+
const {
|
|
1926
|
+
x,
|
|
1927
|
+
y,
|
|
1928
|
+
width,
|
|
1929
|
+
height
|
|
1930
|
+
} = rect;
|
|
1931
|
+
return {
|
|
1932
|
+
width,
|
|
1933
|
+
height,
|
|
1934
|
+
top: y,
|
|
1935
|
+
left: x,
|
|
1936
|
+
right: x + width,
|
|
1937
|
+
bottom: y + height,
|
|
1938
|
+
x,
|
|
1939
|
+
y
|
|
1940
|
+
};
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1679
1943
|
function isDifferentGridRow(index, cols, prevRow) {
|
|
1680
1944
|
return Math.floor(index / cols) !== prevRow;
|
|
1681
1945
|
}
|
|
@@ -1811,7 +2075,7 @@ function getGridNavigatedIndex(list, {
|
|
|
1811
2075
|
const colInRow = prevIndex % verticalCols;
|
|
1812
2076
|
const rowStep = direction === 'up' ? -verticalCols : verticalCols;
|
|
1813
2077
|
const lastRowStart = maxIndex - maxIndex % verticalCols;
|
|
1814
|
-
const rowCount =
|
|
2078
|
+
const rowCount = floor(maxIndex / verticalCols) + 1;
|
|
1815
2079
|
for (let rowStart = prevIndex - colInRow + rowStep, i = 0; i < rowCount; i += 1, rowStart += rowStep) {
|
|
1816
2080
|
if (rowStart < 0 || rowStart > maxIndex) {
|
|
1817
2081
|
if (!loopFocus) {
|
|
@@ -1876,7 +2140,7 @@ function getGridNavigatedIndex(list, {
|
|
|
1876
2140
|
|
|
1877
2141
|
// Remains on the same row/column.
|
|
1878
2142
|
if (orientation === 'both') {
|
|
1879
|
-
const prevRow =
|
|
2143
|
+
const prevRow = floor(prevIndex / cols);
|
|
1880
2144
|
if (event.key === (rtl ? ARROW_LEFT : ARROW_RIGHT)) {
|
|
1881
2145
|
if (stop) {
|
|
1882
2146
|
stopEvent(event);
|
|
@@ -1942,7 +2206,7 @@ function getGridNavigatedIndex(list, {
|
|
|
1942
2206
|
nextIndex = prevIndex;
|
|
1943
2207
|
}
|
|
1944
2208
|
}
|
|
1945
|
-
const lastRow =
|
|
2209
|
+
const lastRow = floor(maxIndex / cols) === prevRow;
|
|
1946
2210
|
if (isIndexOutOfListBounds(list, nextIndex)) {
|
|
1947
2211
|
if (loopFocus && lastRow) {
|
|
1948
2212
|
nextIndex = event.key === (rtl ? ARROW_RIGHT : ARROW_LEFT) ? maxIndex : findNonDisabledListIndex(list, {
|
|
@@ -1971,12 +2235,19 @@ function isListIndexDisabled(list, index, disabledIndices) {
|
|
|
1971
2235
|
if (!isElementVisible(element)) {
|
|
1972
2236
|
return true;
|
|
1973
2237
|
}
|
|
2238
|
+
|
|
2239
|
+
// A natively disabled element can never receive focus, so it must always be
|
|
2240
|
+
// skipped, even when `disabledIndices` marks it as enabled. Only
|
|
2241
|
+
// `aria-disabled` items can be focusable-while-disabled.
|
|
2242
|
+
if (element.matches(':disabled')) {
|
|
2243
|
+
return true;
|
|
2244
|
+
}
|
|
1974
2245
|
return !disabledIndices && (element.hasAttribute('disabled') || element.getAttribute('aria-disabled') === 'true');
|
|
1975
2246
|
}
|
|
1976
2247
|
function isHiddenByStyles(styles) {
|
|
1977
2248
|
return styles.visibility === 'hidden' || styles.visibility === 'collapse';
|
|
1978
2249
|
}
|
|
1979
|
-
function isElementVisible(element, styles = element ?
|
|
2250
|
+
function isElementVisible(element, styles = element ? getComputedStyle(element) : null) {
|
|
1980
2251
|
if (!element || !element.isConnected || !styles || isHiddenByStyles(styles)) {
|
|
1981
2252
|
return false;
|
|
1982
2253
|
}
|
|
@@ -1996,11 +2267,11 @@ function getParentElement(element) {
|
|
|
1996
2267
|
return element.parentElement;
|
|
1997
2268
|
}
|
|
1998
2269
|
const rootNode = element.getRootNode();
|
|
1999
|
-
return
|
|
2270
|
+
return isShadowRoot(rootNode) ? rootNode.host : null;
|
|
2000
2271
|
}
|
|
2001
2272
|
function getDetailsSummary(details) {
|
|
2002
2273
|
for (const child of Array.from(details.children)) {
|
|
2003
|
-
if (
|
|
2274
|
+
if (getNodeName(child) === 'summary') {
|
|
2004
2275
|
return child;
|
|
2005
2276
|
}
|
|
2006
2277
|
}
|
|
@@ -2011,8 +2282,8 @@ function isWithinOpenDetailsSummary(element, details) {
|
|
|
2011
2282
|
return !!summary && (element === summary || contains(summary, element));
|
|
2012
2283
|
}
|
|
2013
2284
|
function isFocusableCandidate(element) {
|
|
2014
|
-
const nodeName = element ?
|
|
2015
|
-
return element != null && element.matches(CANDIDATE_SELECTOR) && (nodeName !== 'summary' || element.parentElement != null &&
|
|
2285
|
+
const nodeName = element ? getNodeName(element) : '';
|
|
2286
|
+
return element != null && element.matches(CANDIDATE_SELECTOR) && (nodeName !== 'summary' || element.parentElement != null && getNodeName(element.parentElement) === 'details' && getDetailsSummary(element.parentElement) === element) && (nodeName !== 'details' || getDetailsSummary(element) == null) && (nodeName !== 'input' || element.type !== 'hidden');
|
|
2016
2287
|
}
|
|
2017
2288
|
function isFocusableElement(element) {
|
|
2018
2289
|
if (!isFocusableCandidate(element) || !element.isConnected || element.matches(':disabled')) {
|
|
@@ -2020,18 +2291,18 @@ function isFocusableElement(element) {
|
|
|
2020
2291
|
}
|
|
2021
2292
|
for (let current = element; current; current = getParentElement(current)) {
|
|
2022
2293
|
const isAncestor = current !== element;
|
|
2023
|
-
const isSlot =
|
|
2294
|
+
const isSlot = getNodeName(current) === 'slot';
|
|
2024
2295
|
if (current.hasAttribute('inert')) {
|
|
2025
2296
|
return false;
|
|
2026
2297
|
}
|
|
2027
|
-
if (isAncestor &&
|
|
2298
|
+
if (isAncestor && getNodeName(current) === 'details' && !current.open && !isWithinOpenDetailsSummary(element, current) || current.hasAttribute('hidden') || !isSlot && !isVisibleInTabbableTree(current, isAncestor)) {
|
|
2028
2299
|
return false;
|
|
2029
2300
|
}
|
|
2030
2301
|
}
|
|
2031
2302
|
return true;
|
|
2032
2303
|
}
|
|
2033
2304
|
function isVisibleInTabbableTree(element, isAncestor) {
|
|
2034
|
-
const styles =
|
|
2305
|
+
const styles = getComputedStyle(element);
|
|
2035
2306
|
if (!isAncestor) {
|
|
2036
2307
|
return isElementVisible(element, styles);
|
|
2037
2308
|
}
|
|
@@ -2040,15 +2311,15 @@ function isVisibleInTabbableTree(element, isAncestor) {
|
|
|
2040
2311
|
function getTabIndex(element) {
|
|
2041
2312
|
const tabIndex = element.tabIndex;
|
|
2042
2313
|
if (tabIndex < 0) {
|
|
2043
|
-
const nodeName =
|
|
2044
|
-
if (nodeName === 'details' || nodeName === 'audio' || nodeName === 'video' ||
|
|
2314
|
+
const nodeName = getNodeName(element);
|
|
2315
|
+
if (nodeName === 'details' || nodeName === 'audio' || nodeName === 'video' || isHTMLElement(element) && element.isContentEditable) {
|
|
2045
2316
|
return 0;
|
|
2046
2317
|
}
|
|
2047
2318
|
}
|
|
2048
2319
|
return tabIndex;
|
|
2049
2320
|
}
|
|
2050
2321
|
function getNamedRadioInput(element) {
|
|
2051
|
-
if (
|
|
2322
|
+
if (getNodeName(element) !== 'input') {
|
|
2052
2323
|
return null;
|
|
2053
2324
|
}
|
|
2054
2325
|
const input = element;
|
|
@@ -2072,7 +2343,7 @@ function isTabbableRadio(element, candidates) {
|
|
|
2072
2343
|
}) === input;
|
|
2073
2344
|
}
|
|
2074
2345
|
function getComposedChildren(container) {
|
|
2075
|
-
if (
|
|
2346
|
+
if (isHTMLElement(container) && getNodeName(container) === 'slot') {
|
|
2076
2347
|
const assignedElements = container.assignedElements({
|
|
2077
2348
|
flatten: true
|
|
2078
2349
|
});
|
|
@@ -2080,7 +2351,7 @@ function getComposedChildren(container) {
|
|
|
2080
2351
|
return assignedElements;
|
|
2081
2352
|
}
|
|
2082
2353
|
}
|
|
2083
|
-
if (
|
|
2354
|
+
if (isHTMLElement(container) && container.shadowRoot) {
|
|
2084
2355
|
return Array.from(container.shadowRoot.children);
|
|
2085
2356
|
}
|
|
2086
2357
|
return Array.from(container.children);
|
|
@@ -2095,7 +2366,7 @@ function appendCandidates(container, list) {
|
|
|
2095
2366
|
}
|
|
2096
2367
|
function appendMatchingElements(container, selector, list) {
|
|
2097
2368
|
getComposedChildren(container).forEach(child => {
|
|
2098
|
-
if (
|
|
2369
|
+
if (isHTMLElement(child) && child.matches(selector)) {
|
|
2099
2370
|
list.push(child);
|
|
2100
2371
|
}
|
|
2101
2372
|
appendMatchingElements(child, selector, list);
|
|
@@ -2252,7 +2523,7 @@ function unwrapHost(node) {
|
|
|
2252
2523
|
if (!node) {
|
|
2253
2524
|
return null;
|
|
2254
2525
|
}
|
|
2255
|
-
return
|
|
2526
|
+
return isShadowRoot(node) ? node.host : unwrapHost(node.parentNode);
|
|
2256
2527
|
}
|
|
2257
2528
|
const correctElements = (parent, targets) => targets.map(target => {
|
|
2258
2529
|
if (parent.contains(target)) {
|
|
@@ -2282,7 +2553,7 @@ const collectOutsideElements = (root, keepElements, stopElements) => {
|
|
|
2282
2553
|
return;
|
|
2283
2554
|
}
|
|
2284
2555
|
Array.from(parent.children).forEach(node => {
|
|
2285
|
-
if (
|
|
2556
|
+
if (getNodeName(node) === 'script') {
|
|
2286
2557
|
return;
|
|
2287
2558
|
}
|
|
2288
2559
|
if (keepElements.has(node)) {
|
|
@@ -2501,12 +2772,7 @@ function useFloatingPortalNode(props = {}) {
|
|
|
2501
2772
|
}
|
|
2502
2773
|
return;
|
|
2503
2774
|
}
|
|
2504
|
-
|
|
2505
|
-
// React 17 does not use React.useId().
|
|
2506
|
-
if (uniqueId == null) {
|
|
2507
|
-
return;
|
|
2508
|
-
}
|
|
2509
|
-
const resolvedContainer = (containerProp && (floatingUi_utils.isNode(containerProp) ? containerProp : containerProp.current)) ?? parentPortalNode ?? document.body;
|
|
2775
|
+
const resolvedContainer = (containerProp && (isNode(containerProp) ? containerProp : containerProp.current)) ?? parentPortalNode ?? document.body;
|
|
2510
2776
|
if (resolvedContainer == null) {
|
|
2511
2777
|
if (containerRef.current) {
|
|
2512
2778
|
containerRef.current = null;
|
|
@@ -2520,7 +2786,7 @@ function useFloatingPortalNode(props = {}) {
|
|
|
2520
2786
|
setPortalNode(null);
|
|
2521
2787
|
setContainerElement(resolvedContainer);
|
|
2522
2788
|
}
|
|
2523
|
-
}, [containerProp, parentPortalNode
|
|
2789
|
+
}, [containerProp, parentPortalNode]);
|
|
2524
2790
|
const portalElement = useRenderElement.useRenderElement('div', componentProps, {
|
|
2525
2791
|
ref: [ref, setPortalNodeRef],
|
|
2526
2792
|
props: [{
|
|
@@ -2533,8 +2799,11 @@ function useFloatingPortalNode(props = {}) {
|
|
|
2533
2799
|
// Another call inside `FloatingPortal`/`FloatingPortalLite` then injects the children into `portalElement`.
|
|
2534
2800
|
const portalSubtree = containerElement && portalElement ? /*#__PURE__*/ReactDOM__namespace.createPortal(portalElement, containerElement) : null;
|
|
2535
2801
|
return {
|
|
2536
|
-
portalNode,
|
|
2537
|
-
|
|
2802
|
+
node: portalNode,
|
|
2803
|
+
// `id` and `render` props can override or remove the generated ID. Use the exact
|
|
2804
|
+
// rendered value so `aria-owns` never points at an ID absent from the DOM.
|
|
2805
|
+
nodeId: /*#__PURE__*/React__namespace.isValidElement(portalElement) ? portalElement.props.id : undefined,
|
|
2806
|
+
subtree: portalSubtree
|
|
2538
2807
|
};
|
|
2539
2808
|
}
|
|
2540
2809
|
|
|
@@ -2554,12 +2823,12 @@ const FloatingPortal = /*#__PURE__*/React__namespace.forwardRef(function Floatin
|
|
|
2554
2823
|
style,
|
|
2555
2824
|
children,
|
|
2556
2825
|
container,
|
|
2557
|
-
renderGuards,
|
|
2558
2826
|
...elementProps
|
|
2559
2827
|
} = componentProps;
|
|
2560
2828
|
const {
|
|
2561
|
-
portalNode,
|
|
2562
|
-
|
|
2829
|
+
node: portalNode,
|
|
2830
|
+
nodeId: portalNodeId,
|
|
2831
|
+
subtree: portalSubtree
|
|
2563
2832
|
} = useFloatingPortalNode({
|
|
2564
2833
|
container,
|
|
2565
2834
|
ref: forwardedRef,
|
|
@@ -2574,7 +2843,7 @@ const FloatingPortal = /*#__PURE__*/React__namespace.forwardRef(function Floatin
|
|
|
2574
2843
|
const focusInsideDisabledRef = React__namespace.useRef(false);
|
|
2575
2844
|
const modal = focusManagerState?.modal;
|
|
2576
2845
|
const open = focusManagerState?.open;
|
|
2577
|
-
const shouldRenderGuards =
|
|
2846
|
+
const shouldRenderGuards = !!focusManagerState && !focusManagerState.modal && focusManagerState.open && !!portalNode;
|
|
2578
2847
|
|
|
2579
2848
|
// https://codesandbox.io/s/tabbable-portal-f4tng?file=/src/TabbablePortal.tsx
|
|
2580
2849
|
React__namespace.useEffect(() => {
|
|
@@ -2636,7 +2905,7 @@ const FloatingPortal = /*#__PURE__*/React__namespace.forwardRef(function Floatin
|
|
|
2636
2905
|
}
|
|
2637
2906
|
}
|
|
2638
2907
|
}), shouldRenderGuards && portalNode && /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
2639
|
-
"aria-owns":
|
|
2908
|
+
"aria-owns": portalNodeId,
|
|
2640
2909
|
style: ownerVisuallyHidden
|
|
2641
2910
|
}), portalNode && /*#__PURE__*/ReactDOM__namespace.createPortal(children, portalNode), shouldRenderGuards && portalNode && /*#__PURE__*/jsxRuntime.jsx(FocusGuard, {
|
|
2642
2911
|
"data-type": "outside",
|
|
@@ -2793,7 +3062,7 @@ function resolveRef(maybeRef) {
|
|
|
2793
3062
|
}
|
|
2794
3063
|
|
|
2795
3064
|
function getEventType(event, lastInteractionType) {
|
|
2796
|
-
const win =
|
|
3065
|
+
const win = getWindow(getTarget(event));
|
|
2797
3066
|
if (event instanceof win.KeyboardEvent) {
|
|
2798
3067
|
return 'keyboard';
|
|
2799
3068
|
}
|
|
@@ -2823,7 +3092,7 @@ function clearDisconnectedPreviouslyFocusedElements() {
|
|
|
2823
3092
|
}
|
|
2824
3093
|
function addPreviouslyFocusedElement(element) {
|
|
2825
3094
|
clearDisconnectedPreviouslyFocusedElements();
|
|
2826
|
-
if (element &&
|
|
3095
|
+
if (element && getNodeName(element) !== 'body') {
|
|
2827
3096
|
previouslyFocusedElements.push(new WeakRef(element));
|
|
2828
3097
|
if (previouslyFocusedElements.length > LIST_LIMIT) {
|
|
2829
3098
|
previouslyFocusedElements = previouslyFocusedElements.slice(-LIST_LIMIT);
|
|
@@ -2900,11 +3169,10 @@ function FloatingFocusManager(props) {
|
|
|
2900
3169
|
} = store.context;
|
|
2901
3170
|
const getNodeId = useStableCallback(() => dataRef.current.floatingContext?.nodeId);
|
|
2902
3171
|
const ignoreInitialFocus = initialFocus === false;
|
|
2903
|
-
//
|
|
2904
|
-
//
|
|
2905
|
-
//
|
|
2906
|
-
//
|
|
2907
|
-
// start.
|
|
3172
|
+
// A typeable combobox reference (e.g. input/textarea) with `initialFocus={false}`
|
|
3173
|
+
// has different focus semantics: focus is not trapped inside the floating element,
|
|
3174
|
+
// so in the modal case the guards are not rendered, but `aria-hidden` is still
|
|
3175
|
+
// applied to the outside nodes.
|
|
2908
3176
|
const isUntrappedTypeableCombobox = isTypeableCombobox(domReference) && ignoreInitialFocus;
|
|
2909
3177
|
const initialFocusRef = useValueAsRef(initialFocus);
|
|
2910
3178
|
const returnFocusRef = useValueAsRef(returnFocus);
|
|
@@ -3018,25 +3286,25 @@ function FloatingFocusManager(props) {
|
|
|
3018
3286
|
const triggers = store.context.triggerElements;
|
|
3019
3287
|
const insideElements = getResolvedInsideElements();
|
|
3020
3288
|
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)) ||
|
|
3289
|
+
const movedToUnrelatedNode = !(contains(domReference, relatedTarget) || contains(floating, relatedTarget) || contains(relatedTarget, floating) || contains(portalContext?.portalNode, relatedTarget) || insideElements.some(element => element === relatedTarget || contains(element, 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)));
|
|
3022
3290
|
if (currentTarget === domReference && floatingFocusElement) {
|
|
3023
3291
|
handleTabIndex(floatingFocusElement);
|
|
3024
3292
|
}
|
|
3025
3293
|
|
|
3026
|
-
// Restore focus to the
|
|
3294
|
+
// Restore focus to the previously focused tabbable element to prevent
|
|
3027
3295
|
// focus from being lost outside the floating tree.
|
|
3028
3296
|
if (restoreFocus && currentTarget !== domReference && !isElementVisible(target) && activeElement(doc) === doc.body) {
|
|
3029
3297
|
// Let `FloatingPortal` effect knows that focus is still inside the
|
|
3030
3298
|
// floating tree.
|
|
3031
|
-
if (
|
|
3299
|
+
if (isHTMLElement(floatingFocusElement)) {
|
|
3032
3300
|
floatingFocusElement.focus();
|
|
3033
3301
|
// If explicitly requested to restore focus to the popup container, do not search
|
|
3034
3302
|
// for the next/previous tabbable element.
|
|
3035
3303
|
if (restoreFocus === 'popup') {
|
|
3036
|
-
// If the element is removed on pointerdown,
|
|
3037
|
-
//
|
|
3038
|
-
//
|
|
3039
|
-
//
|
|
3304
|
+
// If the focused element is removed on pointerdown, the browser
|
|
3305
|
+
// tries to move focus to it right after the `.focus()` call above,
|
|
3306
|
+
// but because it's removed in the same tick, focus is lost instead.
|
|
3307
|
+
// Re-focusing asynchronously (next frame) wins that race.
|
|
3040
3308
|
restoreFocusFrame.request(() => {
|
|
3041
3309
|
floatingFocusElement.focus();
|
|
3042
3310
|
});
|
|
@@ -3046,7 +3314,7 @@ function FloatingFocusManager(props) {
|
|
|
3046
3314
|
const tabbableContent = getTabbableContent();
|
|
3047
3315
|
const prevTabbable = lastFocusedTabbableRef.current;
|
|
3048
3316
|
const nodeToFocus = (prevTabbable && tabbableContent.includes(prevTabbable) ? prevTabbable : null) || tabbableContent[tabbableContent.length - 1] || floatingFocusElement;
|
|
3049
|
-
if (
|
|
3317
|
+
if (isHTMLElement(nodeToFocus)) {
|
|
3050
3318
|
nodeToFocus.focus();
|
|
3051
3319
|
}
|
|
3052
3320
|
}
|
|
@@ -3082,7 +3350,7 @@ function FloatingFocusManager(props) {
|
|
|
3082
3350
|
dataRef.current.insideReactTree = false;
|
|
3083
3351
|
});
|
|
3084
3352
|
}
|
|
3085
|
-
const domReferenceElement =
|
|
3353
|
+
const domReferenceElement = isHTMLElement(domReference) ? domReference : null;
|
|
3086
3354
|
if (!floating && !domReferenceElement) {
|
|
3087
3355
|
return undefined;
|
|
3088
3356
|
}
|
|
@@ -3115,9 +3383,11 @@ function FloatingFocusManager(props) {
|
|
|
3115
3383
|
|
|
3116
3384
|
// Focus the initial element when the floating element opens.
|
|
3117
3385
|
useIsoLayoutEffect(() => {
|
|
3118
|
-
if (!open || disabled || !
|
|
3386
|
+
if (!open || disabled || !isHTMLElement(floatingFocusElement)) {
|
|
3119
3387
|
return;
|
|
3120
3388
|
}
|
|
3389
|
+
closeTypeRef.current = '';
|
|
3390
|
+
lastInteractionTypeRef.current = '';
|
|
3121
3391
|
const doc = ownerDocument(floatingFocusElement);
|
|
3122
3392
|
const previouslyFocusedElement = activeElement(doc);
|
|
3123
3393
|
|
|
@@ -3149,7 +3419,9 @@ function FloatingFocusManager(props) {
|
|
|
3149
3419
|
}
|
|
3150
3420
|
elToFocus = elToFocus || getDefaultFocusElement();
|
|
3151
3421
|
const hadFocusInside = contains(floatingFocusElement, activeElement(doc));
|
|
3152
|
-
|
|
3422
|
+
|
|
3423
|
+
// enqueueFocus returns a rAF-cancel function; we intentionally don't cancel this focus.
|
|
3424
|
+
void enqueueFocus(elToFocus, {
|
|
3153
3425
|
preventScroll: elToFocus === floatingFocusElement,
|
|
3154
3426
|
shouldFocus() {
|
|
3155
3427
|
// This focus is queued on the next animation frame. If the floating element has closed
|
|
@@ -3176,13 +3448,11 @@ function FloatingFocusManager(props) {
|
|
|
3176
3448
|
}
|
|
3177
3449
|
const doc = ownerDocument(floatingFocusElement);
|
|
3178
3450
|
const elementFocusedBeforeOpen = activeElement(doc);
|
|
3179
|
-
// Only
|
|
3180
|
-
//
|
|
3451
|
+
// Only an explicit `null` interaction type represents a programmatic open.
|
|
3452
|
+
// `undefined` is normalized to `''` by the prop default, so it never reaches
|
|
3453
|
+
// here as nullish and is intentionally not treated as programmatic.
|
|
3181
3454
|
const preferPreviousFocus = openInteractionTypeRef.current == null;
|
|
3182
3455
|
addPreviouslyFocusedElement(elementFocusedBeforeOpen);
|
|
3183
|
-
|
|
3184
|
-
// Dismissing via outside press should always ignore `returnFocus` to
|
|
3185
|
-
// prevent unwanted scrolling.
|
|
3186
3456
|
function onOpenChangeLocal(details) {
|
|
3187
3457
|
if (!details.open) {
|
|
3188
3458
|
closeTypeRef.current = getEventType(details.nativeEvent, lastInteractionTypeRef.current);
|
|
@@ -3198,6 +3468,11 @@ function FloatingFocusManager(props) {
|
|
|
3198
3468
|
} else if (isVirtualClick(details.nativeEvent) || isVirtualPointerEvent(details.nativeEvent)) {
|
|
3199
3469
|
preventReturnFocusRef.current = false;
|
|
3200
3470
|
} else {
|
|
3471
|
+
// On outside press, only return focus to the reference when the browser supports the
|
|
3472
|
+
// `focus({ preventScroll })` option; without it, restoring focus scrolls the page.
|
|
3473
|
+
// Chrome on Android and Samsung Internet still don't support `preventScroll`
|
|
3474
|
+
// (https://issues.chromium.org/issues/41453122), so the runtime check keeps return
|
|
3475
|
+
// focus disabled there to avoid the scroll jump.
|
|
3201
3476
|
let isPreventScrollSupported = false;
|
|
3202
3477
|
ownerDocument(floatingFocusElement).createElement('div').focus({
|
|
3203
3478
|
get preventScroll() {
|
|
@@ -3213,9 +3488,9 @@ function FloatingFocusManager(props) {
|
|
|
3213
3488
|
}
|
|
3214
3489
|
}
|
|
3215
3490
|
events.on('openchange', onOpenChangeLocal);
|
|
3216
|
-
function getReturnElement() {
|
|
3491
|
+
function getReturnElement(closeType) {
|
|
3217
3492
|
const returnFocusValueOrFn = returnFocusRef.current;
|
|
3218
|
-
let resolvedReturnFocusValue = typeof returnFocusValueOrFn === 'function' ? returnFocusValueOrFn(
|
|
3493
|
+
let resolvedReturnFocusValue = typeof returnFocusValueOrFn === 'function' ? returnFocusValueOrFn(closeType) : returnFocusValueOrFn;
|
|
3219
3494
|
|
|
3220
3495
|
// `null` should fallback to default behavior in case of an empty ref.
|
|
3221
3496
|
if (resolvedReturnFocusValue === undefined || resolvedReturnFocusValue === false) {
|
|
@@ -3225,7 +3500,7 @@ function FloatingFocusManager(props) {
|
|
|
3225
3500
|
resolvedReturnFocusValue = true;
|
|
3226
3501
|
}
|
|
3227
3502
|
const referenceReturnElement = domReference?.isConnected ? domReference : null;
|
|
3228
|
-
const previousReturnElement = elementFocusedBeforeOpen?.isConnected &&
|
|
3503
|
+
const previousReturnElement = elementFocusedBeforeOpen?.isConnected && getNodeName(elementFocusedBeforeOpen) !== 'body' ? elementFocusedBeforeOpen : null;
|
|
3229
3504
|
let defaultReturnElement = preferPreviousFocus ? previousReturnElement || referenceReturnElement : referenceReturnElement || previousReturnElement;
|
|
3230
3505
|
if (!defaultReturnElement) {
|
|
3231
3506
|
defaultReturnElement = getPreviouslyFocusedElement() || null;
|
|
@@ -3243,19 +3518,25 @@ function FloatingFocusManager(props) {
|
|
|
3243
3518
|
|
|
3244
3519
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
3245
3520
|
const returnFocusValueOrFn = returnFocusRef.current;
|
|
3246
|
-
const
|
|
3521
|
+
const closeType = closeTypeRef.current;
|
|
3522
|
+
const returnElement = getReturnElement(closeType);
|
|
3247
3523
|
queueMicrotask(() => {
|
|
3248
|
-
//
|
|
3524
|
+
// `returnElement` if it is tabbable, otherwise its first tabbable child,
|
|
3525
|
+
// otherwise `returnElement` itself (which may not be tabbable at all).
|
|
3249
3526
|
const tabbableReturnElement = getFirstTabbableElement(returnElement);
|
|
3250
3527
|
const hasExplicitReturnFocus = typeof returnFocusValueOrFn !== 'boolean';
|
|
3251
|
-
if (returnFocusValueOrFn && !preventReturnFocusRef.current &&
|
|
3528
|
+
if (returnFocusValueOrFn && !preventReturnFocusRef.current && isHTMLElement(tabbableReturnElement) && (
|
|
3252
3529
|
// If the focus moved somewhere else after mount, avoid returning focus
|
|
3253
3530
|
// since it likely entered a different element which should be
|
|
3254
3531
|
// respected: https://github.com/floating-ui/floating-ui/issues/2607
|
|
3255
3532
|
!hasExplicitReturnFocus && tabbableReturnElement !== activeEl && activeEl !== doc.body ? isFocusInsideFloatingTree : true)) {
|
|
3256
|
-
|
|
3533
|
+
const focusOptions = {
|
|
3257
3534
|
preventScroll: true
|
|
3258
|
-
}
|
|
3535
|
+
};
|
|
3536
|
+
if (closeType === 'keyboard') {
|
|
3537
|
+
focusOptions.focusVisible = true;
|
|
3538
|
+
}
|
|
3539
|
+
tabbableReturnElement.focus(focusOptions);
|
|
3259
3540
|
}
|
|
3260
3541
|
preventReturnFocusRef.current = false;
|
|
3261
3542
|
});
|
|
@@ -3270,7 +3551,7 @@ function FloatingFocusManager(props) {
|
|
|
3270
3551
|
return;
|
|
3271
3552
|
}
|
|
3272
3553
|
const activeEl = activeElement(ownerDocument(floating));
|
|
3273
|
-
if (!
|
|
3554
|
+
if (!isHTMLElement(activeEl) || !isTypeableElement(activeEl)) {
|
|
3274
3555
|
return;
|
|
3275
3556
|
}
|
|
3276
3557
|
if (contains(floating, activeEl)) {
|
|
@@ -3278,8 +3559,8 @@ function FloatingFocusManager(props) {
|
|
|
3278
3559
|
}
|
|
3279
3560
|
}, [open, floating]);
|
|
3280
3561
|
|
|
3281
|
-
// Synchronize the
|
|
3282
|
-
//
|
|
3562
|
+
// Synchronize the focus manager state (modal, closeOnFocusOut, open, etc.) to the
|
|
3563
|
+
// FloatingPortal context, which uses it to decide whether to render its own guards.
|
|
3283
3564
|
useIsoLayoutEffect(() => {
|
|
3284
3565
|
if (disabled || !portalContext) {
|
|
3285
3566
|
return undefined;
|
|
@@ -3314,7 +3595,8 @@ function FloatingFocusManager(props) {
|
|
|
3314
3595
|
onFocus: event => {
|
|
3315
3596
|
if (modal) {
|
|
3316
3597
|
const els = getTabbableContent();
|
|
3317
|
-
enqueueFocus
|
|
3598
|
+
// enqueueFocus returns a rAF-cancel function we don't need here.
|
|
3599
|
+
void enqueueFocus(els[els.length - 1]);
|
|
3318
3600
|
} else if (portalContext?.portalNode) {
|
|
3319
3601
|
preventReturnFocusRef.current = false;
|
|
3320
3602
|
if (isOutsideEvent(event, portalContext.portalNode)) {
|
|
@@ -3330,7 +3612,8 @@ function FloatingFocusManager(props) {
|
|
|
3330
3612
|
ref: mergedAfterGuardRef,
|
|
3331
3613
|
onFocus: event => {
|
|
3332
3614
|
if (modal) {
|
|
3333
|
-
enqueueFocus
|
|
3615
|
+
// enqueueFocus returns a rAF-cancel function we don't need here.
|
|
3616
|
+
void enqueueFocus(getTabbableContent()[0]);
|
|
3334
3617
|
} else if (portalContext?.portalNode) {
|
|
3335
3618
|
if (closeOnFocusOut) {
|
|
3336
3619
|
preventReturnFocusRef.current = true;
|
|
@@ -3402,7 +3685,11 @@ function useClick(context, props = {}) {
|
|
|
3402
3685
|
}
|
|
3403
3686
|
return {
|
|
3404
3687
|
onPointerDown(event) {
|
|
3405
|
-
|
|
3688
|
+
// Screen reader activations (Android TalkBack, desktop screen readers) report a
|
|
3689
|
+
// mouse-like `pointerType`, but `ignoreMouse` must not drop them: hover logic cannot
|
|
3690
|
+
// open for a virtual press since there is no real pointer movement to wait for.
|
|
3691
|
+
// Virtual `touch` presses (iOS VoiceOver) keep their type so `touchOpenDelay` applies.
|
|
3692
|
+
pointerTypeRef.current = isMouseLikePointerType(event.pointerType, true) && isVirtualPointerEvent(event.nativeEvent) ? 'virtual' : event.pointerType;
|
|
3406
3693
|
},
|
|
3407
3694
|
onMouseDown(event) {
|
|
3408
3695
|
const pointerType = pointerTypeRef.current;
|
|
@@ -3582,7 +3869,7 @@ function useDismiss(context, props = {}) {
|
|
|
3582
3869
|
});
|
|
3583
3870
|
React__namespace.useEffect(() => {
|
|
3584
3871
|
if (!open || !enabled) {
|
|
3585
|
-
return
|
|
3872
|
+
return clearInsideReactTree;
|
|
3586
3873
|
}
|
|
3587
3874
|
dataRef.current.__escapeKeyBubbles = escapeKeyBubbles;
|
|
3588
3875
|
dataRef.current.__outsidePressBubbles = outsidePressBubbles;
|
|
@@ -3651,18 +3938,18 @@ function useDismiss(context, props = {}) {
|
|
|
3651
3938
|
}
|
|
3652
3939
|
const target = getTarget(event);
|
|
3653
3940
|
const inertSelector = `[${createAttribute('inert')}]`;
|
|
3654
|
-
const targetRoot =
|
|
3655
|
-
const markers = Array.from((
|
|
3941
|
+
const targetRoot = isElement(target) ? target.getRootNode() : null;
|
|
3942
|
+
const markers = Array.from((isShadowRoot(targetRoot) ? targetRoot : ownerDocument(store.select('floatingElement'))).querySelectorAll(inertSelector));
|
|
3656
3943
|
const triggers = store.context.triggerElements;
|
|
3657
3944
|
|
|
3658
3945
|
// If another trigger is clicked, don't close the floating element.
|
|
3659
3946
|
if (target && (triggers.hasElement(target) || triggers.hasMatchingElement(trigger => contains(trigger, target)))) {
|
|
3660
3947
|
return;
|
|
3661
3948
|
}
|
|
3662
|
-
let targetRootAncestor =
|
|
3663
|
-
while (targetRootAncestor && !
|
|
3664
|
-
const nextParent =
|
|
3665
|
-
if (
|
|
3949
|
+
let targetRootAncestor = isElement(target) ? target : null;
|
|
3950
|
+
while (targetRootAncestor && !isLastTraversableNode(targetRootAncestor)) {
|
|
3951
|
+
const nextParent = getParentNode(targetRootAncestor);
|
|
3952
|
+
if (isLastTraversableNode(nextParent) || !isElement(nextParent)) {
|
|
3666
3953
|
break;
|
|
3667
3954
|
}
|
|
3668
3955
|
targetRootAncestor = nextParent;
|
|
@@ -3670,7 +3957,7 @@ function useDismiss(context, props = {}) {
|
|
|
3670
3957
|
|
|
3671
3958
|
// Check if the click occurred on a third-party element injected after the
|
|
3672
3959
|
// floating element rendered.
|
|
3673
|
-
if (markers.length &&
|
|
3960
|
+
if (markers.length && isElement(target) && !isRootElement(target) &&
|
|
3674
3961
|
// Clicked on a direct ancestor (e.g. FloatingOverlay).
|
|
3675
3962
|
!contains(target, store.select('floatingElement')) &&
|
|
3676
3963
|
// If the target root element contains none of the markers, then the
|
|
@@ -3681,9 +3968,9 @@ function useDismiss(context, props = {}) {
|
|
|
3681
3968
|
|
|
3682
3969
|
// Check if the click occurred on the scrollbar
|
|
3683
3970
|
// Skip for touch events: scrollbars don't receive touch events on most platforms
|
|
3684
|
-
if (
|
|
3685
|
-
const lastTraversableNode =
|
|
3686
|
-
const style =
|
|
3971
|
+
if (isHTMLElement(target) && !('touches' in event)) {
|
|
3972
|
+
const lastTraversableNode = isLastTraversableNode(target);
|
|
3973
|
+
const style = getComputedStyle(target);
|
|
3687
3974
|
const scrollRe = /auto|scroll/;
|
|
3688
3975
|
const isScrollableX = lastTraversableNode || scrollRe.test(style.overflowX);
|
|
3689
3976
|
const isScrollableY = lastTraversableNode || scrollRe.test(style.overflowY);
|
|
@@ -3860,9 +4147,9 @@ function useDismiss(context, props = {}) {
|
|
|
3860
4147
|
preventedPressSuppressionTimeout.clear();
|
|
3861
4148
|
resetPressStartState();
|
|
3862
4149
|
suppressNextOutsideClickRef.current = false;
|
|
4150
|
+
clearInsideReactTree();
|
|
3863
4151
|
};
|
|
3864
4152
|
}, [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]);
|
|
3866
4153
|
const reference = React__namespace.useMemo(() => ({
|
|
3867
4154
|
onKeyDown: closeOnEscapeKeyDown,
|
|
3868
4155
|
onPointerDown: closeOnReferencePress,
|
|
@@ -3896,12 +4183,12 @@ function useDismiss(context, props = {}) {
|
|
|
3896
4183
|
}
|
|
3897
4184
|
|
|
3898
4185
|
const selectors = {
|
|
3899
|
-
open:
|
|
3900
|
-
transitionStatus:
|
|
3901
|
-
domReferenceElement:
|
|
3902
|
-
referenceElement:
|
|
3903
|
-
floatingElement:
|
|
3904
|
-
floatingId:
|
|
4186
|
+
open: state => state.open,
|
|
4187
|
+
transitionStatus: state => state.transitionStatus,
|
|
4188
|
+
domReferenceElement: state => state.domReferenceElement,
|
|
4189
|
+
referenceElement: state => state.positionReference ?? state.referenceElement,
|
|
4190
|
+
floatingElement: state => state.floatingElement,
|
|
4191
|
+
floatingId: state => state.floatingId
|
|
3905
4192
|
};
|
|
3906
4193
|
class FloatingRootStore extends ReactStore {
|
|
3907
4194
|
constructor(options) {
|
|
@@ -4012,7 +4299,7 @@ function useSyncedFloatingRootContext(options) {
|
|
|
4012
4299
|
referenceElement,
|
|
4013
4300
|
floatingElement
|
|
4014
4301
|
};
|
|
4015
|
-
if (
|
|
4302
|
+
if (isElement(referenceElement)) {
|
|
4016
4303
|
valuesToSync.domReferenceElement = referenceElement;
|
|
4017
4304
|
}
|
|
4018
4305
|
if (store.state.positionReference === store.state.referenceElement) {
|
|
@@ -4090,44 +4377,14 @@ function useTransitionStatus(open, enableIdleState = false, deferEndingState = f
|
|
|
4090
4377
|
};
|
|
4091
4378
|
}
|
|
4092
4379
|
|
|
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
4380
|
/**
|
|
4123
4381
|
* Executes a function once all animations have finished on the provided element.
|
|
4382
|
+
* If an animation is canceled, waits for any replacement animations before executing.
|
|
4124
4383
|
* @param elementOrRef - The element to watch for animations.
|
|
4125
4384
|
* @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
4385
|
* @returns A function that takes a callback to execute once all animations have finished, and an optional AbortSignal to abort the callback
|
|
4129
4386
|
*/
|
|
4130
|
-
function useAnimationsFinished(elementOrRef, waitForStartingStyleRemoved = false
|
|
4387
|
+
function useAnimationsFinished(elementOrRef, waitForStartingStyleRemoved = false) {
|
|
4131
4388
|
const frame = useAnimationFrame();
|
|
4132
4389
|
return useStableCallback((fnToExecute,
|
|
4133
4390
|
/**
|
|
@@ -4156,23 +4413,22 @@ function useAnimationsFinished(elementOrRef, waitForStartingStyleRemoved = false
|
|
|
4156
4413
|
if (!signal?.aborted) {
|
|
4157
4414
|
done();
|
|
4158
4415
|
}
|
|
4159
|
-
}
|
|
4160
|
-
if (
|
|
4161
|
-
if (!signal?.aborted) {
|
|
4162
|
-
done();
|
|
4163
|
-
}
|
|
4416
|
+
}, () => {
|
|
4417
|
+
if (signal?.aborted) {
|
|
4164
4418
|
return;
|
|
4165
4419
|
}
|
|
4166
4420
|
const currentAnimations = resolvedElement.getAnimations();
|
|
4167
|
-
if (
|
|
4421
|
+
if (currentAnimations.some(animation => animation.pending || animation.playState !== 'finished')) {
|
|
4168
4422
|
// Sometimes animations can be aborted because a property they depend on changes while the animation plays.
|
|
4169
4423
|
// In such cases, we need to re-check if any new animations have started.
|
|
4170
4424
|
exec();
|
|
4425
|
+
return;
|
|
4171
4426
|
}
|
|
4427
|
+
done();
|
|
4172
4428
|
});
|
|
4173
4429
|
}
|
|
4174
4430
|
if (waitForStartingStyleRemoved) {
|
|
4175
|
-
const startingStyleAttribute =
|
|
4431
|
+
const startingStyleAttribute = 'data-starting-style';
|
|
4176
4432
|
|
|
4177
4433
|
// If `[data-starting-style]` isn't present, fall back to waiting one more frame
|
|
4178
4434
|
// to give "open" animations a chance to be registered.
|
|
@@ -4212,7 +4468,7 @@ function useOpenChangeComplete(parameters) {
|
|
|
4212
4468
|
onComplete: onCompleteParam
|
|
4213
4469
|
} = parameters;
|
|
4214
4470
|
const onComplete = useStableCallback(onCompleteParam);
|
|
4215
|
-
const runOnceAnimationsFinish = useAnimationsFinished(ref, open
|
|
4471
|
+
const runOnceAnimationsFinish = useAnimationsFinished(ref, open);
|
|
4216
4472
|
React__namespace.useEffect(() => {
|
|
4217
4473
|
if (!enabled) {
|
|
4218
4474
|
return undefined;
|
|
@@ -4238,14 +4494,26 @@ const FOCUSABLE_POPUP_PROPS = {
|
|
|
4238
4494
|
function createDefaultInitialFocus(popupRef) {
|
|
4239
4495
|
return interactionType => interactionType === 'touch' ? popupRef.current : true;
|
|
4240
4496
|
}
|
|
4241
|
-
|
|
4497
|
+
|
|
4498
|
+
/**
|
|
4499
|
+
* The subset of a popup handle that a Root needs to bind its store to. Both the real handle classes
|
|
4500
|
+
* and any test double satisfy it.
|
|
4501
|
+
*/
|
|
4502
|
+
|
|
4503
|
+
/**
|
|
4504
|
+
* Creates and owns a popup store on behalf of a Root part. The store is created exactly once, with
|
|
4505
|
+
* controlled props and root state synced separately after creation. Sets up the synced floating
|
|
4506
|
+
* root context and returns the store.
|
|
4507
|
+
*
|
|
4508
|
+
* @param createStore Factory that builds the store. Called exactly once, receiving the floating id
|
|
4509
|
+
* and whether the popup is nested inside another floating element, both resolved on the first render.
|
|
4510
|
+
* @param treatPopupAsFloatingElement Whether the popup element is passed to Floating UI as the
|
|
4511
|
+
* floating element instead of the default positioner.
|
|
4512
|
+
*/
|
|
4513
|
+
function usePopupRootStore(createStore, treatPopupAsFloatingElement = false) {
|
|
4242
4514
|
const floatingId = useId();
|
|
4243
4515
|
const nested = useFloatingParentNodeId() != null;
|
|
4244
|
-
const
|
|
4245
|
-
if (externalStore === undefined && internalStoreRef.current === null) {
|
|
4246
|
-
internalStoreRef.current = createStore(floatingId, nested);
|
|
4247
|
-
}
|
|
4248
|
-
const store = externalStore ?? internalStoreRef.current;
|
|
4516
|
+
const store = useRenderElement.useRefWithInit(() => createStore(floatingId, nested)).current;
|
|
4249
4517
|
useSyncedFloatingRootContext({
|
|
4250
4518
|
popupStore: store,
|
|
4251
4519
|
treatPopupAsFloatingElement,
|
|
@@ -4254,10 +4522,27 @@ function usePopupStore(externalStore, createStore, treatPopupAsFloatingElement =
|
|
|
4254
4522
|
nested,
|
|
4255
4523
|
onOpenChange: store.setOpen
|
|
4256
4524
|
});
|
|
4257
|
-
return
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4525
|
+
return store;
|
|
4526
|
+
}
|
|
4527
|
+
|
|
4528
|
+
/**
|
|
4529
|
+
* Attaches a Root's store to a handle for this component's committed lifetime. Popup Roots render
|
|
4530
|
+
* it before their interactions and user children so its layout effect runs before descendant layout
|
|
4531
|
+
* effects. This lets descendants call the handle during the Root's initial commit without attaching
|
|
4532
|
+
* during render, which would leak suspended or abandoned stores. Store subscribers are notified by
|
|
4533
|
+
* `attachStore` in this ordinary layout phase, where React permits synchronous updates.
|
|
4534
|
+
*
|
|
4535
|
+
* Popup Roots must render this component only when a handle is present so handle-less Roots avoid
|
|
4536
|
+
* mounting an extra fiber and layout effect.
|
|
4537
|
+
*/
|
|
4538
|
+
function PopupHandleAttachment({
|
|
4539
|
+
handle,
|
|
4540
|
+
store
|
|
4541
|
+
}) {
|
|
4542
|
+
useIsoLayoutEffect(() => {
|
|
4543
|
+
return handle.attachStore(store);
|
|
4544
|
+
}, [handle, store]);
|
|
4545
|
+
return null;
|
|
4261
4546
|
}
|
|
4262
4547
|
|
|
4263
4548
|
/**
|
|
@@ -4322,19 +4607,6 @@ function attachPreventUnmountOnClose(eventDetails) {
|
|
|
4322
4607
|
};
|
|
4323
4608
|
return () => preventUnmountOnClose;
|
|
4324
4609
|
}
|
|
4325
|
-
function useInitialOpenSync(store, openProp, defaultOpen, defaultTriggerId) {
|
|
4326
|
-
useOnFirstRender(() => {
|
|
4327
|
-
if (openProp === undefined && store.state.open === false && defaultOpen) {
|
|
4328
|
-
// Avoid notifying detached trigger subscribers while the Root is rendering.
|
|
4329
|
-
store.state = {
|
|
4330
|
-
...store.state,
|
|
4331
|
-
open: true,
|
|
4332
|
-
activeTriggerId: defaultTriggerId,
|
|
4333
|
-
preventUnmountingOnClose: false
|
|
4334
|
-
};
|
|
4335
|
-
}
|
|
4336
|
-
});
|
|
4337
|
-
}
|
|
4338
4610
|
|
|
4339
4611
|
/**
|
|
4340
4612
|
* Sets up trigger data forwarding to the store.
|
|
@@ -4347,11 +4619,11 @@ function useInitialOpenSync(store, openProp, defaultOpen, defaultTriggerId) {
|
|
|
4347
4619
|
function useTriggerDataForwarding(triggerId, triggerElementRef, store, stateUpdates) {
|
|
4348
4620
|
const isMountedByThisTrigger = store.useState('isMountedByTrigger', triggerId);
|
|
4349
4621
|
const baseRegisterTrigger = useTriggerRegistration(triggerId, store);
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4622
|
+
|
|
4623
|
+
// Applies trigger-owned state (active-trigger ownership and payload) when the trigger registers.
|
|
4624
|
+
// Stable so payload/`stateUpdates` changes do not change the ref identity (which would needlessly
|
|
4625
|
+
// churn registration); it reads the latest closure values when invoked.
|
|
4626
|
+
const applyTriggerData = useStableCallback(element => {
|
|
4355
4627
|
const open = store.select('open');
|
|
4356
4628
|
const activeTriggerId = store.select('activeTriggerId');
|
|
4357
4629
|
if (activeTriggerId === triggerId) {
|
|
@@ -4372,6 +4644,18 @@ function useTriggerDataForwarding(triggerId, triggerElementRef, store, stateUpda
|
|
|
4372
4644
|
});
|
|
4373
4645
|
}
|
|
4374
4646
|
});
|
|
4647
|
+
|
|
4648
|
+
// Intentionally NOT stable. Its identity is derived from `baseRegisterTrigger`, which is keyed on
|
|
4649
|
+
// `[store, id]`, so when a handle-backed trigger's store pointer swaps the merged ref re-fires —
|
|
4650
|
+
// unregistering from the previous store and registering into the new one. This lets a detached
|
|
4651
|
+
// trigger follow its handle's currently-attached store across attach/detach/remount. (A stable
|
|
4652
|
+
// callback would keep its identity and never re-fire on a store swap.)
|
|
4653
|
+
const registerTrigger = React__namespace.useCallback(element => {
|
|
4654
|
+
baseRegisterTrigger(element);
|
|
4655
|
+
if (element) {
|
|
4656
|
+
applyTriggerData(element);
|
|
4657
|
+
}
|
|
4658
|
+
}, [baseRegisterTrigger, applyTriggerData]);
|
|
4375
4659
|
useIsoLayoutEffect(() => {
|
|
4376
4660
|
if (isMountedByThisTrigger) {
|
|
4377
4661
|
store.update({
|
|
@@ -4391,12 +4675,17 @@ function useTriggerDataForwarding(triggerId, triggerElementRef, store, stateUpda
|
|
|
4391
4675
|
*
|
|
4392
4676
|
* When a popup opens without an explicit trigger id and exactly one trigger is registered, that
|
|
4393
4677
|
* trigger is claimed as the active trigger. When the active trigger id is still registered but its
|
|
4394
|
-
* element changed, the active element is refreshed. When the active trigger
|
|
4395
|
-
*
|
|
4396
|
-
*
|
|
4678
|
+
* element changed, the active element is refreshed. When the active trigger id is missing from the
|
|
4679
|
+
* registry but the same element is still registered under a different id (e.g. the rendered trigger
|
|
4680
|
+
* carries its own DOM `id` that differs from Base UI's internal trigger id), the active id is
|
|
4681
|
+
* reassociated to the registered id instead of being treated as lost. When the active trigger
|
|
4682
|
+
* unregisters, the default path preserves existing ownership so non-closing popup families do not
|
|
4683
|
+
* silently claim a different trigger while staying open.
|
|
4397
4684
|
*
|
|
4398
|
-
* If `closeOnActiveTriggerUnmount` is enabled, unregistering
|
|
4399
|
-
* after a microtask so a same-tick replacement trigger with the same id can
|
|
4685
|
+
* If `closeOnActiveTriggerUnmount` is enabled, unregistering a previously resolved active trigger
|
|
4686
|
+
* requests a close after a microtask so a same-tick replacement trigger with the same id can
|
|
4687
|
+
* register first. An active trigger id that has not matched a registered trigger yet is treated as
|
|
4688
|
+
* pending and does not request a close.
|
|
4400
4689
|
*
|
|
4401
4690
|
* This should be called on the Root part.
|
|
4402
4691
|
*
|
|
@@ -4407,10 +4696,22 @@ function useImplicitActiveTrigger(store, options = {}) {
|
|
|
4407
4696
|
const {
|
|
4408
4697
|
closeOnActiveTriggerUnmount = false
|
|
4409
4698
|
} = options;
|
|
4699
|
+
// Distinguishes a trigger that unmounted from a new active trigger that has not hydrated yet.
|
|
4700
|
+
const resolvedActiveTriggerIdRef = React__namespace.useRef(null);
|
|
4410
4701
|
const open = store.useState('open');
|
|
4411
4702
|
const reactiveTriggerCount = store.useState('triggerCount');
|
|
4703
|
+
// Subscribe to the active trigger id so the reconciliation below reruns when ownership moves to
|
|
4704
|
+
// another trigger while the popup stays open (e.g. a focus/hover handoff between triggers).
|
|
4705
|
+
const activeTriggerId = store.useState('activeTriggerId');
|
|
4706
|
+
// Subscribe to the active trigger element so the reconciliation reruns when a pending active
|
|
4707
|
+
// trigger registers in a commit where the trigger count nets out unchanged (registration
|
|
4708
|
+
// forwards the element to the store when the registering trigger matches the active id).
|
|
4709
|
+
// Without this, the id would never be marked resolved and a later genuine unmount would be
|
|
4710
|
+
// misclassified as pending, disabling `closeOnActiveTriggerUnmount`.
|
|
4711
|
+
const reactiveActiveTriggerElement = store.useState('activeTriggerElement');
|
|
4412
4712
|
useIsoLayoutEffect(() => {
|
|
4413
4713
|
if (!open) {
|
|
4714
|
+
resolvedActiveTriggerIdRef.current = null;
|
|
4414
4715
|
if (store.state.triggerCount !== 0) {
|
|
4415
4716
|
store.set('triggerCount', 0);
|
|
4416
4717
|
}
|
|
@@ -4421,22 +4722,42 @@ function useImplicitActiveTrigger(store, options = {}) {
|
|
|
4421
4722
|
if (store.state.triggerCount !== triggerCount) {
|
|
4422
4723
|
stateUpdates.triggerCount = triggerCount;
|
|
4423
4724
|
}
|
|
4424
|
-
const
|
|
4725
|
+
const currentActiveTriggerId = store.select('activeTriggerId');
|
|
4425
4726
|
let lostActiveTriggerId = null;
|
|
4426
|
-
if (
|
|
4427
|
-
const activeTriggerElement = store.context.triggerElements.getById(
|
|
4727
|
+
if (currentActiveTriggerId) {
|
|
4728
|
+
const activeTriggerElement = store.context.triggerElements.getById(currentActiveTriggerId);
|
|
4428
4729
|
if (!activeTriggerElement) {
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4730
|
+
for (const [triggerId, triggerElement] of store.context.triggerElements.entries()) {
|
|
4731
|
+
if (triggerElement === store.state.activeTriggerElement) {
|
|
4732
|
+
stateUpdates.activeTriggerId = triggerId;
|
|
4733
|
+
stateUpdates.activeTriggerElement = triggerElement;
|
|
4734
|
+
resolvedActiveTriggerIdRef.current = triggerId;
|
|
4735
|
+
break;
|
|
4736
|
+
}
|
|
4737
|
+
}
|
|
4738
|
+
if (stateUpdates.activeTriggerId === undefined) {
|
|
4739
|
+
if (resolvedActiveTriggerIdRef.current === currentActiveTriggerId) {
|
|
4740
|
+
lostActiveTriggerId = currentActiveTriggerId;
|
|
4741
|
+
} else {
|
|
4742
|
+
resolvedActiveTriggerIdRef.current = null;
|
|
4743
|
+
}
|
|
4744
|
+
}
|
|
4745
|
+
} else {
|
|
4746
|
+
resolvedActiveTriggerIdRef.current = currentActiveTriggerId;
|
|
4747
|
+
if (activeTriggerElement !== store.state.activeTriggerElement) {
|
|
4748
|
+
stateUpdates.activeTriggerElement = activeTriggerElement;
|
|
4749
|
+
}
|
|
4432
4750
|
}
|
|
4751
|
+
} else {
|
|
4752
|
+
resolvedActiveTriggerIdRef.current = null;
|
|
4433
4753
|
}
|
|
4434
|
-
if (!lostActiveTriggerId && !
|
|
4754
|
+
if (!lostActiveTriggerId && !currentActiveTriggerId && triggerCount === 1) {
|
|
4435
4755
|
const iteratorResult = store.context.triggerElements.entries().next();
|
|
4436
4756
|
if (!iteratorResult.done) {
|
|
4437
4757
|
const [implicitTriggerId, implicitTriggerElement] = iteratorResult.value;
|
|
4438
4758
|
stateUpdates.activeTriggerId = implicitTriggerId;
|
|
4439
4759
|
stateUpdates.activeTriggerElement = implicitTriggerElement;
|
|
4760
|
+
resolvedActiveTriggerIdRef.current = implicitTriggerId;
|
|
4440
4761
|
}
|
|
4441
4762
|
}
|
|
4442
4763
|
if (stateUpdates.triggerCount !== undefined || stateUpdates.activeTriggerId !== undefined || stateUpdates.activeTriggerElement !== undefined) {
|
|
@@ -4461,7 +4782,7 @@ function useImplicitActiveTrigger(store, options = {}) {
|
|
|
4461
4782
|
});
|
|
4462
4783
|
}
|
|
4463
4784
|
}
|
|
4464
|
-
}, [open, store, reactiveTriggerCount, closeOnActiveTriggerUnmount]);
|
|
4785
|
+
}, [open, store, reactiveTriggerCount, activeTriggerId, reactiveActiveTriggerElement, closeOnActiveTriggerUnmount]);
|
|
4465
4786
|
}
|
|
4466
4787
|
|
|
4467
4788
|
/**
|
|
@@ -4539,13 +4860,33 @@ function usePopupRootSync(store, open) {
|
|
|
4539
4860
|
}, [store]);
|
|
4540
4861
|
}
|
|
4541
4862
|
|
|
4863
|
+
/**
|
|
4864
|
+
* Development-only reverse index of element to registered id, keyed by the owning map.
|
|
4865
|
+
*
|
|
4866
|
+
* Registration would otherwise have to scan every entry to detect an element claimed by two ids,
|
|
4867
|
+
* making the mount of many triggers sharing one handle quadratic. Kept module-scoped, lazily
|
|
4868
|
+
* initialized, and read only from `process.env.NODE_ENV` guards so production builds drop it along
|
|
4869
|
+
* with the checks.
|
|
4870
|
+
*/
|
|
4871
|
+
let devElementIdsByMap;
|
|
4872
|
+
function getDevElementIds(map) {
|
|
4873
|
+
devElementIdsByMap ??= new WeakMap();
|
|
4874
|
+
let elementIds = devElementIdsByMap.get(map);
|
|
4875
|
+
if (!elementIds) {
|
|
4876
|
+
elementIds = new WeakMap();
|
|
4877
|
+
devElementIdsByMap.set(map, elementIds);
|
|
4878
|
+
}
|
|
4879
|
+
return elementIds;
|
|
4880
|
+
}
|
|
4881
|
+
|
|
4542
4882
|
/**
|
|
4543
4883
|
* Data structure to keep track of popup trigger elements by their IDs.
|
|
4544
|
-
*
|
|
4884
|
+
*
|
|
4885
|
+
* Element lookups iterate the id map rather than maintaining a parallel Set. Registration is O(1),
|
|
4886
|
+
* while `hasElement` and `hasMatchingElement` are linear in the number of triggers.
|
|
4545
4887
|
*/
|
|
4546
4888
|
class PopupTriggerMap {
|
|
4547
4889
|
constructor() {
|
|
4548
|
-
this.elementsSet = new Set();
|
|
4549
4890
|
this.idMap = new Map();
|
|
4550
4891
|
}
|
|
4551
4892
|
|
|
@@ -4555,49 +4896,56 @@ class PopupTriggerMap {
|
|
|
4555
4896
|
* Note: The provided element is assumed to not be registered under multiple IDs.
|
|
4556
4897
|
*/
|
|
4557
4898
|
add(id, element) {
|
|
4558
|
-
const existingElement = this.idMap.get(id);
|
|
4559
|
-
if (existingElement === element) {
|
|
4560
|
-
return;
|
|
4561
|
-
}
|
|
4562
|
-
if (existingElement !== undefined) {
|
|
4563
|
-
// We assume that the same element won't be registered under multiple ids.
|
|
4564
|
-
// This is safe considering how useTriggerRegistration is implemented.
|
|
4565
|
-
this.elementsSet.delete(existingElement);
|
|
4566
|
-
}
|
|
4567
|
-
this.elementsSet.add(element);
|
|
4568
|
-
this.idMap.set(id, element);
|
|
4569
4899
|
if (process.env.NODE_ENV !== 'production') {
|
|
4570
|
-
|
|
4900
|
+
const elementIds = getDevElementIds(this);
|
|
4901
|
+
const existingId = elementIds.get(element);
|
|
4902
|
+
if (existingId !== undefined && existingId !== id) {
|
|
4571
4903
|
// TODO: fix mui/no-guarded-throw
|
|
4572
4904
|
// eslint-disable-next-line mui/no-guarded-throw
|
|
4573
4905
|
throw new Error('Base UI: A trigger element cannot be registered under multiple IDs in PopupTriggerMap.');
|
|
4574
4906
|
}
|
|
4907
|
+
|
|
4908
|
+
// Reusing an id for a different element evicts the previous one, so it must lose its claim
|
|
4909
|
+
// on the id or a later registration under a different id would be reported as a duplicate.
|
|
4910
|
+
const previousElement = this.idMap.get(id);
|
|
4911
|
+
if (previousElement !== undefined && previousElement !== element) {
|
|
4912
|
+
elementIds.delete(previousElement);
|
|
4913
|
+
}
|
|
4914
|
+
elementIds.set(element, id);
|
|
4575
4915
|
}
|
|
4916
|
+
this.idMap.set(id, element);
|
|
4576
4917
|
}
|
|
4577
4918
|
|
|
4578
4919
|
/**
|
|
4579
4920
|
* Removes the trigger element with the given ID.
|
|
4580
4921
|
*/
|
|
4581
4922
|
delete(id) {
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4923
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
4924
|
+
const element = this.idMap.get(id);
|
|
4925
|
+
if (element !== undefined) {
|
|
4926
|
+
devElementIdsByMap?.get(this)?.delete(element);
|
|
4927
|
+
}
|
|
4586
4928
|
}
|
|
4929
|
+
this.idMap.delete(id);
|
|
4587
4930
|
}
|
|
4588
4931
|
|
|
4589
4932
|
/**
|
|
4590
4933
|
* Whether the given element is registered as a trigger.
|
|
4591
4934
|
*/
|
|
4592
4935
|
hasElement(element) {
|
|
4593
|
-
|
|
4936
|
+
for (const registered of this.idMap.values()) {
|
|
4937
|
+
if (registered === element) {
|
|
4938
|
+
return true;
|
|
4939
|
+
}
|
|
4940
|
+
}
|
|
4941
|
+
return false;
|
|
4594
4942
|
}
|
|
4595
4943
|
|
|
4596
4944
|
/**
|
|
4597
4945
|
* Whether there is a registered trigger element matching the given predicate.
|
|
4598
4946
|
*/
|
|
4599
4947
|
hasMatchingElement(predicate) {
|
|
4600
|
-
for (const element of this.
|
|
4948
|
+
for (const element of this.idMap.values()) {
|
|
4601
4949
|
if (predicate(element)) {
|
|
4602
4950
|
return true;
|
|
4603
4951
|
}
|
|
@@ -4623,7 +4971,7 @@ class PopupTriggerMap {
|
|
|
4623
4971
|
* Returns an iterable of all registered trigger elements.
|
|
4624
4972
|
*/
|
|
4625
4973
|
elements() {
|
|
4626
|
-
return this.
|
|
4974
|
+
return this.idMap.values();
|
|
4627
4975
|
}
|
|
4628
4976
|
|
|
4629
4977
|
/**
|
|
@@ -4683,14 +5031,11 @@ function useValueChanged(value, onChange) {
|
|
|
4683
5031
|
const valueRef = React__namespace.useRef(value);
|
|
4684
5032
|
const onChangeCallback = useStableCallback(onChange);
|
|
4685
5033
|
useIsoLayoutEffect(() => {
|
|
4686
|
-
if (valueRef.current
|
|
4687
|
-
|
|
5034
|
+
if (valueRef.current !== value) {
|
|
5035
|
+
onChangeCallback(valueRef.current);
|
|
4688
5036
|
}
|
|
4689
|
-
onChangeCallback(valueRef.current);
|
|
4690
|
-
}, [value, onChangeCallback]);
|
|
4691
|
-
useIsoLayoutEffect(() => {
|
|
4692
5037
|
valueRef.current = value;
|
|
4693
|
-
}, [value]);
|
|
5038
|
+
}, [value, onChangeCallback]);
|
|
4694
5039
|
}
|
|
4695
5040
|
|
|
4696
5041
|
function useOpenMethodTriggerProps(open, setOpenMethod) {
|
|
@@ -4733,9 +5078,6 @@ function useOpenInteractionType(open) {
|
|
|
4733
5078
|
}), [openMethod, triggerProps]);
|
|
4734
5079
|
}
|
|
4735
5080
|
|
|
4736
|
-
/**
|
|
4737
|
-
* @internal
|
|
4738
|
-
*/
|
|
4739
5081
|
const DirectionContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
4740
5082
|
if (process.env.NODE_ENV !== "production") DirectionContext.displayName = "DirectionContext";
|
|
4741
5083
|
function useDirection() {
|
|
@@ -4794,6 +5136,30 @@ function useFocusableWhenDisabled(parameters) {
|
|
|
4794
5136
|
};
|
|
4795
5137
|
}
|
|
4796
5138
|
|
|
5139
|
+
/**
|
|
5140
|
+
* Dispatches a constructed click on the target so it carries the source event's
|
|
5141
|
+
* modifier state, which `click()` always reports as unpressed. Like `click()`,
|
|
5142
|
+
* the untrusted click still runs native activation behavior (form submission,
|
|
5143
|
+
* link navigation).
|
|
5144
|
+
* `detail` defaults to 0 (the native convention for keyboard-generated clicks);
|
|
5145
|
+
* pass `detail: 1` when the click represents a mouse gesture so consumers keying
|
|
5146
|
+
* off `detail === 0` don't classify it as a keyboard activation.
|
|
5147
|
+
*/
|
|
5148
|
+
function dispatchClickWithModifiers(target, sourceEvent, {
|
|
5149
|
+
detail = 0
|
|
5150
|
+
} = {}) {
|
|
5151
|
+
target.dispatchEvent(new (getWindow(target).PointerEvent)('click', {
|
|
5152
|
+
bubbles: true,
|
|
5153
|
+
cancelable: true,
|
|
5154
|
+
composed: true,
|
|
5155
|
+
detail,
|
|
5156
|
+
shiftKey: sourceEvent.shiftKey,
|
|
5157
|
+
ctrlKey: sourceEvent.ctrlKey,
|
|
5158
|
+
altKey: sourceEvent.altKey,
|
|
5159
|
+
metaKey: sourceEvent.metaKey
|
|
5160
|
+
}));
|
|
5161
|
+
}
|
|
5162
|
+
|
|
4797
5163
|
function useButton(parameters = {}) {
|
|
4798
5164
|
const {
|
|
4799
5165
|
disabled = false,
|
|
@@ -4894,24 +5260,34 @@ function useButton(parameters = {}) {
|
|
|
4894
5260
|
return;
|
|
4895
5261
|
}
|
|
4896
5262
|
event.preventDefault();
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
} else if (shouldClick) {
|
|
4901
|
-
externalOnClick?.(event);
|
|
5263
|
+
|
|
5264
|
+
// Only a native-mode item that isn't a real <button> is excluded.
|
|
5265
|
+
if (!isNativeButton || isButton) {
|
|
4902
5266
|
event.preventBaseUIHandler();
|
|
5267
|
+
dispatchClickWithModifiers(currentTarget, event);
|
|
4903
5268
|
}
|
|
4904
5269
|
return;
|
|
4905
5270
|
}
|
|
4906
5271
|
|
|
4907
5272
|
// Keyboard accessibility for native and non-native elements.
|
|
4908
|
-
if (shouldClick) {
|
|
4909
|
-
|
|
5273
|
+
if (!shouldClick || isNativeButton || !isSpaceKey && !isEnterKey) {
|
|
5274
|
+
// Space activates links on keyup (`role="button"` semantics, matching the
|
|
5275
|
+
// composite path); prevent the page scroll Space would otherwise trigger.
|
|
5276
|
+
// Enter is left to the browser's native link activation.
|
|
5277
|
+
if (isCurrentTarget && isLink && isSpaceKey) {
|
|
4910
5278
|
event.preventDefault();
|
|
4911
5279
|
}
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
5280
|
+
return;
|
|
5281
|
+
}
|
|
5282
|
+
|
|
5283
|
+
// Match native buttons: preventing the keydown's default cancels activation.
|
|
5284
|
+
if (event.defaultPrevented) {
|
|
5285
|
+
return;
|
|
5286
|
+
}
|
|
5287
|
+
event.preventDefault();
|
|
5288
|
+
if (isEnterKey) {
|
|
5289
|
+
event.preventBaseUIHandler();
|
|
5290
|
+
dispatchClickWithModifiers(currentTarget, event);
|
|
4915
5291
|
}
|
|
4916
5292
|
},
|
|
4917
5293
|
onKeyUp(event) {
|
|
@@ -4931,9 +5307,14 @@ function useButton(parameters = {}) {
|
|
|
4931
5307
|
return;
|
|
4932
5308
|
}
|
|
4933
5309
|
|
|
4934
|
-
// Keyboard accessibility for non interactive elements
|
|
4935
|
-
|
|
4936
|
-
|
|
5310
|
+
// Keyboard accessibility for non interactive elements.
|
|
5311
|
+
// Match native buttons: preventing the keyup's default cancels Space activation.
|
|
5312
|
+
// Limitation: unlike a native <button>, a prevented *keydown* cannot cancel the
|
|
5313
|
+
// activation — no state is kept between keydown and keyup, so we can't tell
|
|
5314
|
+
// whether the keydown was prevented or even happened on this element.
|
|
5315
|
+
if (event.target === event.currentTarget && !isNativeButton && !isCompositeItem && !event.defaultPrevented && event.key === ' ') {
|
|
5316
|
+
event.preventBaseUIHandler();
|
|
5317
|
+
dispatchClickWithModifiers(event.currentTarget, event);
|
|
4937
5318
|
}
|
|
4938
5319
|
},
|
|
4939
5320
|
onPointerDown(event) {
|
|
@@ -4959,12 +5340,41 @@ function useButton(parameters = {}) {
|
|
|
4959
5340
|
};
|
|
4960
5341
|
}
|
|
4961
5342
|
function isButtonElement(elem) {
|
|
4962
|
-
return
|
|
5343
|
+
return isHTMLElement(elem) && elem.tagName === 'BUTTON';
|
|
4963
5344
|
}
|
|
4964
5345
|
function isValidLinkElement(elem) {
|
|
4965
|
-
return
|
|
5346
|
+
return isHTMLElement(elem) && elem.tagName === 'A' && Boolean(elem.href);
|
|
4966
5347
|
}
|
|
4967
5348
|
|
|
5349
|
+
let TransitionStatusDataAttributes = /*#__PURE__*/function (TransitionStatusDataAttributes) {
|
|
5350
|
+
/**
|
|
5351
|
+
* Present when the component begins animating in.
|
|
5352
|
+
*/
|
|
5353
|
+
TransitionStatusDataAttributes["startingStyle"] = "data-starting-style";
|
|
5354
|
+
/**
|
|
5355
|
+
* Present when the component is animating out.
|
|
5356
|
+
*/
|
|
5357
|
+
TransitionStatusDataAttributes["endingStyle"] = "data-ending-style";
|
|
5358
|
+
return TransitionStatusDataAttributes;
|
|
5359
|
+
}({});
|
|
5360
|
+
const STARTING_HOOK = {
|
|
5361
|
+
'data-starting-style': ''
|
|
5362
|
+
};
|
|
5363
|
+
const ENDING_HOOK = {
|
|
5364
|
+
'data-ending-style': ''
|
|
5365
|
+
};
|
|
5366
|
+
const transitionStatusMapping = {
|
|
5367
|
+
transitionStatus(value) {
|
|
5368
|
+
if (value === 'starting') {
|
|
5369
|
+
return STARTING_HOOK;
|
|
5370
|
+
}
|
|
5371
|
+
if (value === 'ending') {
|
|
5372
|
+
return ENDING_HOOK;
|
|
5373
|
+
}
|
|
5374
|
+
return null;
|
|
5375
|
+
}
|
|
5376
|
+
};
|
|
5377
|
+
|
|
4968
5378
|
let CommonPopupDataAttributes = function (CommonPopupDataAttributes) {
|
|
4969
5379
|
/**
|
|
4970
5380
|
* Present when the popup is open.
|
|
@@ -4975,7 +5385,7 @@ let CommonPopupDataAttributes = function (CommonPopupDataAttributes) {
|
|
|
4975
5385
|
*/
|
|
4976
5386
|
CommonPopupDataAttributes["closed"] = "data-closed";
|
|
4977
5387
|
/**
|
|
4978
|
-
* Present when the popup
|
|
5388
|
+
* Present when the popup begins animating in.
|
|
4979
5389
|
*/
|
|
4980
5390
|
CommonPopupDataAttributes[CommonPopupDataAttributes["startingStyle"] = TransitionStatusDataAttributes.startingStyle] = "startingStyle";
|
|
4981
5391
|
/**
|
|
@@ -4998,32 +5408,24 @@ let CommonPopupDataAttributes = function (CommonPopupDataAttributes) {
|
|
|
4998
5408
|
CommonPopupDataAttributes["align"] = "data-align";
|
|
4999
5409
|
return CommonPopupDataAttributes;
|
|
5000
5410
|
}({});
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
*/
|
|
5005
|
-
CommonTriggerDataAttributes["popupOpen"] = "data-popup-open";
|
|
5006
|
-
/**
|
|
5007
|
-
* Present when a pressable trigger is pressed.
|
|
5008
|
-
*/
|
|
5009
|
-
CommonTriggerDataAttributes["pressed"] = "data-pressed";
|
|
5010
|
-
return CommonTriggerDataAttributes;
|
|
5011
|
-
}({});
|
|
5411
|
+
|
|
5412
|
+
// Literal keys (instead of enum member references) keep the docs-only enums above
|
|
5413
|
+
// tree-shakeable: a runtime reference would retain the whole enum IIFE in every bundle.
|
|
5012
5414
|
const TRIGGER_HOOK = {
|
|
5013
|
-
|
|
5415
|
+
'data-popup-open': ''
|
|
5014
5416
|
};
|
|
5015
5417
|
const PRESSABLE_TRIGGER_HOOK = {
|
|
5016
|
-
|
|
5017
|
-
|
|
5418
|
+
'data-popup-open': '',
|
|
5419
|
+
'data-pressed': ''
|
|
5018
5420
|
};
|
|
5019
5421
|
const POPUP_OPEN_HOOK = {
|
|
5020
|
-
|
|
5422
|
+
'data-open': ''
|
|
5021
5423
|
};
|
|
5022
5424
|
const POPUP_CLOSED_HOOK = {
|
|
5023
|
-
|
|
5425
|
+
'data-closed': ''
|
|
5024
5426
|
};
|
|
5025
5427
|
const ANCHOR_HIDDEN_HOOK = {
|
|
5026
|
-
|
|
5428
|
+
'data-anchor-hidden': ''
|
|
5027
5429
|
};
|
|
5028
5430
|
const triggerOpenStateMapping = {
|
|
5029
5431
|
open(value) {
|
|
@@ -5055,6 +5457,10 @@ const popupStateMapping = {
|
|
|
5055
5457
|
return null;
|
|
5056
5458
|
}
|
|
5057
5459
|
};
|
|
5460
|
+
const popupTransitionStateMapping = {
|
|
5461
|
+
...popupStateMapping,
|
|
5462
|
+
...transitionStatusMapping
|
|
5463
|
+
};
|
|
5058
5464
|
|
|
5059
5465
|
function inertValue(value) {
|
|
5060
5466
|
if (useRenderElement.isReactVersionAtLeast(19)) {
|
|
@@ -5096,12 +5502,21 @@ if (process.env.NODE_ENV !== "production") InternalBackdrop.displayName = "Inter
|
|
|
5096
5502
|
let originalHtmlStyles = {};
|
|
5097
5503
|
let originalBodyStyles = {};
|
|
5098
5504
|
let originalHtmlScrollBehavior = '';
|
|
5505
|
+
|
|
5506
|
+
// The viewport's overflow comes from <html> when it establishes its own scroll container, and
|
|
5507
|
+
// propagates from <body> otherwise. An `overflow` style on the other element doesn't lock the page.
|
|
5508
|
+
function getViewportScroller(html, body) {
|
|
5509
|
+
return isOverflowElement(html) ? html : body;
|
|
5510
|
+
}
|
|
5511
|
+
function isPageScrollLocked(win, html, body) {
|
|
5512
|
+
return /hidden|clip/.test(win.getComputedStyle(getViewportScroller(html, body)).overflowY);
|
|
5513
|
+
}
|
|
5099
5514
|
function hasInsetScrollbars(referenceElement) {
|
|
5100
5515
|
if (typeof document === 'undefined') {
|
|
5101
5516
|
return false;
|
|
5102
5517
|
}
|
|
5103
5518
|
const doc = ownerDocument(referenceElement);
|
|
5104
|
-
const win =
|
|
5519
|
+
const win = getWindow(doc);
|
|
5105
5520
|
return win.innerWidth - doc.documentElement.clientWidth > 0;
|
|
5106
5521
|
}
|
|
5107
5522
|
function supportsStableScrollbarGutter(referenceElement) {
|
|
@@ -5112,7 +5527,7 @@ function supportsStableScrollbarGutter(referenceElement) {
|
|
|
5112
5527
|
const doc = ownerDocument(referenceElement);
|
|
5113
5528
|
const html = doc.documentElement;
|
|
5114
5529
|
const body = doc.body;
|
|
5115
|
-
const scrollContainer =
|
|
5530
|
+
const scrollContainer = getViewportScroller(html, body);
|
|
5116
5531
|
const originalScrollContainerOverflowY = scrollContainer.style.overflowY;
|
|
5117
5532
|
const originalHtmlStyleGutter = html.style.scrollbarGutter;
|
|
5118
5533
|
html.style.scrollbarGutter = 'stable';
|
|
@@ -5133,7 +5548,7 @@ function preventScrollOverlayScrollbars(referenceElement) {
|
|
|
5133
5548
|
// won't have any effect.
|
|
5134
5549
|
// But if <body> has an `overflow` style (like `overflow-x: hidden`), we need to lock it
|
|
5135
5550
|
// instead, as sticky elements shift otherwise.
|
|
5136
|
-
const elementToLock =
|
|
5551
|
+
const elementToLock = getViewportScroller(html, body);
|
|
5137
5552
|
const originalElementToLockStyles = {
|
|
5138
5553
|
overflowY: elementToLock.style.overflowY,
|
|
5139
5554
|
overflowX: elementToLock.style.overflowX
|
|
@@ -5150,7 +5565,7 @@ function preventScrollInsetScrollbars(referenceElement) {
|
|
|
5150
5565
|
const doc = ownerDocument(referenceElement);
|
|
5151
5566
|
const html = doc.documentElement;
|
|
5152
5567
|
const body = doc.body;
|
|
5153
|
-
const win =
|
|
5568
|
+
const win = getWindow(html);
|
|
5154
5569
|
let scrollTop = 0;
|
|
5155
5570
|
let scrollLeft = 0;
|
|
5156
5571
|
let updateGutterOnly = false;
|
|
@@ -5198,7 +5613,7 @@ function preventScrollInsetScrollbars(referenceElement) {
|
|
|
5198
5613
|
// with whitespace. Warn if <body> has margins?
|
|
5199
5614
|
const marginY = parseFloat(bodyStyles.marginTop) + parseFloat(bodyStyles.marginBottom);
|
|
5200
5615
|
const marginX = parseFloat(bodyStyles.marginLeft) + parseFloat(bodyStyles.marginRight);
|
|
5201
|
-
const elementToLock =
|
|
5616
|
+
const elementToLock = getViewportScroller(html, body);
|
|
5202
5617
|
updateGutterOnly = supportsStableScrollbarGutter(referenceElement);
|
|
5203
5618
|
|
|
5204
5619
|
/*
|
|
@@ -5228,7 +5643,9 @@ function preventScrollInsetScrollbars(referenceElement) {
|
|
|
5228
5643
|
height: marginY || scrollbarHeight ? `calc(100dvh - ${marginY + scrollbarHeight}px)` : '100dvh',
|
|
5229
5644
|
width: marginX || scrollbarWidth ? `calc(100vw - ${marginX + scrollbarWidth}px)` : '100vw',
|
|
5230
5645
|
boxSizing: 'border-box',
|
|
5231
|
-
|
|
5646
|
+
// Assign the longhands that `cleanup` restores, so nothing is left behind.
|
|
5647
|
+
overflowY: 'hidden',
|
|
5648
|
+
overflowX: 'hidden',
|
|
5232
5649
|
scrollBehavior: 'unset'
|
|
5233
5650
|
});
|
|
5234
5651
|
body.scrollTop = scrollTop;
|
|
@@ -5293,11 +5710,30 @@ class ScrollLocker {
|
|
|
5293
5710
|
}
|
|
5294
5711
|
const doc = ownerDocument(referenceElement);
|
|
5295
5712
|
const html = doc.documentElement;
|
|
5296
|
-
const
|
|
5713
|
+
const body = doc.body;
|
|
5714
|
+
const win = getWindow(html);
|
|
5715
|
+
|
|
5716
|
+
// The page is already locked, either by the site author or by a non-Base UI overlay that
|
|
5717
|
+
// hasn't cleaned up yet. Leave it alone and wait for the lock to clear before taking over,
|
|
5718
|
+
// otherwise we'd snapshot the locked state and restore it after our own lock is released.
|
|
5719
|
+
if (isPageScrollLocked(win, html, body)) {
|
|
5720
|
+
const observer = new win.MutationObserver(() => {
|
|
5721
|
+
if (isPageScrollLocked(win, html, body)) {
|
|
5722
|
+
return;
|
|
5723
|
+
}
|
|
5724
|
+
observer.disconnect();
|
|
5725
|
+
this.restore = null;
|
|
5726
|
+
this.lock(referenceElement);
|
|
5727
|
+
});
|
|
5297
5728
|
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5729
|
+
// Watch every attribute: locks are applied through inline styles, classes, or attributes
|
|
5730
|
+
// paired with a stylesheet (`data-scroll-locked` in react-remove-scroll, for example).
|
|
5731
|
+
const options = {
|
|
5732
|
+
attributes: true
|
|
5733
|
+
};
|
|
5734
|
+
observer.observe(html, options);
|
|
5735
|
+
observer.observe(body, options);
|
|
5736
|
+
this.restore = () => observer.disconnect();
|
|
5301
5737
|
return;
|
|
5302
5738
|
}
|
|
5303
5739
|
const hasOverlayScrollbars = ios || !hasInsetScrollbars(referenceElement);
|
|
@@ -5332,6 +5768,7 @@ exports.ARROW_DOWN = ARROW_DOWN;
|
|
|
5332
5768
|
exports.ARROW_LEFT = ARROW_LEFT;
|
|
5333
5769
|
exports.ARROW_RIGHT = ARROW_RIGHT;
|
|
5334
5770
|
exports.ARROW_UP = ARROW_UP;
|
|
5771
|
+
exports.AnimationFrame = AnimationFrame;
|
|
5335
5772
|
exports.BASE_UI_SWIPE_IGNORE_SELECTOR = BASE_UI_SWIPE_IGNORE_SELECTOR;
|
|
5336
5773
|
exports.CLICK_TRIGGER_IDENTIFIER = CLICK_TRIGGER_IDENTIFIER;
|
|
5337
5774
|
exports.CommonPopupDataAttributes = CommonPopupDataAttributes;
|
|
@@ -5348,6 +5785,7 @@ exports.FocusGuard = FocusGuard;
|
|
|
5348
5785
|
exports.InternalBackdrop = InternalBackdrop;
|
|
5349
5786
|
exports.PATIENT_CLICK_THRESHOLD = PATIENT_CLICK_THRESHOLD;
|
|
5350
5787
|
exports.POPUP_COLLISION_AVOIDANCE = POPUP_COLLISION_AVOIDANCE;
|
|
5788
|
+
exports.PopupHandleAttachment = PopupHandleAttachment;
|
|
5351
5789
|
exports.PopupTriggerMap = PopupTriggerMap;
|
|
5352
5790
|
exports.ReactStore = ReactStore;
|
|
5353
5791
|
exports.SafeReact = SafeReact;
|
|
@@ -5361,33 +5799,57 @@ exports.android = android;
|
|
|
5361
5799
|
exports.attachPreventUnmountOnClose = attachPreventUnmountOnClose;
|
|
5362
5800
|
exports.cancelOpen = cancelOpen;
|
|
5363
5801
|
exports.chipRemovePress = chipRemovePress;
|
|
5802
|
+
exports.clamp = clamp;
|
|
5364
5803
|
exports.clearPress = clearPress;
|
|
5365
5804
|
exports.closePress = closePress;
|
|
5366
5805
|
exports.closeWatcher = closeWatcher;
|
|
5367
5806
|
exports.contains = contains;
|
|
5368
5807
|
exports.createAttribute = createAttribute;
|
|
5369
5808
|
exports.createChangeEventDetails = createChangeEventDetails;
|
|
5809
|
+
exports.createCoords = createCoords;
|
|
5370
5810
|
exports.createDefaultInitialFocus = createDefaultInitialFocus;
|
|
5371
5811
|
exports.createGenericEventDetails = createGenericEventDetails;
|
|
5372
|
-
exports.createSelector = createSelector;
|
|
5373
5812
|
exports.decrementPress = decrementPress;
|
|
5813
|
+
exports.dispatchClickWithModifiers = dispatchClickWithModifiers;
|
|
5374
5814
|
exports.enqueueFocus = enqueueFocus;
|
|
5375
5815
|
exports.error = error;
|
|
5376
5816
|
exports.escapeKey = escapeKey;
|
|
5817
|
+
exports.evaluate = evaluate;
|
|
5377
5818
|
exports.fastComponent = fastComponent;
|
|
5378
5819
|
exports.fastComponentRef = fastComponentRef;
|
|
5379
5820
|
exports.findNonDisabledListIndex = findNonDisabledListIndex;
|
|
5821
|
+
exports.floor = floor;
|
|
5380
5822
|
exports.focusOut = focusOut;
|
|
5381
5823
|
exports.gecko = gecko;
|
|
5824
|
+
exports.getAlignment = getAlignment;
|
|
5825
|
+
exports.getAlignmentAxis = getAlignmentAxis;
|
|
5826
|
+
exports.getAlignmentSides = getAlignmentSides;
|
|
5827
|
+
exports.getAxisLength = getAxisLength;
|
|
5828
|
+
exports.getComputedStyle = getComputedStyle;
|
|
5829
|
+
exports.getContainingBlock = getContainingBlock;
|
|
5830
|
+
exports.getDocumentElement = getDocumentElement;
|
|
5831
|
+
exports.getExpandedPlacements = getExpandedPlacements;
|
|
5382
5832
|
exports.getFloatingFocusElement = getFloatingFocusElement;
|
|
5833
|
+
exports.getFrameElement = getFrameElement;
|
|
5383
5834
|
exports.getGridNavigatedIndex = getGridNavigatedIndex;
|
|
5384
5835
|
exports.getMaxListIndex = getMaxListIndex;
|
|
5385
5836
|
exports.getMinListIndex = getMinListIndex;
|
|
5386
5837
|
exports.getNextTabbable = getNextTabbable;
|
|
5387
5838
|
exports.getNodeChildren = getNodeChildren;
|
|
5839
|
+
exports.getNodeName = getNodeName;
|
|
5840
|
+
exports.getNodeScroll = getNodeScroll;
|
|
5841
|
+
exports.getOppositeAxis = getOppositeAxis;
|
|
5842
|
+
exports.getOppositeAxisPlacements = getOppositeAxisPlacements;
|
|
5843
|
+
exports.getOppositePlacement = getOppositePlacement;
|
|
5844
|
+
exports.getOverflowAncestors = getOverflowAncestors;
|
|
5845
|
+
exports.getPaddingObject = getPaddingObject;
|
|
5846
|
+
exports.getParentNode = getParentNode;
|
|
5847
|
+
exports.getSide = getSide;
|
|
5848
|
+
exports.getSideAxis = getSideAxis;
|
|
5388
5849
|
exports.getTabbableAfterElement = getTabbableAfterElement;
|
|
5389
5850
|
exports.getTabbableBeforeElement = getTabbableBeforeElement;
|
|
5390
5851
|
exports.getTarget = getTarget;
|
|
5852
|
+
exports.getWindow = getWindow;
|
|
5391
5853
|
exports.imperativeAction = imperativeAction;
|
|
5392
5854
|
exports.incrementPress = incrementPress;
|
|
5393
5855
|
exports.inertValue = inertValue;
|
|
@@ -5397,32 +5859,46 @@ exports.inputClear = inputClear;
|
|
|
5397
5859
|
exports.inputPaste = inputPaste;
|
|
5398
5860
|
exports.inputPress = inputPress;
|
|
5399
5861
|
exports.ios = ios;
|
|
5862
|
+
exports.isContainingBlock = isContainingBlock;
|
|
5863
|
+
exports.isElement = isElement;
|
|
5400
5864
|
exports.isElementVisible = isElementVisible;
|
|
5865
|
+
exports.isHTMLElement = isHTMLElement;
|
|
5401
5866
|
exports.isIndexOutOfListBounds = isIndexOutOfListBounds;
|
|
5402
5867
|
exports.isInteractiveElement = isInteractiveElement;
|
|
5868
|
+
exports.isLastTraversableNode = isLastTraversableNode;
|
|
5403
5869
|
exports.isListIndexDisabled = isListIndexDisabled;
|
|
5404
5870
|
exports.isMouseLikePointerType = isMouseLikePointerType;
|
|
5405
5871
|
exports.isOutsideEvent = isOutsideEvent;
|
|
5872
|
+
exports.isOverflowElement = isOverflowElement;
|
|
5873
|
+
exports.isTableElement = isTableElement;
|
|
5406
5874
|
exports.isTargetInsideEnabledTrigger = isTargetInsideEnabledTrigger;
|
|
5875
|
+
exports.isTopLayer = isTopLayer;
|
|
5407
5876
|
exports.isTypeableCombobox = isTypeableCombobox;
|
|
5408
5877
|
exports.isTypeableElement = isTypeableElement;
|
|
5409
5878
|
exports.isVirtualClick = isVirtualClick;
|
|
5410
5879
|
exports.isVirtualPointerEvent = isVirtualPointerEvent;
|
|
5880
|
+
exports.isWebKit = isWebKit;
|
|
5411
5881
|
exports.itemPress = itemPress;
|
|
5412
5882
|
exports.jsdom = jsdom;
|
|
5413
5883
|
exports.keyboard = keyboard;
|
|
5414
5884
|
exports.listNavigation = listNavigation;
|
|
5415
5885
|
exports.mac = mac;
|
|
5416
5886
|
exports.matchesFocusVisible = matchesFocusVisible;
|
|
5887
|
+
exports.max = max;
|
|
5417
5888
|
exports.mergeCleanups = mergeCleanups;
|
|
5889
|
+
exports.min = min;
|
|
5418
5890
|
exports.none = none;
|
|
5419
5891
|
exports.outsidePress = outsidePress;
|
|
5420
5892
|
exports.ownerDocument = ownerDocument;
|
|
5421
5893
|
exports.pointer = pointer;
|
|
5422
5894
|
exports.popupStateMapping = popupStateMapping;
|
|
5895
|
+
exports.popupTransitionStateMapping = popupTransitionStateMapping;
|
|
5423
5896
|
exports.pressableTriggerOpenStateMapping = pressableTriggerOpenStateMapping;
|
|
5897
|
+
exports.rectToClientRect = rectToClientRect;
|
|
5898
|
+
exports.round = round;
|
|
5424
5899
|
exports.scrub = scrub;
|
|
5425
5900
|
exports.setPopupOpenState = setPopupOpenState;
|
|
5901
|
+
exports.shimExports = shimExports;
|
|
5426
5902
|
exports.siblingOpen = siblingOpen;
|
|
5427
5903
|
exports.stopEvent = stopEvent;
|
|
5428
5904
|
exports.swipe = swipe;
|
|
@@ -5445,17 +5921,15 @@ exports.useFloatingParentNodeId = useFloatingParentNodeId;
|
|
|
5445
5921
|
exports.useFloatingTree = useFloatingTree;
|
|
5446
5922
|
exports.useId = useId;
|
|
5447
5923
|
exports.useImplicitActiveTrigger = useImplicitActiveTrigger;
|
|
5448
|
-
exports.useInitialOpenSync = useInitialOpenSync;
|
|
5449
5924
|
exports.useIsoLayoutEffect = useIsoLayoutEffect;
|
|
5450
|
-
exports.useOnFirstRender = useOnFirstRender;
|
|
5451
5925
|
exports.useOnMount = useOnMount;
|
|
5452
5926
|
exports.useOpenChangeComplete = useOpenChangeComplete;
|
|
5453
5927
|
exports.useOpenInteractionType = useOpenInteractionType;
|
|
5454
5928
|
exports.useOpenMethodTriggerProps = useOpenMethodTriggerProps;
|
|
5455
5929
|
exports.useOpenStateTransitions = useOpenStateTransitions;
|
|
5456
5930
|
exports.usePopupInteractionProps = usePopupInteractionProps;
|
|
5931
|
+
exports.usePopupRootStore = usePopupRootStore;
|
|
5457
5932
|
exports.usePopupRootSync = usePopupRootSync;
|
|
5458
|
-
exports.usePopupStore = usePopupStore;
|
|
5459
5933
|
exports.useScrollLock = useScrollLock;
|
|
5460
5934
|
exports.useStableCallback = useStableCallback;
|
|
5461
5935
|
exports.useStore = useStore;
|
|
@@ -5468,6 +5942,7 @@ exports.useValueAsRef = useValueAsRef;
|
|
|
5468
5942
|
exports.useValueChanged = useValueChanged;
|
|
5469
5943
|
exports.visuallyHidden = visuallyHidden;
|
|
5470
5944
|
exports.visuallyHiddenInput = visuallyHiddenInput;
|
|
5945
|
+
exports.voiceOver = voiceOver;
|
|
5471
5946
|
exports.webkit = webkit;
|
|
5472
5947
|
exports.wheel = wheel;
|
|
5473
5948
|
exports.windowResize = windowResize;
|