@jobber/components 8.23.0 → 8.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Autocomplete/index.cjs +1 -1
- package/dist/Autocomplete/index.mjs +1 -1
- package/dist/Card/index.cjs +4 -4
- package/dist/Card/index.mjs +4 -4
- package/dist/Chip/index.cjs +1 -1
- package/dist/Chip/index.mjs +1 -1
- package/dist/Chips/InternalChipDismissible/hooks/index.cjs +1 -1
- package/dist/Chips/InternalChipDismissible/hooks/index.mjs +1 -1
- package/dist/Chips/InternalChipDismissible/index.cjs +1 -1
- package/dist/Chips/InternalChipDismissible/index.mjs +1 -1
- package/dist/Chips/index.cjs +1 -1
- package/dist/Chips/index.mjs +1 -1
- package/dist/ComboboxChipRemove-cjs.js +668 -379
- package/dist/ComboboxChipRemove-es.js +508 -219
- package/dist/ConfirmationModal/index.cjs +1 -1
- package/dist/ConfirmationModal/index.mjs +1 -1
- package/dist/DataDump/index.cjs +4 -4
- package/dist/DataDump/index.mjs +4 -4
- package/dist/DataList/components/DataListActions/index.cjs +1 -1
- package/dist/DataList/components/DataListActions/index.mjs +1 -1
- package/dist/DataList/components/DataListBulkActions/index.cjs +1 -1
- package/dist/DataList/components/DataListBulkActions/index.mjs +1 -1
- package/dist/DataList/components/DataListFilters/components/DataListSort/index.cjs +1 -1
- package/dist/DataList/components/DataListFilters/components/DataListSort/index.mjs +1 -1
- package/dist/DataList/components/DataListFilters/index.cjs +1 -1
- package/dist/DataList/components/DataListFilters/index.mjs +1 -1
- package/dist/DataList/components/DataListHeader/index.cjs +1 -1
- package/dist/DataList/components/DataListHeader/index.mjs +1 -1
- package/dist/DataList/components/DataListItem/index.cjs +1 -1
- package/dist/DataList/components/DataListItem/index.mjs +1 -1
- package/dist/DataList/components/DataListItemActions/index.cjs +1 -1
- package/dist/DataList/components/DataListItemActions/index.mjs +1 -1
- package/dist/DataList/components/DataListItemActionsOverflow/index.cjs +1 -1
- package/dist/DataList/components/DataListItemActionsOverflow/index.mjs +1 -1
- package/dist/DataList/components/DataListItems/index.cjs +1 -1
- package/dist/DataList/components/DataListItems/index.mjs +1 -1
- package/dist/DataList/components/DataListLayout/index.cjs +1 -1
- package/dist/DataList/components/DataListLayout/index.mjs +1 -1
- package/dist/DataList/components/DataListLayoutActions/index.cjs +1 -1
- package/dist/DataList/components/DataListLayoutActions/index.mjs +1 -1
- package/dist/DataList/index.cjs +1 -1
- package/dist/DataList/index.mjs +1 -1
- package/dist/DatePicker/index.cjs +1 -1
- package/dist/DatePicker/index.mjs +1 -1
- package/dist/Dialog/index.cjs +3 -3
- package/dist/Dialog/index.mjs +3 -3
- package/dist/DrawerDescription-cjs.js +32 -33
- package/dist/DrawerDescription-es.js +19 -20
- package/dist/DrawerTitle-cjs.js +7 -5
- package/dist/DrawerTitle-es.js +7 -5
- package/dist/FilterPicker/components/FilterPickerActivator/index.cjs +1 -1
- package/dist/FilterPicker/components/FilterPickerActivator/index.mjs +1 -1
- package/dist/FilterPicker/components/FilterPickerContent/index.cjs +1 -1
- package/dist/FilterPicker/components/FilterPickerContent/index.mjs +1 -1
- package/dist/FilterPicker/components/FilterPickerTrigger/index.cjs +1 -1
- package/dist/FilterPicker/components/FilterPickerTrigger/index.mjs +1 -1
- package/dist/FilterPicker/index.cjs +1 -1
- package/dist/FilterPicker/index.mjs +1 -1
- package/dist/FormFieldWrapper-cjs.js +2 -2
- package/dist/FormFieldWrapper-es.js +2 -2
- package/dist/FormatFile/index.cjs +1 -1
- package/dist/FormatFile/index.mjs +1 -1
- package/dist/Gallery/index.cjs +1 -1
- package/dist/Gallery/index.mjs +1 -1
- package/dist/InputDate/index.cjs +1 -1
- package/dist/InputDate/index.mjs +1 -1
- package/dist/InputNumberExperimental-cjs.js +319 -102
- package/dist/InputNumberExperimental-es.js +321 -104
- package/dist/LightBox/index.cjs +1 -1
- package/dist/LightBox/index.mjs +1 -1
- package/dist/Menu/index.cjs +4 -4
- package/dist/Menu/index.mjs +4 -4
- package/dist/MenuSubmenuTrigger-cjs.js +545 -498
- package/dist/MenuSubmenuTrigger-es.js +490 -443
- package/dist/Modal/index.cjs +1 -1
- package/dist/Modal/index.mjs +1 -1
- package/dist/NumberFieldInput-cjs.js +609 -496
- package/dist/NumberFieldInput-es.js +612 -498
- package/dist/Page/index.cjs +4 -4
- package/dist/Page/index.mjs +4 -4
- package/dist/Popover/index.cjs +1 -1
- package/dist/Popover/index.mjs +1 -1
- package/dist/ScrollAreaViewport-cjs.js +326 -601
- package/dist/ScrollAreaViewport-es.js +278 -548
- package/dist/SelectGroupLabel-cjs.js +494 -528
- package/dist/SelectGroupLabel-es.js +411 -445
- package/dist/Separator-cjs.js +1 -0
- package/dist/Separator-es.js +1 -0
- package/dist/Tooltip/index.cjs +1 -1
- package/dist/Tooltip/index.mjs +1 -1
- package/dist/docs/InputTime/InputTime.md +8 -0
- package/dist/docs/SelectPrimitive/SelectPrimitive.md +38 -25
- package/dist/floating-ui.react-cjs.js +586 -10
- package/dist/floating-ui.react-dom-cjs.js +92 -92
- package/dist/floating-ui.react-dom-es.js +1 -1
- package/dist/floating-ui.react-es.js +580 -4
- package/dist/floating-ui.utils-cjs.js +159 -0
- package/dist/floating-ui.utils-es.js +136 -0
- package/dist/index.cjs +4 -4
- package/dist/index.mjs +4 -4
- package/dist/{ToolbarRootContext-cjs.js → isElementDisabled-cjs.js} +5 -0
- package/dist/{ToolbarRootContext-es.js → isElementDisabled-es.js} +5 -1
- package/dist/primitives/BottomSheet/index.cjs +3 -3
- package/dist/primitives/BottomSheet/index.mjs +3 -3
- package/dist/primitives/ComboboxPrimitive/index.cjs +2 -2
- package/dist/primitives/ComboboxPrimitive/index.mjs +2 -2
- package/dist/primitives/InputNumberExperimental/index.cjs +1 -1
- package/dist/primitives/InputNumberExperimental/index.mjs +1 -1
- package/dist/primitives/SelectPrimitive/index.cjs +5 -5
- package/dist/primitives/SelectPrimitive/index.mjs +5 -5
- package/dist/primitives/index.cjs +4 -4
- package/dist/primitives/index.mjs +4 -4
- package/dist/resolveAriaLabelledBy-cjs.js +5 -0
- package/dist/resolveAriaLabelledBy-es.js +5 -1
- package/dist/{CSPContext-cjs.js → scrollEdges-cjs.js} +30 -2
- package/dist/{CSPContext-es.js → scrollEdges-es.js} +28 -3
- package/dist/styles.css +9 -3
- package/dist/unstyledPrimitives/index.cjs +1217 -639
- package/dist/unstyledPrimitives/index.mjs +1163 -585
- package/dist/useButton-cjs.js +283 -317
- package/dist/useButton-es.js +277 -298
- package/dist/useCompositeListItem-cjs.js +328 -279
- package/dist/useCompositeListItem-es.js +293 -246
- package/dist/useLabel-cjs.js +11 -1
- package/dist/useLabel-es.js +11 -2
- package/dist/useLabelableId-cjs.js +37 -91
- package/dist/useLabelableId-es.js +37 -90
- package/dist/useRenderElement-cjs.js +81 -26
- package/dist/useRenderElement-es.js +81 -27
- package/dist/{InternalBackdrop-cjs.js → useScrollLock-cjs.js} +1286 -1220
- package/dist/{InternalBackdrop-es.js → useScrollLock-es.js} +1250 -1207
- package/package.json +3 -3
- package/dist/index.esm-cjs.js +0 -738
- package/dist/index.esm-es.js +0 -712
|
@@ -1,176 +1,22 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { E as EMPTY_OBJECT,
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { C as COMPOSITE_KEYS, u as useCSPContext, s as styleDisableScrollbar } from './
|
|
2
|
+
import { E as EMPTY_OBJECT, f as formatErrorMessage, u as useRenderElement } from './useRenderElement-es.js';
|
|
3
|
+
import { b as FloatingRootStore, P as PopupTriggerMap, t as createSelector, E as FloatingPortal, I as InternalBackdrop, G as inertValue, K as usePopupRootSync, L as useImplicitActiveTrigger, M as useOpenStateTransitions, y as useDismiss, s as useScrollLock, N as usePopupInteractionProps, R as ReactStore, O as setPopupOpenState, Q as usePopupStore, z as useOnFirstRender, T as useTriggerDataForwarding, x as useClick, U as useOpenMethodTriggerProps, V as CLICK_TRIGGER_IDENTIFIER, W as triggerOpenStateMapping, p as popupStateMapping, C as CommonPopupDataAttributes, F as FOCUSABLE_POPUP_PROPS, a as FloatingFocusManager, r as useDirection, J as webkit } from './useScrollLock-es.js';
|
|
4
|
+
import { d as createChangeEventDetails, i as imperativeAction, g as getTarget, q as contains, u as useBaseUiId, c as useButton, t as transitionStatusMapping, b as useStableCallback, o as ownerDocument, a as useIsoLayoutEffect, S as SafeReact, j as error, f as useOpenChangeComplete, z as useControlled, C as none, l as useId, W as android, B as addEventListener, X as closeWatcher, h as useTimeout } from './useButton-es.js';
|
|
5
|
+
import { C as COMPOSITE_KEYS, u as useCSPContext, s as styleDisableScrollbar, n as normalizeScrollOffset } from './scrollEdges-es.js';
|
|
6
6
|
import { c as clamp } from './clamp-es.js';
|
|
7
7
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Returns a callback ref that registers/unregisters the trigger element in the store.
|
|
12
|
-
*
|
|
13
|
-
* @param store The Store instance where the trigger should be registered.
|
|
14
|
-
*/
|
|
15
|
-
function useTriggerRegistration(id, store) {
|
|
16
|
-
// Keep track of the currently registered element to unregister it on unmount or id change.
|
|
17
|
-
const registeredElementIdRef = React.useRef(null);
|
|
18
|
-
const registeredElementRef = React.useRef(null);
|
|
19
|
-
return React.useCallback(element => {
|
|
20
|
-
if (id === undefined) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
if (registeredElementIdRef.current !== null) {
|
|
24
|
-
const registeredId = registeredElementIdRef.current;
|
|
25
|
-
const registeredElement = registeredElementRef.current;
|
|
26
|
-
const currentElement = store.context.triggerElements.getById(registeredId);
|
|
27
|
-
if (registeredElement && currentElement === registeredElement) {
|
|
28
|
-
store.context.triggerElements.delete(registeredId);
|
|
29
|
-
}
|
|
30
|
-
registeredElementIdRef.current = null;
|
|
31
|
-
registeredElementRef.current = null;
|
|
32
|
-
}
|
|
33
|
-
if (element !== null) {
|
|
34
|
-
registeredElementIdRef.current = id;
|
|
35
|
-
registeredElementRef.current = element;
|
|
36
|
-
store.context.triggerElements.add(id, element);
|
|
37
|
-
}
|
|
38
|
-
}, [store, id]);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Sets up trigger data forwarding to the store.
|
|
43
|
-
*
|
|
44
|
-
* @param triggerId Id of the trigger.
|
|
45
|
-
* @param triggerElement The trigger DOM element.
|
|
46
|
-
* @param store The Store instance managing the popup state.
|
|
47
|
-
* @param stateUpdates An object with state updates to apply when the trigger is active.
|
|
48
|
-
*/
|
|
49
|
-
function useTriggerDataForwarding(triggerId, triggerElementRef, store, stateUpdates) {
|
|
50
|
-
const isMountedByThisTrigger = store.useState('isMountedByTrigger', triggerId);
|
|
51
|
-
const baseRegisterTrigger = useTriggerRegistration(triggerId, store);
|
|
52
|
-
const registerTrigger = useStableCallback(element => {
|
|
53
|
-
baseRegisterTrigger(element);
|
|
54
|
-
if (!element || !store.select('open')) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
const activeTriggerId = store.select('activeTriggerId');
|
|
58
|
-
if (activeTriggerId === triggerId) {
|
|
59
|
-
store.update({
|
|
60
|
-
activeTriggerElement: element,
|
|
61
|
-
...stateUpdates
|
|
62
|
-
});
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
if (activeTriggerId == null) {
|
|
66
|
-
// This runs when popup is open, but no active trigger is set.
|
|
67
|
-
// It can happen when using controlled mode and the trigger is mounted after opening or if `triggerId` prop is not set explicitly.
|
|
68
|
-
// In such cases the first trigger to run this code becomes the active trigger (store.select('activeTriggerId') should not return null after that).
|
|
69
|
-
// This is mostly for compatibility with contained triggers where no explicit `triggerId` was required in controlled mode.
|
|
70
|
-
store.update({
|
|
71
|
-
activeTriggerId: triggerId,
|
|
72
|
-
activeTriggerElement: element,
|
|
73
|
-
...stateUpdates
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
useIsoLayoutEffect(() => {
|
|
78
|
-
if (isMountedByThisTrigger) {
|
|
79
|
-
store.update({
|
|
80
|
-
activeTriggerElement: triggerElementRef.current,
|
|
81
|
-
...stateUpdates
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
85
|
-
}, [isMountedByThisTrigger, store, triggerElementRef, ...Object.values(stateUpdates)]);
|
|
86
|
-
return {
|
|
87
|
-
registerTrigger,
|
|
88
|
-
isMountedByThisTrigger
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Ensures that when there's only one trigger element registered, it is set as the active trigger.
|
|
93
|
-
* This allows controlled popups to work correctly without an explicit triggerId, maintaining compatibility
|
|
94
|
-
* with the contained triggers.
|
|
95
|
-
*
|
|
96
|
-
* This should be called on the Root part.
|
|
97
|
-
*
|
|
98
|
-
* @param open Whether the popup is open.
|
|
99
|
-
* @param store The Store instance managing the popup state.
|
|
100
|
-
*/
|
|
101
|
-
function useImplicitActiveTrigger(store) {
|
|
102
|
-
const open = store.useState('open');
|
|
103
|
-
useIsoLayoutEffect(() => {
|
|
104
|
-
if (open && !store.select('activeTriggerId') && store.context.triggerElements.size === 1) {
|
|
105
|
-
const iteratorResult = store.context.triggerElements.entries().next();
|
|
106
|
-
if (!iteratorResult.done) {
|
|
107
|
-
const [implicitTriggerId, implicitTriggerElement] = iteratorResult.value;
|
|
108
|
-
store.update({
|
|
109
|
-
activeTriggerId: implicitTriggerId,
|
|
110
|
-
activeTriggerElement: implicitTriggerElement
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}, [open, store]);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Mangages the mounted state of the popup.
|
|
119
|
-
* Sets up the transition status listeners and handles unmounting when needed.
|
|
120
|
-
* Updates the `mounted` and `transitionStatus` states in the store.
|
|
121
|
-
*
|
|
122
|
-
* @param open Whether the popup is open.
|
|
123
|
-
* @param store The Store instance managing the popup state.
|
|
124
|
-
* @param onUnmount Optional callback to be called when the popup is unmounted.
|
|
125
|
-
*
|
|
126
|
-
* @returns A function to forcibly unmount the popup.
|
|
127
|
-
*/
|
|
128
|
-
function useOpenStateTransitions(open, store, onUnmount) {
|
|
129
|
-
const {
|
|
130
|
-
mounted,
|
|
131
|
-
setMounted,
|
|
132
|
-
transitionStatus
|
|
133
|
-
} = useTransitionStatus(open);
|
|
134
|
-
store.useSyncedValues({
|
|
135
|
-
mounted,
|
|
136
|
-
transitionStatus
|
|
137
|
-
});
|
|
138
|
-
const forceUnmount = useStableCallback(() => {
|
|
139
|
-
setMounted(false);
|
|
140
|
-
store.update({
|
|
141
|
-
activeTriggerId: null,
|
|
142
|
-
activeTriggerElement: null,
|
|
143
|
-
mounted: false
|
|
144
|
-
});
|
|
145
|
-
onUnmount?.();
|
|
146
|
-
store.context.onOpenChangeComplete?.(false);
|
|
147
|
-
});
|
|
148
|
-
const preventUnmountingOnClose = store.useState('preventUnmountingOnClose');
|
|
149
|
-
useOpenChangeComplete({
|
|
150
|
-
enabled: !preventUnmountingOnClose,
|
|
151
|
-
open,
|
|
152
|
-
ref: store.context.popupRef,
|
|
153
|
-
onComplete() {
|
|
154
|
-
if (!open) {
|
|
155
|
-
forceUnmount();
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
return {
|
|
160
|
-
forceUnmount,
|
|
161
|
-
transitionStatus
|
|
162
|
-
};
|
|
163
|
-
}
|
|
8
|
+
import { o as getWindow } from './floating-ui.utils.dom-es.js';
|
|
164
9
|
|
|
165
10
|
function getEmptyRootContext() {
|
|
166
11
|
return new FloatingRootStore({
|
|
167
12
|
open: false,
|
|
13
|
+
transitionStatus: undefined,
|
|
168
14
|
floatingElement: null,
|
|
169
15
|
referenceElement: null,
|
|
170
16
|
triggerElements: new PopupTriggerMap(),
|
|
171
|
-
floatingId:
|
|
17
|
+
floatingId: undefined,
|
|
18
|
+
syncOnly: false,
|
|
172
19
|
nested: false,
|
|
173
|
-
noEmit: false,
|
|
174
20
|
onOpenChange: undefined
|
|
175
21
|
});
|
|
176
22
|
}
|
|
@@ -184,8 +30,10 @@ function createInitialPopupStoreState() {
|
|
|
184
30
|
open: false,
|
|
185
31
|
openProp: undefined,
|
|
186
32
|
mounted: false,
|
|
187
|
-
transitionStatus:
|
|
33
|
+
transitionStatus: undefined,
|
|
188
34
|
floatingRootContext: getEmptyRootContext(),
|
|
35
|
+
floatingId: undefined,
|
|
36
|
+
triggerCount: 0,
|
|
189
37
|
preventUnmountingOnClose: false,
|
|
190
38
|
payload: undefined,
|
|
191
39
|
activeTriggerId: null,
|
|
@@ -198,16 +46,45 @@ function createInitialPopupStoreState() {
|
|
|
198
46
|
popupProps: EMPTY_OBJECT
|
|
199
47
|
};
|
|
200
48
|
}
|
|
49
|
+
function createPopupFloatingRootContext(triggerElements, floatingId, nested = false) {
|
|
50
|
+
return new FloatingRootStore({
|
|
51
|
+
open: false,
|
|
52
|
+
transitionStatus: undefined,
|
|
53
|
+
floatingElement: null,
|
|
54
|
+
referenceElement: null,
|
|
55
|
+
triggerElements,
|
|
56
|
+
floatingId,
|
|
57
|
+
syncOnly: true,
|
|
58
|
+
nested,
|
|
59
|
+
onOpenChange: undefined
|
|
60
|
+
});
|
|
61
|
+
}
|
|
201
62
|
const activeTriggerIdSelector = createSelector(state => state.triggerIdProp ?? state.activeTriggerId);
|
|
63
|
+
const openSelector = createSelector(state => state.openProp ?? state.open);
|
|
64
|
+
const popupIdSelector = createSelector(state => {
|
|
65
|
+
const popupId = state.popupElement?.id ?? state.floatingId;
|
|
66
|
+
return popupId || undefined;
|
|
67
|
+
});
|
|
68
|
+
function triggerOwnsOpenPopup(state, triggerId) {
|
|
69
|
+
return triggerId !== undefined && openSelector(state) && activeTriggerIdSelector(state) === triggerId;
|
|
70
|
+
}
|
|
71
|
+
function triggerOwnsOpenPopupOrIsOnlyTrigger(state, triggerId) {
|
|
72
|
+
if (triggerOwnsOpenPopup(state, triggerId)) {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
return triggerId !== undefined && openSelector(state) && activeTriggerIdSelector(state) == null && state.triggerCount === 1;
|
|
76
|
+
}
|
|
202
77
|
const popupStoreSelectors = {
|
|
203
|
-
open:
|
|
78
|
+
open: openSelector,
|
|
204
79
|
mounted: createSelector(state => state.mounted),
|
|
205
80
|
transitionStatus: createSelector(state => state.transitionStatus),
|
|
206
81
|
floatingRootContext: createSelector(state => state.floatingRootContext),
|
|
82
|
+
triggerCount: createSelector(state => state.triggerCount),
|
|
207
83
|
preventUnmountingOnClose: createSelector(state => state.preventUnmountingOnClose),
|
|
208
84
|
payload: createSelector(state => state.payload),
|
|
209
85
|
activeTriggerId: activeTriggerIdSelector,
|
|
210
86
|
activeTriggerElement: createSelector(state => state.mounted ? state.activeTriggerElement : null),
|
|
87
|
+
popupId: popupIdSelector,
|
|
211
88
|
/**
|
|
212
89
|
* Whether the trigger with the given ID was used to open the popup.
|
|
213
90
|
*/
|
|
@@ -215,175 +92,23 @@ const popupStoreSelectors = {
|
|
|
215
92
|
/**
|
|
216
93
|
* Whether the popup is open and was activated by a trigger with the given ID.
|
|
217
94
|
*/
|
|
218
|
-
isOpenedByTrigger: createSelector((state, triggerId) =>
|
|
95
|
+
isOpenedByTrigger: createSelector((state, triggerId) => triggerOwnsOpenPopup(state, triggerId)),
|
|
219
96
|
/**
|
|
220
97
|
* Whether the popup is mounted and was activated by a trigger with the given ID.
|
|
221
98
|
*/
|
|
222
99
|
isMountedByTrigger: createSelector((state, triggerId) => triggerId !== undefined && activeTriggerIdSelector(state) === triggerId && state.mounted),
|
|
223
100
|
triggerProps: createSelector((state, isActive) => isActive ? state.activeTriggerProps : state.inactiveTriggerProps),
|
|
101
|
+
/**
|
|
102
|
+
* Popup id for the trigger that currently owns the open popup.
|
|
103
|
+
*/
|
|
104
|
+
triggerPopupId: createSelector((state, triggerId) => triggerOwnsOpenPopupOrIsOnlyTrigger(state, triggerId) ? popupIdSelector(state) : undefined),
|
|
224
105
|
popupProps: createSelector(state => state.popupProps),
|
|
225
106
|
popupElement: createSelector(state => state.popupElement),
|
|
226
107
|
positionerElement: createSelector(state => state.positionerElement)
|
|
227
108
|
};
|
|
228
109
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
* The new instance is created only once and updated on every render.
|
|
232
|
-
*/
|
|
233
|
-
function useSyncedFloatingRootContext(options) {
|
|
234
|
-
const {
|
|
235
|
-
popupStore,
|
|
236
|
-
noEmit = false,
|
|
237
|
-
treatPopupAsFloatingElement = false,
|
|
238
|
-
onOpenChange
|
|
239
|
-
} = options;
|
|
240
|
-
const floatingId = useId();
|
|
241
|
-
const nested = useFloatingParentNodeId() != null;
|
|
242
|
-
const open = popupStore.useState('open');
|
|
243
|
-
const referenceElement = popupStore.useState('activeTriggerElement');
|
|
244
|
-
const floatingElement = popupStore.useState(treatPopupAsFloatingElement ? 'popupElement' : 'positionerElement');
|
|
245
|
-
const triggerElements = popupStore.context.triggerElements;
|
|
246
|
-
const store = useRefWithInit(() => new FloatingRootStore({
|
|
247
|
-
open,
|
|
248
|
-
referenceElement,
|
|
249
|
-
floatingElement,
|
|
250
|
-
triggerElements,
|
|
251
|
-
onOpenChange,
|
|
252
|
-
floatingId,
|
|
253
|
-
nested,
|
|
254
|
-
noEmit
|
|
255
|
-
})).current;
|
|
256
|
-
useIsoLayoutEffect(() => {
|
|
257
|
-
const valuesToSync = {
|
|
258
|
-
open,
|
|
259
|
-
floatingId,
|
|
260
|
-
referenceElement,
|
|
261
|
-
floatingElement
|
|
262
|
-
};
|
|
263
|
-
if (isElement(referenceElement)) {
|
|
264
|
-
valuesToSync.domReferenceElement = referenceElement;
|
|
265
|
-
}
|
|
266
|
-
if (store.state.positionReference === store.state.referenceElement) {
|
|
267
|
-
valuesToSync.positionReference = referenceElement;
|
|
268
|
-
}
|
|
269
|
-
store.update(valuesToSync);
|
|
270
|
-
}, [open, floatingId, referenceElement, floatingElement, store]);
|
|
271
|
-
|
|
272
|
-
// TODO: When `setOpen` is a part of the PopupStore API, we don't need to sync it.
|
|
273
|
-
store.context.onOpenChange = onOpenChange;
|
|
274
|
-
store.context.nested = nested;
|
|
275
|
-
store.context.noEmit = noEmit;
|
|
276
|
-
return store;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
const componentRoleToAriaRoleMap = new Map([['select', 'listbox'], ['combobox', 'listbox'], ['label', false]]);
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Adds base screen reader props to the reference and floating elements for a
|
|
283
|
-
* given floating element `role`.
|
|
284
|
-
* @see https://floating-ui.com/docs/useRole
|
|
285
|
-
*/
|
|
286
|
-
function useRole(context, props = {}) {
|
|
287
|
-
const store = 'rootStore' in context ? context.rootStore : context;
|
|
288
|
-
const open = store.useState('open');
|
|
289
|
-
const defaultFloatingId = store.useState('floatingId');
|
|
290
|
-
const domReference = store.useState('domReferenceElement');
|
|
291
|
-
const floatingElement = store.useState('floatingElement');
|
|
292
|
-
const {
|
|
293
|
-
role = 'dialog'
|
|
294
|
-
} = props;
|
|
295
|
-
const defaultReferenceId = useId();
|
|
296
|
-
const referenceId = domReference?.id || defaultReferenceId;
|
|
297
|
-
const floatingId = React.useMemo(() => getFloatingFocusElement(floatingElement)?.id || defaultFloatingId, [floatingElement, defaultFloatingId]);
|
|
298
|
-
const ariaRole = componentRoleToAriaRoleMap.get(role) ?? role;
|
|
299
|
-
const parentId = useFloatingParentNodeId();
|
|
300
|
-
const isNested = parentId != null;
|
|
301
|
-
const trigger = React.useMemo(() => {
|
|
302
|
-
if (ariaRole === 'tooltip' || role === 'label') {
|
|
303
|
-
return EMPTY_OBJECT;
|
|
304
|
-
}
|
|
305
|
-
return {
|
|
306
|
-
'aria-haspopup': ariaRole === 'alertdialog' ? 'dialog' : ariaRole,
|
|
307
|
-
'aria-expanded': 'false',
|
|
308
|
-
...(ariaRole === 'listbox' && {
|
|
309
|
-
role: 'combobox'
|
|
310
|
-
}),
|
|
311
|
-
...(ariaRole === 'menu' && isNested && {
|
|
312
|
-
role: 'menuitem'
|
|
313
|
-
}),
|
|
314
|
-
...(role === 'select' && {
|
|
315
|
-
'aria-autocomplete': 'none'
|
|
316
|
-
}),
|
|
317
|
-
...(role === 'combobox' && {
|
|
318
|
-
'aria-autocomplete': 'list'
|
|
319
|
-
})
|
|
320
|
-
};
|
|
321
|
-
}, [ariaRole, isNested, role]);
|
|
322
|
-
const reference = React.useMemo(() => {
|
|
323
|
-
if (ariaRole === 'tooltip' || role === 'label') {
|
|
324
|
-
return {
|
|
325
|
-
[`aria-${role === 'label' ? 'labelledby' : 'describedby'}`]: open ? floatingId : undefined
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
const triggerProps = trigger;
|
|
329
|
-
return {
|
|
330
|
-
...triggerProps,
|
|
331
|
-
'aria-expanded': open ? 'true' : 'false',
|
|
332
|
-
'aria-controls': open ? floatingId : undefined,
|
|
333
|
-
...(ariaRole === 'menu' && {
|
|
334
|
-
id: referenceId
|
|
335
|
-
})
|
|
336
|
-
};
|
|
337
|
-
}, [ariaRole, floatingId, open, referenceId, role, trigger]);
|
|
338
|
-
const floating = React.useMemo(() => {
|
|
339
|
-
const floatingProps = {
|
|
340
|
-
id: floatingId,
|
|
341
|
-
...(ariaRole && {
|
|
342
|
-
role: ariaRole
|
|
343
|
-
})
|
|
344
|
-
};
|
|
345
|
-
if (ariaRole === 'tooltip' || role === 'label') {
|
|
346
|
-
return floatingProps;
|
|
347
|
-
}
|
|
348
|
-
return {
|
|
349
|
-
...floatingProps,
|
|
350
|
-
...(ariaRole === 'menu' && {
|
|
351
|
-
'aria-labelledby': referenceId
|
|
352
|
-
})
|
|
353
|
-
};
|
|
354
|
-
}, [ariaRole, floatingId, referenceId, role]);
|
|
355
|
-
const item = React.useCallback(({
|
|
356
|
-
active,
|
|
357
|
-
selected
|
|
358
|
-
}) => {
|
|
359
|
-
const commonProps = {
|
|
360
|
-
role: 'option',
|
|
361
|
-
...(active && {
|
|
362
|
-
id: `${floatingId}-fui-option`
|
|
363
|
-
})
|
|
364
|
-
};
|
|
365
|
-
|
|
366
|
-
// For `menu`, we are unable to tell if the item is a `menuitemradio`
|
|
367
|
-
// or `menuitemcheckbox`. For backwards-compatibility reasons, also
|
|
368
|
-
// avoid defaulting to `menuitem` as it may overwrite custom role props.
|
|
369
|
-
switch (role) {
|
|
370
|
-
case 'select':
|
|
371
|
-
case 'combobox':
|
|
372
|
-
return {
|
|
373
|
-
...commonProps,
|
|
374
|
-
'aria-selected': selected
|
|
375
|
-
};
|
|
376
|
-
}
|
|
377
|
-
return {};
|
|
378
|
-
}, [floatingId, role]);
|
|
379
|
-
return React.useMemo(() => ({
|
|
380
|
-
reference,
|
|
381
|
-
floating,
|
|
382
|
-
item,
|
|
383
|
-
trigger
|
|
384
|
-
}), [reference, floating, trigger, item]);
|
|
385
|
-
}
|
|
386
|
-
|
|
110
|
+
const IsDrawerContext = /*#__PURE__*/React.createContext(false);
|
|
111
|
+
if (process.env.NODE_ENV !== "production") IsDrawerContext.displayName = "IsDrawerContext";
|
|
387
112
|
const DialogRootContext = /*#__PURE__*/React.createContext(undefined);
|
|
388
113
|
if (process.env.NODE_ENV !== "production") DialogRootContext.displayName = "DialogRootContext";
|
|
389
114
|
function useDialogRootContext(optional) {
|
|
@@ -436,44 +161,35 @@ if (process.env.NODE_ENV !== "production") DialogPortal.displayName = "DialogPor
|
|
|
436
161
|
function useDialogRoot(params) {
|
|
437
162
|
const {
|
|
438
163
|
store,
|
|
439
|
-
parentContext,
|
|
440
164
|
actionsRef
|
|
441
165
|
} = params;
|
|
442
166
|
const open = store.useState('open');
|
|
443
|
-
|
|
444
|
-
const modal = store.useState('modal');
|
|
445
|
-
const popupElement = store.useState('popupElement');
|
|
446
|
-
const {
|
|
447
|
-
openMethod,
|
|
448
|
-
triggerProps
|
|
449
|
-
} = useOpenInteractionType(open);
|
|
167
|
+
usePopupRootSync(store, open);
|
|
450
168
|
useImplicitActiveTrigger(store);
|
|
451
169
|
const {
|
|
452
170
|
forceUnmount
|
|
453
171
|
} = useOpenStateTransitions(open, store);
|
|
454
|
-
const createDialogEventDetails = useStableCallback(reason => {
|
|
455
|
-
const details = createChangeEventDetails(reason);
|
|
456
|
-
details.preventUnmountOnClose = () => {
|
|
457
|
-
store.set('preventUnmountingOnClose', true);
|
|
458
|
-
};
|
|
459
|
-
return details;
|
|
460
|
-
});
|
|
461
172
|
const handleImperativeClose = React.useCallback(() => {
|
|
462
|
-
store.setOpen(false,
|
|
463
|
-
}, [store
|
|
173
|
+
store.setOpen(false, createChangeEventDetails(imperativeAction));
|
|
174
|
+
}, [store]);
|
|
464
175
|
React.useImperativeHandle(actionsRef, () => ({
|
|
465
176
|
unmount: forceUnmount,
|
|
466
177
|
close: handleImperativeClose
|
|
467
178
|
}), [forceUnmount, handleImperativeClose]);
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
179
|
+
}
|
|
180
|
+
function DialogInteractions({
|
|
181
|
+
store,
|
|
182
|
+
parentContext,
|
|
183
|
+
isDrawer
|
|
184
|
+
}) {
|
|
185
|
+
const open = store.useState('open');
|
|
186
|
+
const disablePointerDismissal = store.useState('disablePointerDismissal');
|
|
187
|
+
const modal = store.useState('modal');
|
|
188
|
+
const popupElement = store.useState('popupElement');
|
|
189
|
+
const floatingRootContext = store.useState('floatingRootContext');
|
|
474
190
|
const [ownNestedOpenDialogs, setOwnNestedOpenDialogs] = React.useState(0);
|
|
191
|
+
const [ownNestedOpenDrawers, setOwnNestedOpenDrawers] = React.useState(0);
|
|
475
192
|
const isTopmost = ownNestedOpenDialogs === 0;
|
|
476
|
-
const role = useRole(floatingRootContext);
|
|
477
193
|
const dismiss = useDismiss(floatingRootContext, {
|
|
478
194
|
outsidePressEvent() {
|
|
479
195
|
if (store.context.internalBackdropRef.current || store.context.backdropRef.current) {
|
|
@@ -501,12 +217,11 @@ function useDialogRoot(params) {
|
|
|
501
217
|
}
|
|
502
218
|
const target = getTarget(event);
|
|
503
219
|
if (isTopmost && !disablePointerDismissal) {
|
|
504
|
-
const eventTarget = target;
|
|
505
220
|
// Only close if the click occurred on the dialog's owning backdrop.
|
|
506
221
|
// This supports multiple modal dialogs that aren't nested in the React tree:
|
|
507
222
|
// https://github.com/mui/base-ui/issues/1320
|
|
508
223
|
if (modal) {
|
|
509
|
-
return store.context.internalBackdropRef.current || store.context.backdropRef.current ? store.context.internalBackdropRef.current ===
|
|
224
|
+
return store.context.internalBackdropRef.current || store.context.backdropRef.current ? store.context.internalBackdropRef.current === target || store.context.backdropRef.current === target || contains(target, popupElement) && !target?.hasAttribute('data-base-ui-portal') : true;
|
|
510
225
|
}
|
|
511
226
|
return true;
|
|
512
227
|
}
|
|
@@ -515,24 +230,21 @@ function useDialogRoot(params) {
|
|
|
515
230
|
escapeKey: isTopmost
|
|
516
231
|
});
|
|
517
232
|
useScrollLock(open && modal === true, popupElement);
|
|
518
|
-
const {
|
|
519
|
-
getReferenceProps,
|
|
520
|
-
getFloatingProps,
|
|
521
|
-
getTriggerProps
|
|
522
|
-
} = useInteractions([role, dismiss]);
|
|
523
233
|
|
|
524
|
-
// Listen for nested open/close events on this store to maintain the
|
|
525
|
-
store.useContextCallback('onNestedDialogOpen',
|
|
526
|
-
setOwnNestedOpenDialogs(
|
|
234
|
+
// Listen for nested open/close events on this store to maintain the counts.
|
|
235
|
+
store.useContextCallback('onNestedDialogOpen', (dialogCount, drawerCount) => {
|
|
236
|
+
setOwnNestedOpenDialogs(dialogCount);
|
|
237
|
+
setOwnNestedOpenDrawers(drawerCount);
|
|
527
238
|
});
|
|
528
239
|
store.useContextCallback('onNestedDialogClose', () => {
|
|
529
240
|
setOwnNestedOpenDialogs(0);
|
|
241
|
+
setOwnNestedOpenDrawers(0);
|
|
530
242
|
});
|
|
531
243
|
|
|
532
244
|
// Notify parent of our open/close state using parent callbacks, if any
|
|
533
245
|
React.useEffect(() => {
|
|
534
246
|
if (parentContext?.onNestedDialogOpen && open) {
|
|
535
|
-
parentContext.onNestedDialogOpen(ownNestedOpenDialogs);
|
|
247
|
+
parentContext.onNestedDialogOpen(ownNestedOpenDialogs + 1, ownNestedOpenDrawers + (isDrawer ? 1 : 0));
|
|
536
248
|
}
|
|
537
249
|
if (parentContext?.onNestedDialogClose && !open) {
|
|
538
250
|
parentContext.onNestedDialogClose();
|
|
@@ -542,18 +254,20 @@ function useDialogRoot(params) {
|
|
|
542
254
|
parentContext.onNestedDialogClose();
|
|
543
255
|
}
|
|
544
256
|
};
|
|
545
|
-
}, [open,
|
|
546
|
-
const activeTriggerProps =
|
|
547
|
-
const inactiveTriggerProps =
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
257
|
+
}, [isDrawer, open, ownNestedOpenDialogs, ownNestedOpenDrawers, parentContext]);
|
|
258
|
+
const activeTriggerProps = dismiss.reference ?? EMPTY_OBJECT;
|
|
259
|
+
const inactiveTriggerProps = dismiss.trigger ?? EMPTY_OBJECT;
|
|
260
|
+
// Consumers (DialogPopup/DrawerPopup) already spread `FOCUSABLE_POPUP_PROPS`
|
|
261
|
+
// directly, so the popup props only need to carry the dismiss handlers.
|
|
262
|
+
const popupProps = dismiss.floating ?? EMPTY_OBJECT;
|
|
263
|
+
usePopupInteractionProps(store, {
|
|
551
264
|
activeTriggerProps,
|
|
552
265
|
inactiveTriggerProps,
|
|
553
266
|
popupProps,
|
|
554
|
-
|
|
555
|
-
|
|
267
|
+
nestedOpenDialogCount: ownNestedOpenDialogs,
|
|
268
|
+
nestedOpenDrawerCount: ownNestedOpenDrawers
|
|
556
269
|
});
|
|
270
|
+
return null;
|
|
557
271
|
}
|
|
558
272
|
|
|
559
273
|
const selectors = {
|
|
@@ -561,6 +275,7 @@ const selectors = {
|
|
|
561
275
|
modal: createSelector(state => state.modal),
|
|
562
276
|
nested: createSelector(state => state.nested),
|
|
563
277
|
nestedOpenDialogCount: createSelector(state => state.nestedOpenDialogCount),
|
|
278
|
+
nestedOpenDrawerCount: createSelector(state => state.nestedOpenDrawerCount),
|
|
564
279
|
disablePointerDismissal: createSelector(state => state.disablePointerDismissal),
|
|
565
280
|
openMethod: createSelector(state => state.openMethod),
|
|
566
281
|
descriptionElementId: createSelector(state => state.descriptionElementId),
|
|
@@ -569,15 +284,18 @@ const selectors = {
|
|
|
569
284
|
role: createSelector(state => state.role)
|
|
570
285
|
};
|
|
571
286
|
class DialogStore extends ReactStore {
|
|
572
|
-
constructor(initialState) {
|
|
573
|
-
|
|
287
|
+
constructor(initialState, floatingId, nested = false) {
|
|
288
|
+
const triggerElements = new PopupTriggerMap();
|
|
289
|
+
const state = createInitialState(initialState);
|
|
290
|
+
state.floatingRootContext = createPopupFloatingRootContext(triggerElements, floatingId, nested);
|
|
291
|
+
super(state, {
|
|
574
292
|
popupRef: /*#__PURE__*/React.createRef(),
|
|
575
293
|
backdropRef: /*#__PURE__*/React.createRef(),
|
|
576
294
|
internalBackdropRef: /*#__PURE__*/React.createRef(),
|
|
577
295
|
outsidePressEnabledRef: {
|
|
578
296
|
current: true
|
|
579
297
|
},
|
|
580
|
-
triggerElements
|
|
298
|
+
triggerElements,
|
|
581
299
|
onOpenChange: undefined,
|
|
582
300
|
onOpenChangeComplete: undefined
|
|
583
301
|
}, selectors);
|
|
@@ -595,26 +313,20 @@ class DialogStore extends ReactStore {
|
|
|
595
313
|
if (eventDetails.isCanceled) {
|
|
596
314
|
return;
|
|
597
315
|
}
|
|
598
|
-
|
|
599
|
-
open: nextOpen,
|
|
600
|
-
nativeEvent: eventDetails.event,
|
|
601
|
-
reason: eventDetails.reason,
|
|
602
|
-
nested: this.state.nested
|
|
603
|
-
};
|
|
604
|
-
this.state.floatingRootContext.context.events?.emit('openchange', details);
|
|
316
|
+
this.state.floatingRootContext.dispatchOpenChange(nextOpen, eventDetails);
|
|
605
317
|
const updatedState = {
|
|
606
318
|
open: nextOpen
|
|
607
319
|
};
|
|
608
|
-
|
|
609
|
-
// If a popup is closing, the `trigger` may be null.
|
|
610
|
-
// We want to keep the previous value so that exit animations are played and focus is returned correctly.
|
|
611
|
-
const newTriggerId = eventDetails.trigger?.id ?? null;
|
|
612
|
-
if (newTriggerId || nextOpen) {
|
|
613
|
-
updatedState.activeTriggerId = newTriggerId;
|
|
614
|
-
updatedState.activeTriggerElement = eventDetails.trigger ?? null;
|
|
615
|
-
}
|
|
320
|
+
setPopupOpenState(updatedState, nextOpen, eventDetails.trigger);
|
|
616
321
|
this.update(updatedState);
|
|
617
322
|
};
|
|
323
|
+
static useStore(externalStore, initialState) {
|
|
324
|
+
/* eslint-disable react-hooks/rules-of-hooks */
|
|
325
|
+
const store = usePopupStore(externalStore, (floatingId, nested) => new DialogStore(initialState, floatingId, nested), true).store;
|
|
326
|
+
/* eslint-enable react-hooks/rules-of-hooks */
|
|
327
|
+
|
|
328
|
+
return store;
|
|
329
|
+
}
|
|
618
330
|
}
|
|
619
331
|
function createInitialState(initialState = {}) {
|
|
620
332
|
return {
|
|
@@ -628,82 +340,105 @@ function createInitialState(initialState = {}) {
|
|
|
628
340
|
openMethod: null,
|
|
629
341
|
nested: false,
|
|
630
342
|
nestedOpenDialogCount: 0,
|
|
343
|
+
nestedOpenDrawerCount: 0,
|
|
631
344
|
role: 'dialog',
|
|
632
345
|
...initialState
|
|
633
346
|
};
|
|
634
347
|
}
|
|
635
348
|
|
|
636
|
-
|
|
637
|
-
* Groups all parts of the dialog.
|
|
638
|
-
* Doesn’t render its own HTML element.
|
|
639
|
-
*
|
|
640
|
-
* Documentation: [Base UI Dialog](https://base-ui.com/react/components/dialog)
|
|
641
|
-
*/
|
|
642
|
-
function DialogRoot(props) {
|
|
349
|
+
function useRenderDialogRoot(props, mode = 'dialog') {
|
|
643
350
|
const {
|
|
644
351
|
children,
|
|
645
352
|
open: openProp,
|
|
646
353
|
defaultOpen = false,
|
|
647
354
|
onOpenChange,
|
|
648
355
|
onOpenChangeComplete,
|
|
649
|
-
disablePointerDismissal = false,
|
|
650
|
-
modal = true,
|
|
356
|
+
disablePointerDismissal: disablePointerDismissalProp = false,
|
|
357
|
+
modal: modalProp = true,
|
|
651
358
|
actionsRef,
|
|
652
359
|
handle,
|
|
653
360
|
triggerId: triggerIdProp,
|
|
654
361
|
defaultTriggerId: defaultTriggerIdProp = null
|
|
655
362
|
} = props;
|
|
363
|
+
const isDrawer = mode === 'drawer';
|
|
364
|
+
const isAlertDialog = mode === 'alert-dialog';
|
|
365
|
+
const modal = isAlertDialog ? true : modalProp;
|
|
366
|
+
const disablePointerDismissal = isAlertDialog || disablePointerDismissalProp;
|
|
367
|
+
const role = isAlertDialog ? 'alertdialog' : 'dialog';
|
|
656
368
|
const parentDialogRootContext = useDialogRootContext(true);
|
|
657
369
|
const nested = Boolean(parentDialogRootContext);
|
|
658
|
-
const
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
370
|
+
const rootState = {
|
|
371
|
+
modal,
|
|
372
|
+
disablePointerDismissal,
|
|
373
|
+
nested,
|
|
374
|
+
role
|
|
375
|
+
};
|
|
376
|
+
const store = DialogStore.useStore(handle?.store, {
|
|
377
|
+
open: defaultOpen,
|
|
378
|
+
openProp,
|
|
379
|
+
activeTriggerId: defaultTriggerIdProp,
|
|
380
|
+
triggerIdProp,
|
|
381
|
+
...rootState
|
|
382
|
+
});
|
|
669
383
|
|
|
670
384
|
// Support initially open state when uncontrolled
|
|
671
385
|
useOnFirstRender(() => {
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
386
|
+
const nextState = openProp === undefined && store.state.open === false && defaultOpen === true ? {
|
|
387
|
+
open: true,
|
|
388
|
+
activeTriggerId: defaultTriggerIdProp
|
|
389
|
+
} : null;
|
|
390
|
+
if (isAlertDialog) {
|
|
391
|
+
// Handles can reuse plain Dialog stores; alert dialog invariants must exist immediately.
|
|
392
|
+
store.update(nextState ? {
|
|
393
|
+
...rootState,
|
|
394
|
+
...nextState
|
|
395
|
+
} : rootState);
|
|
396
|
+
} else if (nextState) {
|
|
397
|
+
store.update(nextState);
|
|
677
398
|
}
|
|
678
399
|
});
|
|
679
400
|
store.useControlledProp('openProp', openProp);
|
|
680
401
|
store.useControlledProp('triggerIdProp', triggerIdProp);
|
|
681
|
-
store.useSyncedValues(
|
|
682
|
-
disablePointerDismissal,
|
|
683
|
-
nested,
|
|
684
|
-
modal
|
|
685
|
-
});
|
|
402
|
+
store.useSyncedValues(rootState);
|
|
686
403
|
store.useContextCallback('onOpenChange', onOpenChange);
|
|
687
404
|
store.useContextCallback('onOpenChangeComplete', onOpenChangeComplete);
|
|
405
|
+
const open = store.useState('open');
|
|
406
|
+
const mounted = store.useState('mounted');
|
|
688
407
|
const payload = store.useState('payload');
|
|
689
408
|
useDialogRoot({
|
|
690
409
|
store,
|
|
691
|
-
actionsRef
|
|
692
|
-
parentContext: parentDialogRootContext?.store.context,
|
|
693
|
-
onOpenChange,
|
|
694
|
-
triggerIdProp
|
|
410
|
+
actionsRef
|
|
695
411
|
});
|
|
412
|
+
const shouldRenderInteractions = open || mounted;
|
|
696
413
|
const contextValue = React.useMemo(() => ({
|
|
697
414
|
store
|
|
698
415
|
}), [store]);
|
|
699
|
-
return /*#__PURE__*/jsx(
|
|
700
|
-
value:
|
|
701
|
-
children:
|
|
702
|
-
|
|
703
|
-
|
|
416
|
+
return /*#__PURE__*/jsx(IsDrawerContext.Provider, {
|
|
417
|
+
value: false,
|
|
418
|
+
children: /*#__PURE__*/jsxs(DialogRootContext.Provider, {
|
|
419
|
+
value: contextValue,
|
|
420
|
+
children: [shouldRenderInteractions && /*#__PURE__*/jsx(DialogInteractions, {
|
|
421
|
+
store: store,
|
|
422
|
+
parentContext: parentDialogRootContext?.store.context,
|
|
423
|
+
isDrawer: isDrawer
|
|
424
|
+
}), typeof children === 'function' ? children({
|
|
425
|
+
payload
|
|
426
|
+
}) : children]
|
|
427
|
+
})
|
|
704
428
|
});
|
|
705
429
|
}
|
|
706
430
|
|
|
431
|
+
/**
|
|
432
|
+
* Groups all parts of the dialog.
|
|
433
|
+
* Doesn't render its own HTML element.
|
|
434
|
+
*
|
|
435
|
+
* Documentation: [Base UI Dialog](https://base-ui.com/react/components/dialog)
|
|
436
|
+
*/
|
|
437
|
+
function DialogRoot(props) {
|
|
438
|
+
const mode = React.useContext(IsDrawerContext) ? 'drawer' : 'dialog';
|
|
439
|
+
return useRenderDialogRoot(props, mode);
|
|
440
|
+
}
|
|
441
|
+
|
|
707
442
|
/**
|
|
708
443
|
* A button that opens the dialog.
|
|
709
444
|
* Renders a `<button>` element.
|
|
@@ -714,6 +449,7 @@ const DialogTrigger = /*#__PURE__*/React.forwardRef(function DialogTrigger(compo
|
|
|
714
449
|
const {
|
|
715
450
|
render,
|
|
716
451
|
className,
|
|
452
|
+
style,
|
|
717
453
|
disabled = false,
|
|
718
454
|
nativeButton = true,
|
|
719
455
|
id: idProp,
|
|
@@ -729,6 +465,7 @@ const DialogTrigger = /*#__PURE__*/React.forwardRef(function DialogTrigger(compo
|
|
|
729
465
|
const thisTriggerId = useBaseUiId(idProp);
|
|
730
466
|
const floatingContext = store.useState('floatingRootContext');
|
|
731
467
|
const isOpenedByThisTrigger = store.useState('isOpenedByTrigger', thisTriggerId);
|
|
468
|
+
const popupId = store.useState('triggerPopupId', thisTriggerId);
|
|
732
469
|
const triggerElementRef = React.useRef(null);
|
|
733
470
|
const {
|
|
734
471
|
registerTrigger,
|
|
@@ -746,7 +483,9 @@ const DialogTrigger = /*#__PURE__*/React.forwardRef(function DialogTrigger(compo
|
|
|
746
483
|
const click = useClick(floatingContext, {
|
|
747
484
|
enabled: floatingContext != null
|
|
748
485
|
});
|
|
749
|
-
const
|
|
486
|
+
const interactionTypeProps = useOpenMethodTriggerProps(() => store.select('open'), interactionType => {
|
|
487
|
+
store.set('openMethod', interactionType);
|
|
488
|
+
});
|
|
750
489
|
const state = {
|
|
751
490
|
disabled,
|
|
752
491
|
open: isOpenedByThisTrigger
|
|
@@ -755,9 +494,12 @@ const DialogTrigger = /*#__PURE__*/React.forwardRef(function DialogTrigger(compo
|
|
|
755
494
|
return useRenderElement('button', componentProps, {
|
|
756
495
|
state,
|
|
757
496
|
ref: [buttonRef, forwardedRef, registerTrigger, triggerElementRef],
|
|
758
|
-
props: [
|
|
497
|
+
props: [click.reference, rootTriggerProps, interactionTypeProps, {
|
|
759
498
|
[CLICK_TRIGGER_IDENTIFIER]: '',
|
|
760
|
-
id: thisTriggerId
|
|
499
|
+
id: thisTriggerId,
|
|
500
|
+
'aria-haspopup': 'dialog',
|
|
501
|
+
'aria-expanded': isOpenedByThisTrigger,
|
|
502
|
+
'aria-controls': popupId
|
|
761
503
|
}, elementProps, getButtonProps],
|
|
762
504
|
stateAttributesMapping: triggerOpenStateMapping
|
|
763
505
|
});
|
|
@@ -827,6 +569,7 @@ const DrawerBackdrop = /*#__PURE__*/React.forwardRef(function DrawerBackdrop(com
|
|
|
827
569
|
const {
|
|
828
570
|
render,
|
|
829
571
|
className,
|
|
572
|
+
style,
|
|
830
573
|
forceRender = false,
|
|
831
574
|
...elementProps
|
|
832
575
|
} = componentProps;
|
|
@@ -873,6 +616,7 @@ const DrawerContent = /*#__PURE__*/React.forwardRef(function DrawerContent(compo
|
|
|
873
616
|
const {
|
|
874
617
|
render,
|
|
875
618
|
className,
|
|
619
|
+
style,
|
|
876
620
|
...elementProps
|
|
877
621
|
} = componentProps;
|
|
878
622
|
useDialogRootContext();
|
|
@@ -947,6 +691,17 @@ function useDrawerRootContext(optional) {
|
|
|
947
691
|
return drawerRootContext;
|
|
948
692
|
}
|
|
949
693
|
|
|
694
|
+
/**
|
|
695
|
+
* Resolves the vertical swipe movement for a snap point, applying square-root damping once the drag
|
|
696
|
+
* overshoots the fully-open edge (`nextOffset < 0`) so the popup resists travelling past it.
|
|
697
|
+
*/
|
|
698
|
+
function getSnapPointSwipeMovement(baseOffset, movementValue) {
|
|
699
|
+
const nextOffset = baseOffset + movementValue;
|
|
700
|
+
if (nextOffset >= 0) {
|
|
701
|
+
return movementValue;
|
|
702
|
+
}
|
|
703
|
+
return -Math.sqrt(-nextOffset) - baseOffset;
|
|
704
|
+
}
|
|
950
705
|
function resolveSnapPointValue(snapPoint, viewportHeight, rootFontSize) {
|
|
951
706
|
if (!Number.isFinite(viewportHeight) || viewportHeight <= 0) {
|
|
952
707
|
return null;
|
|
@@ -1100,7 +855,6 @@ let drawerSwipeVarsRegistered = false;
|
|
|
1100
855
|
/**
|
|
1101
856
|
* Removes inheritance of high-frequency drawer swipe CSS variables, which
|
|
1102
857
|
* reduces style recalculation cost in complex drawers with deep subtrees.
|
|
1103
|
-
* Child elements that need these values can still opt-in by using `inherit`.
|
|
1104
858
|
* See https://motion.dev/blog/web-animation-performance-tier-list
|
|
1105
859
|
* under the "Improving CSS variable performance" section.
|
|
1106
860
|
*/
|
|
@@ -1188,15 +942,17 @@ const stateAttributesMapping = {
|
|
|
1188
942
|
*/
|
|
1189
943
|
const DrawerPopup = /*#__PURE__*/React.forwardRef(function DrawerPopup(componentProps, forwardedRef) {
|
|
1190
944
|
const {
|
|
945
|
+
render,
|
|
1191
946
|
className,
|
|
947
|
+
style,
|
|
1192
948
|
finalFocus,
|
|
1193
949
|
initialFocus,
|
|
1194
|
-
render,
|
|
1195
950
|
...elementProps
|
|
1196
951
|
} = componentProps;
|
|
1197
952
|
const {
|
|
1198
953
|
store
|
|
1199
954
|
} = useDialogRootContext();
|
|
955
|
+
const popupRef = store.context.popupRef;
|
|
1200
956
|
const {
|
|
1201
957
|
swipeDirection,
|
|
1202
958
|
frontmostHeight,
|
|
@@ -1214,26 +970,39 @@ const DrawerPopup = /*#__PURE__*/React.forwardRef(function DrawerPopup(component
|
|
|
1214
970
|
const modal = store.useState('modal');
|
|
1215
971
|
const mounted = store.useState('mounted');
|
|
1216
972
|
const nested = store.useState('nested');
|
|
1217
|
-
const
|
|
973
|
+
const nestedOpenDrawerCount = store.useState('nestedOpenDrawerCount');
|
|
1218
974
|
const transitionStatus = store.useState('transitionStatus');
|
|
1219
975
|
const open = store.useState('open');
|
|
1220
976
|
const openMethod = store.useState('openMethod');
|
|
1221
977
|
const titleElementId = store.useState('titleElementId');
|
|
1222
978
|
const role = store.useState('role');
|
|
1223
|
-
const
|
|
979
|
+
const floatingId = floatingRootContext.useState('floatingId');
|
|
980
|
+
const popupId = elementProps.id ?? floatingId;
|
|
1224
981
|
const swipe = useDrawerViewportContext();
|
|
1225
|
-
|
|
1226
|
-
const swipeStrength = swipe?.swipeStrength ?? null;
|
|
982
|
+
useDialogPortalContext();
|
|
1227
983
|
const {
|
|
1228
984
|
snapPoints,
|
|
1229
985
|
activeSnapPoint,
|
|
1230
986
|
activeSnapPointOffset
|
|
1231
987
|
} = useDrawerSnapPoints();
|
|
1232
|
-
|
|
988
|
+
const nestedDrawerOpen = nestedOpenDrawerCount > 0;
|
|
989
|
+
const swiping = swipe?.swiping ?? false;
|
|
990
|
+
const swipeStrength = swipe?.swipeStrength ?? null;
|
|
1233
991
|
const [popupHeight, setPopupHeight] = React.useState(0);
|
|
1234
992
|
const popupHeightRef = React.useRef(0);
|
|
993
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
994
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
995
|
+
React.useEffect(() => {
|
|
996
|
+
if (swipe) {
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
const ownerStackMessage = SafeReact.captureOwnerStack?.() || '';
|
|
1000
|
+
const message = '<Drawer.Popup> expected to be rendered within <Drawer.Viewport>. Omitting the ' + 'viewport disables drawer swipe handling and touch scroll locking. Wrap ' + '<Drawer.Popup> in <Drawer.Viewport>.';
|
|
1001
|
+
error(`${message}${ownerStackMessage}`);
|
|
1002
|
+
}, [swipe]);
|
|
1003
|
+
}
|
|
1235
1004
|
const measureHeight = useStableCallback(() => {
|
|
1236
|
-
const popupElement =
|
|
1005
|
+
const popupElement = popupRef.current;
|
|
1237
1006
|
if (!popupElement) {
|
|
1238
1007
|
return;
|
|
1239
1008
|
}
|
|
@@ -1265,7 +1034,7 @@ const DrawerPopup = /*#__PURE__*/React.forwardRef(function DrawerPopup(component
|
|
|
1265
1034
|
onPopupHeightChange(0);
|
|
1266
1035
|
return undefined;
|
|
1267
1036
|
}
|
|
1268
|
-
const popupElement =
|
|
1037
|
+
const popupElement = popupRef.current;
|
|
1269
1038
|
if (!popupElement) {
|
|
1270
1039
|
return undefined;
|
|
1271
1040
|
}
|
|
@@ -1279,9 +1048,8 @@ const DrawerPopup = /*#__PURE__*/React.forwardRef(function DrawerPopup(component
|
|
|
1279
1048
|
return () => {
|
|
1280
1049
|
resizeObserver.disconnect();
|
|
1281
1050
|
};
|
|
1282
|
-
}, [measureHeight, mounted, nestedDrawerOpen, onPopupHeightChange,
|
|
1051
|
+
}, [measureHeight, mounted, nestedDrawerOpen, onPopupHeightChange, popupRef]);
|
|
1283
1052
|
useIsoLayoutEffect(() => {
|
|
1284
|
-
const popupRef = store.context.popupRef;
|
|
1285
1053
|
const syncNestedSwipeProgress = () => {
|
|
1286
1054
|
const popupElement = popupRef.current;
|
|
1287
1055
|
if (!popupElement) {
|
|
@@ -1296,14 +1064,14 @@ const DrawerPopup = /*#__PURE__*/React.forwardRef(function DrawerPopup(component
|
|
|
1296
1064
|
};
|
|
1297
1065
|
syncNestedSwipeProgress();
|
|
1298
1066
|
const unsubscribe = nestedSwipeProgressStore.subscribe(syncNestedSwipeProgress);
|
|
1067
|
+
const popupElement = popupRef.current;
|
|
1299
1068
|
return () => {
|
|
1300
1069
|
unsubscribe();
|
|
1301
|
-
const popupElement = popupRef.current;
|
|
1302
1070
|
if (popupElement) {
|
|
1303
1071
|
popupElement.style.setProperty(DrawerBackdropCssVars.swipeProgress, '0');
|
|
1304
1072
|
}
|
|
1305
1073
|
};
|
|
1306
|
-
}, [nestedSwipeProgressStore,
|
|
1074
|
+
}, [nestedSwipeProgressStore, popupRef]);
|
|
1307
1075
|
React.useEffect(() => {
|
|
1308
1076
|
if (!open) {
|
|
1309
1077
|
return undefined;
|
|
@@ -1325,14 +1093,15 @@ const DrawerPopup = /*#__PURE__*/React.forwardRef(function DrawerPopup(component
|
|
|
1325
1093
|
}, [notifyParentHasNestedDrawer, open, transitionStatus]);
|
|
1326
1094
|
useOpenChangeComplete({
|
|
1327
1095
|
open,
|
|
1328
|
-
ref:
|
|
1096
|
+
ref: popupRef,
|
|
1329
1097
|
onComplete() {
|
|
1330
1098
|
if (open) {
|
|
1331
1099
|
store.context.onOpenChangeComplete?.(true);
|
|
1332
1100
|
}
|
|
1333
1101
|
}
|
|
1334
1102
|
});
|
|
1335
|
-
const resolvedInitialFocus = initialFocus === undefined ?
|
|
1103
|
+
const resolvedInitialFocus = initialFocus === undefined ? popupRef : initialFocus;
|
|
1104
|
+
const setPopupElement = store.useStateSetter('popupElement');
|
|
1336
1105
|
const state = {
|
|
1337
1106
|
open,
|
|
1338
1107
|
nested,
|
|
@@ -1357,16 +1126,11 @@ const DrawerPopup = /*#__PURE__*/React.forwardRef(function DrawerPopup(component
|
|
|
1357
1126
|
if (shouldApplySnapPoints && swipeDirection === 'down') {
|
|
1358
1127
|
const baseOffset = activeSnapPointOffset ?? 0;
|
|
1359
1128
|
const movementValue = Number.parseFloat(String(dragStyles[DrawerPopupCssVars.swipeMovementY] ?? 0));
|
|
1360
|
-
|
|
1361
|
-
const shouldDamp = nextOffset < 0;
|
|
1362
|
-
if (swiping && shouldDamp && Number.isFinite(movementValue)) {
|
|
1363
|
-
const overshoot = Math.abs(nextOffset);
|
|
1364
|
-
const dampedOffset = -Math.sqrt(overshoot);
|
|
1365
|
-
const dampedMovement = dampedOffset - baseOffset;
|
|
1129
|
+
if (swiping && Number.isFinite(movementValue)) {
|
|
1366
1130
|
dragStyles = {
|
|
1367
1131
|
...dragStyles,
|
|
1368
1132
|
transform: undefined,
|
|
1369
|
-
[DrawerPopupCssVars.swipeMovementY]: `${
|
|
1133
|
+
[DrawerPopupCssVars.swipeMovementY]: `${getSnapPointSwipeMovement(baseOffset, movementValue)}px`
|
|
1370
1134
|
};
|
|
1371
1135
|
} else {
|
|
1372
1136
|
dragStyles = {
|
|
@@ -1378,10 +1142,11 @@ const DrawerPopup = /*#__PURE__*/React.forwardRef(function DrawerPopup(component
|
|
|
1378
1142
|
const element = useRenderElement('div', componentProps, {
|
|
1379
1143
|
state,
|
|
1380
1144
|
props: [rootPopupProps, {
|
|
1145
|
+
id: popupId,
|
|
1381
1146
|
'aria-labelledby': titleElementId,
|
|
1382
1147
|
'aria-describedby': descriptionElementId,
|
|
1383
1148
|
role,
|
|
1384
|
-
|
|
1149
|
+
...FOCUSABLE_POPUP_PROPS,
|
|
1385
1150
|
hidden: !mounted,
|
|
1386
1151
|
onKeyDown(event) {
|
|
1387
1152
|
if (COMPOSITE_KEYS.has(event.key)) {
|
|
@@ -1391,14 +1156,14 @@ const DrawerPopup = /*#__PURE__*/React.forwardRef(function DrawerPopup(component
|
|
|
1391
1156
|
style: {
|
|
1392
1157
|
...dragStyles,
|
|
1393
1158
|
[DrawerBackdropCssVars.swipeProgress]: '0',
|
|
1394
|
-
[DrawerPopupCssVars.nestedDrawers]:
|
|
1159
|
+
[DrawerPopupCssVars.nestedDrawers]: nestedOpenDrawerCount,
|
|
1395
1160
|
[DrawerPopupCssVars.height]: popupHeightCssVarValue,
|
|
1396
1161
|
[DrawerPopupCssVars.snapPointOffset]: typeof snapPointOffsetValue === 'number' ? `${snapPointOffsetValue}px` : '0px',
|
|
1397
1162
|
[DrawerPopupCssVars.frontmostHeight]: frontmostHeight ? `${frontmostHeight}px` : undefined,
|
|
1398
1163
|
[DrawerPopupCssVars.swipeStrength]: typeof swipeStrength === 'number' && Number.isFinite(swipeStrength) && swipeStrength > 0 ? `${swipeStrength}` : '1'
|
|
1399
1164
|
}
|
|
1400
1165
|
}, elementProps],
|
|
1401
|
-
ref: [forwardedRef,
|
|
1166
|
+
ref: [forwardedRef, popupRef, setPopupElement],
|
|
1402
1167
|
stateAttributesMapping
|
|
1403
1168
|
});
|
|
1404
1169
|
return /*#__PURE__*/jsx(FloatingFocusManager, {
|
|
@@ -1449,9 +1214,8 @@ function DrawerRoot(props) {
|
|
|
1449
1214
|
snapPoints,
|
|
1450
1215
|
snapPoint: snapPointProp,
|
|
1451
1216
|
defaultSnapPoint,
|
|
1452
|
-
onSnapPointChange
|
|
1217
|
+
onSnapPointChange
|
|
1453
1218
|
} = props;
|
|
1454
|
-
const onSnapPointChange = useStableCallback(onSnapPointChangeProp);
|
|
1455
1219
|
const parentDrawerRootContext = useDrawerRootContext(true);
|
|
1456
1220
|
const notifyParentSwipeProgressChange = parentDrawerRootContext?.onNestedSwipeProgressChange;
|
|
1457
1221
|
const notifyParentFrontmostHeight = parentDrawerRootContext?.onNestedFrontmostHeightChange;
|
|
@@ -1556,18 +1320,21 @@ function DrawerRoot(props) {
|
|
|
1556
1320
|
});
|
|
1557
1321
|
return /*#__PURE__*/jsx(DrawerRootContext.Provider, {
|
|
1558
1322
|
value: contextValue,
|
|
1559
|
-
children: /*#__PURE__*/jsx(
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1323
|
+
children: /*#__PURE__*/jsx(IsDrawerContext.Provider, {
|
|
1324
|
+
value: true,
|
|
1325
|
+
children: /*#__PURE__*/jsx(DialogRoot, {
|
|
1326
|
+
open: openProp,
|
|
1327
|
+
defaultOpen: defaultOpen,
|
|
1328
|
+
onOpenChange: handleOpenChange,
|
|
1329
|
+
onOpenChangeComplete: onOpenChangeComplete,
|
|
1330
|
+
disablePointerDismissal: disablePointerDismissal,
|
|
1331
|
+
modal: modal,
|
|
1332
|
+
actionsRef: actionsRef,
|
|
1333
|
+
handle: handle,
|
|
1334
|
+
triggerId: triggerIdProp,
|
|
1335
|
+
defaultTriggerId: defaultTriggerIdProp,
|
|
1336
|
+
children: resolvedChildren
|
|
1337
|
+
})
|
|
1571
1338
|
})
|
|
1572
1339
|
});
|
|
1573
1340
|
}
|
|
@@ -1597,10 +1364,12 @@ function createNestedSwipeProgressStore() {
|
|
|
1597
1364
|
function DrawerProviderReporter() {
|
|
1598
1365
|
const drawerId = useId();
|
|
1599
1366
|
const providerContext = useDrawerProviderContext();
|
|
1600
|
-
const
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
const
|
|
1367
|
+
const {
|
|
1368
|
+
store
|
|
1369
|
+
} = useDialogRootContext(false);
|
|
1370
|
+
const open = store.useState('open');
|
|
1371
|
+
const nestedOpenDialogCount = store.useState('nestedOpenDialogCount');
|
|
1372
|
+
const popupElement = store.useState('popupElement');
|
|
1604
1373
|
const isTopmost = nestedOpenDialogCount === 0;
|
|
1605
1374
|
React.useEffect(() => {
|
|
1606
1375
|
if (!providerContext || drawerId == null) {
|
|
@@ -1619,7 +1388,7 @@ function DrawerProviderReporter() {
|
|
|
1619
1388
|
React.useEffect(() => {
|
|
1620
1389
|
// CloseWatcher enables the Android back gesture (Chromium-only).
|
|
1621
1390
|
// Keep this Android-only for now to avoid interfering with Escape/nesting semantics on desktop due to `useDismiss`.
|
|
1622
|
-
if (!open || !isTopmost || !
|
|
1391
|
+
if (!open || !isTopmost || !android) {
|
|
1623
1392
|
return undefined;
|
|
1624
1393
|
}
|
|
1625
1394
|
const win = getWindow(popupElement);
|
|
@@ -1628,18 +1397,18 @@ function DrawerProviderReporter() {
|
|
|
1628
1397
|
return undefined;
|
|
1629
1398
|
}
|
|
1630
1399
|
function handleCloseWatcher(event) {
|
|
1631
|
-
if (!
|
|
1400
|
+
if (!store.select('open')) {
|
|
1632
1401
|
return;
|
|
1633
1402
|
}
|
|
1634
|
-
|
|
1403
|
+
store.setOpen(false, createChangeEventDetails(closeWatcher, event));
|
|
1635
1404
|
}
|
|
1636
1405
|
const closeWatcher$1 = new CloseWatcherCtor();
|
|
1637
|
-
closeWatcher$1
|
|
1406
|
+
const unsubscribe = addEventListener(closeWatcher$1, 'close', handleCloseWatcher);
|
|
1638
1407
|
return () => {
|
|
1639
|
-
|
|
1408
|
+
unsubscribe();
|
|
1640
1409
|
closeWatcher$1.destroy();
|
|
1641
1410
|
};
|
|
1642
|
-
}, [
|
|
1411
|
+
}, [store, isTopmost, open, popupElement]);
|
|
1643
1412
|
return null;
|
|
1644
1413
|
}
|
|
1645
1414
|
|
|
@@ -1818,9 +1587,15 @@ const ScrollAreaRoot = /*#__PURE__*/React.forwardRef(function ScrollAreaRoot(com
|
|
|
1818
1587
|
render,
|
|
1819
1588
|
className,
|
|
1820
1589
|
overflowEdgeThreshold: overflowEdgeThresholdProp,
|
|
1590
|
+
style,
|
|
1821
1591
|
...elementProps
|
|
1822
1592
|
} = componentProps;
|
|
1823
|
-
const
|
|
1593
|
+
const {
|
|
1594
|
+
xStart,
|
|
1595
|
+
xEnd,
|
|
1596
|
+
yStart,
|
|
1597
|
+
yEnd
|
|
1598
|
+
} = normalizeOverflowEdgeThreshold(overflowEdgeThresholdProp);
|
|
1824
1599
|
const rootId = useBaseUiId();
|
|
1825
1600
|
const scrollYTimeout = useTimeout();
|
|
1826
1601
|
const scrollXTimeout = useTimeout();
|
|
@@ -1928,10 +1703,13 @@ const ScrollAreaRoot = /*#__PURE__*/React.forwardRef(function ScrollAreaRoot(com
|
|
|
1928
1703
|
});
|
|
1929
1704
|
const handlePointerUp = useStableCallback(event => {
|
|
1930
1705
|
thumbDraggingRef.current = false;
|
|
1931
|
-
|
|
1706
|
+
|
|
1707
|
+
// `pointercancel` releases capture implicitly, so guard against releasing a
|
|
1708
|
+
// capture we no longer hold (which would throw).
|
|
1709
|
+
if (thumbYRef.current && currentOrientationRef.current === 'vertical' && thumbYRef.current.hasPointerCapture(event.pointerId)) {
|
|
1932
1710
|
thumbYRef.current.releasePointerCapture(event.pointerId);
|
|
1933
1711
|
}
|
|
1934
|
-
if (thumbXRef.current && currentOrientationRef.current === 'horizontal') {
|
|
1712
|
+
if (thumbXRef.current && currentOrientationRef.current === 'horizontal' && thumbXRef.current.hasPointerCapture(event.pointerId)) {
|
|
1935
1713
|
thumbXRef.current.releasePointerCapture(event.pointerId);
|
|
1936
1714
|
}
|
|
1937
1715
|
});
|
|
@@ -2006,8 +1784,13 @@ const ScrollAreaRoot = /*#__PURE__*/React.forwardRef(function ScrollAreaRoot(com
|
|
|
2006
1784
|
overflowEdges,
|
|
2007
1785
|
setOverflowEdges,
|
|
2008
1786
|
viewportState: state,
|
|
2009
|
-
overflowEdgeThreshold
|
|
2010
|
-
|
|
1787
|
+
overflowEdgeThreshold: {
|
|
1788
|
+
xStart,
|
|
1789
|
+
xEnd,
|
|
1790
|
+
yStart,
|
|
1791
|
+
yEnd
|
|
1792
|
+
}
|
|
1793
|
+
}), [handlePointerDown, handlePointerMove, handlePointerUp, handleScroll, cornerSize, thumbSize, hasMeasuredScrollbar, touchModality, scrollingX, setScrollingX, scrollingY, setScrollingY, hovering, setHovering, rootId, hiddenState, overflowEdges, state, xStart, xEnd, yStart, yEnd]);
|
|
2011
1794
|
return /*#__PURE__*/jsxs(ScrollAreaRootContext.Provider, {
|
|
2012
1795
|
value: contextValue,
|
|
2013
1796
|
children: [!disableStyleElements && styleDisableScrollbar.getElement(nonce), element]
|
|
@@ -2042,27 +1825,6 @@ function useScrollAreaViewportContext() {
|
|
|
2042
1825
|
return context;
|
|
2043
1826
|
}
|
|
2044
1827
|
|
|
2045
|
-
/**
|
|
2046
|
-
* Executes a callback when an element becomes visible.
|
|
2047
|
-
*/
|
|
2048
|
-
function onVisible(element, callback) {
|
|
2049
|
-
if (typeof IntersectionObserver === 'undefined') {
|
|
2050
|
-
return () => {};
|
|
2051
|
-
}
|
|
2052
|
-
const observer = new IntersectionObserver(entries => {
|
|
2053
|
-
entries.forEach(entry => {
|
|
2054
|
-
if (entry.intersectionRatio > 0) {
|
|
2055
|
-
callback();
|
|
2056
|
-
observer.disconnect();
|
|
2057
|
-
}
|
|
2058
|
-
});
|
|
2059
|
-
});
|
|
2060
|
-
observer.observe(element);
|
|
2061
|
-
return () => {
|
|
2062
|
-
observer.disconnect();
|
|
2063
|
-
};
|
|
2064
|
-
}
|
|
2065
|
-
|
|
2066
1828
|
let ScrollAreaViewportCssVars = /*#__PURE__*/function (ScrollAreaViewportCssVars) {
|
|
2067
1829
|
/**
|
|
2068
1830
|
* The distance from the horizontal start edge in pixels.
|
|
@@ -2087,30 +1849,7 @@ let ScrollAreaViewportCssVars = /*#__PURE__*/function (ScrollAreaViewportCssVars
|
|
|
2087
1849
|
return ScrollAreaViewportCssVars;
|
|
2088
1850
|
}({});
|
|
2089
1851
|
|
|
2090
|
-
const SCROLL_EDGE_TOLERANCE_PX = 1;
|
|
2091
|
-
function normalizeScrollOffset(value, max) {
|
|
2092
|
-
if (max <= 0) {
|
|
2093
|
-
return 0;
|
|
2094
|
-
}
|
|
2095
|
-
const clamped = clamp(value, 0, max);
|
|
2096
|
-
const startDistance = clamped;
|
|
2097
|
-
const endDistance = max - clamped;
|
|
2098
|
-
const withinStartTolerance = startDistance <= SCROLL_EDGE_TOLERANCE_PX;
|
|
2099
|
-
const withinEndTolerance = endDistance <= SCROLL_EDGE_TOLERANCE_PX;
|
|
2100
|
-
if (withinStartTolerance && withinEndTolerance) {
|
|
2101
|
-
return startDistance <= endDistance ? 0 : max;
|
|
2102
|
-
}
|
|
2103
|
-
if (withinStartTolerance) {
|
|
2104
|
-
return 0;
|
|
2105
|
-
}
|
|
2106
|
-
if (withinEndTolerance) {
|
|
2107
|
-
return max;
|
|
2108
|
-
}
|
|
2109
|
-
return clamped;
|
|
2110
|
-
}
|
|
2111
|
-
|
|
2112
1852
|
let scrollAreaOverflowVarsRegistered = false;
|
|
2113
|
-
const HAS_RESIZE_OBSERVER = typeof ResizeObserver !== 'undefined';
|
|
2114
1853
|
|
|
2115
1854
|
/**
|
|
2116
1855
|
* Removes inheritance of the scroll area overflow CSS variables, which
|
|
@@ -2124,7 +1863,7 @@ function removeCSSVariableInheritance() {
|
|
|
2124
1863
|
if (scrollAreaOverflowVarsRegistered ||
|
|
2125
1864
|
// When `inherits: false`, specifying `inherit` on child elements doesn't work
|
|
2126
1865
|
// in Safari. To let CSS features work correctly, this optimization must be skipped.
|
|
2127
|
-
|
|
1866
|
+
webkit) {
|
|
2128
1867
|
return;
|
|
2129
1868
|
}
|
|
2130
1869
|
if (typeof CSS !== 'undefined' && 'registerProperty' in CSS) {
|
|
@@ -2154,6 +1893,7 @@ const ScrollAreaViewport = /*#__PURE__*/React.forwardRef(function ScrollAreaView
|
|
|
2154
1893
|
const {
|
|
2155
1894
|
render,
|
|
2156
1895
|
className,
|
|
1896
|
+
style,
|
|
2157
1897
|
...elementProps
|
|
2158
1898
|
} = componentProps;
|
|
2159
1899
|
const {
|
|
@@ -2323,20 +2063,15 @@ const ScrollAreaViewport = /*#__PURE__*/React.forwardRef(function ScrollAreaView
|
|
|
2323
2063
|
});
|
|
2324
2064
|
useIsoLayoutEffect(() => {
|
|
2325
2065
|
if (!viewportRef.current) {
|
|
2326
|
-
return
|
|
2066
|
+
return;
|
|
2327
2067
|
}
|
|
2328
2068
|
removeCSSVariableInheritance();
|
|
2329
|
-
|
|
2330
|
-
return undefined;
|
|
2331
|
-
}
|
|
2332
|
-
return onVisible(viewportRef.current, () => {
|
|
2333
|
-
computeThumbPosition();
|
|
2334
|
-
});
|
|
2335
|
-
}, [computeThumbPosition, viewportRef]);
|
|
2069
|
+
}, [viewportRef]);
|
|
2336
2070
|
useIsoLayoutEffect(() => {
|
|
2337
|
-
// Wait for scrollbar and thumb refs after hidden-state toggles,
|
|
2071
|
+
// Wait for scrollbar and thumb refs after hidden-state toggles, refresh math on direction
|
|
2072
|
+
// flips, and re-evaluate overflow edges when the threshold changes.
|
|
2338
2073
|
queueMicrotask(computeThumbPosition);
|
|
2339
|
-
}, [computeThumbPosition, hiddenState, direction]);
|
|
2074
|
+
}, [computeThumbPosition, hiddenState, direction, overflowEdgeThreshold.xStart, overflowEdgeThreshold.xEnd, overflowEdgeThreshold.yStart, overflowEdgeThreshold.yEnd]);
|
|
2340
2075
|
useIsoLayoutEffect(() => {
|
|
2341
2076
|
// `onMouseEnter` doesn't fire upon load, so we need to check if the viewport is already
|
|
2342
2077
|
// being hovered.
|
|
@@ -2344,13 +2079,13 @@ const ScrollAreaViewport = /*#__PURE__*/React.forwardRef(function ScrollAreaView
|
|
|
2344
2079
|
setHovering(true);
|
|
2345
2080
|
}
|
|
2346
2081
|
}, [viewportRef, setHovering]);
|
|
2347
|
-
|
|
2082
|
+
useIsoLayoutEffect(() => {
|
|
2348
2083
|
const viewport = viewportRef.current;
|
|
2349
|
-
if (
|
|
2084
|
+
if (typeof ResizeObserver === 'undefined' || !viewport) {
|
|
2350
2085
|
return undefined;
|
|
2351
2086
|
}
|
|
2352
2087
|
let hasInitialized = false;
|
|
2353
|
-
const
|
|
2088
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
2354
2089
|
// Avoid duplicate mount-time recompute when observer data matches what the mount
|
|
2355
2090
|
// scheduling pass already measured. If dimensions changed before the first observer
|
|
2356
2091
|
// delivery, keep the recompute so overflow transitions stay in sync.
|
|
@@ -2363,15 +2098,10 @@ const ScrollAreaViewport = /*#__PURE__*/React.forwardRef(function ScrollAreaView
|
|
|
2363
2098
|
}
|
|
2364
2099
|
computeThumbPosition();
|
|
2365
2100
|
});
|
|
2366
|
-
|
|
2101
|
+
resizeObserver.observe(viewport);
|
|
2367
2102
|
|
|
2368
|
-
//
|
|
2369
|
-
//
|
|
2370
|
-
// and the popup is using a transform for the animation, which affects the size of the viewport.
|
|
2371
|
-
// Without this, the thumb position will be incorrect until scrolling (i.e. if the scrollbar shows
|
|
2372
|
-
// on hover, the thumb has an incorrect size).
|
|
2373
|
-
// We assume the user is using `onOpenChangeComplete` to hide the scrollbar
|
|
2374
|
-
// until animations complete because otherwise the scrollbar would show the thumb resizing mid-animation.
|
|
2103
|
+
// Wait for subtree animations to finish, then recompute thumb geometry that
|
|
2104
|
+
// may have been affected by transform-based animations.
|
|
2375
2105
|
waitForAnimationsTimeout.start(0, () => {
|
|
2376
2106
|
const animations = viewport.getAnimations({
|
|
2377
2107
|
subtree: true
|
|
@@ -2382,7 +2112,7 @@ const ScrollAreaViewport = /*#__PURE__*/React.forwardRef(function ScrollAreaView
|
|
|
2382
2112
|
Promise.allSettled(animations.map(animation => animation.finished)).then(computeThumbPosition).catch(() => {});
|
|
2383
2113
|
});
|
|
2384
2114
|
return () => {
|
|
2385
|
-
|
|
2115
|
+
resizeObserver.disconnect();
|
|
2386
2116
|
waitForAnimationsTimeout.clear();
|
|
2387
2117
|
};
|
|
2388
2118
|
}, [computeThumbPosition, viewportRef, waitForAnimationsTimeout]);
|
|
@@ -2470,4 +2200,4 @@ function mergeHiddenState(prevState, nextState) {
|
|
|
2470
2200
|
return nextState;
|
|
2471
2201
|
}
|
|
2472
2202
|
|
|
2473
|
-
export {
|
|
2203
|
+
export { ScrollAreaRootCssVars as A, scrollAreaStateAttributesMapping as B, useScrollAreaViewportContext as C, DrawerTrigger as D, ScrollAreaRoot as S, DrawerRoot as a, DrawerPortal as b, DrawerBackdrop as c, DrawerPopup as d, ScrollAreaViewport as e, DrawerContent as f, DialogRoot as g, DialogTrigger as h, DialogPortal as i, useDialogPortalContext as j, DialogStore as k, createInitialPopupStoreState as l, useDrawerProviderContext as m, DrawerBackdropCssVars as n, DrawerPopupCssVars as o, popupStoreSelectors as p, DrawerProviderContext as q, useDrawerRootContext as r, DrawerPopupDataAttributes as s, useDrawerSnapPoints as t, useDialogRootContext as u, getSnapPointSwipeMovement as v, DrawerViewportContext as w, DRAWER_CONTENT_ATTRIBUTE as x, useScrollAreaRootContext as y, getOffset as z };
|