@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
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
var React = require('react');
|
|
4
4
|
var useScrollLock = require('./useScrollLock-cjs.js');
|
|
5
|
-
var floatingUi_utils = require('./floating-ui.utils-cjs.js');
|
|
6
5
|
var useRenderElement = require('./useRenderElement-cjs.js');
|
|
7
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
-
var
|
|
7
|
+
var ReactDOM = require('react-dom');
|
|
9
8
|
|
|
10
9
|
function _interopNamespaceDefault(e) {
|
|
11
10
|
var n = Object.create(null);
|
|
@@ -25,6 +24,1718 @@ function _interopNamespaceDefault(e) {
|
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
|
27
|
+
var ReactDOM__namespace = /*#__PURE__*/_interopNamespaceDefault(ReactDOM);
|
|
28
|
+
|
|
29
|
+
function useOnFirstRender(fn) {
|
|
30
|
+
const ref = React__namespace.useRef(true);
|
|
31
|
+
if (ref.current) {
|
|
32
|
+
ref.current = false;
|
|
33
|
+
fn();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function computeCoordsFromPlacement(_ref, placement, rtl) {
|
|
38
|
+
let {
|
|
39
|
+
reference,
|
|
40
|
+
floating
|
|
41
|
+
} = _ref;
|
|
42
|
+
const sideAxis = useScrollLock.getSideAxis(placement);
|
|
43
|
+
const alignmentAxis = useScrollLock.getAlignmentAxis(placement);
|
|
44
|
+
const alignLength = useScrollLock.getAxisLength(alignmentAxis);
|
|
45
|
+
const side = useScrollLock.getSide(placement);
|
|
46
|
+
const isVertical = sideAxis === 'y';
|
|
47
|
+
const commonX = reference.x + reference.width / 2 - floating.width / 2;
|
|
48
|
+
const commonY = reference.y + reference.height / 2 - floating.height / 2;
|
|
49
|
+
const commonAlign = reference[alignLength] / 2 - floating[alignLength] / 2;
|
|
50
|
+
let coords;
|
|
51
|
+
switch (side) {
|
|
52
|
+
case 'top':
|
|
53
|
+
coords = {
|
|
54
|
+
x: commonX,
|
|
55
|
+
y: reference.y - floating.height
|
|
56
|
+
};
|
|
57
|
+
break;
|
|
58
|
+
case 'bottom':
|
|
59
|
+
coords = {
|
|
60
|
+
x: commonX,
|
|
61
|
+
y: reference.y + reference.height
|
|
62
|
+
};
|
|
63
|
+
break;
|
|
64
|
+
case 'right':
|
|
65
|
+
coords = {
|
|
66
|
+
x: reference.x + reference.width,
|
|
67
|
+
y: commonY
|
|
68
|
+
};
|
|
69
|
+
break;
|
|
70
|
+
case 'left':
|
|
71
|
+
coords = {
|
|
72
|
+
x: reference.x - floating.width,
|
|
73
|
+
y: commonY
|
|
74
|
+
};
|
|
75
|
+
break;
|
|
76
|
+
default:
|
|
77
|
+
coords = {
|
|
78
|
+
x: reference.x,
|
|
79
|
+
y: reference.y
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const alignment = useScrollLock.getAlignment(placement);
|
|
83
|
+
if (alignment) {
|
|
84
|
+
coords[alignmentAxis] += commonAlign * (alignment === 'end' ? 1 : -1) * (rtl && isVertical ? -1 : 1);
|
|
85
|
+
}
|
|
86
|
+
return coords;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Resolves with an object of overflow side offsets that determine how much the
|
|
91
|
+
* element is overflowing a given clipping boundary on each side.
|
|
92
|
+
* - positive = overflowing the boundary by that number of pixels
|
|
93
|
+
* - negative = how many pixels left before it will overflow
|
|
94
|
+
* - 0 = lies flush with the boundary
|
|
95
|
+
* @see https://floating-ui.com/docs/detectOverflow
|
|
96
|
+
*/
|
|
97
|
+
async function detectOverflow(state, options) {
|
|
98
|
+
var _await$platform$isEle;
|
|
99
|
+
if (options === void 0) {
|
|
100
|
+
options = {};
|
|
101
|
+
}
|
|
102
|
+
const {
|
|
103
|
+
x,
|
|
104
|
+
y,
|
|
105
|
+
platform,
|
|
106
|
+
rects,
|
|
107
|
+
elements,
|
|
108
|
+
strategy
|
|
109
|
+
} = state;
|
|
110
|
+
const {
|
|
111
|
+
boundary = 'clippingAncestors',
|
|
112
|
+
rootBoundary = 'viewport',
|
|
113
|
+
elementContext = 'floating',
|
|
114
|
+
altBoundary = false,
|
|
115
|
+
padding = 0
|
|
116
|
+
} = useScrollLock.evaluate(options, state);
|
|
117
|
+
const paddingObject = useScrollLock.getPaddingObject(padding);
|
|
118
|
+
const altContext = elementContext === 'floating' ? 'reference' : 'floating';
|
|
119
|
+
const element = elements[altBoundary ? altContext : elementContext];
|
|
120
|
+
const clippingClientRect = useScrollLock.rectToClientRect(await platform.getClippingRect({
|
|
121
|
+
element: ((_await$platform$isEle = await (platform.isElement == null ? void 0 : platform.isElement(element))) != null ? _await$platform$isEle : true) ? element : element.contextElement || (await (platform.getDocumentElement == null ? void 0 : platform.getDocumentElement(elements.floating))),
|
|
122
|
+
boundary,
|
|
123
|
+
rootBoundary,
|
|
124
|
+
strategy
|
|
125
|
+
}));
|
|
126
|
+
const rect = elementContext === 'floating' ? {
|
|
127
|
+
x,
|
|
128
|
+
y,
|
|
129
|
+
width: rects.floating.width,
|
|
130
|
+
height: rects.floating.height
|
|
131
|
+
} : rects.reference;
|
|
132
|
+
const offsetParent = await (platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(elements.floating));
|
|
133
|
+
const offsetScale = (await (platform.isElement == null ? void 0 : platform.isElement(offsetParent))) && (await (platform.getScale == null ? void 0 : platform.getScale(offsetParent))) || {
|
|
134
|
+
x: 1,
|
|
135
|
+
y: 1
|
|
136
|
+
};
|
|
137
|
+
const elementClientRect = useScrollLock.rectToClientRect(platform.convertOffsetParentRelativeRectToViewportRelativeRect ? await platform.convertOffsetParentRelativeRectToViewportRelativeRect({
|
|
138
|
+
elements,
|
|
139
|
+
rect,
|
|
140
|
+
offsetParent,
|
|
141
|
+
strategy
|
|
142
|
+
}) : rect);
|
|
143
|
+
return {
|
|
144
|
+
top: (clippingClientRect.top - elementClientRect.top + paddingObject.top) / offsetScale.y,
|
|
145
|
+
bottom: (elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom) / offsetScale.y,
|
|
146
|
+
left: (clippingClientRect.left - elementClientRect.left + paddingObject.left) / offsetScale.x,
|
|
147
|
+
right: (elementClientRect.right - clippingClientRect.right + paddingObject.right) / offsetScale.x
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Maximum number of resets that can occur before bailing to avoid infinite reset loops.
|
|
152
|
+
const MAX_RESET_COUNT = 50;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Computes the `x` and `y` coordinates that will place the floating element
|
|
156
|
+
* next to a given reference element.
|
|
157
|
+
*
|
|
158
|
+
* This export does not have any `platform` interface logic. You will need to
|
|
159
|
+
* write one for the platform you are using Floating UI with.
|
|
160
|
+
*/
|
|
161
|
+
const computePosition$1 = async (reference, floating, config) => {
|
|
162
|
+
const {
|
|
163
|
+
placement = 'bottom',
|
|
164
|
+
strategy = 'absolute',
|
|
165
|
+
middleware = [],
|
|
166
|
+
platform
|
|
167
|
+
} = config;
|
|
168
|
+
const platformWithDetectOverflow = platform.detectOverflow ? platform : {
|
|
169
|
+
...platform,
|
|
170
|
+
detectOverflow
|
|
171
|
+
};
|
|
172
|
+
const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(floating));
|
|
173
|
+
let rects = await platform.getElementRects({
|
|
174
|
+
reference,
|
|
175
|
+
floating,
|
|
176
|
+
strategy
|
|
177
|
+
});
|
|
178
|
+
let {
|
|
179
|
+
x,
|
|
180
|
+
y
|
|
181
|
+
} = computeCoordsFromPlacement(rects, placement, rtl);
|
|
182
|
+
let statefulPlacement = placement;
|
|
183
|
+
let resetCount = 0;
|
|
184
|
+
const middlewareData = {};
|
|
185
|
+
for (let i = 0; i < middleware.length; i++) {
|
|
186
|
+
const currentMiddleware = middleware[i];
|
|
187
|
+
if (!currentMiddleware) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
const {
|
|
191
|
+
name,
|
|
192
|
+
fn
|
|
193
|
+
} = currentMiddleware;
|
|
194
|
+
const {
|
|
195
|
+
x: nextX,
|
|
196
|
+
y: nextY,
|
|
197
|
+
data,
|
|
198
|
+
reset
|
|
199
|
+
} = await fn({
|
|
200
|
+
x,
|
|
201
|
+
y,
|
|
202
|
+
initialPlacement: placement,
|
|
203
|
+
placement: statefulPlacement,
|
|
204
|
+
strategy,
|
|
205
|
+
middlewareData,
|
|
206
|
+
rects,
|
|
207
|
+
platform: platformWithDetectOverflow,
|
|
208
|
+
elements: {
|
|
209
|
+
reference,
|
|
210
|
+
floating
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
x = nextX != null ? nextX : x;
|
|
214
|
+
y = nextY != null ? nextY : y;
|
|
215
|
+
middlewareData[name] = {
|
|
216
|
+
...middlewareData[name],
|
|
217
|
+
...data
|
|
218
|
+
};
|
|
219
|
+
if (reset && resetCount < MAX_RESET_COUNT) {
|
|
220
|
+
resetCount++;
|
|
221
|
+
if (typeof reset === 'object') {
|
|
222
|
+
if (reset.placement) {
|
|
223
|
+
statefulPlacement = reset.placement;
|
|
224
|
+
}
|
|
225
|
+
if (reset.rects) {
|
|
226
|
+
rects = reset.rects === true ? await platform.getElementRects({
|
|
227
|
+
reference,
|
|
228
|
+
floating,
|
|
229
|
+
strategy
|
|
230
|
+
}) : reset.rects;
|
|
231
|
+
}
|
|
232
|
+
({
|
|
233
|
+
x,
|
|
234
|
+
y
|
|
235
|
+
} = computeCoordsFromPlacement(rects, statefulPlacement, rtl));
|
|
236
|
+
}
|
|
237
|
+
i = -1;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return {
|
|
241
|
+
x,
|
|
242
|
+
y,
|
|
243
|
+
placement: statefulPlacement,
|
|
244
|
+
strategy,
|
|
245
|
+
middlewareData
|
|
246
|
+
};
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Optimizes the visibility of the floating element by flipping the `placement`
|
|
251
|
+
* in order to keep it in view when the preferred placement(s) will overflow the
|
|
252
|
+
* clipping boundary. Alternative to `autoPlacement`.
|
|
253
|
+
* @see https://floating-ui.com/docs/flip
|
|
254
|
+
*/
|
|
255
|
+
const flip$2 = function (options) {
|
|
256
|
+
if (options === void 0) {
|
|
257
|
+
options = {};
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
name: 'flip',
|
|
261
|
+
options,
|
|
262
|
+
async fn(state) {
|
|
263
|
+
var _middlewareData$arrow, _middlewareData$flip;
|
|
264
|
+
const {
|
|
265
|
+
placement,
|
|
266
|
+
middlewareData,
|
|
267
|
+
rects,
|
|
268
|
+
initialPlacement,
|
|
269
|
+
platform,
|
|
270
|
+
elements
|
|
271
|
+
} = state;
|
|
272
|
+
const {
|
|
273
|
+
mainAxis: checkMainAxis = true,
|
|
274
|
+
crossAxis: checkCrossAxis = true,
|
|
275
|
+
fallbackPlacements: specifiedFallbackPlacements,
|
|
276
|
+
fallbackStrategy = 'bestFit',
|
|
277
|
+
fallbackAxisSideDirection = 'none',
|
|
278
|
+
flipAlignment = true,
|
|
279
|
+
...detectOverflowOptions
|
|
280
|
+
} = useScrollLock.evaluate(options, state);
|
|
281
|
+
|
|
282
|
+
// If a reset by the arrow was caused due to an alignment offset being
|
|
283
|
+
// added, we should skip any logic now since `flip()` has already done its
|
|
284
|
+
// work.
|
|
285
|
+
// https://github.com/floating-ui/floating-ui/issues/2549#issuecomment-1719601643
|
|
286
|
+
if ((_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) {
|
|
287
|
+
return {};
|
|
288
|
+
}
|
|
289
|
+
const side = useScrollLock.getSide(placement);
|
|
290
|
+
const initialSideAxis = useScrollLock.getSideAxis(initialPlacement);
|
|
291
|
+
const isBasePlacement = useScrollLock.getSide(initialPlacement) === initialPlacement;
|
|
292
|
+
const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating));
|
|
293
|
+
const fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipAlignment ? [useScrollLock.getOppositePlacement(initialPlacement)] : useScrollLock.getExpandedPlacements(initialPlacement));
|
|
294
|
+
const hasFallbackAxisSideDirection = fallbackAxisSideDirection !== 'none';
|
|
295
|
+
if (!specifiedFallbackPlacements && hasFallbackAxisSideDirection) {
|
|
296
|
+
fallbackPlacements.push(...useScrollLock.getOppositeAxisPlacements(initialPlacement, flipAlignment, fallbackAxisSideDirection, rtl));
|
|
297
|
+
}
|
|
298
|
+
const placements = [initialPlacement, ...fallbackPlacements];
|
|
299
|
+
const overflow = await platform.detectOverflow(state, detectOverflowOptions);
|
|
300
|
+
const overflows = [];
|
|
301
|
+
let overflowsData = ((_middlewareData$flip = middlewareData.flip) == null ? void 0 : _middlewareData$flip.overflows) || [];
|
|
302
|
+
if (checkMainAxis) {
|
|
303
|
+
overflows.push(overflow[side]);
|
|
304
|
+
}
|
|
305
|
+
if (checkCrossAxis) {
|
|
306
|
+
const sides = useScrollLock.getAlignmentSides(placement, rects, rtl);
|
|
307
|
+
overflows.push(overflow[sides[0]], overflow[sides[1]]);
|
|
308
|
+
}
|
|
309
|
+
overflowsData = [...overflowsData, {
|
|
310
|
+
placement,
|
|
311
|
+
overflows
|
|
312
|
+
}];
|
|
313
|
+
|
|
314
|
+
// One or more sides is overflowing.
|
|
315
|
+
if (!overflows.every(side => side <= 0)) {
|
|
316
|
+
var _middlewareData$flip2, _overflowsData$filter;
|
|
317
|
+
const nextIndex = (((_middlewareData$flip2 = middlewareData.flip) == null ? void 0 : _middlewareData$flip2.index) || 0) + 1;
|
|
318
|
+
const nextPlacement = placements[nextIndex];
|
|
319
|
+
if (nextPlacement) {
|
|
320
|
+
const ignoreCrossAxisOverflow = checkCrossAxis === 'alignment' ? initialSideAxis !== useScrollLock.getSideAxis(nextPlacement) : false;
|
|
321
|
+
if (!ignoreCrossAxisOverflow ||
|
|
322
|
+
// We leave the current main axis only if every placement on that axis
|
|
323
|
+
// overflows the main axis.
|
|
324
|
+
overflowsData.every(d => useScrollLock.getSideAxis(d.placement) === initialSideAxis ? d.overflows[0] > 0 : true)) {
|
|
325
|
+
// Try next placement and re-run the lifecycle.
|
|
326
|
+
return {
|
|
327
|
+
data: {
|
|
328
|
+
index: nextIndex,
|
|
329
|
+
overflows: overflowsData
|
|
330
|
+
},
|
|
331
|
+
reset: {
|
|
332
|
+
placement: nextPlacement
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// First, find the candidates that fit on the mainAxis side of overflow,
|
|
339
|
+
// then find the placement that fits the best on the main crossAxis side.
|
|
340
|
+
let resetPlacement = (_overflowsData$filter = overflowsData.filter(d => d.overflows[0] <= 0).sort((a, b) => a.overflows[1] - b.overflows[1])[0]) == null ? void 0 : _overflowsData$filter.placement;
|
|
341
|
+
|
|
342
|
+
// Otherwise fallback.
|
|
343
|
+
if (!resetPlacement) {
|
|
344
|
+
switch (fallbackStrategy) {
|
|
345
|
+
case 'bestFit':
|
|
346
|
+
{
|
|
347
|
+
var _overflowsData$filter2;
|
|
348
|
+
const placement = (_overflowsData$filter2 = overflowsData.filter(d => {
|
|
349
|
+
if (hasFallbackAxisSideDirection) {
|
|
350
|
+
const currentSideAxis = useScrollLock.getSideAxis(d.placement);
|
|
351
|
+
return currentSideAxis === initialSideAxis ||
|
|
352
|
+
// Create a bias to the `y` side axis due to horizontal
|
|
353
|
+
// reading directions favoring greater width.
|
|
354
|
+
currentSideAxis === 'y';
|
|
355
|
+
}
|
|
356
|
+
return true;
|
|
357
|
+
}).map(d => [d.placement, d.overflows.filter(overflow => overflow > 0).reduce((acc, overflow) => acc + overflow, 0)]).sort((a, b) => a[1] - b[1])[0]) == null ? void 0 : _overflowsData$filter2[0];
|
|
358
|
+
if (placement) {
|
|
359
|
+
resetPlacement = placement;
|
|
360
|
+
}
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
case 'initialPlacement':
|
|
364
|
+
resetPlacement = initialPlacement;
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (placement !== resetPlacement) {
|
|
369
|
+
return {
|
|
370
|
+
reset: {
|
|
371
|
+
placement: resetPlacement
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return {};
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
const originSides = /*#__PURE__*/new Set(['left', 'top']);
|
|
382
|
+
|
|
383
|
+
// For type backwards-compatibility, the `OffsetOptions` type was also
|
|
384
|
+
// Derivable.
|
|
385
|
+
|
|
386
|
+
async function convertValueToCoords(state, options) {
|
|
387
|
+
const {
|
|
388
|
+
placement,
|
|
389
|
+
platform,
|
|
390
|
+
elements
|
|
391
|
+
} = state;
|
|
392
|
+
const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating));
|
|
393
|
+
const side = useScrollLock.getSide(placement);
|
|
394
|
+
const alignment = useScrollLock.getAlignment(placement);
|
|
395
|
+
const isVertical = useScrollLock.getSideAxis(placement) === 'y';
|
|
396
|
+
const mainAxisMulti = originSides.has(side) ? -1 : 1;
|
|
397
|
+
const crossAxisMulti = rtl && isVertical ? -1 : 1;
|
|
398
|
+
const rawValue = useScrollLock.evaluate(options, state);
|
|
399
|
+
|
|
400
|
+
// eslint-disable-next-line prefer-const
|
|
401
|
+
let {
|
|
402
|
+
mainAxis,
|
|
403
|
+
crossAxis,
|
|
404
|
+
alignmentAxis
|
|
405
|
+
} = typeof rawValue === 'number' ? {
|
|
406
|
+
mainAxis: rawValue,
|
|
407
|
+
crossAxis: 0,
|
|
408
|
+
alignmentAxis: null
|
|
409
|
+
} : {
|
|
410
|
+
mainAxis: rawValue.mainAxis || 0,
|
|
411
|
+
crossAxis: rawValue.crossAxis || 0,
|
|
412
|
+
alignmentAxis: rawValue.alignmentAxis
|
|
413
|
+
};
|
|
414
|
+
if (alignment && typeof alignmentAxis === 'number') {
|
|
415
|
+
crossAxis = alignment === 'end' ? alignmentAxis * -1 : alignmentAxis;
|
|
416
|
+
}
|
|
417
|
+
return isVertical ? {
|
|
418
|
+
x: crossAxis * crossAxisMulti,
|
|
419
|
+
y: mainAxis * mainAxisMulti
|
|
420
|
+
} : {
|
|
421
|
+
x: mainAxis * mainAxisMulti,
|
|
422
|
+
y: crossAxis * crossAxisMulti
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Modifies the placement by translating the floating element along the
|
|
428
|
+
* specified axes.
|
|
429
|
+
* A number (shorthand for `mainAxis` or distance), or an axes configuration
|
|
430
|
+
* object may be passed.
|
|
431
|
+
* @see https://floating-ui.com/docs/offset
|
|
432
|
+
*/
|
|
433
|
+
const offset$2 = function (options) {
|
|
434
|
+
if (options === void 0) {
|
|
435
|
+
options = 0;
|
|
436
|
+
}
|
|
437
|
+
return {
|
|
438
|
+
name: 'offset',
|
|
439
|
+
options,
|
|
440
|
+
async fn(state) {
|
|
441
|
+
var _middlewareData$offse, _middlewareData$arrow;
|
|
442
|
+
const {
|
|
443
|
+
x,
|
|
444
|
+
y,
|
|
445
|
+
placement,
|
|
446
|
+
middlewareData
|
|
447
|
+
} = state;
|
|
448
|
+
const diffCoords = await convertValueToCoords(state, options);
|
|
449
|
+
|
|
450
|
+
// If the placement is the same and the arrow caused an alignment offset
|
|
451
|
+
// then we don't need to change the positioning coordinates.
|
|
452
|
+
if (placement === ((_middlewareData$offse = middlewareData.offset) == null ? void 0 : _middlewareData$offse.placement) && (_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) {
|
|
453
|
+
return {};
|
|
454
|
+
}
|
|
455
|
+
return {
|
|
456
|
+
x: x + diffCoords.x,
|
|
457
|
+
y: y + diffCoords.y,
|
|
458
|
+
data: {
|
|
459
|
+
...diffCoords,
|
|
460
|
+
placement
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Optimizes the visibility of the floating element by shifting it in order to
|
|
469
|
+
* keep it in view when it will overflow the clipping boundary.
|
|
470
|
+
* @see https://floating-ui.com/docs/shift
|
|
471
|
+
*/
|
|
472
|
+
const shift$2 = function (options) {
|
|
473
|
+
if (options === void 0) {
|
|
474
|
+
options = {};
|
|
475
|
+
}
|
|
476
|
+
return {
|
|
477
|
+
name: 'shift',
|
|
478
|
+
options,
|
|
479
|
+
async fn(state) {
|
|
480
|
+
const {
|
|
481
|
+
x,
|
|
482
|
+
y,
|
|
483
|
+
placement,
|
|
484
|
+
platform
|
|
485
|
+
} = state;
|
|
486
|
+
const {
|
|
487
|
+
mainAxis: checkMainAxis = true,
|
|
488
|
+
crossAxis: checkCrossAxis = false,
|
|
489
|
+
limiter = {
|
|
490
|
+
fn: _ref => {
|
|
491
|
+
let {
|
|
492
|
+
x,
|
|
493
|
+
y
|
|
494
|
+
} = _ref;
|
|
495
|
+
return {
|
|
496
|
+
x,
|
|
497
|
+
y
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
},
|
|
501
|
+
...detectOverflowOptions
|
|
502
|
+
} = useScrollLock.evaluate(options, state);
|
|
503
|
+
const coords = {
|
|
504
|
+
x,
|
|
505
|
+
y
|
|
506
|
+
};
|
|
507
|
+
const overflow = await platform.detectOverflow(state, detectOverflowOptions);
|
|
508
|
+
const crossAxis = useScrollLock.getSideAxis(placement);
|
|
509
|
+
const mainAxis = useScrollLock.getOppositeAxis(crossAxis);
|
|
510
|
+
let mainAxisCoord = coords[mainAxis];
|
|
511
|
+
let crossAxisCoord = coords[crossAxis];
|
|
512
|
+
const clampCoord = (axis, coord) => useScrollLock.clamp(coord + overflow[axis === 'y' ? 'top' : 'left'], coord, coord - overflow[axis === 'y' ? 'bottom' : 'right']);
|
|
513
|
+
if (checkMainAxis) {
|
|
514
|
+
mainAxisCoord = clampCoord(mainAxis, mainAxisCoord);
|
|
515
|
+
}
|
|
516
|
+
if (checkCrossAxis) {
|
|
517
|
+
crossAxisCoord = clampCoord(crossAxis, crossAxisCoord);
|
|
518
|
+
}
|
|
519
|
+
const limitedCoords = limiter.fn({
|
|
520
|
+
...state,
|
|
521
|
+
[mainAxis]: mainAxisCoord,
|
|
522
|
+
[crossAxis]: crossAxisCoord
|
|
523
|
+
});
|
|
524
|
+
return {
|
|
525
|
+
...limitedCoords,
|
|
526
|
+
data: {
|
|
527
|
+
x: limitedCoords.x - x,
|
|
528
|
+
y: limitedCoords.y - y,
|
|
529
|
+
enabled: {
|
|
530
|
+
[mainAxis]: checkMainAxis,
|
|
531
|
+
[crossAxis]: checkCrossAxis
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
};
|
|
538
|
+
/**
|
|
539
|
+
* Built-in `limiter` that will stop `shift()` at a certain point.
|
|
540
|
+
*/
|
|
541
|
+
const limitShift$2 = function (options) {
|
|
542
|
+
if (options === void 0) {
|
|
543
|
+
options = {};
|
|
544
|
+
}
|
|
545
|
+
return {
|
|
546
|
+
options,
|
|
547
|
+
fn(state) {
|
|
548
|
+
var _rawOffset$mainAxis, _rawOffset$crossAxis;
|
|
549
|
+
const {
|
|
550
|
+
x,
|
|
551
|
+
y,
|
|
552
|
+
placement,
|
|
553
|
+
rects,
|
|
554
|
+
middlewareData
|
|
555
|
+
} = state;
|
|
556
|
+
const {
|
|
557
|
+
offset = 0,
|
|
558
|
+
mainAxis: checkMainAxis = true,
|
|
559
|
+
crossAxis: checkCrossAxis = true
|
|
560
|
+
} = useScrollLock.evaluate(options, state);
|
|
561
|
+
const coords = {
|
|
562
|
+
x,
|
|
563
|
+
y
|
|
564
|
+
};
|
|
565
|
+
const crossAxis = useScrollLock.getSideAxis(placement);
|
|
566
|
+
const mainAxis = useScrollLock.getOppositeAxis(crossAxis);
|
|
567
|
+
let mainAxisCoord = coords[mainAxis];
|
|
568
|
+
let crossAxisCoord = coords[crossAxis];
|
|
569
|
+
const rawOffset = useScrollLock.evaluate(offset, state);
|
|
570
|
+
const computedOffset = typeof rawOffset === 'number' ? {
|
|
571
|
+
mainAxis: rawOffset,
|
|
572
|
+
crossAxis: 0
|
|
573
|
+
} : {
|
|
574
|
+
mainAxis: (_rawOffset$mainAxis = rawOffset.mainAxis) != null ? _rawOffset$mainAxis : 0,
|
|
575
|
+
crossAxis: (_rawOffset$crossAxis = rawOffset.crossAxis) != null ? _rawOffset$crossAxis : 0
|
|
576
|
+
};
|
|
577
|
+
if (checkMainAxis) {
|
|
578
|
+
const len = mainAxis === 'y' ? 'height' : 'width';
|
|
579
|
+
const limitMin = rects.reference[mainAxis] - rects.floating[len] + computedOffset.mainAxis;
|
|
580
|
+
const limitMax = rects.reference[mainAxis] + rects.reference[len] - computedOffset.mainAxis;
|
|
581
|
+
if (mainAxisCoord < limitMin) {
|
|
582
|
+
mainAxisCoord = limitMin;
|
|
583
|
+
} else if (mainAxisCoord > limitMax) {
|
|
584
|
+
mainAxisCoord = limitMax;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
if (checkCrossAxis) {
|
|
588
|
+
var _middlewareData$offse, _middlewareData$offse2;
|
|
589
|
+
const len = mainAxis === 'y' ? 'width' : 'height';
|
|
590
|
+
const isOriginSide = originSides.has(useScrollLock.getSide(placement));
|
|
591
|
+
const limitMin = rects.reference[crossAxis] - rects.floating[len] + (isOriginSide ? ((_middlewareData$offse = middlewareData.offset) == null ? void 0 : _middlewareData$offse[crossAxis]) || 0 : 0) + (isOriginSide ? 0 : computedOffset.crossAxis);
|
|
592
|
+
const limitMax = rects.reference[crossAxis] + rects.reference[len] + (isOriginSide ? 0 : ((_middlewareData$offse2 = middlewareData.offset) == null ? void 0 : _middlewareData$offse2[crossAxis]) || 0) - (isOriginSide ? computedOffset.crossAxis : 0);
|
|
593
|
+
if (crossAxisCoord < limitMin) {
|
|
594
|
+
crossAxisCoord = limitMin;
|
|
595
|
+
} else if (crossAxisCoord > limitMax) {
|
|
596
|
+
crossAxisCoord = limitMax;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
return {
|
|
600
|
+
[mainAxis]: mainAxisCoord,
|
|
601
|
+
[crossAxis]: crossAxisCoord
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
// Method syntax keeps callback parameters bivariant, but expressing the
|
|
608
|
+
// explicit `| undefined` required by `exactOptionalPropertyTypes` needs
|
|
609
|
+
// property syntax, which is contravariant under `strictFunctionTypes`.
|
|
610
|
+
// Extracting the function from a method position restores that bivariance so
|
|
611
|
+
// consumers can still assign callbacks with narrower parameter types.
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Provides data that allows you to change the size of the floating element —
|
|
615
|
+
* for instance, prevent it from overflowing the clipping boundary or match the
|
|
616
|
+
* width of the reference element.
|
|
617
|
+
* @see https://floating-ui.com/docs/size
|
|
618
|
+
*/
|
|
619
|
+
const size$2 = function (options) {
|
|
620
|
+
if (options === void 0) {
|
|
621
|
+
options = {};
|
|
622
|
+
}
|
|
623
|
+
return {
|
|
624
|
+
name: 'size',
|
|
625
|
+
options,
|
|
626
|
+
async fn(state) {
|
|
627
|
+
const {
|
|
628
|
+
placement,
|
|
629
|
+
rects,
|
|
630
|
+
platform,
|
|
631
|
+
elements
|
|
632
|
+
} = state;
|
|
633
|
+
const {
|
|
634
|
+
apply = () => {},
|
|
635
|
+
...detectOverflowOptions
|
|
636
|
+
} = useScrollLock.evaluate(options, state);
|
|
637
|
+
const overflow = await platform.detectOverflow(state, detectOverflowOptions);
|
|
638
|
+
const side = useScrollLock.getSide(placement);
|
|
639
|
+
const alignment = useScrollLock.getAlignment(placement);
|
|
640
|
+
const isYAxis = useScrollLock.getSideAxis(placement) === 'y';
|
|
641
|
+
const {
|
|
642
|
+
width,
|
|
643
|
+
height
|
|
644
|
+
} = rects.floating;
|
|
645
|
+
let heightSide;
|
|
646
|
+
let widthSide;
|
|
647
|
+
if (side === 'top' || side === 'bottom') {
|
|
648
|
+
heightSide = side;
|
|
649
|
+
widthSide = alignment === ((await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating))) ? 'start' : 'end') ? 'left' : 'right';
|
|
650
|
+
} else {
|
|
651
|
+
widthSide = side;
|
|
652
|
+
heightSide = alignment === 'end' ? 'top' : 'bottom';
|
|
653
|
+
}
|
|
654
|
+
const maximumClippingHeight = height - overflow.top - overflow.bottom;
|
|
655
|
+
const maximumClippingWidth = width - overflow.left - overflow.right;
|
|
656
|
+
const overflowAvailableHeight = useScrollLock.min(height - overflow[heightSide], maximumClippingHeight);
|
|
657
|
+
const overflowAvailableWidth = useScrollLock.min(width - overflow[widthSide], maximumClippingWidth);
|
|
658
|
+
const shiftData = state.middlewareData.shift;
|
|
659
|
+
const noShift = !shiftData;
|
|
660
|
+
let availableHeight = overflowAvailableHeight;
|
|
661
|
+
let availableWidth = overflowAvailableWidth;
|
|
662
|
+
if (shiftData != null && shiftData.enabled.x) {
|
|
663
|
+
availableWidth = maximumClippingWidth;
|
|
664
|
+
}
|
|
665
|
+
if (shiftData != null && shiftData.enabled.y) {
|
|
666
|
+
availableHeight = maximumClippingHeight;
|
|
667
|
+
}
|
|
668
|
+
if (noShift && !alignment) {
|
|
669
|
+
if (isYAxis) {
|
|
670
|
+
availableWidth = width - 2 * useScrollLock.max(overflow.left, overflow.right);
|
|
671
|
+
} else {
|
|
672
|
+
availableHeight = height - 2 * useScrollLock.max(overflow.top, overflow.bottom);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
await apply({
|
|
676
|
+
...state,
|
|
677
|
+
availableWidth,
|
|
678
|
+
availableHeight
|
|
679
|
+
});
|
|
680
|
+
const nextDimensions = await platform.getDimensions(elements.floating);
|
|
681
|
+
if (width !== nextDimensions.width || height !== nextDimensions.height) {
|
|
682
|
+
return {
|
|
683
|
+
reset: {
|
|
684
|
+
rects: true
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
return {};
|
|
689
|
+
}
|
|
690
|
+
};
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
function getCssDimensions(element) {
|
|
694
|
+
const css = useScrollLock.getComputedStyle(element);
|
|
695
|
+
// In testing environments, the `width` and `height` properties are empty
|
|
696
|
+
// strings for SVG elements, returning NaN. Fallback to `0` in this case.
|
|
697
|
+
let width = parseFloat(css.width) || 0;
|
|
698
|
+
let height = parseFloat(css.height) || 0;
|
|
699
|
+
const hasOffset = useScrollLock.isHTMLElement(element);
|
|
700
|
+
const offsetWidth = hasOffset ? element.offsetWidth : width;
|
|
701
|
+
const offsetHeight = hasOffset ? element.offsetHeight : height;
|
|
702
|
+
const shouldFallback = useScrollLock.round(width) !== offsetWidth || useScrollLock.round(height) !== offsetHeight;
|
|
703
|
+
if (shouldFallback) {
|
|
704
|
+
width = offsetWidth;
|
|
705
|
+
height = offsetHeight;
|
|
706
|
+
}
|
|
707
|
+
return {
|
|
708
|
+
width,
|
|
709
|
+
height,
|
|
710
|
+
$: shouldFallback
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
function unwrapElement(element) {
|
|
715
|
+
return !useScrollLock.isElement(element) ? element.contextElement : element;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
function getScale(element) {
|
|
719
|
+
const domElement = unwrapElement(element);
|
|
720
|
+
if (!useScrollLock.isHTMLElement(domElement)) {
|
|
721
|
+
return useScrollLock.createCoords(1);
|
|
722
|
+
}
|
|
723
|
+
const rect = domElement.getBoundingClientRect();
|
|
724
|
+
const {
|
|
725
|
+
width,
|
|
726
|
+
height,
|
|
727
|
+
$
|
|
728
|
+
} = getCssDimensions(domElement);
|
|
729
|
+
let x = ($ ? useScrollLock.round(rect.width) : rect.width) / width;
|
|
730
|
+
let y = ($ ? useScrollLock.round(rect.height) : rect.height) / height;
|
|
731
|
+
|
|
732
|
+
// 0, NaN, or Infinity should always fallback to 1.
|
|
733
|
+
|
|
734
|
+
if (!x || !Number.isFinite(x)) {
|
|
735
|
+
x = 1;
|
|
736
|
+
}
|
|
737
|
+
if (!y || !Number.isFinite(y)) {
|
|
738
|
+
y = 1;
|
|
739
|
+
}
|
|
740
|
+
return {
|
|
741
|
+
x,
|
|
742
|
+
y
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
const noOffsets = /*#__PURE__*/useScrollLock.createCoords(0);
|
|
747
|
+
function getVisualOffsets(element) {
|
|
748
|
+
const win = useScrollLock.getWindow(element);
|
|
749
|
+
if (!useScrollLock.isWebKit() || !win.visualViewport) {
|
|
750
|
+
return noOffsets;
|
|
751
|
+
}
|
|
752
|
+
return {
|
|
753
|
+
x: win.visualViewport.offsetLeft,
|
|
754
|
+
y: win.visualViewport.offsetTop
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
function shouldAddVisualOffsets(element, isFixed, floatingOffsetParent) {
|
|
758
|
+
if (isFixed === void 0) {
|
|
759
|
+
isFixed = false;
|
|
760
|
+
}
|
|
761
|
+
return !!floatingOffsetParent && isFixed && floatingOffsetParent === useScrollLock.getWindow(element);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
function getBoundingClientRect(element, includeScale, isFixedStrategy, offsetParent) {
|
|
765
|
+
if (includeScale === void 0) {
|
|
766
|
+
includeScale = false;
|
|
767
|
+
}
|
|
768
|
+
if (isFixedStrategy === void 0) {
|
|
769
|
+
isFixedStrategy = false;
|
|
770
|
+
}
|
|
771
|
+
const clientRect = element.getBoundingClientRect();
|
|
772
|
+
const domElement = unwrapElement(element);
|
|
773
|
+
let scale = useScrollLock.createCoords(1);
|
|
774
|
+
if (includeScale) {
|
|
775
|
+
if (offsetParent) {
|
|
776
|
+
if (useScrollLock.isElement(offsetParent)) {
|
|
777
|
+
scale = getScale(offsetParent);
|
|
778
|
+
}
|
|
779
|
+
} else {
|
|
780
|
+
scale = getScale(element);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
const visualOffsets = shouldAddVisualOffsets(domElement, isFixedStrategy, offsetParent) ? getVisualOffsets(domElement) : useScrollLock.createCoords(0);
|
|
784
|
+
let x = (clientRect.left + visualOffsets.x) / scale.x;
|
|
785
|
+
let y = (clientRect.top + visualOffsets.y) / scale.y;
|
|
786
|
+
let width = clientRect.width / scale.x;
|
|
787
|
+
let height = clientRect.height / scale.y;
|
|
788
|
+
if (domElement && offsetParent) {
|
|
789
|
+
const win = useScrollLock.getWindow(domElement);
|
|
790
|
+
const offsetWin = useScrollLock.isElement(offsetParent) ? useScrollLock.getWindow(offsetParent) : offsetParent;
|
|
791
|
+
let currentWin = win;
|
|
792
|
+
let currentIFrame = useScrollLock.getFrameElement(currentWin);
|
|
793
|
+
while (currentIFrame && offsetWin !== currentWin) {
|
|
794
|
+
const iframeScale = getScale(currentIFrame);
|
|
795
|
+
const iframeRect = currentIFrame.getBoundingClientRect();
|
|
796
|
+
const css = useScrollLock.getComputedStyle(currentIFrame);
|
|
797
|
+
const left = iframeRect.left + (currentIFrame.clientLeft + parseFloat(css.paddingLeft)) * iframeScale.x;
|
|
798
|
+
const top = iframeRect.top + (currentIFrame.clientTop + parseFloat(css.paddingTop)) * iframeScale.y;
|
|
799
|
+
x *= iframeScale.x;
|
|
800
|
+
y *= iframeScale.y;
|
|
801
|
+
width *= iframeScale.x;
|
|
802
|
+
height *= iframeScale.y;
|
|
803
|
+
x += left;
|
|
804
|
+
y += top;
|
|
805
|
+
currentWin = useScrollLock.getWindow(currentIFrame);
|
|
806
|
+
currentIFrame = useScrollLock.getFrameElement(currentWin);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
return useScrollLock.rectToClientRect({
|
|
810
|
+
width,
|
|
811
|
+
height,
|
|
812
|
+
x,
|
|
813
|
+
y
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// If <html> has a CSS width greater than the viewport, then this will be
|
|
818
|
+
// incorrect for RTL.
|
|
819
|
+
function getWindowScrollBarX(element, rect) {
|
|
820
|
+
const leftScroll = useScrollLock.getNodeScroll(element).scrollLeft;
|
|
821
|
+
if (!rect) {
|
|
822
|
+
return getBoundingClientRect(useScrollLock.getDocumentElement(element)).left + leftScroll;
|
|
823
|
+
}
|
|
824
|
+
return rect.left + leftScroll;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
function getHTMLOffset(documentElement, scroll) {
|
|
828
|
+
const htmlRect = documentElement.getBoundingClientRect();
|
|
829
|
+
const x = htmlRect.left + scroll.scrollLeft - getWindowScrollBarX(documentElement, htmlRect);
|
|
830
|
+
const y = htmlRect.top + scroll.scrollTop;
|
|
831
|
+
return {
|
|
832
|
+
x,
|
|
833
|
+
y
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
function convertOffsetParentRelativeRectToViewportRelativeRect(_ref) {
|
|
838
|
+
let {
|
|
839
|
+
elements,
|
|
840
|
+
rect,
|
|
841
|
+
offsetParent,
|
|
842
|
+
strategy
|
|
843
|
+
} = _ref;
|
|
844
|
+
const isFixed = strategy === 'fixed';
|
|
845
|
+
const documentElement = useScrollLock.getDocumentElement(offsetParent);
|
|
846
|
+
const topLayer = elements ? useScrollLock.isTopLayer(elements.floating) : false;
|
|
847
|
+
if (offsetParent === documentElement || topLayer && isFixed) {
|
|
848
|
+
return rect;
|
|
849
|
+
}
|
|
850
|
+
let scroll = {
|
|
851
|
+
scrollLeft: 0,
|
|
852
|
+
scrollTop: 0
|
|
853
|
+
};
|
|
854
|
+
let scale = useScrollLock.createCoords(1);
|
|
855
|
+
const offsets = useScrollLock.createCoords(0);
|
|
856
|
+
const isOffsetParentAnElement = useScrollLock.isHTMLElement(offsetParent);
|
|
857
|
+
if (isOffsetParentAnElement || !isFixed) {
|
|
858
|
+
if (useScrollLock.getNodeName(offsetParent) !== 'body' || useScrollLock.isOverflowElement(documentElement)) {
|
|
859
|
+
scroll = useScrollLock.getNodeScroll(offsetParent);
|
|
860
|
+
}
|
|
861
|
+
if (isOffsetParentAnElement) {
|
|
862
|
+
const offsetRect = getBoundingClientRect(offsetParent);
|
|
863
|
+
scale = getScale(offsetParent);
|
|
864
|
+
offsets.x = offsetRect.x + offsetParent.clientLeft;
|
|
865
|
+
offsets.y = offsetRect.y + offsetParent.clientTop;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
const htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll) : useScrollLock.createCoords(0);
|
|
869
|
+
return {
|
|
870
|
+
width: rect.width * scale.x,
|
|
871
|
+
height: rect.height * scale.y,
|
|
872
|
+
x: rect.x * scale.x - scroll.scrollLeft * scale.x + offsets.x + htmlOffset.x,
|
|
873
|
+
y: rect.y * scale.y - scroll.scrollTop * scale.y + offsets.y + htmlOffset.y
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
function getClientRects(element) {
|
|
878
|
+
return element.getClientRects ? Array.from(element.getClientRects()) : [];
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
// Gets the entire size of the scrollable document area, even extending outside
|
|
882
|
+
// of the `<html>` and `<body>` rect bounds if horizontally scrollable.
|
|
883
|
+
function getDocumentRect(html) {
|
|
884
|
+
const scroll = useScrollLock.getNodeScroll(html);
|
|
885
|
+
const body = html.ownerDocument.body;
|
|
886
|
+
const width = useScrollLock.max(html.scrollWidth, html.clientWidth, body.scrollWidth, body.clientWidth);
|
|
887
|
+
const height = useScrollLock.max(html.scrollHeight, html.clientHeight, body.scrollHeight, body.clientHeight);
|
|
888
|
+
let x = -scroll.scrollLeft + getWindowScrollBarX(html);
|
|
889
|
+
const y = -scroll.scrollTop;
|
|
890
|
+
if (useScrollLock.getComputedStyle(body).direction === 'rtl') {
|
|
891
|
+
x += useScrollLock.max(html.clientWidth, body.clientWidth) - width;
|
|
892
|
+
}
|
|
893
|
+
return {
|
|
894
|
+
width,
|
|
895
|
+
height,
|
|
896
|
+
x,
|
|
897
|
+
y
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
// Safety check: ensure the scrollbar space is reasonable in case this
|
|
902
|
+
// calculation is affected by unusual styles.
|
|
903
|
+
// Most scrollbars leave 15-18px of space.
|
|
904
|
+
const SCROLLBAR_MAX = 25;
|
|
905
|
+
function getViewportRect(element, strategy, rootBoundary) {
|
|
906
|
+
if (rootBoundary === void 0) {
|
|
907
|
+
rootBoundary = 'viewport';
|
|
908
|
+
}
|
|
909
|
+
const isLayoutViewport = rootBoundary === 'layoutViewport';
|
|
910
|
+
const win = useScrollLock.getWindow(element);
|
|
911
|
+
const html = useScrollLock.getDocumentElement(element);
|
|
912
|
+
const visualViewport = win.visualViewport;
|
|
913
|
+
let width = html.clientWidth;
|
|
914
|
+
let height = html.clientHeight;
|
|
915
|
+
let x = 0;
|
|
916
|
+
let y = 0;
|
|
917
|
+
if (visualViewport) {
|
|
918
|
+
// Client coordinates are relative to the layout viewport, except in
|
|
919
|
+
// WebKit with an `absolute` strategy, where they are relative to the
|
|
920
|
+
// visual viewport.
|
|
921
|
+
const layoutRelativeClientCoords = !useScrollLock.isWebKit() || strategy === 'fixed';
|
|
922
|
+
if (isLayoutViewport) {
|
|
923
|
+
if (!layoutRelativeClientCoords) {
|
|
924
|
+
x = -visualViewport.offsetLeft;
|
|
925
|
+
y = -visualViewport.offsetTop;
|
|
926
|
+
}
|
|
927
|
+
} else {
|
|
928
|
+
width = visualViewport.width;
|
|
929
|
+
height = visualViewport.height;
|
|
930
|
+
if (layoutRelativeClientCoords) {
|
|
931
|
+
x = visualViewport.offsetLeft;
|
|
932
|
+
y = visualViewport.offsetTop;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
const windowScrollbarX = getWindowScrollBarX(html);
|
|
937
|
+
// `scrollbar-gutter: stable` on the <html> reserves gutter space that shrinks
|
|
938
|
+
// the visual width but isn't reflected in `html.clientWidth`, so subtract it.
|
|
939
|
+
// Only the inline-end (right) gutter can hold the scrollbar; `both-edges` also
|
|
940
|
+
// reserves an empty inline-start gutter that clips nothing, so exclude just
|
|
941
|
+
// the one scrollbar-side gutter — halve the measured (two-gutter) total. A
|
|
942
|
+
// left-side scrollbar (`windowScrollbarX > 0`) is already handled by
|
|
943
|
+
// `getHTMLOffset`/`visualViewport.width`; skip it here.
|
|
944
|
+
if (windowScrollbarX <= 0) {
|
|
945
|
+
const doc = html.ownerDocument;
|
|
946
|
+
const body = doc.body;
|
|
947
|
+
const bodyStyles = getComputedStyle(body);
|
|
948
|
+
const bodyMarginInline = doc.compatMode === 'CSS1Compat' ? parseFloat(bodyStyles.marginLeft) + parseFloat(bodyStyles.marginRight) || 0 : 0;
|
|
949
|
+
const reservedWidth = Math.abs(html.clientWidth - body.clientWidth - bodyMarginInline);
|
|
950
|
+
const gutter = getComputedStyle(html).scrollbarGutter === 'stable both-edges' ? reservedWidth / 2 : reservedWidth;
|
|
951
|
+
if (gutter <= SCROLLBAR_MAX) {
|
|
952
|
+
width -= gutter;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
return {
|
|
956
|
+
width,
|
|
957
|
+
height,
|
|
958
|
+
x,
|
|
959
|
+
y
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
// Returns the inner client rect, subtracting scrollbars if present.
|
|
964
|
+
function getInnerBoundingClientRect(element, strategy) {
|
|
965
|
+
const clientRect = getBoundingClientRect(element, true, strategy === 'fixed');
|
|
966
|
+
const top = clientRect.top + element.clientTop;
|
|
967
|
+
const left = clientRect.left + element.clientLeft;
|
|
968
|
+
const scale = getScale(element);
|
|
969
|
+
const width = element.clientWidth * scale.x;
|
|
970
|
+
const height = element.clientHeight * scale.y;
|
|
971
|
+
const x = left * scale.x;
|
|
972
|
+
const y = top * scale.y;
|
|
973
|
+
return {
|
|
974
|
+
width,
|
|
975
|
+
height,
|
|
976
|
+
x,
|
|
977
|
+
y
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
function getClientRectFromClippingAncestor(element, clippingAncestor, strategy) {
|
|
981
|
+
let rect;
|
|
982
|
+
if (clippingAncestor === 'viewport' || clippingAncestor === 'layoutViewport') {
|
|
983
|
+
rect = getViewportRect(element, strategy, clippingAncestor);
|
|
984
|
+
} else if (clippingAncestor === 'document') {
|
|
985
|
+
rect = getDocumentRect(useScrollLock.getDocumentElement(element));
|
|
986
|
+
} else if (useScrollLock.isElement(clippingAncestor)) {
|
|
987
|
+
rect = getInnerBoundingClientRect(clippingAncestor, strategy);
|
|
988
|
+
} else {
|
|
989
|
+
const visualOffsets = getVisualOffsets(element);
|
|
990
|
+
rect = {
|
|
991
|
+
x: clippingAncestor.x - visualOffsets.x,
|
|
992
|
+
y: clippingAncestor.y - visualOffsets.y,
|
|
993
|
+
width: clippingAncestor.width,
|
|
994
|
+
height: clippingAncestor.height
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
return useScrollLock.rectToClientRect(rect);
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
// A "clipping ancestor" is an `overflow` element with the characteristic of
|
|
1001
|
+
// clipping (or hiding) child elements. This returns all clipping ancestors
|
|
1002
|
+
// of the given element up the tree.
|
|
1003
|
+
function getClippingElementAncestors(element, cache) {
|
|
1004
|
+
const cachedResult = cache.get(element);
|
|
1005
|
+
if (cachedResult) {
|
|
1006
|
+
return cachedResult;
|
|
1007
|
+
}
|
|
1008
|
+
let result = useScrollLock.getOverflowAncestors(element, [], false).filter(el => useScrollLock.isElement(el) && useScrollLock.getNodeName(el) !== 'body');
|
|
1009
|
+
let lastKeptComputedStyle = null;
|
|
1010
|
+
const elementIsFixed = useScrollLock.getComputedStyle(element).position === 'fixed';
|
|
1011
|
+
let currentNode = elementIsFixed ? useScrollLock.getParentNode(element) : element;
|
|
1012
|
+
|
|
1013
|
+
// https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
|
|
1014
|
+
while (useScrollLock.isElement(currentNode) && !useScrollLock.isLastTraversableNode(currentNode)) {
|
|
1015
|
+
const computedStyle = useScrollLock.getComputedStyle(currentNode);
|
|
1016
|
+
const currentNodeIsContaining = useScrollLock.isContainingBlock(currentNode);
|
|
1017
|
+
// Position of the containing block chain below the current node. A fixed
|
|
1018
|
+
// element whose containing block hasn't been found yet is a fixed chain.
|
|
1019
|
+
const lastPosition = lastKeptComputedStyle ? lastKeptComputedStyle.position : elementIsFixed ? 'fixed' : '';
|
|
1020
|
+
|
|
1021
|
+
// A non-containing ancestor does not clip the element when the chain
|
|
1022
|
+
// below it escapes it: a fixed chain escapes all ancestors up to the
|
|
1023
|
+
// next containing block, an absolute chain escapes static ancestors.
|
|
1024
|
+
const shouldDropCurrentNode = !currentNodeIsContaining && (lastPosition === 'fixed' || lastPosition === 'absolute' && computedStyle.position === 'static');
|
|
1025
|
+
if (shouldDropCurrentNode) {
|
|
1026
|
+
// Drop non-containing blocks.
|
|
1027
|
+
result = result.filter(ancestor => ancestor !== currentNode);
|
|
1028
|
+
} else {
|
|
1029
|
+
// The kept node carries the chain position for the next iteration.
|
|
1030
|
+
lastKeptComputedStyle = computedStyle;
|
|
1031
|
+
}
|
|
1032
|
+
currentNode = useScrollLock.getParentNode(currentNode);
|
|
1033
|
+
}
|
|
1034
|
+
cache.set(element, result);
|
|
1035
|
+
return result;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
// Gets the maximum area that the element is visible in due to any number of
|
|
1039
|
+
// clipping ancestors.
|
|
1040
|
+
function getClippingRect(_ref) {
|
|
1041
|
+
let {
|
|
1042
|
+
element,
|
|
1043
|
+
boundary,
|
|
1044
|
+
rootBoundary,
|
|
1045
|
+
strategy
|
|
1046
|
+
} = _ref;
|
|
1047
|
+
const elementClippingAncestors = boundary === 'clippingAncestors' ? useScrollLock.isTopLayer(element) ? [] : getClippingElementAncestors(element, this._c) : [].concat(boundary);
|
|
1048
|
+
const clippingAncestors = [...elementClippingAncestors, rootBoundary];
|
|
1049
|
+
const firstRect = getClientRectFromClippingAncestor(element, clippingAncestors[0], strategy);
|
|
1050
|
+
let top = firstRect.top;
|
|
1051
|
+
let right = firstRect.right;
|
|
1052
|
+
let bottom = firstRect.bottom;
|
|
1053
|
+
let left = firstRect.left;
|
|
1054
|
+
for (let i = 1; i < clippingAncestors.length; i++) {
|
|
1055
|
+
const rect = getClientRectFromClippingAncestor(element, clippingAncestors[i], strategy);
|
|
1056
|
+
top = useScrollLock.max(rect.top, top);
|
|
1057
|
+
right = useScrollLock.min(rect.right, right);
|
|
1058
|
+
bottom = useScrollLock.min(rect.bottom, bottom);
|
|
1059
|
+
left = useScrollLock.max(rect.left, left);
|
|
1060
|
+
}
|
|
1061
|
+
return {
|
|
1062
|
+
width: right - left,
|
|
1063
|
+
height: bottom - top,
|
|
1064
|
+
x: left,
|
|
1065
|
+
y: top
|
|
1066
|
+
};
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
function getDimensions(element) {
|
|
1070
|
+
const {
|
|
1071
|
+
width,
|
|
1072
|
+
height
|
|
1073
|
+
} = getCssDimensions(element);
|
|
1074
|
+
return {
|
|
1075
|
+
width,
|
|
1076
|
+
height
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
function getRectRelativeToOffsetParent(element, offsetParent, strategy) {
|
|
1081
|
+
const isOffsetParentAnElement = useScrollLock.isHTMLElement(offsetParent);
|
|
1082
|
+
const documentElement = useScrollLock.getDocumentElement(offsetParent);
|
|
1083
|
+
const isFixed = strategy === 'fixed';
|
|
1084
|
+
const rect = getBoundingClientRect(element, true, isFixed, offsetParent);
|
|
1085
|
+
let scroll = {
|
|
1086
|
+
scrollLeft: 0,
|
|
1087
|
+
scrollTop: 0
|
|
1088
|
+
};
|
|
1089
|
+
const offsets = useScrollLock.createCoords(0);
|
|
1090
|
+
if (isOffsetParentAnElement || !isFixed) {
|
|
1091
|
+
if (useScrollLock.getNodeName(offsetParent) !== 'body' || useScrollLock.isOverflowElement(documentElement)) {
|
|
1092
|
+
scroll = useScrollLock.getNodeScroll(offsetParent);
|
|
1093
|
+
}
|
|
1094
|
+
if (isOffsetParentAnElement) {
|
|
1095
|
+
const offsetRect = getBoundingClientRect(offsetParent, true, isFixed, offsetParent);
|
|
1096
|
+
offsets.x = offsetRect.x + offsetParent.clientLeft;
|
|
1097
|
+
offsets.y = offsetRect.y + offsetParent.clientTop;
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
// If the <body> scrollbar appears on the left (e.g. RTL systems). Use
|
|
1102
|
+
// Firefox with layout.scrollbar.side = 3 in about:config to test this.
|
|
1103
|
+
if (!isOffsetParentAnElement && documentElement) {
|
|
1104
|
+
offsets.x = getWindowScrollBarX(documentElement);
|
|
1105
|
+
}
|
|
1106
|
+
const htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll) : useScrollLock.createCoords(0);
|
|
1107
|
+
const x = rect.left + scroll.scrollLeft - offsets.x - htmlOffset.x;
|
|
1108
|
+
const y = rect.top + scroll.scrollTop - offsets.y - htmlOffset.y;
|
|
1109
|
+
return {
|
|
1110
|
+
x,
|
|
1111
|
+
y,
|
|
1112
|
+
width: rect.width,
|
|
1113
|
+
height: rect.height
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
function isStaticPositioned(element) {
|
|
1118
|
+
return useScrollLock.getComputedStyle(element).position === 'static';
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
function getTrueOffsetParent(element, polyfill) {
|
|
1122
|
+
if (!useScrollLock.isHTMLElement(element) || useScrollLock.getComputedStyle(element).position === 'fixed') {
|
|
1123
|
+
return null;
|
|
1124
|
+
}
|
|
1125
|
+
if (polyfill) {
|
|
1126
|
+
return polyfill(element);
|
|
1127
|
+
}
|
|
1128
|
+
let rawOffsetParent = element.offsetParent;
|
|
1129
|
+
|
|
1130
|
+
// Firefox returns the <html> element as the offsetParent if it's non-static,
|
|
1131
|
+
// while Chrome and Safari return the <body> element. The <body> element must
|
|
1132
|
+
// be used to perform the correct calculations even if the <html> element is
|
|
1133
|
+
// non-static.
|
|
1134
|
+
if (useScrollLock.getDocumentElement(element) === rawOffsetParent) {
|
|
1135
|
+
rawOffsetParent = rawOffsetParent.ownerDocument.body;
|
|
1136
|
+
}
|
|
1137
|
+
return rawOffsetParent;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
// Gets the closest ancestor positioned element. Handles some edge cases,
|
|
1141
|
+
// such as table ancestors and cross browser bugs.
|
|
1142
|
+
function getOffsetParent(element, polyfill) {
|
|
1143
|
+
const win = useScrollLock.getWindow(element);
|
|
1144
|
+
if (useScrollLock.isTopLayer(element)) {
|
|
1145
|
+
return win;
|
|
1146
|
+
}
|
|
1147
|
+
if (!useScrollLock.isHTMLElement(element)) {
|
|
1148
|
+
let svgOffsetParent = useScrollLock.getParentNode(element);
|
|
1149
|
+
while (svgOffsetParent && !useScrollLock.isLastTraversableNode(svgOffsetParent)) {
|
|
1150
|
+
if (useScrollLock.isElement(svgOffsetParent) && !isStaticPositioned(svgOffsetParent)) {
|
|
1151
|
+
return svgOffsetParent;
|
|
1152
|
+
}
|
|
1153
|
+
svgOffsetParent = useScrollLock.getParentNode(svgOffsetParent);
|
|
1154
|
+
}
|
|
1155
|
+
return win;
|
|
1156
|
+
}
|
|
1157
|
+
let offsetParent = getTrueOffsetParent(element, polyfill);
|
|
1158
|
+
while (offsetParent && useScrollLock.isTableElement(offsetParent) && isStaticPositioned(offsetParent)) {
|
|
1159
|
+
offsetParent = getTrueOffsetParent(offsetParent, polyfill);
|
|
1160
|
+
}
|
|
1161
|
+
if (offsetParent && useScrollLock.isLastTraversableNode(offsetParent) && isStaticPositioned(offsetParent) && !useScrollLock.isContainingBlock(offsetParent)) {
|
|
1162
|
+
return win;
|
|
1163
|
+
}
|
|
1164
|
+
return offsetParent || useScrollLock.getContainingBlock(element) || win;
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
const getElementRects = async function (data) {
|
|
1168
|
+
const getOffsetParentFn = this.getOffsetParent || getOffsetParent;
|
|
1169
|
+
const getDimensionsFn = this.getDimensions;
|
|
1170
|
+
const floatingDimensions = await getDimensionsFn(data.floating);
|
|
1171
|
+
return {
|
|
1172
|
+
reference: getRectRelativeToOffsetParent(data.reference, await getOffsetParentFn(data.floating), data.strategy),
|
|
1173
|
+
floating: {
|
|
1174
|
+
x: 0,
|
|
1175
|
+
y: 0,
|
|
1176
|
+
width: floatingDimensions.width,
|
|
1177
|
+
height: floatingDimensions.height
|
|
1178
|
+
}
|
|
1179
|
+
};
|
|
1180
|
+
};
|
|
1181
|
+
|
|
1182
|
+
function isRTL(element) {
|
|
1183
|
+
return useScrollLock.getComputedStyle(element).direction === 'rtl';
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
const platform = {
|
|
1187
|
+
convertOffsetParentRelativeRectToViewportRelativeRect,
|
|
1188
|
+
getDocumentElement: useScrollLock.getDocumentElement,
|
|
1189
|
+
getClippingRect,
|
|
1190
|
+
getOffsetParent,
|
|
1191
|
+
getElementRects,
|
|
1192
|
+
getClientRects,
|
|
1193
|
+
getDimensions,
|
|
1194
|
+
getScale,
|
|
1195
|
+
isElement: useScrollLock.isElement,
|
|
1196
|
+
isRTL
|
|
1197
|
+
};
|
|
1198
|
+
|
|
1199
|
+
function rectsAreEqual(a, b) {
|
|
1200
|
+
return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
// https://samthor.au/2021/observing-dom/
|
|
1204
|
+
function observeMove(element, onMove, ancestorResize) {
|
|
1205
|
+
let io = null;
|
|
1206
|
+
let timeoutId;
|
|
1207
|
+
const root = useScrollLock.getDocumentElement(element);
|
|
1208
|
+
function cleanup() {
|
|
1209
|
+
var _io;
|
|
1210
|
+
clearTimeout(timeoutId);
|
|
1211
|
+
(_io = io) == null || _io.disconnect();
|
|
1212
|
+
io = null;
|
|
1213
|
+
}
|
|
1214
|
+
function refresh(skip, threshold) {
|
|
1215
|
+
if (skip === void 0) {
|
|
1216
|
+
skip = false;
|
|
1217
|
+
}
|
|
1218
|
+
if (threshold === void 0) {
|
|
1219
|
+
threshold = 1;
|
|
1220
|
+
}
|
|
1221
|
+
cleanup();
|
|
1222
|
+
const elementRectForRootMargin = element.getBoundingClientRect();
|
|
1223
|
+
const {
|
|
1224
|
+
left,
|
|
1225
|
+
top,
|
|
1226
|
+
width,
|
|
1227
|
+
height
|
|
1228
|
+
} = elementRectForRootMargin;
|
|
1229
|
+
if (!skip) {
|
|
1230
|
+
onMove();
|
|
1231
|
+
}
|
|
1232
|
+
if (!width || !height) {
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
const insetTop = useScrollLock.floor(top);
|
|
1236
|
+
const insetRight = useScrollLock.floor(root.clientWidth - (left + width));
|
|
1237
|
+
const insetBottom = useScrollLock.floor(root.clientHeight - (top + height));
|
|
1238
|
+
const insetLeft = useScrollLock.floor(left);
|
|
1239
|
+
const rootMargin = -insetTop + "px " + -insetRight + "px " + -insetBottom + "px " + -insetLeft + "px";
|
|
1240
|
+
const options = {
|
|
1241
|
+
rootMargin,
|
|
1242
|
+
threshold: useScrollLock.max(0, useScrollLock.min(1, threshold)) || 1
|
|
1243
|
+
};
|
|
1244
|
+
let isFirstUpdate = true;
|
|
1245
|
+
function handleObserve(entries) {
|
|
1246
|
+
const ratio = entries[0].intersectionRatio;
|
|
1247
|
+
|
|
1248
|
+
// The entry is a snapshot, so the reference may have moved since the
|
|
1249
|
+
// intersection was computed (under performance constraints, or between
|
|
1250
|
+
// consecutive frames of a multi-frame layout shift). The reported ratio
|
|
1251
|
+
// and the observed area are stale in that case and cannot be trusted to
|
|
1252
|
+
// detect subsequent movement, so refresh regardless of the ratio.
|
|
1253
|
+
if (!rectsAreEqual(elementRectForRootMargin, element.getBoundingClientRect())) {
|
|
1254
|
+
return refresh();
|
|
1255
|
+
}
|
|
1256
|
+
if (ratio !== threshold) {
|
|
1257
|
+
if (!isFirstUpdate) {
|
|
1258
|
+
return refresh();
|
|
1259
|
+
}
|
|
1260
|
+
if (!ratio) {
|
|
1261
|
+
// If the reference is clipped in place, the ratio is 0. Throttle
|
|
1262
|
+
// the refresh to prevent an infinite loop of updates.
|
|
1263
|
+
timeoutId = setTimeout(() => {
|
|
1264
|
+
refresh(false, 1e-7);
|
|
1265
|
+
}, 1000);
|
|
1266
|
+
} else {
|
|
1267
|
+
refresh(false, ratio);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
isFirstUpdate = false;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
// Older browsers don't support a `document` as the root and will throw an
|
|
1274
|
+
// error.
|
|
1275
|
+
try {
|
|
1276
|
+
io = new IntersectionObserver(handleObserve, {
|
|
1277
|
+
...options,
|
|
1278
|
+
// Handle <iframe>s
|
|
1279
|
+
root: root.ownerDocument
|
|
1280
|
+
});
|
|
1281
|
+
} catch (_e) {
|
|
1282
|
+
io = new IntersectionObserver(handleObserve, options);
|
|
1283
|
+
}
|
|
1284
|
+
io.observe(element);
|
|
1285
|
+
}
|
|
1286
|
+
const win = useScrollLock.getWindow(element);
|
|
1287
|
+
// The window is a resize ancestor, so when `ancestorResize` is enabled its
|
|
1288
|
+
// listener already runs the update on resize. Here we only need to rebuild
|
|
1289
|
+
// the `IntersectionObserver` for the new root size, skipping a redundant
|
|
1290
|
+
// update. When `ancestorResize` is disabled, this becomes the sole update.
|
|
1291
|
+
const handleResize = () => refresh(ancestorResize);
|
|
1292
|
+
win.addEventListener('resize', handleResize);
|
|
1293
|
+
refresh(true);
|
|
1294
|
+
return () => {
|
|
1295
|
+
win.removeEventListener('resize', handleResize);
|
|
1296
|
+
cleanup();
|
|
1297
|
+
};
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
/**
|
|
1301
|
+
* Automatically updates the position of the floating element when necessary.
|
|
1302
|
+
* Should only be called when the floating element is mounted on the DOM or
|
|
1303
|
+
* visible on the screen.
|
|
1304
|
+
* @returns cleanup function that should be invoked when the floating element is
|
|
1305
|
+
* removed from the DOM or hidden from the screen.
|
|
1306
|
+
* @see https://floating-ui.com/docs/autoUpdate
|
|
1307
|
+
*/
|
|
1308
|
+
function autoUpdate(reference, floating, update, options) {
|
|
1309
|
+
if (options === void 0) {
|
|
1310
|
+
options = {};
|
|
1311
|
+
}
|
|
1312
|
+
const {
|
|
1313
|
+
ancestorScroll = true,
|
|
1314
|
+
ancestorResize = true,
|
|
1315
|
+
elementResize = typeof ResizeObserver === 'function',
|
|
1316
|
+
layoutShift = typeof IntersectionObserver === 'function',
|
|
1317
|
+
animationFrame = false
|
|
1318
|
+
} = options;
|
|
1319
|
+
const referenceEl = unwrapElement(reference);
|
|
1320
|
+
const ancestors = ancestorScroll || ancestorResize ? [...(referenceEl ? useScrollLock.getOverflowAncestors(referenceEl) : []), ...(floating ? useScrollLock.getOverflowAncestors(floating) : [])] : [];
|
|
1321
|
+
ancestors.forEach(ancestor => {
|
|
1322
|
+
ancestorScroll && ancestor.addEventListener('scroll', update);
|
|
1323
|
+
ancestorResize && ancestor.addEventListener('resize', update);
|
|
1324
|
+
});
|
|
1325
|
+
const cleanupIo = referenceEl && layoutShift ? observeMove(referenceEl, update, ancestorResize) : null;
|
|
1326
|
+
let reobserveFrame = -1;
|
|
1327
|
+
let resizeObserver = null;
|
|
1328
|
+
if (elementResize) {
|
|
1329
|
+
resizeObserver = new ResizeObserver(_ref => {
|
|
1330
|
+
let [firstEntry] = _ref;
|
|
1331
|
+
if (firstEntry && firstEntry.target === referenceEl && resizeObserver && floating) {
|
|
1332
|
+
// Prevent update loops when using the `size` middleware.
|
|
1333
|
+
// https://github.com/floating-ui/floating-ui/issues/1740
|
|
1334
|
+
resizeObserver.unobserve(floating);
|
|
1335
|
+
cancelAnimationFrame(reobserveFrame);
|
|
1336
|
+
reobserveFrame = requestAnimationFrame(() => {
|
|
1337
|
+
var _resizeObserver;
|
|
1338
|
+
(_resizeObserver = resizeObserver) == null || _resizeObserver.observe(floating);
|
|
1339
|
+
});
|
|
1340
|
+
}
|
|
1341
|
+
update();
|
|
1342
|
+
});
|
|
1343
|
+
if (referenceEl && !animationFrame) {
|
|
1344
|
+
resizeObserver.observe(referenceEl);
|
|
1345
|
+
}
|
|
1346
|
+
if (floating) {
|
|
1347
|
+
resizeObserver.observe(floating);
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
let frameId;
|
|
1351
|
+
let prevRefRect = animationFrame ? getBoundingClientRect(reference) : null;
|
|
1352
|
+
if (animationFrame) {
|
|
1353
|
+
frameLoop();
|
|
1354
|
+
}
|
|
1355
|
+
function frameLoop() {
|
|
1356
|
+
const nextRefRect = getBoundingClientRect(reference);
|
|
1357
|
+
if (prevRefRect && !rectsAreEqual(prevRefRect, nextRefRect)) {
|
|
1358
|
+
update();
|
|
1359
|
+
}
|
|
1360
|
+
prevRefRect = nextRefRect;
|
|
1361
|
+
frameId = requestAnimationFrame(frameLoop);
|
|
1362
|
+
}
|
|
1363
|
+
update();
|
|
1364
|
+
return () => {
|
|
1365
|
+
var _resizeObserver2;
|
|
1366
|
+
ancestors.forEach(ancestor => {
|
|
1367
|
+
ancestorScroll && ancestor.removeEventListener('scroll', update);
|
|
1368
|
+
ancestorResize && ancestor.removeEventListener('resize', update);
|
|
1369
|
+
});
|
|
1370
|
+
cleanupIo == null || cleanupIo();
|
|
1371
|
+
(_resizeObserver2 = resizeObserver) == null || _resizeObserver2.disconnect();
|
|
1372
|
+
resizeObserver = null;
|
|
1373
|
+
if (animationFrame) {
|
|
1374
|
+
cancelAnimationFrame(frameId);
|
|
1375
|
+
}
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
/**
|
|
1380
|
+
* Modifies the placement by translating the floating element along the
|
|
1381
|
+
* specified axes.
|
|
1382
|
+
* A number (shorthand for `mainAxis` or distance), or an axes configuration
|
|
1383
|
+
* object may be passed.
|
|
1384
|
+
* @see https://floating-ui.com/docs/offset
|
|
1385
|
+
*/
|
|
1386
|
+
const offset$1 = offset$2;
|
|
1387
|
+
|
|
1388
|
+
/**
|
|
1389
|
+
* Optimizes the visibility of the floating element by shifting it in order to
|
|
1390
|
+
* keep it in view when it will overflow the clipping boundary.
|
|
1391
|
+
* @see https://floating-ui.com/docs/shift
|
|
1392
|
+
*/
|
|
1393
|
+
const shift$1 = shift$2;
|
|
1394
|
+
|
|
1395
|
+
/**
|
|
1396
|
+
* Optimizes the visibility of the floating element by flipping the `placement`
|
|
1397
|
+
* in order to keep it in view when the preferred placement(s) will overflow the
|
|
1398
|
+
* clipping boundary. Alternative to `autoPlacement`.
|
|
1399
|
+
* @see https://floating-ui.com/docs/flip
|
|
1400
|
+
*/
|
|
1401
|
+
const flip$1 = flip$2;
|
|
1402
|
+
|
|
1403
|
+
/**
|
|
1404
|
+
* Provides data that allows you to change the size of the floating element —
|
|
1405
|
+
* for instance, prevent it from overflowing the clipping boundary or match the
|
|
1406
|
+
* width of the reference element.
|
|
1407
|
+
* @see https://floating-ui.com/docs/size
|
|
1408
|
+
*/
|
|
1409
|
+
const size$1 = size$2;
|
|
1410
|
+
|
|
1411
|
+
/**
|
|
1412
|
+
* Built-in `limiter` that will stop `shift()` at a certain point.
|
|
1413
|
+
*/
|
|
1414
|
+
const limitShift$1 = limitShift$2;
|
|
1415
|
+
|
|
1416
|
+
/**
|
|
1417
|
+
* Computes the `x` and `y` coordinates that will place the floating element
|
|
1418
|
+
* next to a given reference element.
|
|
1419
|
+
*/
|
|
1420
|
+
const computePosition = (reference, floating, options) => {
|
|
1421
|
+
// This caches the expensive `getClippingElementAncestors` function so that
|
|
1422
|
+
// multiple lifecycle resets re-use the same result. It only lives for a
|
|
1423
|
+
// single call. If other functions become expensive, we can add them as well.
|
|
1424
|
+
const cache = new Map();
|
|
1425
|
+
const mergedOptions = options != null ? options : {};
|
|
1426
|
+
const platformWithCache = {
|
|
1427
|
+
...platform,
|
|
1428
|
+
...mergedOptions.platform,
|
|
1429
|
+
_c: cache
|
|
1430
|
+
};
|
|
1431
|
+
return computePosition$1(reference, floating, {
|
|
1432
|
+
...mergedOptions,
|
|
1433
|
+
platform: platformWithCache
|
|
1434
|
+
});
|
|
1435
|
+
};
|
|
1436
|
+
|
|
1437
|
+
var isClient = typeof document !== 'undefined';
|
|
1438
|
+
|
|
1439
|
+
var noop = function noop() {};
|
|
1440
|
+
var index = isClient ? React.useLayoutEffect : noop;
|
|
1441
|
+
|
|
1442
|
+
// Fork of `fast-deep-equal` that only does the comparisons we need and compares
|
|
1443
|
+
// functions
|
|
1444
|
+
function deepEqual(a, b) {
|
|
1445
|
+
if (a === b) {
|
|
1446
|
+
return true;
|
|
1447
|
+
}
|
|
1448
|
+
if (typeof a !== typeof b) {
|
|
1449
|
+
return false;
|
|
1450
|
+
}
|
|
1451
|
+
if (typeof a === 'function' && a.toString() === b.toString()) {
|
|
1452
|
+
return true;
|
|
1453
|
+
}
|
|
1454
|
+
let length;
|
|
1455
|
+
let i;
|
|
1456
|
+
let keys;
|
|
1457
|
+
if (a && b && typeof a === 'object') {
|
|
1458
|
+
if (Array.isArray(a)) {
|
|
1459
|
+
length = a.length;
|
|
1460
|
+
if (length !== b.length) return false;
|
|
1461
|
+
for (i = length; i-- !== 0;) {
|
|
1462
|
+
if (!deepEqual(a[i], b[i])) {
|
|
1463
|
+
return false;
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
return true;
|
|
1467
|
+
}
|
|
1468
|
+
keys = Object.keys(a);
|
|
1469
|
+
length = keys.length;
|
|
1470
|
+
if (length !== Object.keys(b).length) {
|
|
1471
|
+
return false;
|
|
1472
|
+
}
|
|
1473
|
+
for (i = length; i-- !== 0;) {
|
|
1474
|
+
if (!{}.hasOwnProperty.call(b, keys[i])) {
|
|
1475
|
+
return false;
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
for (i = length; i-- !== 0;) {
|
|
1479
|
+
const key = keys[i];
|
|
1480
|
+
if (key === '_owner' && a.$$typeof) {
|
|
1481
|
+
continue;
|
|
1482
|
+
}
|
|
1483
|
+
if (!deepEqual(a[key], b[key])) {
|
|
1484
|
+
return false;
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
return true;
|
|
1488
|
+
}
|
|
1489
|
+
return a !== a && b !== b;
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
function getDPR(element) {
|
|
1493
|
+
if (typeof window === 'undefined') {
|
|
1494
|
+
return 1;
|
|
1495
|
+
}
|
|
1496
|
+
const win = element.ownerDocument.defaultView || window;
|
|
1497
|
+
return win.devicePixelRatio || 1;
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
function roundByDPR(element, value) {
|
|
1501
|
+
const dpr = getDPR(element);
|
|
1502
|
+
return Math.round(value * dpr) / dpr;
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
function useLatestRef(value) {
|
|
1506
|
+
const ref = React__namespace.useRef(value);
|
|
1507
|
+
index(() => {
|
|
1508
|
+
ref.current = value;
|
|
1509
|
+
});
|
|
1510
|
+
return ref;
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
/**
|
|
1514
|
+
* Provides data to position a floating element.
|
|
1515
|
+
* @see https://floating-ui.com/docs/useFloating
|
|
1516
|
+
*/
|
|
1517
|
+
function useFloating(options) {
|
|
1518
|
+
if (options === void 0) {
|
|
1519
|
+
options = {};
|
|
1520
|
+
}
|
|
1521
|
+
const {
|
|
1522
|
+
placement = 'bottom',
|
|
1523
|
+
strategy = 'absolute',
|
|
1524
|
+
middleware = [],
|
|
1525
|
+
platform,
|
|
1526
|
+
elements: {
|
|
1527
|
+
reference: externalReference,
|
|
1528
|
+
floating: externalFloating
|
|
1529
|
+
} = {},
|
|
1530
|
+
transform = true,
|
|
1531
|
+
whileElementsMounted,
|
|
1532
|
+
open
|
|
1533
|
+
} = options;
|
|
1534
|
+
const [data, setData] = React__namespace.useState({
|
|
1535
|
+
x: 0,
|
|
1536
|
+
y: 0,
|
|
1537
|
+
strategy,
|
|
1538
|
+
placement,
|
|
1539
|
+
middlewareData: {},
|
|
1540
|
+
isPositioned: false
|
|
1541
|
+
});
|
|
1542
|
+
const [latestMiddleware, setLatestMiddleware] = React__namespace.useState(middleware);
|
|
1543
|
+
if (!deepEqual(latestMiddleware, middleware)) {
|
|
1544
|
+
setLatestMiddleware(middleware);
|
|
1545
|
+
}
|
|
1546
|
+
const [_reference, _setReference] = React__namespace.useState(null);
|
|
1547
|
+
const [_floating, _setFloating] = React__namespace.useState(null);
|
|
1548
|
+
const setReference = React__namespace.useCallback(node => {
|
|
1549
|
+
if (node !== referenceRef.current) {
|
|
1550
|
+
referenceRef.current = node;
|
|
1551
|
+
_setReference(node);
|
|
1552
|
+
}
|
|
1553
|
+
}, []);
|
|
1554
|
+
const setFloating = React__namespace.useCallback(node => {
|
|
1555
|
+
if (node !== floatingRef.current) {
|
|
1556
|
+
floatingRef.current = node;
|
|
1557
|
+
_setFloating(node);
|
|
1558
|
+
}
|
|
1559
|
+
}, []);
|
|
1560
|
+
const referenceEl = externalReference || _reference;
|
|
1561
|
+
const floatingEl = externalFloating || _floating;
|
|
1562
|
+
const referenceRef = React__namespace.useRef(null);
|
|
1563
|
+
const floatingRef = React__namespace.useRef(null);
|
|
1564
|
+
const dataRef = React__namespace.useRef(data);
|
|
1565
|
+
const hasWhileElementsMounted = whileElementsMounted != null;
|
|
1566
|
+
const whileElementsMountedRef = useLatestRef(whileElementsMounted);
|
|
1567
|
+
const platformRef = useLatestRef(platform);
|
|
1568
|
+
const openRef = useLatestRef(open);
|
|
1569
|
+
const update = React__namespace.useCallback(() => {
|
|
1570
|
+
if (!referenceRef.current || !floatingRef.current) {
|
|
1571
|
+
return;
|
|
1572
|
+
}
|
|
1573
|
+
const config = {
|
|
1574
|
+
placement,
|
|
1575
|
+
strategy,
|
|
1576
|
+
middleware: latestMiddleware
|
|
1577
|
+
};
|
|
1578
|
+
if (platformRef.current) {
|
|
1579
|
+
config.platform = platformRef.current;
|
|
1580
|
+
}
|
|
1581
|
+
computePosition(referenceRef.current, floatingRef.current, config).then(data => {
|
|
1582
|
+
const fullData = {
|
|
1583
|
+
...data,
|
|
1584
|
+
// The floating element's position may be recomputed while it's closed
|
|
1585
|
+
// but still mounted (such as when transitioning out). To ensure
|
|
1586
|
+
// `isPositioned` will be `false` initially on the next open, avoid
|
|
1587
|
+
// setting it to `true` when `open === false` (must be specified).
|
|
1588
|
+
isPositioned: openRef.current !== false
|
|
1589
|
+
};
|
|
1590
|
+
if (isMountedRef.current && !deepEqual(dataRef.current, fullData)) {
|
|
1591
|
+
dataRef.current = fullData;
|
|
1592
|
+
ReactDOM__namespace.flushSync(() => {
|
|
1593
|
+
setData(fullData);
|
|
1594
|
+
});
|
|
1595
|
+
}
|
|
1596
|
+
});
|
|
1597
|
+
}, [latestMiddleware, placement, strategy, platformRef, openRef]);
|
|
1598
|
+
index(() => {
|
|
1599
|
+
if (open === false && dataRef.current.isPositioned) {
|
|
1600
|
+
dataRef.current.isPositioned = false;
|
|
1601
|
+
setData(data => ({
|
|
1602
|
+
...data,
|
|
1603
|
+
isPositioned: false
|
|
1604
|
+
}));
|
|
1605
|
+
}
|
|
1606
|
+
}, [open]);
|
|
1607
|
+
const isMountedRef = React__namespace.useRef(false);
|
|
1608
|
+
index(() => {
|
|
1609
|
+
isMountedRef.current = true;
|
|
1610
|
+
return () => {
|
|
1611
|
+
isMountedRef.current = false;
|
|
1612
|
+
};
|
|
1613
|
+
}, []);
|
|
1614
|
+
index(() => {
|
|
1615
|
+
if (referenceEl) referenceRef.current = referenceEl;
|
|
1616
|
+
if (floatingEl) floatingRef.current = floatingEl;
|
|
1617
|
+
if (referenceEl && floatingEl) {
|
|
1618
|
+
if (whileElementsMountedRef.current) {
|
|
1619
|
+
return whileElementsMountedRef.current(referenceEl, floatingEl, update);
|
|
1620
|
+
}
|
|
1621
|
+
update();
|
|
1622
|
+
}
|
|
1623
|
+
}, [referenceEl, floatingEl, update, whileElementsMountedRef, hasWhileElementsMounted]);
|
|
1624
|
+
const refs = React__namespace.useMemo(() => ({
|
|
1625
|
+
reference: referenceRef,
|
|
1626
|
+
floating: floatingRef,
|
|
1627
|
+
setReference,
|
|
1628
|
+
setFloating
|
|
1629
|
+
}), [setReference, setFloating]);
|
|
1630
|
+
const elements = React__namespace.useMemo(() => ({
|
|
1631
|
+
reference: referenceEl,
|
|
1632
|
+
floating: floatingEl
|
|
1633
|
+
}), [referenceEl, floatingEl]);
|
|
1634
|
+
const floatingStyles = React__namespace.useMemo(() => {
|
|
1635
|
+
const initialStyles = {
|
|
1636
|
+
position: strategy,
|
|
1637
|
+
left: 0,
|
|
1638
|
+
top: 0
|
|
1639
|
+
};
|
|
1640
|
+
if (!elements.floating) {
|
|
1641
|
+
return initialStyles;
|
|
1642
|
+
}
|
|
1643
|
+
const x = roundByDPR(elements.floating, data.x);
|
|
1644
|
+
const y = roundByDPR(elements.floating, data.y);
|
|
1645
|
+
if (transform) {
|
|
1646
|
+
return {
|
|
1647
|
+
...initialStyles,
|
|
1648
|
+
transform: "translate(" + x + "px, " + y + "px)",
|
|
1649
|
+
...(getDPR(elements.floating) >= 1.5 && {
|
|
1650
|
+
willChange: 'transform'
|
|
1651
|
+
})
|
|
1652
|
+
};
|
|
1653
|
+
}
|
|
1654
|
+
return {
|
|
1655
|
+
position: strategy,
|
|
1656
|
+
left: x,
|
|
1657
|
+
top: y
|
|
1658
|
+
};
|
|
1659
|
+
}, [strategy, transform, elements.floating, data.x, data.y]);
|
|
1660
|
+
return React__namespace.useMemo(() => ({
|
|
1661
|
+
...data,
|
|
1662
|
+
update,
|
|
1663
|
+
refs,
|
|
1664
|
+
elements,
|
|
1665
|
+
floatingStyles
|
|
1666
|
+
}), [data, update, refs, elements, floatingStyles]);
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
/**
|
|
1670
|
+
* Modifies the placement by translating the floating element along the
|
|
1671
|
+
* specified axes.
|
|
1672
|
+
* A number (shorthand for `mainAxis` or distance), or an axes configuration
|
|
1673
|
+
* object may be passed.
|
|
1674
|
+
* @see https://floating-ui.com/docs/offset
|
|
1675
|
+
*/
|
|
1676
|
+
const offset = (options, deps) => {
|
|
1677
|
+
const result = offset$1(options);
|
|
1678
|
+
return {
|
|
1679
|
+
name: result.name,
|
|
1680
|
+
fn: result.fn,
|
|
1681
|
+
options: [options, deps]
|
|
1682
|
+
};
|
|
1683
|
+
};
|
|
1684
|
+
|
|
1685
|
+
/**
|
|
1686
|
+
* Optimizes the visibility of the floating element by shifting it in order to
|
|
1687
|
+
* keep it in view when it will overflow the clipping boundary.
|
|
1688
|
+
* @see https://floating-ui.com/docs/shift
|
|
1689
|
+
*/
|
|
1690
|
+
const shift = (options, deps) => {
|
|
1691
|
+
const result = shift$1(options);
|
|
1692
|
+
return {
|
|
1693
|
+
name: result.name,
|
|
1694
|
+
fn: result.fn,
|
|
1695
|
+
options: [options, deps]
|
|
1696
|
+
};
|
|
1697
|
+
};
|
|
1698
|
+
|
|
1699
|
+
/**
|
|
1700
|
+
* Built-in `limiter` that will stop `shift()` at a certain point.
|
|
1701
|
+
*/
|
|
1702
|
+
const limitShift = (options, deps) => {
|
|
1703
|
+
const result = limitShift$1(options);
|
|
1704
|
+
return {
|
|
1705
|
+
fn: result.fn,
|
|
1706
|
+
options: [options, deps]
|
|
1707
|
+
};
|
|
1708
|
+
};
|
|
1709
|
+
|
|
1710
|
+
/**
|
|
1711
|
+
* Optimizes the visibility of the floating element by flipping the `placement`
|
|
1712
|
+
* in order to keep it in view when the preferred placement(s) will overflow the
|
|
1713
|
+
* clipping boundary. Alternative to `autoPlacement`.
|
|
1714
|
+
* @see https://floating-ui.com/docs/flip
|
|
1715
|
+
*/
|
|
1716
|
+
const flip = (options, deps) => {
|
|
1717
|
+
const result = flip$1(options);
|
|
1718
|
+
return {
|
|
1719
|
+
name: result.name,
|
|
1720
|
+
fn: result.fn,
|
|
1721
|
+
options: [options, deps]
|
|
1722
|
+
};
|
|
1723
|
+
};
|
|
1724
|
+
|
|
1725
|
+
/**
|
|
1726
|
+
* Provides data that allows you to change the size of the floating element —
|
|
1727
|
+
* for instance, prevent it from overflowing the clipping boundary or match the
|
|
1728
|
+
* width of the reference element.
|
|
1729
|
+
* @see https://floating-ui.com/docs/size
|
|
1730
|
+
*/
|
|
1731
|
+
const size = (options, deps) => {
|
|
1732
|
+
const result = size$1(options);
|
|
1733
|
+
return {
|
|
1734
|
+
name: result.name,
|
|
1735
|
+
fn: result.fn,
|
|
1736
|
+
options: [options, deps]
|
|
1737
|
+
};
|
|
1738
|
+
};
|
|
28
1739
|
|
|
29
1740
|
function useFloatingRootContext(options) {
|
|
30
1741
|
const {
|
|
@@ -36,7 +1747,7 @@ function useFloatingRootContext(options) {
|
|
|
36
1747
|
const nested = useScrollLock.useFloatingParentNodeId() != null;
|
|
37
1748
|
if (process.env.NODE_ENV !== 'production') {
|
|
38
1749
|
const optionDomReference = elements.reference;
|
|
39
|
-
if (optionDomReference && !
|
|
1750
|
+
if (optionDomReference && !useScrollLock.isElement(optionDomReference)) {
|
|
40
1751
|
console.error('Cannot pass a virtual element to the `elements.reference` option,', 'as it must be a real DOM element. Use `context.setPositionReference()`', 'instead.');
|
|
41
1752
|
}
|
|
42
1753
|
}
|
|
@@ -60,7 +1771,7 @@ function useFloatingRootContext(options) {
|
|
|
60
1771
|
// Only sync elements that are defined to avoid overwriting existing ones
|
|
61
1772
|
if (elements.reference !== undefined) {
|
|
62
1773
|
valuesToSync.referenceElement = elements.reference;
|
|
63
|
-
valuesToSync.domReferenceElement =
|
|
1774
|
+
valuesToSync.domReferenceElement = useScrollLock.isElement(elements.reference) ? elements.reference : null;
|
|
64
1775
|
}
|
|
65
1776
|
if (elements.floating !== undefined) {
|
|
66
1777
|
valuesToSync.floatingElement = elements.floating;
|
|
@@ -73,16 +1784,17 @@ function useFloatingRootContext(options) {
|
|
|
73
1784
|
}
|
|
74
1785
|
|
|
75
1786
|
/**
|
|
76
|
-
*
|
|
77
|
-
*
|
|
1787
|
+
* Base UI's private `useFloating` path. The caller must supply the root store, so this skips the
|
|
1788
|
+
* internal root-context hook used by the public Floating UI-compatible API.
|
|
78
1789
|
*/
|
|
79
|
-
function
|
|
1790
|
+
function useBaseUIFloating(options) {
|
|
1791
|
+
return useFloatingWithStore(options, options.rootContext);
|
|
1792
|
+
}
|
|
1793
|
+
function useFloatingWithStore(options, store) {
|
|
80
1794
|
const {
|
|
81
1795
|
nodeId,
|
|
82
1796
|
externalTree
|
|
83
1797
|
} = options;
|
|
84
|
-
const internalStore = useFloatingRootContext(options);
|
|
85
|
-
const store = options.rootContext || internalStore;
|
|
86
1798
|
const referenceElement = store.useState('referenceElement');
|
|
87
1799
|
const floatingElement = store.useState('floatingElement');
|
|
88
1800
|
const domReferenceElement = store.useState('domReferenceElement');
|
|
@@ -98,7 +1810,7 @@ function useFloating(options = {}) {
|
|
|
98
1810
|
floating: floatingElement,
|
|
99
1811
|
domReference: domReferenceElement
|
|
100
1812
|
}), [referenceElement, floatingElement, domReferenceElement]);
|
|
101
|
-
const position =
|
|
1813
|
+
const position = useFloating({
|
|
102
1814
|
...options,
|
|
103
1815
|
elements: {
|
|
104
1816
|
...storeElements,
|
|
@@ -107,13 +1819,13 @@ function useFloating(options = {}) {
|
|
|
107
1819
|
})
|
|
108
1820
|
}
|
|
109
1821
|
});
|
|
110
|
-
const localDomReferenceElement =
|
|
1822
|
+
const localDomReferenceElement = useScrollLock.isElement(localDomReference) ? localDomReference : null;
|
|
111
1823
|
const syncedFloatingElement = localFloatingElement === undefined ? store.state.floatingElement : localFloatingElement;
|
|
112
1824
|
store.useSyncedValue('referenceElement', localDomReference ?? null);
|
|
113
1825
|
store.useSyncedValue('domReferenceElement', localDomReference === undefined ? domReferenceElement : localDomReferenceElement);
|
|
114
1826
|
store.useSyncedValue('floatingElement', syncedFloatingElement);
|
|
115
1827
|
const setPositionReference = React__namespace.useCallback(node => {
|
|
116
|
-
const computedPositionReference =
|
|
1828
|
+
const computedPositionReference = useScrollLock.isElement(node) ? {
|
|
117
1829
|
getBoundingClientRect: () => node.getBoundingClientRect(),
|
|
118
1830
|
getClientRects: () => node.getClientRects(),
|
|
119
1831
|
contextElement: node
|
|
@@ -124,18 +1836,18 @@ function useFloating(options = {}) {
|
|
|
124
1836
|
position.refs.setReference(computedPositionReference);
|
|
125
1837
|
}, [position.refs]);
|
|
126
1838
|
const setReference = React__namespace.useCallback(node => {
|
|
127
|
-
if (
|
|
1839
|
+
if (useScrollLock.isElement(node) || node === null) {
|
|
128
1840
|
domReferenceRef.current = node;
|
|
129
1841
|
setLocalDomReference(node);
|
|
130
1842
|
}
|
|
131
1843
|
|
|
132
1844
|
// Backwards-compatibility for passing a virtual element to `reference`
|
|
133
1845
|
// after it has set the DOM reference.
|
|
134
|
-
if (
|
|
1846
|
+
if (useScrollLock.isElement(position.refs.reference.current) || position.refs.reference.current === null ||
|
|
135
1847
|
// Don't allow setting virtual elements using the old technique back to
|
|
136
1848
|
// `null` to support `positionReference` + an unstable `reference`
|
|
137
1849
|
// callback ref.
|
|
138
|
-
node !== null && !
|
|
1850
|
+
node !== null && !useScrollLock.isElement(node)) {
|
|
139
1851
|
position.refs.setReference(node);
|
|
140
1852
|
}
|
|
141
1853
|
}, [position.refs, setLocalDomReference]);
|
|
@@ -188,6 +1900,13 @@ function useFloating(options = {}) {
|
|
|
188
1900
|
}
|
|
189
1901
|
|
|
190
1902
|
const ESCAPE = 'Escape';
|
|
1903
|
+
|
|
1904
|
+
// WebKit fires zero-delta `mousemove`/`pointermove` events when the list scrolls
|
|
1905
|
+
// beneath a stationary pointer, moving the highlight during keyboard navigation.
|
|
1906
|
+
// https://github.com/mui/base-ui/issues/4002
|
|
1907
|
+
function isStationaryWebKitPointer(event) {
|
|
1908
|
+
return useScrollLock.webkit && event.movementX === 0 && event.movementY === 0;
|
|
1909
|
+
}
|
|
191
1910
|
function doSwitch(orientation, vertical, horizontal) {
|
|
192
1911
|
switch (orientation) {
|
|
193
1912
|
case 'vertical':
|
|
@@ -484,7 +2203,7 @@ function useListNavigation(context, props) {
|
|
|
484
2203
|
useScrollLock.stopEvent(event);
|
|
485
2204
|
}
|
|
486
2205
|
store.setOpen(false, useScrollLock.createChangeEventDetails(useScrollLock.listNavigation, event.nativeEvent));
|
|
487
|
-
if (
|
|
2206
|
+
if (useScrollLock.isHTMLElement(domReferenceElement)) {
|
|
488
2207
|
if (virtual) {
|
|
489
2208
|
tree?.events.emit('virtualfocus', domReferenceElement);
|
|
490
2209
|
} else {
|
|
@@ -594,6 +2313,9 @@ function useListNavigation(context, props) {
|
|
|
594
2313
|
}),
|
|
595
2314
|
// Safari
|
|
596
2315
|
onMouseMove(event) {
|
|
2316
|
+
if (isStationaryWebKitPointer(event)) {
|
|
2317
|
+
return;
|
|
2318
|
+
}
|
|
597
2319
|
forceSyncFocusRef.current = true;
|
|
598
2320
|
forceScrollIntoViewRef.current = false;
|
|
599
2321
|
if (focusItemOnHover) {
|
|
@@ -650,14 +2372,17 @@ function useListNavigation(context, props) {
|
|
|
650
2372
|
}
|
|
651
2373
|
useScrollLock.stopEvent(event);
|
|
652
2374
|
store.setOpen(false, useScrollLock.createChangeEventDetails(useScrollLock.focusOut, event.nativeEvent));
|
|
653
|
-
if (
|
|
2375
|
+
if (useScrollLock.isHTMLElement(domReferenceElement)) {
|
|
654
2376
|
domReferenceElement.focus();
|
|
655
2377
|
}
|
|
656
2378
|
return;
|
|
657
2379
|
}
|
|
658
2380
|
commonOnKeyDown(event);
|
|
659
2381
|
},
|
|
660
|
-
onPointerMove() {
|
|
2382
|
+
onPointerMove(event) {
|
|
2383
|
+
if (isStationaryWebKitPointer(event)) {
|
|
2384
|
+
return;
|
|
2385
|
+
}
|
|
661
2386
|
isPointerModalityRef.current = true;
|
|
662
2387
|
}
|
|
663
2388
|
};
|
|
@@ -778,18 +2503,19 @@ function useTypeahead(context, props) {
|
|
|
778
2503
|
const prevIndexRef = React__namespace.useRef(selectedIndex ?? activeIndex ?? -1);
|
|
779
2504
|
const matchIndexRef = React__namespace.useRef(null);
|
|
780
2505
|
const onKeyDown = useScrollLock.useStableCallback(event => {
|
|
781
|
-
function
|
|
782
|
-
|
|
783
|
-
return !element || useScrollLock.isElementVisible(element);
|
|
2506
|
+
function getElement(index) {
|
|
2507
|
+
return elementsRef?.current[index];
|
|
784
2508
|
}
|
|
785
2509
|
function isItemAvailable(index) {
|
|
786
|
-
|
|
2510
|
+
const element = getElement(index);
|
|
2511
|
+
if (element && !useScrollLock.isElementVisible(element) || element?.matches(':disabled')) {
|
|
787
2512
|
return false;
|
|
788
2513
|
}
|
|
789
|
-
// Visibility
|
|
790
|
-
//
|
|
791
|
-
//
|
|
792
|
-
// visible
|
|
2514
|
+
// Visibility and native disabled state are handled above; pass an empty
|
|
2515
|
+
// element list so `isListIndexDisabled` resolves only the explicit
|
|
2516
|
+
// `disabledIndices` (array/predicate) and skips its own fallbacks.
|
|
2517
|
+
// Consumers that don't pass `disabledIndices` keep matching every visible
|
|
2518
|
+
// item except native disabled elements provided through `elementsRef`.
|
|
793
2519
|
return disabledIndices == null || !useScrollLock.isListIndexDisabled(useRenderElement.EMPTY_ARRAY, index, disabledIndices);
|
|
794
2520
|
}
|
|
795
2521
|
function getMatchingIndex(list, string, startIndex = 0) {
|
|
@@ -897,12 +2623,6 @@ function useTypeahead(context, props) {
|
|
|
897
2623
|
stringRef.current = '';
|
|
898
2624
|
}
|
|
899
2625
|
}, [open, selectedIndex, timeout]);
|
|
900
|
-
useScrollLock.useIsoLayoutEffect(() => {
|
|
901
|
-
// Sync arrow key navigation but not typeahead navigation.
|
|
902
|
-
if (open && stringRef.current === '') {
|
|
903
|
-
prevIndexRef.current = selectedIndex ?? activeIndex ?? -1;
|
|
904
|
-
}
|
|
905
|
-
}, [open, selectedIndex, activeIndex]);
|
|
906
2626
|
const sharedProps = React__namespace.useMemo(() => ({
|
|
907
2627
|
onKeyDown,
|
|
908
2628
|
onBlur
|
|
@@ -942,6 +2662,12 @@ function findItemIndex(itemValues, selectedValue, comparer) {
|
|
|
942
2662
|
return compareItemEquality(itemValue, selectedValue, comparer);
|
|
943
2663
|
});
|
|
944
2664
|
}
|
|
2665
|
+
function findSelectionIndex(itemValues, selectedValue, comparer, multiple) {
|
|
2666
|
+
// Only unwrap in multiple mode: an array can itself be a valid single-select value.
|
|
2667
|
+
const lastValue = multiple && Array.isArray(selectedValue) ? selectedValue[selectedValue.length - 1] : selectedValue;
|
|
2668
|
+
const index = findItemIndex(itemValues, lastValue, comparer);
|
|
2669
|
+
return index === -1 ? null : index;
|
|
2670
|
+
}
|
|
945
2671
|
function removeItem(selectedValues, itemValue, comparer) {
|
|
946
2672
|
return selectedValues.filter(selectedValue => !compareItemEquality(itemValue, selectedValue, comparer));
|
|
947
2673
|
}
|
|
@@ -1064,38 +2790,6 @@ function resolveMultipleLabels(values, items, itemToStringLabel) {
|
|
|
1064
2790
|
}, []);
|
|
1065
2791
|
}
|
|
1066
2792
|
|
|
1067
|
-
let FieldControlDataAttributes = /*#__PURE__*/function (FieldControlDataAttributes) {
|
|
1068
|
-
/**
|
|
1069
|
-
* Present when the field is disabled.
|
|
1070
|
-
*/
|
|
1071
|
-
FieldControlDataAttributes["disabled"] = "data-disabled";
|
|
1072
|
-
/**
|
|
1073
|
-
* Present when the field is in a valid state.
|
|
1074
|
-
*/
|
|
1075
|
-
FieldControlDataAttributes["valid"] = "data-valid";
|
|
1076
|
-
/**
|
|
1077
|
-
* Present when the field is in an invalid state.
|
|
1078
|
-
*/
|
|
1079
|
-
FieldControlDataAttributes["invalid"] = "data-invalid";
|
|
1080
|
-
/**
|
|
1081
|
-
* Present when the field has been touched.
|
|
1082
|
-
*/
|
|
1083
|
-
FieldControlDataAttributes["touched"] = "data-touched";
|
|
1084
|
-
/**
|
|
1085
|
-
* Present when the field's value has changed.
|
|
1086
|
-
*/
|
|
1087
|
-
FieldControlDataAttributes["dirty"] = "data-dirty";
|
|
1088
|
-
/**
|
|
1089
|
-
* Present when the field is filled.
|
|
1090
|
-
*/
|
|
1091
|
-
FieldControlDataAttributes["filled"] = "data-filled";
|
|
1092
|
-
/**
|
|
1093
|
-
* Present when the field control is focused.
|
|
1094
|
-
*/
|
|
1095
|
-
FieldControlDataAttributes["focused"] = "data-focused";
|
|
1096
|
-
return FieldControlDataAttributes;
|
|
1097
|
-
}({});
|
|
1098
|
-
|
|
1099
2793
|
const DEFAULT_VALIDITY_STATE = {
|
|
1100
2794
|
badInput: false,
|
|
1101
2795
|
customError: false,
|
|
@@ -1127,11 +2821,11 @@ const fieldValidityMapping = {
|
|
|
1127
2821
|
}
|
|
1128
2822
|
if (value) {
|
|
1129
2823
|
return {
|
|
1130
|
-
|
|
2824
|
+
'data-valid': ''
|
|
1131
2825
|
};
|
|
1132
2826
|
}
|
|
1133
2827
|
return {
|
|
1134
|
-
|
|
2828
|
+
'data-invalid': ''
|
|
1135
2829
|
};
|
|
1136
2830
|
}
|
|
1137
2831
|
};
|
|
@@ -1148,29 +2842,22 @@ const DEFAULT_FIELD_ROOT_CONTEXT = {
|
|
|
1148
2842
|
},
|
|
1149
2843
|
setValidityData: useRenderElement.NOOP,
|
|
1150
2844
|
disabled: undefined,
|
|
1151
|
-
touched: DEFAULT_FIELD_STATE_ATTRIBUTES.touched,
|
|
1152
2845
|
setTouched: useRenderElement.NOOP,
|
|
1153
|
-
dirty: DEFAULT_FIELD_STATE_ATTRIBUTES.dirty,
|
|
1154
2846
|
setDirty: useRenderElement.NOOP,
|
|
1155
|
-
filled: DEFAULT_FIELD_STATE_ATTRIBUTES.filled,
|
|
1156
2847
|
setFilled: useRenderElement.NOOP,
|
|
1157
|
-
focused: DEFAULT_FIELD_STATE_ATTRIBUTES.focused,
|
|
1158
2848
|
setFocused: useRenderElement.NOOP,
|
|
1159
|
-
validate: () => null,
|
|
1160
2849
|
validationMode: 'onSubmit',
|
|
1161
|
-
validationDebounceTime: 0,
|
|
1162
2850
|
shouldValidateOnChange: () => false,
|
|
1163
2851
|
state: DEFAULT_FIELD_ROOT_STATE,
|
|
1164
|
-
markedDirtyRef: {
|
|
1165
|
-
current: false
|
|
1166
|
-
},
|
|
1167
2852
|
registerFieldControl: useRenderElement.NOOP,
|
|
1168
2853
|
validation: {
|
|
1169
2854
|
getValidationProps: (_disabled, props = useRenderElement.EMPTY_OBJECT) => props,
|
|
1170
2855
|
inputRef: {
|
|
1171
2856
|
current: null
|
|
1172
2857
|
},
|
|
2858
|
+
registeredInputs: new Map(),
|
|
1173
2859
|
registerInput: useRenderElement.NOOP,
|
|
2860
|
+
getInputControl: () => null,
|
|
1174
2861
|
commit: async () => {},
|
|
1175
2862
|
change: useRenderElement.NOOP
|
|
1176
2863
|
}
|
|
@@ -1189,14 +2876,16 @@ function useRegisterFieldControl(controlRef, id, value, getFormValueOverride, en
|
|
|
1189
2876
|
const {
|
|
1190
2877
|
registerFieldControl
|
|
1191
2878
|
} = useFieldRootContext();
|
|
1192
|
-
const sourceRef =
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
2879
|
+
const sourceRef = useRenderElement.useRefWithInit(() => Symbol());
|
|
2880
|
+
|
|
2881
|
+
// Re-register without unregistering first: re-registration with the same id updates the
|
|
2882
|
+
// form's fields Map entry in place, while a delete + re-add would move the field to the
|
|
2883
|
+
// end of the Map every time its value changes.
|
|
1196
2884
|
useScrollLock.useIsoLayoutEffect(() => {
|
|
1197
2885
|
const source = sourceRef.current;
|
|
1198
|
-
if (!
|
|
1199
|
-
|
|
2886
|
+
if (!enabled) {
|
|
2887
|
+
registerFieldControl(source, undefined);
|
|
2888
|
+
return;
|
|
1200
2889
|
}
|
|
1201
2890
|
const registration = {
|
|
1202
2891
|
controlRef,
|
|
@@ -1206,13 +2895,19 @@ function useRegisterFieldControl(controlRef, id, value, getFormValueOverride, en
|
|
|
1206
2895
|
value
|
|
1207
2896
|
};
|
|
1208
2897
|
registerFieldControl(source, registration);
|
|
2898
|
+
}, [controlRef, enabled, getFormValueOverride, id, name, registerFieldControl, sourceRef, value]);
|
|
2899
|
+
useScrollLock.useIsoLayoutEffect(() => {
|
|
2900
|
+
const source = sourceRef.current;
|
|
1209
2901
|
return () => {
|
|
1210
2902
|
registerFieldControl(source, undefined);
|
|
1211
2903
|
};
|
|
1212
|
-
}, [
|
|
2904
|
+
}, [registerFieldControl, sourceRef]);
|
|
1213
2905
|
}
|
|
1214
2906
|
|
|
1215
2907
|
const FormContext = /*#__PURE__*/React__namespace.createContext({
|
|
2908
|
+
elementRef: {
|
|
2909
|
+
current: null
|
|
2910
|
+
},
|
|
1216
2911
|
formRef: {
|
|
1217
2912
|
current: {
|
|
1218
2913
|
fields: new Map()
|
|
@@ -1260,7 +2955,7 @@ function useLabelableId(params = {}) {
|
|
|
1260
2955
|
} = useLabelableContext();
|
|
1261
2956
|
const defaultId = useScrollLock.useBaseUiId(id);
|
|
1262
2957
|
const controlIdForEffect = implicit ? controlId : undefined;
|
|
1263
|
-
const controlSourceRef = useRenderElement.useRefWithInit(() => Symbol(
|
|
2958
|
+
const controlSourceRef = useRenderElement.useRefWithInit(() => Symbol());
|
|
1264
2959
|
const hasRegisteredRef = React__namespace.useRef(false);
|
|
1265
2960
|
const hadExplicitIdRef = React__namespace.useRef(id != null);
|
|
1266
2961
|
const unregisterControlId = useScrollLock.useStableCallback(() => {
|
|
@@ -1277,7 +2972,7 @@ function useLabelableId(params = {}) {
|
|
|
1277
2972
|
let nextId;
|
|
1278
2973
|
if (implicit) {
|
|
1279
2974
|
const elem = controlRef?.current;
|
|
1280
|
-
if (
|
|
2975
|
+
if (useScrollLock.isElement(elem) && elem.closest('label') != null) {
|
|
1281
2976
|
nextId = id ?? null;
|
|
1282
2977
|
} else {
|
|
1283
2978
|
nextId = controlIdForEffect ?? defaultId;
|
|
@@ -1309,9 +3004,22 @@ function areArraysEqual(array1, array2, itemComparer = (a, b) => a === b) {
|
|
|
1309
3004
|
return array1.length === array2.length && array1.every((value, index) => itemComparer(value, array2[index]));
|
|
1310
3005
|
}
|
|
1311
3006
|
|
|
3007
|
+
// Tolerance around the element bounds so a fast click whose pointer drifts slightly
|
|
3008
|
+
// during press-release isn't mistaken for a drag-off-and-release cancellation.
|
|
3009
|
+
// Matches typical OS/browser drag-initiation thresholds.
|
|
3010
|
+
const BOUNDARY_OFFSET = 5;
|
|
3011
|
+
|
|
3012
|
+
/**
|
|
3013
|
+
* Determines if a mouse event occurred within the bounds of an element
|
|
3014
|
+
* (including its pseudo-elements), with a small tolerance for pointer drift.
|
|
3015
|
+
*/
|
|
3016
|
+
function isMouseWithinBounds(event, element) {
|
|
3017
|
+
const bounds = getPseudoElementBounds(element);
|
|
3018
|
+
return event.clientX >= bounds.left - BOUNDARY_OFFSET && event.clientX <= bounds.right + BOUNDARY_OFFSET && event.clientY >= bounds.top - BOUNDARY_OFFSET && event.clientY <= bounds.bottom + BOUNDARY_OFFSET;
|
|
3019
|
+
}
|
|
1312
3020
|
function getPseudoElementBounds(element) {
|
|
1313
3021
|
const elementRect = element.getBoundingClientRect();
|
|
1314
|
-
const win =
|
|
3022
|
+
const win = useScrollLock.getWindow(element);
|
|
1315
3023
|
|
|
1316
3024
|
// Avoid "Not implemented: window.getComputedStyle(elt, pseudoElt)" in jsdom.
|
|
1317
3025
|
if (useScrollLock.jsdom) {
|
|
@@ -1355,12 +3063,7 @@ function resolveAriaLabelledBy(fieldLabelId, localLabelId) {
|
|
|
1355
3063
|
const CompositeListContext = /*#__PURE__*/React__namespace.createContext({
|
|
1356
3064
|
register: () => {},
|
|
1357
3065
|
unregister: () => {},
|
|
1358
|
-
subscribeMapChange: () => {
|
|
1359
|
-
return () => {};
|
|
1360
|
-
},
|
|
1361
|
-
elementsRef: {
|
|
1362
|
-
current: []
|
|
1363
|
-
},
|
|
3066
|
+
subscribeMapChange: () => () => {},
|
|
1364
3067
|
nextIndexRef: {
|
|
1365
3068
|
current: 0
|
|
1366
3069
|
}
|
|
@@ -1373,7 +3076,6 @@ function useCompositeListContext() {
|
|
|
1373
3076
|
/* eslint-disable no-bitwise */
|
|
1374
3077
|
/**
|
|
1375
3078
|
* Provides context for a list of items in a composite component.
|
|
1376
|
-
* @internal
|
|
1377
3079
|
*/
|
|
1378
3080
|
function CompositeList(props) {
|
|
1379
3081
|
const {
|
|
@@ -1383,114 +3085,146 @@ function CompositeList(props) {
|
|
|
1383
3085
|
onMapChange: onMapChangeProp
|
|
1384
3086
|
} = props;
|
|
1385
3087
|
const onMapChange = useScrollLock.useStableCallback(onMapChangeProp);
|
|
1386
|
-
const
|
|
3088
|
+
const [, setMapTick] = React__namespace.useState(false);
|
|
1387
3089
|
const listeners = useRenderElement.useRefWithInit(createListeners).current;
|
|
1388
|
-
|
|
1389
|
-
// We use a stable `map` to avoid O(n^2) re-allocation costs for large lists.
|
|
1390
|
-
// `mapTick` is our re-render trigger mechanism. We also need to update the
|
|
1391
|
-
// elements and label refs, but there's a lot of async work going on and sometimes
|
|
1392
|
-
// the effect that handles `onMapChange` gets called after those refs have been
|
|
1393
|
-
// filled, and we don't want to lose those values by setting their lengths to `0`.
|
|
1394
|
-
// We also need to have them at the proper length because floating-ui uses that
|
|
1395
|
-
// information for list navigation.
|
|
1396
|
-
|
|
1397
3090
|
const map = useRenderElement.useRefWithInit(createMap).current;
|
|
1398
|
-
|
|
1399
|
-
const
|
|
1400
|
-
const
|
|
1401
|
-
const
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
3091
|
+
const nextIndexRef = React__namespace.useRef(0);
|
|
3092
|
+
const isDirtyRef = React__namespace.useRef(true);
|
|
3093
|
+
const itemsRef = React__namespace.useRef([]);
|
|
3094
|
+
const mutationObserverRef = React__namespace.useRef(null);
|
|
3095
|
+
|
|
3096
|
+
// Item effects can run without their parent rendering. Schedule one synchronous
|
|
3097
|
+
// parent update for the whole commit so refs are rebuilt before paint and while
|
|
3098
|
+
// the originating React event is still inside `act()` in tests.
|
|
3099
|
+
const scheduleMapUpdate = useScrollLock.useStableCallback(() => {
|
|
3100
|
+
if (isDirtyRef.current) {
|
|
3101
|
+
return;
|
|
3102
|
+
}
|
|
3103
|
+
isDirtyRef.current = true;
|
|
3104
|
+
setMapTick(tick => !tick);
|
|
3105
|
+
});
|
|
3106
|
+
const register = useScrollLock.useStableCallback((node, registration) => {
|
|
3107
|
+
map.set(node, registration);
|
|
3108
|
+
scheduleMapUpdate();
|
|
1405
3109
|
});
|
|
1406
3110
|
const unregister = useScrollLock.useStableCallback(node => {
|
|
1407
3111
|
map.delete(node);
|
|
1408
|
-
|
|
1409
|
-
setMapTick(lastTickRef.current);
|
|
3112
|
+
scheduleMapUpdate();
|
|
1410
3113
|
});
|
|
1411
|
-
const
|
|
1412
|
-
const
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
...metadata,
|
|
1420
|
-
index
|
|
3114
|
+
const syncRefs = useScrollLock.useStableCallback(items => {
|
|
3115
|
+
const nextMap = new Map();
|
|
3116
|
+
elementsRef.current.length = 0;
|
|
3117
|
+
if (labelsRef) {
|
|
3118
|
+
labelsRef.current.length = 0;
|
|
3119
|
+
}
|
|
3120
|
+
items.forEach(item => {
|
|
3121
|
+
nextMap.set(item.element, {
|
|
3122
|
+
...(item.registration.metadata ?? {}),
|
|
3123
|
+
index: item.index
|
|
1421
3124
|
});
|
|
3125
|
+
elementsRef.current[item.index] = item.element;
|
|
3126
|
+
if (labelsRef) {
|
|
3127
|
+
labelsRef.current[item.index] = item.registration.label !== undefined ? item.registration.label : item.registration.textRef?.current?.textContent ?? item.element.textContent;
|
|
3128
|
+
}
|
|
1422
3129
|
});
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
3130
|
+
nextIndexRef.current = elementsRef.current.length;
|
|
3131
|
+
return nextMap;
|
|
3132
|
+
});
|
|
3133
|
+
function observe(sortedNodes) {
|
|
3134
|
+
mutationObserverRef.current?.disconnect();
|
|
3135
|
+
mutationObserverRef.current = null;
|
|
3136
|
+
|
|
3137
|
+
// A single item can't reorder.
|
|
3138
|
+
if (typeof MutationObserver !== 'function' || sortedNodes.length < 2) {
|
|
3139
|
+
return;
|
|
1428
3140
|
}
|
|
1429
3141
|
const mutationObserver = new MutationObserver(entries => {
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
if (diff.size === 0) {
|
|
1437
|
-
lastTickRef.current += 1;
|
|
1438
|
-
setMapTick(lastTickRef.current);
|
|
3142
|
+
// Only verify the order after a move: a node that was removed and later
|
|
3143
|
+
// re-added within the same batch. Additions and removals alone can't
|
|
3144
|
+
// change the relative order of the remaining items, and items that mount
|
|
3145
|
+
// or unmount re-sort through `register`/`unregister`.
|
|
3146
|
+
if (!hasMovedNode(entries)) {
|
|
3147
|
+
return;
|
|
1439
3148
|
}
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
3149
|
+
let previousConnectedNode = null;
|
|
3150
|
+
|
|
3151
|
+
// If any connected node now appears before the previous connected node,
|
|
3152
|
+
// wrappers/items moved and the index map needs to be rebuilt.
|
|
3153
|
+
for (const node of sortedNodes) {
|
|
3154
|
+
if (!node.isConnected) {
|
|
3155
|
+
continue;
|
|
3156
|
+
}
|
|
3157
|
+
if (previousConnectedNode && sortByDocumentPosition(previousConnectedNode, node) > 0) {
|
|
3158
|
+
mutationObserver.disconnect();
|
|
3159
|
+
scheduleMapUpdate();
|
|
3160
|
+
return;
|
|
3161
|
+
}
|
|
3162
|
+
previousConnectedNode = node;
|
|
1446
3163
|
}
|
|
1447
3164
|
});
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
const
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
3165
|
+
mutationObserverRef.current = mutationObserver;
|
|
3166
|
+
|
|
3167
|
+
// A reorder that changes item indexes must invert at least one adjacent pair
|
|
3168
|
+
// from the previous sorted order. Observing each pair's common parent catches
|
|
3169
|
+
// both direct item moves and ancestor wrapper moves at the boundary.
|
|
3170
|
+
const roots = new Set();
|
|
3171
|
+
for (let i = 1; i < sortedNodes.length; i += 1) {
|
|
3172
|
+
const root = getCommonAncestor(sortedNodes[i - 1], sortedNodes[i]);
|
|
3173
|
+
if (root) {
|
|
3174
|
+
roots.add(root);
|
|
1457
3175
|
}
|
|
1458
|
-
if (labelsRef && labelsRef.current.length !== sortedMap.size) {
|
|
1459
|
-
labelsRef.current.length = sortedMap.size;
|
|
1460
|
-
}
|
|
1461
|
-
nextIndexRef.current = sortedMap.size;
|
|
1462
3176
|
}
|
|
1463
|
-
|
|
1464
|
-
|
|
3177
|
+
roots.forEach(root => mutationObserver.observe(root, {
|
|
3178
|
+
childList: true
|
|
3179
|
+
}));
|
|
3180
|
+
}
|
|
3181
|
+
const flush = useScrollLock.useStableCallback(() => {
|
|
3182
|
+
const [items, automaticNodes] = getCompositeListSnapshot(map);
|
|
3183
|
+
const nextMap = syncRefs(items);
|
|
3184
|
+
observe(automaticNodes);
|
|
3185
|
+
itemsRef.current = items;
|
|
3186
|
+
isDirtyRef.current = false;
|
|
3187
|
+
listeners.forEach(listener => listener(nextMap));
|
|
3188
|
+
onMapChange(nextMap);
|
|
3189
|
+
});
|
|
1465
3190
|
useScrollLock.useIsoLayoutEffect(() => {
|
|
3191
|
+
// Re-copy the last committed snapshot when the ref objects change or Strict Mode replays
|
|
3192
|
+
// effects without reattaching callback refs.
|
|
3193
|
+
if (!isDirtyRef.current) {
|
|
3194
|
+
syncRefs(itemsRef.current);
|
|
3195
|
+
}
|
|
1466
3196
|
return () => {
|
|
1467
3197
|
elementsRef.current = [];
|
|
1468
|
-
};
|
|
1469
|
-
}, [elementsRef]);
|
|
1470
|
-
useScrollLock.useIsoLayoutEffect(() => {
|
|
1471
|
-
return () => {
|
|
1472
3198
|
if (labelsRef) {
|
|
1473
3199
|
labelsRef.current = [];
|
|
1474
3200
|
}
|
|
1475
3201
|
};
|
|
1476
|
-
}, [labelsRef]);
|
|
3202
|
+
}, [elementsRef, labelsRef, syncRefs]);
|
|
3203
|
+
useScrollLock.useIsoLayoutEffect(() => {
|
|
3204
|
+
if (isDirtyRef.current) {
|
|
3205
|
+
flush();
|
|
3206
|
+
}
|
|
3207
|
+
});
|
|
3208
|
+
useScrollLock.useIsoLayoutEffect(() => {
|
|
3209
|
+
return () => {
|
|
3210
|
+
mutationObserverRef.current?.disconnect();
|
|
3211
|
+
// React 18 Strict Mode replays effects without replaying callback refs.
|
|
3212
|
+
// Mark the retained map dirty so the replay rebuilds refs and observation.
|
|
3213
|
+
isDirtyRef.current = true;
|
|
3214
|
+
};
|
|
3215
|
+
}, []);
|
|
1477
3216
|
const subscribeMapChange = useScrollLock.useStableCallback(fn => {
|
|
1478
3217
|
listeners.add(fn);
|
|
1479
3218
|
return () => {
|
|
1480
3219
|
listeners.delete(fn);
|
|
1481
3220
|
};
|
|
1482
3221
|
});
|
|
1483
|
-
useScrollLock.useIsoLayoutEffect(() => {
|
|
1484
|
-
listeners.forEach(l => l(sortedMap));
|
|
1485
|
-
}, [listeners, sortedMap]);
|
|
1486
3222
|
const contextValue = React__namespace.useMemo(() => ({
|
|
1487
3223
|
register,
|
|
1488
3224
|
unregister,
|
|
1489
3225
|
subscribeMapChange,
|
|
1490
|
-
elementsRef,
|
|
1491
|
-
labelsRef,
|
|
1492
3226
|
nextIndexRef
|
|
1493
|
-
}), [register, unregister, subscribeMapChange,
|
|
3227
|
+
}), [register, unregister, subscribeMapChange, nextIndexRef]);
|
|
1494
3228
|
return /*#__PURE__*/jsxRuntime.jsx(CompositeListContext.Provider, {
|
|
1495
3229
|
value: contextValue,
|
|
1496
3230
|
children: children
|
|
@@ -1502,15 +3236,66 @@ function createMap() {
|
|
|
1502
3236
|
function createListeners() {
|
|
1503
3237
|
return new Set();
|
|
1504
3238
|
}
|
|
1505
|
-
function
|
|
1506
|
-
const
|
|
1507
|
-
|
|
1508
|
-
|
|
3239
|
+
function getCompositeListSnapshot(map) {
|
|
3240
|
+
const reservedIndices = new Set();
|
|
3241
|
+
const items = [];
|
|
3242
|
+
const automaticItems = [];
|
|
3243
|
+
map.forEach((registration, node) => {
|
|
3244
|
+
if (!node.isConnected) {
|
|
3245
|
+
return;
|
|
3246
|
+
}
|
|
3247
|
+
const index = registration.index;
|
|
3248
|
+
const item = {
|
|
3249
|
+
index: index ?? -1,
|
|
3250
|
+
element: node,
|
|
3251
|
+
registration
|
|
3252
|
+
};
|
|
3253
|
+
if (index === null) {
|
|
3254
|
+
automaticItems.push(item);
|
|
3255
|
+
} else if (index >= 0) {
|
|
3256
|
+
reservedIndices.add(index);
|
|
3257
|
+
items.push(item);
|
|
3258
|
+
}
|
|
3259
|
+
});
|
|
3260
|
+
let nextAutomaticIndex = 0;
|
|
3261
|
+
automaticItems.sort((a, b) => sortByDocumentPosition(a.element, b.element));
|
|
3262
|
+
automaticItems.forEach(item => {
|
|
3263
|
+
while (reservedIndices.has(nextAutomaticIndex)) {
|
|
3264
|
+
nextAutomaticIndex += 1;
|
|
3265
|
+
}
|
|
3266
|
+
item.index = nextAutomaticIndex;
|
|
3267
|
+
items.push(item);
|
|
3268
|
+
nextAutomaticIndex += 1;
|
|
3269
|
+
});
|
|
3270
|
+
if (reservedIndices.size > 0) {
|
|
3271
|
+
items.sort((a, b) => a.index - b.index);
|
|
1509
3272
|
}
|
|
1510
|
-
|
|
1511
|
-
|
|
3273
|
+
return [items, automaticItems.map(item => item.element)];
|
|
3274
|
+
}
|
|
3275
|
+
function getCommonAncestor(firstNode, lastNode) {
|
|
3276
|
+
let ancestor = firstNode.parentElement;
|
|
3277
|
+
|
|
3278
|
+
// The `parentElement` walk cannot cross shadow boundaries, so the native
|
|
3279
|
+
// `contains` is sufficient here.
|
|
3280
|
+
while (ancestor && !ancestor.contains(lastNode)) {
|
|
3281
|
+
ancestor = ancestor.parentElement;
|
|
3282
|
+
}
|
|
3283
|
+
return ancestor;
|
|
3284
|
+
}
|
|
3285
|
+
function hasMovedNode(entries) {
|
|
3286
|
+
for (const entry of entries) {
|
|
3287
|
+
for (let i = 0; i < entry.removedNodes.length; i += 1) {
|
|
3288
|
+
if (entry.removedNodes[i].isConnected) {
|
|
3289
|
+
return true;
|
|
3290
|
+
}
|
|
3291
|
+
}
|
|
1512
3292
|
}
|
|
1513
|
-
return
|
|
3293
|
+
return false;
|
|
3294
|
+
}
|
|
3295
|
+
function sortByDocumentPosition(a, b) {
|
|
3296
|
+
// `DOCUMENT_POSITION_CONTAINED_BY` is always reported alongside `FOLLOWING`, and `CONTAINS`
|
|
3297
|
+
// alongside `PRECEDING`, so testing `FOLLOWING` alone orders siblings and nested items alike.
|
|
3298
|
+
return a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
|
|
1514
3299
|
}
|
|
1515
3300
|
|
|
1516
3301
|
/**
|
|
@@ -1535,17 +3320,17 @@ const baseArrow = options => ({
|
|
|
1535
3320
|
element,
|
|
1536
3321
|
padding = 0,
|
|
1537
3322
|
offsetParent = 'real'
|
|
1538
|
-
} =
|
|
3323
|
+
} = useScrollLock.evaluate(options, state) || {};
|
|
1539
3324
|
if (element == null) {
|
|
1540
3325
|
return {};
|
|
1541
3326
|
}
|
|
1542
|
-
const paddingObject =
|
|
3327
|
+
const paddingObject = useScrollLock.getPaddingObject(padding);
|
|
1543
3328
|
const coords = {
|
|
1544
3329
|
x,
|
|
1545
3330
|
y
|
|
1546
3331
|
};
|
|
1547
|
-
const axis =
|
|
1548
|
-
const length =
|
|
3332
|
+
const axis = useScrollLock.getAlignmentAxis(placement);
|
|
3333
|
+
const length = useScrollLock.getAxisLength(axis);
|
|
1549
3334
|
const arrowDimensions = await platform.getDimensions(element);
|
|
1550
3335
|
const isYAxis = axis === 'y';
|
|
1551
3336
|
const minProp = isYAxis ? 'top' : 'left';
|
|
@@ -1573,13 +3358,13 @@ const baseArrow = options => ({
|
|
|
1573
3358
|
const min = minPadding;
|
|
1574
3359
|
const max = clientSize - arrowDimensions[length] - maxPadding;
|
|
1575
3360
|
const center = clientSize / 2 - arrowDimensions[length] / 2 + centerToReference;
|
|
1576
|
-
const offset =
|
|
3361
|
+
const offset = useScrollLock.clamp(min, center, max);
|
|
1577
3362
|
|
|
1578
3363
|
// If the reference is small enough that the arrow's padding causes it to
|
|
1579
3364
|
// to point to nothing for an aligned placement, adjust the offset of the
|
|
1580
3365
|
// floating element itself. To ensure `shift()` continues to take action,
|
|
1581
3366
|
// a single reset is performed when this is true.
|
|
1582
|
-
const shouldAddOffset = !middlewareData.arrow &&
|
|
3367
|
+
const shouldAddOffset = !middlewareData.arrow && useScrollLock.getAlignment(placement) != null && center !== offset && rects.reference[length] / 2 - (center < min ? minPadding : maxPadding) - arrowDimensions[length] / 2 < 0;
|
|
1583
3368
|
// eslint-disable-next-line no-nested-ternary
|
|
1584
3369
|
const alignmentOffset = shouldAddOffset ? center < min ? center - min : center - max : 0;
|
|
1585
3370
|
return {
|
|
@@ -1607,7 +3392,6 @@ const arrow = (options, deps) => ({
|
|
|
1607
3392
|
options: [options, deps]
|
|
1608
3393
|
});
|
|
1609
3394
|
|
|
1610
|
-
const nativeHideFn = floatingUi_reactDom.hide().fn;
|
|
1611
3395
|
const hide = {
|
|
1612
3396
|
name: 'hide',
|
|
1613
3397
|
async fn(state) {
|
|
@@ -1618,10 +3402,15 @@ const hide = {
|
|
|
1618
3402
|
y
|
|
1619
3403
|
} = state.rects.reference;
|
|
1620
3404
|
const anchorHidden = width === 0 && height === 0 && x === 0 && y === 0;
|
|
1621
|
-
|
|
3405
|
+
// Mirrors Floating UI's `hide()` referenceHidden strategy. Floating UI injects
|
|
3406
|
+
// `detectOverflow` into the middleware platform before invoking middleware.
|
|
3407
|
+
const overflow = await state.platform.detectOverflow(state, {
|
|
3408
|
+
elementContext: 'reference'
|
|
3409
|
+
});
|
|
3410
|
+
const referenceHidden = overflow.top - height >= 0 || overflow.right - width >= 0 || overflow.bottom - height >= 0 || overflow.left - width >= 0;
|
|
1622
3411
|
return {
|
|
1623
3412
|
data: {
|
|
1624
|
-
referenceHidden:
|
|
3413
|
+
referenceHidden: referenceHidden || anchorHidden
|
|
1625
3414
|
}
|
|
1626
3415
|
};
|
|
1627
3416
|
}
|
|
@@ -1631,75 +3420,13 @@ const DEFAULT_SIDES = {
|
|
|
1631
3420
|
sideX: 'left',
|
|
1632
3421
|
sideY: 'top'
|
|
1633
3422
|
};
|
|
1634
|
-
const adaptiveOrigin = {
|
|
1635
|
-
name: 'adaptiveOrigin',
|
|
1636
|
-
async fn(state) {
|
|
1637
|
-
const {
|
|
1638
|
-
x: rawX,
|
|
1639
|
-
y: rawY,
|
|
1640
|
-
rects: {
|
|
1641
|
-
floating: floatRect
|
|
1642
|
-
},
|
|
1643
|
-
elements: {
|
|
1644
|
-
floating
|
|
1645
|
-
},
|
|
1646
|
-
platform,
|
|
1647
|
-
strategy,
|
|
1648
|
-
placement
|
|
1649
|
-
} = state;
|
|
1650
|
-
const win = floatingUi_utils.getWindow(floating);
|
|
1651
|
-
const styles = win.getComputedStyle(floating);
|
|
1652
|
-
const hasTransition = styles.transitionDuration !== '0s' && styles.transitionDuration !== '';
|
|
1653
|
-
if (!hasTransition) {
|
|
1654
|
-
return {
|
|
1655
|
-
x: rawX,
|
|
1656
|
-
y: rawY,
|
|
1657
|
-
data: DEFAULT_SIDES
|
|
1658
|
-
};
|
|
1659
|
-
}
|
|
1660
|
-
const offsetParent = await platform.getOffsetParent?.(floating);
|
|
1661
|
-
let offsetDimensions = {
|
|
1662
|
-
width: 0,
|
|
1663
|
-
height: 0
|
|
1664
|
-
};
|
|
1665
3423
|
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
width: win.visualViewport.width,
|
|
1670
|
-
height: win.visualViewport.height
|
|
1671
|
-
};
|
|
1672
|
-
} else if (offsetParent === win) {
|
|
1673
|
-
const doc = useScrollLock.ownerDocument(floating);
|
|
1674
|
-
offsetDimensions = {
|
|
1675
|
-
width: doc.documentElement.clientWidth,
|
|
1676
|
-
height: doc.documentElement.clientHeight
|
|
1677
|
-
};
|
|
1678
|
-
} else if (await platform.isElement?.(offsetParent)) {
|
|
1679
|
-
offsetDimensions = await platform.getDimensions(offsetParent);
|
|
1680
|
-
}
|
|
1681
|
-
const currentSide = floatingUi_utils.getSide(placement);
|
|
1682
|
-
let x = rawX;
|
|
1683
|
-
let y = rawY;
|
|
1684
|
-
if (currentSide === 'left') {
|
|
1685
|
-
x = offsetDimensions.width - (rawX + floatRect.width);
|
|
1686
|
-
}
|
|
1687
|
-
if (currentSide === 'top') {
|
|
1688
|
-
y = offsetDimensions.height - (rawY + floatRect.height);
|
|
1689
|
-
}
|
|
1690
|
-
const sideX = currentSide === 'left' ? 'right' : DEFAULT_SIDES.sideX;
|
|
1691
|
-
const sideY = currentSide === 'top' ? 'bottom' : DEFAULT_SIDES.sideY;
|
|
1692
|
-
return {
|
|
1693
|
-
x,
|
|
1694
|
-
y,
|
|
1695
|
-
data: {
|
|
1696
|
-
sideX,
|
|
1697
|
-
sideY
|
|
1698
|
-
}
|
|
1699
|
-
};
|
|
1700
|
-
}
|
|
1701
|
-
};
|
|
3424
|
+
// Self-contained stand-in for Floating UI's `Middleware` type. Referencing the real type in
|
|
3425
|
+
// store state makes `tsc` declaration emit reference `Platform`/`detectOverflow` from
|
|
3426
|
+
// `@floating-ui/core` internals, which fails as non-portable (TS2883) in consuming builds.
|
|
1702
3427
|
|
|
3428
|
+
const AVAILABLE_WIDTH_VAR = '--available-width';
|
|
3429
|
+
const AVAILABLE_HEIGHT_VAR = '--available-height';
|
|
1703
3430
|
function getLogicalSide(sideParam, renderedSide, isRtl) {
|
|
1704
3431
|
const isLogicalSideParam = sideParam === 'inline-start' || sideParam === 'inline-end';
|
|
1705
3432
|
const logicalRight = isRtl ? 'inline-start' : 'inline-end';
|
|
@@ -1717,8 +3444,8 @@ function getOffsetData(state, sideParam, isRtl) {
|
|
|
1717
3444
|
placement
|
|
1718
3445
|
} = state;
|
|
1719
3446
|
const data = {
|
|
1720
|
-
side: getLogicalSide(sideParam,
|
|
1721
|
-
align:
|
|
3447
|
+
side: getLogicalSide(sideParam, useScrollLock.getSide(placement), isRtl),
|
|
3448
|
+
align: useScrollLock.getAlignment(placement) || 'center',
|
|
1722
3449
|
anchor: {
|
|
1723
3450
|
width: rects.reference.width,
|
|
1724
3451
|
height: rects.reference.height
|
|
@@ -1735,6 +3462,9 @@ function getOffsetData(state, sideParam, isRtl) {
|
|
|
1735
3462
|
* `useFloating` hook.
|
|
1736
3463
|
*/
|
|
1737
3464
|
function useAnchorPositioning(params) {
|
|
3465
|
+
return useAnchorPositioningWithHook(params, useBaseUIFloating);
|
|
3466
|
+
}
|
|
3467
|
+
function useAnchorPositioningWithHook(params, useFloatingHook) {
|
|
1738
3468
|
const {
|
|
1739
3469
|
// Public parameters
|
|
1740
3470
|
anchor,
|
|
@@ -1754,7 +3484,7 @@ function useAnchorPositioning(params) {
|
|
|
1754
3484
|
floatingRootContext,
|
|
1755
3485
|
mounted,
|
|
1756
3486
|
collisionAvoidance,
|
|
1757
|
-
|
|
3487
|
+
shift: shift$1,
|
|
1758
3488
|
nodeId,
|
|
1759
3489
|
adaptiveOrigin,
|
|
1760
3490
|
lazyFlip = false,
|
|
@@ -1767,6 +3497,8 @@ function useAnchorPositioning(params) {
|
|
|
1767
3497
|
const collisionAvoidanceSide = collisionAvoidance.side || 'flip';
|
|
1768
3498
|
const collisionAvoidanceAlign = collisionAvoidance.align || 'flip';
|
|
1769
3499
|
const collisionAvoidanceFallbackAxisSide = collisionAvoidance.fallbackAxisSide || 'end';
|
|
3500
|
+
const shiftCrossAxis = shift$1?.crossAxis ?? false;
|
|
3501
|
+
const shiftRootBoundary = shift$1?.rootBoundary;
|
|
1770
3502
|
const anchorFn = typeof anchor === 'function' ? anchor : undefined;
|
|
1771
3503
|
const anchorFnCallback = useScrollLock.useStableCallback(anchorFn);
|
|
1772
3504
|
const anchorDep = anchorFn ? anchorFnCallback : anchor;
|
|
@@ -1784,30 +3516,32 @@ function useAnchorPositioning(params) {
|
|
|
1784
3516
|
}[sideParam];
|
|
1785
3517
|
const placement = align === 'center' ? side : `${side}-${align}`;
|
|
1786
3518
|
let collisionPadding = collisionPaddingParam;
|
|
3519
|
+
if (typeof collisionPadding === 'number') {
|
|
3520
|
+
collisionPadding = {
|
|
3521
|
+
top: collisionPadding,
|
|
3522
|
+
right: collisionPadding,
|
|
3523
|
+
bottom: collisionPadding,
|
|
3524
|
+
left: collisionPadding
|
|
3525
|
+
};
|
|
3526
|
+
} else if (collisionPadding) {
|
|
3527
|
+
collisionPadding = {
|
|
3528
|
+
top: collisionPadding.top || 0,
|
|
3529
|
+
right: collisionPadding.right || 0,
|
|
3530
|
+
bottom: collisionPadding.bottom || 0,
|
|
3531
|
+
left: collisionPadding.left || 0
|
|
3532
|
+
};
|
|
3533
|
+
}
|
|
1787
3534
|
|
|
1788
3535
|
// Create a bias to the preferred side.
|
|
1789
3536
|
// On iOS, when the mobile software keyboard opens, the input is exactly centered
|
|
1790
3537
|
// in the viewport, but this can cause it to flip to the top undesirably.
|
|
3538
|
+
// The bias is only applied to `flip()` so it doesn't shift the resting position
|
|
3539
|
+
// computed by `shift()` and `size()` away from the requested `collisionPadding`.
|
|
1791
3540
|
const bias = 1;
|
|
1792
3541
|
const biasTop = sideParam === 'bottom' ? bias : 0;
|
|
1793
3542
|
const biasBottom = sideParam === 'top' ? bias : 0;
|
|
1794
3543
|
const biasLeft = sideParam === 'right' ? bias : 0;
|
|
1795
3544
|
const biasRight = sideParam === 'left' ? bias : 0;
|
|
1796
|
-
if (typeof collisionPadding === 'number') {
|
|
1797
|
-
collisionPadding = {
|
|
1798
|
-
top: collisionPadding + biasTop,
|
|
1799
|
-
right: collisionPadding + biasRight,
|
|
1800
|
-
bottom: collisionPadding + biasBottom,
|
|
1801
|
-
left: collisionPadding + biasLeft
|
|
1802
|
-
};
|
|
1803
|
-
} else if (collisionPadding) {
|
|
1804
|
-
collisionPadding = {
|
|
1805
|
-
top: (collisionPadding.top || 0) + biasTop,
|
|
1806
|
-
right: (collisionPadding.right || 0) + biasRight,
|
|
1807
|
-
bottom: (collisionPadding.bottom || 0) + biasBottom,
|
|
1808
|
-
left: (collisionPadding.left || 0) + biasLeft
|
|
1809
|
-
};
|
|
1810
|
-
}
|
|
1811
3545
|
const commonCollisionProps = {
|
|
1812
3546
|
boundary: collisionBoundary === 'clipping-ancestors' ? 'clippingAncestors' : collisionBoundary,
|
|
1813
3547
|
padding: collisionPadding
|
|
@@ -1827,7 +3561,7 @@ function useAnchorPositioning(params) {
|
|
|
1827
3561
|
if (inlineMiddleware) {
|
|
1828
3562
|
middleware.push(inlineMiddleware);
|
|
1829
3563
|
}
|
|
1830
|
-
middleware.push(
|
|
3564
|
+
middleware.push(offset(state => {
|
|
1831
3565
|
const data = getOffsetData(state, sideParam, isRtl);
|
|
1832
3566
|
const sideAxis = typeof sideOffsetRef.current === 'function' ? sideOffsetRef.current(data) : sideOffsetRef.current;
|
|
1833
3567
|
const alignAxis = typeof alignOffsetRef.current === 'function' ? alignOffsetRef.current(data) : alignOffsetRef.current;
|
|
@@ -1839,51 +3573,42 @@ function useAnchorPositioning(params) {
|
|
|
1839
3573
|
}, [sideOffsetDep, alignOffsetDep, isRtl, sideParam]));
|
|
1840
3574
|
const shiftDisabled = collisionAvoidanceAlign === 'none' && collisionAvoidanceSide !== 'shift';
|
|
1841
3575
|
const crossAxisShiftEnabled = !shiftDisabled && (sticky || shiftCrossAxis || collisionAvoidanceSide === 'shift');
|
|
1842
|
-
const flipMiddleware = collisionAvoidanceSide === 'none' ? null :
|
|
3576
|
+
const flipMiddleware = collisionAvoidanceSide === 'none' ? null : flip({
|
|
1843
3577
|
...commonCollisionProps,
|
|
1844
3578
|
// Ensure the popup flips if it's been limited by its --available-height and it resizes.
|
|
1845
3579
|
// Since the size() padding is smaller than the flip() padding, flip() will take precedence.
|
|
1846
3580
|
padding: {
|
|
1847
|
-
top: collisionPadding.top + bias,
|
|
1848
|
-
right: collisionPadding.right + bias,
|
|
1849
|
-
bottom: collisionPadding.bottom + bias,
|
|
1850
|
-
left: collisionPadding.left + bias
|
|
3581
|
+
top: collisionPadding.top + bias + biasTop,
|
|
3582
|
+
right: collisionPadding.right + bias + biasRight,
|
|
3583
|
+
bottom: collisionPadding.bottom + bias + biasBottom,
|
|
3584
|
+
left: collisionPadding.left + bias + biasLeft
|
|
1851
3585
|
},
|
|
1852
3586
|
mainAxis: !shiftCrossAxis && collisionAvoidanceSide === 'flip',
|
|
1853
3587
|
crossAxis: collisionAvoidanceAlign === 'flip' ? 'alignment' : false,
|
|
1854
3588
|
fallbackAxisSideDirection: collisionAvoidanceFallbackAxisSide
|
|
1855
3589
|
});
|
|
1856
|
-
const shiftMiddleware = shiftDisabled ? null :
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
const sideAxis = floatingUi_utils.getSideAxis(floatingUi_utils.getSide(limitData.placement));
|
|
1879
|
-
const arrowSize = sideAxis === 'y' ? width : height;
|
|
1880
|
-
const offsetAmount = sideAxis === 'y' ? collisionPadding.left + collisionPadding.right : collisionPadding.top + collisionPadding.bottom;
|
|
1881
|
-
return {
|
|
1882
|
-
offset: arrowSize / 2 + offsetAmount / 2
|
|
1883
|
-
};
|
|
1884
|
-
})
|
|
1885
|
-
};
|
|
1886
|
-
}, [commonCollisionProps, sticky, shiftCrossAxis, collisionPadding, collisionAvoidanceAlign]);
|
|
3590
|
+
const shiftMiddleware = shiftDisabled ? null : shift({
|
|
3591
|
+
...commonCollisionProps,
|
|
3592
|
+
// Use the Layout Viewport to avoid shifting around when pinch-zooming.
|
|
3593
|
+
rootBoundary: shiftRootBoundary,
|
|
3594
|
+
mainAxis: collisionAvoidanceAlign !== 'none',
|
|
3595
|
+
crossAxis: crossAxisShiftEnabled,
|
|
3596
|
+
limiter: sticky || shiftCrossAxis ? undefined : limitShift(limitData => {
|
|
3597
|
+
if (!arrowRef.current) {
|
|
3598
|
+
return {};
|
|
3599
|
+
}
|
|
3600
|
+
const {
|
|
3601
|
+
width,
|
|
3602
|
+
height
|
|
3603
|
+
} = arrowRef.current.getBoundingClientRect();
|
|
3604
|
+
const sideAxis = useScrollLock.getSideAxis(useScrollLock.getSide(limitData.placement));
|
|
3605
|
+
const arrowSize = sideAxis === 'y' ? width : height;
|
|
3606
|
+
const offsetAmount = sideAxis === 'y' ? collisionPadding.left + collisionPadding.right : collisionPadding.top + collisionPadding.bottom;
|
|
3607
|
+
return {
|
|
3608
|
+
offset: arrowSize / 2 + offsetAmount / 2
|
|
3609
|
+
};
|
|
3610
|
+
})
|
|
3611
|
+
}, [commonCollisionProps, sticky, shiftCrossAxis, shiftRootBoundary, collisionPadding, collisionAvoidanceAlign]);
|
|
1887
3612
|
|
|
1888
3613
|
// https://floating-ui.com/docs/flip#combining-with-shift
|
|
1889
3614
|
if (collisionAvoidanceSide === 'shift' || collisionAvoidanceAlign === 'shift' || align === 'center') {
|
|
@@ -1891,7 +3616,7 @@ function useAnchorPositioning(params) {
|
|
|
1891
3616
|
} else {
|
|
1892
3617
|
middleware.push(flipMiddleware, shiftMiddleware);
|
|
1893
3618
|
}
|
|
1894
|
-
middleware.push(
|
|
3619
|
+
middleware.push(size({
|
|
1895
3620
|
...commonCollisionProps,
|
|
1896
3621
|
apply({
|
|
1897
3622
|
elements: {
|
|
@@ -1905,11 +3630,11 @@ function useAnchorPositioning(params) {
|
|
|
1905
3630
|
return;
|
|
1906
3631
|
}
|
|
1907
3632
|
const floatingStyle = floating.style;
|
|
1908
|
-
floatingStyle.setProperty(
|
|
1909
|
-
floatingStyle.setProperty(
|
|
3633
|
+
floatingStyle.setProperty(AVAILABLE_WIDTH_VAR, `${availableWidth}px`);
|
|
3634
|
+
floatingStyle.setProperty(AVAILABLE_HEIGHT_VAR, `${availableHeight}px`);
|
|
1910
3635
|
|
|
1911
3636
|
// Snap anchor dimensions to device pixels to ensure the popup's visual width matches the anchor's one.
|
|
1912
|
-
const dpr =
|
|
3637
|
+
const dpr = useScrollLock.getWindow(floating).devicePixelRatio || 1;
|
|
1913
3638
|
const {
|
|
1914
3639
|
x,
|
|
1915
3640
|
y,
|
|
@@ -1937,8 +3662,8 @@ function useAnchorPositioning(params) {
|
|
|
1937
3662
|
rects,
|
|
1938
3663
|
y
|
|
1939
3664
|
} = state;
|
|
1940
|
-
const currentRenderedSide =
|
|
1941
|
-
const currentRenderedAxis =
|
|
3665
|
+
const currentRenderedSide = useScrollLock.getSide(renderedPlacement);
|
|
3666
|
+
const currentRenderedAxis = useScrollLock.getSideAxis(currentRenderedSide);
|
|
1942
3667
|
const arrowEl = arrowRef.current;
|
|
1943
3668
|
const arrowX = middlewareData.arrow?.x || 0;
|
|
1944
3669
|
const arrowY = middlewareData.arrow?.y || 0;
|
|
@@ -1988,13 +3713,13 @@ function useAnchorPositioning(params) {
|
|
|
1988
3713
|
context,
|
|
1989
3714
|
isPositioned,
|
|
1990
3715
|
floatingStyles: originalFloatingStyles
|
|
1991
|
-
} =
|
|
3716
|
+
} = useFloatingHook({
|
|
1992
3717
|
rootContext: floatingRootContext,
|
|
1993
3718
|
open: keepMounted ? mounted : undefined,
|
|
1994
3719
|
placement,
|
|
1995
3720
|
middleware,
|
|
1996
3721
|
strategy: positionMethod,
|
|
1997
|
-
whileElementsMounted: keepMounted ? undefined : (...args) =>
|
|
3722
|
+
whileElementsMounted: keepMounted ? undefined : (...args) => autoUpdate(...args, autoUpdateOptions),
|
|
1998
3723
|
nodeId,
|
|
1999
3724
|
externalTree
|
|
2000
3725
|
});
|
|
@@ -2007,14 +3732,41 @@ function useAnchorPositioning(params) {
|
|
|
2007
3732
|
// This ensures the popup is inside the viewport initially before it gets positioned.
|
|
2008
3733
|
const resolvedPosition = isPositioned ? positionMethod : 'fixed';
|
|
2009
3734
|
const floatingStyles = React__namespace.useMemo(() => {
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
3735
|
+
let base;
|
|
3736
|
+
if (!isPositioned) {
|
|
3737
|
+
// Until a position for the current open is computed, ignore any coordinates retained from a
|
|
3738
|
+
// previous open (or from a pass that measured the hidden popup as 0x0). Rendering the
|
|
3739
|
+
// full-size popup at such stale coordinates can overflow the layout viewport, which makes
|
|
3740
|
+
// mobile Chrome zoom the page out and reflow everything the popup is anchored to.
|
|
3741
|
+
base = {
|
|
3742
|
+
position: resolvedPosition,
|
|
3743
|
+
top: 0,
|
|
3744
|
+
left: 0
|
|
3745
|
+
};
|
|
3746
|
+
} else if (adaptiveOrigin) {
|
|
3747
|
+
base = {
|
|
3748
|
+
position: resolvedPosition,
|
|
3749
|
+
[sideX]: x,
|
|
3750
|
+
[sideY]: y
|
|
3751
|
+
};
|
|
3752
|
+
} else {
|
|
3753
|
+
base = {
|
|
3754
|
+
...originalFloatingStyles,
|
|
3755
|
+
position: resolvedPosition
|
|
3756
|
+
};
|
|
3757
|
+
}
|
|
3758
|
+
|
|
3759
|
+
// Seed the available size vars so consumer `max-height: min(x, var(--available-height))` rules
|
|
3760
|
+
// resolve to a valid length on the first positioning pass, before `size()` writes the real
|
|
3761
|
+
// values. Without a fallback the unresolved `var()` invalidates the whole declaration, so the
|
|
3762
|
+
// popup is measured unconstrained while `flip()` picks its side, against the full content
|
|
3763
|
+
// height rather than the capped one. Seeded unconditionally (not only while `!isPositioned`):
|
|
3764
|
+
// the keys must stay present with a constant value so React's per-property style diff never
|
|
3765
|
+
// rewrites them after mount, preserving the px values `size()` sets imperatively. Moving them
|
|
3766
|
+
// into the `!isPositioned` branch makes React remove them once positioned, wiping `size()`'s
|
|
3767
|
+
// values and leaving the popup unconstrained.
|
|
3768
|
+
base[AVAILABLE_WIDTH_VAR] = '100vw';
|
|
3769
|
+
base[AVAILABLE_HEIGHT_VAR] = '100vh';
|
|
2018
3770
|
if (!isPositioned) {
|
|
2019
3771
|
base.opacity = 0;
|
|
2020
3772
|
}
|
|
@@ -2052,23 +3804,23 @@ function useAnchorPositioning(params) {
|
|
|
2052
3804
|
}, [mounted, refs, anchorDep, anchorValueRef]);
|
|
2053
3805
|
React__namespace.useEffect(() => {
|
|
2054
3806
|
if (keepMounted && mounted && elements.reference && elements.floating) {
|
|
2055
|
-
return
|
|
3807
|
+
return autoUpdate(elements.reference, elements.floating, update, autoUpdateOptions);
|
|
2056
3808
|
}
|
|
2057
3809
|
return undefined;
|
|
2058
3810
|
}, [keepMounted, mounted, elements, update, autoUpdateOptions]);
|
|
2059
|
-
const renderedSide =
|
|
3811
|
+
const renderedSide = useScrollLock.getSide(renderedPlacement);
|
|
2060
3812
|
const logicalRenderedSide = getLogicalSide(sideParam, renderedSide, isRtl);
|
|
2061
|
-
const renderedAlign =
|
|
3813
|
+
const renderedAlign = useScrollLock.getAlignment(renderedPlacement) || 'center';
|
|
2062
3814
|
const anchorHidden = Boolean(middlewareData.hide?.referenceHidden);
|
|
2063
3815
|
|
|
2064
3816
|
// Locks the flip (makes it "sticky") so it doesn't prefer a given placement
|
|
2065
3817
|
// and flips back lazily, not eagerly. Ideal for filtered lists that change
|
|
2066
3818
|
// the size of the popup dynamically to avoid unwanted flipping when typing.
|
|
2067
3819
|
useScrollLock.useIsoLayoutEffect(() => {
|
|
2068
|
-
if (lazyFlip && mounted && isPositioned) {
|
|
3820
|
+
if (lazyFlip && mounted && isPositioned && renderedSide !== side) {
|
|
2069
3821
|
setMountSide(renderedSide);
|
|
2070
3822
|
}
|
|
2071
|
-
}, [lazyFlip, mounted, isPositioned, renderedSide]);
|
|
3823
|
+
}, [lazyFlip, mounted, isPositioned, renderedSide, side]);
|
|
2072
3824
|
const arrowStyles = React__namespace.useMemo(() => ({
|
|
2073
3825
|
position: 'absolute',
|
|
2074
3826
|
top: middlewareData.arrow?.y,
|
|
@@ -2153,64 +3905,57 @@ function useAnchoredPopupScrollLock(enabled, touchOpen, positionerElement, refer
|
|
|
2153
3905
|
useScrollLock.useScrollLock(enabled && (!touchOpen || touchOpenShouldLockScroll), referenceElement);
|
|
2154
3906
|
}
|
|
2155
3907
|
|
|
2156
|
-
let IndexGuessBehavior = /*#__PURE__*/function (IndexGuessBehavior) {
|
|
2157
|
-
IndexGuessBehavior[IndexGuessBehavior["None"] = 0] = "None";
|
|
2158
|
-
IndexGuessBehavior[IndexGuessBehavior["GuessFromOrder"] = 1] = "GuessFromOrder";
|
|
2159
|
-
return IndexGuessBehavior;
|
|
2160
|
-
}({});
|
|
2161
|
-
|
|
2162
3908
|
/**
|
|
2163
3909
|
* Used to register a list item and its index (DOM position) in the `CompositeList`.
|
|
2164
3910
|
*/
|
|
2165
3911
|
function useCompositeListItem(params = {}) {
|
|
2166
3912
|
const {
|
|
3913
|
+
guess,
|
|
2167
3914
|
label,
|
|
2168
3915
|
metadata,
|
|
2169
3916
|
textRef,
|
|
2170
|
-
indexGuessBehavior,
|
|
2171
3917
|
index: externalIndex
|
|
2172
3918
|
} = params;
|
|
2173
3919
|
const {
|
|
2174
3920
|
register,
|
|
2175
3921
|
unregister,
|
|
2176
3922
|
subscribeMapChange,
|
|
2177
|
-
elementsRef,
|
|
2178
|
-
labelsRef,
|
|
2179
3923
|
nextIndexRef
|
|
2180
3924
|
} = useCompositeListContext();
|
|
3925
|
+
|
|
3926
|
+
// Guess the index from the render order. This avoids a re-render after mount for
|
|
3927
|
+
// flat lists rendered in DOM order; when the guess is wrong (grouped or out-of-order
|
|
3928
|
+
// rendering), the commit flush corrects it before paint.
|
|
2181
3929
|
const indexRef = React__namespace.useRef(-1);
|
|
2182
|
-
const [
|
|
3930
|
+
const [internalIndex, setInternalIndex] = React__namespace.useState(externalIndex == null && guess ? () => {
|
|
2183
3931
|
if (indexRef.current === -1) {
|
|
2184
3932
|
const newIndex = nextIndexRef.current;
|
|
2185
3933
|
nextIndexRef.current += 1;
|
|
2186
3934
|
indexRef.current = newIndex;
|
|
2187
3935
|
}
|
|
2188
3936
|
return indexRef.current;
|
|
2189
|
-
} : -1)
|
|
3937
|
+
} : -1);
|
|
3938
|
+
const index = externalIndex ?? internalIndex;
|
|
2190
3939
|
const componentRef = React__namespace.useRef(null);
|
|
3940
|
+
|
|
3941
|
+
// Deliberately identity-sensitive: nested items sharing one DOM node rely on ref attachment
|
|
3942
|
+
// order to decide which registration wins, and republishing from an effect instead would let
|
|
3943
|
+
// an inner item's later update silently take ownership from the outer one.
|
|
2191
3944
|
const ref = React__namespace.useCallback(node => {
|
|
2192
|
-
componentRef.current
|
|
2193
|
-
if (
|
|
2194
|
-
|
|
2195
|
-
if (labelsRef) {
|
|
2196
|
-
const isLabelDefined = label !== undefined;
|
|
2197
|
-
labelsRef.current[index] = isLabelDefined ? label : textRef?.current?.textContent ?? node.textContent;
|
|
2198
|
-
}
|
|
3945
|
+
const previousNode = componentRef.current;
|
|
3946
|
+
if (previousNode) {
|
|
3947
|
+
unregister(previousNode);
|
|
2199
3948
|
}
|
|
2200
|
-
|
|
2201
|
-
useScrollLock.useIsoLayoutEffect(() => {
|
|
2202
|
-
if (externalIndex != null) {
|
|
2203
|
-
return undefined;
|
|
2204
|
-
}
|
|
2205
|
-
const node = componentRef.current;
|
|
3949
|
+
componentRef.current = node;
|
|
2206
3950
|
if (node) {
|
|
2207
|
-
register(node,
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
3951
|
+
register(node, {
|
|
3952
|
+
metadata: metadata ?? null,
|
|
3953
|
+
index: externalIndex ?? null,
|
|
3954
|
+
label,
|
|
3955
|
+
textRef
|
|
3956
|
+
});
|
|
2211
3957
|
}
|
|
2212
|
-
|
|
2213
|
-
}, [externalIndex, register, unregister, metadata]);
|
|
3958
|
+
}, [externalIndex, register, unregister, metadata, label, textRef]);
|
|
2214
3959
|
useScrollLock.useIsoLayoutEffect(() => {
|
|
2215
3960
|
if (externalIndex != null) {
|
|
2216
3961
|
return undefined;
|
|
@@ -2218,10 +3963,10 @@ function useCompositeListItem(params = {}) {
|
|
|
2218
3963
|
return subscribeMapChange(map => {
|
|
2219
3964
|
const i = componentRef.current ? map.get(componentRef.current)?.index : null;
|
|
2220
3965
|
if (i != null) {
|
|
2221
|
-
|
|
3966
|
+
setInternalIndex(i);
|
|
2222
3967
|
}
|
|
2223
3968
|
});
|
|
2224
|
-
}, [externalIndex, subscribeMapChange
|
|
3969
|
+
}, [externalIndex, subscribeMapChange]);
|
|
2225
3970
|
return {
|
|
2226
3971
|
ref,
|
|
2227
3972
|
index
|
|
@@ -2231,21 +3976,22 @@ function useCompositeListItem(params = {}) {
|
|
|
2231
3976
|
exports.CompositeList = CompositeList;
|
|
2232
3977
|
exports.DEFAULT_FIELD_ROOT_CONTEXT = DEFAULT_FIELD_ROOT_CONTEXT;
|
|
2233
3978
|
exports.DEFAULT_FIELD_STATE_ATTRIBUTES = DEFAULT_FIELD_STATE_ATTRIBUTES;
|
|
3979
|
+
exports.DEFAULT_SIDES = DEFAULT_SIDES;
|
|
2234
3980
|
exports.DEFAULT_VALIDITY_STATE = DEFAULT_VALIDITY_STATE;
|
|
2235
3981
|
exports.FieldRootContext = FieldRootContext;
|
|
2236
|
-
exports.IndexGuessBehavior = IndexGuessBehavior;
|
|
2237
3982
|
exports.LabelableContext = LabelableContext;
|
|
2238
|
-
exports.adaptiveOrigin = adaptiveOrigin;
|
|
2239
3983
|
exports.areArraysEqual = areArraysEqual;
|
|
2240
3984
|
exports.compareItemEquality = compareItemEquality;
|
|
2241
3985
|
exports.defaultItemEquality = defaultItemEquality;
|
|
2242
3986
|
exports.fieldValidityMapping = fieldValidityMapping;
|
|
2243
3987
|
exports.findItemIndex = findItemIndex;
|
|
3988
|
+
exports.findSelectionIndex = findSelectionIndex;
|
|
2244
3989
|
exports.getDefaultLabelId = getDefaultLabelId;
|
|
2245
3990
|
exports.getDisabledMountTransitionStyles = getDisabledMountTransitionStyles;
|
|
2246
|
-
exports.getPseudoElementBounds = getPseudoElementBounds;
|
|
2247
3991
|
exports.hasNullItemLabel = hasNullItemLabel;
|
|
2248
3992
|
exports.isGroupedItems = isGroupedItems;
|
|
3993
|
+
exports.isMouseWithinBounds = isMouseWithinBounds;
|
|
3994
|
+
exports.platform = platform;
|
|
2249
3995
|
exports.removeItem = removeItem;
|
|
2250
3996
|
exports.resolveAriaLabelledBy = resolveAriaLabelledBy;
|
|
2251
3997
|
exports.resolveMultipleLabels = resolveMultipleLabels;
|
|
@@ -2262,6 +4008,7 @@ exports.useFormContext = useFormContext;
|
|
|
2262
4008
|
exports.useLabelableContext = useLabelableContext;
|
|
2263
4009
|
exports.useLabelableId = useLabelableId;
|
|
2264
4010
|
exports.useListNavigation = useListNavigation;
|
|
4011
|
+
exports.useOnFirstRender = useOnFirstRender;
|
|
2265
4012
|
exports.usePositioner = usePositioner;
|
|
2266
4013
|
exports.useRegisterFieldControl = useRegisterFieldControl;
|
|
2267
4014
|
exports.useTypeahead = useTypeahead;
|