@jobber/components 9.6.0 → 9.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ActivityIndicator-cjs.js +1 -0
- package/dist/ActivityIndicator-es.js +1 -0
- package/dist/Autocomplete/index.cjs +2 -0
- package/dist/Autocomplete/index.mjs +2 -0
- package/dist/Autocomplete-cjs.js +6 -4
- package/dist/Autocomplete-es.js +3 -1
- package/dist/Banner-cjs.js +1 -0
- package/dist/Banner-es.js +1 -0
- package/dist/Card/index.cjs +2 -1
- package/dist/Card/index.mjs +2 -1
- package/dist/Chip/index.cjs +2 -0
- package/dist/Chip/index.mjs +2 -0
- package/dist/Chip-cjs.js +1 -0
- package/dist/Chip-es.js +1 -0
- package/dist/Chips/InternalChipDismissible/hooks/index.cjs +2 -0
- package/dist/Chips/InternalChipDismissible/hooks/index.mjs +2 -0
- package/dist/Chips/InternalChipDismissible/index.cjs +2 -0
- package/dist/Chips/InternalChipDismissible/index.mjs +2 -0
- package/dist/Chips/index.cjs +2 -0
- package/dist/Chips/index.mjs +2 -0
- package/dist/Combobox/index.cjs +4 -2
- package/dist/Combobox/index.mjs +4 -2
- package/dist/{ComboboxSeparator-cjs.js → ComboboxChipRemove-cjs.js} +455 -501
- package/dist/{ComboboxSeparator-es.js → ComboboxChipRemove-es.js} +456 -500
- package/dist/ComboboxPrimitive-cjs.js +30 -29
- package/dist/ComboboxPrimitive-es.js +3 -2
- package/dist/ConfirmationModal/index.cjs +2 -0
- package/dist/ConfirmationModal/index.mjs +2 -0
- package/dist/ConfirmationModal-cjs.js +1 -0
- package/dist/ConfirmationModal-es.js +1 -0
- package/dist/DataDump/index.cjs +2 -1
- package/dist/DataDump/index.mjs +2 -1
- package/dist/DataDump-cjs.js +1 -0
- package/dist/DataDump-es.js +1 -0
- package/dist/DataList/components/DataListActions/index.cjs +2 -0
- package/dist/DataList/components/DataListActions/index.mjs +2 -0
- package/dist/DataList/components/DataListBulkActions/index.cjs +2 -0
- package/dist/DataList/components/DataListBulkActions/index.mjs +2 -0
- package/dist/DataList/components/DataListFilters/components/DataListSort/index.cjs +2 -0
- package/dist/DataList/components/DataListFilters/components/DataListSort/index.mjs +2 -0
- package/dist/DataList/components/DataListFilters/index.cjs +2 -0
- package/dist/DataList/components/DataListFilters/index.mjs +2 -0
- package/dist/DataList/components/DataListHeader/index.cjs +2 -0
- package/dist/DataList/components/DataListHeader/index.mjs +2 -0
- package/dist/DataList/components/DataListItem/index.cjs +2 -0
- package/dist/DataList/components/DataListItem/index.mjs +2 -0
- package/dist/DataList/components/DataListItemActions/index.cjs +2 -0
- package/dist/DataList/components/DataListItemActions/index.mjs +2 -0
- package/dist/DataList/components/DataListItemActionsOverflow/index.cjs +2 -0
- package/dist/DataList/components/DataListItemActionsOverflow/index.mjs +2 -0
- package/dist/DataList/components/DataListItems/index.cjs +2 -0
- package/dist/DataList/components/DataListItems/index.mjs +2 -0
- package/dist/DataList/components/DataListLayout/index.cjs +2 -0
- package/dist/DataList/components/DataListLayout/index.mjs +2 -0
- package/dist/DataList/components/DataListLayoutActions/index.cjs +2 -0
- package/dist/DataList/components/DataListLayoutActions/index.mjs +2 -0
- package/dist/DataList/index.cjs +2 -0
- package/dist/DataList/index.mjs +2 -0
- package/dist/DataTable-cjs.js +1 -0
- package/dist/DataTable-es.js +1 -0
- package/dist/DatePicker/index.cjs +2 -0
- package/dist/DatePicker/index.mjs +2 -0
- package/dist/DatePicker-cjs.js +8 -7
- package/dist/DatePicker-es.js +6 -5
- package/dist/Dialog/index.cjs +2 -1
- package/dist/Dialog/index.mjs +2 -1
- package/dist/DrawerDescription-cjs.js +99 -268
- package/dist/DrawerDescription-es.js +103 -270
- package/dist/DrawerGrid-cjs.js +1 -0
- package/dist/DrawerGrid-es.js +1 -0
- package/dist/DrawerTitle-cjs.js +6 -2
- package/dist/DrawerTitle-es.js +7 -3
- package/dist/FeatureSwitch-cjs.js +1 -0
- package/dist/FeatureSwitch-es.js +1 -0
- package/dist/FieldDescription-cjs.js +181 -184
- package/dist/FieldDescription-es.js +184 -187
- package/dist/FilterPicker/components/FilterPickerActivator/index.cjs +2 -0
- package/dist/FilterPicker/components/FilterPickerActivator/index.mjs +2 -0
- package/dist/FilterPicker/components/FilterPickerContent/index.cjs +2 -0
- package/dist/FilterPicker/components/FilterPickerContent/index.mjs +2 -0
- package/dist/FilterPicker/components/FilterPickerTrigger/index.cjs +2 -0
- package/dist/FilterPicker/components/FilterPickerTrigger/index.mjs +2 -0
- package/dist/FilterPicker/index.cjs +2 -0
- package/dist/FilterPicker/index.mjs +2 -0
- package/dist/FilterPickerContent-cjs.js +5 -4
- package/dist/FilterPickerContent-es.js +2 -1
- package/dist/FormFieldWrapper-cjs.js +1 -0
- package/dist/FormFieldWrapper-es.js +1 -0
- package/dist/FormatFile/index.cjs +2 -0
- package/dist/FormatFile/index.mjs +2 -0
- package/dist/FormatFile-cjs.js +1 -0
- package/dist/FormatFile-es.js +1 -0
- package/dist/Gallery/index.cjs +2 -0
- package/dist/Gallery/index.mjs +2 -0
- package/dist/InputAvatar-cjs.js +1 -0
- package/dist/InputAvatar-es.js +1 -0
- package/dist/InputDate/index.cjs +2 -0
- package/dist/InputDate/index.mjs +2 -0
- package/dist/InputDate-cjs.js +1 -0
- package/dist/InputDate-es.js +1 -0
- package/dist/InputNumber/index.cjs +2 -1
- package/dist/InputNumber/index.mjs +2 -1
- package/dist/InternalChipDismissible-cjs.js +1 -0
- package/dist/InternalChipDismissible-es.js +1 -0
- package/dist/LightBox/index.cjs +2 -0
- package/dist/LightBox/index.mjs +2 -0
- package/dist/LightBox-cjs.js +1 -0
- package/dist/LightBox-es.js +1 -0
- package/dist/Menu/index.cjs +2 -1
- package/dist/Menu/index.mjs +2 -1
- package/dist/Menu-cjs.js +6 -4
- package/dist/Menu-es.js +3 -1
- package/dist/MenuSubmenuTrigger-cjs.js +164 -206
- package/dist/MenuSubmenuTrigger-es.js +152 -194
- package/dist/Modal/index.cjs +3 -1
- package/dist/Modal/index.mjs +4 -2
- package/dist/NumberFieldInput-cjs.js +308 -187
- package/dist/NumberFieldInput-es.js +308 -187
- package/dist/Page/index.cjs +2 -1
- package/dist/Page/index.mjs +2 -1
- package/dist/Page-cjs.js +1 -0
- package/dist/Page-es.js +1 -0
- package/dist/Popover/index.cjs +2 -0
- package/dist/Popover/index.mjs +2 -0
- package/dist/Popover-cjs.js +9 -7
- package/dist/Popover-es.js +3 -1
- package/dist/ProgressBar-cjs.js +1 -0
- package/dist/ProgressBar-es.js +1 -0
- package/dist/ScrollAreaViewport-cjs.js +1093 -747
- package/dist/ScrollAreaViewport-es.js +1081 -734
- package/dist/Select/index.cjs +2 -1
- package/dist/Select/index.mjs +2 -1
- package/dist/SelectGroupLabel-cjs.js +306 -207
- package/dist/SelectGroupLabel-es.js +302 -203
- package/dist/SideDrawer-cjs.js +1 -0
- package/dist/SideDrawer-es.js +1 -0
- package/dist/Spinner-cjs.js +1 -0
- package/dist/Spinner-es.js +1 -0
- package/dist/Tooltip/index.cjs +2 -0
- package/dist/Tooltip/index.mjs +2 -0
- package/dist/Tooltip-cjs.js +7 -6
- package/dist/Tooltip-es.js +2 -1
- package/dist/dialogReturnFocus-cjs.js +1 -1
- package/dist/dialogReturnFocus-es.js +2 -2
- package/dist/floating-ui.react-cjs.js +192 -2564
- package/dist/floating-ui.react-dom-cjs.js +2103 -0
- package/dist/floating-ui.react-dom-es.js +2072 -0
- package/dist/floating-ui.react-es.js +156 -2519
- package/dist/floating-ui.utils-cjs.js +342 -0
- package/dist/floating-ui.utils-es.js +300 -0
- package/dist/index.cjs +4 -3
- package/dist/index.mjs +4 -3
- package/dist/primitives/BottomSheet/index.cjs +1 -1
- package/dist/primitives/BottomSheet/index.mjs +1 -1
- package/dist/primitives/ComboboxPrimitive/index.cjs +4 -2
- package/dist/primitives/ComboboxPrimitive/index.mjs +4 -2
- package/dist/primitives/SelectPrimitive/index.cjs +2 -0
- package/dist/primitives/SelectPrimitive/index.mjs +2 -0
- package/dist/primitives/index.cjs +3 -2
- package/dist/primitives/index.mjs +3 -2
- package/dist/scrollEdges-cjs.js +11 -1
- package/dist/scrollEdges-es.js +11 -1
- package/dist/sharedHelpers/i18n/index.cjs +1 -0
- package/dist/sharedHelpers/i18n/index.d.ts +1 -0
- package/dist/sharedHelpers/i18n/index.mjs +1 -1
- package/dist/sharedHelpers/i18n/releasedLanguages.d.ts +12 -0
- package/dist/sharedHelpers/i18n/useReleasedLocale.d.ts +6 -0
- package/dist/showToast-cjs.js +1 -1
- package/dist/showToast-es.js +1 -1
- package/dist/testUtils/releasedLanguages.d.ts +16 -0
- package/dist/unstyledPrimitives/index.cjs +478 -720
- package/dist/unstyledPrimitives/index.mjs +421 -663
- package/dist/useAtlantisI18n-cjs.js +44 -11
- package/dist/useAtlantisI18n-es.js +44 -12
- package/dist/useCompositeListItem-cjs.js +361 -2108
- package/dist/useCompositeListItem-es.js +331 -2076
- package/dist/useLabel-cjs.js +3 -2
- package/dist/useLabel-es.js +3 -2
- package/dist/useRenderElement-cjs.js +7 -9
- package/dist/useRenderElement-es.js +7 -9
- package/dist/useScrollLock-cjs.js +344 -819
- package/dist/useScrollLock-es.js +296 -732
- package/dist/useScrollToActive-cjs.js +5 -4
- package/dist/useScrollToActive-es.js +2 -1
- package/package.json +3 -3
- package/dist/scrollable-cjs.js +0 -58
- package/dist/scrollable-es.js +0 -54
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var React = require('react');
|
|
4
|
-
var
|
|
4
|
+
var ComboboxChipRemove = require('../ComboboxChipRemove-cjs.js');
|
|
5
5
|
var useCompositeListItem = require('../useCompositeListItem-cjs.js');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
7
|
var useScrollLock = require('../useScrollLock-cjs.js');
|
|
8
|
+
var Separator = require('../Separator-cjs.js');
|
|
8
9
|
var DrawerDescription = require('../DrawerDescription-cjs.js');
|
|
9
10
|
var DrawerTitle = require('../DrawerTitle-cjs.js');
|
|
10
11
|
var ScrollAreaViewport = require('../ScrollAreaViewport-cjs.js');
|
|
11
12
|
var useRenderElement = require('../useRenderElement-cjs.js');
|
|
13
|
+
var floatingUi_utils = require('../floating-ui.utils-cjs.js');
|
|
12
14
|
var scrollEdges = require('../scrollEdges-cjs.js');
|
|
13
|
-
var scrollable = require('../scrollable-cjs.js');
|
|
14
15
|
var MenuSubmenuTrigger = require('../MenuSubmenuTrigger-cjs.js');
|
|
15
16
|
var ReactDOM = require('react-dom');
|
|
16
17
|
var SelectGroupLabel = require('../SelectGroupLabel-cjs.js');
|
|
17
|
-
var Separator = require('../Separator-cjs.js');
|
|
18
18
|
var NumberFieldInput = require('../NumberFieldInput-cjs.js');
|
|
19
19
|
var useLabel = require('../useLabel-cjs.js');
|
|
20
20
|
require('../stringifyLocale-cjs.js');
|
|
21
|
+
require('../floating-ui.react-dom-cjs.js');
|
|
21
22
|
|
|
22
23
|
function _interopNamespaceDefault(e) {
|
|
23
24
|
var n = Object.create(null);
|
|
@@ -72,9 +73,7 @@ function AutocompleteRoot(props) {
|
|
|
72
73
|
} else {
|
|
73
74
|
resolvedInputValue = internalValue;
|
|
74
75
|
}
|
|
75
|
-
const collator =
|
|
76
|
-
locale: other.locale
|
|
77
|
-
});
|
|
76
|
+
const collator = ComboboxChipRemove.useCoreFilter();
|
|
78
77
|
const baseFilter = React__namespace.useMemo(() => {
|
|
79
78
|
if (other.filter !== undefined) {
|
|
80
79
|
return other.filter;
|
|
@@ -107,9 +106,17 @@ function AutocompleteRoot(props) {
|
|
|
107
106
|
if (eventDetails.reason === useScrollLock.pointer) {
|
|
108
107
|
return;
|
|
109
108
|
}
|
|
110
|
-
|
|
109
|
+
if (enableInline) {
|
|
110
|
+
if (highlightedValue == null) {
|
|
111
|
+
setInlineInputValue('');
|
|
112
|
+
} else {
|
|
113
|
+
setInlineInputValue(useCompositeListItem.stringifyAsLabel(highlightedValue, itemToStringValue));
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
setInlineInputValue('');
|
|
117
|
+
}
|
|
111
118
|
}
|
|
112
|
-
return /*#__PURE__*/jsxRuntime.jsx(
|
|
119
|
+
return /*#__PURE__*/jsxRuntime.jsx(ComboboxChipRemove.AriaCombobox, {
|
|
113
120
|
...other,
|
|
114
121
|
itemToStringLabel: itemToStringValue,
|
|
115
122
|
openOnInputClick: openOnInputClick,
|
|
@@ -128,7 +135,7 @@ function AutocompleteValue(props) {
|
|
|
128
135
|
const {
|
|
129
136
|
children
|
|
130
137
|
} = props;
|
|
131
|
-
const inputValue =
|
|
138
|
+
const inputValue = ComboboxChipRemove.useComboboxInputValueContext();
|
|
132
139
|
let returnValue = null;
|
|
133
140
|
if (typeof children === 'function') {
|
|
134
141
|
returnValue = children(String(inputValue));
|
|
@@ -148,7 +155,7 @@ function AutocompleteValue(props) {
|
|
|
148
155
|
*
|
|
149
156
|
* Documentation: [Base UI Autocomplete](https://base-ui.com/react/components/autocomplete)
|
|
150
157
|
*/
|
|
151
|
-
const AutocompleteTrigger =
|
|
158
|
+
const AutocompleteTrigger = ComboboxChipRemove.ComboboxTrigger;
|
|
152
159
|
|
|
153
160
|
/**
|
|
154
161
|
* A wrapper for the input and its associated controls.
|
|
@@ -156,7 +163,7 @@ const AutocompleteTrigger = ComboboxSeparator.ComboboxTrigger;
|
|
|
156
163
|
*
|
|
157
164
|
* Documentation: [Base UI Autocomplete](https://base-ui.com/react/components/autocomplete)
|
|
158
165
|
*/
|
|
159
|
-
const AutocompleteInputGroup =
|
|
166
|
+
const AutocompleteInputGroup = ComboboxChipRemove.ComboboxInputGroup;
|
|
160
167
|
|
|
161
168
|
/**
|
|
162
169
|
* An individual item in the list.
|
|
@@ -164,41 +171,33 @@ const AutocompleteInputGroup = ComboboxSeparator.ComboboxInputGroup;
|
|
|
164
171
|
*
|
|
165
172
|
* Documentation: [Base UI Autocomplete](https://base-ui.com/react/components/autocomplete)
|
|
166
173
|
*/
|
|
167
|
-
const AutocompleteItem =
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* A visual separator between items or groups.
|
|
171
|
-
* Renders a `<div>` element.
|
|
172
|
-
*
|
|
173
|
-
* Documentation: [Base UI Autocomplete](https://base-ui.com/react/components/autocomplete)
|
|
174
|
-
*/
|
|
175
|
-
const AutocompleteSeparator = ComboboxSeparator.ListboxSeparator;
|
|
174
|
+
const AutocompleteItem = ComboboxChipRemove.ComboboxItem;
|
|
176
175
|
|
|
177
176
|
var index_parts$7 = /*#__PURE__*/Object.freeze({
|
|
178
177
|
__proto__: null,
|
|
179
|
-
Arrow:
|
|
180
|
-
Backdrop:
|
|
181
|
-
Clear:
|
|
182
|
-
Collection:
|
|
183
|
-
Empty:
|
|
184
|
-
Group:
|
|
185
|
-
GroupLabel:
|
|
186
|
-
Icon:
|
|
187
|
-
Input:
|
|
178
|
+
Arrow: ComboboxChipRemove.ComboboxArrow,
|
|
179
|
+
Backdrop: ComboboxChipRemove.ComboboxBackdrop,
|
|
180
|
+
Clear: ComboboxChipRemove.ComboboxClear,
|
|
181
|
+
Collection: ComboboxChipRemove.ComboboxCollection,
|
|
182
|
+
Empty: ComboboxChipRemove.ComboboxEmpty,
|
|
183
|
+
Group: ComboboxChipRemove.ComboboxGroup,
|
|
184
|
+
GroupLabel: ComboboxChipRemove.ComboboxGroupLabel,
|
|
185
|
+
Icon: ComboboxChipRemove.ComboboxIcon,
|
|
186
|
+
Input: ComboboxChipRemove.ComboboxInput,
|
|
188
187
|
InputGroup: AutocompleteInputGroup,
|
|
189
188
|
Item: AutocompleteItem,
|
|
190
|
-
List:
|
|
191
|
-
Popup:
|
|
192
|
-
Portal:
|
|
193
|
-
Positioner:
|
|
189
|
+
List: ComboboxChipRemove.ComboboxList,
|
|
190
|
+
Popup: ComboboxChipRemove.ComboboxPopup,
|
|
191
|
+
Portal: ComboboxChipRemove.ComboboxPortal,
|
|
192
|
+
Positioner: ComboboxChipRemove.ComboboxPositioner,
|
|
194
193
|
Root: AutocompleteRoot,
|
|
195
|
-
Row:
|
|
196
|
-
Separator:
|
|
197
|
-
Status:
|
|
194
|
+
Row: ComboboxChipRemove.ComboboxRow,
|
|
195
|
+
Separator: Separator.Separator,
|
|
196
|
+
Status: ComboboxChipRemove.ComboboxStatus,
|
|
198
197
|
Trigger: AutocompleteTrigger,
|
|
199
198
|
Value: AutocompleteValue,
|
|
200
|
-
useFilter:
|
|
201
|
-
useFilteredItems:
|
|
199
|
+
useFilter: ComboboxChipRemove.useCoreFilter,
|
|
200
|
+
useFilteredItems: ComboboxChipRemove.useFilteredItems
|
|
202
201
|
});
|
|
203
202
|
|
|
204
203
|
var index_parts$6 = /*#__PURE__*/Object.freeze({
|
|
@@ -209,14 +208,14 @@ var index_parts$6 = /*#__PURE__*/Object.freeze({
|
|
|
209
208
|
Handle: DrawerDescription.DialogHandle,
|
|
210
209
|
Popup: DrawerDescription.DialogPopup,
|
|
211
210
|
Portal: ScrollAreaViewport.DialogPortal,
|
|
212
|
-
Root:
|
|
211
|
+
Root: ScrollAreaViewport.DialogRoot,
|
|
213
212
|
Title: DrawerTitle.DialogTitle,
|
|
214
213
|
Trigger: ScrollAreaViewport.DialogTrigger,
|
|
215
214
|
Viewport: ScrollAreaViewport.DialogViewport,
|
|
216
215
|
createHandle: DrawerDescription.createDialogHandle
|
|
217
216
|
});
|
|
218
217
|
|
|
219
|
-
const stateAttributesMapping$
|
|
218
|
+
const stateAttributesMapping$5 = {
|
|
220
219
|
active(value) {
|
|
221
220
|
if (value) {
|
|
222
221
|
return {
|
|
@@ -287,12 +286,12 @@ const DrawerIndent = /*#__PURE__*/React__namespace.forwardRef(function DrawerInd
|
|
|
287
286
|
[ScrollAreaViewport.DrawerBackdropCssVars.swipeProgress]: '0'
|
|
288
287
|
}
|
|
289
288
|
}, elementProps],
|
|
290
|
-
stateAttributesMapping: stateAttributesMapping$
|
|
289
|
+
stateAttributesMapping: stateAttributesMapping$5
|
|
291
290
|
});
|
|
292
291
|
});
|
|
293
292
|
if (process.env.NODE_ENV !== "production") DrawerIndent.displayName = "DrawerIndent";
|
|
294
293
|
|
|
295
|
-
const stateAttributesMapping$
|
|
294
|
+
const stateAttributesMapping$4 = {
|
|
296
295
|
active(value) {
|
|
297
296
|
if (value) {
|
|
298
297
|
return {
|
|
@@ -327,7 +326,7 @@ const DrawerIndentBackground = /*#__PURE__*/React__namespace.forwardRef(function
|
|
|
327
326
|
ref: forwardedRef,
|
|
328
327
|
state,
|
|
329
328
|
props: elementProps,
|
|
330
|
-
stateAttributesMapping: stateAttributesMapping$
|
|
329
|
+
stateAttributesMapping: stateAttributesMapping$4
|
|
331
330
|
});
|
|
332
331
|
});
|
|
333
332
|
if (process.env.NODE_ENV !== "production") DrawerIndentBackground.displayName = "DrawerIndentBackground";
|
|
@@ -336,26 +335,37 @@ function DrawerProvider(props) {
|
|
|
336
335
|
const {
|
|
337
336
|
children
|
|
338
337
|
} = props;
|
|
339
|
-
const [
|
|
338
|
+
const [openById, setOpenById] = React__namespace.useState(() => new Map());
|
|
340
339
|
const [visualStateStore] = React__namespace.useState(createVisualStateStore);
|
|
341
|
-
const setDrawerOpen = useScrollLock.useStableCallback((
|
|
342
|
-
|
|
343
|
-
|
|
340
|
+
const setDrawerOpen = useScrollLock.useStableCallback((drawerId, open) => {
|
|
341
|
+
setOpenById(prev => {
|
|
342
|
+
const prevOpen = prev.get(drawerId);
|
|
343
|
+
if (prevOpen === open) {
|
|
344
344
|
return prev;
|
|
345
345
|
}
|
|
346
|
-
const next = new
|
|
347
|
-
|
|
348
|
-
next.add(drawer);
|
|
349
|
-
} else {
|
|
350
|
-
next.delete(drawer);
|
|
351
|
-
}
|
|
346
|
+
const next = new Map(prev);
|
|
347
|
+
next.set(drawerId, open);
|
|
352
348
|
return next;
|
|
353
349
|
});
|
|
354
350
|
});
|
|
355
|
-
const removeDrawer = useScrollLock.useStableCallback(
|
|
356
|
-
|
|
351
|
+
const removeDrawer = useScrollLock.useStableCallback(drawerId => {
|
|
352
|
+
setOpenById(prev => {
|
|
353
|
+
if (!prev.has(drawerId)) {
|
|
354
|
+
return prev;
|
|
355
|
+
}
|
|
356
|
+
const next = new Map(prev);
|
|
357
|
+
next.delete(drawerId);
|
|
358
|
+
return next;
|
|
359
|
+
});
|
|
357
360
|
});
|
|
358
|
-
const active =
|
|
361
|
+
const active = React__namespace.useMemo(() => {
|
|
362
|
+
for (const open of openById.values()) {
|
|
363
|
+
if (open) {
|
|
364
|
+
return true;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return false;
|
|
368
|
+
}, [openById]);
|
|
359
369
|
const contextValue = React__namespace.useMemo(() => ({
|
|
360
370
|
setDrawerOpen,
|
|
361
371
|
removeDrawer,
|
|
@@ -445,7 +455,7 @@ const SWIPE_AREA_SWIPING_HOOK = {
|
|
|
445
455
|
const SWIPE_AREA_DISABLED_HOOK = {
|
|
446
456
|
[DrawerSwipeAreaDataAttributes.disabled]: ''
|
|
447
457
|
};
|
|
448
|
-
const stateAttributesMapping$
|
|
458
|
+
const stateAttributesMapping$3 = {
|
|
449
459
|
open(value) {
|
|
450
460
|
return value ? SWIPE_AREA_OPEN_HOOK : SWIPE_AREA_CLOSED_HOOK;
|
|
451
461
|
},
|
|
@@ -453,9 +463,9 @@ const stateAttributesMapping$1 = {
|
|
|
453
463
|
return value ? SWIPE_AREA_SWIPING_HOOK : null;
|
|
454
464
|
},
|
|
455
465
|
swipeDirection(value) {
|
|
456
|
-
return {
|
|
466
|
+
return value ? {
|
|
457
467
|
[DrawerSwipeAreaDataAttributes.swipeDirection]: value
|
|
458
|
-
};
|
|
468
|
+
} : null;
|
|
459
469
|
},
|
|
460
470
|
disabled(value) {
|
|
461
471
|
return value ? SWIPE_AREA_DISABLED_HOOK : null;
|
|
@@ -486,14 +496,16 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
486
496
|
swipeDirection: swipeDirectionProp,
|
|
487
497
|
...elementProps
|
|
488
498
|
} = componentProps;
|
|
489
|
-
const
|
|
499
|
+
const {
|
|
500
|
+
store
|
|
501
|
+
} = ScrollAreaViewport.useDialogRootContext();
|
|
490
502
|
const {
|
|
491
503
|
swipeDirection,
|
|
492
|
-
frontmostHeight
|
|
493
|
-
swipeAreaActiveRef
|
|
504
|
+
frontmostHeight
|
|
494
505
|
} = ScrollAreaViewport.useDrawerRootContext();
|
|
495
506
|
const providerContext = ScrollAreaViewport.useDrawerProviderContext();
|
|
496
507
|
const [swipeActive, setSwipeActive] = React__namespace.useState(false);
|
|
508
|
+
const releaseDismissTimeout = useScrollLock.useTimeout();
|
|
497
509
|
const swipeAreaRef = React__namespace.useRef(null);
|
|
498
510
|
const swipeStartEventRef = React__namespace.useRef(null);
|
|
499
511
|
const openedBySwipeRef = React__namespace.useRef(false);
|
|
@@ -503,10 +515,7 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
503
515
|
});
|
|
504
516
|
const closedOffsetRef = React__namespace.useRef(null);
|
|
505
517
|
const appliedSwipeStylesRef = React__namespace.useRef(false);
|
|
506
|
-
const swipePopupElementRef = React__namespace.useRef(null);
|
|
507
|
-
const swipeBackdropElementRef = React__namespace.useRef(null);
|
|
508
518
|
const popupTransitionRef = React__namespace.useRef(null);
|
|
509
|
-
const releaseGuardCleanupRef = React__namespace.useRef(useRenderElement.NOOP);
|
|
510
519
|
const swipeAreaId = useScrollLock.useBaseUiId(componentProps.id);
|
|
511
520
|
const registerTrigger = useScrollLock.useTriggerRegistration(swipeAreaId, store);
|
|
512
521
|
const open = store.useState('open');
|
|
@@ -518,40 +527,21 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
518
527
|
const dismissDirection = oppositeSwipeDirection[resolvedSwipeDirection];
|
|
519
528
|
const enabled = !disabled && (!open || swipeActive);
|
|
520
529
|
function disableDismissForSwipe() {
|
|
521
|
-
|
|
530
|
+
releaseDismissTimeout.clear();
|
|
522
531
|
store.context.outsidePressEnabledRef.current = false;
|
|
523
532
|
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
// The gesture's trailing release click is the one physical click with no `pointerdown` of
|
|
529
|
-
// its own. Ignore it and keep waiting, so it cannot dismiss the drawer it just opened,
|
|
530
|
-
// while a click-only activation (keyboard or assistive tech) still re-enables in time.
|
|
531
|
-
if (event?.type === 'click' && event.detail !== 0 && !useScrollLock.isVirtualClick(event)) {
|
|
532
|
-
return;
|
|
533
|
-
}
|
|
534
|
-
releaseGuardCleanupRef.current = useRenderElement.NOOP;
|
|
535
|
-
doc.removeEventListener('pointerdown', restore, true);
|
|
536
|
-
doc.removeEventListener('click', restore, true);
|
|
533
|
+
function enableDismissAfterRelease() {
|
|
534
|
+
// Safari can dispatch outside-press for the same swipe-open gesture
|
|
535
|
+
// after release, so defer re-enabling dismissal to the next macrotask.
|
|
536
|
+
releaseDismissTimeout.start(0, () => {
|
|
537
537
|
store.context.outsidePressEnabledRef.current = true;
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
function resolvePopupSize() {
|
|
541
|
+
const popupElement = store.context.popupRef.current;
|
|
542
|
+
if (!popupElement) {
|
|
543
|
+
return null;
|
|
538
544
|
}
|
|
539
|
-
|
|
540
|
-
// The pointerup that ends a swipe-open gesture synthesizes a `click`. When the drag released
|
|
541
|
-
// outside the popup (e.g. it was dragged past the popup's size), that click would be treated as
|
|
542
|
-
// an outside press and immediately dismiss the drawer that was just opened. Keep outside-press
|
|
543
|
-
// dismissal disabled until the next interaction that isn't that release click: a deliberate
|
|
544
|
-
// outside press starts with a `pointerdown`, and a click-only activation (keyboard or
|
|
545
|
-
// assistive tech) is distinguishable from a physical release. This is deterministic, unlike
|
|
546
|
-
// re-enabling on a timer that can race the synthesized click and dismiss at random.
|
|
547
|
-
//
|
|
548
|
-
// `restore` runs in document capture, ahead of floating-ui's own outside-press check (which
|
|
549
|
-
// happens on the event target, after capture), so the triggering press still dismisses.
|
|
550
|
-
releaseGuardCleanupRef.current = restore;
|
|
551
|
-
doc.addEventListener('pointerdown', restore, true);
|
|
552
|
-
doc.addEventListener('click', restore, true);
|
|
553
|
-
});
|
|
554
|
-
function getPopupSize(popupElement) {
|
|
555
545
|
const isHorizontal = dismissDirection === 'left' || dismissDirection === 'right';
|
|
556
546
|
const size = isHorizontal ? popupElement.offsetWidth : popupElement.offsetHeight;
|
|
557
547
|
if (size <= 0) {
|
|
@@ -559,15 +549,15 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
559
549
|
}
|
|
560
550
|
return size;
|
|
561
551
|
}
|
|
562
|
-
function
|
|
563
|
-
const
|
|
564
|
-
return popupElement ? getPopupSize(popupElement) : null;
|
|
565
|
-
}
|
|
566
|
-
function resolveClosedOffset(popupElement) {
|
|
567
|
-
const offset = getPopupSize(popupElement);
|
|
552
|
+
function resolveClosedOffset() {
|
|
553
|
+
const offset = resolvePopupSize();
|
|
568
554
|
if (offset == null) {
|
|
569
555
|
return null;
|
|
570
556
|
}
|
|
557
|
+
const popupElement = store.context.popupRef.current;
|
|
558
|
+
if (!popupElement) {
|
|
559
|
+
return offset;
|
|
560
|
+
}
|
|
571
561
|
const isHorizontal = dismissDirection === 'left' || dismissDirection === 'right';
|
|
572
562
|
const transform = ScrollAreaViewport.getElementTransform(popupElement);
|
|
573
563
|
const transformOffset = isHorizontal ? transform.x : transform.y;
|
|
@@ -584,6 +574,9 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
584
574
|
return popupSize * DEFAULT_SWIPE_OPEN_RATIO;
|
|
585
575
|
}
|
|
586
576
|
function applySwipeMovement() {
|
|
577
|
+
if (!swipeActive) {
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
587
580
|
const popupElement = store.context.popupRef.current;
|
|
588
581
|
if (!popupElement) {
|
|
589
582
|
return;
|
|
@@ -592,10 +585,10 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
592
585
|
return;
|
|
593
586
|
}
|
|
594
587
|
if (closedOffsetRef.current == null) {
|
|
595
|
-
closedOffsetRef.current = resolveClosedOffset(
|
|
588
|
+
closedOffsetRef.current = resolveClosedOffset();
|
|
596
589
|
}
|
|
597
590
|
const closedOffset = closedOffsetRef.current;
|
|
598
|
-
if (closedOffset
|
|
591
|
+
if (!closedOffset || !Number.isFinite(closedOffset) || closedOffset <= 0) {
|
|
599
592
|
return;
|
|
600
593
|
}
|
|
601
594
|
const {
|
|
@@ -616,7 +609,6 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
616
609
|
popupElement.style.setProperty(ScrollAreaViewport.DrawerPopupCssVars.swipeMovementX, `${movementX}px`);
|
|
617
610
|
popupElement.style.setProperty(ScrollAreaViewport.DrawerPopupCssVars.swipeMovementY, `${movementY}px`);
|
|
618
611
|
popupElement.setAttribute(ScrollAreaViewport.DrawerPopupDataAttributes.swiping, '');
|
|
619
|
-
swipePopupElementRef.current = popupElement;
|
|
620
612
|
if (popupTransitionRef.current === null) {
|
|
621
613
|
popupTransitionRef.current = popupElement.style.transition;
|
|
622
614
|
}
|
|
@@ -624,7 +616,6 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
624
616
|
const backdropElement = store.context.backdropRef.current;
|
|
625
617
|
if (backdropElement) {
|
|
626
618
|
backdropElement.setAttribute(ScrollAreaViewport.DrawerPopupDataAttributes.swiping, '');
|
|
627
|
-
swipeBackdropElementRef.current = backdropElement;
|
|
628
619
|
backdropElement.style.setProperty(ScrollAreaViewport.DrawerBackdropCssVars.swipeProgress, `${backdropProgress}`);
|
|
629
620
|
if (openProgress > 0 && frontmostHeight > 0) {
|
|
630
621
|
backdropElement.style.setProperty(ScrollAreaViewport.DrawerPopupCssVars.height, `${frontmostHeight}px`);
|
|
@@ -637,11 +628,10 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
637
628
|
frontmostHeight: openProgress > 0 ? frontmostHeight : 0
|
|
638
629
|
});
|
|
639
630
|
appliedSwipeStylesRef.current = true;
|
|
640
|
-
swipeAreaActiveRef.current = true;
|
|
641
631
|
}
|
|
642
632
|
const clearSwipeStyles = useScrollLock.useStableCallback(() => {
|
|
643
|
-
const popupElement =
|
|
644
|
-
if (popupElement) {
|
|
633
|
+
const popupElement = store.context.popupRef.current;
|
|
634
|
+
if (popupElement && appliedSwipeStylesRef.current) {
|
|
645
635
|
popupElement.style.removeProperty(ScrollAreaViewport.DrawerPopupCssVars.swipeMovementX);
|
|
646
636
|
popupElement.style.removeProperty(ScrollAreaViewport.DrawerPopupCssVars.swipeMovementY);
|
|
647
637
|
popupElement.removeAttribute(ScrollAreaViewport.DrawerPopupDataAttributes.swiping);
|
|
@@ -650,7 +640,7 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
650
640
|
popupElement.style.transition = popupTransitionRef.current;
|
|
651
641
|
popupTransitionRef.current = null;
|
|
652
642
|
}
|
|
653
|
-
const backdropElement =
|
|
643
|
+
const backdropElement = store.context.backdropRef.current;
|
|
654
644
|
if (backdropElement) {
|
|
655
645
|
backdropElement.removeAttribute(ScrollAreaViewport.DrawerPopupDataAttributes.swiping);
|
|
656
646
|
backdropElement.style.setProperty(ScrollAreaViewport.DrawerBackdropCssVars.swipeProgress, '0');
|
|
@@ -661,16 +651,19 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
661
651
|
frontmostHeight: 0
|
|
662
652
|
});
|
|
663
653
|
appliedSwipeStylesRef.current = false;
|
|
664
|
-
swipePopupElementRef.current = null;
|
|
665
|
-
swipeBackdropElementRef.current = null;
|
|
666
|
-
swipeAreaActiveRef.current = false;
|
|
667
654
|
});
|
|
668
655
|
function openDrawer(event) {
|
|
656
|
+
if (store.select('open')) {
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
669
659
|
openedBySwipeRef.current = true;
|
|
670
|
-
store.setOpen(true, useScrollLock.createChangeEventDetails(useScrollLock.swipe, event, swipeAreaRef.current));
|
|
660
|
+
store.setOpen(true, useScrollLock.createChangeEventDetails(useScrollLock.swipe, event, swipeAreaRef.current ?? undefined));
|
|
671
661
|
}
|
|
672
662
|
function closeDrawer(event) {
|
|
673
|
-
store.
|
|
663
|
+
if (!store.select('open')) {
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
store.setOpen(false, useScrollLock.createChangeEventDetails(useScrollLock.swipe, event, swipeAreaRef.current ?? undefined));
|
|
674
667
|
}
|
|
675
668
|
function resetSwipeInteractionState() {
|
|
676
669
|
swipeStartEventRef.current = null;
|
|
@@ -713,10 +706,10 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
713
706
|
return;
|
|
714
707
|
}
|
|
715
708
|
const displacement = ScrollAreaViewport.getDisplacement(resolvedSwipeDirection, details.deltaX, details.deltaY);
|
|
716
|
-
if (
|
|
709
|
+
if (displacement < MIN_SWIPE_START_DISTANCE && !openedBySwipeRef.current) {
|
|
717
710
|
return;
|
|
718
711
|
}
|
|
719
|
-
if (!openedBySwipeRef.current
|
|
712
|
+
if (!openedBySwipeRef.current) {
|
|
720
713
|
openDrawer(swipeStartEventRef.current);
|
|
721
714
|
}
|
|
722
715
|
applySwipeMovement();
|
|
@@ -732,14 +725,14 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
732
725
|
const displacement = ScrollAreaViewport.getDisplacement(resolvedSwipeDirection, deltaX, deltaY);
|
|
733
726
|
const releaseVelocity = ScrollAreaViewport.getDisplacement(resolvedSwipeDirection, releaseVelocityX, releaseVelocityY);
|
|
734
727
|
const threshold = resolveSwipeOpenThreshold();
|
|
735
|
-
const hasEnoughDistance = displacement >= threshold;
|
|
728
|
+
const hasEnoughDistance = threshold != null && displacement >= threshold;
|
|
736
729
|
const hasEnoughVelocity = releaseVelocity >= VELOCITY_THRESHOLD;
|
|
737
|
-
const shouldOpen = direction === resolvedSwipeDirection && (hasEnoughDistance || hasEnoughVelocity) && !disabled;
|
|
730
|
+
const shouldOpen = threshold != null && direction === resolvedSwipeDirection && (hasEnoughDistance || hasEnoughVelocity) && !disabled;
|
|
738
731
|
if (shouldOpen) {
|
|
739
732
|
if (!store.select('open')) {
|
|
740
733
|
openDrawer(event);
|
|
741
734
|
}
|
|
742
|
-
} else if (openedBySwipeRef.current
|
|
735
|
+
} else if (openedBySwipeRef.current) {
|
|
743
736
|
closeDrawer(event);
|
|
744
737
|
}
|
|
745
738
|
finishSwipeInteraction();
|
|
@@ -750,29 +743,16 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
750
743
|
const swipePointerProps = swipe.getPointerProps();
|
|
751
744
|
const swipeTouchProps = swipe.getTouchProps();
|
|
752
745
|
const resetSwipe = swipe.reset;
|
|
753
|
-
|
|
754
|
-
// The commit that opens the drawer re-renders the popup, resetting `--swipe-movement-*` to `0px`
|
|
755
|
-
// (the viewport isn't swiping). Re-assert after the DOM mutation but before paint. No deps: must
|
|
756
|
-
// run on every commit the swipe area participates in.
|
|
757
|
-
useScrollLock.useIsoLayoutEffect(() => {
|
|
758
|
-
if (swipeActive && appliedSwipeStylesRef.current) {
|
|
759
|
-
applySwipeMovement();
|
|
760
|
-
}
|
|
761
|
-
});
|
|
762
|
-
useScrollLock.useIsoLayoutEffect(() => {
|
|
746
|
+
React__namespace.useEffect(() => {
|
|
763
747
|
if (!enabled) {
|
|
764
|
-
if (swipeActive) {
|
|
765
|
-
enableDismissAfterRelease();
|
|
766
|
-
}
|
|
767
748
|
resetSwipe();
|
|
768
749
|
resetDragDelta();
|
|
769
750
|
clearSwipeStyles();
|
|
770
751
|
resetSwipeInteractionState();
|
|
771
752
|
}
|
|
772
|
-
}, [clearSwipeStyles,
|
|
753
|
+
}, [clearSwipeStyles, enabled, resetDragDelta, resetSwipe]);
|
|
773
754
|
React__namespace.useEffect(() => {
|
|
774
755
|
return () => {
|
|
775
|
-
releaseGuardCleanupRef.current();
|
|
776
756
|
store.context.outsidePressEnabledRef.current = true;
|
|
777
757
|
};
|
|
778
758
|
}, [store]);
|
|
@@ -785,7 +765,7 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
785
765
|
return useRenderElement.useRenderElement('div', componentProps, {
|
|
786
766
|
state,
|
|
787
767
|
ref: [forwardedRef, swipeAreaRef, registerTrigger],
|
|
788
|
-
stateAttributesMapping: stateAttributesMapping$
|
|
768
|
+
stateAttributesMapping: stateAttributesMapping$3,
|
|
789
769
|
props: [{
|
|
790
770
|
role: 'presentation',
|
|
791
771
|
'aria-hidden': true,
|
|
@@ -845,15 +825,6 @@ const KEYBOARD_VISIBILITY_MARGIN = 16;
|
|
|
845
825
|
// keyboard overlap, so the field can be scrolled clear of the keyboard instead of
|
|
846
826
|
// ending up flush against it. Only applied when there is actual overlap.
|
|
847
827
|
const KEYBOARD_SCROLL_SLACK = 48;
|
|
848
|
-
// Cadence of the settle-watching realign passes after focus moves with the keyboard open:
|
|
849
|
-
// long enough for a smooth scroll to show progress between passes, short enough to recover
|
|
850
|
-
// quickly from a scroll canceled by WebKit's reveal; the pass count covers CSS transitions
|
|
851
|
-
// reacting to the focus change (e.g. a 260ms footer resize) with room to spare.
|
|
852
|
-
const KEYBOARD_REALIGN_INTERVAL = 150;
|
|
853
|
-
const KEYBOARD_REALIGN_MAX_PASSES = 4;
|
|
854
|
-
// Frames the alignment waits for the scroll destination to stop moving (layout reacting to
|
|
855
|
-
// the focus change, e.g. a footer resizing over a CSS transition) before scrolling anyway.
|
|
856
|
-
const KEYBOARD_SETTLE_FRAME_LIMIT = 60;
|
|
857
828
|
const INPUT_TAP_MOVE_THRESHOLD = 10;
|
|
858
829
|
const INPUT_TAP_HIT_SLOP = 16;
|
|
859
830
|
const KEYBOARD_INPUT_TYPES = new Set(['email', 'number', 'password', 'search', 'tel', 'text', 'url']);
|
|
@@ -877,10 +848,11 @@ function DrawerVirtualKeyboardProvider(props) {
|
|
|
877
848
|
const {
|
|
878
849
|
children
|
|
879
850
|
} = props;
|
|
880
|
-
const
|
|
851
|
+
const {
|
|
852
|
+
store
|
|
853
|
+
} = ScrollAreaViewport.useDialogRootContext();
|
|
881
854
|
const open = store.useState('open');
|
|
882
855
|
const mounted = store.useState('mounted');
|
|
883
|
-
const modal = store.useState('modal');
|
|
884
856
|
const nestedOpenDialogCount = store.useState('nestedOpenDialogCount');
|
|
885
857
|
const viewportElement = store.useState('viewportElement');
|
|
886
858
|
|
|
@@ -893,9 +865,7 @@ function DrawerVirtualKeyboardProvider(props) {
|
|
|
893
865
|
const keyboardTouchStartRef = React__namespace.useRef(null);
|
|
894
866
|
const focusedKeyboardTargetRef = React__namespace.useRef(null);
|
|
895
867
|
const keyboardScrollAdjustmentRef = React__namespace.useRef(null);
|
|
896
|
-
const programmaticKeyboardFocusRef = React__namespace.useRef(false);
|
|
897
868
|
const keyboardFocusFrame = useScrollLock.useAnimationFrame();
|
|
898
|
-
const keyboardRealignTimeout = useScrollLock.useTimeout();
|
|
899
869
|
const restoreKeyboardScrollAdjustment = useScrollLock.useStableCallback(() => {
|
|
900
870
|
const adjustment = keyboardScrollAdjustmentRef.current;
|
|
901
871
|
if (!adjustment) {
|
|
@@ -922,7 +892,7 @@ function DrawerVirtualKeyboardProvider(props) {
|
|
|
922
892
|
adjustment = null;
|
|
923
893
|
}
|
|
924
894
|
if (!adjustment) {
|
|
925
|
-
const styles =
|
|
895
|
+
const styles = floatingUi_utils.getComputedStyle(element);
|
|
926
896
|
adjustment = {
|
|
927
897
|
element,
|
|
928
898
|
overflowAnchor: element.style.overflowAnchor,
|
|
@@ -938,7 +908,7 @@ function DrawerVirtualKeyboardProvider(props) {
|
|
|
938
908
|
element.style.scrollPaddingBottom = `${adjustment.computedScrollPaddingBottom + KEYBOARD_VISIBILITY_MARGIN}px`;
|
|
939
909
|
});
|
|
940
910
|
const animateKeyboardScroll = useScrollLock.useStableCallback((element, scrollTop) => {
|
|
941
|
-
const win =
|
|
911
|
+
const win = floatingUi_utils.getWindow(element);
|
|
942
912
|
const behavior = win.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches ? 'auto' : 'smooth';
|
|
943
913
|
element.scrollTo({
|
|
944
914
|
top: scrollTop,
|
|
@@ -961,102 +931,48 @@ function DrawerVirtualKeyboardProvider(props) {
|
|
|
961
931
|
return undefined;
|
|
962
932
|
}
|
|
963
933
|
const doc = useScrollLock.ownerDocument(rootElement);
|
|
964
|
-
const win =
|
|
934
|
+
const win = floatingUi_utils.getWindow(rootElement);
|
|
965
935
|
const visualViewport = win.visualViewport;
|
|
966
|
-
|
|
967
|
-
// Alignment scroll bookkeeping: destination stability, whether a scroll was issued,
|
|
968
|
-
// and the last observed progress so delayed passes can distinguish moving from stalled.
|
|
969
|
-
let keyboardScrollElement = null;
|
|
970
|
-
let keyboardScrollDestination = 0;
|
|
971
|
-
let keyboardScrollChecks = 0;
|
|
972
|
-
let keyboardScrollObserved = -1;
|
|
973
936
|
const setDrawerKeyboardInset = inset => {
|
|
974
937
|
rootElement.style.setProperty(DrawerViewportCssVars.keyboardInset, `${Math.max(0, Math.ceil(inset))}px`);
|
|
975
938
|
};
|
|
939
|
+
const resetDrawerKeyboardInset = () => {
|
|
940
|
+
setDrawerKeyboardInset(0);
|
|
941
|
+
};
|
|
976
942
|
const clearFocusedKeyboardTarget = () => {
|
|
977
943
|
focusedKeyboardTargetRef.current = null;
|
|
978
|
-
|
|
979
|
-
setDrawerKeyboardInset(0);
|
|
944
|
+
resetDrawerKeyboardInset();
|
|
980
945
|
restoreKeyboardScrollAdjustment();
|
|
981
946
|
keyboardFocusFrame.cancel();
|
|
982
|
-
keyboardRealignTimeout.clear();
|
|
983
|
-
};
|
|
984
|
-
|
|
985
|
-
// WebKit's native reveal scroll can move the page even while the scroll lock hides
|
|
986
|
-
// overflow (e.g. when the software keyboard's previous/next field arrows move focus).
|
|
987
|
-
// While the drawer is modal, any window scroll during keyboard interaction is spurious,
|
|
988
|
-
// so pin the page to the position it had when the drawer opened.
|
|
989
|
-
const baseScrollX = win.scrollX;
|
|
990
|
-
const baseScrollY = win.scrollY;
|
|
991
|
-
const restoreWindowScroll = () => {
|
|
992
|
-
if (modal !== true || nestedDrawerOpen || !focusedKeyboardTargetRef.current || getKeyboardVisualViewport(win) == null) {
|
|
993
|
-
return false;
|
|
994
|
-
}
|
|
995
|
-
if (win.scrollX !== baseScrollX || win.scrollY !== baseScrollY) {
|
|
996
|
-
// Force an instant jump: the two-argument form defaults `behavior` to `auto`, which
|
|
997
|
-
// obeys the page's `scroll-behavior`, so a global `scroll-behavior: smooth` would
|
|
998
|
-
// animate the restore. The measurements that follow assume the page is already back
|
|
999
|
-
// at rest, and a smooth restore also re-emits `scroll`, re-entering this handler.
|
|
1000
|
-
win.scrollTo({
|
|
1001
|
-
left: baseScrollX,
|
|
1002
|
-
top: baseScrollY,
|
|
1003
|
-
behavior: 'instant'
|
|
1004
|
-
});
|
|
1005
|
-
return true;
|
|
1006
|
-
}
|
|
1007
|
-
return false;
|
|
1008
|
-
};
|
|
1009
|
-
|
|
1010
|
-
// Focus moved by the drawer itself goes through `focusKeyboardInputWithoutPageScroll`,
|
|
1011
|
-
// but native focus changes (the iOS keyboard's previous/next field arrows) commit
|
|
1012
|
-
// WebKit's reveal scroll before `focusin` reaches us — cancelling it afterwards
|
|
1013
|
-
// visibly jitters the sheet. `focusout` on the outgoing field fires before focus
|
|
1014
|
-
// lands, so override the incoming field's geometry there and restore it in `focusin`.
|
|
1015
|
-
let restorePreemptedFocus = null;
|
|
1016
|
-
const consumePreemptedFocus = () => {
|
|
1017
|
-
restorePreemptedFocus?.();
|
|
1018
|
-
restorePreemptedFocus = null;
|
|
1019
|
-
};
|
|
1020
|
-
const preemptFocusReveal = (target, keyboardViewport) => {
|
|
1021
|
-
consumePreemptedFocus();
|
|
1022
|
-
|
|
1023
|
-
// Native focus carries no preventScroll, so a fake off-screen rect would make WebKit
|
|
1024
|
-
// scroll the drawer's own scroll containers thousands of pixels chasing it. Presenting
|
|
1025
|
-
// the field as already centered in the visible band above the keyboard instead makes
|
|
1026
|
-
// both the in-page reveal and the viewport pan no-ops.
|
|
1027
|
-
const rect = target.getBoundingClientRect();
|
|
1028
|
-
restorePreemptedFocus = overrideGeometryDuringFocus(target, (keyboardViewport.top + keyboardViewport.bottom - rect.top - rect.bottom) / 2);
|
|
1029
947
|
};
|
|
1030
948
|
const alignFocusedKeyboardTarget = () => {
|
|
1031
|
-
// If focus never lands on a preempted target, the focusout-scheduled alignment still
|
|
1032
|
-
// restores it on the next frame before paint.
|
|
1033
|
-
consumePreemptedFocus();
|
|
1034
949
|
const target = focusedKeyboardTargetRef.current;
|
|
1035
950
|
// If the focused field is removed from the DOM without firing `focusout` (e.g. it is
|
|
1036
951
|
// conditionally rendered away), any applied scroll slack is restored here on the next
|
|
1037
952
|
// focus/viewport event or when the drawer closes. This self-corrects rather than
|
|
1038
953
|
// tracking each field's lifecycle.
|
|
1039
954
|
if (nestedDrawerOpen || !target || !useScrollLock.contains(rootElement, target)) {
|
|
1040
|
-
|
|
955
|
+
resetDrawerKeyboardInset();
|
|
1041
956
|
restoreKeyboardScrollAdjustment();
|
|
1042
957
|
return;
|
|
1043
958
|
}
|
|
1044
|
-
|
|
1045
|
-
// Undo any reveal scroll WebKit applied to the locked page before measuring, so the
|
|
1046
|
-
// keyboard inset and alignment are computed against the resting viewport.
|
|
1047
|
-
restoreWindowScroll();
|
|
1048
959
|
const keyboardViewport = getKeyboardVisualViewport(win);
|
|
1049
960
|
if (!keyboardViewport) {
|
|
1050
|
-
|
|
961
|
+
resetDrawerKeyboardInset();
|
|
1051
962
|
restoreKeyboardScrollAdjustment();
|
|
1052
963
|
return;
|
|
1053
964
|
}
|
|
1054
|
-
setDrawerKeyboardInset(
|
|
965
|
+
setDrawerKeyboardInset(getDrawerKeyboardInset(win, keyboardViewport));
|
|
1055
966
|
const scrollTarget = findKeyboardScrollTarget(target, rootElement);
|
|
1056
967
|
if (!scrollTarget) {
|
|
1057
968
|
restoreKeyboardScrollAdjustment();
|
|
1058
969
|
return;
|
|
1059
970
|
}
|
|
971
|
+
if (!scrollTarget.isConnected || !useScrollLock.contains(rootElement, scrollTarget)) {
|
|
972
|
+
resetDrawerKeyboardInset();
|
|
973
|
+
restoreKeyboardScrollAdjustment();
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
1060
976
|
const scrollTargetRect = scrollTarget.getBoundingClientRect();
|
|
1061
977
|
const clippedBottom = Math.min(scrollTargetRect.bottom, keyboardViewport.bottom);
|
|
1062
978
|
const overlap = Math.max(0, scrollTargetRect.bottom - keyboardViewport.bottom);
|
|
@@ -1072,70 +988,14 @@ function DrawerVirtualKeyboardProvider(props) {
|
|
|
1072
988
|
return;
|
|
1073
989
|
}
|
|
1074
990
|
const targetRect = target.getBoundingClientRect();
|
|
1075
|
-
const
|
|
1076
|
-
const
|
|
1077
|
-
const
|
|
1078
|
-
|
|
1079
|
-
// Commit the scroll only once the destination holds across two consecutive checks.
|
|
1080
|
-
// Layout may still be reacting to the focus change (e.g. a footer sized by
|
|
1081
|
-
// `:focus-within` resizing over a transition), and scrolling toward a
|
|
1082
|
-
// mid-transition destination overshoots, then visibly pulls back once corrected.
|
|
1083
|
-
// The destination is scroll-position-invariant, so an in-flight scroll of the
|
|
1084
|
-
// container itself never defers the commit.
|
|
1085
|
-
const checks = keyboardScrollElement === scrollTarget ? keyboardScrollChecks + 1 : 1;
|
|
1086
|
-
keyboardScrollElement = scrollTarget;
|
|
1087
|
-
keyboardScrollDestination = destination;
|
|
1088
|
-
keyboardScrollChecks = checks;
|
|
1089
|
-
keyboardScrollObserved = -1;
|
|
1090
|
-
// Re-check next frame; give up and scroll anyway if layout never settles.
|
|
1091
|
-
if (checks <= KEYBOARD_SETTLE_FRAME_LIMIT) {
|
|
1092
|
-
keyboardFocusFrame.request(alignFocusedKeyboardTarget);
|
|
1093
|
-
return;
|
|
1094
|
-
}
|
|
1095
|
-
} else if (keyboardScrollObserved >= 0) {
|
|
1096
|
-
// A scroll toward this destination is already out. Leave it alone while it has
|
|
1097
|
-
// arrived or is still progressing — re-issuing restarts the smooth-scroll easing
|
|
1098
|
-
// curve, a visible stutter on every realign pass — and re-issue only when it
|
|
1099
|
-
// stalled short (WebKit cancels in-flight smooth scrolls when its native reveal
|
|
1100
|
-
// for the focus resolves).
|
|
1101
|
-
const current = scrollTarget.scrollTop;
|
|
1102
|
-
if (Math.abs(current - destination) <= 1) {
|
|
1103
|
-
return;
|
|
1104
|
-
}
|
|
1105
|
-
if (current !== keyboardScrollObserved) {
|
|
1106
|
-
keyboardScrollObserved = current;
|
|
1107
|
-
return;
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
keyboardScrollElement = scrollTarget;
|
|
1111
|
-
keyboardScrollDestination = destination;
|
|
1112
|
-
keyboardScrollChecks = 0;
|
|
1113
|
-
keyboardScrollObserved = scrollTarget.scrollTop;
|
|
1114
|
-
animateKeyboardScroll(scrollTarget, destination);
|
|
991
|
+
const targetCenter = (targetRect.top + targetRect.bottom) / 2;
|
|
992
|
+
const visibleCenter = (visibleTop + visibleBottom) / 2;
|
|
993
|
+
const nextScrollTop = scrollTarget.scrollTop + targetCenter - visibleCenter;
|
|
994
|
+
animateKeyboardScroll(scrollTarget, scrollEdges.clamp(nextScrollTop, 0, maxScrollTop));
|
|
1115
995
|
};
|
|
1116
996
|
const scheduleKeyboardFocusAlignment = () => {
|
|
1117
997
|
keyboardFocusFrame.request(alignFocusedKeyboardTarget);
|
|
1118
998
|
};
|
|
1119
|
-
|
|
1120
|
-
// When focus moves with the keyboard already up, no viewport resize events follow to
|
|
1121
|
-
// re-run alignment, and the single frame-scheduled pass is unreliable: WebKit resolves
|
|
1122
|
-
// the reveal for the focus asynchronously (a UI-process round trip) and cancels any
|
|
1123
|
-
// in-flight scroll the pass started when it lands, and layout reacting to the focus
|
|
1124
|
-
// change (e.g. a footer sized by `:focus-within` and the keyboard inset) settles only
|
|
1125
|
-
// after its transition, so the pass measures stale geometry. Re-align on an interval
|
|
1126
|
-
// until both settle; the alignment's scroll bookkeeping observes before re-issuing,
|
|
1127
|
-
// so passes that find the scroll on course are inert.
|
|
1128
|
-
const scheduleDelayedKeyboardRealign = () => {
|
|
1129
|
-
let remainingPasses = KEYBOARD_REALIGN_MAX_PASSES;
|
|
1130
|
-
const realign = () => {
|
|
1131
|
-
alignFocusedKeyboardTarget();
|
|
1132
|
-
remainingPasses -= 1;
|
|
1133
|
-
if (remainingPasses > 0) {
|
|
1134
|
-
keyboardRealignTimeout.start(KEYBOARD_REALIGN_INTERVAL, realign);
|
|
1135
|
-
}
|
|
1136
|
-
};
|
|
1137
|
-
keyboardRealignTimeout.start(KEYBOARD_REALIGN_INTERVAL, realign);
|
|
1138
|
-
};
|
|
1139
999
|
const captureFocusedKeyboardTarget = eventTarget => {
|
|
1140
1000
|
if (nestedDrawerOpen) {
|
|
1141
1001
|
return false;
|
|
@@ -1147,56 +1007,16 @@ function DrawerVirtualKeyboardProvider(props) {
|
|
|
1147
1007
|
if (!target || !useScrollLock.contains(rootElement, target)) {
|
|
1148
1008
|
return false;
|
|
1149
1009
|
}
|
|
1150
|
-
|
|
1151
|
-
// A new field starts a fresh alignment; the scroll bookkeeping must not carry
|
|
1152
|
-
// over from the previous field's scroll.
|
|
1153
|
-
if (focusedKeyboardTargetRef.current !== target) {
|
|
1154
|
-
keyboardScrollElement = null;
|
|
1155
|
-
}
|
|
1156
1010
|
focusedKeyboardTargetRef.current = target;
|
|
1157
1011
|
return true;
|
|
1158
1012
|
};
|
|
1159
1013
|
const handleFocusIn = event => {
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
// handler that blurs or moves focus — and must be reconciled rather than
|
|
1163
|
-
// suppressed, so stop suppressing here instead of waiting for `.focus()` to return.
|
|
1164
|
-
programmaticKeyboardFocusRef.current = false;
|
|
1165
|
-
consumePreemptedFocus();
|
|
1166
|
-
if (!captureFocusedKeyboardTarget(useScrollLock.getTarget(event))) {
|
|
1167
|
-
// Focus landed outside any drawer keyboard input. The `focusout` on the previous
|
|
1168
|
-
// field normally clears the tracked target, but the tap path suppresses that
|
|
1169
|
-
// `focusout` via `programmaticKeyboardFocusRef`, so a consumer `onFocus` handler that
|
|
1170
|
-
// redirects focus out of the drawer would otherwise leave a stale target holding its
|
|
1171
|
-
// inset, slack, and pending realign. Reconcile against the real focus here.
|
|
1172
|
-
// A handler that ends focus entirely emits no `focusin` to reconcile from; that case
|
|
1173
|
-
// is covered by clearing the suppression flag above so its `focusout` is handled.
|
|
1174
|
-
clearFocusedKeyboardTarget();
|
|
1175
|
-
return;
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
|
-
// Covers every way focus can land with the keyboard already up: native moves (the
|
|
1179
|
-
// keyboard's previous/next arrows) and the tap path (which suppresses `focusout`
|
|
1180
|
-
// handling via the programmatic flag).
|
|
1181
|
-
if (getKeyboardVisualViewport(win) != null) {
|
|
1182
|
-
scheduleDelayedKeyboardRealign();
|
|
1014
|
+
if (captureFocusedKeyboardTarget(useScrollLock.getTarget(event))) {
|
|
1015
|
+
scheduleKeyboardFocusAlignment();
|
|
1183
1016
|
}
|
|
1184
|
-
scheduleKeyboardFocusAlignment();
|
|
1185
1017
|
};
|
|
1186
1018
|
const handleFocusOut = event => {
|
|
1187
|
-
// The blur inside `focusKeyboardInputWithoutPageScroll` is followed synchronously by
|
|
1188
|
-
// a re-focus; clearing state here would drop the keyboard inset for a frame.
|
|
1189
|
-
if (programmaticKeyboardFocusRef.current) {
|
|
1190
|
-
return;
|
|
1191
|
-
}
|
|
1192
1019
|
if (captureFocusedKeyboardTarget(event.relatedTarget)) {
|
|
1193
|
-
const target = focusedKeyboardTargetRef.current;
|
|
1194
|
-
const keyboardViewport = getKeyboardVisualViewport(win);
|
|
1195
|
-
// The delayed realign passes are scheduled by the `focusin` that follows once
|
|
1196
|
-
// focus lands on the captured target.
|
|
1197
|
-
if (target && keyboardViewport) {
|
|
1198
|
-
preemptFocusReveal(target, keyboardViewport);
|
|
1199
|
-
}
|
|
1200
1020
|
scheduleKeyboardFocusAlignment();
|
|
1201
1021
|
return;
|
|
1202
1022
|
}
|
|
@@ -1211,36 +1031,25 @@ function DrawerVirtualKeyboardProvider(props) {
|
|
|
1211
1031
|
if (visualViewport) {
|
|
1212
1032
|
cleanupListeners.push(useScrollLock.addEventListener(visualViewport, 'resize', handleViewportUpdate), useScrollLock.addEventListener(visualViewport, 'scroll', handleViewportUpdate));
|
|
1213
1033
|
}
|
|
1214
|
-
|
|
1215
|
-
if (restoreWindowScroll()) {
|
|
1216
|
-
// Recompute the keyboard inset once the page is back at rest; measurements taken
|
|
1217
|
-
// mid-reveal (a non-zero visual viewport offset) inflate it and push the popup up.
|
|
1218
|
-
scheduleKeyboardFocusAlignment();
|
|
1219
|
-
}
|
|
1220
|
-
};
|
|
1221
|
-
|
|
1222
|
-
// Once the user puts a finger down they own the scroll position. Stop both the frame settle
|
|
1223
|
-
// loop, which can center after changing layout settles, and the delayed passes, which can't
|
|
1224
|
-
// distinguish a user scroll from a reveal scroll WebKit canceled. A later focus or viewport
|
|
1225
|
-
// change reschedules alignment if it's still needed.
|
|
1226
|
-
const cancelKeyboardRealignOnPointerDown = () => {
|
|
1227
|
-
keyboardFocusFrame.cancel();
|
|
1228
|
-
keyboardRealignTimeout.clear();
|
|
1229
|
-
keyboardScrollElement = null;
|
|
1230
|
-
};
|
|
1231
|
-
cleanupListeners.push(useScrollLock.addEventListener(doc, 'focusin', handleFocusIn, true), useScrollLock.addEventListener(doc, 'focusout', handleFocusOut, true), useScrollLock.addEventListener(win, 'scroll', handleWindowScroll), useScrollLock.addEventListener(doc, 'pointerdown', cancelKeyboardRealignOnPointerDown, true));
|
|
1034
|
+
cleanupListeners.push(useScrollLock.addEventListener(doc, 'focusin', handleFocusIn, true), useScrollLock.addEventListener(doc, 'focusout', handleFocusOut, true));
|
|
1232
1035
|
if (captureFocusedKeyboardTarget(useScrollLock.activeElement(doc))) {
|
|
1233
1036
|
scheduleKeyboardFocusAlignment();
|
|
1234
1037
|
}
|
|
1235
1038
|
return () => {
|
|
1236
1039
|
cleanupListeners.forEach(cleanup => cleanup());
|
|
1237
|
-
consumePreemptedFocus();
|
|
1238
1040
|
clearFocusedKeyboardTarget();
|
|
1239
1041
|
rootElement.style.removeProperty(DrawerViewportCssVars.keyboardInset);
|
|
1240
1042
|
};
|
|
1241
|
-
}, [animateKeyboardScroll, keyboardFocusFrame,
|
|
1043
|
+
}, [animateKeyboardScroll, keyboardFocusFrame, mounted, nestedDrawerOpen, open, restoreKeyboardScrollAdjustment, rootElement, setKeyboardScrollSlack]);
|
|
1242
1044
|
const onTouchStart = useScrollLock.useStableCallback(event => {
|
|
1045
|
+
if (!open || !mounted || nestedDrawerOpen) {
|
|
1046
|
+
resetTouchTrackingState();
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1243
1049
|
const touch = event.touches[0];
|
|
1050
|
+
if (!touch) {
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1244
1053
|
pendingKeyboardFocusMovedRef.current = false;
|
|
1245
1054
|
keyboardTouchStartRef.current = {
|
|
1246
1055
|
x: touch.clientX,
|
|
@@ -1266,9 +1075,9 @@ function DrawerVirtualKeyboardProvider(props) {
|
|
|
1266
1075
|
return;
|
|
1267
1076
|
}
|
|
1268
1077
|
const touch = event.changedTouches[0] ?? event.touches[0];
|
|
1269
|
-
const
|
|
1078
|
+
const doc = useScrollLock.ownerDocument(event.currentTarget);
|
|
1270
1079
|
const nativeEventTarget = useScrollLock.getTarget(event.nativeEvent);
|
|
1271
|
-
const pointTarget = touch ? resolveKeyboardTouchTargetFromPoint(
|
|
1080
|
+
const pointTarget = touch ? resolveKeyboardTouchTargetFromPoint(doc, touch.clientX, touch.clientY) : null;
|
|
1272
1081
|
|
|
1273
1082
|
// The lift point landed on another interactive/label element; let its native tap
|
|
1274
1083
|
// through instead of stealing it for the touchstart input.
|
|
@@ -1286,7 +1095,7 @@ function DrawerVirtualKeyboardProvider(props) {
|
|
|
1286
1095
|
clickTarget: keyboardClickTarget,
|
|
1287
1096
|
focusTarget: keyboardFocusTarget
|
|
1288
1097
|
} = keyboardTarget;
|
|
1289
|
-
const win =
|
|
1098
|
+
const win = floatingUi_utils.getWindow(keyboardFocusTarget);
|
|
1290
1099
|
|
|
1291
1100
|
// While pinch-zoomed, keyboard alignment is suspended; let native behavior
|
|
1292
1101
|
// handle focus and caret placement instead of blurring and re-focusing.
|
|
@@ -1297,24 +1106,15 @@ function DrawerVirtualKeyboardProvider(props) {
|
|
|
1297
1106
|
|
|
1298
1107
|
// Already focused with the keyboard up: let the native tap through so it can
|
|
1299
1108
|
// reposition the caret, rather than blurring and re-focusing the same input.
|
|
1300
|
-
if (useScrollLock.activeElement(useScrollLock.ownerDocument(keyboardFocusTarget)) === keyboardFocusTarget && (
|
|
1109
|
+
if (useScrollLock.activeElement(useScrollLock.ownerDocument(keyboardFocusTarget)) === keyboardFocusTarget && isKeyboardVisualViewportOpen(win)) {
|
|
1301
1110
|
resetTouchTrackingState();
|
|
1302
1111
|
return;
|
|
1303
1112
|
}
|
|
1304
1113
|
|
|
1305
1114
|
// iOS only opens the software keyboard when focus happens synchronously
|
|
1306
|
-
// inside the touch gesture.
|
|
1307
|
-
// intermediate blur would otherwise trigger, so the keyboard inset isn't
|
|
1308
|
-
// dropped for a frame between the blur and the re-focus. It is cleared by the
|
|
1309
|
-
// `focusin` that lands, so only that blur is suppressed; the `finally` is the
|
|
1310
|
-
// backstop for a target that never takes focus.
|
|
1115
|
+
// inside the touch gesture.
|
|
1311
1116
|
event.preventDefault();
|
|
1312
|
-
|
|
1313
|
-
try {
|
|
1314
|
-
focusKeyboardInputWithoutPageScroll(keyboardFocusTarget);
|
|
1315
|
-
} finally {
|
|
1316
|
-
programmaticKeyboardFocusRef.current = false;
|
|
1317
|
-
}
|
|
1117
|
+
focusKeyboardInputWithoutPageScroll(keyboardFocusTarget);
|
|
1318
1118
|
// Preventing the touchend default also suppresses the compatibility mouse
|
|
1319
1119
|
// events, including `click`; redispatch an untrusted replacement on the
|
|
1320
1120
|
// original tap target so click handlers still run with the tap coordinates.
|
|
@@ -1339,7 +1139,7 @@ function isKeyboardInputElement(element) {
|
|
|
1339
1139
|
if (element.isContentEditable) {
|
|
1340
1140
|
return true;
|
|
1341
1141
|
}
|
|
1342
|
-
const win =
|
|
1142
|
+
const win = floatingUi_utils.getWindow(element);
|
|
1343
1143
|
if (element instanceof win.HTMLTextAreaElement || element instanceof win.HTMLInputElement && KEYBOARD_INPUT_TYPES.has(element.type)) {
|
|
1344
1144
|
// Disabled controls can't focus or open the keyboard, so tap-to-focus must skip them —
|
|
1345
1145
|
// otherwise the dispatched click fires handlers a native tap on a disabled control never would.
|
|
@@ -1348,7 +1148,7 @@ function isKeyboardInputElement(element) {
|
|
|
1348
1148
|
return false;
|
|
1349
1149
|
}
|
|
1350
1150
|
function resolveKeyboardInputTarget(target) {
|
|
1351
|
-
if (!
|
|
1151
|
+
if (!floatingUi_utils.isHTMLElement(target)) {
|
|
1352
1152
|
return null;
|
|
1353
1153
|
}
|
|
1354
1154
|
if (isKeyboardInputElement(target)) {
|
|
@@ -1356,19 +1156,16 @@ function resolveKeyboardInputTarget(target) {
|
|
|
1356
1156
|
}
|
|
1357
1157
|
const label = target.closest('label');
|
|
1358
1158
|
const control = label?.control ?? null;
|
|
1359
|
-
return
|
|
1159
|
+
return floatingUi_utils.isHTMLElement(control) && isKeyboardInputElement(control) ? control : null;
|
|
1360
1160
|
}
|
|
1361
1161
|
function resolveKeyboardTouchTarget(target) {
|
|
1362
|
-
if (!useScrollLock.isHTMLElement(target)) {
|
|
1363
|
-
return null;
|
|
1364
|
-
}
|
|
1365
1162
|
const focusTarget = resolveKeyboardInputTarget(target);
|
|
1366
1163
|
if (!focusTarget) {
|
|
1367
1164
|
return null;
|
|
1368
1165
|
}
|
|
1369
1166
|
return {
|
|
1370
1167
|
focusTarget,
|
|
1371
|
-
clickTarget: target
|
|
1168
|
+
clickTarget: floatingUi_utils.isHTMLElement(target) ? target : focusTarget
|
|
1372
1169
|
};
|
|
1373
1170
|
}
|
|
1374
1171
|
|
|
@@ -1381,16 +1178,14 @@ function getContentEditableHost(element) {
|
|
|
1381
1178
|
}
|
|
1382
1179
|
return host;
|
|
1383
1180
|
}
|
|
1384
|
-
function resolveKeyboardTouchTargetFromPoint(
|
|
1385
|
-
const exactTarget = ScrollAreaViewport.getElementAtPoint(
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
};
|
|
1393
|
-
}
|
|
1181
|
+
function resolveKeyboardTouchTargetFromPoint(doc, clientX, clientY) {
|
|
1182
|
+
const exactTarget = ScrollAreaViewport.getElementAtPoint(doc, clientX, clientY);
|
|
1183
|
+
const exactKeyboardTarget = resolveKeyboardInputTarget(exactTarget);
|
|
1184
|
+
if (exactKeyboardTarget) {
|
|
1185
|
+
return {
|
|
1186
|
+
focusTarget: exactKeyboardTarget,
|
|
1187
|
+
clickTarget: floatingUi_utils.isHTMLElement(exactTarget) ? exactTarget : exactKeyboardTarget
|
|
1188
|
+
};
|
|
1394
1189
|
}
|
|
1395
1190
|
|
|
1396
1191
|
// Probing nearby points compensates for iOS retargeting taps while the page reacts
|
|
@@ -1403,7 +1198,7 @@ function resolveKeyboardTouchTargetFromPoint(root, clientX, clientY) {
|
|
|
1403
1198
|
return KEYBOARD_TAP_BLOCKED;
|
|
1404
1199
|
}
|
|
1405
1200
|
for (const [offsetX, offsetY] of [[0, INPUT_TAP_HIT_SLOP], [0, -INPUT_TAP_HIT_SLOP], [INPUT_TAP_HIT_SLOP, 0], [-INPUT_TAP_HIT_SLOP, 0]]) {
|
|
1406
|
-
const keyboardTarget = resolveKeyboardInputTarget(ScrollAreaViewport.getElementAtPoint(
|
|
1201
|
+
const keyboardTarget = resolveKeyboardInputTarget(ScrollAreaViewport.getElementAtPoint(doc, clientX + offsetX, clientY + offsetY));
|
|
1407
1202
|
if (keyboardTarget) {
|
|
1408
1203
|
return {
|
|
1409
1204
|
focusTarget: keyboardTarget,
|
|
@@ -1414,7 +1209,7 @@ function resolveKeyboardTouchTargetFromPoint(root, clientX, clientY) {
|
|
|
1414
1209
|
return null;
|
|
1415
1210
|
}
|
|
1416
1211
|
function dispatchKeyboardClick(target, touch) {
|
|
1417
|
-
const win =
|
|
1212
|
+
const win = floatingUi_utils.getWindow(target);
|
|
1418
1213
|
const ClickEvent = win.PointerEvent ?? win.MouseEvent;
|
|
1419
1214
|
target.dispatchEvent(new ClickEvent('click', {
|
|
1420
1215
|
bubbles: true,
|
|
@@ -1427,10 +1222,15 @@ function dispatchKeyboardClick(target, touch) {
|
|
|
1427
1222
|
}
|
|
1428
1223
|
function focusKeyboardInputWithoutPageScroll(target) {
|
|
1429
1224
|
const wasFocused = useScrollLock.activeElement(useScrollLock.ownerDocument(target)) === target;
|
|
1225
|
+
const previousOpacity = target.style.opacity;
|
|
1226
|
+
const previousTransform = target.style.transform;
|
|
1227
|
+
const previousTransition = target.style.transition;
|
|
1228
|
+
|
|
1430
1229
|
// iOS Safari can still scroll the page for transformed sheets even with preventScroll.
|
|
1431
|
-
// Move the input off-screen only for the synchronous focus call
|
|
1432
|
-
|
|
1433
|
-
|
|
1230
|
+
// Move the input off-screen only for the synchronous focus call.
|
|
1231
|
+
target.style.transition = 'none';
|
|
1232
|
+
target.style.opacity = '0';
|
|
1233
|
+
target.style.transform = 'translateY(-2000px)';
|
|
1434
1234
|
try {
|
|
1435
1235
|
if (wasFocused) {
|
|
1436
1236
|
target.blur();
|
|
@@ -1439,25 +1239,10 @@ function focusKeyboardInputWithoutPageScroll(target) {
|
|
|
1439
1239
|
preventScroll: true
|
|
1440
1240
|
});
|
|
1441
1241
|
} finally {
|
|
1442
|
-
restoreStyles();
|
|
1443
|
-
}
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
// Overrides the painted geometry WebKit samples when an element gains focus. The rect is
|
|
1447
|
-
// hidden (opacity) rather than detached so layout is unaffected; the caller must restore
|
|
1448
|
-
// synchronously before the next paint.
|
|
1449
|
-
function overrideGeometryDuringFocus(target, translateY) {
|
|
1450
|
-
const previousOpacity = target.style.opacity;
|
|
1451
|
-
const previousTransform = target.style.transform;
|
|
1452
|
-
const previousTransition = target.style.transition;
|
|
1453
|
-
target.style.transition = 'none';
|
|
1454
|
-
target.style.opacity = '0';
|
|
1455
|
-
target.style.transform = `translateY(${translateY}px)`;
|
|
1456
|
-
return () => {
|
|
1457
1242
|
target.style.opacity = previousOpacity;
|
|
1458
1243
|
target.style.transform = previousTransform;
|
|
1459
1244
|
target.style.transition = previousTransition;
|
|
1460
|
-
}
|
|
1245
|
+
}
|
|
1461
1246
|
}
|
|
1462
1247
|
function findKeyboardScrollTarget(target, root) {
|
|
1463
1248
|
// Start at the parent: scrolling the focused field's own content (an overflowing
|
|
@@ -1466,8 +1251,8 @@ function findKeyboardScrollTarget(target, root) {
|
|
|
1466
1251
|
// the drawer body scroller. Prefer an already-scrollable ancestor, then fall back to one
|
|
1467
1252
|
// that only becomes scrollable once keyboard slack is added (overflow intent without
|
|
1468
1253
|
// current overflow).
|
|
1469
|
-
const scrollStart =
|
|
1470
|
-
return
|
|
1254
|
+
const scrollStart = floatingUi_utils.getParentNode(target);
|
|
1255
|
+
return ScrollAreaViewport.findScrollableTouchTarget(scrollStart, root, 'vertical') ?? ScrollAreaViewport.findScrollableTouchTarget(scrollStart, root, 'vertical', true);
|
|
1471
1256
|
}
|
|
1472
1257
|
function getKeyboardVisualViewport(win) {
|
|
1473
1258
|
const visualViewport = win.visualViewport;
|
|
@@ -1485,22 +1270,11 @@ function getKeyboardVisualViewport(win) {
|
|
|
1485
1270
|
bottom: Math.min(win.innerHeight, top + visualViewport.height)
|
|
1486
1271
|
};
|
|
1487
1272
|
}
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
*
|
|
1494
|
-
* The imperative methods take effect only while a root using this handle is mounted; calls made
|
|
1495
|
-
* before a root attaches (or after it unmounts) are ignored.
|
|
1496
|
-
*/
|
|
1497
|
-
class DrawerHandle extends DrawerDescription.DialogHandle {}
|
|
1498
|
-
|
|
1499
|
-
/**
|
|
1500
|
-
* Creates a new handle to connect a Drawer.Root with detached Drawer.Trigger components.
|
|
1501
|
-
*/
|
|
1502
|
-
function createDrawerHandle() {
|
|
1503
|
-
return new DrawerHandle();
|
|
1273
|
+
function getDrawerKeyboardInset(win, keyboardViewport) {
|
|
1274
|
+
return Math.max(0, win.innerHeight - keyboardViewport.bottom);
|
|
1275
|
+
}
|
|
1276
|
+
function isKeyboardVisualViewportOpen(win) {
|
|
1277
|
+
return !win.visualViewport || getKeyboardVisualViewport(win) != null;
|
|
1504
1278
|
}
|
|
1505
1279
|
|
|
1506
1280
|
var index_parts$5 = /*#__PURE__*/Object.freeze({
|
|
@@ -1509,7 +1283,7 @@ var index_parts$5 = /*#__PURE__*/Object.freeze({
|
|
|
1509
1283
|
Close: DrawerTitle.DrawerClose,
|
|
1510
1284
|
Content: ScrollAreaViewport.DrawerContent,
|
|
1511
1285
|
Description: DrawerDescription.DrawerDescription,
|
|
1512
|
-
Handle:
|
|
1286
|
+
Handle: DrawerDescription.DialogHandle,
|
|
1513
1287
|
Indent: DrawerIndent,
|
|
1514
1288
|
IndentBackground: DrawerIndentBackground,
|
|
1515
1289
|
Popup: ScrollAreaViewport.DrawerPopup,
|
|
@@ -1521,7 +1295,7 @@ var index_parts$5 = /*#__PURE__*/Object.freeze({
|
|
|
1521
1295
|
Trigger: ScrollAreaViewport.DrawerTrigger,
|
|
1522
1296
|
Viewport: ScrollAreaViewport.DrawerViewport,
|
|
1523
1297
|
VirtualKeyboardProvider: DrawerVirtualKeyboardProvider,
|
|
1524
|
-
createHandle:
|
|
1298
|
+
createHandle: DrawerDescription.createDialogHandle
|
|
1525
1299
|
});
|
|
1526
1300
|
|
|
1527
1301
|
/**
|
|
@@ -1590,7 +1364,7 @@ const MenuCheckboxItem = /*#__PURE__*/React__namespace.forwardRef(function MenuC
|
|
|
1590
1364
|
id: idProp,
|
|
1591
1365
|
label,
|
|
1592
1366
|
nativeButton = false,
|
|
1593
|
-
disabled
|
|
1367
|
+
disabled = false,
|
|
1594
1368
|
closeOnClick = false,
|
|
1595
1369
|
checked: checkedProp,
|
|
1596
1370
|
defaultChecked,
|
|
@@ -1599,7 +1373,6 @@ const MenuCheckboxItem = /*#__PURE__*/React__namespace.forwardRef(function MenuC
|
|
|
1599
1373
|
...elementProps
|
|
1600
1374
|
} = componentProps;
|
|
1601
1375
|
const listItem = useCompositeListItem.useCompositeListItem({
|
|
1602
|
-
guess: true,
|
|
1603
1376
|
label
|
|
1604
1377
|
});
|
|
1605
1378
|
const menuPositionerContext = MenuSubmenuTrigger.useMenuPositionerContext(true);
|
|
@@ -1607,8 +1380,6 @@ const MenuCheckboxItem = /*#__PURE__*/React__namespace.forwardRef(function MenuC
|
|
|
1607
1380
|
const {
|
|
1608
1381
|
store
|
|
1609
1382
|
} = MenuSubmenuTrigger.useMenuRootContext();
|
|
1610
|
-
const rootDisabled = store.useState('disabled');
|
|
1611
|
-
const disabled = disabledProp || rootDisabled;
|
|
1612
1383
|
const highlighted = store.useState('isActive', listItem.index);
|
|
1613
1384
|
const itemProps = store.useState('itemProps');
|
|
1614
1385
|
const [checked, setChecked] = useScrollLock.useControlled({
|
|
@@ -1637,7 +1408,7 @@ const MenuCheckboxItem = /*#__PURE__*/React__namespace.forwardRef(function MenuC
|
|
|
1637
1408
|
}), [disabled, highlighted, checked]);
|
|
1638
1409
|
function handleClick(event) {
|
|
1639
1410
|
const details = useScrollLock.createChangeEventDetails(useScrollLock.itemPress, event.nativeEvent, undefined, {
|
|
1640
|
-
preventUnmountOnClose
|
|
1411
|
+
preventUnmountOnClose() {}
|
|
1641
1412
|
});
|
|
1642
1413
|
onCheckedChange?.(!checked, details);
|
|
1643
1414
|
if (details.isCanceled) {
|
|
@@ -1680,7 +1451,6 @@ const MenuCheckboxItemIndicator = /*#__PURE__*/React__namespace.forwardRef(funct
|
|
|
1680
1451
|
const indicatorRef = React__namespace.useRef(null);
|
|
1681
1452
|
const {
|
|
1682
1453
|
transitionStatus,
|
|
1683
|
-
mounted,
|
|
1684
1454
|
setMounted
|
|
1685
1455
|
} = useScrollLock.useTransitionStatus(item.checked);
|
|
1686
1456
|
useScrollLock.useOpenChangeComplete({
|
|
@@ -1706,22 +1476,22 @@ const MenuCheckboxItemIndicator = /*#__PURE__*/React__namespace.forwardRef(funct
|
|
|
1706
1476
|
'aria-hidden': true,
|
|
1707
1477
|
...elementProps
|
|
1708
1478
|
},
|
|
1709
|
-
enabled: keepMounted ||
|
|
1479
|
+
enabled: keepMounted || item.checked
|
|
1710
1480
|
});
|
|
1711
1481
|
return element;
|
|
1712
1482
|
});
|
|
1713
1483
|
if (process.env.NODE_ENV !== "production") MenuCheckboxItemIndicator.displayName = "MenuCheckboxItemIndicator";
|
|
1714
1484
|
|
|
1715
1485
|
function getCssDimensions(element) {
|
|
1716
|
-
const css =
|
|
1486
|
+
const css = floatingUi_utils.getComputedStyle(element);
|
|
1717
1487
|
// In testing environments, the `width` and `height` properties are empty
|
|
1718
1488
|
// strings for SVG elements, returning NaN. Fallback to `0` in this case.
|
|
1719
1489
|
let width = parseFloat(css.width) || 0;
|
|
1720
1490
|
let height = parseFloat(css.height) || 0;
|
|
1721
|
-
const hasOffset =
|
|
1491
|
+
const hasOffset = floatingUi_utils.isHTMLElement(element);
|
|
1722
1492
|
const offsetWidth = hasOffset ? element.offsetWidth : width;
|
|
1723
1493
|
const offsetHeight = hasOffset ? element.offsetHeight : height;
|
|
1724
|
-
const shouldFallback =
|
|
1494
|
+
const shouldFallback = floatingUi_utils.round(width) !== offsetWidth || floatingUi_utils.round(height) !== offsetHeight;
|
|
1725
1495
|
if (shouldFallback) {
|
|
1726
1496
|
width = offsetWidth;
|
|
1727
1497
|
height = offsetHeight;
|
|
@@ -1746,14 +1516,30 @@ function usePopupAutoResize(parameters) {
|
|
|
1746
1516
|
side,
|
|
1747
1517
|
direction
|
|
1748
1518
|
} = parameters;
|
|
1749
|
-
const runOnceAnimationsFinish = useScrollLock.useAnimationsFinished(popupElement, true);
|
|
1519
|
+
const runOnceAnimationsFinish = useScrollLock.useAnimationsFinished(popupElement, true, false);
|
|
1750
1520
|
const animationFrame = useScrollLock.useAnimationFrame();
|
|
1751
1521
|
const committedDimensionsRef = React__namespace.useRef(null);
|
|
1752
1522
|
const isInitialRenderRef = React__namespace.useRef(true);
|
|
1753
1523
|
const restoreAnchoringStylesRef = React__namespace.useRef(useRenderElement.NOOP);
|
|
1754
1524
|
const onMeasureLayout = useScrollLock.useStableCallback(onMeasureLayoutParam);
|
|
1755
1525
|
const onMeasureLayoutComplete = useScrollLock.useStableCallback(onMeasureLayoutCompleteParam);
|
|
1756
|
-
const anchoringStyles = React__namespace.useMemo(() =>
|
|
1526
|
+
const anchoringStyles = React__namespace.useMemo(() => {
|
|
1527
|
+
// Ensure popup size transitions correctly when anchored to `bottom` (side=top) or `right` (side=left).
|
|
1528
|
+
let isOriginSide = side === 'top';
|
|
1529
|
+
let isPhysicalLeft = side === 'left';
|
|
1530
|
+
if (direction === 'rtl') {
|
|
1531
|
+
isOriginSide = isOriginSide || side === 'inline-end';
|
|
1532
|
+
isPhysicalLeft = isPhysicalLeft || side === 'inline-end';
|
|
1533
|
+
} else {
|
|
1534
|
+
isOriginSide = isOriginSide || side === 'inline-start';
|
|
1535
|
+
isPhysicalLeft = isPhysicalLeft || side === 'inline-start';
|
|
1536
|
+
}
|
|
1537
|
+
return isOriginSide ? {
|
|
1538
|
+
position: 'absolute',
|
|
1539
|
+
[side === 'top' ? 'bottom' : 'top']: '0',
|
|
1540
|
+
[isPhysicalLeft ? 'right' : 'left']: '0'
|
|
1541
|
+
} : useRenderElement.EMPTY_OBJECT;
|
|
1542
|
+
}, [side, direction]);
|
|
1757
1543
|
useScrollLock.useIsoLayoutEffect(() => {
|
|
1758
1544
|
// Reset the state when the popup is closed.
|
|
1759
1545
|
if (!mounted) {
|
|
@@ -1829,19 +1615,6 @@ function usePopupAutoResize(parameters) {
|
|
|
1829
1615
|
};
|
|
1830
1616
|
}, [content, popupElement, positionerElement, runOnceAnimationsFinish, animationFrame, mounted, onMeasureLayout, onMeasureLayoutComplete, anchoringStyles]);
|
|
1831
1617
|
}
|
|
1832
|
-
function getPopupAnchoringStyles(side, direction) {
|
|
1833
|
-
// Ensure popup size transitions correctly when anchored to `bottom` (side=top) or `right` (side=left).
|
|
1834
|
-
const isPhysicalTop = side === 'top';
|
|
1835
|
-
const isPhysicalLeft = side === 'left' || side === (direction === 'rtl' ? 'inline-end' : 'inline-start');
|
|
1836
|
-
if (!isPhysicalTop && !isPhysicalLeft) {
|
|
1837
|
-
return useRenderElement.EMPTY_OBJECT;
|
|
1838
|
-
}
|
|
1839
|
-
return {
|
|
1840
|
-
position: 'absolute',
|
|
1841
|
-
[isPhysicalTop ? 'bottom' : 'top']: '0',
|
|
1842
|
-
[isPhysicalLeft ? 'right' : 'left']: '0'
|
|
1843
|
-
};
|
|
1844
|
-
}
|
|
1845
1618
|
function overrideElementStyle(element, property, value) {
|
|
1846
1619
|
const originalValue = element.style.getPropertyValue(property);
|
|
1847
1620
|
element.style.setProperty(property, value);
|
|
@@ -1871,80 +1644,6 @@ function setPositionerCssSize(positionerElement, size) {
|
|
|
1871
1644
|
positionerElement.style.setProperty('--positioner-height', height);
|
|
1872
1645
|
}
|
|
1873
1646
|
|
|
1874
|
-
const adaptiveOrigin = {
|
|
1875
|
-
name: 'adaptiveOrigin',
|
|
1876
|
-
async fn(state) {
|
|
1877
|
-
const {
|
|
1878
|
-
x: rawX,
|
|
1879
|
-
y: rawY,
|
|
1880
|
-
rects: {
|
|
1881
|
-
floating: floatRect
|
|
1882
|
-
},
|
|
1883
|
-
elements: {
|
|
1884
|
-
floating
|
|
1885
|
-
},
|
|
1886
|
-
platform,
|
|
1887
|
-
strategy,
|
|
1888
|
-
placement
|
|
1889
|
-
} = state;
|
|
1890
|
-
const win = useScrollLock.getWindow(floating);
|
|
1891
|
-
const styles = win.getComputedStyle(floating);
|
|
1892
|
-
const hasTransition = styles.transitionDuration !== '0s' && styles.transitionDuration !== '';
|
|
1893
|
-
if (!hasTransition) {
|
|
1894
|
-
return {
|
|
1895
|
-
x: rawX,
|
|
1896
|
-
y: rawY,
|
|
1897
|
-
data: useCompositeListItem.DEFAULT_SIDES
|
|
1898
|
-
};
|
|
1899
|
-
}
|
|
1900
|
-
const offsetParent = await platform.getOffsetParent?.(floating);
|
|
1901
|
-
let offsetDimensions = {
|
|
1902
|
-
width: 0,
|
|
1903
|
-
height: 0
|
|
1904
|
-
};
|
|
1905
|
-
|
|
1906
|
-
// For fixed strategy, prefer visualViewport if available
|
|
1907
|
-
if (strategy === 'fixed' && win?.visualViewport) {
|
|
1908
|
-
offsetDimensions = {
|
|
1909
|
-
width: win.visualViewport.width,
|
|
1910
|
-
height: win.visualViewport.height
|
|
1911
|
-
};
|
|
1912
|
-
} else if (offsetParent === win) {
|
|
1913
|
-
const doc = useScrollLock.ownerDocument(floating);
|
|
1914
|
-
offsetDimensions = {
|
|
1915
|
-
width: doc.documentElement.clientWidth,
|
|
1916
|
-
height: doc.documentElement.clientHeight
|
|
1917
|
-
};
|
|
1918
|
-
} else if (await platform.isElement?.(offsetParent)) {
|
|
1919
|
-
offsetDimensions = await platform.getDimensions(offsetParent);
|
|
1920
|
-
}
|
|
1921
|
-
const currentSide = useScrollLock.getSide(placement);
|
|
1922
|
-
let x = rawX;
|
|
1923
|
-
let y = rawY;
|
|
1924
|
-
if (currentSide === 'left') {
|
|
1925
|
-
x = offsetDimensions.width - (rawX + floatRect.width);
|
|
1926
|
-
}
|
|
1927
|
-
if (currentSide === 'top') {
|
|
1928
|
-
y = offsetDimensions.height - (rawY + floatRect.height);
|
|
1929
|
-
}
|
|
1930
|
-
const sideX = currentSide === 'left' ? 'right' : useCompositeListItem.DEFAULT_SIDES.sideX;
|
|
1931
|
-
const sideY = currentSide === 'top' ? 'bottom' : useCompositeListItem.DEFAULT_SIDES.sideY;
|
|
1932
|
-
return {
|
|
1933
|
-
x,
|
|
1934
|
-
y,
|
|
1935
|
-
data: {
|
|
1936
|
-
sideX,
|
|
1937
|
-
sideY
|
|
1938
|
-
}
|
|
1939
|
-
};
|
|
1940
|
-
}
|
|
1941
|
-
};
|
|
1942
|
-
|
|
1943
|
-
const popupViewportStateMapping = {
|
|
1944
|
-
activationDirection: value => value ? {
|
|
1945
|
-
'data-activation-direction': value
|
|
1946
|
-
} : null
|
|
1947
|
-
};
|
|
1948
1647
|
/**
|
|
1949
1648
|
* Builds morphing viewport containers for popups that animate between trigger-based content.
|
|
1950
1649
|
* Handles previous-content snapshots, auto-resize, and state attributes for transitions.
|
|
@@ -1953,6 +1652,7 @@ function usePopupViewport(parameters) {
|
|
|
1953
1652
|
const {
|
|
1954
1653
|
store,
|
|
1955
1654
|
side,
|
|
1655
|
+
cssVars,
|
|
1956
1656
|
children
|
|
1957
1657
|
} = parameters;
|
|
1958
1658
|
const direction = useScrollLock.useDirection();
|
|
@@ -1972,15 +1672,14 @@ function usePopupViewport(parameters) {
|
|
|
1972
1672
|
const [newTriggerOffset, setNewTriggerOffset] = React__namespace.useState(null);
|
|
1973
1673
|
const currentContainerRef = React__namespace.useRef(null);
|
|
1974
1674
|
const previousContainerRef = React__namespace.useRef(null);
|
|
1975
|
-
const onAnimationsFinished = useScrollLock.useAnimationsFinished(currentContainerRef, true);
|
|
1675
|
+
const onAnimationsFinished = useScrollLock.useAnimationsFinished(currentContainerRef, true, false);
|
|
1976
1676
|
const cleanupFrame = useScrollLock.useAnimationFrame();
|
|
1977
|
-
const cleanupControllerRef = React__namespace.useRef(null);
|
|
1978
1677
|
const [previousContentDimensions, setPreviousContentDimensions] = React__namespace.useState(null);
|
|
1979
1678
|
const [showStartingStyleAttribute, setShowStartingStyleAttribute] = React__namespace.useState(false);
|
|
1980
1679
|
useScrollLock.useIsoLayoutEffect(() => {
|
|
1981
|
-
store.set('
|
|
1680
|
+
store.set('hasViewport', true);
|
|
1982
1681
|
return () => {
|
|
1983
|
-
store.set('
|
|
1682
|
+
store.set('hasViewport', false);
|
|
1984
1683
|
};
|
|
1985
1684
|
}, [store]);
|
|
1986
1685
|
const handleMeasureLayout = useScrollLock.useStableCallback(() => {
|
|
@@ -1996,16 +1695,6 @@ function usePopupViewport(parameters) {
|
|
|
1996
1695
|
setPreviousContentDimensions(previousDimensions);
|
|
1997
1696
|
}
|
|
1998
1697
|
});
|
|
1999
|
-
const armViewportCleanup = useScrollLock.useStableCallback(() => {
|
|
2000
|
-
cleanupControllerRef.current?.abort();
|
|
2001
|
-
const controller = new AbortController();
|
|
2002
|
-
cleanupControllerRef.current = controller;
|
|
2003
|
-
onAnimationsFinished(() => {
|
|
2004
|
-
setPreviousContentNode(null);
|
|
2005
|
-
setPreviousContentDimensions(null);
|
|
2006
|
-
capturedNodeRef.current = null;
|
|
2007
|
-
}, controller.signal);
|
|
2008
|
-
});
|
|
2009
1698
|
const lastHandledTriggerRef = React__namespace.useRef(null);
|
|
2010
1699
|
useScrollLock.useIsoLayoutEffect(() => {
|
|
2011
1700
|
if (!open || !mounted) {
|
|
@@ -2023,33 +1712,19 @@ function usePopupViewport(parameters) {
|
|
|
2023
1712
|
// so we can pass it to the style hook for animation purposes.
|
|
2024
1713
|
const offset = calculateRelativePosition(previousActiveTrigger, activeTrigger);
|
|
2025
1714
|
setNewTriggerOffset(offset);
|
|
1715
|
+
cleanupFrame.request(() => {
|
|
1716
|
+
ReactDOM__namespace.flushSync(() => {
|
|
1717
|
+
setShowStartingStyleAttribute(false);
|
|
1718
|
+
});
|
|
1719
|
+
onAnimationsFinished(() => {
|
|
1720
|
+
setPreviousContentNode(null);
|
|
1721
|
+
setPreviousContentDimensions(null);
|
|
1722
|
+
capturedNodeRef.current = null;
|
|
1723
|
+
});
|
|
1724
|
+
});
|
|
2026
1725
|
lastHandledTriggerRef.current = activeTrigger;
|
|
2027
1726
|
}
|
|
2028
|
-
}, [activeTrigger, previousActiveTrigger]);
|
|
2029
|
-
|
|
2030
|
-
// Arm cleanup after a trigger change, and re-arm it if the current container remounts
|
|
2031
|
-
// mid-transition when a lagging payload bumps `currentContentKey`. The remount discards
|
|
2032
|
-
// the running entry animation (and with transition-style CSS the replacement mounts at
|
|
2033
|
-
// final styles with no animation at all), so re-run the starting-style choreography —
|
|
2034
|
-
// otherwise the watcher either strands or fires before the previous container's exit
|
|
2035
|
-
// animation finishes.
|
|
2036
|
-
useScrollLock.useIsoLayoutEffect(() => {
|
|
2037
|
-
if (previousContentNode == null) {
|
|
2038
|
-
return;
|
|
2039
|
-
}
|
|
2040
|
-
|
|
2041
|
-
// Abort the stale watcher synchronously. The remount cancels the old container's
|
|
2042
|
-
// animations, and the resulting promise rejection would otherwise run the cleanup
|
|
2043
|
-
// in a microtask before the re-armed watcher below is in place.
|
|
2044
|
-
cleanupControllerRef.current?.abort();
|
|
2045
|
-
setShowStartingStyleAttribute(true);
|
|
2046
|
-
cleanupFrame.request(() => {
|
|
2047
|
-
ReactDOM__namespace.flushSync(() => {
|
|
2048
|
-
setShowStartingStyleAttribute(false);
|
|
2049
|
-
});
|
|
2050
|
-
armViewportCleanup();
|
|
2051
|
-
});
|
|
2052
|
-
}, [currentContentKey, previousContentNode, armViewportCleanup, cleanupFrame]);
|
|
1727
|
+
}, [activeTrigger, previousActiveTrigger, previousContentNode, onAnimationsFinished, cleanupFrame]);
|
|
2053
1728
|
|
|
2054
1729
|
// Capture a clone of the current content DOM subtree when not transitioning.
|
|
2055
1730
|
// We can't store previous React nodes as they may be stateful; instead we capture DOM clones for visual continuity.
|
|
@@ -2086,8 +1761,8 @@ function usePopupViewport(parameters) {
|
|
|
2086
1761
|
ref: previousContainerRef,
|
|
2087
1762
|
style: {
|
|
2088
1763
|
...(previousContentDimensions ? {
|
|
2089
|
-
|
|
2090
|
-
|
|
1764
|
+
[cssVars.popupWidth]: `${previousContentDimensions.width}px`,
|
|
1765
|
+
[cssVars.popupHeight]: `${previousContentDimensions.height}px`
|
|
2091
1766
|
} : null),
|
|
2092
1767
|
position: 'absolute'
|
|
2093
1768
|
},
|
|
@@ -2212,6 +1887,28 @@ function usePopupContentKey(activeTriggerId, payload) {
|
|
|
2212
1887
|
return `${activeTriggerId ?? 'current'}-${contentKey}`;
|
|
2213
1888
|
}
|
|
2214
1889
|
|
|
1890
|
+
let MenuViewportCssVars = /*#__PURE__*/function (MenuViewportCssVars) {
|
|
1891
|
+
/**
|
|
1892
|
+
* The width of the parent popup.
|
|
1893
|
+
* This variable is placed on the 'previous' container and stores the width of the popup when the previous content was rendered.
|
|
1894
|
+
* It can be used to freeze the dimensions of the popup when animating between different content.
|
|
1895
|
+
*/
|
|
1896
|
+
MenuViewportCssVars["popupWidth"] = "--popup-width";
|
|
1897
|
+
/**
|
|
1898
|
+
* The height of the parent popup.
|
|
1899
|
+
* This variable is placed on the 'previous' container and stores the height of the popup when the previous content was rendered.
|
|
1900
|
+
* It can be used to freeze the dimensions of the popup when animating between different content.
|
|
1901
|
+
*/
|
|
1902
|
+
MenuViewportCssVars["popupHeight"] = "--popup-height";
|
|
1903
|
+
return MenuViewportCssVars;
|
|
1904
|
+
}({});
|
|
1905
|
+
|
|
1906
|
+
const stateAttributesMapping$2 = {
|
|
1907
|
+
activationDirection: value => value ? {
|
|
1908
|
+
'data-activation-direction': value
|
|
1909
|
+
} : null
|
|
1910
|
+
};
|
|
1911
|
+
|
|
2215
1912
|
/**
|
|
2216
1913
|
* A viewport for displaying content transitions.
|
|
2217
1914
|
* This component is only required if one popup can be opened by multiple triggers, its content
|
|
@@ -2241,6 +1938,7 @@ const MenuViewport = /*#__PURE__*/React__namespace.forwardRef(function MenuViewp
|
|
|
2241
1938
|
} = usePopupViewport({
|
|
2242
1939
|
store,
|
|
2243
1940
|
side,
|
|
1941
|
+
cssVars: MenuViewportCssVars,
|
|
2244
1942
|
children
|
|
2245
1943
|
});
|
|
2246
1944
|
const state = {
|
|
@@ -2254,50 +1952,47 @@ const MenuViewport = /*#__PURE__*/React__namespace.forwardRef(function MenuViewp
|
|
|
2254
1952
|
props: [elementProps, {
|
|
2255
1953
|
children: childrenToRender
|
|
2256
1954
|
}],
|
|
2257
|
-
stateAttributesMapping:
|
|
1955
|
+
stateAttributesMapping: stateAttributesMapping$2
|
|
2258
1956
|
});
|
|
2259
1957
|
});
|
|
2260
1958
|
if (process.env.NODE_ENV !== "production") MenuViewport.displayName = "MenuViewport";
|
|
2261
1959
|
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
* before a root attaches (or after it unmounts) are ignored.
|
|
2269
|
-
*/
|
|
2270
|
-
class MenuHandle extends DrawerDescription.BasePopupHandle {
|
|
1960
|
+
class MenuHandle {
|
|
1961
|
+
/**
|
|
1962
|
+
* Internal store holding the menu's state.
|
|
1963
|
+
* @internal
|
|
1964
|
+
*/
|
|
1965
|
+
|
|
2271
1966
|
constructor() {
|
|
2272
|
-
|
|
1967
|
+
this.store = new MenuSubmenuTrigger.MenuStore();
|
|
2273
1968
|
}
|
|
2274
1969
|
|
|
2275
1970
|
/**
|
|
2276
1971
|
* Opens the menu and associates it with the trigger with the given id.
|
|
1972
|
+
* The trigger must be a Menu.Trigger component with this handle passed as a prop.
|
|
2277
1973
|
*
|
|
2278
|
-
*
|
|
2279
|
-
*
|
|
2280
|
-
* @param triggerId ID of the trigger to associate with the menu. The trigger must be a matching
|
|
2281
|
-
* `Menu.Trigger` with this handle passed as a prop.
|
|
1974
|
+
* @param triggerId ID of the trigger to associate with the menu.
|
|
2282
1975
|
*/
|
|
2283
1976
|
open(triggerId) {
|
|
2284
|
-
this.
|
|
1977
|
+
const triggerElement = triggerId ? this.store.context.triggerElements.getById(triggerId) : undefined;
|
|
1978
|
+
if (triggerId && !triggerElement) {
|
|
1979
|
+
throw new Error(process.env.NODE_ENV !== "production" ? `Base UI: MenuHandle.open: No trigger found with id "${triggerId}".` : useRenderElement.formatErrorMessage(83, triggerId));
|
|
1980
|
+
}
|
|
1981
|
+
this.store.setOpen(true, useScrollLock.createChangeEventDetails('imperative-action', undefined, triggerElement));
|
|
2285
1982
|
}
|
|
2286
1983
|
|
|
2287
1984
|
/**
|
|
2288
1985
|
* Closes the menu.
|
|
2289
|
-
*
|
|
2290
|
-
* This method should only be called in an event handler or an effect (not during rendering).
|
|
2291
1986
|
*/
|
|
2292
1987
|
close() {
|
|
2293
|
-
this.
|
|
1988
|
+
this.store.setOpen(false, useScrollLock.createChangeEventDetails('imperative-action', undefined, undefined));
|
|
2294
1989
|
}
|
|
2295
1990
|
|
|
2296
1991
|
/**
|
|
2297
|
-
*
|
|
1992
|
+
* Indicates whether the menu is currently open.
|
|
2298
1993
|
*/
|
|
2299
1994
|
get isOpen() {
|
|
2300
|
-
return this.
|
|
1995
|
+
return this.store.select('open');
|
|
2301
1996
|
}
|
|
2302
1997
|
}
|
|
2303
1998
|
|
|
@@ -2344,6 +2039,20 @@ function useScrollAreaScrollbarContext() {
|
|
|
2344
2039
|
return context;
|
|
2345
2040
|
}
|
|
2346
2041
|
|
|
2042
|
+
let ScrollAreaScrollbarCssVars = /*#__PURE__*/function (ScrollAreaScrollbarCssVars) {
|
|
2043
|
+
/**
|
|
2044
|
+
* The scroll area thumb's height.
|
|
2045
|
+
* @type {number}
|
|
2046
|
+
*/
|
|
2047
|
+
ScrollAreaScrollbarCssVars["scrollAreaThumbHeight"] = "--scroll-area-thumb-height";
|
|
2048
|
+
/**
|
|
2049
|
+
* The scroll area thumb's width.
|
|
2050
|
+
* @type {number}
|
|
2051
|
+
*/
|
|
2052
|
+
ScrollAreaScrollbarCssVars["scrollAreaThumbWidth"] = "--scroll-area-thumb-width";
|
|
2053
|
+
return ScrollAreaScrollbarCssVars;
|
|
2054
|
+
}({});
|
|
2055
|
+
|
|
2347
2056
|
/**
|
|
2348
2057
|
* A vertical or horizontal scrollbar for the scroll area.
|
|
2349
2058
|
* Renders a `<div>` element.
|
|
@@ -2364,6 +2073,7 @@ const ScrollAreaScrollbar = /*#__PURE__*/React__namespace.forwardRef(function Sc
|
|
|
2364
2073
|
scrollingX,
|
|
2365
2074
|
scrollingY,
|
|
2366
2075
|
hiddenState,
|
|
2076
|
+
overflowEdges,
|
|
2367
2077
|
scrollbarYRef,
|
|
2368
2078
|
scrollbarXRef,
|
|
2369
2079
|
viewportRef,
|
|
@@ -2372,37 +2082,43 @@ const ScrollAreaScrollbar = /*#__PURE__*/React__namespace.forwardRef(function Sc
|
|
|
2372
2082
|
handlePointerDown,
|
|
2373
2083
|
handlePointerUp,
|
|
2374
2084
|
handleScroll,
|
|
2375
|
-
disableViewportSnap,
|
|
2376
2085
|
rootId,
|
|
2377
2086
|
thumbSize,
|
|
2378
|
-
hasMeasuredScrollbar
|
|
2379
|
-
viewportState
|
|
2087
|
+
hasMeasuredScrollbar
|
|
2380
2088
|
} = ScrollAreaViewport.useScrollAreaRootContext();
|
|
2381
|
-
const vertical = orientation === 'vertical';
|
|
2382
2089
|
const state = {
|
|
2383
|
-
...viewportState,
|
|
2384
2090
|
hovering,
|
|
2385
|
-
scrolling:
|
|
2386
|
-
|
|
2091
|
+
scrolling: {
|
|
2092
|
+
horizontal: scrollingX,
|
|
2093
|
+
vertical: scrollingY
|
|
2094
|
+
}[orientation],
|
|
2095
|
+
orientation,
|
|
2096
|
+
hasOverflowX: !hiddenState.x,
|
|
2097
|
+
hasOverflowY: !hiddenState.y,
|
|
2098
|
+
overflowXStart: overflowEdges.xStart,
|
|
2099
|
+
overflowXEnd: overflowEdges.xEnd,
|
|
2100
|
+
overflowYStart: overflowEdges.yStart,
|
|
2101
|
+
overflowYEnd: overflowEdges.yEnd,
|
|
2102
|
+
cornerHidden: hiddenState.corner
|
|
2387
2103
|
};
|
|
2388
2104
|
const direction = useScrollLock.useDirection();
|
|
2389
2105
|
const hideTrackUntilMeasured = !hasMeasuredScrollbar && !keepMounted;
|
|
2390
|
-
const isHidden = vertical ? hiddenState.y : hiddenState.x;
|
|
2106
|
+
const isHidden = orientation === 'vertical' ? hiddenState.y : hiddenState.x;
|
|
2391
2107
|
const shouldRender = keepMounted || !isHidden;
|
|
2392
2108
|
React__namespace.useEffect(() => {
|
|
2393
2109
|
if (!shouldRender) {
|
|
2394
2110
|
return undefined;
|
|
2395
2111
|
}
|
|
2396
2112
|
const viewportEl = viewportRef.current;
|
|
2397
|
-
const scrollbarEl = vertical ? scrollbarYRef.current : scrollbarXRef.current;
|
|
2113
|
+
const scrollbarEl = orientation === 'vertical' ? scrollbarYRef.current : scrollbarXRef.current;
|
|
2398
2114
|
if (!scrollbarEl) {
|
|
2399
2115
|
return undefined;
|
|
2400
2116
|
}
|
|
2401
2117
|
function handleWheel(event) {
|
|
2402
|
-
if (!viewportEl || event.ctrlKey) {
|
|
2118
|
+
if (!viewportEl || !scrollbarEl || event.ctrlKey) {
|
|
2403
2119
|
return;
|
|
2404
2120
|
}
|
|
2405
|
-
const horizontal =
|
|
2121
|
+
const horizontal = orientation === 'horizontal';
|
|
2406
2122
|
const scrollProperty = horizontal ? 'scrollLeft' : 'scrollTop';
|
|
2407
2123
|
const delta = horizontal ? event.deltaX : event.deltaY;
|
|
2408
2124
|
if (delta === 0) {
|
|
@@ -2429,7 +2145,7 @@ const ScrollAreaScrollbar = /*#__PURE__*/React__namespace.forwardRef(function Sc
|
|
|
2429
2145
|
return useScrollLock.addEventListener(scrollbarEl, 'wheel', handleWheel, {
|
|
2430
2146
|
passive: false
|
|
2431
2147
|
});
|
|
2432
|
-
}, [direction, handleScroll,
|
|
2148
|
+
}, [direction, handleScroll, orientation, scrollbarXRef, scrollbarYRef, shouldRender, viewportRef]);
|
|
2433
2149
|
const props = {
|
|
2434
2150
|
...(rootId && {
|
|
2435
2151
|
'data-id': `${rootId}-scrollbar`
|
|
@@ -2439,55 +2155,58 @@ const ScrollAreaScrollbar = /*#__PURE__*/React__namespace.forwardRef(function Sc
|
|
|
2439
2155
|
return;
|
|
2440
2156
|
}
|
|
2441
2157
|
const target = useScrollLock.getTarget(event.nativeEvent);
|
|
2442
|
-
const
|
|
2158
|
+
const thumb = orientation === 'vertical' ? thumbYRef.current : thumbXRef.current;
|
|
2443
2159
|
|
|
2444
2160
|
// Ignore clicks on thumb, including cases where React retargets the
|
|
2445
2161
|
// synthetic event to the track host across a shadow boundary.
|
|
2446
|
-
if (
|
|
2447
|
-
return;
|
|
2448
|
-
}
|
|
2449
|
-
const viewportEl = viewportRef.current;
|
|
2450
|
-
if (!viewportEl) {
|
|
2451
|
-
return;
|
|
2452
|
-
}
|
|
2453
|
-
const scrollbarEl = vertical ? scrollbarYRef.current : scrollbarXRef.current;
|
|
2454
|
-
if (!thumbEl || !scrollbarEl) {
|
|
2162
|
+
if (thumb && useScrollLock.contains(thumb, target)) {
|
|
2455
2163
|
return;
|
|
2456
2164
|
}
|
|
2457
|
-
|
|
2458
|
-
const thumbOffset = ScrollAreaViewport.getOffset(thumbEl, 'margin', axis);
|
|
2459
|
-
const scrollbarOffset = ScrollAreaViewport.getOffset(scrollbarEl, 'padding', axis);
|
|
2460
|
-
const thumbSizePx = vertical ? thumbEl.offsetHeight : thumbEl.offsetWidth;
|
|
2461
|
-
const trackRect = scrollbarEl.getBoundingClientRect();
|
|
2462
|
-
const clickPosition = vertical ? event.clientY - trackRect.top - thumbSizePx / 2 - scrollbarOffset + thumbOffset / 2 : event.clientX - trackRect.left - thumbSizePx / 2 - scrollbarOffset + thumbOffset / 2;
|
|
2463
|
-
const scrollableSize = vertical ? viewportEl.scrollHeight : viewportEl.scrollWidth;
|
|
2464
|
-
const viewportSize = vertical ? viewportEl.clientHeight : viewportEl.clientWidth;
|
|
2465
|
-
const trackSize = vertical ? scrollbarEl.offsetHeight : scrollbarEl.offsetWidth;
|
|
2466
|
-
const maxThumbOffset = trackSize - thumbSizePx - scrollbarOffset - thumbOffset;
|
|
2467
|
-
// A short or heavily padded track can drive `maxThumbOffset` to zero or
|
|
2468
|
-
// negative once the thumb hits its `MIN_THUMB_SIZE` floor. Dividing by it
|
|
2469
|
-
// would yield a non-finite (`Infinity`/`NaN`) or inverted scroll position.
|
|
2470
|
-
if (maxThumbOffset <= 0) {
|
|
2165
|
+
if (!viewportRef.current) {
|
|
2471
2166
|
return;
|
|
2472
2167
|
}
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2168
|
+
|
|
2169
|
+
// Handle Y-axis (vertical) scroll
|
|
2170
|
+
if (thumbYRef.current && scrollbarYRef.current && orientation === 'vertical') {
|
|
2171
|
+
const thumbYOffset = ScrollAreaViewport.getOffset(thumbYRef.current, 'margin', 'y');
|
|
2172
|
+
const scrollbarYOffset = ScrollAreaViewport.getOffset(scrollbarYRef.current, 'padding', 'y');
|
|
2173
|
+
const thumbHeight = thumbYRef.current.offsetHeight;
|
|
2174
|
+
const trackRectY = scrollbarYRef.current.getBoundingClientRect();
|
|
2175
|
+
const clickY = event.clientY - trackRectY.top - thumbHeight / 2 - scrollbarYOffset + thumbYOffset / 2;
|
|
2176
|
+
const scrollableContentHeight = viewportRef.current.scrollHeight;
|
|
2177
|
+
const viewportHeight = viewportRef.current.clientHeight;
|
|
2178
|
+
const maxThumbOffsetY = scrollbarYRef.current.offsetHeight - thumbHeight - scrollbarYOffset - thumbYOffset;
|
|
2179
|
+
const scrollRatioY = clickY / maxThumbOffsetY;
|
|
2180
|
+
const newScrollTop = scrollRatioY * (scrollableContentHeight - viewportHeight);
|
|
2181
|
+
viewportRef.current.scrollTop = newScrollTop;
|
|
2182
|
+
}
|
|
2183
|
+
if (thumbXRef.current && scrollbarXRef.current && orientation === 'horizontal') {
|
|
2184
|
+
const thumbXOffset = ScrollAreaViewport.getOffset(thumbXRef.current, 'margin', 'x');
|
|
2185
|
+
const scrollbarXOffset = ScrollAreaViewport.getOffset(scrollbarXRef.current, 'padding', 'x');
|
|
2186
|
+
const thumbWidth = thumbXRef.current.offsetWidth;
|
|
2187
|
+
const trackRectX = scrollbarXRef.current.getBoundingClientRect();
|
|
2188
|
+
const clickX = event.clientX - trackRectX.left - thumbWidth / 2 - scrollbarXOffset + thumbXOffset / 2;
|
|
2189
|
+
const scrollableContentWidth = viewportRef.current.scrollWidth;
|
|
2190
|
+
const viewportWidth = viewportRef.current.clientWidth;
|
|
2191
|
+
const maxThumbOffsetX = scrollbarXRef.current.offsetWidth - thumbWidth - scrollbarXOffset - thumbXOffset;
|
|
2192
|
+
const scrollRatioX = clickX / maxThumbOffsetX;
|
|
2193
|
+
let newScrollLeft;
|
|
2194
|
+
if (direction === 'rtl') {
|
|
2195
|
+
// In RTL, invert the scroll direction
|
|
2196
|
+
newScrollLeft = (1 - scrollRatioX) * (scrollableContentWidth - viewportWidth);
|
|
2197
|
+
|
|
2198
|
+
// Adjust for browsers that use negative scrollLeft in RTL
|
|
2199
|
+
if (viewportRef.current.scrollLeft <= 0) {
|
|
2200
|
+
newScrollLeft = -newScrollLeft;
|
|
2201
|
+
}
|
|
2202
|
+
} else {
|
|
2203
|
+
newScrollLeft = scrollRatioX * (scrollableContentWidth - viewportWidth);
|
|
2204
|
+
}
|
|
2205
|
+
viewportRef.current.scrollLeft = newScrollLeft;
|
|
2487
2206
|
}
|
|
2488
2207
|
handleScroll({
|
|
2489
|
-
x:
|
|
2490
|
-
y:
|
|
2208
|
+
x: viewportRef.current.scrollLeft,
|
|
2209
|
+
y: viewportRef.current.scrollTop
|
|
2491
2210
|
});
|
|
2492
2211
|
handlePointerDown(event);
|
|
2493
2212
|
},
|
|
@@ -2501,30 +2220,34 @@ const ScrollAreaScrollbar = /*#__PURE__*/React__namespace.forwardRef(function Sc
|
|
|
2501
2220
|
WebkitUserSelect: 'none',
|
|
2502
2221
|
userSelect: 'none',
|
|
2503
2222
|
visibility: hideTrackUntilMeasured ? 'hidden' : undefined,
|
|
2504
|
-
...(vertical
|
|
2223
|
+
...(orientation === 'vertical' && {
|
|
2505
2224
|
top: 0,
|
|
2506
|
-
bottom:
|
|
2225
|
+
bottom: `var(${ScrollAreaViewport.ScrollAreaRootCssVars.scrollAreaCornerHeight})`,
|
|
2507
2226
|
insetInlineEnd: 0,
|
|
2508
|
-
[
|
|
2509
|
-
}
|
|
2227
|
+
[ScrollAreaScrollbarCssVars.scrollAreaThumbHeight]: `${thumbSize.height}px`
|
|
2228
|
+
}),
|
|
2229
|
+
...(orientation === 'horizontal' && {
|
|
2510
2230
|
insetInlineStart: 0,
|
|
2511
|
-
insetInlineEnd:
|
|
2231
|
+
insetInlineEnd: `var(${ScrollAreaViewport.ScrollAreaRootCssVars.scrollAreaCornerWidth})`,
|
|
2512
2232
|
bottom: 0,
|
|
2513
|
-
[
|
|
2233
|
+
[ScrollAreaScrollbarCssVars.scrollAreaThumbWidth]: `${thumbSize.width}px`
|
|
2514
2234
|
})
|
|
2515
2235
|
}
|
|
2516
2236
|
};
|
|
2517
2237
|
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
2518
|
-
ref: [forwardedRef, vertical ? scrollbarYRef : scrollbarXRef],
|
|
2238
|
+
ref: [forwardedRef, orientation === 'vertical' ? scrollbarYRef : scrollbarXRef],
|
|
2519
2239
|
state,
|
|
2520
2240
|
props: [props, elementProps],
|
|
2521
2241
|
stateAttributesMapping: ScrollAreaViewport.scrollAreaStateAttributesMapping
|
|
2522
2242
|
});
|
|
2243
|
+
const contextValue = React__namespace.useMemo(() => ({
|
|
2244
|
+
orientation
|
|
2245
|
+
}), [orientation]);
|
|
2523
2246
|
if (!shouldRender) {
|
|
2524
2247
|
return null;
|
|
2525
2248
|
}
|
|
2526
2249
|
return /*#__PURE__*/jsxRuntime.jsx(ScrollAreaScrollbarContext.Provider, {
|
|
2527
|
-
value:
|
|
2250
|
+
value: contextValue,
|
|
2528
2251
|
children: element
|
|
2529
2252
|
});
|
|
2530
2253
|
});
|
|
@@ -2612,30 +2335,43 @@ const ScrollAreaThumb = /*#__PURE__*/React__namespace.forwardRef(function Scroll
|
|
|
2612
2335
|
handlePointerDown,
|
|
2613
2336
|
handlePointerMove,
|
|
2614
2337
|
handlePointerUp,
|
|
2338
|
+
setScrollingX,
|
|
2339
|
+
setScrollingY,
|
|
2615
2340
|
scrollingX,
|
|
2616
2341
|
scrollingY,
|
|
2617
2342
|
hasMeasuredScrollbar
|
|
2618
2343
|
} = ScrollAreaViewport.useScrollAreaRootContext();
|
|
2619
|
-
const
|
|
2620
|
-
|
|
2344
|
+
const {
|
|
2345
|
+
orientation
|
|
2346
|
+
} = useScrollAreaScrollbarContext();
|
|
2621
2347
|
const state = {
|
|
2622
|
-
scrolling:
|
|
2348
|
+
scrolling: orientation === 'horizontal' ? scrollingX : scrollingY,
|
|
2623
2349
|
orientation
|
|
2624
2350
|
};
|
|
2351
|
+
function endDrag(event) {
|
|
2352
|
+
if (orientation === 'vertical') {
|
|
2353
|
+
setScrollingY(false);
|
|
2354
|
+
}
|
|
2355
|
+
if (orientation === 'horizontal') {
|
|
2356
|
+
setScrollingX(false);
|
|
2357
|
+
}
|
|
2358
|
+
handlePointerUp(event);
|
|
2359
|
+
}
|
|
2625
2360
|
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
2626
|
-
ref: [forwardedRef, vertical ? thumbYRef : thumbXRef],
|
|
2361
|
+
ref: [forwardedRef, orientation === 'vertical' ? thumbYRef : thumbXRef],
|
|
2627
2362
|
state,
|
|
2628
2363
|
props: [{
|
|
2629
2364
|
onPointerDown: handlePointerDown,
|
|
2630
2365
|
onPointerMove: handlePointerMove,
|
|
2631
|
-
onPointerUp:
|
|
2632
|
-
onPointerCancel:
|
|
2366
|
+
onPointerUp: endDrag,
|
|
2367
|
+
onPointerCancel: endDrag,
|
|
2633
2368
|
style: {
|
|
2634
2369
|
visibility: hasMeasuredScrollbar ? undefined : 'hidden',
|
|
2635
|
-
...(vertical
|
|
2636
|
-
height:
|
|
2637
|
-
}
|
|
2638
|
-
|
|
2370
|
+
...(orientation === 'vertical' && {
|
|
2371
|
+
height: `var(${ScrollAreaScrollbarCssVars.scrollAreaThumbHeight})`
|
|
2372
|
+
}),
|
|
2373
|
+
...(orientation === 'horizontal' && {
|
|
2374
|
+
width: `var(${ScrollAreaScrollbarCssVars.scrollAreaThumbWidth})`
|
|
2639
2375
|
})
|
|
2640
2376
|
}
|
|
2641
2377
|
}, elementProps]
|
|
@@ -2693,34 +2429,34 @@ var index_parts$3 = /*#__PURE__*/Object.freeze({
|
|
|
2693
2429
|
|
|
2694
2430
|
var index_parts$2 = /*#__PURE__*/Object.freeze({
|
|
2695
2431
|
__proto__: null,
|
|
2696
|
-
Arrow:
|
|
2697
|
-
Backdrop:
|
|
2698
|
-
Chip:
|
|
2699
|
-
ChipRemove:
|
|
2700
|
-
Chips:
|
|
2701
|
-
Clear:
|
|
2702
|
-
Collection:
|
|
2703
|
-
Empty:
|
|
2704
|
-
Group:
|
|
2705
|
-
GroupLabel:
|
|
2706
|
-
Icon:
|
|
2707
|
-
Input:
|
|
2708
|
-
InputGroup:
|
|
2709
|
-
Item:
|
|
2710
|
-
ItemIndicator:
|
|
2711
|
-
Label:
|
|
2712
|
-
List:
|
|
2713
|
-
Popup:
|
|
2714
|
-
Portal:
|
|
2715
|
-
Positioner:
|
|
2716
|
-
Root:
|
|
2717
|
-
Row:
|
|
2718
|
-
Separator:
|
|
2719
|
-
Status:
|
|
2720
|
-
Trigger:
|
|
2721
|
-
Value:
|
|
2722
|
-
useFilter:
|
|
2723
|
-
useFilteredItems:
|
|
2432
|
+
Arrow: ComboboxChipRemove.ComboboxArrow,
|
|
2433
|
+
Backdrop: ComboboxChipRemove.ComboboxBackdrop,
|
|
2434
|
+
Chip: ComboboxChipRemove.ComboboxChip,
|
|
2435
|
+
ChipRemove: ComboboxChipRemove.ComboboxChipRemove,
|
|
2436
|
+
Chips: ComboboxChipRemove.ComboboxChips,
|
|
2437
|
+
Clear: ComboboxChipRemove.ComboboxClear,
|
|
2438
|
+
Collection: ComboboxChipRemove.ComboboxCollection,
|
|
2439
|
+
Empty: ComboboxChipRemove.ComboboxEmpty,
|
|
2440
|
+
Group: ComboboxChipRemove.ComboboxGroup,
|
|
2441
|
+
GroupLabel: ComboboxChipRemove.ComboboxGroupLabel,
|
|
2442
|
+
Icon: ComboboxChipRemove.ComboboxIcon,
|
|
2443
|
+
Input: ComboboxChipRemove.ComboboxInput,
|
|
2444
|
+
InputGroup: ComboboxChipRemove.ComboboxInputGroup,
|
|
2445
|
+
Item: ComboboxChipRemove.ComboboxItem,
|
|
2446
|
+
ItemIndicator: ComboboxChipRemove.ComboboxItemIndicator,
|
|
2447
|
+
Label: ComboboxChipRemove.ComboboxLabel,
|
|
2448
|
+
List: ComboboxChipRemove.ComboboxList,
|
|
2449
|
+
Popup: ComboboxChipRemove.ComboboxPopup,
|
|
2450
|
+
Portal: ComboboxChipRemove.ComboboxPortal,
|
|
2451
|
+
Positioner: ComboboxChipRemove.ComboboxPositioner,
|
|
2452
|
+
Root: ComboboxChipRemove.ComboboxRoot,
|
|
2453
|
+
Row: ComboboxChipRemove.ComboboxRow,
|
|
2454
|
+
Separator: Separator.Separator,
|
|
2455
|
+
Status: ComboboxChipRemove.ComboboxStatus,
|
|
2456
|
+
Trigger: ComboboxChipRemove.ComboboxTrigger,
|
|
2457
|
+
Value: ComboboxChipRemove.ComboboxValue,
|
|
2458
|
+
useFilter: ComboboxChipRemove.useComboboxFilter,
|
|
2459
|
+
useFilteredItems: ComboboxChipRemove.useFilteredItems
|
|
2724
2460
|
});
|
|
2725
2461
|
|
|
2726
2462
|
const NumberFieldScrubAreaContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
@@ -2735,7 +2471,7 @@ function useNumberFieldScrubAreaContext() {
|
|
|
2735
2471
|
|
|
2736
2472
|
// Calculates the bounds the virtual cursor wraps within, as absolute edge coordinates.
|
|
2737
2473
|
function getViewportRect(teleportDistance, scrubAreaEl) {
|
|
2738
|
-
const win =
|
|
2474
|
+
const win = floatingUi_utils.getWindow(scrubAreaEl);
|
|
2739
2475
|
if (teleportDistance != null) {
|
|
2740
2476
|
const rect = scrubAreaEl.getBoundingClientRect();
|
|
2741
2477
|
return {
|
|
@@ -2762,6 +2498,22 @@ function getViewportRect(teleportDistance, scrubAreaEl) {
|
|
|
2762
2498
|
};
|
|
2763
2499
|
}
|
|
2764
2500
|
|
|
2501
|
+
// This lets us invert the scale of the cursor to match the OS scale, in which the cursor doesn't
|
|
2502
|
+
// scale with the content on pinch-zoom.
|
|
2503
|
+
function subscribeToVisualViewportResize(element, visualScaleRef) {
|
|
2504
|
+
const vV = floatingUi_utils.getWindow(element).visualViewport;
|
|
2505
|
+
if (!vV) {
|
|
2506
|
+
return () => {};
|
|
2507
|
+
}
|
|
2508
|
+
function handleVisualResize() {
|
|
2509
|
+
if (vV) {
|
|
2510
|
+
visualScaleRef.current = vV.scale;
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
handleVisualResize();
|
|
2514
|
+
return useScrollLock.addEventListener(vV, 'resize', handleVisualResize);
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2765
2517
|
const SCRUB_AREA_STYLE = {
|
|
2766
2518
|
touchAction: 'none',
|
|
2767
2519
|
WebkitUserSelect: 'none',
|
|
@@ -2787,6 +2539,8 @@ const NumberFieldScrubArea = /*#__PURE__*/React__namespace.forwardRef(function N
|
|
|
2787
2539
|
const {
|
|
2788
2540
|
state,
|
|
2789
2541
|
setIsScrubbing: setRootScrubbing,
|
|
2542
|
+
disabled,
|
|
2543
|
+
readOnly,
|
|
2790
2544
|
inputRef,
|
|
2791
2545
|
incrementValue,
|
|
2792
2546
|
allowInputSyncRef,
|
|
@@ -2795,10 +2549,6 @@ const NumberFieldScrubArea = /*#__PURE__*/React__namespace.forwardRef(function N
|
|
|
2795
2549
|
lastChangedValueRef,
|
|
2796
2550
|
valueRef
|
|
2797
2551
|
} = NumberFieldInput.useNumberFieldRootContext();
|
|
2798
|
-
const {
|
|
2799
|
-
disabled,
|
|
2800
|
-
readOnly
|
|
2801
|
-
} = state;
|
|
2802
2552
|
const scrubAreaRef = React__namespace.useRef(null);
|
|
2803
2553
|
const isScrubbingRef = React__namespace.useRef(false);
|
|
2804
2554
|
const didMoveRef = React__namespace.useRef(false);
|
|
@@ -2808,15 +2558,21 @@ const NumberFieldScrubArea = /*#__PURE__*/React__namespace.forwardRef(function N
|
|
|
2808
2558
|
x: 0,
|
|
2809
2559
|
y: 0
|
|
2810
2560
|
});
|
|
2561
|
+
const visualScaleRef = React__namespace.useRef(1);
|
|
2811
2562
|
const exitPointerLockTimeout = useScrollLock.useTimeout();
|
|
2812
2563
|
const [isTouchInput, setIsTouchInput] = React__namespace.useState(false);
|
|
2813
2564
|
const [isPointerLockDenied, setIsPointerLockDenied] = React__namespace.useState(false);
|
|
2814
2565
|
const [isScrubbing, setIsScrubbing] = React__namespace.useState(false);
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2566
|
+
React__namespace.useEffect(() => {
|
|
2567
|
+
if (!isScrubbing || !scrubAreaCursorRef.current) {
|
|
2568
|
+
return undefined;
|
|
2569
|
+
}
|
|
2570
|
+
return subscribeToVisualViewportResize(scrubAreaCursorRef.current, visualScaleRef);
|
|
2571
|
+
}, [isScrubbing]);
|
|
2572
|
+
function updateCursorTransform(x, y) {
|
|
2573
|
+
if (scrubAreaCursorRef.current) {
|
|
2574
|
+
scrubAreaCursorRef.current.style.transform = `translate3d(${x}px,${y}px,0) scale(${1 / visualScaleRef.current})`;
|
|
2575
|
+
}
|
|
2820
2576
|
}
|
|
2821
2577
|
const onScrub = useScrollLock.useStableCallback(({
|
|
2822
2578
|
movementX,
|
|
@@ -2829,23 +2585,24 @@ const NumberFieldScrubArea = /*#__PURE__*/React__namespace.forwardRef(function N
|
|
|
2829
2585
|
}
|
|
2830
2586
|
const rect = getViewportRect(teleportDistance, scrubAreaEl);
|
|
2831
2587
|
const coords = virtualCursorCoords.current;
|
|
2832
|
-
|
|
2833
|
-
// Wrap the cursor to the opposite edge when its center crosses a viewport bound.
|
|
2834
|
-
const wrap = (coord, halfSize, low, high) => {
|
|
2835
|
-
if (coord + halfSize < low) {
|
|
2836
|
-
return high - halfSize;
|
|
2837
|
-
}
|
|
2838
|
-
if (coord + halfSize > high) {
|
|
2839
|
-
return low - halfSize;
|
|
2840
|
-
}
|
|
2841
|
-
return coord;
|
|
2842
|
-
};
|
|
2843
2588
|
const newCoords = {
|
|
2844
|
-
x:
|
|
2845
|
-
y:
|
|
2589
|
+
x: Math.round(coords.x + movementX),
|
|
2590
|
+
y: Math.round(coords.y + movementY)
|
|
2846
2591
|
};
|
|
2592
|
+
const cursorWidth = virtualCursor.offsetWidth;
|
|
2593
|
+
const cursorHeight = virtualCursor.offsetHeight;
|
|
2594
|
+
if (newCoords.x + cursorWidth / 2 < rect.left) {
|
|
2595
|
+
newCoords.x = rect.right - cursorWidth / 2;
|
|
2596
|
+
} else if (newCoords.x + cursorWidth / 2 > rect.right) {
|
|
2597
|
+
newCoords.x = rect.left - cursorWidth / 2;
|
|
2598
|
+
}
|
|
2599
|
+
if (newCoords.y + cursorHeight / 2 < rect.top) {
|
|
2600
|
+
newCoords.y = rect.bottom - cursorHeight / 2;
|
|
2601
|
+
} else if (newCoords.y + cursorHeight / 2 > rect.bottom) {
|
|
2602
|
+
newCoords.y = rect.top - cursorHeight / 2;
|
|
2603
|
+
}
|
|
2847
2604
|
virtualCursorCoords.current = newCoords;
|
|
2848
|
-
updateCursorTransform(
|
|
2605
|
+
updateCursorTransform(newCoords.x, newCoords.y);
|
|
2849
2606
|
});
|
|
2850
2607
|
const onScrubbingChange = useScrollLock.useStableCallback((scrubbingValue, {
|
|
2851
2608
|
clientX,
|
|
@@ -2864,7 +2621,7 @@ const NumberFieldScrubArea = /*#__PURE__*/React__namespace.forwardRef(function N
|
|
|
2864
2621
|
y: clientY - virtualCursor.offsetHeight / 2
|
|
2865
2622
|
};
|
|
2866
2623
|
virtualCursorCoords.current = initialCoords;
|
|
2867
|
-
updateCursorTransform(
|
|
2624
|
+
updateCursorTransform(initialCoords.x, initialCoords.y);
|
|
2868
2625
|
});
|
|
2869
2626
|
React__namespace.useEffect(function registerGlobalScrubbingEventListeners() {
|
|
2870
2627
|
// Only listen while actively scrubbing; avoids unrelated pointerup events committing.
|
|
@@ -2888,7 +2645,7 @@ const NumberFieldScrubArea = /*#__PURE__*/React__namespace.forwardRef(function N
|
|
|
2888
2645
|
const pointerDownTarget = pointerDownTargetRef.current;
|
|
2889
2646
|
const input = inputRef.current;
|
|
2890
2647
|
if (!didMoveRef.current && pointerDownTarget != null && input) {
|
|
2891
|
-
pointerDownTarget.dispatchEvent(new (
|
|
2648
|
+
pointerDownTarget.dispatchEvent(new (floatingUi_utils.getWindow(input).MouseEvent)('click', {
|
|
2892
2649
|
bubbles: true,
|
|
2893
2650
|
cancelable: true
|
|
2894
2651
|
}));
|
|
@@ -2906,9 +2663,6 @@ const NumberFieldScrubArea = /*#__PURE__*/React__namespace.forwardRef(function N
|
|
|
2906
2663
|
}
|
|
2907
2664
|
}
|
|
2908
2665
|
function handleScrubPointerMove(event) {
|
|
2909
|
-
// The effects below can tear down and re-run without unmounting (`<Activity>`), which
|
|
2910
|
-
// clears the ref while `isScrubbing` stays `true` and re-attaches this listener. The ref
|
|
2911
|
-
// is the source of truth for whether a pointer is actually down.
|
|
2912
2666
|
if (!isScrubbingRef.current) {
|
|
2913
2667
|
return;
|
|
2914
2668
|
}
|
|
@@ -2937,7 +2691,7 @@ const NumberFieldScrubArea = /*#__PURE__*/React__namespace.forwardRef(function N
|
|
|
2937
2691
|
}
|
|
2938
2692
|
}
|
|
2939
2693
|
}
|
|
2940
|
-
const win =
|
|
2694
|
+
const win = floatingUi_utils.getWindow(inputRef.current);
|
|
2941
2695
|
const unsubscribe = useScrollLock.mergeCleanups(useScrollLock.addEventListener(win, 'pointerup', handleScrubPointerUp, true), useScrollLock.addEventListener(win, 'pointermove', handleScrubPointerMove, true));
|
|
2942
2696
|
return () => {
|
|
2943
2697
|
exitPointerLockTimeout.clear();
|
|
@@ -2976,7 +2730,8 @@ const NumberFieldScrubArea = /*#__PURE__*/React__namespace.forwardRef(function N
|
|
|
2976
2730
|
role: 'presentation',
|
|
2977
2731
|
style: SCRUB_AREA_STYLE,
|
|
2978
2732
|
async onPointerDown(event) {
|
|
2979
|
-
|
|
2733
|
+
const isMainButton = !event.button || event.button === 0;
|
|
2734
|
+
if (event.defaultPrevented || readOnly || !isMainButton || disabled) {
|
|
2980
2735
|
return;
|
|
2981
2736
|
}
|
|
2982
2737
|
const isTouch = event.pointerType === 'touch';
|
|
@@ -3116,8 +2871,7 @@ const SelectLabel = /*#__PURE__*/React__namespace.forwardRef(function SelectLabe
|
|
|
3116
2871
|
id: defaultLabelId,
|
|
3117
2872
|
fallbackControlId: triggerElement?.id ?? rootId,
|
|
3118
2873
|
setLabelId(nextLabelId) {
|
|
3119
|
-
|
|
3120
|
-
store.set('labelId', resolvedLabelId);
|
|
2874
|
+
store.set('labelId', nextLabelId);
|
|
3121
2875
|
}
|
|
3122
2876
|
});
|
|
3123
2877
|
return useRenderElement.useRenderElement('div', componentProps, {
|
|
@@ -3162,7 +2916,7 @@ const SelectIcon = /*#__PURE__*/React__namespace.forwardRef(function SelectIcon(
|
|
|
3162
2916
|
});
|
|
3163
2917
|
if (process.env.NODE_ENV !== "production") SelectIcon.displayName = "SelectIcon";
|
|
3164
2918
|
|
|
3165
|
-
const stateAttributesMapping = {
|
|
2919
|
+
const stateAttributesMapping$1 = {
|
|
3166
2920
|
...useScrollLock.popupStateMapping,
|
|
3167
2921
|
...useScrollLock.transitionStatusMapping
|
|
3168
2922
|
};
|
|
@@ -3201,12 +2955,17 @@ const SelectBackdrop = /*#__PURE__*/React__namespace.forwardRef(function SelectB
|
|
|
3201
2955
|
WebkitUserSelect: 'none'
|
|
3202
2956
|
}
|
|
3203
2957
|
}, elementProps],
|
|
3204
|
-
stateAttributesMapping
|
|
2958
|
+
stateAttributesMapping: stateAttributesMapping$1
|
|
3205
2959
|
});
|
|
3206
2960
|
return element;
|
|
3207
2961
|
});
|
|
3208
2962
|
if (process.env.NODE_ENV !== "production") SelectBackdrop.displayName = "SelectBackdrop";
|
|
3209
2963
|
|
|
2964
|
+
const stateAttributesMapping = {
|
|
2965
|
+
...useScrollLock.popupStateMapping,
|
|
2966
|
+
...useScrollLock.transitionStatusMapping
|
|
2967
|
+
};
|
|
2968
|
+
|
|
3210
2969
|
/**
|
|
3211
2970
|
* Displays an element positioned against the select popup anchor.
|
|
3212
2971
|
* Renders a `<div>` element.
|
|
@@ -3245,7 +3004,7 @@ const SelectArrow = /*#__PURE__*/React__namespace.forwardRef(function SelectArro
|
|
|
3245
3004
|
style: arrowStyles,
|
|
3246
3005
|
'aria-hidden': true
|
|
3247
3006
|
}, elementProps],
|
|
3248
|
-
stateAttributesMapping
|
|
3007
|
+
stateAttributesMapping
|
|
3249
3008
|
});
|
|
3250
3009
|
if (alignItemWithTriggerActive) {
|
|
3251
3010
|
return null;
|
|
@@ -3263,7 +3022,7 @@ const SelectScrollArrow = /*#__PURE__*/React__namespace.forwardRef(function Sele
|
|
|
3263
3022
|
className,
|
|
3264
3023
|
style,
|
|
3265
3024
|
direction,
|
|
3266
|
-
keepMounted,
|
|
3025
|
+
keepMounted = false,
|
|
3267
3026
|
...elementProps
|
|
3268
3027
|
} = componentProps;
|
|
3269
3028
|
const isUp = direction === 'up';
|
|
@@ -3294,10 +3053,12 @@ const SelectScrollArrow = /*#__PURE__*/React__namespace.forwardRef(function Sele
|
|
|
3294
3053
|
} = useScrollLock.useTransitionStatus(visible);
|
|
3295
3054
|
useScrollLock.useIsoLayoutEffect(() => {
|
|
3296
3055
|
scrollArrowsMountedCountRef.current += 1;
|
|
3297
|
-
store.
|
|
3056
|
+
if (!store.state.hasScrollArrows) {
|
|
3057
|
+
store.set('hasScrollArrows', true);
|
|
3058
|
+
}
|
|
3298
3059
|
return () => {
|
|
3299
3060
|
scrollArrowsMountedCountRef.current = Math.max(0, scrollArrowsMountedCountRef.current - 1);
|
|
3300
|
-
if (scrollArrowsMountedCountRef.current === 0) {
|
|
3061
|
+
if (scrollArrowsMountedCountRef.current === 0 && store.state.hasScrollArrows) {
|
|
3301
3062
|
store.set('hasScrollArrows', false);
|
|
3302
3063
|
}
|
|
3303
3064
|
};
|
|
@@ -3334,7 +3095,7 @@ const SelectScrollArrow = /*#__PURE__*/React__namespace.forwardRef(function Sele
|
|
|
3334
3095
|
return;
|
|
3335
3096
|
}
|
|
3336
3097
|
store.set('activeIndex', null);
|
|
3337
|
-
handleScrollArrowVisibility(
|
|
3098
|
+
handleScrollArrowVisibility();
|
|
3338
3099
|
const maxScrollTop = scrollEdges.getMaxScrollOffset(scroller.scrollHeight, scroller.clientHeight);
|
|
3339
3100
|
const scrollTop = scrollEdges.normalizeScrollOffset(scroller.scrollTop, maxScrollTop);
|
|
3340
3101
|
const isScrolledToEdge = scrollTop === (isUp ? 0 : maxScrollTop);
|
|
@@ -3342,6 +3103,11 @@ const SelectScrollArrow = /*#__PURE__*/React__namespace.forwardRef(function Sele
|
|
|
3342
3103
|
if (scrollTop !== scroller.scrollTop) {
|
|
3343
3104
|
scroller.scrollTop = scrollTop;
|
|
3344
3105
|
}
|
|
3106
|
+
|
|
3107
|
+
// Fallback when there are no items registered yet.
|
|
3108
|
+
if (items.length === 0) {
|
|
3109
|
+
store.set(isUp ? 'scrollUpArrowVisible' : 'scrollDownArrowVisible', !isScrolledToEdge);
|
|
3110
|
+
}
|
|
3345
3111
|
if (isScrolledToEdge) {
|
|
3346
3112
|
timeout.clear();
|
|
3347
3113
|
return;
|
|
@@ -3430,14 +3196,6 @@ const SelectScrollUpArrow = /*#__PURE__*/React__namespace.forwardRef(function Se
|
|
|
3430
3196
|
});
|
|
3431
3197
|
if (process.env.NODE_ENV !== "production") SelectScrollUpArrow.displayName = "SelectScrollUpArrow";
|
|
3432
3198
|
|
|
3433
|
-
/**
|
|
3434
|
-
* A visual separator between items or groups.
|
|
3435
|
-
* Renders a `<div>` element.
|
|
3436
|
-
*
|
|
3437
|
-
* Documentation: [Base UI Select](https://base-ui.com/react/components/select)
|
|
3438
|
-
*/
|
|
3439
|
-
const SelectSeparator = ComboboxSeparator.ListboxSeparator;
|
|
3440
|
-
|
|
3441
3199
|
var index_parts = /*#__PURE__*/Object.freeze({
|
|
3442
3200
|
__proto__: null,
|
|
3443
3201
|
Arrow: SelectArrow,
|
|
@@ -3456,7 +3214,7 @@ var index_parts = /*#__PURE__*/Object.freeze({
|
|
|
3456
3214
|
Root: SelectGroupLabel.SelectRoot,
|
|
3457
3215
|
ScrollDownArrow: SelectScrollDownArrow,
|
|
3458
3216
|
ScrollUpArrow: SelectScrollUpArrow,
|
|
3459
|
-
Separator:
|
|
3217
|
+
Separator: Separator.Separator,
|
|
3460
3218
|
Trigger: SelectGroupLabel.SelectTrigger,
|
|
3461
3219
|
Value: SelectGroupLabel.SelectValue
|
|
3462
3220
|
});
|