@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
|
@@ -5,8 +5,8 @@ var useRenderElement = require('./useRenderElement-cjs.js');
|
|
|
5
5
|
var useScrollLock = require('./useScrollLock-cjs.js');
|
|
6
6
|
var scrollEdges = require('./scrollEdges-cjs.js');
|
|
7
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
+
var floatingUi_utils = require('./floating-ui.utils-cjs.js');
|
|
8
9
|
var ReactDOM = require('react-dom');
|
|
9
|
-
var scrollable = require('./scrollable-cjs.js');
|
|
10
10
|
|
|
11
11
|
function _interopNamespaceDefault(e) {
|
|
12
12
|
var n = Object.create(null);
|
|
@@ -80,12 +80,12 @@ function createPopupFloatingRootContext(triggerElements, floatingId, nested = fa
|
|
|
80
80
|
onOpenChange: undefined
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
|
-
const activeTriggerIdSelector = state => state.triggerIdProp ?? state.activeTriggerId;
|
|
84
|
-
const openSelector = state => state.openProp ?? state.open;
|
|
85
|
-
const popupIdSelector = state => {
|
|
83
|
+
const activeTriggerIdSelector = useScrollLock.createSelector(state => state.triggerIdProp ?? state.activeTriggerId);
|
|
84
|
+
const openSelector = useScrollLock.createSelector(state => state.openProp ?? state.open);
|
|
85
|
+
const popupIdSelector = useScrollLock.createSelector(state => {
|
|
86
86
|
const popupId = state.popupElement?.id ?? state.floatingId;
|
|
87
87
|
return popupId || undefined;
|
|
88
|
-
};
|
|
88
|
+
});
|
|
89
89
|
function triggerOwnsOpenPopup(state, triggerId) {
|
|
90
90
|
return triggerId !== undefined && openSelector(state) && activeTriggerIdSelector(state) === triggerId;
|
|
91
91
|
}
|
|
@@ -97,81 +97,47 @@ function triggerOwnsOpenPopupOrIsOnlyTrigger(state, triggerId) {
|
|
|
97
97
|
}
|
|
98
98
|
const popupStoreSelectors = {
|
|
99
99
|
open: openSelector,
|
|
100
|
-
mounted: state => state.mounted,
|
|
101
|
-
transitionStatus: state => state.transitionStatus,
|
|
102
|
-
floatingRootContext: state => state.floatingRootContext,
|
|
103
|
-
triggerCount: state => state.triggerCount,
|
|
104
|
-
preventUnmountingOnClose: state => state.preventUnmountingOnClose,
|
|
105
|
-
payload: state => state.payload,
|
|
100
|
+
mounted: useScrollLock.createSelector(state => state.mounted),
|
|
101
|
+
transitionStatus: useScrollLock.createSelector(state => state.transitionStatus),
|
|
102
|
+
floatingRootContext: useScrollLock.createSelector(state => state.floatingRootContext),
|
|
103
|
+
triggerCount: useScrollLock.createSelector(state => state.triggerCount),
|
|
104
|
+
preventUnmountingOnClose: useScrollLock.createSelector(state => state.preventUnmountingOnClose),
|
|
105
|
+
payload: useScrollLock.createSelector(state => state.payload),
|
|
106
106
|
activeTriggerId: activeTriggerIdSelector,
|
|
107
|
-
activeTriggerElement: state => state.mounted ? state.activeTriggerElement : null,
|
|
107
|
+
activeTriggerElement: useScrollLock.createSelector(state => state.mounted ? state.activeTriggerElement : null),
|
|
108
108
|
popupId: popupIdSelector,
|
|
109
109
|
/**
|
|
110
110
|
* Whether the trigger with the given ID was used to open the popup.
|
|
111
111
|
*/
|
|
112
|
-
isTriggerActive: (state, triggerId) => triggerId !== undefined && activeTriggerIdSelector(state) === triggerId,
|
|
112
|
+
isTriggerActive: useScrollLock.createSelector((state, triggerId) => triggerId !== undefined && activeTriggerIdSelector(state) === triggerId),
|
|
113
113
|
/**
|
|
114
114
|
* Whether the popup is open and was activated by a trigger with the given ID.
|
|
115
115
|
*/
|
|
116
|
-
isOpenedByTrigger: (state, triggerId) => triggerOwnsOpenPopup(state, triggerId),
|
|
116
|
+
isOpenedByTrigger: useScrollLock.createSelector((state, triggerId) => triggerOwnsOpenPopup(state, triggerId)),
|
|
117
117
|
/**
|
|
118
118
|
* Whether the popup is mounted and was activated by a trigger with the given ID.
|
|
119
119
|
*/
|
|
120
|
-
isMountedByTrigger: (state, triggerId) => triggerId !== undefined && activeTriggerIdSelector(state) === triggerId && state.mounted,
|
|
121
|
-
triggerProps: (state, isActive) => isActive ? state.activeTriggerProps : state.inactiveTriggerProps,
|
|
120
|
+
isMountedByTrigger: useScrollLock.createSelector((state, triggerId) => triggerId !== undefined && activeTriggerIdSelector(state) === triggerId && state.mounted),
|
|
121
|
+
triggerProps: useScrollLock.createSelector((state, isActive) => isActive ? state.activeTriggerProps : state.inactiveTriggerProps),
|
|
122
122
|
/**
|
|
123
123
|
* Popup id for the trigger that currently owns the open popup.
|
|
124
124
|
*/
|
|
125
|
-
triggerPopupId: (state, triggerId) => triggerOwnsOpenPopupOrIsOnlyTrigger(state, triggerId) ? popupIdSelector(state) : undefined,
|
|
126
|
-
popupProps: state => state.popupProps,
|
|
127
|
-
popupElement: state => state.popupElement,
|
|
128
|
-
positionerElement: state => state.positionerElement
|
|
125
|
+
triggerPopupId: useScrollLock.createSelector((state, triggerId) => triggerOwnsOpenPopupOrIsOnlyTrigger(state, triggerId) ? popupIdSelector(state) : undefined),
|
|
126
|
+
popupProps: useScrollLock.createSelector(state => state.popupProps),
|
|
127
|
+
popupElement: useScrollLock.createSelector(state => state.popupElement),
|
|
128
|
+
positionerElement: useScrollLock.createSelector(state => state.positionerElement)
|
|
129
129
|
};
|
|
130
130
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
* forwarding. `set`/`update` are included only for trigger-count and trigger-data bookkeeping; on a
|
|
134
|
-
* detached (inert) store they are intentionally no-ops, so a write through them is not guaranteed to
|
|
135
|
-
* be durable. Component handle-store views Pick these from their concrete store (preserving its
|
|
136
|
-
* context and selectors) and add any component-specific trigger-invoked members such as `setOpen`.
|
|
137
|
-
*/
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* The subset of a popup store that trigger registration and data forwarding rely on. Narrow enough
|
|
141
|
-
* that an inert store can be passed while detached.
|
|
142
|
-
*/
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Reads the store currently exposed by a popup handle and subscribes to store-pointer changes.
|
|
146
|
-
* Detached triggers use this to follow a handle as a root attaches or detaches: while no root is
|
|
147
|
-
* attached, the handle exposes its fallback store; once a root attaches, subscribers re-render and
|
|
148
|
-
* read from the live root store.
|
|
149
|
-
*
|
|
150
|
-
* Returns `undefined` when no handle is provided so callers can fall back to their root context.
|
|
151
|
-
*
|
|
152
|
-
* @param handle The popup handle to read from, or `undefined` when the trigger is not handle-bound.
|
|
153
|
-
*/
|
|
154
|
-
function usePopupHandleStore(handle) {
|
|
155
|
-
const subscribe = React__namespace.useCallback(listener => {
|
|
156
|
-
if (handle === undefined) {
|
|
157
|
-
return useRenderElement.NOOP;
|
|
158
|
-
}
|
|
159
|
-
return handle.subscribeStore(listener);
|
|
160
|
-
}, [handle]);
|
|
161
|
-
const getSnapshot = React__namespace.useCallback(() => {
|
|
162
|
-
return handle === undefined ? undefined : handle.store;
|
|
163
|
-
}, [handle]);
|
|
164
|
-
return useScrollLock.shimExports.useSyncExternalStore(subscribe, getSnapshot, () => handle?.serverStore);
|
|
165
|
-
}
|
|
166
|
-
|
|
131
|
+
const IsDrawerContext = /*#__PURE__*/React__namespace.createContext(false);
|
|
132
|
+
if (process.env.NODE_ENV !== "production") IsDrawerContext.displayName = "IsDrawerContext";
|
|
167
133
|
const DialogRootContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
168
134
|
if (process.env.NODE_ENV !== "production") DialogRootContext.displayName = "DialogRootContext";
|
|
169
135
|
function useDialogRootContext(optional) {
|
|
170
|
-
const
|
|
171
|
-
if (
|
|
136
|
+
const dialogRootContext = React__namespace.useContext(DialogRootContext);
|
|
137
|
+
if (optional === false && dialogRootContext === undefined) {
|
|
172
138
|
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: DialogRootContext is missing. Dialog parts must be placed within <Dialog.Root>.' : useRenderElement.formatErrorMessage(27));
|
|
173
139
|
}
|
|
174
|
-
return
|
|
140
|
+
return dialogRootContext;
|
|
175
141
|
}
|
|
176
142
|
|
|
177
143
|
const DialogPortalContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
@@ -184,26 +150,14 @@ function useDialogPortalContext() {
|
|
|
184
150
|
return value;
|
|
185
151
|
}
|
|
186
152
|
|
|
187
|
-
/**
|
|
188
|
-
* Shared by `Dialog.Popup` and `Dialog.Viewport`, whose states have the same shape.
|
|
189
|
-
* `nested` is not mapped: unmapped `true` booleans already render as `data-nested`.
|
|
190
|
-
*/
|
|
191
|
-
const dialogStateAttributesMapping = {
|
|
192
|
-
...useScrollLock.popupStateMapping,
|
|
193
|
-
...useScrollLock.transitionStatusMapping,
|
|
194
|
-
nestedDialogOpen(value) {
|
|
195
|
-
return value ? {
|
|
196
|
-
'data-nested-dialog-open': ''
|
|
197
|
-
} : null;
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
|
|
201
153
|
const DialogPortal = /*#__PURE__*/React__namespace.forwardRef(function DialogPortal(props, forwardedRef) {
|
|
202
154
|
const {
|
|
203
155
|
keepMounted = false,
|
|
204
156
|
...portalProps
|
|
205
157
|
} = props;
|
|
206
|
-
const
|
|
158
|
+
const {
|
|
159
|
+
store
|
|
160
|
+
} = useDialogRootContext();
|
|
207
161
|
const mounted = store.useState('mounted');
|
|
208
162
|
const modal = store.useState('modal');
|
|
209
163
|
const open = store.useState('open');
|
|
@@ -225,6 +179,25 @@ const DialogPortal = /*#__PURE__*/React__namespace.forwardRef(function DialogPor
|
|
|
225
179
|
});
|
|
226
180
|
if (process.env.NODE_ENV !== "production") DialogPortal.displayName = "DialogPortal";
|
|
227
181
|
|
|
182
|
+
function useDialogRoot(params) {
|
|
183
|
+
const {
|
|
184
|
+
store,
|
|
185
|
+
actionsRef
|
|
186
|
+
} = params;
|
|
187
|
+
const open = store.useState('open');
|
|
188
|
+
useScrollLock.usePopupRootSync(store, open);
|
|
189
|
+
useScrollLock.useImplicitActiveTrigger(store);
|
|
190
|
+
const {
|
|
191
|
+
forceUnmount
|
|
192
|
+
} = useScrollLock.useOpenStateTransitions(open, store);
|
|
193
|
+
const handleImperativeClose = React__namespace.useCallback(() => {
|
|
194
|
+
store.setOpen(false, useScrollLock.createChangeEventDetails(useScrollLock.imperativeAction));
|
|
195
|
+
}, [store]);
|
|
196
|
+
React__namespace.useImperativeHandle(actionsRef, () => ({
|
|
197
|
+
unmount: forceUnmount,
|
|
198
|
+
close: handleImperativeClose
|
|
199
|
+
}), [forceUnmount, handleImperativeClose]);
|
|
200
|
+
}
|
|
228
201
|
function DialogInteractions({
|
|
229
202
|
store,
|
|
230
203
|
parentContext,
|
|
@@ -260,18 +233,8 @@ function DialogInteractions({
|
|
|
260
233
|
if ('button' in event && event.button !== 0) {
|
|
261
234
|
return false;
|
|
262
235
|
}
|
|
263
|
-
if ('touches' in event) {
|
|
264
|
-
|
|
265
|
-
// reported in `changedTouches` and `touches` contains any remaining
|
|
266
|
-
// active points. Treat it as a single-finger tap only when exactly one
|
|
267
|
-
// touch ended and no other fingers are still down.
|
|
268
|
-
if (event.type === 'touchend') {
|
|
269
|
-
if (event.changedTouches.length !== 1 || event.touches.length !== 0) {
|
|
270
|
-
return false;
|
|
271
|
-
}
|
|
272
|
-
} else if (event.touches.length !== 1) {
|
|
273
|
-
return false;
|
|
274
|
-
}
|
|
236
|
+
if ('touches' in event && event.touches.length !== 1) {
|
|
237
|
+
return false;
|
|
275
238
|
}
|
|
276
239
|
const target = useScrollLock.getTarget(event);
|
|
277
240
|
if (isTopmost && !disablePointerDismissal) {
|
|
@@ -279,9 +242,7 @@ function DialogInteractions({
|
|
|
279
242
|
// This supports multiple modal dialogs that aren't nested in the React tree:
|
|
280
243
|
// https://github.com/mui/base-ui/issues/1320
|
|
281
244
|
if (modal) {
|
|
282
|
-
|
|
283
|
-
const backdrop = store.context.backdropRef.current;
|
|
284
|
-
return internalBackdrop || backdrop ? internalBackdrop === target || backdrop === target || useScrollLock.contains(target, popupElement) && !target?.hasAttribute('data-base-ui-portal') : true;
|
|
245
|
+
return store.context.internalBackdropRef.current || store.context.backdropRef.current ? store.context.internalBackdropRef.current === target || store.context.backdropRef.current === target || useScrollLock.contains(target, popupElement) && !target?.hasAttribute('data-base-ui-portal') : true;
|
|
285
246
|
}
|
|
286
247
|
return true;
|
|
287
248
|
}
|
|
@@ -292,82 +253,73 @@ function DialogInteractions({
|
|
|
292
253
|
useScrollLock.useScrollLock(open && modal === true, popupElement);
|
|
293
254
|
|
|
294
255
|
// Listen for nested open/close events on this store to maintain the counts.
|
|
295
|
-
// A close notification is an open notification with zeroed counts.
|
|
296
256
|
store.useContextCallback('onNestedDialogOpen', (dialogCount, drawerCount) => {
|
|
297
257
|
setOwnNestedOpenDialogs(dialogCount);
|
|
298
258
|
setOwnNestedOpenDrawers(drawerCount);
|
|
299
259
|
});
|
|
260
|
+
store.useContextCallback('onNestedDialogClose', () => {
|
|
261
|
+
setOwnNestedOpenDialogs(0);
|
|
262
|
+
setOwnNestedOpenDrawers(0);
|
|
263
|
+
});
|
|
300
264
|
|
|
301
265
|
// Notify parent of our open/close state using parent callbacks, if any
|
|
302
|
-
|
|
303
|
-
if (parentContext?.onNestedDialogOpen) {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
}
|
|
266
|
+
React__namespace.useEffect(() => {
|
|
267
|
+
if (parentContext?.onNestedDialogOpen && open) {
|
|
268
|
+
parentContext.onNestedDialogOpen(ownNestedOpenDialogs + 1, ownNestedOpenDrawers + (isDrawer ? 1 : 0));
|
|
269
|
+
}
|
|
270
|
+
if (parentContext?.onNestedDialogClose && !open) {
|
|
271
|
+
parentContext.onNestedDialogClose();
|
|
309
272
|
}
|
|
310
273
|
return () => {
|
|
311
|
-
if (parentContext?.
|
|
312
|
-
parentContext.
|
|
274
|
+
if (parentContext?.onNestedDialogClose && open) {
|
|
275
|
+
parentContext.onNestedDialogClose();
|
|
313
276
|
}
|
|
314
277
|
};
|
|
315
278
|
}, [isDrawer, open, ownNestedOpenDialogs, ownNestedOpenDrawers, parentContext]);
|
|
279
|
+
const activeTriggerProps = dismiss.reference ?? useRenderElement.EMPTY_OBJECT;
|
|
280
|
+
const inactiveTriggerProps = dismiss.trigger ?? useRenderElement.EMPTY_OBJECT;
|
|
281
|
+
// Consumers (DialogPopup/DrawerPopup) already spread `FOCUSABLE_POPUP_PROPS`
|
|
282
|
+
// directly, so the popup props only need to carry the dismiss handlers.
|
|
283
|
+
const popupProps = dismiss.floating ?? useRenderElement.EMPTY_OBJECT;
|
|
316
284
|
useScrollLock.usePopupInteractionProps(store, {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
inactiveTriggerProps: dismiss.trigger,
|
|
321
|
-
// DialogPopup and DrawerPopup spread `FOCUSABLE_POPUP_PROPS` directly, so
|
|
322
|
-
// this only needs to carry the dismiss handlers.
|
|
323
|
-
popupProps: dismiss.floating,
|
|
285
|
+
activeTriggerProps,
|
|
286
|
+
inactiveTriggerProps,
|
|
287
|
+
popupProps,
|
|
324
288
|
nestedOpenDialogCount: ownNestedOpenDialogs,
|
|
325
289
|
nestedOpenDrawerCount: ownNestedOpenDrawers
|
|
326
290
|
});
|
|
327
291
|
return null;
|
|
328
292
|
}
|
|
329
293
|
|
|
330
|
-
/**
|
|
331
|
-
* A `ReactStore` whose state never changes.
|
|
332
|
-
*
|
|
333
|
-
* Useful for fallback stores that need to support normal store reads while detached from the
|
|
334
|
-
* component that owns real state. Context values may still contain mutable refs or maps.
|
|
335
|
-
*/
|
|
336
|
-
class NullStore extends useScrollLock.ReactStore {
|
|
337
|
-
// `update`/`set`/`notifyAll` funnel through `setState` in the base `Store`, so overriding
|
|
338
|
-
// `setState` alone would neutralize them today. They are overridden explicitly so the store stays
|
|
339
|
-
// inert even if a future base-class change stops routing a mutator through `setState`.
|
|
340
|
-
setState(_newState) {}
|
|
341
|
-
update(_changes) {}
|
|
342
|
-
set(_key, _value) {}
|
|
343
|
-
notifyAll() {}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
294
|
const selectors = {
|
|
347
295
|
...popupStoreSelectors,
|
|
348
|
-
modal: state => state.modal,
|
|
349
|
-
nested: state => state.nested,
|
|
350
|
-
nestedOpenDialogCount: state => state.nestedOpenDialogCount,
|
|
351
|
-
nestedOpenDrawerCount: state => state.nestedOpenDrawerCount,
|
|
352
|
-
disablePointerDismissal: state => state.disablePointerDismissal,
|
|
353
|
-
openMethod: state => state.openMethod,
|
|
354
|
-
descriptionElementId: state => state.descriptionElementId,
|
|
355
|
-
titleElementId: state => state.titleElementId,
|
|
356
|
-
viewportElement: state => state.viewportElement,
|
|
357
|
-
role: state => state.role
|
|
296
|
+
modal: useScrollLock.createSelector(state => state.modal),
|
|
297
|
+
nested: useScrollLock.createSelector(state => state.nested),
|
|
298
|
+
nestedOpenDialogCount: useScrollLock.createSelector(state => state.nestedOpenDialogCount),
|
|
299
|
+
nestedOpenDrawerCount: useScrollLock.createSelector(state => state.nestedOpenDrawerCount),
|
|
300
|
+
disablePointerDismissal: useScrollLock.createSelector(state => state.disablePointerDismissal),
|
|
301
|
+
openMethod: useScrollLock.createSelector(state => state.openMethod),
|
|
302
|
+
descriptionElementId: useScrollLock.createSelector(state => state.descriptionElementId),
|
|
303
|
+
titleElementId: useScrollLock.createSelector(state => state.titleElementId),
|
|
304
|
+
viewportElement: useScrollLock.createSelector(state => state.viewportElement),
|
|
305
|
+
role: useScrollLock.createSelector(state => state.role)
|
|
358
306
|
};
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* The subset of `DialogStore` that detached handle-backed triggers rely on. Both the real
|
|
362
|
-
* `DialogStore` and the inert fallback store satisfy it, so a trigger can read from whichever
|
|
363
|
-
* store the handle currently exposes.
|
|
364
|
-
*/
|
|
365
|
-
|
|
366
307
|
class DialogStore extends useScrollLock.ReactStore {
|
|
367
|
-
constructor(initialState, floatingId, nested) {
|
|
308
|
+
constructor(initialState, floatingId, nested = false) {
|
|
368
309
|
const triggerElements = new useScrollLock.PopupTriggerMap();
|
|
369
|
-
const state = createInitialState(initialState
|
|
370
|
-
|
|
310
|
+
const state = createInitialState(initialState);
|
|
311
|
+
state.floatingRootContext = createPopupFloatingRootContext(triggerElements, floatingId, nested);
|
|
312
|
+
super(state, {
|
|
313
|
+
popupRef: /*#__PURE__*/React__namespace.createRef(),
|
|
314
|
+
backdropRef: /*#__PURE__*/React__namespace.createRef(),
|
|
315
|
+
internalBackdropRef: /*#__PURE__*/React__namespace.createRef(),
|
|
316
|
+
outsidePressEnabledRef: {
|
|
317
|
+
current: true
|
|
318
|
+
},
|
|
319
|
+
triggerElements,
|
|
320
|
+
onOpenChange: undefined,
|
|
321
|
+
onOpenChangeComplete: undefined
|
|
322
|
+
}, selectors);
|
|
371
323
|
}
|
|
372
324
|
setOpen = (nextOpen, eventDetails) => {
|
|
373
325
|
eventDetails.preventUnmountOnClose = () => {
|
|
@@ -389,22 +341,20 @@ class DialogStore extends useScrollLock.ReactStore {
|
|
|
389
341
|
useScrollLock.setPopupOpenState(updatedState, nextOpen, eventDetails.trigger);
|
|
390
342
|
this.update(updatedState);
|
|
391
343
|
};
|
|
392
|
-
|
|
344
|
+
static useStore(externalStore, initialState) {
|
|
345
|
+
/* eslint-disable react-hooks/rules-of-hooks */
|
|
346
|
+
const store = useScrollLock.usePopupStore(externalStore, (floatingId, nested) => new DialogStore(initialState, floatingId, nested), true).store;
|
|
347
|
+
/* eslint-enable react-hooks/rules-of-hooks */
|
|
393
348
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
* `Dialog.Root` is attached. It preserves a dialog-specific trigger registry in context so
|
|
397
|
-
* detached triggers can register before migrating to the live root store.
|
|
398
|
-
*/
|
|
399
|
-
function createNullDialogStore() {
|
|
400
|
-
const triggerElements = new useScrollLock.PopupTriggerMap();
|
|
401
|
-
return new NullStore(Object.freeze(createInitialState(undefined, triggerElements)), Object.freeze(createInitialContext(triggerElements)), selectors);
|
|
349
|
+
return store;
|
|
350
|
+
}
|
|
402
351
|
}
|
|
403
|
-
function createInitialState(initialState
|
|
404
|
-
|
|
352
|
+
function createInitialState(initialState = {}) {
|
|
353
|
+
return {
|
|
405
354
|
...createInitialPopupStoreState(),
|
|
406
355
|
modal: true,
|
|
407
356
|
disablePointerDismissal: false,
|
|
357
|
+
popupElement: null,
|
|
408
358
|
viewportElement: null,
|
|
409
359
|
descriptionElementId: undefined,
|
|
410
360
|
titleElementId: undefined,
|
|
@@ -415,24 +365,9 @@ function createInitialState(initialState, triggerElements, floatingId, nested =
|
|
|
415
365
|
role: 'dialog',
|
|
416
366
|
...initialState
|
|
417
367
|
};
|
|
418
|
-
state.floatingRootContext = createPopupFloatingRootContext(triggerElements, floatingId, nested);
|
|
419
|
-
return state;
|
|
420
|
-
}
|
|
421
|
-
function createInitialContext(triggerElements) {
|
|
422
|
-
return {
|
|
423
|
-
popupRef: /*#__PURE__*/React__namespace.createRef(),
|
|
424
|
-
backdropRef: /*#__PURE__*/React__namespace.createRef(),
|
|
425
|
-
internalBackdropRef: /*#__PURE__*/React__namespace.createRef(),
|
|
426
|
-
outsidePressEnabledRef: {
|
|
427
|
-
current: true
|
|
428
|
-
},
|
|
429
|
-
triggerElements,
|
|
430
|
-
onOpenChange: undefined,
|
|
431
|
-
onOpenChangeComplete: undefined
|
|
432
|
-
};
|
|
433
368
|
}
|
|
434
369
|
|
|
435
|
-
function useRenderDialogRoot(
|
|
370
|
+
function useRenderDialogRoot(props, mode = 'dialog') {
|
|
436
371
|
const {
|
|
437
372
|
children,
|
|
438
373
|
open: openProp,
|
|
@@ -451,26 +386,38 @@ function useRenderDialogRoot(mode, props) {
|
|
|
451
386
|
const modal = isAlertDialog ? true : modalProp;
|
|
452
387
|
const disablePointerDismissal = isAlertDialog || disablePointerDismissalProp;
|
|
453
388
|
const role = isAlertDialog ? 'alertdialog' : 'dialog';
|
|
454
|
-
const
|
|
455
|
-
const nested =
|
|
389
|
+
const parentDialogRootContext = useDialogRootContext(true);
|
|
390
|
+
const nested = Boolean(parentDialogRootContext);
|
|
456
391
|
const rootState = {
|
|
457
392
|
modal,
|
|
458
393
|
disablePointerDismissal,
|
|
459
394
|
nested,
|
|
460
395
|
role
|
|
461
396
|
};
|
|
462
|
-
|
|
463
|
-
// The store is owned by this Root instance and created exactly once. It is not tied to the handle:
|
|
464
|
-
// the handle attaches to it, so swapping the handle re-attaches rather than recreating state.
|
|
465
|
-
// Default values are only initial values; controlled values and root state are synced after creation.
|
|
466
|
-
// Dialogs pass the popup element to Floating UI as the floating element (`treatPopupAsFloatingElement`).
|
|
467
|
-
const store = useScrollLock.usePopupRootStore((floatingId, floatingNested) => new DialogStore({
|
|
397
|
+
const store = DialogStore.useStore(handle?.store, {
|
|
468
398
|
open: defaultOpen,
|
|
469
399
|
openProp,
|
|
470
400
|
activeTriggerId: defaultTriggerIdProp,
|
|
471
401
|
triggerIdProp,
|
|
472
402
|
...rootState
|
|
473
|
-
}
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
// Support initially open state when uncontrolled
|
|
406
|
+
useScrollLock.useOnFirstRender(() => {
|
|
407
|
+
const nextState = openProp === undefined && store.state.open === false && defaultOpen === true ? {
|
|
408
|
+
open: true,
|
|
409
|
+
activeTriggerId: defaultTriggerIdProp
|
|
410
|
+
} : null;
|
|
411
|
+
if (isAlertDialog) {
|
|
412
|
+
// Handles can reuse plain Dialog stores; alert dialog invariants must exist immediately.
|
|
413
|
+
store.update(nextState ? {
|
|
414
|
+
...rootState,
|
|
415
|
+
...nextState
|
|
416
|
+
} : rootState);
|
|
417
|
+
} else if (nextState) {
|
|
418
|
+
store.update(nextState);
|
|
419
|
+
}
|
|
420
|
+
});
|
|
474
421
|
store.useControlledProp('openProp', openProp);
|
|
475
422
|
store.useControlledProp('triggerIdProp', triggerIdProp);
|
|
476
423
|
store.useSyncedValues(rootState);
|
|
@@ -479,31 +426,83 @@ function useRenderDialogRoot(mode, props) {
|
|
|
479
426
|
const open = store.useState('open');
|
|
480
427
|
const mounted = store.useState('mounted');
|
|
481
428
|
const payload = store.useState('payload');
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
} = useScrollLock.useOpenStateTransitions(open, store);
|
|
487
|
-
React__namespace.useImperativeHandle(actionsRef, () => ({
|
|
488
|
-
unmount: forceUnmount,
|
|
489
|
-
close: () => store.setOpen(false, useScrollLock.createChangeEventDetails(useScrollLock.imperativeAction))
|
|
490
|
-
}), [forceUnmount, store]);
|
|
429
|
+
useDialogRoot({
|
|
430
|
+
store,
|
|
431
|
+
actionsRef
|
|
432
|
+
});
|
|
491
433
|
const shouldRenderInteractions = open || mounted;
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
434
|
+
const contextValue = React__namespace.useMemo(() => ({
|
|
435
|
+
store
|
|
436
|
+
}), [store]);
|
|
437
|
+
return /*#__PURE__*/jsxRuntime.jsx(IsDrawerContext.Provider, {
|
|
438
|
+
value: false,
|
|
439
|
+
children: /*#__PURE__*/jsxRuntime.jsxs(DialogRootContext.Provider, {
|
|
440
|
+
value: contextValue,
|
|
441
|
+
children: [shouldRenderInteractions && /*#__PURE__*/jsxRuntime.jsx(DialogInteractions, {
|
|
442
|
+
store: store,
|
|
443
|
+
parentContext: parentDialogRootContext?.store.context,
|
|
444
|
+
isDrawer: isDrawer
|
|
445
|
+
}), typeof children === 'function' ? children({
|
|
446
|
+
payload
|
|
447
|
+
}) : children]
|
|
448
|
+
})
|
|
504
449
|
});
|
|
505
450
|
}
|
|
506
451
|
|
|
452
|
+
/**
|
|
453
|
+
* Groups all parts of the dialog.
|
|
454
|
+
* Doesn't render its own HTML element.
|
|
455
|
+
*
|
|
456
|
+
* Documentation: [Base UI Dialog](https://base-ui.com/react/components/dialog)
|
|
457
|
+
*/
|
|
458
|
+
function DialogRoot(props) {
|
|
459
|
+
const mode = React__namespace.useContext(IsDrawerContext) ? 'drawer' : 'dialog';
|
|
460
|
+
return useRenderDialogRoot(props, mode);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
let DialogViewportDataAttributes = function (DialogViewportDataAttributes) {
|
|
464
|
+
/**
|
|
465
|
+
* Present when the dialog is open.
|
|
466
|
+
*/
|
|
467
|
+
DialogViewportDataAttributes[DialogViewportDataAttributes["open"] = useScrollLock.CommonPopupDataAttributes.open] = "open";
|
|
468
|
+
/**
|
|
469
|
+
* Present when the dialog is closed.
|
|
470
|
+
*/
|
|
471
|
+
DialogViewportDataAttributes[DialogViewportDataAttributes["closed"] = useScrollLock.CommonPopupDataAttributes.closed] = "closed";
|
|
472
|
+
/**
|
|
473
|
+
* Present when the dialog is animating in.
|
|
474
|
+
*/
|
|
475
|
+
DialogViewportDataAttributes[DialogViewportDataAttributes["startingStyle"] = useScrollLock.CommonPopupDataAttributes.startingStyle] = "startingStyle";
|
|
476
|
+
/**
|
|
477
|
+
* Present when the dialog is animating out.
|
|
478
|
+
*/
|
|
479
|
+
DialogViewportDataAttributes[DialogViewportDataAttributes["endingStyle"] = useScrollLock.CommonPopupDataAttributes.endingStyle] = "endingStyle";
|
|
480
|
+
/**
|
|
481
|
+
* Present when the dialog is nested within another dialog.
|
|
482
|
+
*/
|
|
483
|
+
DialogViewportDataAttributes["nested"] = "data-nested";
|
|
484
|
+
/**
|
|
485
|
+
* Present when the dialog has other open dialogs nested within it.
|
|
486
|
+
*/
|
|
487
|
+
DialogViewportDataAttributes["nestedDialogOpen"] = "data-nested-dialog-open";
|
|
488
|
+
return DialogViewportDataAttributes;
|
|
489
|
+
}({});
|
|
490
|
+
|
|
491
|
+
const stateAttributesMapping$2 = {
|
|
492
|
+
...useScrollLock.popupStateMapping,
|
|
493
|
+
...useScrollLock.transitionStatusMapping,
|
|
494
|
+
nested(value) {
|
|
495
|
+
return value ? {
|
|
496
|
+
[DialogViewportDataAttributes.nested]: ''
|
|
497
|
+
} : null;
|
|
498
|
+
},
|
|
499
|
+
nestedDialogOpen(value) {
|
|
500
|
+
return value ? {
|
|
501
|
+
[DialogViewportDataAttributes.nestedDialogOpen]: ''
|
|
502
|
+
} : null;
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
|
|
507
506
|
/**
|
|
508
507
|
* A positioning container for the dialog popup that can be made scrollable.
|
|
509
508
|
* Renders a `<div>` element.
|
|
@@ -519,7 +518,9 @@ const DialogViewport = /*#__PURE__*/React__namespace.forwardRef(function DialogV
|
|
|
519
518
|
...elementProps
|
|
520
519
|
} = componentProps;
|
|
521
520
|
const keepMounted = useDialogPortalContext();
|
|
522
|
-
const
|
|
521
|
+
const {
|
|
522
|
+
store
|
|
523
|
+
} = useDialogRootContext();
|
|
523
524
|
const open = store.useState('open');
|
|
524
525
|
const nested = store.useState('nested');
|
|
525
526
|
const transitionStatus = store.useState('transitionStatus');
|
|
@@ -538,7 +539,7 @@ const DialogViewport = /*#__PURE__*/React__namespace.forwardRef(function DialogV
|
|
|
538
539
|
enabled: shouldRender,
|
|
539
540
|
state,
|
|
540
541
|
ref: [forwardedRef, setViewportElement],
|
|
541
|
-
stateAttributesMapping:
|
|
542
|
+
stateAttributesMapping: stateAttributesMapping$2,
|
|
542
543
|
props: [{
|
|
543
544
|
role: 'presentation',
|
|
544
545
|
hidden: !mounted,
|
|
@@ -569,9 +570,8 @@ const DialogTrigger = /*#__PURE__*/React__namespace.forwardRef(function DialogTr
|
|
|
569
570
|
handle,
|
|
570
571
|
...elementProps
|
|
571
572
|
} = componentProps;
|
|
572
|
-
const
|
|
573
|
-
const
|
|
574
|
-
const store = handleStore ?? dialogRootStore;
|
|
573
|
+
const dialogRootContext = useDialogRootContext(true);
|
|
574
|
+
const store = handle?.store ?? dialogRootContext?.store;
|
|
575
575
|
if (!store) {
|
|
576
576
|
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: <Dialog.Trigger> must be used within <Dialog.Root> or provided with a handle.' : useRenderElement.formatErrorMessage(79));
|
|
577
577
|
}
|
|
@@ -593,7 +593,9 @@ const DialogTrigger = /*#__PURE__*/React__namespace.forwardRef(function DialogTr
|
|
|
593
593
|
disabled,
|
|
594
594
|
native: nativeButton
|
|
595
595
|
});
|
|
596
|
-
const click = useScrollLock.useClick(floatingContext
|
|
596
|
+
const click = useScrollLock.useClick(floatingContext, {
|
|
597
|
+
enabled: floatingContext != null
|
|
598
|
+
});
|
|
597
599
|
const interactionTypeProps = useScrollLock.useOpenMethodTriggerProps(() => store.select('open'), interactionType => {
|
|
598
600
|
store.set('openMethod', interactionType);
|
|
599
601
|
});
|
|
@@ -665,6 +667,11 @@ let DrawerBackdropCssVars = /*#__PURE__*/function (DrawerBackdropCssVars) {
|
|
|
665
667
|
return DrawerBackdropCssVars;
|
|
666
668
|
}({});
|
|
667
669
|
|
|
670
|
+
const stateAttributesMapping$1 = {
|
|
671
|
+
...useScrollLock.popupStateMapping,
|
|
672
|
+
...useScrollLock.transitionStatusMapping
|
|
673
|
+
};
|
|
674
|
+
|
|
668
675
|
/**
|
|
669
676
|
* An overlay displayed beneath the popup.
|
|
670
677
|
* Renders a `<div>` element.
|
|
@@ -679,7 +686,9 @@ const DrawerBackdrop = /*#__PURE__*/React__namespace.forwardRef(function DrawerB
|
|
|
679
686
|
forceRender = false,
|
|
680
687
|
...elementProps
|
|
681
688
|
} = componentProps;
|
|
682
|
-
const
|
|
689
|
+
const {
|
|
690
|
+
store
|
|
691
|
+
} = useDialogRootContext();
|
|
683
692
|
const open = store.useState('open');
|
|
684
693
|
const nested = store.useState('nested');
|
|
685
694
|
const mounted = store.useState('mounted');
|
|
@@ -691,7 +700,7 @@ const DrawerBackdrop = /*#__PURE__*/React__namespace.forwardRef(function DrawerB
|
|
|
691
700
|
return useRenderElement.useRenderElement('div', componentProps, {
|
|
692
701
|
state,
|
|
693
702
|
ref: [store.context.backdropRef, forwardedRef],
|
|
694
|
-
stateAttributesMapping:
|
|
703
|
+
stateAttributesMapping: stateAttributesMapping$1,
|
|
695
704
|
props: [{
|
|
696
705
|
role: 'presentation',
|
|
697
706
|
hidden: !mounted,
|
|
@@ -735,8 +744,9 @@ if (process.env.NODE_ENV !== "production") DrawerContent.displayName = "DrawerCo
|
|
|
735
744
|
|
|
736
745
|
const DrawerProviderContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
737
746
|
if (process.env.NODE_ENV !== "production") DrawerProviderContext.displayName = "DrawerProviderContext";
|
|
738
|
-
function useDrawerProviderContext() {
|
|
739
|
-
|
|
747
|
+
function useDrawerProviderContext(optional) {
|
|
748
|
+
const context = React__namespace.useContext(DrawerProviderContext);
|
|
749
|
+
return context;
|
|
740
750
|
}
|
|
741
751
|
|
|
742
752
|
let DrawerPopupDataAttributes = function (DrawerPopupDataAttributes) {
|
|
@@ -749,7 +759,7 @@ let DrawerPopupDataAttributes = function (DrawerPopupDataAttributes) {
|
|
|
749
759
|
*/
|
|
750
760
|
DrawerPopupDataAttributes[DrawerPopupDataAttributes["closed"] = useScrollLock.CommonPopupDataAttributes.closed] = "closed";
|
|
751
761
|
/**
|
|
752
|
-
* Present when the drawer
|
|
762
|
+
* Present when the drawer is animating in.
|
|
753
763
|
*/
|
|
754
764
|
DrawerPopupDataAttributes[DrawerPopupDataAttributes["startingStyle"] = useScrollLock.CommonPopupDataAttributes.startingStyle] = "startingStyle";
|
|
755
765
|
/**
|
|
@@ -788,7 +798,7 @@ const DrawerRootContext = /*#__PURE__*/React__namespace.createContext(undefined)
|
|
|
788
798
|
if (process.env.NODE_ENV !== "production") DrawerRootContext.displayName = "DrawerRootContext";
|
|
789
799
|
function useDrawerRootContext(optional) {
|
|
790
800
|
const drawerRootContext = React__namespace.useContext(DrawerRootContext);
|
|
791
|
-
if (optional
|
|
801
|
+
if (optional === false && drawerRootContext === undefined) {
|
|
792
802
|
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: DrawerRootContext is missing. Drawer parts must be placed within <Drawer.Root>.' : useRenderElement.formatErrorMessage(90));
|
|
793
803
|
}
|
|
794
804
|
return drawerRootContext;
|
|
@@ -829,24 +839,22 @@ function resolveSnapPointValue(snapPoint, viewportHeight, rootFontSize) {
|
|
|
829
839
|
}
|
|
830
840
|
return null;
|
|
831
841
|
}
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
* Returns the index of the value closest to `target`, or `-1` if `values` is empty.
|
|
835
|
-
*/
|
|
836
|
-
function closestSnapPointIndex(values, target) {
|
|
837
|
-
let closestIndex = -1;
|
|
842
|
+
function findClosestSnapPoint(height, points) {
|
|
843
|
+
let closest = null;
|
|
838
844
|
let closestDistance = Infinity;
|
|
839
|
-
for (
|
|
840
|
-
const distance = Math.abs(
|
|
845
|
+
for (const point of points) {
|
|
846
|
+
const distance = Math.abs(point.height - height);
|
|
841
847
|
if (distance < closestDistance) {
|
|
842
848
|
closestDistance = distance;
|
|
843
|
-
|
|
849
|
+
closest = point;
|
|
844
850
|
}
|
|
845
851
|
}
|
|
846
|
-
return
|
|
852
|
+
return closest;
|
|
847
853
|
}
|
|
848
854
|
function useDrawerSnapPoints() {
|
|
849
|
-
const
|
|
855
|
+
const {
|
|
856
|
+
store
|
|
857
|
+
} = useDialogRootContext();
|
|
850
858
|
const {
|
|
851
859
|
snapPoints,
|
|
852
860
|
activeSnapPoint,
|
|
@@ -859,7 +867,12 @@ function useDrawerSnapPoints() {
|
|
|
859
867
|
const measureViewportHeight = useScrollLock.useStableCallback(() => {
|
|
860
868
|
const doc = useScrollLock.ownerDocument(viewportElement);
|
|
861
869
|
const html = doc.documentElement;
|
|
862
|
-
|
|
870
|
+
if (viewportElement) {
|
|
871
|
+
setViewportHeight(viewportElement.offsetHeight);
|
|
872
|
+
}
|
|
873
|
+
if (!viewportElement) {
|
|
874
|
+
setViewportHeight(html.clientHeight);
|
|
875
|
+
}
|
|
863
876
|
const fontSize = parseFloat(getComputedStyle(html).fontSize);
|
|
864
877
|
if (Number.isFinite(fontSize)) {
|
|
865
878
|
setRootFontSize(fontSize);
|
|
@@ -881,9 +894,12 @@ function useDrawerSnapPoints() {
|
|
|
881
894
|
return [];
|
|
882
895
|
}
|
|
883
896
|
const maxHeight = Math.min(popupHeight, viewportHeight);
|
|
897
|
+
if (!Number.isFinite(maxHeight) || maxHeight <= 0) {
|
|
898
|
+
return [];
|
|
899
|
+
}
|
|
884
900
|
const resolved = snapPoints.map(value => {
|
|
885
901
|
const resolvedHeight = resolveSnapPointValue(value, viewportHeight, rootFontSize);
|
|
886
|
-
if (resolvedHeight === null) {
|
|
902
|
+
if (resolvedHeight === null || !Number.isFinite(resolvedHeight)) {
|
|
887
903
|
return null;
|
|
888
904
|
}
|
|
889
905
|
const clampedHeight = scrollEdges.clamp(resolvedHeight, 0, maxHeight);
|
|
@@ -911,6 +927,9 @@ function useDrawerSnapPoints() {
|
|
|
911
927
|
return deduped;
|
|
912
928
|
}, [popupHeight, rootFontSize, snapPoints, viewportHeight]);
|
|
913
929
|
const resolvedActiveSnapPoint = React__namespace.useMemo(() => {
|
|
930
|
+
if (activeSnapPoint === undefined) {
|
|
931
|
+
return resolvedSnapPoints[0];
|
|
932
|
+
}
|
|
914
933
|
if (activeSnapPoint === null) {
|
|
915
934
|
return undefined;
|
|
916
935
|
}
|
|
@@ -920,11 +939,11 @@ function useDrawerSnapPoints() {
|
|
|
920
939
|
}
|
|
921
940
|
const maxHeight = Math.min(popupHeight, viewportHeight);
|
|
922
941
|
const resolvedHeight = resolveSnapPointValue(activeSnapPoint, viewportHeight, rootFontSize);
|
|
923
|
-
if (resolvedHeight === null) {
|
|
942
|
+
if (resolvedHeight === null || !Number.isFinite(resolvedHeight)) {
|
|
924
943
|
return undefined;
|
|
925
944
|
}
|
|
926
945
|
const clampedHeight = scrollEdges.clamp(resolvedHeight, 0, maxHeight);
|
|
927
|
-
return
|
|
946
|
+
return findClosestSnapPoint(clampedHeight, resolvedSnapPoints) ?? undefined;
|
|
928
947
|
}, [activeSnapPoint, popupHeight, resolvedSnapPoints, rootFontSize, viewportHeight]);
|
|
929
948
|
return {
|
|
930
949
|
snapPoints,
|
|
@@ -939,8 +958,9 @@ function useDrawerSnapPoints() {
|
|
|
939
958
|
|
|
940
959
|
const DrawerViewportContext = /*#__PURE__*/React__namespace.createContext(null);
|
|
941
960
|
if (process.env.NODE_ENV !== "production") DrawerViewportContext.displayName = "DrawerViewportContext";
|
|
942
|
-
function useDrawerViewportContext() {
|
|
943
|
-
|
|
961
|
+
function useDrawerViewportContext(optional) {
|
|
962
|
+
const context = React__namespace.useContext(DrawerViewportContext);
|
|
963
|
+
return context;
|
|
944
964
|
}
|
|
945
965
|
|
|
946
966
|
let drawerSwipeVarsRegistered = false;
|
|
@@ -998,7 +1018,8 @@ function removeCSSVariableInheritance$1() {
|
|
|
998
1018
|
drawerSwipeVarsRegistered = true;
|
|
999
1019
|
}
|
|
1000
1020
|
const stateAttributesMapping = {
|
|
1001
|
-
...useScrollLock.
|
|
1021
|
+
...useScrollLock.popupStateMapping,
|
|
1022
|
+
...useScrollLock.transitionStatusMapping,
|
|
1002
1023
|
expanded(value) {
|
|
1003
1024
|
return value ? {
|
|
1004
1025
|
[DrawerPopupDataAttributes.expanded]: ''
|
|
@@ -1015,9 +1036,9 @@ const stateAttributesMapping = {
|
|
|
1015
1036
|
} : null;
|
|
1016
1037
|
},
|
|
1017
1038
|
swipeDirection(value) {
|
|
1018
|
-
return {
|
|
1039
|
+
return value ? {
|
|
1019
1040
|
[DrawerPopupDataAttributes.swipeDirection]: value
|
|
1020
|
-
};
|
|
1041
|
+
} : null;
|
|
1021
1042
|
},
|
|
1022
1043
|
swiping(value) {
|
|
1023
1044
|
return value ? {
|
|
@@ -1041,7 +1062,9 @@ const DrawerPopup = /*#__PURE__*/React__namespace.forwardRef(function DrawerPopu
|
|
|
1041
1062
|
initialFocus,
|
|
1042
1063
|
...elementProps
|
|
1043
1064
|
} = componentProps;
|
|
1044
|
-
const
|
|
1065
|
+
const {
|
|
1066
|
+
store
|
|
1067
|
+
} = useDialogRootContext();
|
|
1045
1068
|
const popupRef = store.context.popupRef;
|
|
1046
1069
|
const {
|
|
1047
1070
|
swipeDirection,
|
|
@@ -1080,8 +1103,6 @@ const DrawerPopup = /*#__PURE__*/React__namespace.forwardRef(function DrawerPopu
|
|
|
1080
1103
|
const swipeStrength = swipe?.swipeStrength ?? null;
|
|
1081
1104
|
const [popupHeight, setPopupHeight] = React__namespace.useState(0);
|
|
1082
1105
|
const popupHeightRef = React__namespace.useRef(0);
|
|
1083
|
-
|
|
1084
|
-
/* istanbul ignore else -- process.env.NODE_ENV is a build-time constant. */
|
|
1085
1106
|
if (process.env.NODE_ENV !== 'production') {
|
|
1086
1107
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
1087
1108
|
React__namespace.useEffect(() => {
|
|
@@ -1164,7 +1185,7 @@ const DrawerPopup = /*#__PURE__*/React__namespace.forwardRef(function DrawerPopu
|
|
|
1164
1185
|
}
|
|
1165
1186
|
};
|
|
1166
1187
|
}, [nestedSwipeProgressStore, popupRef]);
|
|
1167
|
-
|
|
1188
|
+
React__namespace.useEffect(() => {
|
|
1168
1189
|
if (!open) {
|
|
1169
1190
|
return undefined;
|
|
1170
1191
|
}
|
|
@@ -1173,7 +1194,7 @@ const DrawerPopup = /*#__PURE__*/React__namespace.forwardRef(function DrawerPopu
|
|
|
1173
1194
|
notifyParentFrontmostHeight?.(0);
|
|
1174
1195
|
};
|
|
1175
1196
|
}, [frontmostHeight, open, notifyParentFrontmostHeight]);
|
|
1176
|
-
|
|
1197
|
+
React__namespace.useEffect(() => {
|
|
1177
1198
|
if (!notifyParentHasNestedDrawer) {
|
|
1178
1199
|
return undefined;
|
|
1179
1200
|
}
|
|
@@ -1217,7 +1238,7 @@ const DrawerPopup = /*#__PURE__*/React__namespace.forwardRef(function DrawerPopu
|
|
|
1217
1238
|
let dragStyles = swipe ? swipe.getDragStyles() : useRenderElement.EMPTY_OBJECT;
|
|
1218
1239
|
if (shouldApplySnapPoints && swipeDirection === 'down') {
|
|
1219
1240
|
const baseOffset = activeSnapPointOffset ?? 0;
|
|
1220
|
-
const movementValue = Number.parseFloat(String(dragStyles[DrawerPopupCssVars.swipeMovementY]));
|
|
1241
|
+
const movementValue = Number.parseFloat(String(dragStyles[DrawerPopupCssVars.swipeMovementY] ?? 0));
|
|
1221
1242
|
if (swiping && Number.isFinite(movementValue)) {
|
|
1222
1243
|
dragStyles = {
|
|
1223
1244
|
...dragStyles,
|
|
@@ -1327,7 +1348,6 @@ function DrawerRoot(props) {
|
|
|
1327
1348
|
state: 'snapPoint'
|
|
1328
1349
|
});
|
|
1329
1350
|
const isNestedDrawerOpenRef = React__namespace.useRef(false);
|
|
1330
|
-
const swipeAreaActiveRef = React__namespace.useRef(false);
|
|
1331
1351
|
const setActiveSnapPoint = useScrollLock.useStableCallback((nextSnapPoint, eventDetails) => {
|
|
1332
1352
|
const resolvedEventDetails = eventDetails ?? useScrollLock.createChangeEventDetails(useScrollLock.none);
|
|
1333
1353
|
onSnapPointChange?.(nextSnapPoint, resolvedEventDetails);
|
|
@@ -1387,7 +1407,6 @@ function DrawerRoot(props) {
|
|
|
1387
1407
|
});
|
|
1388
1408
|
const contextValue = React__namespace.useMemo(() => ({
|
|
1389
1409
|
swipeDirection,
|
|
1390
|
-
swipeAreaActiveRef,
|
|
1391
1410
|
snapToSequentialPoints,
|
|
1392
1411
|
snapPoints,
|
|
1393
1412
|
activeSnapPoint: resolvedActiveSnapPoint,
|
|
@@ -1406,28 +1425,30 @@ function DrawerRoot(props) {
|
|
|
1406
1425
|
notifyParentSwipingChange,
|
|
1407
1426
|
notifyParentSwipeProgressChange,
|
|
1408
1427
|
notifyParentHasNestedDrawer
|
|
1409
|
-
}), [resolvedActiveSnapPoint, frontmostHeight, hasNestedDrawer, nestedSwiping, nestedSwipeProgressStore, notifyParentHasNestedDrawer, notifyParentSwipeProgressChange, notifyParentSwipingChange, notifyParentFrontmostHeight, onNestedDrawerPresenceChange, onNestedFrontmostHeightChange, onNestedSwipeProgressChange, onNestedSwipingChange, onPopupHeightChange, popupHeight, setActiveSnapPoint, snapPoints, snapToSequentialPoints,
|
|
1428
|
+
}), [resolvedActiveSnapPoint, frontmostHeight, hasNestedDrawer, nestedSwiping, nestedSwipeProgressStore, notifyParentHasNestedDrawer, notifyParentSwipeProgressChange, notifyParentSwipingChange, notifyParentFrontmostHeight, onNestedDrawerPresenceChange, onNestedFrontmostHeightChange, onNestedSwipeProgressChange, onNestedSwipingChange, onPopupHeightChange, popupHeight, setActiveSnapPoint, snapPoints, snapToSequentialPoints, swipeDirection]);
|
|
1410
1429
|
const resolvedChildren = typeof children === 'function' ? payload => /*#__PURE__*/jsxRuntime.jsxs(React__namespace.Fragment, {
|
|
1411
1430
|
children: [_DrawerProviderReport || (_DrawerProviderReport = /*#__PURE__*/jsxRuntime.jsx(DrawerProviderReporter, {})), children(payload)]
|
|
1412
1431
|
}) : /*#__PURE__*/jsxRuntime.jsxs(React__namespace.Fragment, {
|
|
1413
1432
|
children: [_DrawerProviderReport2 || (_DrawerProviderReport2 = /*#__PURE__*/jsxRuntime.jsx(DrawerProviderReporter, {})), children]
|
|
1414
1433
|
});
|
|
1415
|
-
const dialog = useRenderDialogRoot('drawer', {
|
|
1416
|
-
open: openProp,
|
|
1417
|
-
defaultOpen,
|
|
1418
|
-
onOpenChange: handleOpenChange,
|
|
1419
|
-
onOpenChangeComplete,
|
|
1420
|
-
disablePointerDismissal,
|
|
1421
|
-
modal,
|
|
1422
|
-
actionsRef,
|
|
1423
|
-
handle,
|
|
1424
|
-
triggerId: triggerIdProp,
|
|
1425
|
-
defaultTriggerId: defaultTriggerIdProp,
|
|
1426
|
-
children: resolvedChildren
|
|
1427
|
-
});
|
|
1428
1434
|
return /*#__PURE__*/jsxRuntime.jsx(DrawerRootContext.Provider, {
|
|
1429
1435
|
value: contextValue,
|
|
1430
|
-
children:
|
|
1436
|
+
children: /*#__PURE__*/jsxRuntime.jsx(IsDrawerContext.Provider, {
|
|
1437
|
+
value: true,
|
|
1438
|
+
children: /*#__PURE__*/jsxRuntime.jsx(DialogRoot, {
|
|
1439
|
+
open: openProp,
|
|
1440
|
+
defaultOpen: defaultOpen,
|
|
1441
|
+
onOpenChange: handleOpenChange,
|
|
1442
|
+
onOpenChangeComplete: onOpenChangeComplete,
|
|
1443
|
+
disablePointerDismissal: disablePointerDismissal,
|
|
1444
|
+
modal: modal,
|
|
1445
|
+
actionsRef: actionsRef,
|
|
1446
|
+
handle: handle,
|
|
1447
|
+
triggerId: triggerIdProp,
|
|
1448
|
+
defaultTriggerId: defaultTriggerIdProp,
|
|
1449
|
+
children: resolvedChildren
|
|
1450
|
+
})
|
|
1451
|
+
})
|
|
1431
1452
|
});
|
|
1432
1453
|
}
|
|
1433
1454
|
function createNestedSwipeProgressStore() {
|
|
@@ -1454,32 +1475,36 @@ function createNestedSwipeProgressStore() {
|
|
|
1454
1475
|
};
|
|
1455
1476
|
}
|
|
1456
1477
|
function DrawerProviderReporter() {
|
|
1478
|
+
const drawerId = useScrollLock.useId();
|
|
1457
1479
|
const providerContext = useDrawerProviderContext();
|
|
1458
|
-
const
|
|
1459
|
-
|
|
1460
|
-
|
|
1480
|
+
const {
|
|
1481
|
+
store
|
|
1482
|
+
} = useDialogRootContext(false);
|
|
1461
1483
|
const open = store.useState('open');
|
|
1462
1484
|
const nestedOpenDialogCount = store.useState('nestedOpenDialogCount');
|
|
1463
1485
|
const popupElement = store.useState('popupElement');
|
|
1464
1486
|
const isTopmost = nestedOpenDialogCount === 0;
|
|
1465
|
-
|
|
1466
|
-
if (!
|
|
1487
|
+
React__namespace.useEffect(() => {
|
|
1488
|
+
if (!providerContext || drawerId == null) {
|
|
1467
1489
|
return undefined;
|
|
1468
1490
|
}
|
|
1469
1491
|
return () => {
|
|
1470
|
-
removeDrawer(
|
|
1492
|
+
providerContext.removeDrawer(drawerId);
|
|
1471
1493
|
};
|
|
1472
|
-
}, [
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1494
|
+
}, [drawerId, providerContext]);
|
|
1495
|
+
React__namespace.useEffect(() => {
|
|
1496
|
+
if (drawerId == null) {
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1499
|
+
providerContext?.setDrawerOpen(drawerId, open);
|
|
1500
|
+
}, [drawerId, open, providerContext]);
|
|
1476
1501
|
React__namespace.useEffect(() => {
|
|
1477
1502
|
// CloseWatcher enables the Android back gesture (Chromium-only).
|
|
1478
1503
|
// Keep this Android-only for now to avoid interfering with Escape/nesting semantics on desktop due to `useDismiss`.
|
|
1479
1504
|
if (!open || !isTopmost || !useScrollLock.android) {
|
|
1480
1505
|
return undefined;
|
|
1481
1506
|
}
|
|
1482
|
-
const win =
|
|
1507
|
+
const win = floatingUi_utils.getWindow(popupElement);
|
|
1483
1508
|
const CloseWatcherCtor = win.CloseWatcher;
|
|
1484
1509
|
if (!CloseWatcherCtor) {
|
|
1485
1510
|
return undefined;
|
|
@@ -1500,11 +1525,53 @@ function DrawerProviderReporter() {
|
|
|
1500
1525
|
return null;
|
|
1501
1526
|
}
|
|
1502
1527
|
|
|
1503
|
-
|
|
1504
|
-
//
|
|
1505
|
-
//
|
|
1506
|
-
|
|
1507
|
-
|
|
1528
|
+
function isScrollable(element, axis,
|
|
1529
|
+
// When true, a container that overflows only once extra space is added (e.g. drawer
|
|
1530
|
+
// keyboard scroll slack) still counts, as long as it has layout size on the axis.
|
|
1531
|
+
allowOverflowIntent = false) {
|
|
1532
|
+
const style = floatingUi_utils.getComputedStyle(element);
|
|
1533
|
+
if (axis === 'vertical') {
|
|
1534
|
+
const overflowY = style.overflowY;
|
|
1535
|
+
if (overflowY !== 'auto' && overflowY !== 'scroll') {
|
|
1536
|
+
return false;
|
|
1537
|
+
}
|
|
1538
|
+
return allowOverflowIntent ? element.clientHeight > 0 : element.scrollHeight > element.clientHeight;
|
|
1539
|
+
}
|
|
1540
|
+
const overflowX = style.overflowX;
|
|
1541
|
+
if (overflowX !== 'auto' && overflowX !== 'scroll') {
|
|
1542
|
+
return false;
|
|
1543
|
+
}
|
|
1544
|
+
return allowOverflowIntent ? element.clientWidth > 0 : element.scrollWidth > element.clientWidth;
|
|
1545
|
+
}
|
|
1546
|
+
function hasScrollableAncestor(target, root, axes) {
|
|
1547
|
+
// `getParentNode` crosses shadow boundaries (and slots), so a target inside a shadow root
|
|
1548
|
+
// still walks up to scrollable ancestors in the light DOM.
|
|
1549
|
+
let node = target;
|
|
1550
|
+
while (floatingUi_utils.isHTMLElement(node) && node !== root && !floatingUi_utils.isLastTraversableNode(node)) {
|
|
1551
|
+
for (const axis of axes) {
|
|
1552
|
+
if (isScrollable(node, axis)) {
|
|
1553
|
+
return true;
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
node = floatingUi_utils.getParentNode(node);
|
|
1557
|
+
}
|
|
1558
|
+
return false;
|
|
1559
|
+
}
|
|
1560
|
+
function findScrollableTouchTarget(target, root, axis = 'vertical', allowOverflowIntent = false) {
|
|
1561
|
+
// `getParentNode` crosses shadow boundaries (and slots), so a target inside a shadow root
|
|
1562
|
+
// still reaches a scrollable ancestor in the light DOM.
|
|
1563
|
+
let node = floatingUi_utils.isHTMLElement(target) ? target : null;
|
|
1564
|
+
while (floatingUi_utils.isHTMLElement(node) && node !== root && !floatingUi_utils.isLastTraversableNode(node)) {
|
|
1565
|
+
if (isScrollable(node, axis, allowOverflowIntent)) {
|
|
1566
|
+
return node;
|
|
1567
|
+
}
|
|
1568
|
+
node = floatingUi_utils.getParentNode(node);
|
|
1569
|
+
}
|
|
1570
|
+
return isScrollable(root, axis, allowOverflowIntent) ? root : null;
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
function getElementAtPoint(doc, x, y) {
|
|
1574
|
+
return typeof doc?.elementFromPoint === 'function' ? doc.elementFromPoint(x, y) : null;
|
|
1508
1575
|
}
|
|
1509
1576
|
|
|
1510
1577
|
const DEFAULT_SWIPE_THRESHOLD = 40;
|
|
@@ -1529,7 +1596,7 @@ function getDisplacement(direction, deltaX, deltaY) {
|
|
|
1529
1596
|
}
|
|
1530
1597
|
}
|
|
1531
1598
|
function getElementTransform(element) {
|
|
1532
|
-
const computedStyle =
|
|
1599
|
+
const computedStyle = floatingUi_utils.getWindow(element).getComputedStyle(element);
|
|
1533
1600
|
const transform = computedStyle.transform;
|
|
1534
1601
|
let translateX = 0;
|
|
1535
1602
|
let translateY = 0;
|
|
@@ -1651,7 +1718,6 @@ function useSwipeDismiss(options) {
|
|
|
1651
1718
|
});
|
|
1652
1719
|
const swipeProgressRef = React__namespace.useRef(0);
|
|
1653
1720
|
const swipeThresholdRef = React__namespace.useRef(swipeThresholdDefault);
|
|
1654
|
-
const swipeThresholdFunctionRef = React__namespace.useRef(null);
|
|
1655
1721
|
const swipeStartTimeRef = React__namespace.useRef(null);
|
|
1656
1722
|
const lastDragSampleRef = React__namespace.useRef(null);
|
|
1657
1723
|
const lastDragVelocityRef = React__namespace.useRef({
|
|
@@ -1673,12 +1739,15 @@ function useSwipeDismiss(options) {
|
|
|
1673
1739
|
if (!direction) {
|
|
1674
1740
|
return;
|
|
1675
1741
|
}
|
|
1742
|
+
if (typeof swipeThresholdProp !== 'function') {
|
|
1743
|
+
swipeThresholdRef.current = swipeThresholdDefault;
|
|
1744
|
+
return;
|
|
1745
|
+
}
|
|
1676
1746
|
const element = elementRef.current;
|
|
1677
|
-
|
|
1678
|
-
if (!element || !thresholdFunction) {
|
|
1747
|
+
if (!element) {
|
|
1679
1748
|
return;
|
|
1680
1749
|
}
|
|
1681
|
-
const value =
|
|
1750
|
+
const value = swipeThresholdProp({
|
|
1682
1751
|
element,
|
|
1683
1752
|
direction
|
|
1684
1753
|
});
|
|
@@ -1756,7 +1825,6 @@ function useSwipeDismiss(options) {
|
|
|
1756
1825
|
setDragDismissed(false);
|
|
1757
1826
|
updateSwipeProgress(0);
|
|
1758
1827
|
swipeThresholdRef.current = swipeThresholdDefault;
|
|
1759
|
-
swipeThresholdFunctionRef.current = null;
|
|
1760
1828
|
dragStartPosRef.current = {
|
|
1761
1829
|
x: 0,
|
|
1762
1830
|
y: 0
|
|
@@ -1797,6 +1865,11 @@ function useSwipeDismiss(options) {
|
|
|
1797
1865
|
lastProgressDetailsRef.current = null;
|
|
1798
1866
|
syncDragStyles(false);
|
|
1799
1867
|
}, [setSwiping, swipeThresholdDefault, syncDragStyles, updateSwipeProgress]);
|
|
1868
|
+
React__namespace.useEffect(() => {
|
|
1869
|
+
if (typeof swipeThresholdProp !== 'function') {
|
|
1870
|
+
swipeThresholdRef.current = swipeThresholdDefault;
|
|
1871
|
+
}
|
|
1872
|
+
}, [swipeThresholdDefault, swipeThresholdProp]);
|
|
1800
1873
|
function getPrimaryPointerPosition(event) {
|
|
1801
1874
|
if ('touches' in event) {
|
|
1802
1875
|
const touch = event.touches[0];
|
|
@@ -1817,19 +1890,19 @@ function useSwipeDismiss(options) {
|
|
|
1817
1890
|
return event.pointerType === 'touch';
|
|
1818
1891
|
}
|
|
1819
1892
|
function getTargetAtPoint(position, nativeEvent) {
|
|
1820
|
-
const
|
|
1821
|
-
const elementAtPoint = getElementAtPoint(
|
|
1893
|
+
const doc = useScrollLock.ownerDocument(elementRef.current);
|
|
1894
|
+
const elementAtPoint = getElementAtPoint(doc, position.x, position.y);
|
|
1822
1895
|
const target = elementAtPoint ?? useScrollLock.getTarget(nativeEvent);
|
|
1823
1896
|
return target;
|
|
1824
1897
|
}
|
|
1825
1898
|
function findGestureScrollableTouchTarget(target, root) {
|
|
1826
1899
|
if (hasHorizontal && !hasVertical) {
|
|
1827
|
-
return
|
|
1900
|
+
return findScrollableTouchTarget(target, root, 'horizontal');
|
|
1828
1901
|
}
|
|
1829
1902
|
if (hasVertical && !hasHorizontal) {
|
|
1830
|
-
return
|
|
1903
|
+
return findScrollableTouchTarget(target, root, 'vertical');
|
|
1831
1904
|
}
|
|
1832
|
-
return
|
|
1905
|
+
return findScrollableTouchTarget(target, root, 'vertical') ?? findScrollableTouchTarget(target, root, 'horizontal');
|
|
1833
1906
|
}
|
|
1834
1907
|
function startSwipeAtPosition(event, position, startOptions) {
|
|
1835
1908
|
swipeFromScrollableRef.current = false;
|
|
@@ -1850,7 +1923,7 @@ function useSwipeDismiss(options) {
|
|
|
1850
1923
|
const element = elementRef.current;
|
|
1851
1924
|
if (ignoreScrollableAncestors && element && target && scrollAxes.length > 0) {
|
|
1852
1925
|
const ignoreAncestors = startOptions?.ignoreScrollableAncestors ?? false;
|
|
1853
|
-
if (!ignoreAncestors &&
|
|
1926
|
+
if (!ignoreAncestors && hasScrollableAncestor(target, element, scrollAxes)) {
|
|
1854
1927
|
return false;
|
|
1855
1928
|
}
|
|
1856
1929
|
}
|
|
@@ -1861,8 +1934,6 @@ function useSwipeDismiss(options) {
|
|
|
1861
1934
|
swipeStartTimeRef.current = getValidTimeStamp(event.timeStamp);
|
|
1862
1935
|
swipeCancelBaselineRef.current = position;
|
|
1863
1936
|
lastMovePosRef.current = position;
|
|
1864
|
-
swipeThresholdRef.current = swipeThresholdDefault;
|
|
1865
|
-
swipeThresholdFunctionRef.current = typeof swipeThresholdProp === 'function' ? swipeThresholdProp : null;
|
|
1866
1937
|
if (element) {
|
|
1867
1938
|
elementSizeRef.current = {
|
|
1868
1939
|
width: element.offsetWidth,
|
|
@@ -1927,9 +1998,12 @@ function useSwipeDismiss(options) {
|
|
|
1927
1998
|
onCancel?.(event.nativeEvent);
|
|
1928
1999
|
}
|
|
1929
2000
|
function applyDirectionalDamping(deltaX, deltaY) {
|
|
1930
|
-
const exponent = value =>
|
|
2001
|
+
const exponent = value => value >= 0 ? value ** 0.5 : -(Math.abs(value) ** 0.5);
|
|
1931
2002
|
const dampAxis = (delta, allowNegative, allowPositive) => {
|
|
1932
|
-
if (!allowNegative && delta < 0
|
|
2003
|
+
if (!allowNegative && delta < 0) {
|
|
2004
|
+
return exponent(delta);
|
|
2005
|
+
}
|
|
2006
|
+
if (!allowPositive && delta > 0) {
|
|
1933
2007
|
return exponent(delta);
|
|
1934
2008
|
}
|
|
1935
2009
|
return delta;
|
|
@@ -1942,16 +2016,29 @@ function useSwipeDismiss(options) {
|
|
|
1942
2016
|
};
|
|
1943
2017
|
}
|
|
1944
2018
|
function canSwipeFromScrollEdgeOnPendingMove(scrollTarget, deltaX, deltaY) {
|
|
1945
|
-
// Swiping toward the axis start edge (down/right) is allowed when scrolled to the start;
|
|
1946
|
-
// toward the end edge (up/left) when scrolled to the end.
|
|
1947
|
-
const canSwipeOnAxis = (delta, scrollOffset, maxScrollOffset, allowTowardStart, allowTowardEnd) => delta > 0 && scrollOffset <= 0 && allowTowardStart || delta < 0 && scrollOffset >= Math.max(0, maxScrollOffset) && allowTowardEnd;
|
|
1948
2019
|
const absDeltaX = Math.abs(deltaX);
|
|
1949
2020
|
const absDeltaY = Math.abs(deltaY);
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
2021
|
+
const useVerticalAxis = hasVertical && deltaY !== 0 && (!hasHorizontal || absDeltaY >= absDeltaX);
|
|
2022
|
+
if (useVerticalAxis) {
|
|
2023
|
+
const maxScrollTop = Math.max(0, scrollTarget.scrollHeight - scrollTarget.clientHeight);
|
|
2024
|
+
const atTop = scrollTarget.scrollTop <= 0;
|
|
2025
|
+
const atBottom = scrollTarget.scrollTop >= maxScrollTop;
|
|
2026
|
+
const movingDown = deltaY > 0;
|
|
2027
|
+
const movingUp = deltaY < 0;
|
|
2028
|
+
const canSwipeDown = movingDown && atTop && allowDown;
|
|
2029
|
+
const canSwipeUp = movingUp && atBottom && allowUp;
|
|
2030
|
+
return canSwipeDown || canSwipeUp;
|
|
2031
|
+
}
|
|
2032
|
+
const useHorizontalAxis = hasHorizontal && deltaX !== 0 && (!hasVertical || absDeltaX > absDeltaY);
|
|
2033
|
+
if (useHorizontalAxis) {
|
|
2034
|
+
const maxScrollLeft = Math.max(0, scrollTarget.scrollWidth - scrollTarget.clientWidth);
|
|
2035
|
+
const atLeft = scrollTarget.scrollLeft <= 0;
|
|
2036
|
+
const atRight = scrollTarget.scrollLeft >= maxScrollLeft;
|
|
2037
|
+
const movingRight = deltaX > 0;
|
|
2038
|
+
const movingLeft = deltaX < 0;
|
|
2039
|
+
const canSwipeRight = movingRight && atLeft && allowRight;
|
|
2040
|
+
const canSwipeLeft = movingLeft && atRight && allowLeft;
|
|
2041
|
+
return canSwipeRight || canSwipeLeft;
|
|
1955
2042
|
}
|
|
1956
2043
|
return null;
|
|
1957
2044
|
}
|
|
@@ -1972,7 +2059,7 @@ function useSwipeDismiss(options) {
|
|
|
1972
2059
|
pendingSwipeRef.current = true;
|
|
1973
2060
|
pendingSwipeStartPosRef.current = startPos;
|
|
1974
2061
|
swipeFromScrollableRef.current = false;
|
|
1975
|
-
sawPrimaryButtonsOnMoveRef.current =
|
|
2062
|
+
sawPrimaryButtonsOnMoveRef.current = false;
|
|
1976
2063
|
const allowedToStart = canStart ? canStart(startPos, {
|
|
1977
2064
|
nativeEvent: event.nativeEvent,
|
|
1978
2065
|
direction: primaryDirection
|
|
@@ -2000,21 +2087,14 @@ function useSwipeDismiss(options) {
|
|
|
2000
2087
|
event.preventDefault();
|
|
2001
2088
|
}
|
|
2002
2089
|
if (isFirstPointerMoveRef.current) {
|
|
2003
|
-
|
|
2004
|
-
//
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
// still registers: on a low-refresh-rate display the whole travel can land in this single
|
|
2010
|
-
// first move, and discarding it would drop the gesture.
|
|
2011
|
-
if (trackDrag) {
|
|
2012
|
-
dragStartPosRef.current = position;
|
|
2013
|
-
const moveTime = getValidTimeStamp(event.timeStamp);
|
|
2014
|
-
if (moveTime !== null) {
|
|
2015
|
-
swipeStartTimeRef.current = moveTime;
|
|
2016
|
-
}
|
|
2090
|
+
// Adjust the starting position to the current position on the first move
|
|
2091
|
+
// to account for the delay between pointerdown and the first pointermove on iOS.
|
|
2092
|
+
dragStartPosRef.current = position;
|
|
2093
|
+
const moveTime = getValidTimeStamp(event.timeStamp);
|
|
2094
|
+
if (moveTime !== null) {
|
|
2095
|
+
swipeStartTimeRef.current = moveTime;
|
|
2017
2096
|
}
|
|
2097
|
+
isFirstPointerMoveRef.current = false;
|
|
2018
2098
|
}
|
|
2019
2099
|
const clientX = position.x;
|
|
2020
2100
|
const clientY = position.y;
|
|
@@ -2102,45 +2182,51 @@ function useSwipeDismiss(options) {
|
|
|
2102
2182
|
newOffsetY += dampedDelta.y;
|
|
2103
2183
|
}
|
|
2104
2184
|
}
|
|
2105
|
-
|
|
2106
|
-
// Only rewrite drag styles when the drag offset actually changed. `syncDragStyles` writes the
|
|
2107
|
-
// raw (undamped) frozen transform and movement vars, relying on the consumer's `onProgress`
|
|
2108
|
-
// to overwrite them with damped styles — but `updateSwipeProgress` dedupes unchanged
|
|
2109
|
-
// deltas and skips `onProgress`. A move that doesn't change the offset (e.g. the cursor
|
|
2110
|
-
// pinned at a screen edge during an off-screen drag, jittering only on the ignored axis)
|
|
2111
|
-
// would otherwise reinstate the raw styles with no correction, jumping the element to the
|
|
2112
|
-
// undamped position.
|
|
2113
|
-
const previousOffset = dragOffsetRef.current;
|
|
2114
|
-
const offsetChanged = newOffsetX !== previousOffset.x || newOffsetY !== previousOffset.y;
|
|
2115
2185
|
dragOffsetRef.current = {
|
|
2116
2186
|
x: newOffsetX,
|
|
2117
2187
|
y: newOffsetY
|
|
2118
2188
|
};
|
|
2119
|
-
|
|
2120
|
-
syncDragStyles(true);
|
|
2121
|
-
}
|
|
2189
|
+
syncDragStyles(true);
|
|
2122
2190
|
recordDragSample({
|
|
2123
2191
|
x: newOffsetX,
|
|
2124
2192
|
y: newOffsetY
|
|
2125
2193
|
}, getValidTimeStamp(event.timeStamp));
|
|
2126
2194
|
const dragDeltaX = newOffsetX - initialTransformRef.current.x;
|
|
2127
2195
|
const dragDeltaY = newOffsetY - initialTransformRef.current.y;
|
|
2128
|
-
const
|
|
2129
|
-
deltaX: dragDeltaX,
|
|
2130
|
-
deltaY: dragDeltaY,
|
|
2131
|
-
direction: intendedSwipeDirectionRef.current
|
|
2132
|
-
};
|
|
2133
|
-
let progress = 0;
|
|
2196
|
+
const swipeDirectionDetails = intendedSwipeDirectionRef.current;
|
|
2134
2197
|
const progressDirection = primaryDirection ?? intendedSwipeDirectionRef.current;
|
|
2135
|
-
if (progressDirection) {
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2198
|
+
if (!progressDirection) {
|
|
2199
|
+
updateSwipeProgress(0, {
|
|
2200
|
+
deltaX: dragDeltaX,
|
|
2201
|
+
deltaY: dragDeltaY,
|
|
2202
|
+
direction: swipeDirectionDetails
|
|
2203
|
+
});
|
|
2204
|
+
return;
|
|
2142
2205
|
}
|
|
2143
|
-
|
|
2206
|
+
const size = progressDirection === 'left' || progressDirection === 'right' ? elementSizeRef.current.width : elementSizeRef.current.height;
|
|
2207
|
+
const scale = initialTransformRef.current.scale || 1;
|
|
2208
|
+
if (size <= 0 || scale <= 0) {
|
|
2209
|
+
updateSwipeProgress(0, {
|
|
2210
|
+
deltaX: dragDeltaX,
|
|
2211
|
+
deltaY: dragDeltaY,
|
|
2212
|
+
direction: swipeDirectionDetails
|
|
2213
|
+
});
|
|
2214
|
+
return;
|
|
2215
|
+
}
|
|
2216
|
+
const progressDisplacement = getDisplacement(progressDirection, newOffsetX - initialTransformRef.current.x, newOffsetY - initialTransformRef.current.y);
|
|
2217
|
+
if (progressDisplacement <= 0) {
|
|
2218
|
+
updateSwipeProgress(0, {
|
|
2219
|
+
deltaX: dragDeltaX,
|
|
2220
|
+
deltaY: dragDeltaY,
|
|
2221
|
+
direction: swipeDirectionDetails
|
|
2222
|
+
});
|
|
2223
|
+
return;
|
|
2224
|
+
}
|
|
2225
|
+
updateSwipeProgress(progressDisplacement / (size * scale), {
|
|
2226
|
+
deltaX: dragDeltaX,
|
|
2227
|
+
deltaY: dragDeltaY,
|
|
2228
|
+
direction: swipeDirectionDetails
|
|
2229
|
+
});
|
|
2144
2230
|
}
|
|
2145
2231
|
const handleEnd = useScrollLock.useStableCallback(event => {
|
|
2146
2232
|
if (!enabled) {
|
|
@@ -2228,9 +2314,33 @@ function useSwipeDismiss(options) {
|
|
|
2228
2314
|
dismissDirection = intendedSwipeDirectionRef.current ?? primaryDirection;
|
|
2229
2315
|
} else {
|
|
2230
2316
|
for (const direction of directions) {
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2317
|
+
switch (direction) {
|
|
2318
|
+
case 'right':
|
|
2319
|
+
if (deltaX > swipeThresholdRef.current) {
|
|
2320
|
+
shouldClose = true;
|
|
2321
|
+
dismissDirection = 'right';
|
|
2322
|
+
}
|
|
2323
|
+
break;
|
|
2324
|
+
case 'left':
|
|
2325
|
+
if (deltaX < -swipeThresholdRef.current) {
|
|
2326
|
+
shouldClose = true;
|
|
2327
|
+
dismissDirection = 'left';
|
|
2328
|
+
}
|
|
2329
|
+
break;
|
|
2330
|
+
case 'down':
|
|
2331
|
+
if (deltaY > swipeThresholdRef.current) {
|
|
2332
|
+
shouldClose = true;
|
|
2333
|
+
dismissDirection = 'down';
|
|
2334
|
+
}
|
|
2335
|
+
break;
|
|
2336
|
+
case 'up':
|
|
2337
|
+
if (deltaY < -swipeThresholdRef.current) {
|
|
2338
|
+
shouldClose = true;
|
|
2339
|
+
dismissDirection = 'up';
|
|
2340
|
+
}
|
|
2341
|
+
break;
|
|
2342
|
+
}
|
|
2343
|
+
if (shouldClose) {
|
|
2234
2344
|
break;
|
|
2235
2345
|
}
|
|
2236
2346
|
}
|
|
@@ -2372,29 +2482,25 @@ function useSwipeDismiss(options) {
|
|
|
2372
2482
|
});
|
|
2373
2483
|
});
|
|
2374
2484
|
const getDragStyles = React__namespace.useCallback(() => {
|
|
2375
|
-
// Read `isSwipingRef`, not the lagging `isSwiping` state, to match the imperative writer
|
|
2376
|
-
// `syncDragStyles`. Otherwise a render that commits before `setSwiping(true)` flushes strips the
|
|
2377
|
-
// transform it just wrote, flashing the popup to its resting position for a frame.
|
|
2378
|
-
const swiping = isSwipingRef.current;
|
|
2379
2485
|
const dragOffset = dragOffsetRef.current;
|
|
2380
2486
|
const initialTransform = initialTransformRef.current;
|
|
2381
2487
|
const deltaX = dragOffset.x - initialTransform.x;
|
|
2382
2488
|
const deltaY = dragOffset.y - initialTransform.y;
|
|
2383
|
-
if (!
|
|
2489
|
+
if (!isSwiping && deltaX === 0 && deltaY === 0 && !dragDismissed) {
|
|
2384
2490
|
return {
|
|
2385
2491
|
[movementCssVars.x]: '0px',
|
|
2386
2492
|
[movementCssVars.y]: '0px'
|
|
2387
2493
|
};
|
|
2388
2494
|
}
|
|
2389
2495
|
return {
|
|
2390
|
-
transition:
|
|
2496
|
+
transition: isSwiping ? 'none' : undefined,
|
|
2391
2497
|
// While swiping, freeze the element at its current visual transform so it doesn't snap to the
|
|
2392
2498
|
// end position.
|
|
2393
|
-
transform:
|
|
2499
|
+
transform: isSwiping ? getDragTransform(dragOffset, initialTransform.scale) : undefined,
|
|
2394
2500
|
[movementCssVars.x]: `${deltaX}px`,
|
|
2395
2501
|
[movementCssVars.y]: `${deltaY}px`
|
|
2396
2502
|
};
|
|
2397
|
-
}, [dragDismissed, movementCssVars]);
|
|
2503
|
+
}, [dragDismissed, isSwiping, movementCssVars]);
|
|
2398
2504
|
const getPointerProps = React__namespace.useCallback(() => {
|
|
2399
2505
|
if (!enabled) {
|
|
2400
2506
|
return {};
|
|
@@ -2454,8 +2560,6 @@ const MIN_SWIPE_RELEASE_DURATION_MS = 80;
|
|
|
2454
2560
|
const MAX_SWIPE_RELEASE_DURATION_MS = 360;
|
|
2455
2561
|
const MIN_SWIPE_RELEASE_SCALAR = 0.1;
|
|
2456
2562
|
const MAX_SWIPE_RELEASE_SCALAR = 1;
|
|
2457
|
-
const AXIS_LOCK_SLOP = 6;
|
|
2458
|
-
const AXIS_LOCK_BIAS = 2;
|
|
2459
2563
|
const DRAWER_CONTENT_SELECTOR = `[${DRAWER_CONTENT_ATTRIBUTE}]`;
|
|
2460
2564
|
/**
|
|
2461
2565
|
* A positioning container for the drawer popup that can be made scrollable.
|
|
@@ -2471,7 +2575,9 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2471
2575
|
children,
|
|
2472
2576
|
...elementProps
|
|
2473
2577
|
} = props;
|
|
2474
|
-
const
|
|
2578
|
+
const {
|
|
2579
|
+
store
|
|
2580
|
+
} = useDialogRootContext();
|
|
2475
2581
|
const popupRef = store.context.popupRef;
|
|
2476
2582
|
const backdropRef = store.context.backdropRef;
|
|
2477
2583
|
const {
|
|
@@ -2479,8 +2585,7 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2479
2585
|
notifyParentSwipingChange,
|
|
2480
2586
|
notifyParentSwipeProgressChange,
|
|
2481
2587
|
frontmostHeight,
|
|
2482
|
-
snapToSequentialPoints
|
|
2483
|
-
swipeAreaActiveRef
|
|
2588
|
+
snapToSequentialPoints
|
|
2484
2589
|
} = useDrawerRootContext();
|
|
2485
2590
|
const providerContext = useDrawerProviderContext();
|
|
2486
2591
|
const {
|
|
@@ -2514,13 +2619,30 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2514
2619
|
const touchScrollStateRef = React__namespace.useRef(null);
|
|
2515
2620
|
const virtualKeyboard = useDrawerVirtualKeyboardContext();
|
|
2516
2621
|
const snapPointRange = React__namespace.useMemo(() => {
|
|
2517
|
-
if (!snapPoints || snapPoints.length < 2
|
|
2622
|
+
if (!snapPoints || snapPoints.length < 2) {
|
|
2623
|
+
return null;
|
|
2624
|
+
}
|
|
2625
|
+
if (swipeDirection !== 'down' && swipeDirection !== 'up') {
|
|
2626
|
+
return null;
|
|
2627
|
+
}
|
|
2628
|
+
if (resolvedSnapPoints.length < 2) {
|
|
2629
|
+
return null;
|
|
2630
|
+
}
|
|
2631
|
+
const offsets = resolvedSnapPoints.map(point => point.offset).filter(offset => Number.isFinite(offset)).sort((a, b) => a - b);
|
|
2632
|
+
if (offsets.length < 2) {
|
|
2518
2633
|
return null;
|
|
2519
2634
|
}
|
|
2520
|
-
const offsets = resolvedSnapPoints.map(point => point.offset).sort((a, b) => a - b);
|
|
2521
2635
|
const minOffset = offsets[0];
|
|
2522
2636
|
const nextOffset = offsets[1];
|
|
2523
|
-
const
|
|
2637
|
+
const maxOffset = offsets[offsets.length - 1];
|
|
2638
|
+
let range = nextOffset - minOffset;
|
|
2639
|
+
if (!Number.isFinite(range) || range <= 0) {
|
|
2640
|
+
const fallbackRange = maxOffset - minOffset;
|
|
2641
|
+
if (!Number.isFinite(fallbackRange) || fallbackRange <= 0) {
|
|
2642
|
+
return null;
|
|
2643
|
+
}
|
|
2644
|
+
range = fallbackRange;
|
|
2645
|
+
}
|
|
2524
2646
|
return {
|
|
2525
2647
|
minOffset,
|
|
2526
2648
|
range
|
|
@@ -2539,8 +2661,7 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2539
2661
|
return [swipeDirection];
|
|
2540
2662
|
}, [snapPoints, swipeDirection]);
|
|
2541
2663
|
const setSwipeDismissed = useScrollLock.useStableCallback(dismissed => {
|
|
2542
|
-
popupRef.current
|
|
2543
|
-
backdropRef.current?.toggleAttribute(DrawerPopupDataAttributes.swipeDismiss, dismissed);
|
|
2664
|
+
setSwipeDismissedElements(popupRef.current, backdropRef.current, dismissed);
|
|
2544
2665
|
});
|
|
2545
2666
|
const clearSwipeRelease = useScrollLock.useStableCallback(() => {
|
|
2546
2667
|
setSwipeDismissed(false);
|
|
@@ -2554,7 +2675,11 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2554
2675
|
nestedSwipeActiveRef.current = false;
|
|
2555
2676
|
notifyParentSwipingChange?.(false);
|
|
2556
2677
|
});
|
|
2557
|
-
const applySwipeProgress = useScrollLock.useStableCallback((
|
|
2678
|
+
const applySwipeProgress = useScrollLock.useStableCallback(({
|
|
2679
|
+
resolvedProgress,
|
|
2680
|
+
shouldTrackProgress,
|
|
2681
|
+
notifyParent
|
|
2682
|
+
}) => {
|
|
2558
2683
|
const isActive = open && !nested && shouldTrackProgress;
|
|
2559
2684
|
const swipeProgress = isActive ? resolvedProgress : 0;
|
|
2560
2685
|
const nestedSwipeProgress = open && shouldTrackProgress ? resolvedProgress : 0;
|
|
@@ -2572,48 +2697,78 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2572
2697
|
if (!backdropElement) {
|
|
2573
2698
|
return;
|
|
2574
2699
|
}
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2700
|
+
if (!isActive || swipeProgress <= 0) {
|
|
2701
|
+
backdropElement.style.setProperty(DrawerBackdropCssVars.swipeProgress, '0');
|
|
2702
|
+
backdropElement.style.removeProperty(DrawerPopupCssVars.height);
|
|
2703
|
+
return;
|
|
2704
|
+
}
|
|
2705
|
+
backdropElement.style.setProperty(DrawerBackdropCssVars.swipeProgress, `${swipeProgress}`);
|
|
2706
|
+
if (frontmostHeight > 0) {
|
|
2578
2707
|
backdropElement.style.setProperty(DrawerPopupCssVars.height, `${frontmostHeight}px`);
|
|
2579
2708
|
} else {
|
|
2580
2709
|
backdropElement.style.removeProperty(DrawerPopupCssVars.height);
|
|
2581
2710
|
}
|
|
2582
2711
|
});
|
|
2583
|
-
function resolveSwipeRelease(
|
|
2584
|
-
|
|
2585
|
-
|
|
2712
|
+
function resolveSwipeRelease({
|
|
2713
|
+
direction,
|
|
2714
|
+
deltaX,
|
|
2715
|
+
deltaY,
|
|
2716
|
+
velocityX,
|
|
2717
|
+
velocityY,
|
|
2718
|
+
releaseVelocityX,
|
|
2719
|
+
releaseVelocityY
|
|
2720
|
+
}) {
|
|
2721
|
+
if (!direction) {
|
|
2586
2722
|
return null;
|
|
2587
2723
|
}
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
const
|
|
2724
|
+
const popupElement = store.context.popupRef.current;
|
|
2725
|
+
if (!popupElement) {
|
|
2726
|
+
return null;
|
|
2727
|
+
}
|
|
2728
|
+
const size = direction === 'left' || direction === 'right' ? popupElement.offsetWidth : popupElement.offsetHeight;
|
|
2729
|
+
if (!Number.isFinite(size) || size <= 0) {
|
|
2730
|
+
return null;
|
|
2731
|
+
}
|
|
2732
|
+
const axisDelta = direction === 'left' || direction === 'right' ? deltaX : deltaY;
|
|
2733
|
+
const snapPointBaseOffset = snapPoints && snapPoints.length > 0 ? activeSnapPointOffset ?? 0 : 0;
|
|
2734
|
+
let baseOffset = 0;
|
|
2735
|
+
if (direction === 'down') {
|
|
2736
|
+
baseOffset = snapPointBaseOffset;
|
|
2737
|
+
} else if (direction === 'up') {
|
|
2738
|
+
baseOffset = -snapPointBaseOffset;
|
|
2739
|
+
}
|
|
2740
|
+
const translation = baseOffset + axisDelta;
|
|
2741
|
+
const translationAlongDirection = direction === 'left' || direction === 'up' ? -translation : translation;
|
|
2593
2742
|
const remainingDistance = Math.max(0, size - translationAlongDirection);
|
|
2594
|
-
if (remainingDistance <= 0) {
|
|
2743
|
+
if (!Number.isFinite(remainingDistance) || remainingDistance <= 0) {
|
|
2595
2744
|
return null;
|
|
2596
2745
|
}
|
|
2597
|
-
const
|
|
2598
|
-
const
|
|
2599
|
-
|
|
2746
|
+
const axisVelocity = direction === 'left' || direction === 'right' ? releaseVelocityX : releaseVelocityY;
|
|
2747
|
+
const fallbackVelocity = direction === 'left' || direction === 'right' ? velocityX : velocityY;
|
|
2748
|
+
const resolvedVelocity = Math.abs(axisVelocity) > 0 && Number.isFinite(axisVelocity) ? axisVelocity : fallbackVelocity;
|
|
2749
|
+
const directionalVelocity = direction === 'left' || direction === 'up' ? -resolvedVelocity : resolvedVelocity;
|
|
2750
|
+
if (!Number.isFinite(directionalVelocity) || directionalVelocity <= MIN_SWIPE_RELEASE_VELOCITY) {
|
|
2600
2751
|
return null;
|
|
2601
2752
|
}
|
|
2602
2753
|
const clampedVelocity = scrollEdges.clamp(directionalVelocity, MIN_SWIPE_RELEASE_VELOCITY, MAX_SWIPE_RELEASE_VELOCITY);
|
|
2603
|
-
// The gesture hook supplies finite deltas and velocities. The guards above keep the remaining
|
|
2604
|
-
// distance and divisor positive, so the duration stays within [MIN, MAX] and the resulting
|
|
2605
|
-
// scalar within (0, 1].
|
|
2606
2754
|
const durationMs = scrollEdges.clamp(remainingDistance / clampedVelocity, MIN_SWIPE_RELEASE_DURATION_MS, MAX_SWIPE_RELEASE_DURATION_MS);
|
|
2755
|
+
if (!Number.isFinite(durationMs)) {
|
|
2756
|
+
return null;
|
|
2757
|
+
}
|
|
2607
2758
|
const normalizedDuration = (durationMs - MIN_SWIPE_RELEASE_DURATION_MS) / (MAX_SWIPE_RELEASE_DURATION_MS - MIN_SWIPE_RELEASE_DURATION_MS);
|
|
2608
|
-
|
|
2759
|
+
const durationScalar = scrollEdges.clamp(MIN_SWIPE_RELEASE_SCALAR + normalizedDuration * (MAX_SWIPE_RELEASE_SCALAR - MIN_SWIPE_RELEASE_SCALAR), MIN_SWIPE_RELEASE_SCALAR, MAX_SWIPE_RELEASE_SCALAR);
|
|
2760
|
+
if (!Number.isFinite(durationScalar) || durationScalar <= 0) {
|
|
2761
|
+
return null;
|
|
2762
|
+
}
|
|
2763
|
+
return durationScalar;
|
|
2609
2764
|
}
|
|
2610
2765
|
function updateNestedSwipeActive(details) {
|
|
2611
2766
|
if (nestedSwipeActiveRef.current || !details) {
|
|
2612
2767
|
return;
|
|
2613
2768
|
}
|
|
2614
2769
|
const direction = details.direction ?? swipeDirection;
|
|
2615
|
-
const delta =
|
|
2616
|
-
if (Math.abs(delta) < MIN_SWIPE_THRESHOLD) {
|
|
2770
|
+
const delta = direction === 'left' || direction === 'right' ? details.deltaX : details.deltaY;
|
|
2771
|
+
if (!Number.isFinite(delta) || Math.abs(delta) < MIN_SWIPE_THRESHOLD) {
|
|
2617
2772
|
return;
|
|
2618
2773
|
}
|
|
2619
2774
|
nestedSwipeActiveRef.current = true;
|
|
@@ -2630,17 +2785,20 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2630
2785
|
y: DrawerPopupCssVars.swipeMovementY
|
|
2631
2786
|
},
|
|
2632
2787
|
onSwipeStart(event) {
|
|
2633
|
-
if ('touches' in event || event.pointerType === 'touch') {
|
|
2788
|
+
if ('touches' in event || 'pointerType' in event && event.pointerType === 'touch') {
|
|
2634
2789
|
return;
|
|
2635
2790
|
}
|
|
2636
2791
|
const popupElement = popupRef.current;
|
|
2792
|
+
if (!popupElement) {
|
|
2793
|
+
return;
|
|
2794
|
+
}
|
|
2637
2795
|
const doc = useScrollLock.ownerDocument(popupElement);
|
|
2638
2796
|
const selection = doc.getSelection?.();
|
|
2639
2797
|
if (!selection || selection.isCollapsed) {
|
|
2640
2798
|
return;
|
|
2641
2799
|
}
|
|
2642
|
-
const anchorElement =
|
|
2643
|
-
const focusElement =
|
|
2800
|
+
const anchorElement = floatingUi_utils.isElement(selection.anchorNode) ? selection.anchorNode : selection.anchorNode?.parentElement;
|
|
2801
|
+
const focusElement = floatingUi_utils.isElement(selection.focusNode) ? selection.focusNode : selection.focusNode?.parentElement;
|
|
2644
2802
|
if (!useScrollLock.contains(popupElement, anchorElement) && !useScrollLock.contains(popupElement, focusElement)) {
|
|
2645
2803
|
return;
|
|
2646
2804
|
}
|
|
@@ -2665,38 +2823,54 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2665
2823
|
return false;
|
|
2666
2824
|
}
|
|
2667
2825
|
const doc = popupElement.ownerDocument;
|
|
2668
|
-
const elementAtPoint = getElementAtPoint(
|
|
2826
|
+
const elementAtPoint = getElementAtPoint(doc, position.x, position.y);
|
|
2669
2827
|
if (!elementAtPoint || !useScrollLock.contains(popupElement, elementAtPoint)) {
|
|
2670
2828
|
return false;
|
|
2671
2829
|
}
|
|
2672
2830
|
const nativeEvent = details.nativeEvent;
|
|
2673
|
-
const touchLike = 'touches' in nativeEvent || nativeEvent.pointerType === 'touch';
|
|
2831
|
+
const touchLike = 'touches' in nativeEvent || 'pointerType' in nativeEvent && nativeEvent.pointerType === 'touch';
|
|
2674
2832
|
if (touchLike && shouldIgnoreSwipeForTextSelection(doc, popupElement)) {
|
|
2675
2833
|
return false;
|
|
2676
2834
|
}
|
|
2835
|
+
if (nativeEvent.type === 'touchstart' && isSwipeIgnoredTarget(elementAtPoint)) {
|
|
2836
|
+
return false;
|
|
2837
|
+
}
|
|
2677
2838
|
return true;
|
|
2678
2839
|
},
|
|
2679
2840
|
onProgress(progress, details) {
|
|
2680
2841
|
updateNestedSwipeActive(details);
|
|
2681
2842
|
const hasSnapPoints = Boolean(snapPoints && snapPoints.length > 0);
|
|
2682
|
-
if (swipingRef.current && swipeDirection === 'down' && hasSnapPoints && details) {
|
|
2843
|
+
if (swipingRef.current && swipeDirection === 'down' && hasSnapPoints && details && Number.isFinite(details.deltaY)) {
|
|
2683
2844
|
const popupElement = store.context.popupRef.current;
|
|
2684
2845
|
if (popupElement) {
|
|
2685
2846
|
popupElement.style.removeProperty('transform');
|
|
2686
2847
|
popupElement.style.setProperty(DrawerPopupCssVars.swipeMovementY, `${getSnapPointSwipeMovement(activeSnapPointOffset ?? 0, details.deltaY)}px`);
|
|
2687
2848
|
}
|
|
2688
2849
|
}
|
|
2850
|
+
const currentDirection = details?.direction ?? swipe.swipeDirection;
|
|
2851
|
+
const isDismissSwipe = currentDirection === undefined || currentDirection === swipeDirection;
|
|
2852
|
+
const isVerticalSwipe = swipeDirection === 'down' || swipeDirection === 'up';
|
|
2853
|
+
const shouldTrackProgress = hasSnapPoints && isVerticalSwipe || !hasSnapPoints || swipeDirection === 'left' || swipeDirection === 'right' || isDismissSwipe;
|
|
2689
2854
|
let resolvedProgress = progress;
|
|
2690
2855
|
if (snapPointRange && popupHeight > 0) {
|
|
2691
|
-
const baseOffset = activeSnapPointOffset ?? snapPointRange.minOffset;
|
|
2692
|
-
const offsetToProgress = nextOffset => scrollEdges.clamp((nextOffset - snapPointRange.minOffset) / snapPointRange.range, 0, 1);
|
|
2693
2856
|
if (details && Number.isFinite(details.deltaY)) {
|
|
2694
|
-
|
|
2857
|
+
const baseOffset = activeSnapPointOffset ?? snapPointRange.minOffset;
|
|
2858
|
+
const nextOffset = scrollEdges.clamp(baseOffset + details.deltaY, 0, popupHeight);
|
|
2859
|
+
resolvedProgress = scrollEdges.clamp((nextOffset - snapPointRange.minOffset) / snapPointRange.range, 0, 1);
|
|
2695
2860
|
} else if (snapPointProgress !== null) {
|
|
2696
2861
|
resolvedProgress = snapPointProgress;
|
|
2862
|
+
} else if (currentDirection === 'down' || currentDirection === 'up') {
|
|
2863
|
+
const displacement = progress * popupHeight;
|
|
2864
|
+
const baseOffset = activeSnapPointOffset ?? snapPointRange.minOffset;
|
|
2865
|
+
const nextOffset = currentDirection === 'down' ? baseOffset + displacement : baseOffset - displacement;
|
|
2866
|
+
resolvedProgress = scrollEdges.clamp((nextOffset - snapPointRange.minOffset) / snapPointRange.range, 0, 1);
|
|
2697
2867
|
}
|
|
2698
2868
|
}
|
|
2699
|
-
applySwipeProgress(
|
|
2869
|
+
applySwipeProgress({
|
|
2870
|
+
resolvedProgress,
|
|
2871
|
+
shouldTrackProgress,
|
|
2872
|
+
notifyParent: true
|
|
2873
|
+
});
|
|
2700
2874
|
},
|
|
2701
2875
|
onRelease({
|
|
2702
2876
|
event,
|
|
@@ -2708,21 +2882,30 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2708
2882
|
releaseVelocityX,
|
|
2709
2883
|
releaseVelocityY
|
|
2710
2884
|
}) {
|
|
2711
|
-
const
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2885
|
+
const swipeReleasePayload = {
|
|
2886
|
+
deltaX,
|
|
2887
|
+
deltaY,
|
|
2888
|
+
velocityX,
|
|
2889
|
+
velocityY,
|
|
2890
|
+
releaseVelocityX,
|
|
2891
|
+
releaseVelocityY
|
|
2892
|
+
};
|
|
2717
2893
|
function startSwipeRelease(resolvedDirection) {
|
|
2718
2894
|
// Start ending transition styles earlier and synchronously to prevent a period where
|
|
2719
2895
|
// the popup appears stuck on release before the actual closing animation starts.
|
|
2896
|
+
const popupElement = store.context.popupRef.current;
|
|
2897
|
+
if (!popupElement) {
|
|
2898
|
+
return;
|
|
2899
|
+
}
|
|
2720
2900
|
finishNestedSwipe();
|
|
2721
2901
|
setSwipeDismissed(true);
|
|
2722
|
-
|
|
2723
|
-
|
|
2902
|
+
popupElement.style.removeProperty('transition');
|
|
2903
|
+
popupElement.setAttribute(useScrollLock.TransitionStatusDataAttributes.endingStyle, '');
|
|
2724
2904
|
ReactDOM__namespace.flushSync(() => {
|
|
2725
|
-
setSwipeRelease(resolveSwipeRelease(
|
|
2905
|
+
setSwipeRelease(resolveSwipeRelease({
|
|
2906
|
+
direction: resolvedDirection,
|
|
2907
|
+
...swipeReleasePayload
|
|
2908
|
+
}));
|
|
2726
2909
|
});
|
|
2727
2910
|
}
|
|
2728
2911
|
if (!snapPoints || snapPoints.length === 0) {
|
|
@@ -2730,16 +2913,29 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2730
2913
|
clearSwipeRelease();
|
|
2731
2914
|
return undefined;
|
|
2732
2915
|
}
|
|
2733
|
-
const
|
|
2916
|
+
const element = store.context.popupRef.current;
|
|
2917
|
+
if (!element) {
|
|
2918
|
+
clearSwipeRelease();
|
|
2919
|
+
return undefined;
|
|
2920
|
+
}
|
|
2921
|
+
const baseThreshold = getBaseSwipeThreshold(element, direction);
|
|
2922
|
+
const delta = direction === 'left' || direction === 'right' ? deltaX : deltaY;
|
|
2923
|
+
if (!Number.isFinite(delta)) {
|
|
2924
|
+
clearSwipeRelease();
|
|
2925
|
+
return undefined;
|
|
2926
|
+
}
|
|
2927
|
+
const directionalDelta = direction === 'left' || direction === 'up' ? -delta : delta;
|
|
2734
2928
|
if (directionalDelta <= 0) {
|
|
2735
2929
|
clearSwipeRelease();
|
|
2736
2930
|
return false;
|
|
2737
2931
|
}
|
|
2738
|
-
|
|
2932
|
+
const velocity = direction === 'left' || direction === 'right' ? velocityX : velocityY;
|
|
2933
|
+
const directionalVelocity = direction === 'left' || direction === 'up' ? -velocity : velocity;
|
|
2934
|
+
if (directionalVelocity >= FAST_SWIPE_VELOCITY && directionalDelta > 0) {
|
|
2739
2935
|
startSwipeRelease(direction);
|
|
2740
2936
|
return true;
|
|
2741
2937
|
}
|
|
2742
|
-
const shouldClose = directionalDelta >
|
|
2938
|
+
const shouldClose = directionalDelta > baseThreshold;
|
|
2743
2939
|
if (shouldClose) {
|
|
2744
2940
|
startSwipeRelease(direction);
|
|
2745
2941
|
} else {
|
|
@@ -2751,20 +2947,20 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2751
2947
|
clearSwipeRelease();
|
|
2752
2948
|
return undefined;
|
|
2753
2949
|
}
|
|
2754
|
-
if (!popupHeight) {
|
|
2950
|
+
if (!popupHeight || resolvedSnapPoints.length === 0) {
|
|
2755
2951
|
clearSwipeRelease();
|
|
2756
|
-
return
|
|
2952
|
+
return undefined;
|
|
2757
2953
|
}
|
|
2758
|
-
|
|
2954
|
+
const dragDelta = swipeDirection === 'down' ? deltaY : -deltaY;
|
|
2955
|
+
if (!Number.isFinite(dragDelta)) {
|
|
2759
2956
|
clearSwipeRelease();
|
|
2760
2957
|
return undefined;
|
|
2761
2958
|
}
|
|
2762
|
-
const dragDelta = swipeDirection === 'down' ? deltaY : -deltaY;
|
|
2763
2959
|
const dragDirection = Math.sign(dragDelta);
|
|
2764
2960
|
const releaseDirectionalVelocity = swipeDirection === 'down' ? releaseVelocityY : -releaseVelocityY;
|
|
2765
2961
|
const fallbackDirectionalVelocity = swipeDirection === 'down' ? velocityY : -velocityY;
|
|
2766
|
-
let resolvedDirectionalVelocity = releaseDirectionalVelocity;
|
|
2767
|
-
if (dragDirection !== 0 && Math.abs(dragDelta) >= MIN_SWIPE_THRESHOLD) {
|
|
2962
|
+
let resolvedDirectionalVelocity = Number.isFinite(releaseDirectionalVelocity) ? releaseDirectionalVelocity : fallbackDirectionalVelocity;
|
|
2963
|
+
if (dragDirection !== 0 && Math.abs(dragDelta) >= MIN_SWIPE_THRESHOLD && Number.isFinite(resolvedDirectionalVelocity)) {
|
|
2768
2964
|
const velocityDirection = Math.sign(resolvedDirectionalVelocity);
|
|
2769
2965
|
if (velocityDirection !== 0 && velocityDirection !== dragDirection) {
|
|
2770
2966
|
// Ignore touch reversals that would otherwise flip the snap decision.
|
|
@@ -2773,20 +2969,39 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2773
2969
|
}
|
|
2774
2970
|
const currentOffset = activeSnapPointOffset ?? 0;
|
|
2775
2971
|
const dragTargetOffset = scrollEdges.clamp(currentOffset + dragDelta, 0, popupHeight);
|
|
2776
|
-
const velocityOffset = Math.abs(resolvedDirectionalVelocity) >= SNAP_VELOCITY_THRESHOLD ? scrollEdges.clamp(resolvedDirectionalVelocity, -MAX_SNAP_VELOCITY, MAX_SNAP_VELOCITY) * SNAP_VELOCITY_MULTIPLIER : 0;
|
|
2972
|
+
const velocityOffset = Number.isFinite(resolvedDirectionalVelocity) && Math.abs(resolvedDirectionalVelocity) >= SNAP_VELOCITY_THRESHOLD ? scrollEdges.clamp(resolvedDirectionalVelocity, -MAX_SNAP_VELOCITY, MAX_SNAP_VELOCITY) * SNAP_VELOCITY_MULTIPLIER : 0;
|
|
2777
2973
|
const targetOffset = snapToSequentialPoints ? dragTargetOffset : scrollEdges.clamp(dragTargetOffset + velocityOffset, 0, popupHeight);
|
|
2778
2974
|
const snapPointEventDetails = useScrollLock.createChangeEventDetails(useScrollLock.swipe, event);
|
|
2779
2975
|
const closeFromSnapPoints = () => {
|
|
2780
2976
|
pendingSwipeCloseSnapPointRef.current = activeSnapPoint;
|
|
2781
|
-
setActiveSnapPoint(null, snapPointEventDetails);
|
|
2977
|
+
setActiveSnapPoint?.(null, snapPointEventDetails);
|
|
2782
2978
|
startSwipeRelease(swipeDirection);
|
|
2783
2979
|
return true;
|
|
2784
2980
|
};
|
|
2785
2981
|
if (snapToSequentialPoints) {
|
|
2786
2982
|
const orderedSnapPoints = [...resolvedSnapPoints].sort((first, second) => first.offset - second.offset);
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2983
|
+
if (orderedSnapPoints.length === 0) {
|
|
2984
|
+
clearSwipeRelease();
|
|
2985
|
+
return false;
|
|
2986
|
+
}
|
|
2987
|
+
let currentIndex = 0;
|
|
2988
|
+
let closestDistance = Math.abs(currentOffset - orderedSnapPoints[0].offset);
|
|
2989
|
+
for (let index = 1; index < orderedSnapPoints.length; index += 1) {
|
|
2990
|
+
const distance = Math.abs(currentOffset - orderedSnapPoints[index].offset);
|
|
2991
|
+
if (distance < closestDistance) {
|
|
2992
|
+
closestDistance = distance;
|
|
2993
|
+
currentIndex = index;
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
let targetSnapPoint = orderedSnapPoints[0];
|
|
2997
|
+
closestDistance = Math.abs(targetOffset - targetSnapPoint.offset);
|
|
2998
|
+
for (const snapPoint of orderedSnapPoints) {
|
|
2999
|
+
const distance = Math.abs(targetOffset - snapPoint.offset);
|
|
3000
|
+
if (distance < closestDistance) {
|
|
3001
|
+
closestDistance = distance;
|
|
3002
|
+
targetSnapPoint = snapPoint;
|
|
3003
|
+
}
|
|
3004
|
+
}
|
|
2790
3005
|
const velocityDirection = Math.sign(resolvedDirectionalVelocity);
|
|
2791
3006
|
const shouldAdvance = dragDirection !== 0 && velocityDirection !== 0 && velocityDirection === dragDirection && Math.abs(resolvedDirectionalVelocity) >= SNAP_VELOCITY_THRESHOLD;
|
|
2792
3007
|
let effectiveTargetOffset = targetOffset;
|
|
@@ -2803,24 +3018,34 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2803
3018
|
return closeFromSnapPoints();
|
|
2804
3019
|
}
|
|
2805
3020
|
}
|
|
2806
|
-
const
|
|
3021
|
+
const closeOffset = popupHeight;
|
|
3022
|
+
const closeDistance = Math.abs(effectiveTargetOffset - closeOffset);
|
|
2807
3023
|
const snapDistance = Math.abs(effectiveTargetOffset - targetSnapPoint.offset);
|
|
2808
3024
|
if (closeDistance < snapDistance) {
|
|
2809
3025
|
return closeFromSnapPoints();
|
|
2810
3026
|
}
|
|
2811
|
-
setActiveSnapPoint(targetSnapPoint.value, snapPointEventDetails);
|
|
3027
|
+
setActiveSnapPoint?.(targetSnapPoint.value, snapPointEventDetails);
|
|
2812
3028
|
clearSwipeRelease();
|
|
2813
3029
|
return false;
|
|
2814
3030
|
}
|
|
2815
3031
|
if (resolvedDirectionalVelocity >= FAST_SWIPE_VELOCITY && dragDelta > 0) {
|
|
2816
3032
|
return closeFromSnapPoints();
|
|
2817
3033
|
}
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
3034
|
+
let closestSnapPoint = resolvedSnapPoints[0];
|
|
3035
|
+
let closestDistance = Math.abs(targetOffset - closestSnapPoint.offset);
|
|
3036
|
+
for (const snapPoint of resolvedSnapPoints) {
|
|
3037
|
+
const distance = Math.abs(targetOffset - snapPoint.offset);
|
|
3038
|
+
if (distance < closestDistance) {
|
|
3039
|
+
closestDistance = distance;
|
|
3040
|
+
closestSnapPoint = snapPoint;
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
const closeOffset = popupHeight;
|
|
3044
|
+
const closeDistance = Math.abs(targetOffset - closeOffset);
|
|
3045
|
+
if (closeDistance < closestDistance) {
|
|
2821
3046
|
return closeFromSnapPoints();
|
|
2822
3047
|
}
|
|
2823
|
-
setActiveSnapPoint(closestSnapPoint.value, snapPointEventDetails);
|
|
3048
|
+
setActiveSnapPoint?.(closestSnapPoint.value, snapPointEventDetails);
|
|
2824
3049
|
clearSwipeRelease();
|
|
2825
3050
|
return false;
|
|
2826
3051
|
},
|
|
@@ -2839,7 +3064,7 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2839
3064
|
if (dismissEventDetails.isCanceled) {
|
|
2840
3065
|
const pendingSnapPoint = pendingSwipeCloseSnapPointRef.current;
|
|
2841
3066
|
if (pendingSnapPoint !== undefined) {
|
|
2842
|
-
setActiveSnapPoint(pendingSnapPoint, useScrollLock.createChangeEventDetails(useScrollLock.swipe, event));
|
|
3067
|
+
setActiveSnapPoint?.(pendingSnapPoint, useScrollLock.createChangeEventDetails(useScrollLock.swipe, event));
|
|
2843
3068
|
}
|
|
2844
3069
|
pendingSwipeCloseSnapPointRef.current = undefined;
|
|
2845
3070
|
resetSwipeRef.current?.();
|
|
@@ -2861,7 +3086,7 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2861
3086
|
// Parent rejected: revert animation and restore snap point.
|
|
2862
3087
|
const pendingSnapPoint = pendingSwipeCloseSnapPointRef.current;
|
|
2863
3088
|
if (pendingSnapPoint !== undefined) {
|
|
2864
|
-
setActiveSnapPoint(pendingSnapPoint, useScrollLock.createChangeEventDetails(useScrollLock.swipe, savedEvent));
|
|
3089
|
+
setActiveSnapPoint?.(pendingSnapPoint, useScrollLock.createChangeEventDetails(useScrollLock.swipe, savedEvent));
|
|
2865
3090
|
}
|
|
2866
3091
|
pendingSwipeCloseSnapPointRef.current = undefined;
|
|
2867
3092
|
clearSwipeRelease();
|
|
@@ -2891,18 +3116,42 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2891
3116
|
}
|
|
2892
3117
|
const resolvedRootElement = rootElement;
|
|
2893
3118
|
const doc = useScrollLock.ownerDocument(resolvedRootElement);
|
|
2894
|
-
|
|
3119
|
+
const win = floatingUi_utils.getWindow(doc);
|
|
3120
|
+
function handleNativeTouchMove(event) {
|
|
3121
|
+
// The virtual keyboard provider observes the move to tell a tap apart from a drag.
|
|
3122
|
+
// It must run even when the swipe gesture below claims the event with
|
|
3123
|
+
// `stopPropagation()`, which would otherwise prevent React's delegated handlers
|
|
3124
|
+
// (and the provider) from ever seeing the move.
|
|
3125
|
+
virtualKeyboard?.onTouchMove(event);
|
|
3126
|
+
if (ignoreTouchSwipeRef.current) {
|
|
3127
|
+
return;
|
|
3128
|
+
}
|
|
3129
|
+
const touchState = touchScrollStateRef.current;
|
|
3130
|
+
const touch = event.touches[0];
|
|
3131
|
+
if (!touch || !touchState) {
|
|
3132
|
+
return;
|
|
3133
|
+
}
|
|
2895
3134
|
const drawerAxisDelta = isVerticalScrollAxis ? touch.clientY - touchState.lastY : touch.clientX - touchState.lastX;
|
|
2896
3135
|
|
|
3136
|
+
// Preserve native range interaction by never locking touchmove for range inputs.
|
|
3137
|
+
if (isEventOnRangeInput(event, win)) {
|
|
3138
|
+
touchState.allowSwipe = false;
|
|
3139
|
+
updateTouchScrollPosition(touchState, touch);
|
|
3140
|
+
return;
|
|
3141
|
+
}
|
|
3142
|
+
|
|
2897
3143
|
// Avoid blocking pinch zoom or text selection adjustments on iOS Safari.
|
|
2898
3144
|
if (event.touches.length === 2) {
|
|
3145
|
+
updateTouchScrollPosition(touchState, touch);
|
|
2899
3146
|
return;
|
|
2900
3147
|
}
|
|
2901
3148
|
const allowTouchMove = shouldIgnoreSwipeForTextSelection(doc, resolvedRootElement);
|
|
2902
3149
|
if (allowTouchMove || !open || !mounted || nestedDrawerOpen) {
|
|
3150
|
+
updateTouchScrollPosition(touchState, touch);
|
|
2903
3151
|
return;
|
|
2904
3152
|
}
|
|
2905
|
-
if (
|
|
3153
|
+
if (preserveNativeCrossAxisScrollOnMove(touchState, touch, isVerticalScrollAxis)) {
|
|
3154
|
+
updateTouchScrollPosition(touchState, touch);
|
|
2906
3155
|
return;
|
|
2907
3156
|
}
|
|
2908
3157
|
const scrollTarget = touchState.scrollTarget;
|
|
@@ -2914,21 +3163,27 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2914
3163
|
// move through React re-rasterizes the popup content on every frame.
|
|
2915
3164
|
event.stopPropagation();
|
|
2916
3165
|
moveSwipeNative(event, resolvedRootElement);
|
|
3166
|
+
updateTouchScrollPosition(touchState, touch);
|
|
2917
3167
|
return;
|
|
2918
3168
|
}
|
|
2919
|
-
|
|
3169
|
+
const hasScrollableContent = hasScrollableContentOnAxis(scrollTarget, scrollAxis);
|
|
3170
|
+
if (!hasScrollableContent) {
|
|
2920
3171
|
// If the scroll container doesn't overflow on the drawer axis, prevent the window from
|
|
2921
3172
|
// scrolling instead.
|
|
2922
3173
|
if (event.cancelable) {
|
|
2923
3174
|
event.preventDefault();
|
|
2924
3175
|
}
|
|
2925
3176
|
event.stopPropagation();
|
|
3177
|
+
updateTouchScrollPosition(touchState, touch);
|
|
2926
3178
|
return;
|
|
2927
3179
|
}
|
|
2928
|
-
|
|
2929
|
-
|
|
3180
|
+
const delta = drawerAxisDelta;
|
|
3181
|
+
if (delta !== 0) {
|
|
3182
|
+
const canSwipeFromScrollEdge = canSwipeFromScrollEdgeOnMove(scrollTarget, scrollAxis, swipeDirection, delta);
|
|
2930
3183
|
if (!touchState.allowSwipe) {
|
|
2931
|
-
if (event.cancelable
|
|
3184
|
+
if (!event.cancelable) {
|
|
3185
|
+
touchState.allowSwipe = false;
|
|
3186
|
+
} else if (canSwipeFromScrollEdge) {
|
|
2932
3187
|
touchState.allowSwipe = true;
|
|
2933
3188
|
event.preventDefault();
|
|
2934
3189
|
} else {
|
|
@@ -2942,22 +3197,6 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2942
3197
|
event.stopPropagation();
|
|
2943
3198
|
moveSwipeNative(event, resolvedRootElement);
|
|
2944
3199
|
}
|
|
2945
|
-
}
|
|
2946
|
-
function handleNativeTouchMove(event) {
|
|
2947
|
-
// The virtual keyboard provider observes the move to tell a tap apart from a drag.
|
|
2948
|
-
// It must run even when the swipe gesture below claims the event with
|
|
2949
|
-
// `stopPropagation()`, which would otherwise prevent React's delegated handlers
|
|
2950
|
-
// (and the provider) from ever seeing the move.
|
|
2951
|
-
virtualKeyboard?.onTouchMove(event);
|
|
2952
|
-
if (ignoreTouchSwipeRef.current) {
|
|
2953
|
-
return;
|
|
2954
|
-
}
|
|
2955
|
-
const touchState = touchScrollStateRef.current;
|
|
2956
|
-
const touch = event.touches[0];
|
|
2957
|
-
if (!touch || !touchState) {
|
|
2958
|
-
return;
|
|
2959
|
-
}
|
|
2960
|
-
processTouchMove(event, touchState, touch);
|
|
2961
3200
|
updateTouchScrollPosition(touchState, touch);
|
|
2962
3201
|
}
|
|
2963
3202
|
return useScrollLock.addEventListener(doc, 'touchmove', handleNativeTouchMove, {
|
|
@@ -2965,13 +3204,18 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2965
3204
|
capture: true
|
|
2966
3205
|
});
|
|
2967
3206
|
}, [mounted, nestedDrawerOpen, open, popupElementState, isVerticalScrollAxis, scrollAxis, swipeDirection, moveSwipeNative, viewportElement, virtualKeyboard]);
|
|
2968
|
-
|
|
3207
|
+
React__namespace.useEffect(() => {
|
|
2969
3208
|
if (!snapPointRange || swipe.swiping) {
|
|
2970
3209
|
return;
|
|
2971
3210
|
}
|
|
2972
|
-
|
|
3211
|
+
const resolvedProgress = !open || nested ? 0 : snapPointProgress ?? 0;
|
|
3212
|
+
applySwipeProgress({
|
|
3213
|
+
resolvedProgress,
|
|
3214
|
+
shouldTrackProgress: true,
|
|
3215
|
+
notifyParent: false
|
|
3216
|
+
});
|
|
2973
3217
|
}, [applySwipeProgress, frontmostHeight, nested, notifyParentSwipeProgressChange, open, snapPointProgress, snapPointRange, swipe.swiping, store, visualStateStore]);
|
|
2974
|
-
|
|
3218
|
+
React__namespace.useEffect(() => {
|
|
2975
3219
|
if (!notifyParentSwipeProgressChange) {
|
|
2976
3220
|
return undefined;
|
|
2977
3221
|
}
|
|
@@ -2982,19 +3226,13 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2982
3226
|
notifyParentSwipeProgressChange(0);
|
|
2983
3227
|
};
|
|
2984
3228
|
}, [notifyParentSwipeProgressChange, open]);
|
|
2985
|
-
|
|
3229
|
+
React__namespace.useEffect(() => {
|
|
2986
3230
|
if (open) {
|
|
2987
|
-
|
|
2988
|
-
// `--swipe-movement-*` (via `syncDragStyles(false)`), flashing it fully open for a frame.
|
|
2989
|
-
// `clearSwipeRelease` doesn't touch those vars, so always run it to clear any leftover
|
|
2990
|
-
// release state from a prior dismiss (e.g. when the popup is kept mounted).
|
|
2991
|
-
if (!swipeAreaActiveRef.current) {
|
|
2992
|
-
resetSwipe();
|
|
2993
|
-
}
|
|
3231
|
+
resetSwipe();
|
|
2994
3232
|
clearSwipeRelease();
|
|
2995
3233
|
}
|
|
2996
|
-
}, [clearSwipeRelease, open, resetSwipe
|
|
2997
|
-
|
|
3234
|
+
}, [clearSwipeRelease, open, resetSwipe]);
|
|
3235
|
+
React__namespace.useEffect(() => {
|
|
2998
3236
|
const backdropElement = backdropRef.current;
|
|
2999
3237
|
return () => {
|
|
3000
3238
|
visualStateStore?.set({
|
|
@@ -3019,19 +3257,12 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
3019
3257
|
swipeStrength: swipeRelease ?? null,
|
|
3020
3258
|
setSwipeDismissed
|
|
3021
3259
|
}), [setSwipeDismissed, swipe.getDragStyles, swipe.swiping, swipeRelease]);
|
|
3022
|
-
function resetTouchSwipeState(ignoreSwipe) {
|
|
3023
|
-
ignoreTouchSwipeRef.current = ignoreSwipe;
|
|
3024
|
-
touchScrollStateRef.current = null;
|
|
3025
|
-
}
|
|
3026
3260
|
function resetTouchTrackingState() {
|
|
3027
|
-
|
|
3261
|
+
ignoreTouchSwipeRef.current = false;
|
|
3262
|
+
touchScrollStateRef.current = null;
|
|
3028
3263
|
lastPointerTypeRef.current = '';
|
|
3029
3264
|
ignoreNextTouchStartFromPenRef.current = false;
|
|
3030
3265
|
}
|
|
3031
|
-
function handlePointerEnd(event) {
|
|
3032
|
-
lastPointerTypeRef.current = '';
|
|
3033
|
-
return event.pointerType !== 'touch';
|
|
3034
|
-
}
|
|
3035
3266
|
return /*#__PURE__*/jsxRuntime.jsx(DialogViewport, {
|
|
3036
3267
|
ref: forwardedRef,
|
|
3037
3268
|
className: className,
|
|
@@ -3044,7 +3275,8 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
3044
3275
|
if (!open || !mounted || nestedDrawerOpen) {
|
|
3045
3276
|
return;
|
|
3046
3277
|
}
|
|
3047
|
-
const
|
|
3278
|
+
const doc = useScrollLock.ownerDocument(event.currentTarget);
|
|
3279
|
+
const elementAtPoint = getElementAtPoint(doc, event.clientX, event.clientY);
|
|
3048
3280
|
if (isSwipeIgnoredTarget(elementAtPoint) || isDrawerContentTarget(elementAtPoint)) {
|
|
3049
3281
|
return;
|
|
3050
3282
|
}
|
|
@@ -3060,24 +3292,34 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
3060
3292
|
swipePointerProps.onPointerMove?.(event);
|
|
3061
3293
|
},
|
|
3062
3294
|
onPointerUp(event) {
|
|
3063
|
-
if (
|
|
3064
|
-
|
|
3295
|
+
if (lastPointerTypeRef.current === event.pointerType) {
|
|
3296
|
+
lastPointerTypeRef.current = '';
|
|
3297
|
+
}
|
|
3298
|
+
if (event.pointerType === 'touch') {
|
|
3299
|
+
return;
|
|
3065
3300
|
}
|
|
3301
|
+
swipePointerProps.onPointerUp?.(event);
|
|
3066
3302
|
},
|
|
3067
3303
|
onPointerCancel(event) {
|
|
3068
|
-
if (
|
|
3069
|
-
|
|
3304
|
+
if (lastPointerTypeRef.current === event.pointerType) {
|
|
3305
|
+
lastPointerTypeRef.current = '';
|
|
3306
|
+
}
|
|
3307
|
+
if (event.pointerType === 'touch') {
|
|
3308
|
+
return;
|
|
3070
3309
|
}
|
|
3310
|
+
swipePointerProps.onPointerCancel?.(event);
|
|
3071
3311
|
},
|
|
3072
3312
|
onTouchStart(event) {
|
|
3073
3313
|
const startedFromPenPointerDown = lastPointerTypeRef.current === 'pen' && ignoreNextTouchStartFromPenRef.current;
|
|
3074
3314
|
if (startedFromPenPointerDown) {
|
|
3075
3315
|
ignoreNextTouchStartFromPenRef.current = false;
|
|
3076
|
-
|
|
3316
|
+
ignoreTouchSwipeRef.current = false;
|
|
3317
|
+
touchScrollStateRef.current = null;
|
|
3077
3318
|
return;
|
|
3078
3319
|
}
|
|
3079
3320
|
if (!open || !mounted || nestedDrawerOpen) {
|
|
3080
|
-
|
|
3321
|
+
ignoreTouchSwipeRef.current = false;
|
|
3322
|
+
touchScrollStateRef.current = null;
|
|
3081
3323
|
return;
|
|
3082
3324
|
}
|
|
3083
3325
|
const touch = event.touches[0];
|
|
@@ -3085,25 +3327,32 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
3085
3327
|
return;
|
|
3086
3328
|
}
|
|
3087
3329
|
if (isReactTouchEventOnRangeInput(event)) {
|
|
3088
|
-
|
|
3330
|
+
ignoreTouchSwipeRef.current = false;
|
|
3331
|
+
touchScrollStateRef.current = null;
|
|
3089
3332
|
return;
|
|
3090
3333
|
}
|
|
3091
|
-
const
|
|
3092
|
-
const elementAtPoint = getElementAtPoint(
|
|
3334
|
+
const doc = useScrollLock.ownerDocument(event.currentTarget);
|
|
3335
|
+
const elementAtPoint = getElementAtPoint(doc, touch.clientX, touch.clientY);
|
|
3336
|
+
const rootElement = viewportElement ?? popupElementState;
|
|
3093
3337
|
const eventTarget = useScrollLock.getTarget(event.nativeEvent);
|
|
3094
|
-
const target =
|
|
3095
|
-
if (!useScrollLock.contains(rootElement, target)) {
|
|
3096
|
-
|
|
3338
|
+
const target = floatingUi_utils.isElement(eventTarget) ? eventTarget : null;
|
|
3339
|
+
if (rootElement && target && !useScrollLock.contains(rootElement, target)) {
|
|
3340
|
+
ignoreTouchSwipeRef.current = true;
|
|
3341
|
+
touchScrollStateRef.current = null;
|
|
3097
3342
|
return;
|
|
3098
3343
|
}
|
|
3099
3344
|
virtualKeyboard?.onTouchStart(event);
|
|
3100
|
-
|
|
3101
|
-
|
|
3345
|
+
ignoreTouchSwipeRef.current = isSwipeIgnoredTarget(elementAtPoint);
|
|
3346
|
+
if (ignoreTouchSwipeRef.current) {
|
|
3347
|
+
touchScrollStateRef.current = null;
|
|
3102
3348
|
return;
|
|
3103
3349
|
}
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3350
|
+
let scrollTarget = null;
|
|
3351
|
+
let hasCrossAxisScrollableContent = false;
|
|
3352
|
+
if (rootElement && target) {
|
|
3353
|
+
scrollTarget = findScrollableTouchTarget(target, rootElement, scrollAxis);
|
|
3354
|
+
hasCrossAxisScrollableContent = findScrollableTouchTarget(target, rootElement, crossScrollAxis) != null;
|
|
3355
|
+
}
|
|
3107
3356
|
let allowSwipe = null;
|
|
3108
3357
|
if (scrollTarget) {
|
|
3109
3358
|
const canSwipeFromEdge = isAtSwipeStartEdge(scrollTarget, scrollAxis, swipeDirection);
|
|
@@ -3117,8 +3366,7 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
3117
3366
|
scrollTarget,
|
|
3118
3367
|
hasCrossAxisScrollableContent,
|
|
3119
3368
|
allowSwipe,
|
|
3120
|
-
preserveNativeCrossAxisScroll: false
|
|
3121
|
-
drawerAxisAttributed: false
|
|
3369
|
+
preserveNativeCrossAxisScroll: false
|
|
3122
3370
|
};
|
|
3123
3371
|
swipeTouchProps.onTouchStart?.(event);
|
|
3124
3372
|
},
|
|
@@ -3143,8 +3391,24 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
3143
3391
|
});
|
|
3144
3392
|
});
|
|
3145
3393
|
if (process.env.NODE_ENV !== "production") DrawerViewport.displayName = "DrawerViewport";
|
|
3394
|
+
function setSwipeDismissedElements(popupElement, backdropElement, dismissed) {
|
|
3395
|
+
if (dismissed) {
|
|
3396
|
+
popupElement?.setAttribute(DrawerPopupDataAttributes.swipeDismiss, '');
|
|
3397
|
+
backdropElement?.setAttribute(DrawerPopupDataAttributes.swipeDismiss, '');
|
|
3398
|
+
return;
|
|
3399
|
+
}
|
|
3400
|
+
popupElement?.removeAttribute(DrawerPopupDataAttributes.swipeDismiss);
|
|
3401
|
+
backdropElement?.removeAttribute(DrawerPopupDataAttributes.swipeDismiss);
|
|
3402
|
+
}
|
|
3146
3403
|
function setBackdropSwipingAttribute(backdropElement, swiping) {
|
|
3147
|
-
backdropElement
|
|
3404
|
+
if (!backdropElement) {
|
|
3405
|
+
return;
|
|
3406
|
+
}
|
|
3407
|
+
if (swiping) {
|
|
3408
|
+
backdropElement.setAttribute(DrawerPopupDataAttributes.swiping, '');
|
|
3409
|
+
return;
|
|
3410
|
+
}
|
|
3411
|
+
backdropElement.removeAttribute(DrawerPopupDataAttributes.swiping);
|
|
3148
3412
|
}
|
|
3149
3413
|
function isSwipeIgnoredTarget(target) {
|
|
3150
3414
|
return Boolean(target?.closest(useScrollLock.BASE_UI_SWIPE_IGNORE_SELECTOR));
|
|
@@ -3152,26 +3416,28 @@ function isSwipeIgnoredTarget(target) {
|
|
|
3152
3416
|
function isDrawerContentTarget(target) {
|
|
3153
3417
|
return Boolean(target?.closest(DRAWER_CONTENT_SELECTOR));
|
|
3154
3418
|
}
|
|
3155
|
-
function getBaseSwipeSize(element, direction) {
|
|
3156
|
-
return direction === 'left' || direction === 'right' ? element.offsetWidth : element.offsetHeight;
|
|
3157
|
-
}
|
|
3158
3419
|
function getBaseSwipeThreshold(element, direction) {
|
|
3159
|
-
|
|
3420
|
+
const size = direction === 'left' || direction === 'right' ? element.offsetWidth : element.offsetHeight;
|
|
3421
|
+
return Math.max(size * 0.5, MIN_SWIPE_THRESHOLD);
|
|
3160
3422
|
}
|
|
3161
3423
|
function isRangeInput(target, win) {
|
|
3162
3424
|
return target instanceof win.HTMLInputElement && target.type === 'range';
|
|
3163
3425
|
}
|
|
3164
3426
|
function isTextSelectionControl(target) {
|
|
3427
|
+
if (!floatingUi_utils.isElement(target)) {
|
|
3428
|
+
return false;
|
|
3429
|
+
}
|
|
3165
3430
|
return target.tagName === 'INPUT' || target.tagName === 'TEXTAREA';
|
|
3166
3431
|
}
|
|
3167
3432
|
function hasExpandedSelectionWithinTarget(selection, target) {
|
|
3168
|
-
const anchorElement =
|
|
3169
|
-
const focusElement =
|
|
3433
|
+
const anchorElement = floatingUi_utils.isElement(selection.anchorNode) ? selection.anchorNode : selection.anchorNode?.parentElement;
|
|
3434
|
+
const focusElement = floatingUi_utils.isElement(selection.focusNode) ? selection.focusNode : selection.focusNode?.parentElement;
|
|
3170
3435
|
return selection.containsNode(target, true) || useScrollLock.contains(target, anchorElement) || useScrollLock.contains(target, focusElement);
|
|
3171
3436
|
}
|
|
3172
3437
|
function shouldIgnoreSwipeForTextSelection(doc, rootElement) {
|
|
3173
3438
|
const activeEl = useScrollLock.activeElement(doc);
|
|
3174
|
-
|
|
3439
|
+
const activeElementWithinRoot = Boolean(activeEl && useScrollLock.contains(rootElement, activeEl));
|
|
3440
|
+
if (activeElementWithinRoot && isTextSelectionControl(activeEl)) {
|
|
3175
3441
|
const {
|
|
3176
3442
|
selectionStart,
|
|
3177
3443
|
selectionEnd
|
|
@@ -3187,60 +3453,38 @@ function shouldIgnoreSwipeForTextSelection(doc, rootElement) {
|
|
|
3187
3453
|
return hasExpandedSelectionWithinTarget(selection, rootElement);
|
|
3188
3454
|
}
|
|
3189
3455
|
function isEventOnRangeInput(event, win) {
|
|
3190
|
-
|
|
3456
|
+
const composedPath = event.composedPath();
|
|
3457
|
+
if (composedPath) {
|
|
3458
|
+
return composedPath.some(pathTarget => isRangeInput(pathTarget, win));
|
|
3459
|
+
}
|
|
3460
|
+
return isRangeInput(useScrollLock.getTarget(event), win);
|
|
3191
3461
|
}
|
|
3192
3462
|
function isReactTouchEventOnRangeInput(event) {
|
|
3193
|
-
return isEventOnRangeInput(event.nativeEvent,
|
|
3463
|
+
return isEventOnRangeInput(event.nativeEvent, floatingUi_utils.getWindow(event.currentTarget));
|
|
3194
3464
|
}
|
|
3195
3465
|
function updateTouchScrollPosition(touchState, touch) {
|
|
3196
3466
|
touchState.lastX = touch.clientX;
|
|
3197
3467
|
touchState.lastY = touch.clientY;
|
|
3198
3468
|
}
|
|
3199
|
-
|
|
3200
|
-
/**
|
|
3201
|
-
* Arbitrates a touchmove between the drawer swipe and a native cross-axis scroll.
|
|
3202
|
-
* Returns `true` when the move must be left alone — either because the cross axis already won the
|
|
3203
|
-
* gesture, or because neither axis has passed the slop yet and the gesture cannot be attributed.
|
|
3204
|
-
*/
|
|
3205
|
-
function shouldYieldTouchMove(touchState, event, touch, isVerticalScrollAxis) {
|
|
3469
|
+
function preserveNativeCrossAxisScrollOnMove(touchState, touch, isVerticalScrollAxis) {
|
|
3206
3470
|
if (touchState.preserveNativeCrossAxisScroll) {
|
|
3207
3471
|
return true;
|
|
3208
3472
|
}
|
|
3209
|
-
|
|
3210
|
-
// Attribution happens once per gesture. Re-arbitrating after the drawer axis has won would let
|
|
3211
|
-
// the pre-attribution branches below fire mid-drag (the slop is measured from the touch origin,
|
|
3212
|
-
// which is never re-baselined), freezing the popup and dropping `preventDefault()`.
|
|
3213
|
-
if (touchState.drawerAxisAttributed || touchState.allowSwipe === true || !touchState.hasCrossAxisScrollableContent) {
|
|
3473
|
+
if (touchState.allowSwipe === true || !touchState.hasCrossAxisScrollableContent) {
|
|
3214
3474
|
return false;
|
|
3215
3475
|
}
|
|
3216
|
-
|
|
3217
|
-
// A non-cancelable touchmove means the browser has already committed the gesture to a native
|
|
3218
|
-
// scroll; claiming it for the swipe would drag the popup alongside the scrolling content.
|
|
3219
|
-
if (!event.cancelable) {
|
|
3220
|
-
touchState.preserveNativeCrossAxisScroll = true;
|
|
3221
|
-
return true;
|
|
3222
|
-
}
|
|
3223
3476
|
const drawerAxisGestureDelta = isVerticalScrollAxis ? touch.clientY - touchState.startY : touch.clientX - touchState.startX;
|
|
3224
3477
|
const crossAxisGestureDelta = isVerticalScrollAxis ? touch.clientX - touchState.startX : touch.clientY - touchState.startY;
|
|
3225
3478
|
const absDrawerAxisGestureDelta = Math.abs(drawerAxisGestureDelta);
|
|
3226
3479
|
const absCrossAxisGestureDelta = Math.abs(crossAxisGestureDelta);
|
|
3227
|
-
if (absCrossAxisGestureDelta
|
|
3228
|
-
touchState.preserveNativeCrossAxisScroll = true;
|
|
3229
|
-
return true;
|
|
3230
|
-
}
|
|
3231
|
-
if (absDrawerAxisGestureDelta >= AXIS_LOCK_SLOP) {
|
|
3232
|
-
touchState.drawerAxisAttributed = true;
|
|
3480
|
+
if (absCrossAxisGestureDelta < 6 || absCrossAxisGestureDelta <= absDrawerAxisGestureDelta + 2) {
|
|
3233
3481
|
return false;
|
|
3234
3482
|
}
|
|
3235
|
-
|
|
3236
|
-
// Neither axis has traveled past the slop yet, so the gesture cannot be attributed. Leave the
|
|
3237
|
-
// event alone: on iOS, `preventDefault()` on the first cancelable touchmove cancels native
|
|
3238
|
-
// scrolling for the entire gesture, which would lock a cross-axis scroll that only passes the
|
|
3239
|
-
// slop on a later move.
|
|
3483
|
+
touchState.preserveNativeCrossAxisScroll = true;
|
|
3240
3484
|
return true;
|
|
3241
3485
|
}
|
|
3242
3486
|
function hasScrollableContentOnAxis(scrollTarget, axis) {
|
|
3243
|
-
return
|
|
3487
|
+
return axis === 'vertical' ? scrollTarget.scrollHeight > scrollTarget.clientHeight : scrollTarget.scrollWidth > scrollTarget.clientWidth;
|
|
3244
3488
|
}
|
|
3245
3489
|
function getScrollMetrics(scrollTarget, axis) {
|
|
3246
3490
|
if (axis === 'vertical') {
|
|
@@ -3257,23 +3501,48 @@ function getScrollMetrics(scrollTarget, axis) {
|
|
|
3257
3501
|
};
|
|
3258
3502
|
}
|
|
3259
3503
|
function isAtSwipeStartEdge(scrollTarget, axis, direction) {
|
|
3260
|
-
const dismissFromStartEdge = shouldDismissFromStartEdge(direction, axis);
|
|
3261
3504
|
const {
|
|
3262
3505
|
offset,
|
|
3263
3506
|
max
|
|
3264
3507
|
} = getScrollMetrics(scrollTarget, axis);
|
|
3508
|
+
const dismissFromStartEdge = shouldDismissFromStartEdge(direction, axis);
|
|
3509
|
+
if (dismissFromStartEdge === null) {
|
|
3510
|
+
return false;
|
|
3511
|
+
}
|
|
3265
3512
|
return dismissFromStartEdge ? offset <= 0 : offset >= max;
|
|
3266
3513
|
}
|
|
3267
3514
|
function canSwipeFromScrollEdgeOnMove(scrollTarget, axis, direction, delta) {
|
|
3515
|
+
const {
|
|
3516
|
+
offset,
|
|
3517
|
+
max
|
|
3518
|
+
} = getScrollMetrics(scrollTarget, axis);
|
|
3268
3519
|
const dismissFromStartEdge = shouldDismissFromStartEdge(direction, axis);
|
|
3520
|
+
if (dismissFromStartEdge === null) {
|
|
3521
|
+
return false;
|
|
3522
|
+
}
|
|
3269
3523
|
const movingTowardDismiss = dismissFromStartEdge ? delta > 0 : delta < 0;
|
|
3270
3524
|
if (!movingTowardDismiss) {
|
|
3271
3525
|
return false;
|
|
3272
3526
|
}
|
|
3273
|
-
return
|
|
3527
|
+
return dismissFromStartEdge ? offset <= 0 : offset >= max;
|
|
3274
3528
|
}
|
|
3275
3529
|
function shouldDismissFromStartEdge(direction, axis) {
|
|
3276
|
-
|
|
3530
|
+
if (axis === 'vertical') {
|
|
3531
|
+
if (direction === 'down') {
|
|
3532
|
+
return true;
|
|
3533
|
+
}
|
|
3534
|
+
if (direction === 'up') {
|
|
3535
|
+
return false;
|
|
3536
|
+
}
|
|
3537
|
+
return null;
|
|
3538
|
+
}
|
|
3539
|
+
if (direction === 'right') {
|
|
3540
|
+
return true;
|
|
3541
|
+
}
|
|
3542
|
+
if (direction === 'left') {
|
|
3543
|
+
return false;
|
|
3544
|
+
}
|
|
3545
|
+
return null;
|
|
3277
3546
|
}
|
|
3278
3547
|
|
|
3279
3548
|
const ScrollAreaRootContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
@@ -3286,6 +3555,20 @@ function useScrollAreaRootContext() {
|
|
|
3286
3555
|
return context;
|
|
3287
3556
|
}
|
|
3288
3557
|
|
|
3558
|
+
let ScrollAreaRootCssVars = /*#__PURE__*/function (ScrollAreaRootCssVars) {
|
|
3559
|
+
/**
|
|
3560
|
+
* The scroll area's corner height.
|
|
3561
|
+
* @type {number}
|
|
3562
|
+
*/
|
|
3563
|
+
ScrollAreaRootCssVars["scrollAreaCornerHeight"] = "--scroll-area-corner-height";
|
|
3564
|
+
/**
|
|
3565
|
+
* The scroll area's corner width.
|
|
3566
|
+
* @type {number}
|
|
3567
|
+
*/
|
|
3568
|
+
ScrollAreaRootCssVars["scrollAreaCornerWidth"] = "--scroll-area-corner-width";
|
|
3569
|
+
return ScrollAreaRootCssVars;
|
|
3570
|
+
}({});
|
|
3571
|
+
|
|
3289
3572
|
const SCROLL_TIMEOUT = 500;
|
|
3290
3573
|
const MIN_THUMB_SIZE = 16;
|
|
3291
3574
|
|
|
@@ -3294,28 +3577,108 @@ function getOffset(element, prop, axis) {
|
|
|
3294
3577
|
return 0;
|
|
3295
3578
|
}
|
|
3296
3579
|
const styles = getComputedStyle(element);
|
|
3297
|
-
const
|
|
3298
|
-
const start = parseFloat(styles[`${key}Start`]);
|
|
3580
|
+
const propAxis = axis === 'x' ? 'Inline' : 'Block';
|
|
3299
3581
|
|
|
3300
3582
|
// Safari misreports `marginInlineEnd` in RTL.
|
|
3301
3583
|
// We have to assume the start/end values are symmetrical, which is likely.
|
|
3302
3584
|
if (axis === 'x' && prop === 'margin') {
|
|
3303
|
-
return
|
|
3585
|
+
return parseFloat(styles[`${prop}InlineStart`]) * 2;
|
|
3304
3586
|
}
|
|
3305
|
-
return
|
|
3587
|
+
return parseFloat(styles[`${prop}${propAxis}Start`]) + parseFloat(styles[`${prop}${propAxis}End`]);
|
|
3306
3588
|
}
|
|
3307
3589
|
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3590
|
+
let ScrollAreaScrollbarDataAttributes = /*#__PURE__*/function (ScrollAreaScrollbarDataAttributes) {
|
|
3591
|
+
/**
|
|
3592
|
+
* Indicates the orientation of the scrollbar.
|
|
3593
|
+
* @type {'horizontal' | 'vertical'}
|
|
3594
|
+
*/
|
|
3595
|
+
ScrollAreaScrollbarDataAttributes["orientation"] = "data-orientation";
|
|
3596
|
+
/**
|
|
3597
|
+
* Present when the pointer is over the scroll area.
|
|
3598
|
+
*/
|
|
3599
|
+
ScrollAreaScrollbarDataAttributes["hovering"] = "data-hovering";
|
|
3600
|
+
/**
|
|
3601
|
+
* Present when the user scrolls inside the scroll area.
|
|
3602
|
+
*/
|
|
3603
|
+
ScrollAreaScrollbarDataAttributes["scrolling"] = "data-scrolling";
|
|
3604
|
+
/**
|
|
3605
|
+
* Present when the scroll area content is wider than the viewport.
|
|
3606
|
+
*/
|
|
3607
|
+
ScrollAreaScrollbarDataAttributes["hasOverflowX"] = "data-has-overflow-x";
|
|
3608
|
+
/**
|
|
3609
|
+
* Present when the scroll area content is taller than the viewport.
|
|
3610
|
+
*/
|
|
3611
|
+
ScrollAreaScrollbarDataAttributes["hasOverflowY"] = "data-has-overflow-y";
|
|
3612
|
+
/**
|
|
3613
|
+
* Present when there is overflow on the horizontal start side.
|
|
3614
|
+
*/
|
|
3615
|
+
ScrollAreaScrollbarDataAttributes["overflowXStart"] = "data-overflow-x-start";
|
|
3616
|
+
/**
|
|
3617
|
+
* Present when there is overflow on the horizontal end side.
|
|
3618
|
+
*/
|
|
3619
|
+
ScrollAreaScrollbarDataAttributes["overflowXEnd"] = "data-overflow-x-end";
|
|
3620
|
+
/**
|
|
3621
|
+
* Present when there is overflow on the vertical start side.
|
|
3622
|
+
*/
|
|
3623
|
+
ScrollAreaScrollbarDataAttributes["overflowYStart"] = "data-overflow-y-start";
|
|
3624
|
+
/**
|
|
3625
|
+
* Present when there is overflow on the vertical end side.
|
|
3626
|
+
*/
|
|
3627
|
+
ScrollAreaScrollbarDataAttributes["overflowYEnd"] = "data-overflow-y-end";
|
|
3628
|
+
return ScrollAreaScrollbarDataAttributes;
|
|
3629
|
+
}({});
|
|
3630
|
+
|
|
3631
|
+
let ScrollAreaRootDataAttributes = /*#__PURE__*/function (ScrollAreaRootDataAttributes) {
|
|
3632
|
+
/**
|
|
3633
|
+
* Present when the user scrolls inside the scroll area.
|
|
3634
|
+
*/
|
|
3635
|
+
ScrollAreaRootDataAttributes["scrolling"] = "data-scrolling";
|
|
3636
|
+
/**
|
|
3637
|
+
* Present when the scroll area content is wider than the viewport.
|
|
3638
|
+
*/
|
|
3639
|
+
ScrollAreaRootDataAttributes["hasOverflowX"] = "data-has-overflow-x";
|
|
3640
|
+
/**
|
|
3641
|
+
* Present when the scroll area content is taller than the viewport.
|
|
3642
|
+
*/
|
|
3643
|
+
ScrollAreaRootDataAttributes["hasOverflowY"] = "data-has-overflow-y";
|
|
3644
|
+
/**
|
|
3645
|
+
* Present when there is overflow on the horizontal start side.
|
|
3646
|
+
*/
|
|
3647
|
+
ScrollAreaRootDataAttributes["overflowXStart"] = "data-overflow-x-start";
|
|
3648
|
+
/**
|
|
3649
|
+
* Present when there is overflow on the horizontal end side.
|
|
3650
|
+
*/
|
|
3651
|
+
ScrollAreaRootDataAttributes["overflowXEnd"] = "data-overflow-x-end";
|
|
3652
|
+
/**
|
|
3653
|
+
* Present when there is overflow on the vertical start side.
|
|
3654
|
+
*/
|
|
3655
|
+
ScrollAreaRootDataAttributes["overflowYStart"] = "data-overflow-y-start";
|
|
3656
|
+
/**
|
|
3657
|
+
* Present when there is overflow on the vertical end side.
|
|
3658
|
+
*/
|
|
3659
|
+
ScrollAreaRootDataAttributes["overflowYEnd"] = "data-overflow-y-end";
|
|
3660
|
+
return ScrollAreaRootDataAttributes;
|
|
3661
|
+
}({});
|
|
3662
|
+
|
|
3312
3663
|
const scrollAreaStateAttributesMapping = {
|
|
3313
|
-
hasOverflowX:
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3664
|
+
hasOverflowX: value => value ? {
|
|
3665
|
+
[ScrollAreaRootDataAttributes.hasOverflowX]: ''
|
|
3666
|
+
} : null,
|
|
3667
|
+
hasOverflowY: value => value ? {
|
|
3668
|
+
[ScrollAreaRootDataAttributes.hasOverflowY]: ''
|
|
3669
|
+
} : null,
|
|
3670
|
+
overflowXStart: value => value ? {
|
|
3671
|
+
[ScrollAreaRootDataAttributes.overflowXStart]: ''
|
|
3672
|
+
} : null,
|
|
3673
|
+
overflowXEnd: value => value ? {
|
|
3674
|
+
[ScrollAreaRootDataAttributes.overflowXEnd]: ''
|
|
3675
|
+
} : null,
|
|
3676
|
+
overflowYStart: value => value ? {
|
|
3677
|
+
[ScrollAreaRootDataAttributes.overflowYStart]: ''
|
|
3678
|
+
} : null,
|
|
3679
|
+
overflowYEnd: value => value ? {
|
|
3680
|
+
[ScrollAreaRootDataAttributes.overflowYEnd]: ''
|
|
3681
|
+
} : null,
|
|
3319
3682
|
cornerHidden: () => null
|
|
3320
3683
|
};
|
|
3321
3684
|
|
|
@@ -3381,145 +3744,99 @@ const ScrollAreaRoot = /*#__PURE__*/React__namespace.forwardRef(function ScrollA
|
|
|
3381
3744
|
const thumbYRef = React__namespace.useRef(null);
|
|
3382
3745
|
const thumbXRef = React__namespace.useRef(null);
|
|
3383
3746
|
const cornerRef = React__namespace.useRef(null);
|
|
3384
|
-
const
|
|
3747
|
+
const thumbDraggingRef = React__namespace.useRef(false);
|
|
3385
3748
|
const startYRef = React__namespace.useRef(0);
|
|
3386
3749
|
const startXRef = React__namespace.useRef(0);
|
|
3387
3750
|
const startScrollTopRef = React__namespace.useRef(0);
|
|
3388
3751
|
const startScrollLeftRef = React__namespace.useRef(0);
|
|
3389
3752
|
const currentOrientationRef = React__namespace.useRef('vertical');
|
|
3390
3753
|
const scrollPositionRef = React__namespace.useRef(DEFAULT_COORDS);
|
|
3391
|
-
const savedSnapTypeRef = React__namespace.useRef(null);
|
|
3392
|
-
function startScrolling(vertical) {
|
|
3393
|
-
const setScrolling = vertical ? setScrollingY : setScrollingX;
|
|
3394
|
-
const timeout = vertical ? scrollYTimeout : scrollXTimeout;
|
|
3395
|
-
setScrolling(true);
|
|
3396
|
-
timeout.start(SCROLL_TIMEOUT, () => {
|
|
3397
|
-
setScrolling(false);
|
|
3398
|
-
});
|
|
3399
|
-
}
|
|
3400
3754
|
const handleScroll = useScrollLock.useStableCallback(scrollPosition => {
|
|
3401
3755
|
const offsetX = scrollPosition.x - scrollPositionRef.current.x;
|
|
3402
3756
|
const offsetY = scrollPosition.y - scrollPositionRef.current.y;
|
|
3403
3757
|
scrollPositionRef.current = scrollPosition;
|
|
3404
3758
|
if (offsetY !== 0) {
|
|
3405
|
-
|
|
3759
|
+
setScrollingY(true);
|
|
3760
|
+
scrollYTimeout.start(SCROLL_TIMEOUT, () => {
|
|
3761
|
+
setScrollingY(false);
|
|
3762
|
+
});
|
|
3406
3763
|
}
|
|
3407
3764
|
if (offsetX !== 0) {
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
// CSS scroll snap forces every programmatic scroll to land on a snap
|
|
3413
|
-
// point, making thumb dragging jump between snap points. Native
|
|
3414
|
-
// scrollbars suppress snapping while dragging, so disable it until the
|
|
3415
|
-
// pointer is released; restoring the value re-snaps the viewport. The
|
|
3416
|
-
// save is guarded so a second pointer during an active drag can't
|
|
3417
|
-
// clobber the saved value with `none`.
|
|
3418
|
-
const disableViewportSnap = useScrollLock.useStableCallback(() => {
|
|
3419
|
-
const viewportEl = viewportRef.current;
|
|
3420
|
-
if (viewportEl && savedSnapTypeRef.current === null) {
|
|
3421
|
-
savedSnapTypeRef.current = viewportEl.style.scrollSnapType;
|
|
3422
|
-
viewportEl.style.scrollSnapType = 'none';
|
|
3765
|
+
setScrollingX(true);
|
|
3766
|
+
scrollXTimeout.start(SCROLL_TIMEOUT, () => {
|
|
3767
|
+
setScrollingX(false);
|
|
3768
|
+
});
|
|
3423
3769
|
}
|
|
3424
3770
|
});
|
|
3425
3771
|
const handlePointerDown = useScrollLock.useStableCallback(event => {
|
|
3426
3772
|
if (event.button !== 0) {
|
|
3427
3773
|
return;
|
|
3428
3774
|
}
|
|
3429
|
-
|
|
3430
|
-
const activeThumb = currentOrientationRef.current === 'vertical' ? thumbYRef.current : thumbXRef.current;
|
|
3431
|
-
// A live drag holds capture for the active pointer — ignore other pointers.
|
|
3432
|
-
// No capture means the release went missing entirely (silent capture drop
|
|
3433
|
-
// with an id that never reappears, e.g. a lost touch contact), so let the
|
|
3434
|
-
// new pointer take over the latch instead of leaving dragging dead.
|
|
3435
|
-
if (activeThumb?.hasPointerCapture(activePointerIdRef.current)) {
|
|
3436
|
-
return;
|
|
3437
|
-
}
|
|
3438
|
-
}
|
|
3439
|
-
activePointerIdRef.current = event.pointerId;
|
|
3775
|
+
thumbDraggingRef.current = true;
|
|
3440
3776
|
startYRef.current = event.clientY;
|
|
3441
3777
|
startXRef.current = event.clientX;
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
const viewportEl = viewportRef.current;
|
|
3447
|
-
if (viewportEl) {
|
|
3448
|
-
startScrollTopRef.current = viewportEl.scrollTop;
|
|
3449
|
-
startScrollLeftRef.current = viewportEl.scrollLeft;
|
|
3450
|
-
disableViewportSnap();
|
|
3451
|
-
}
|
|
3452
|
-
const thumb = currentOrientationRef.current === 'vertical' ? thumbYRef.current : thumbXRef.current;
|
|
3453
|
-
thumb?.setPointerCapture(event.pointerId);
|
|
3454
|
-
});
|
|
3455
|
-
const handlePointerUp = useScrollLock.useStableCallback(event => {
|
|
3456
|
-
if (event.pointerId !== activePointerIdRef.current) {
|
|
3457
|
-
return;
|
|
3778
|
+
currentOrientationRef.current = event.currentTarget.getAttribute(ScrollAreaScrollbarDataAttributes.orientation);
|
|
3779
|
+
if (viewportRef.current) {
|
|
3780
|
+
startScrollTopRef.current = viewportRef.current.scrollTop;
|
|
3781
|
+
startScrollLeftRef.current = viewportRef.current.scrollLeft;
|
|
3458
3782
|
}
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
// `SCROLL_TIMEOUT` timer armed by the last drag move, so every release path
|
|
3462
|
-
// (real, `pointercancel`, or the missed-release fallback) behaves the same.
|
|
3463
|
-
(currentOrientationRef.current === 'vertical' ? setScrollingY : setScrollingX)(false);
|
|
3464
|
-
if (savedSnapTypeRef.current !== null) {
|
|
3465
|
-
if (viewportRef.current) {
|
|
3466
|
-
viewportRef.current.style.scrollSnapType = savedSnapTypeRef.current;
|
|
3467
|
-
}
|
|
3468
|
-
savedSnapTypeRef.current = null;
|
|
3783
|
+
if (thumbYRef.current && currentOrientationRef.current === 'vertical') {
|
|
3784
|
+
thumbYRef.current.setPointerCapture(event.pointerId);
|
|
3469
3785
|
}
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
// capture we no longer hold (which would throw).
|
|
3473
|
-
if (thumb?.hasPointerCapture(event.pointerId)) {
|
|
3474
|
-
thumb.releasePointerCapture(event.pointerId);
|
|
3786
|
+
if (thumbXRef.current && currentOrientationRef.current === 'horizontal') {
|
|
3787
|
+
thumbXRef.current.setPointerCapture(event.pointerId);
|
|
3475
3788
|
}
|
|
3476
3789
|
});
|
|
3477
3790
|
const handlePointerMove = useScrollLock.useStableCallback(event => {
|
|
3478
|
-
if (
|
|
3479
|
-
return;
|
|
3480
|
-
}
|
|
3481
|
-
|
|
3482
|
-
// The release can go missing entirely (e.g. the browser drops pointer
|
|
3483
|
-
// capture while the scrollbar is hidden mid-drag), leaving the drag
|
|
3484
|
-
// latched so a buttonless hover over the thumb scrolls the viewport.
|
|
3485
|
-
// Treat a move without the primary button held (`buttons` bit 1 unset)
|
|
3486
|
-
// as the missed release.
|
|
3487
|
-
if (event.buttons % 2 === 0) {
|
|
3488
|
-
handlePointerUp(event);
|
|
3791
|
+
if (!thumbDraggingRef.current) {
|
|
3489
3792
|
return;
|
|
3490
3793
|
}
|
|
3491
|
-
const
|
|
3492
|
-
|
|
3493
|
-
|
|
3794
|
+
const deltaY = event.clientY - startYRef.current;
|
|
3795
|
+
const deltaX = event.clientX - startXRef.current;
|
|
3796
|
+
if (viewportRef.current) {
|
|
3797
|
+
const scrollableContentHeight = viewportRef.current.scrollHeight;
|
|
3798
|
+
const viewportHeight = viewportRef.current.clientHeight;
|
|
3799
|
+
const scrollableContentWidth = viewportRef.current.scrollWidth;
|
|
3800
|
+
const viewportWidth = viewportRef.current.clientWidth;
|
|
3801
|
+
if (thumbYRef.current && scrollbarYRef.current && currentOrientationRef.current === 'vertical') {
|
|
3802
|
+
const scrollbarYOffset = getOffset(scrollbarYRef.current, 'padding', 'y');
|
|
3803
|
+
const thumbYOffset = getOffset(thumbYRef.current, 'margin', 'y');
|
|
3804
|
+
const thumbHeight = thumbYRef.current.offsetHeight;
|
|
3805
|
+
const maxThumbOffsetY = scrollbarYRef.current.offsetHeight - thumbHeight - scrollbarYOffset - thumbYOffset;
|
|
3806
|
+
const scrollRatioY = deltaY / maxThumbOffsetY;
|
|
3807
|
+
viewportRef.current.scrollTop = startScrollTopRef.current + scrollRatioY * (scrollableContentHeight - viewportHeight);
|
|
3808
|
+
event.preventDefault();
|
|
3809
|
+
setScrollingY(true);
|
|
3810
|
+
scrollYTimeout.start(SCROLL_TIMEOUT, () => {
|
|
3811
|
+
setScrollingY(false);
|
|
3812
|
+
});
|
|
3813
|
+
}
|
|
3814
|
+
if (thumbXRef.current && scrollbarXRef.current && currentOrientationRef.current === 'horizontal') {
|
|
3815
|
+
const scrollbarXOffset = getOffset(scrollbarXRef.current, 'padding', 'x');
|
|
3816
|
+
const thumbXOffset = getOffset(thumbXRef.current, 'margin', 'x');
|
|
3817
|
+
const thumbWidth = thumbXRef.current.offsetWidth;
|
|
3818
|
+
const maxThumbOffsetX = scrollbarXRef.current.offsetWidth - thumbWidth - scrollbarXOffset - thumbXOffset;
|
|
3819
|
+
const scrollRatioX = deltaX / maxThumbOffsetX;
|
|
3820
|
+
viewportRef.current.scrollLeft = startScrollLeftRef.current + scrollRatioX * (scrollableContentWidth - viewportWidth);
|
|
3821
|
+
event.preventDefault();
|
|
3822
|
+
setScrollingX(true);
|
|
3823
|
+
scrollXTimeout.start(SCROLL_TIMEOUT, () => {
|
|
3824
|
+
setScrollingX(false);
|
|
3825
|
+
});
|
|
3826
|
+
}
|
|
3494
3827
|
}
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3828
|
+
});
|
|
3829
|
+
const handlePointerUp = useScrollLock.useStableCallback(event => {
|
|
3830
|
+
thumbDraggingRef.current = false;
|
|
3831
|
+
|
|
3832
|
+
// `pointercancel` releases capture implicitly, so guard against releasing a
|
|
3833
|
+
// capture we no longer hold (which would throw).
|
|
3834
|
+
if (thumbYRef.current && currentOrientationRef.current === 'vertical' && thumbYRef.current.hasPointerCapture(event.pointerId)) {
|
|
3835
|
+
thumbYRef.current.releasePointerCapture(event.pointerId);
|
|
3500
3836
|
}
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
const thumbOffset = getOffset(thumbEl, 'margin', axis);
|
|
3504
|
-
const thumbSizePx = vertical ? thumbEl.offsetHeight : thumbEl.offsetWidth;
|
|
3505
|
-
const trackSize = vertical ? scrollbarEl.offsetHeight : scrollbarEl.offsetWidth;
|
|
3506
|
-
const maxThumbOffset = trackSize - thumbSizePx - scrollbarOffset - thumbOffset;
|
|
3507
|
-
// A short or heavily padded track can drive `maxThumbOffset` to zero or
|
|
3508
|
-
// negative once the thumb hits its `MIN_THUMB_SIZE` floor. Dividing by it
|
|
3509
|
-
// would yield a non-finite (`Infinity`/`NaN`) or inverted scroll position.
|
|
3510
|
-
const delta = vertical ? event.clientY - startYRef.current : event.clientX - startXRef.current;
|
|
3511
|
-
const scrollRatio = maxThumbOffset <= 0 ? 0 : delta / maxThumbOffset;
|
|
3512
|
-
const scrollableSize = vertical ? viewportEl.scrollHeight : viewportEl.scrollWidth;
|
|
3513
|
-
const viewportSize = vertical ? viewportEl.clientHeight : viewportEl.clientWidth;
|
|
3514
|
-
const startScroll = vertical ? startScrollTopRef.current : startScrollLeftRef.current;
|
|
3515
|
-
const nextScroll = startScroll + scrollRatio * (scrollableSize - viewportSize);
|
|
3516
|
-
if (vertical) {
|
|
3517
|
-
viewportEl.scrollTop = nextScroll;
|
|
3518
|
-
} else {
|
|
3519
|
-
viewportEl.scrollLeft = nextScroll;
|
|
3837
|
+
if (thumbXRef.current && currentOrientationRef.current === 'horizontal' && thumbXRef.current.hasPointerCapture(event.pointerId)) {
|
|
3838
|
+
thumbXRef.current.releasePointerCapture(event.pointerId);
|
|
3520
3839
|
}
|
|
3521
|
-
event.preventDefault();
|
|
3522
|
-
startScrolling(vertical);
|
|
3523
3840
|
});
|
|
3524
3841
|
function handleTouchModalityChange(event) {
|
|
3525
3842
|
setTouchModality(event.pointerType === 'touch');
|
|
@@ -3551,8 +3868,8 @@ const ScrollAreaRoot = /*#__PURE__*/React__namespace.forwardRef(function ScrollA
|
|
|
3551
3868
|
},
|
|
3552
3869
|
style: {
|
|
3553
3870
|
position: 'relative',
|
|
3554
|
-
[
|
|
3555
|
-
[
|
|
3871
|
+
[ScrollAreaRootCssVars.scrollAreaCornerHeight]: `${cornerSize.height}px`,
|
|
3872
|
+
[ScrollAreaRootCssVars.scrollAreaCornerWidth]: `${cornerSize.width}px`
|
|
3556
3873
|
}
|
|
3557
3874
|
};
|
|
3558
3875
|
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
@@ -3566,7 +3883,6 @@ const ScrollAreaRoot = /*#__PURE__*/React__namespace.forwardRef(function ScrollA
|
|
|
3566
3883
|
handlePointerMove,
|
|
3567
3884
|
handlePointerUp,
|
|
3568
3885
|
handleScroll,
|
|
3569
|
-
disableViewportSnap,
|
|
3570
3886
|
cornerSize,
|
|
3571
3887
|
setCornerSize,
|
|
3572
3888
|
thumbSize,
|
|
@@ -3576,10 +3892,13 @@ const ScrollAreaRoot = /*#__PURE__*/React__namespace.forwardRef(function ScrollA
|
|
|
3576
3892
|
touchModality,
|
|
3577
3893
|
cornerRef,
|
|
3578
3894
|
scrollingX,
|
|
3895
|
+
setScrollingX,
|
|
3579
3896
|
scrollingY,
|
|
3897
|
+
setScrollingY,
|
|
3580
3898
|
hovering,
|
|
3581
3899
|
setHovering,
|
|
3582
3900
|
viewportRef,
|
|
3901
|
+
rootRef,
|
|
3583
3902
|
scrollbarYRef,
|
|
3584
3903
|
scrollbarXRef,
|
|
3585
3904
|
thumbYRef,
|
|
@@ -3596,7 +3915,7 @@ const ScrollAreaRoot = /*#__PURE__*/React__namespace.forwardRef(function ScrollA
|
|
|
3596
3915
|
yStart,
|
|
3597
3916
|
yEnd
|
|
3598
3917
|
}
|
|
3599
|
-
}), [handlePointerDown, handlePointerMove, handlePointerUp, handleScroll,
|
|
3918
|
+
}), [handlePointerDown, handlePointerMove, handlePointerUp, handleScroll, cornerSize, thumbSize, hasMeasuredScrollbar, touchModality, scrollingX, setScrollingX, scrollingY, setScrollingY, hovering, setHovering, rootId, hiddenState, overflowEdges, state, xStart, xEnd, yStart, yEnd]);
|
|
3600
3919
|
return /*#__PURE__*/jsxRuntime.jsxs(ScrollAreaRootContext.Provider, {
|
|
3601
3920
|
value: contextValue,
|
|
3602
3921
|
children: [!disableStyleElements && scrollEdges.styleDisableScrollbar.getElement(nonce), element]
|
|
@@ -3604,17 +3923,20 @@ const ScrollAreaRoot = /*#__PURE__*/React__namespace.forwardRef(function ScrollA
|
|
|
3604
3923
|
});
|
|
3605
3924
|
if (process.env.NODE_ENV !== "production") ScrollAreaRoot.displayName = "ScrollAreaRoot";
|
|
3606
3925
|
function normalizeOverflowEdgeThreshold(threshold) {
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3926
|
+
if (typeof threshold === 'number') {
|
|
3927
|
+
const value = Math.max(0, threshold);
|
|
3928
|
+
return {
|
|
3929
|
+
xStart: value,
|
|
3930
|
+
xEnd: value,
|
|
3931
|
+
yStart: value,
|
|
3932
|
+
yEnd: value
|
|
3933
|
+
};
|
|
3934
|
+
}
|
|
3613
3935
|
return {
|
|
3614
|
-
xStart: Math.max(0,
|
|
3615
|
-
xEnd: Math.max(0,
|
|
3616
|
-
yStart: Math.max(0,
|
|
3617
|
-
yEnd: Math.max(0,
|
|
3936
|
+
xStart: Math.max(0, threshold?.xStart || 0),
|
|
3937
|
+
xEnd: Math.max(0, threshold?.xEnd || 0),
|
|
3938
|
+
yStart: Math.max(0, threshold?.yStart || 0),
|
|
3939
|
+
yEnd: Math.max(0, threshold?.yEnd || 0)
|
|
3618
3940
|
};
|
|
3619
3941
|
}
|
|
3620
3942
|
|
|
@@ -3628,10 +3950,30 @@ function useScrollAreaViewportContext() {
|
|
|
3628
3950
|
return context;
|
|
3629
3951
|
}
|
|
3630
3952
|
|
|
3631
|
-
|
|
3953
|
+
let ScrollAreaViewportCssVars = /*#__PURE__*/function (ScrollAreaViewportCssVars) {
|
|
3954
|
+
/**
|
|
3955
|
+
* The distance from the horizontal start edge in pixels.
|
|
3956
|
+
* @type {number}
|
|
3957
|
+
*/
|
|
3958
|
+
ScrollAreaViewportCssVars["scrollAreaOverflowXStart"] = "--scroll-area-overflow-x-start";
|
|
3959
|
+
/**
|
|
3960
|
+
* The distance from the horizontal end edge in pixels.
|
|
3961
|
+
* @type {number}
|
|
3962
|
+
*/
|
|
3963
|
+
ScrollAreaViewportCssVars["scrollAreaOverflowXEnd"] = "--scroll-area-overflow-x-end";
|
|
3964
|
+
/**
|
|
3965
|
+
* The distance from the vertical start edge in pixels.
|
|
3966
|
+
* @type {number}
|
|
3967
|
+
*/
|
|
3968
|
+
ScrollAreaViewportCssVars["scrollAreaOverflowYStart"] = "--scroll-area-overflow-y-start";
|
|
3969
|
+
/**
|
|
3970
|
+
* The distance from the vertical end edge in pixels.
|
|
3971
|
+
* @type {number}
|
|
3972
|
+
*/
|
|
3973
|
+
ScrollAreaViewportCssVars["scrollAreaOverflowYEnd"] = "--scroll-area-overflow-y-end";
|
|
3974
|
+
return ScrollAreaViewportCssVars;
|
|
3975
|
+
}({});
|
|
3632
3976
|
|
|
3633
|
-
// Module-level flag to ensure we only register the CSS properties once,
|
|
3634
|
-
// regardless of how many Scroll Area components are mounted.
|
|
3635
3977
|
let scrollAreaOverflowVarsRegistered = false;
|
|
3636
3978
|
|
|
3637
3979
|
/**
|
|
@@ -3650,7 +3992,7 @@ function removeCSSVariableInheritance() {
|
|
|
3650
3992
|
return;
|
|
3651
3993
|
}
|
|
3652
3994
|
if (typeof CSS !== 'undefined' && 'registerProperty' in CSS) {
|
|
3653
|
-
|
|
3995
|
+
[ScrollAreaViewportCssVars.scrollAreaOverflowXStart, ScrollAreaViewportCssVars.scrollAreaOverflowXEnd, ScrollAreaViewportCssVars.scrollAreaOverflowYStart, ScrollAreaViewportCssVars.scrollAreaOverflowYEnd].forEach(name => {
|
|
3654
3996
|
try {
|
|
3655
3997
|
CSS.registerProperty({
|
|
3656
3998
|
name,
|
|
@@ -3694,11 +4036,12 @@ const ScrollAreaViewport = /*#__PURE__*/React__namespace.forwardRef(function Scr
|
|
|
3694
4036
|
hiddenState,
|
|
3695
4037
|
setHasMeasuredScrollbar,
|
|
3696
4038
|
handleScroll,
|
|
3697
|
-
touchModality,
|
|
3698
4039
|
setHovering,
|
|
3699
4040
|
setOverflowEdges,
|
|
4041
|
+
overflowEdges,
|
|
3700
4042
|
overflowEdgeThreshold,
|
|
3701
|
-
|
|
4043
|
+
scrollingX,
|
|
4044
|
+
scrollingY
|
|
3702
4045
|
} = useScrollAreaRootContext();
|
|
3703
4046
|
const direction = useScrollLock.useDirection();
|
|
3704
4047
|
const programmaticScrollRef = React__namespace.useRef(true);
|
|
@@ -3743,12 +4086,18 @@ const ScrollAreaViewport = /*#__PURE__*/React__namespace.forwardRef(function Scr
|
|
|
3743
4086
|
let scrollLeftFromStart = 0;
|
|
3744
4087
|
let scrollLeftFromEnd = 0;
|
|
3745
4088
|
if (!scrollbarXHidden) {
|
|
3746
|
-
|
|
3747
|
-
|
|
4089
|
+
let rawScrollLeftFromStart = 0;
|
|
4090
|
+
if (direction === 'rtl') {
|
|
4091
|
+
rawScrollLeftFromStart = scrollEdges.clamp(-scrollLeft, 0, maxScrollLeft);
|
|
4092
|
+
} else {
|
|
4093
|
+
rawScrollLeftFromStart = scrollEdges.clamp(scrollLeft, 0, maxScrollLeft);
|
|
4094
|
+
}
|
|
4095
|
+
scrollLeftFromStart = scrollEdges.normalizeScrollOffset(rawScrollLeftFromStart, maxScrollLeft);
|
|
3748
4096
|
scrollLeftFromEnd = maxScrollLeft - scrollLeftFromStart;
|
|
3749
4097
|
}
|
|
3750
|
-
const
|
|
3751
|
-
const
|
|
4098
|
+
const rawScrollTopFromStart = !scrollbarYHidden ? scrollEdges.clamp(scrollTop, 0, maxScrollTop) : 0;
|
|
4099
|
+
const scrollTopFromStart = !scrollbarYHidden ? scrollEdges.normalizeScrollOffset(rawScrollTopFromStart, maxScrollTop) : 0;
|
|
4100
|
+
const scrollTopFromEnd = !scrollbarYHidden ? maxScrollTop - scrollTopFromStart : 0;
|
|
3752
4101
|
const nextWidth = scrollbarXHidden ? 0 : viewportWidth;
|
|
3753
4102
|
const nextHeight = scrollbarYHidden ? 0 : viewportHeight;
|
|
3754
4103
|
let nextCornerWidth = 0;
|
|
@@ -3773,53 +4122,76 @@ const ScrollAreaViewport = /*#__PURE__*/React__namespace.forwardRef(function Scr
|
|
|
3773
4122
|
const maxNextHeight = scrollbarYEl ? Math.min(scrollbarYEl.offsetHeight - cornerHeightOffset, idealNextHeight) : idealNextHeight;
|
|
3774
4123
|
const clampedNextWidth = Math.max(MIN_THUMB_SIZE, maxNextWidth * ratioX);
|
|
3775
4124
|
const clampedNextHeight = Math.max(MIN_THUMB_SIZE, maxNextHeight * ratioY);
|
|
3776
|
-
setThumbSize(prevSize =>
|
|
3777
|
-
width
|
|
3778
|
-
|
|
3779
|
-
|
|
4125
|
+
setThumbSize(prevSize => {
|
|
4126
|
+
if (prevSize.height === clampedNextHeight && prevSize.width === clampedNextWidth) {
|
|
4127
|
+
return prevSize;
|
|
4128
|
+
}
|
|
4129
|
+
return {
|
|
4130
|
+
width: clampedNextWidth,
|
|
4131
|
+
height: clampedNextHeight
|
|
4132
|
+
};
|
|
4133
|
+
});
|
|
3780
4134
|
|
|
3781
4135
|
// Handle Y (vertical) scroll
|
|
3782
4136
|
if (scrollbarYEl && thumbYEl) {
|
|
3783
4137
|
const maxThumbOffsetY = scrollbarYEl.offsetHeight - clampedNextHeight - scrollbarYOffset - thumbYOffset;
|
|
3784
|
-
const
|
|
4138
|
+
const scrollRangeY = scrollableContentHeight - viewportHeight;
|
|
4139
|
+
const scrollRatioY = scrollRangeY === 0 ? 0 : scrollTop / scrollRangeY;
|
|
4140
|
+
|
|
4141
|
+
// In Safari, don't allow it to go negative or too far as `scrollTop` considers the rubber
|
|
4142
|
+
// band effect.
|
|
4143
|
+
const thumbOffsetY = Math.min(maxThumbOffsetY, Math.max(0, scrollRatioY * maxThumbOffsetY));
|
|
3785
4144
|
thumbYEl.style.transform = `translate3d(0,${thumbOffsetY}px,0)`;
|
|
3786
4145
|
}
|
|
3787
4146
|
|
|
3788
4147
|
// Handle X (horizontal) scroll
|
|
3789
4148
|
if (scrollbarXEl && thumbXEl) {
|
|
3790
4149
|
const maxThumbOffsetX = scrollbarXEl.offsetWidth - clampedNextWidth - scrollbarXOffset - thumbXOffset;
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
4150
|
+
const scrollRangeX = scrollableContentWidth - viewportWidth;
|
|
4151
|
+
const scrollRatioX = scrollRangeX === 0 ? 0 : scrollLeft / scrollRangeX;
|
|
4152
|
+
|
|
4153
|
+
// In Safari, don't allow it to go negative or too far as `scrollLeft` considers the rubber
|
|
4154
|
+
// band effect.
|
|
4155
|
+
const thumbOffsetX = direction === 'rtl' ? scrollEdges.clamp(scrollRatioX * maxThumbOffsetX, -maxThumbOffsetX, 0) : scrollEdges.clamp(scrollRatioX * maxThumbOffsetX, 0, maxThumbOffsetX);
|
|
4156
|
+
thumbXEl.style.transform = `translate3d(${thumbOffsetX}px,0,0)`;
|
|
4157
|
+
}
|
|
4158
|
+
const overflowMetricsPx = [[ScrollAreaViewportCssVars.scrollAreaOverflowXStart, scrollLeftFromStart], [ScrollAreaViewportCssVars.scrollAreaOverflowXEnd, scrollLeftFromEnd], [ScrollAreaViewportCssVars.scrollAreaOverflowYStart, scrollTopFromStart], [ScrollAreaViewportCssVars.scrollAreaOverflowYEnd, scrollTopFromEnd]];
|
|
4159
|
+
for (const [cssVar, value] of overflowMetricsPx) {
|
|
4160
|
+
viewportEl.style.setProperty(cssVar, `${value}px`);
|
|
4161
|
+
}
|
|
3801
4162
|
if (cornerEl) {
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
4163
|
+
if (scrollbarXHidden || scrollbarYHidden) {
|
|
4164
|
+
setCornerSize({
|
|
4165
|
+
width: 0,
|
|
4166
|
+
height: 0
|
|
4167
|
+
});
|
|
4168
|
+
} else if (!scrollbarXHidden && !scrollbarYHidden) {
|
|
4169
|
+
setCornerSize({
|
|
4170
|
+
width: nextCornerWidth,
|
|
4171
|
+
height: nextCornerHeight
|
|
4172
|
+
});
|
|
4173
|
+
}
|
|
4174
|
+
}
|
|
4175
|
+
setHiddenState(prevState => mergeHiddenState(prevState, nextHiddenState));
|
|
3812
4176
|
const nextOverflowEdges = {
|
|
3813
4177
|
xStart: !scrollbarXHidden && scrollLeftFromStart > overflowEdgeThreshold.xStart,
|
|
3814
4178
|
xEnd: !scrollbarXHidden && scrollLeftFromEnd > overflowEdgeThreshold.xEnd,
|
|
3815
4179
|
yStart: !scrollbarYHidden && scrollTopFromStart > overflowEdgeThreshold.yStart,
|
|
3816
4180
|
yEnd: !scrollbarYHidden && scrollTopFromEnd > overflowEdgeThreshold.yEnd
|
|
3817
4181
|
};
|
|
3818
|
-
setOverflowEdges(prev =>
|
|
4182
|
+
setOverflowEdges(prev => {
|
|
4183
|
+
if (prev.xStart === nextOverflowEdges.xStart && prev.xEnd === nextOverflowEdges.xEnd && prev.yStart === nextOverflowEdges.yStart && prev.yEnd === nextOverflowEdges.yEnd) {
|
|
4184
|
+
return prev;
|
|
4185
|
+
}
|
|
4186
|
+
return nextOverflowEdges;
|
|
4187
|
+
});
|
|
3819
4188
|
});
|
|
3820
4189
|
useScrollLock.useIsoLayoutEffect(() => {
|
|
4190
|
+
if (!viewportRef.current) {
|
|
4191
|
+
return;
|
|
4192
|
+
}
|
|
3821
4193
|
removeCSSVariableInheritance();
|
|
3822
|
-
}, []);
|
|
4194
|
+
}, [viewportRef]);
|
|
3823
4195
|
useScrollLock.useIsoLayoutEffect(() => {
|
|
3824
4196
|
// Wait for scrollbar and thumb refs after hidden-state toggles, refresh math on direction
|
|
3825
4197
|
// flips, and re-evaluate overflow edges when the threshold changes.
|
|
@@ -3862,10 +4234,6 @@ const ScrollAreaViewport = /*#__PURE__*/React__namespace.forwardRef(function Scr
|
|
|
3862
4234
|
if (animations.length === 0) {
|
|
3863
4235
|
return;
|
|
3864
4236
|
}
|
|
3865
|
-
|
|
3866
|
-
// `allSettled` never rejects, but `computeThumbPosition` can still run against a
|
|
3867
|
-
// torn-down tree once the animations resolve. Swallow instead of leaking an unhandled
|
|
3868
|
-
// rejection; `void` alone would only silence the floating-promise lint.
|
|
3869
4237
|
Promise.allSettled(animations.map(animation => animation.finished)).then(computeThumbPosition).catch(() => {});
|
|
3870
4238
|
});
|
|
3871
4239
|
return () => {
|
|
@@ -3893,13 +4261,7 @@ const ScrollAreaViewport = /*#__PURE__*/React__namespace.forwardRef(function Scr
|
|
|
3893
4261
|
return;
|
|
3894
4262
|
}
|
|
3895
4263
|
computeThumbPosition();
|
|
3896
|
-
|
|
3897
|
-
// WebKit consumes a touch that catches an in-flight momentum scroll or
|
|
3898
|
-
// rubber-band bounce without dispatching any DOM events for the whole
|
|
3899
|
-
// gesture (not even `touchstart`), so scrolls cannot be attributed to
|
|
3900
|
-
// the user through events. Treat every scroll in touch modality as
|
|
3901
|
-
// user-driven instead.
|
|
3902
|
-
if (touchModality || !programmaticScrollRef.current) {
|
|
4264
|
+
if (!programmaticScrollRef.current) {
|
|
3903
4265
|
handleScroll({
|
|
3904
4266
|
x: viewportRef.current.scrollLeft,
|
|
3905
4267
|
y: viewportRef.current.scrollTop
|
|
@@ -3917,10 +4279,21 @@ const ScrollAreaViewport = /*#__PURE__*/React__namespace.forwardRef(function Scr
|
|
|
3917
4279
|
});
|
|
3918
4280
|
},
|
|
3919
4281
|
onWheel: handleUserInteraction,
|
|
4282
|
+
onTouchMove: handleUserInteraction,
|
|
3920
4283
|
onPointerMove: handleUserInteraction,
|
|
3921
4284
|
onPointerEnter: handleUserInteraction,
|
|
3922
4285
|
onKeyDown: handleUserInteraction
|
|
3923
4286
|
};
|
|
4287
|
+
const viewportState = React__namespace.useMemo(() => ({
|
|
4288
|
+
scrolling: scrollingX || scrollingY,
|
|
4289
|
+
hasOverflowX: !hiddenState.x,
|
|
4290
|
+
hasOverflowY: !hiddenState.y,
|
|
4291
|
+
overflowXStart: overflowEdges.xStart,
|
|
4292
|
+
overflowXEnd: overflowEdges.xEnd,
|
|
4293
|
+
overflowYStart: overflowEdges.yStart,
|
|
4294
|
+
overflowYEnd: overflowEdges.yEnd,
|
|
4295
|
+
cornerHidden: hiddenState.corner
|
|
4296
|
+
}), [scrollingX, scrollingY, hiddenState.x, hiddenState.y, hiddenState.corner, overflowEdges]);
|
|
3924
4297
|
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
3925
4298
|
ref: [forwardedRef, viewportRef],
|
|
3926
4299
|
state: viewportState,
|
|
@@ -3945,40 +4318,16 @@ function getHiddenState(viewport) {
|
|
|
3945
4318
|
corner: y || x
|
|
3946
4319
|
};
|
|
3947
4320
|
}
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
* scroll-frame updates don't rebuild the root context.
|
|
3952
|
-
*/
|
|
3953
|
-
function pickState(prev, next) {
|
|
3954
|
-
for (const key in next) {
|
|
3955
|
-
if (prev[key] !== next[key]) {
|
|
3956
|
-
return next;
|
|
3957
|
-
}
|
|
4321
|
+
function mergeHiddenState(prevState, nextState) {
|
|
4322
|
+
if (prevState.y === nextState.y && prevState.x === nextState.x && prevState.corner === nextState.corner) {
|
|
4323
|
+
return prevState;
|
|
3958
4324
|
}
|
|
3959
|
-
return
|
|
3960
|
-
}
|
|
3961
|
-
|
|
3962
|
-
/**
|
|
3963
|
-
* Sizes the thumb and returns its axis offset. On overscroll (Safari rubber-band only) it shrinks
|
|
3964
|
-
* against the pinned edge, damped by `content / (content + overscroll)` to match native feedback;
|
|
3965
|
-
* the size flows through the thumb-size variable so the resting `var(...)` still applies.
|
|
3966
|
-
*/
|
|
3967
|
-
function applyOverscrollThumb(thumbEl, sizeVar, scrollFromStart, maxScroll, content, size, maxThumbOffset) {
|
|
3968
|
-
const clamped = scrollEdges.clamp(scrollFromStart, 0, maxScroll);
|
|
3969
|
-
const overscroll = scrollFromStart - clamped;
|
|
3970
|
-
const nextSize = Math.max(MIN_THUMB_SIZE, size * content / (content + Math.abs(overscroll)));
|
|
3971
|
-
|
|
3972
|
-
// Passing an empty string removes the override, restoring the resting `var(...)` size.
|
|
3973
|
-
thumbEl.style.setProperty(sizeVar, overscroll ? `${nextSize}px` : '');
|
|
3974
|
-
|
|
3975
|
-
// Slide proportionally; at the end edge push down by the shrink so the thumb stays pinned to
|
|
3976
|
-
// it, while a start overscroll pins to offset 0.
|
|
3977
|
-
const offset = maxScroll ? clamped / maxScroll * maxThumbOffset : 0;
|
|
3978
|
-
return offset + (overscroll > 0 ? size - nextSize : 0);
|
|
4325
|
+
return nextState;
|
|
3979
4326
|
}
|
|
3980
4327
|
|
|
3981
4328
|
exports.DialogPortal = DialogPortal;
|
|
4329
|
+
exports.DialogRoot = DialogRoot;
|
|
4330
|
+
exports.DialogStore = DialogStore;
|
|
3982
4331
|
exports.DialogTrigger = DialogTrigger;
|
|
3983
4332
|
exports.DialogViewport = DialogViewport;
|
|
3984
4333
|
exports.DrawerBackdrop = DrawerBackdrop;
|
|
@@ -3993,12 +4342,11 @@ exports.DrawerRoot = DrawerRoot;
|
|
|
3993
4342
|
exports.DrawerTrigger = DrawerTrigger;
|
|
3994
4343
|
exports.DrawerViewport = DrawerViewport;
|
|
3995
4344
|
exports.DrawerVirtualKeyboardContext = DrawerVirtualKeyboardContext;
|
|
3996
|
-
exports.NullStore = NullStore;
|
|
3997
4345
|
exports.ScrollAreaRoot = ScrollAreaRoot;
|
|
4346
|
+
exports.ScrollAreaRootCssVars = ScrollAreaRootCssVars;
|
|
3998
4347
|
exports.ScrollAreaViewport = ScrollAreaViewport;
|
|
3999
4348
|
exports.createInitialPopupStoreState = createInitialPopupStoreState;
|
|
4000
|
-
exports.
|
|
4001
|
-
exports.dialogStateAttributesMapping = dialogStateAttributesMapping;
|
|
4349
|
+
exports.findScrollableTouchTarget = findScrollableTouchTarget;
|
|
4002
4350
|
exports.getDisplacement = getDisplacement;
|
|
4003
4351
|
exports.getElementAtPoint = getElementAtPoint;
|
|
4004
4352
|
exports.getElementTransform = getElementTransform;
|
|
@@ -4009,8 +4357,6 @@ exports.useDialogPortalContext = useDialogPortalContext;
|
|
|
4009
4357
|
exports.useDialogRootContext = useDialogRootContext;
|
|
4010
4358
|
exports.useDrawerProviderContext = useDrawerProviderContext;
|
|
4011
4359
|
exports.useDrawerRootContext = useDrawerRootContext;
|
|
4012
|
-
exports.usePopupHandleStore = usePopupHandleStore;
|
|
4013
|
-
exports.useRenderDialogRoot = useRenderDialogRoot;
|
|
4014
4360
|
exports.useScrollAreaRootContext = useScrollAreaRootContext;
|
|
4015
4361
|
exports.useScrollAreaViewportContext = useScrollAreaViewportContext;
|
|
4016
4362
|
exports.useSwipeDismiss = useSwipeDismiss;
|