@astryxdesign/core 0.7.3 → 0.7.4-canary.1b56e00
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/BottomSheet/BottomSheet.d.ts +18 -6
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +268 -58
- package/dist/BottomSheet/BottomSheetSwitcher.d.ts +41 -12
- package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetSwitcher.js +294 -165
- package/dist/BottomSheet/BottomSheetSwitcherContext.d.ts +51 -1
- package/dist/BottomSheet/BottomSheetSwitcherContext.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetSwitcherContext.js +13 -1
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +7 -11
- package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/Chat/useTriggerMenu.js +46 -7
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +6 -0
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +6 -1
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +12 -0
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +6 -1
- package/dist/DateInput/NativeDateField.d.ts.map +1 -1
- package/dist/DateInput/NativeDateField.js +6 -1
- package/dist/DateInput/TouchDateField.d.ts.map +1 -1
- package/dist/DateInput/TouchDateField.js +9 -1
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +6 -1
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +6 -1
- package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
- package/dist/DateTimeInput/TouchDateTimeField.js +9 -1
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +6 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +6 -1
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +6 -1
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +6 -1
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +6 -1
- package/dist/TimeInput/TouchTimeField.d.ts.map +1 -1
- package/dist/TimeInput/TouchTimeField.js +9 -1
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +9 -1
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +7 -1
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +9 -1
- package/dist/astryx.css +2 -0
- package/dist/hooks/useBusyAnnouncement.d.ts +22 -0
- package/dist/hooks/useBusyAnnouncement.d.ts.map +1 -0
- package/dist/hooks/useBusyAnnouncement.js +87 -0
- package/dist/hooks/useMenuPress.d.ts +2 -2
- package/dist/hooks/useMenuPress.d.ts.map +1 -1
- package/dist/hooks/useMenuPress.js +5 -1
- package/dist/hooks/useTypeahead.d.ts.map +1 -1
- package/dist/hooks/useTypeahead.js +7 -2
- package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/en.generated.js +1 -0
- package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/pseudo.generated.js +1 -0
- package/locales/en.json +6 -2
- package/locales/pseudo.json +3 -0
- package/package.json +4 -4
- package/src/BottomSheet/BottomSheet.doc.mjs +2 -2
- package/src/BottomSheet/BottomSheet.spec.md +2 -5
- package/src/BottomSheet/BottomSheet.tsx +260 -47
- package/src/BottomSheet/BottomSheetEdgeTint.test.tsx +4 -2
- package/src/BottomSheet/BottomSheetSwitcher.doc.mjs +11 -10
- package/src/BottomSheet/BottomSheetSwitcher.spec.md +28 -35
- package/src/BottomSheet/BottomSheetSwitcher.test.tsx +830 -48
- package/src/BottomSheet/BottomSheetSwitcher.tsx +396 -215
- package/src/BottomSheet/BottomSheetSwitcherContext.ts +57 -2
- package/src/Carousel/Carousel.test.tsx +8 -12
- package/src/Carousel/Carousel.tsx +6 -13
- package/src/Chat/ChatComposerInput.test.tsx +167 -1
- package/src/Chat/useTriggerMenu.tsx +55 -6
- package/src/CheckboxInput/CheckboxInput.tsx +6 -0
- package/src/ComplexSelector/ComplexSelector.tsx +5 -1
- package/src/ContextMenu/ContextMenu.test.tsx +34 -0
- package/src/ContextMenu/ContextMenu.tsx +13 -1
- package/src/DateInput/DateInput.tsx +5 -1
- package/src/DateInput/DateInputTouch.test.tsx +45 -0
- package/src/DateInput/NativeDateField.test.tsx +10 -2
- package/src/DateInput/NativeDateField.tsx +5 -1
- package/src/DateInput/TouchDateField.tsx +14 -2
- package/src/DateRangeInput/DateRangeInput.tsx +5 -1
- package/src/DateTimeInput/DateTimeInput.tsx +5 -1
- package/src/DateTimeInput/TouchDateTimeField.tsx +14 -2
- package/src/MultiSelector/MultiSelector.test.tsx +18 -4
- package/src/MultiSelector/MultiSelector.tsx +5 -1
- package/src/ProgressBar/ProgressBar.test.tsx +4 -21
- package/src/ProgressBar/__tests__/ProgressBar.a11y.chromium.spec.ts +114 -0
- package/src/ProgressBar/__tests__/ProgressBar.a11y.known-failures.ts +12 -0
- package/src/ProgressBar/__tests__/ProgressBar.a11y.renders.tsx +38 -0
- package/src/ProgressBar/__tests__/ProgressBar.a11y.states.ts +123 -0
- package/src/ProgressBar/__tests__/ProgressBar.a11y.test.tsx +107 -0
- package/src/Selector/Selector.test.tsx +22 -5
- package/src/Selector/Selector.tsx +5 -1
- package/src/TextArea/TextArea.test.tsx +9 -1
- package/src/TextArea/TextArea.tsx +5 -1
- package/src/TextInput/TextInput.tsx +5 -1
- package/src/TimeInput/TimeInput.tsx +5 -1
- package/src/TimeInput/TouchTimeField.tsx +12 -2
- package/src/Tokenizer/Tokenizer.test.tsx +17 -12
- package/src/Tokenizer/Tokenizer.tsx +10 -1
- package/src/Typeahead/BaseTypeahead.tsx +14 -1
- package/src/Typeahead/Typeahead.test.tsx +32 -41
- package/src/Typeahead/Typeahead.tsx +10 -1
- package/src/__tests__/BusyOwnerAnnouncement.test.tsx +483 -0
- package/src/hooks/__tests__/MenuPressShadowRoot.a11y.chromium.spec.ts +50 -0
- package/src/hooks/useBusyAnnouncement.ts +100 -0
- package/src/hooks/useMenuPress.test.tsx +27 -1
- package/src/hooks/useMenuPress.ts +12 -3
- package/src/hooks/useTypeahead.test.tsx +42 -1
- package/src/hooks/useTypeahead.ts +7 -2
- package/src/i18n/generated-locales/en.generated.ts +1 -0
- package/src/i18n/generated-locales/pseudo.generated.ts +1 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file BottomSheetSwitcher.tsx
|
|
7
|
-
* @input Uses React context, StyleX,
|
|
7
|
+
* @input Uses React context, StyleX, shared layer dismissal, BottomSheetSwitcherContext
|
|
8
8
|
* @output Exports BottomSheetSwitcher and BottomSheetSwitcherProps
|
|
9
9
|
* @position Core switcher for mutually exclusive BottomSheet flows
|
|
10
10
|
*
|
|
@@ -15,14 +15,37 @@
|
|
|
15
15
|
* down at the same time until their top edges align; otherwise it stays
|
|
16
16
|
* stationary. The previous sheet fades only after both motions complete.
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
* scrim flow
|
|
20
|
-
*
|
|
21
|
-
*
|
|
18
|
+
* Every child sheet owns a native `<dialog>`, exactly like a standalone
|
|
19
|
+
* sheet: a scrim flow presents each sheet with showModal(), a no-scrim flow
|
|
20
|
+
* with show(). The browser then does what a modal dialog does -- the page is
|
|
21
|
+
* inert, focus stays in the top-layer dialog, Escape and the platform close
|
|
22
|
+
* arrive as `cancel`. The switcher is the coordinator: it decides which
|
|
23
|
+
* sheet dialog is presented, retained, or hidden, keeps one scrim painted
|
|
24
|
+
* across a handoff (the retained sheet's backdrop until it fades, then the
|
|
25
|
+
* new sheet's, swapped without a fade), holds the flow's one page scroll
|
|
26
|
+
* lock (the shared useScrollLock, as Dialog uses, acquired once while the
|
|
27
|
+
* flow is presented and released after its exit, never per step) and the
|
|
28
|
+
* one layer-dismissal registration, and returns focus to the flow's opener
|
|
29
|
+
* when the flow ends, which no single dialog can know.
|
|
30
|
+
*
|
|
31
|
+
* The switcher's one element is a flow wrapper. In a scrim flow it has no box
|
|
32
|
+
* (`display: contents`): the dialogs sit in the top layer. In a no-scrim flow
|
|
33
|
+
* it is the isolated surface that orders the sheet dialogs locally, the way
|
|
34
|
+
* the shared shell once did, so no sheet needs a page-level value of its own.
|
|
35
|
+
*
|
|
36
|
+
* Its `ref` resolves to the host dialog: the one presenting the active sheet,
|
|
37
|
+
* the exiting sheet's through its exit, and the last host's (or the first
|
|
38
|
+
* mounted sheet's) while the flow is closed, so the ref is never null while a
|
|
39
|
+
* sheet is mounted. `id` and `data-testid` render on the host dialog only:
|
|
40
|
+
* a flow that mounts open carries them on the active sheet's dialog in server
|
|
41
|
+
* markup too; a flow that mounts closed carries them from the first commit's
|
|
42
|
+
* synchronous re-render on, and its server markup carries them on no element.
|
|
43
|
+
* Every other dialog prop and handler, `onCancel` included, applies to every
|
|
44
|
+
* sheet dialog; the browser raises `cancel` on the dialog it presents.
|
|
22
45
|
*
|
|
23
46
|
* SYNC: When modified, update these files to stay in sync:
|
|
24
47
|
* - /packages/core/src/BottomSheet/BottomSheet.tsx
|
|
25
|
-
* - /packages/core/src/BottomSheet/
|
|
48
|
+
* - /packages/core/src/BottomSheet/BottomSheetSwitcherContext.ts
|
|
26
49
|
* - /packages/core/src/BottomSheet/BottomSheetSwitcher.doc.mjs
|
|
27
50
|
* - /packages/core/src/BottomSheet/BottomSheetSwitcher.spec.md
|
|
28
51
|
* - /packages/core/src/BottomSheet/BottomSheetSwitcher.test.tsx
|
|
@@ -32,62 +55,14 @@
|
|
|
32
55
|
*/
|
|
33
56
|
import { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
34
57
|
import * as stylex from '@stylexjs/stylex';
|
|
35
|
-
import "../theme/tokens.stylex.js";
|
|
36
|
-
import { colorVars, durationVars, easeVars } from "../theme/tokens.stylex.js";
|
|
37
58
|
import { useScrollLock } from "../hooks/index.js";
|
|
38
|
-
import {
|
|
39
|
-
import { LayerDepthProvider } from "../Layer/LayerDepthContext.js";
|
|
59
|
+
import { useFocusTrapEscapeCompatibilitySignal } from "../hooks/useFocusTrap.js";
|
|
40
60
|
import { dispatchLayerEscapeKeyDown } from "../Layer/layerStack.js";
|
|
41
61
|
import { useLayerDismissal } from "../Layer/useLayerDismissal.js";
|
|
42
|
-
import { composeEventHandlers
|
|
43
|
-
import {
|
|
62
|
+
import { composeEventHandlers } from "../utils/index.js";
|
|
63
|
+
import { mergeRefs } from "../utils/mergeRefs.js";
|
|
44
64
|
import { BottomSheetSwitcherContext } from "./BottomSheetSwitcherContext.js";
|
|
45
|
-
import {
|
|
46
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
47
|
-
const styles = {
|
|
48
|
-
dialog: {
|
|
49
|
-
kVAEAm: "xixxii4",
|
|
50
|
-
kpwlN0: "x10a8y8t",
|
|
51
|
-
kzqmXN: "x1o6l61p",
|
|
52
|
-
kZKoxP: "xtdtrs8",
|
|
53
|
-
ks0D6T: "x1x1rfll",
|
|
54
|
-
kskxy: "x7ab17h",
|
|
55
|
-
kogj98: "x1ghz6dp",
|
|
56
|
-
kmVPX3: "x1717udv",
|
|
57
|
-
kMzoRj: "xc342km",
|
|
58
|
-
ksu8eU: "xng3xce",
|
|
59
|
-
kWkggS: "xjbqb8w",
|
|
60
|
-
kVQacm: "x1rea2x4",
|
|
61
|
-
k1xSpc: "x1s85apg",
|
|
62
|
-
kI3sdo: "x1a2a7pz",
|
|
63
|
-
$$css: true
|
|
64
|
-
},
|
|
65
|
-
dialogOpen: {
|
|
66
|
-
k1xSpc: "x1lliihq",
|
|
67
|
-
$$css: true
|
|
68
|
-
},
|
|
69
|
-
dialogNonModal: {
|
|
70
|
-
kfzvcC: "x47corl",
|
|
71
|
-
kY2c9j: "xfo81ep",
|
|
72
|
-
kzqmXN: "xh8yej3",
|
|
73
|
-
kZKoxP: "x5yr21d",
|
|
74
|
-
$$css: true
|
|
75
|
-
},
|
|
76
|
-
scrim: {
|
|
77
|
-
kGyWv1: "xnixb3f",
|
|
78
|
-
k5sjJv: "xni466t xxiuuzi",
|
|
79
|
-
kND0Po: "xc0dz0a",
|
|
80
|
-
k9an0g: "xft5bk6",
|
|
81
|
-
kb4ib: "x15h3t91",
|
|
82
|
-
kwHxkk: "x142juwg",
|
|
83
|
-
k4oj2o: "x1viac0w",
|
|
84
|
-
$$css: true
|
|
85
|
-
},
|
|
86
|
-
scrimClosing: {
|
|
87
|
-
kb4ib: "x1cz9k3x",
|
|
88
|
-
$$css: true
|
|
89
|
-
}
|
|
90
|
-
};
|
|
65
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
91
66
|
const IDLE_TRANSITION = {
|
|
92
67
|
enteringSheet: null,
|
|
93
68
|
retainedSheet: null,
|
|
@@ -125,9 +100,44 @@ function alignmentOffsetForElements(enteringElement, retainedElement) {
|
|
|
125
100
|
const enteringTop = enteringPositioner?.getBoundingClientRect().top ?? enteringElement.getBoundingClientRect().top;
|
|
126
101
|
return Math.max(0, enteringTop - retainedElement.getBoundingClientRect().top);
|
|
127
102
|
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Keeps one object identity while its own enumerable entries are unchanged, so
|
|
106
|
+
* the consumer's rest props can sit in a memoized context value without
|
|
107
|
+
* refreshing every sheet host on each switcher render.
|
|
108
|
+
*/
|
|
109
|
+
function useShallowStable(value) {
|
|
110
|
+
const stableRef = useRef(value);
|
|
111
|
+
const previous = stableRef.current;
|
|
112
|
+
const previousKeys = Object.keys(previous);
|
|
113
|
+
const nextKeys = Object.keys(value);
|
|
114
|
+
const isSame = previousKeys.length === nextKeys.length && nextKeys.every(key => Object.is(previous[key], value[key]));
|
|
115
|
+
if (!isSame) {
|
|
116
|
+
stableRef.current = value;
|
|
117
|
+
}
|
|
118
|
+
return stableRef.current;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Hands the flow's scrim to `dialog` without a fade. The backdrop's opacity
|
|
123
|
+
* transition would otherwise ease from the transparent value the entering
|
|
124
|
+
* dialog was presented with, dipping the page's dim for one motion token
|
|
125
|
+
* exactly when the previous dialog's backdrop disappears. Even a near-zero
|
|
126
|
+
* duration paints its first frame at the start value, so the swap disables
|
|
127
|
+
* the transition outright, flushes style so the new value is committed under
|
|
128
|
+
* that rule, then restores the token for later gesture and exit fades.
|
|
129
|
+
*/
|
|
130
|
+
function takeOverScrim(dialog, opacity) {
|
|
131
|
+
dialog.style.setProperty('--_sheet-scrim-duration', '0s');
|
|
132
|
+
dialog.style.setProperty('--_sheet-scrim-opacity', String(opacity));
|
|
133
|
+
if (typeof getComputedStyle === 'function') {
|
|
134
|
+
void getComputedStyle(dialog, '::backdrop').opacity;
|
|
135
|
+
}
|
|
136
|
+
dialog.style.removeProperty('--_sheet-scrim-duration');
|
|
137
|
+
}
|
|
128
138
|
/**
|
|
129
|
-
* Coordinates a set of BottomSheets so zero or one is active at a time
|
|
130
|
-
*
|
|
139
|
+
* Coordinates a set of BottomSheets so zero or one is active at a time, each
|
|
140
|
+
* in its own native dialog. During a handoff the previous panel stays visible
|
|
131
141
|
* and inert beneath the entering panel, then fades after motion completes.
|
|
132
142
|
*
|
|
133
143
|
* @example
|
|
@@ -146,27 +156,70 @@ export function BottomSheetSwitcher({
|
|
|
146
156
|
hasScrim = true,
|
|
147
157
|
children,
|
|
148
158
|
ref,
|
|
149
|
-
xstyle,
|
|
150
|
-
className,
|
|
151
|
-
style,
|
|
152
159
|
onCancel,
|
|
153
160
|
onClick,
|
|
154
161
|
onKeyDown,
|
|
155
|
-
|
|
162
|
+
className,
|
|
163
|
+
style,
|
|
164
|
+
xstyle,
|
|
165
|
+
...restDialogProps
|
|
156
166
|
}) {
|
|
157
|
-
|
|
158
|
-
const
|
|
167
|
+
// Every sheet host applies the switcher's dialog surface to its own dialog.
|
|
168
|
+
const dialogProps = useShallowStable({
|
|
169
|
+
...restDialogProps,
|
|
170
|
+
className,
|
|
171
|
+
style,
|
|
172
|
+
xstyle
|
|
173
|
+
});
|
|
174
|
+
const hostDialogRef = useRef(null);
|
|
175
|
+
const sheetDialogsRef = useRef(new Map());
|
|
176
|
+
// Sheet ids in the order their dialogs mounted (tree order on first mount).
|
|
177
|
+
// State, not a ref: the resting host below is rendered -- it carries the
|
|
178
|
+
// consumer's `id` -- so a sheet mounting or leaving must re-render.
|
|
179
|
+
const [sheetOrder, setSheetOrder] = useState([]);
|
|
180
|
+
// The sheet that hosted the flow last, kept while the flow is closed so the
|
|
181
|
+
// ref and `id` stay on the dialog the person last used. State adjusted
|
|
182
|
+
// during render (not a ref read during render): it changes exactly when
|
|
183
|
+
// the presented host does, and the next render reads it.
|
|
184
|
+
const [lastHostSheet, setLastHostSheet] = useState(null);
|
|
185
|
+
const presentationOrderRef = useRef(new Map());
|
|
186
|
+
const presentationCounterRef = useRef(0);
|
|
187
|
+
const modalFlowRef = useRef(false);
|
|
159
188
|
const triggerRef = useRef(null);
|
|
160
189
|
const sheetElementsRef = useRef(new Map());
|
|
161
190
|
const committedActiveSheetRef = useRef(activeSheet);
|
|
162
|
-
const
|
|
191
|
+
const scrimOpacityRef = useRef(1);
|
|
192
|
+
const scrimOwnerRef = useRef(null);
|
|
163
193
|
const [sheetPurposes, setSheetPurposes] = useState(() => new Map());
|
|
164
194
|
const [unmountedSheetIds, setUnmountedSheetIds] = useState(() => new Set());
|
|
165
195
|
const [transition, setTransition] = useState(IDLE_TRANSITION);
|
|
166
196
|
const activeSheetChanged = committedActiveSheetRef.current !== activeSheet;
|
|
167
197
|
const visibleTransition = activeSheetChanged ? transitionForActiveSheetChange(committedActiveSheetRef.current, activeSheet) : transition;
|
|
168
|
-
const
|
|
198
|
+
const presentedActiveSheet = activeSheet != null && !unmountedSheetIds.has(activeSheet) ? activeSheet : null;
|
|
199
|
+
const presentedRetainedSheet = visibleTransition.retainedSheet != null && !unmountedSheetIds.has(visibleTransition.retainedSheet) ? visibleTransition.retainedSheet : null;
|
|
200
|
+
const isFlowVisible = presentedActiveSheet != null || presentedRetainedSheet != null;
|
|
169
201
|
const isModal = hasScrim && isFlowVisible;
|
|
202
|
+
// The dialog that hosts the flow for its ref, its single-instance
|
|
203
|
+
// attributes, and its dismissal registration: the active sheet's, the
|
|
204
|
+
// retained sheet's while the flow closes through its exit, and while the
|
|
205
|
+
// flow is closed the dialog that hosted it last (or the first mounted
|
|
206
|
+
// sheet's before any open), so the ref resolves to a closed dialog element
|
|
207
|
+
// rather than to null, as the shared dialog did. Which sheet mounts first
|
|
208
|
+
// is known only once its dialog registers during the first commit: the
|
|
209
|
+
// ref is attached to it in that same commit (below), and the rendered
|
|
210
|
+
// `id` follows in the synchronous re-render that commit schedules, before
|
|
211
|
+
// the first paint. Server markup therefore carries the `id` on no element.
|
|
212
|
+
const presentedHostSheet = presentedActiveSheet ?? presentedRetainedSheet;
|
|
213
|
+
if (presentedHostSheet != null && presentedHostSheet !== lastHostSheet) {
|
|
214
|
+
setLastHostSheet(presentedHostSheet);
|
|
215
|
+
}
|
|
216
|
+
const restingHostSheet = lastHostSheet != null && sheetOrder.includes(lastHostSheet) ? lastHostSheet : sheetOrder[0] ?? null;
|
|
217
|
+
const hostSheet = presentedHostSheet ?? restingHostSheet;
|
|
218
|
+
// The dialog whose backdrop paints the flow's one scrim. A retained sheet
|
|
219
|
+
// keeps it through a handoff so the entering dialog, presented above it in
|
|
220
|
+
// the top layer, does not dim the previous panel beneath its own backdrop.
|
|
221
|
+
const scrimOwnerSheet = presentedRetainedSheet ?? presentedActiveSheet;
|
|
222
|
+
const isFlowClosing = isFlowVisible && activeSheet == null;
|
|
170
223
|
const activeSheetPurpose = (activeSheet == null ? null : sheetPurposes.get(activeSheet)) ?? 'info';
|
|
171
224
|
const allowsEscapeDismiss = activeSheetPurpose !== 'required';
|
|
172
225
|
const allowsLightDismiss = activeSheetPurpose === 'info';
|
|
@@ -189,61 +242,96 @@ export function BottomSheetSwitcher({
|
|
|
189
242
|
onActiveSheetChange(null);
|
|
190
243
|
}
|
|
191
244
|
}, [allowsLightDismiss, onActiveSheetChange]);
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
});
|
|
197
|
-
// Before the shared dismissal stack, this modal trap supplied `onEscape`, so
|
|
198
|
-
// the released compatibility shim reported it as active. Keep that signal
|
|
199
|
-
// without registering the switcher twice in the one shared stack.
|
|
245
|
+
// Focus containment is the native modal dialog's: showModal() makes the
|
|
246
|
+
// page inert, so Tab cannot leave the active sheet. The released read-only
|
|
247
|
+
// `hasActiveFocusTrapEscape()` signal still reports a modal flow as a trap,
|
|
248
|
+
// as it did when a JavaScript trap backed it.
|
|
200
249
|
useFocusTrapEscapeCompatibilitySignal(isModal);
|
|
250
|
+
// One lock for the whole modal flow, as on a shared dialog: `isModal` stays
|
|
251
|
+
// true through a handoff (two dialogs open) and through the exit motion, so
|
|
252
|
+
// the shared counter is taken once and given back once.
|
|
253
|
+
useScrollLock(isModal);
|
|
201
254
|
const {
|
|
202
255
|
shouldDismissOnCloseRequest
|
|
203
256
|
} = useLayerDismissal({
|
|
204
257
|
isActive: isFlowVisible,
|
|
205
258
|
escapeBehavior: allowsEscapeDismiss ? 'close' : 'block',
|
|
206
259
|
onDismiss: dismissOnEscape,
|
|
207
|
-
getContainer: () =>
|
|
208
|
-
isPresent: () =>
|
|
260
|
+
getContainer: () => hostDialogRef.current,
|
|
261
|
+
isPresent: () => hostDialogRef.current?.open ?? false
|
|
209
262
|
});
|
|
210
|
-
useScrollLock(isModal);
|
|
211
263
|
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
//
|
|
215
|
-
//
|
|
264
|
+
// Point the consumer ref and the dismissal registration at the host dialog.
|
|
265
|
+
// Sheet hosts register their dialogs during commit, so by the time this
|
|
266
|
+
// layout effect runs the map already names the dialog for `hostSheet` --
|
|
267
|
+
// and, in the first commit of a flow that mounts closed, the first
|
|
268
|
+
// registered dialog before `sheetOrder` has caught up, so a parent's own
|
|
269
|
+
// mount effects already find the ref resolved. The ref is attached the way
|
|
270
|
+
// React attaches one: a callback ref's returned cleanup runs on detach, and
|
|
271
|
+
// only a ref without one receives null. Attachment follows the resolved
|
|
272
|
+
// element, not the render that resolved it: the re-render that catches
|
|
273
|
+
// `sheetOrder` up resolves the same dialog and leaves the ref alone.
|
|
274
|
+
const attachedRef = useRef(null);
|
|
216
275
|
useLayoutEffect(() => {
|
|
217
|
-
const
|
|
218
|
-
|
|
276
|
+
const host = hostSheet == null ? sheetDialogsRef.current.values().next().value ?? null : sheetDialogsRef.current.get(hostSheet) ?? null;
|
|
277
|
+
hostDialogRef.current = host;
|
|
278
|
+
const attached = attachedRef.current;
|
|
279
|
+
if (attached?.host === host && attached.ref === ref) {
|
|
219
280
|
return;
|
|
220
281
|
}
|
|
282
|
+
attached?.detach?.();
|
|
283
|
+
if (host == null) {
|
|
284
|
+
attachedRef.current = null;
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const detach = mergeRefs(ref)(host);
|
|
288
|
+
attachedRef.current = {
|
|
289
|
+
ref,
|
|
290
|
+
host,
|
|
291
|
+
detach: typeof detach === 'function' ? detach : undefined
|
|
292
|
+
};
|
|
293
|
+
}, [hostSheet, ref, sheetOrder]);
|
|
294
|
+
useLayoutEffect(() => () => {
|
|
295
|
+
hostDialogRef.current = null;
|
|
296
|
+
attachedRef.current?.detach?.();
|
|
297
|
+
attachedRef.current = null;
|
|
298
|
+
}, []);
|
|
299
|
+
|
|
300
|
+
// Focus return is native per dialog: each showModal() records the focused
|
|
301
|
+
// element and close() focuses it again. That serves a one-sheet flow, but
|
|
302
|
+
// the second sheet of a flow records a control inside the first, which is
|
|
303
|
+
// hidden by the time the flow ends, so the browser's return lands nowhere.
|
|
304
|
+
// The flow therefore remembers its own opener -- the page element focused
|
|
305
|
+
// before the first modal present -- and focuses it after the last dialog
|
|
306
|
+
// closes. Sheet hosts ask before presenting modally, so the capture sees
|
|
307
|
+
// the page element; hosts present in their own layout effects, which run
|
|
308
|
+
// before the one below, so the restore follows the last dialog's close.
|
|
309
|
+
const onBeforeSheetPresent = useCallback(sheetId => {
|
|
310
|
+
if (triggerRef.current == null) {
|
|
311
|
+
triggerRef.current = document.activeElement;
|
|
312
|
+
}
|
|
313
|
+
modalFlowRef.current = true;
|
|
314
|
+
presentationCounterRef.current += 1;
|
|
315
|
+
presentationOrderRef.current.set(sheetId, presentationCounterRef.current);
|
|
316
|
+
}, []);
|
|
317
|
+
useLayoutEffect(() => {
|
|
221
318
|
if (isFlowVisible) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
dialog.close();
|
|
225
|
-
}
|
|
226
|
-
if (!dialog.open) {
|
|
227
|
-
if (hasScrim && triggerRef.current == null) {
|
|
228
|
-
triggerRef.current = document.activeElement;
|
|
229
|
-
}
|
|
230
|
-
if (hasScrim) {
|
|
231
|
-
dialog.showModal();
|
|
232
|
-
} else {
|
|
233
|
-
dialog.show();
|
|
234
|
-
}
|
|
319
|
+
if (!hasScrim) {
|
|
320
|
+
modalFlowRef.current = false;
|
|
235
321
|
}
|
|
236
|
-
dialogModeRef.current = nextMode;
|
|
237
322
|
return;
|
|
238
323
|
}
|
|
239
|
-
if (
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
triggerRef.current?.focus(
|
|
324
|
+
if (modalFlowRef.current) {
|
|
325
|
+
// Like the browser's own return on close(), without scrolling: the
|
|
326
|
+
// page kept its scroll offset under the lock, and an opener scrolled
|
|
327
|
+
// out of view must not drag the page back to itself.
|
|
328
|
+
triggerRef.current?.focus({
|
|
329
|
+
preventScroll: true
|
|
330
|
+
});
|
|
244
331
|
}
|
|
245
332
|
triggerRef.current = null;
|
|
246
|
-
|
|
333
|
+
modalFlowRef.current = false;
|
|
334
|
+
presentationOrderRef.current.clear();
|
|
247
335
|
}, [hasScrim, isFlowVisible]);
|
|
248
336
|
const getSheetPhase = useCallback(sheetId => {
|
|
249
337
|
if (sheetId === activeSheet) {
|
|
@@ -255,6 +343,7 @@ export function BottomSheetSwitcher({
|
|
|
255
343
|
return 'hidden';
|
|
256
344
|
}, [activeSheet, visibleTransition]);
|
|
257
345
|
const getSheetAlignmentOffset = useCallback(sheetId => visibleTransition.retainedSheet === sheetId ? visibleTransition.alignmentOffset : 0, [visibleTransition]);
|
|
346
|
+
const isScrimOwner = useCallback(sheetId => sheetId === scrimOwnerSheet, [scrimOwnerSheet]);
|
|
258
347
|
const registerSheetElement = useCallback((sheetId, element) => {
|
|
259
348
|
if (element == null) {
|
|
260
349
|
sheetElementsRef.current.delete(sheetId);
|
|
@@ -279,23 +368,28 @@ export function BottomSheetSwitcher({
|
|
|
279
368
|
});
|
|
280
369
|
}
|
|
281
370
|
}, []);
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
371
|
+
const registerSheetDialog = useCallback((sheetId, dialog) => {
|
|
372
|
+
if (dialog == null) {
|
|
373
|
+
sheetDialogsRef.current.delete(sheetId);
|
|
374
|
+
presentationOrderRef.current.delete(sheetId);
|
|
375
|
+
setSheetOrder(current => current.includes(sheetId) ? current.filter(id => id !== sheetId) : current);
|
|
376
|
+
} else {
|
|
377
|
+
sheetDialogsRef.current.set(sheetId, dialog);
|
|
378
|
+
setSheetOrder(current => current.includes(sheetId) ? current : [...current, sheetId]);
|
|
379
|
+
}
|
|
380
|
+
}, []);
|
|
381
|
+
const isCoveredInTopLayer = useCallback(sheetId => {
|
|
382
|
+
const order = presentationOrderRef.current;
|
|
383
|
+
const own = order.get(sheetId);
|
|
384
|
+
if (own == null) {
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
for (const [otherId, stamp] of order) {
|
|
388
|
+
if (otherId !== sheetId && stamp > own && sheetDialogsRef.current.get(otherId)?.open) {
|
|
389
|
+
return true;
|
|
294
390
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
return next;
|
|
298
|
-
});
|
|
391
|
+
}
|
|
392
|
+
return false;
|
|
299
393
|
}, []);
|
|
300
394
|
const registerSheetPurpose = useCallback((sheetId, purpose) => {
|
|
301
395
|
setSheetPurposes(current => {
|
|
@@ -375,39 +469,54 @@ export function BottomSheetSwitcher({
|
|
|
375
469
|
return current;
|
|
376
470
|
});
|
|
377
471
|
}, []);
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
472
|
+
|
|
473
|
+
// One scrim for the flow. Only the owning dialog's backdrop carries the
|
|
474
|
+
// current opacity; every other presented dialog keeps its backdrop clear.
|
|
475
|
+
// When ownership moves — the retained dialog has faded and closes, or a
|
|
476
|
+
// rapid replacement hides it — the new owner takes the value without a
|
|
477
|
+
// fade, in the same layout pass that closes the old one.
|
|
478
|
+
const applyScrimOpacity = useCallback(() => {
|
|
479
|
+
const owner = scrimOwnerSheet == null ? null : sheetDialogsRef.current.get(scrimOwnerSheet) ?? null;
|
|
480
|
+
// A fresh open keeps the backdrop's @starting-style fade; only a hand
|
|
481
|
+
// from one presented dialog to another swaps without one.
|
|
482
|
+
const ownerChanged = scrimOwnerRef.current != null && scrimOwnerRef.current !== scrimOwnerSheet;
|
|
483
|
+
scrimOwnerRef.current = scrimOwnerSheet;
|
|
484
|
+
for (const [sheetId, dialog] of sheetDialogsRef.current) {
|
|
485
|
+
if (dialog === owner) {
|
|
486
|
+
if (ownerChanged && dialog.open) {
|
|
487
|
+
takeOverScrim(dialog, scrimOpacityRef.current);
|
|
488
|
+
} else {
|
|
489
|
+
dialog.style.setProperty('--_sheet-scrim-opacity', String(scrimOpacityRef.current));
|
|
490
|
+
}
|
|
491
|
+
} else if (sheetId !== scrimOwnerSheet) {
|
|
492
|
+
dialog.style.setProperty('--_sheet-scrim-opacity', '0');
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}, [scrimOwnerSheet]);
|
|
381
496
|
const onSheetScrimOpacityChange = useCallback((sheetId, opacity) => {
|
|
382
497
|
// A pointer captured by the outgoing sheet can keep delivering gesture
|
|
383
498
|
// events after a handoff. Only the currently committed sheet owns the
|
|
384
|
-
//
|
|
499
|
+
// flow's scrim value, so stale gesture updates must not reach it.
|
|
385
500
|
if (sheetId !== committedActiveSheetRef.current) {
|
|
386
501
|
return;
|
|
387
502
|
}
|
|
388
|
-
|
|
389
|
-
|
|
503
|
+
scrimOpacityRef.current = opacity;
|
|
504
|
+
applyScrimOpacity();
|
|
505
|
+
}, [applyScrimOpacity]);
|
|
506
|
+
|
|
507
|
+
// A committed selection resets the flow's scrim value -- 1 while a sheet
|
|
508
|
+
// is active, 0 for the exit fade -- and writes it to the owning backdrop in
|
|
509
|
+
// the same effect; a gesture then adjusts the value through
|
|
510
|
+
// `onSheetScrimOpacityChange` until the next selection.
|
|
390
511
|
useLayoutEffect(() => {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
activeSheet,
|
|
395
|
-
hasScrim,
|
|
396
|
-
onActiveSheetChange,
|
|
397
|
-
getSheetPhase,
|
|
398
|
-
getSheetAlignmentOffset,
|
|
399
|
-
registerSheetElement,
|
|
400
|
-
registerSheetLabel,
|
|
401
|
-
registerSheetPurpose,
|
|
402
|
-
onSheetEnterStart,
|
|
403
|
-
onSheetTransitionComplete,
|
|
404
|
-
onSheetScrimOpacityChange
|
|
405
|
-
}), [activeSheet, getSheetAlignmentOffset, getSheetPhase, hasScrim, onActiveSheetChange, onSheetEnterStart, onSheetScrimOpacityChange, onSheetTransitionComplete, registerSheetElement, registerSheetLabel, registerSheetPurpose]);
|
|
406
|
-
const activeLabel = (activeSheet == null ? null : sheetLabels.get(activeSheet)) ?? (visibleTransition.retainedSheet == null ? undefined : sheetLabels.get(visibleTransition.retainedSheet));
|
|
512
|
+
scrimOpacityRef.current = activeSheet == null ? 0 : 1;
|
|
513
|
+
applyScrimOpacity();
|
|
514
|
+
}, [applyScrimOpacity, activeSheet, hasScrim, isFlowVisible]);
|
|
407
515
|
|
|
408
|
-
// A `cancel` that bubbles up from a step is not a close request for
|
|
409
|
-
// flow: a file input fires one when its picker is dismissed, and
|
|
410
|
-
//
|
|
516
|
+
// A `cancel` that bubbles up from inside a step is not a close request for
|
|
517
|
+
// the flow: a file input fires one when its picker is dismissed, and it
|
|
518
|
+
// reaches the step's dialog. Only a `cancel` fired at a sheet dialog itself
|
|
519
|
+
// dismisses; the bubbled one is left alone.
|
|
411
520
|
const handleCancel = useCallback(event => {
|
|
412
521
|
if (event.target !== event.currentTarget) {
|
|
413
522
|
return;
|
|
@@ -425,30 +534,50 @@ export function BottomSheetSwitcher({
|
|
|
425
534
|
dispatchLayerEscapeKeyDown(event.nativeEvent);
|
|
426
535
|
}, []);
|
|
427
536
|
const handleClick = useCallback(event => {
|
|
428
|
-
|
|
537
|
+
// A `::backdrop` click targets its dialog element. Only the active
|
|
538
|
+
// sheet's backdrop is the flow's scrim; a retained dialog is inert and
|
|
539
|
+
// a hidden one closed, so neither can be clicked, but be explicit.
|
|
540
|
+
if (hasScrim && event.target === event.currentTarget && event.currentTarget === hostDialogRef.current) {
|
|
429
541
|
dismissOnLightInteraction();
|
|
430
542
|
}
|
|
431
543
|
}, [dismissOnLightInteraction, hasScrim]);
|
|
432
|
-
const
|
|
433
|
-
const
|
|
434
|
-
const
|
|
544
|
+
const onDialogCancel = useMemo(() => composeEventHandlers(onCancel, handleCancel), [handleCancel, onCancel]);
|
|
545
|
+
const onDialogClick = useMemo(() => composeEventHandlers(onClick, handleClick), [handleClick, onClick]);
|
|
546
|
+
const onDialogKeyDown = useMemo(() => composeEventHandlers(onKeyDown, handleKeyDown), [handleKeyDown, onKeyDown]);
|
|
547
|
+
const contextValue = useMemo(() => ({
|
|
548
|
+
activeSheet,
|
|
549
|
+
hasScrim,
|
|
550
|
+
onActiveSheetChange,
|
|
551
|
+
getSheetPhase,
|
|
552
|
+
getSheetAlignmentOffset,
|
|
553
|
+
hostSheet,
|
|
554
|
+
isScrimOwner,
|
|
555
|
+
isFlowClosing,
|
|
556
|
+
registerSheetElement,
|
|
557
|
+
registerSheetDialog,
|
|
558
|
+
registerSheetPurpose,
|
|
559
|
+
onBeforeSheetPresent,
|
|
560
|
+
isCoveredInTopLayer,
|
|
561
|
+
onSheetEnterStart,
|
|
562
|
+
onSheetTransitionComplete,
|
|
563
|
+
onSheetScrimOpacityChange,
|
|
564
|
+
dialogProps,
|
|
565
|
+
onDialogCancel,
|
|
566
|
+
onDialogClick,
|
|
567
|
+
onDialogKeyDown
|
|
568
|
+
}), [activeSheet, dialogProps, getSheetAlignmentOffset, getSheetPhase, hasScrim, hostSheet, isCoveredInTopLayer, isFlowClosing, isScrimOwner, onActiveSheetChange, onBeforeSheetPresent, onDialogCancel, onDialogClick, onDialogKeyDown, onSheetEnterStart, onSheetScrimOpacityChange, onSheetTransitionComplete, registerSheetDialog, registerSheetElement, registerSheetPurpose]);
|
|
435
569
|
return /*#__PURE__*/_jsx(BottomSheetSwitcherContext, {
|
|
436
570
|
value: contextValue,
|
|
437
|
-
children: /*#__PURE__*/
|
|
438
|
-
...
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
role: 'alertdialog'
|
|
448
|
-
} : undefined),
|
|
449
|
-
children: [/*#__PURE__*/_jsx(LayerDepthProvider, {
|
|
450
|
-
children: children
|
|
451
|
-
}), /*#__PURE__*/_jsx(BottomSheetEdgeTint, {})]
|
|
571
|
+
children: /*#__PURE__*/_jsx("div", {
|
|
572
|
+
...{
|
|
573
|
+
0: {
|
|
574
|
+
className: "xjp7ctv"
|
|
575
|
+
},
|
|
576
|
+
1: {
|
|
577
|
+
className: "x1lliihq xixxii4 x10a8y8t xh8yej3 x5yr21d x47corl xc8icb0 xfo81ep"
|
|
578
|
+
}
|
|
579
|
+
}[!!(!hasScrim && isFlowVisible) << 0],
|
|
580
|
+
children: children
|
|
452
581
|
})
|
|
453
582
|
});
|
|
454
583
|
}
|
|
@@ -1,21 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file BottomSheetSwitcherContext.ts
|
|
3
|
+
* @input Uses React context
|
|
4
|
+
* @output Internal phase, lifecycle, and host-dialog context shared by BottomSheetSwitcher and BottomSheet
|
|
5
|
+
* @position Private coordination layer for mutually exclusive BottomSheets
|
|
6
|
+
*
|
|
7
|
+
* Every child sheet renders its own native `<dialog>`; the switcher's only
|
|
8
|
+
* element is a flow wrapper. This context carries the phase machine, the
|
|
9
|
+
* host-dialog selection, and the switcher's dialog-level props and handlers
|
|
10
|
+
* down to those sheet hosts.
|
|
11
|
+
*/
|
|
12
|
+
import type { KeyboardEvent as ReactKeyboardEvent, MouseEvent as ReactMouseEvent, SyntheticEvent } from 'react';
|
|
13
|
+
import type { BaseProps } from '../BaseProps';
|
|
1
14
|
import type { DialogPurpose } from '../Dialog';
|
|
2
15
|
export type BottomSheetSwitcherPhase = 'entering' | 'active' | 'covered' | 'aligning' | 'fading' | 'exiting' | 'hidden';
|
|
3
16
|
export interface BottomSheetSwitcherTransitionEvent {
|
|
4
17
|
sheetId: string;
|
|
5
18
|
phase: 'entering' | 'aligning' | 'fading' | 'exiting';
|
|
6
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* The switcher's own dialog surface, applied by every sheet host. `ref` is not
|
|
22
|
+
* part of it: the switcher resolves its ref to the host sheet's dialog, and
|
|
23
|
+
* the single-instance attributes (`id`, `data-testid`) render there only.
|
|
24
|
+
*/
|
|
25
|
+
export type BottomSheetSwitcherDialogProps = Omit<BaseProps<HTMLDialogElement>, 'onClick' | 'onKeyDown'>;
|
|
7
26
|
export interface BottomSheetSwitcherContextValue {
|
|
8
27
|
activeSheet: string | null;
|
|
9
28
|
hasScrim: boolean;
|
|
10
29
|
onActiveSheetChange: (sheetId: string | null) => void;
|
|
11
30
|
getSheetPhase: (sheetId: string) => BottomSheetSwitcherPhase;
|
|
12
31
|
getSheetAlignmentOffset: (sheetId: string) => number;
|
|
32
|
+
/**
|
|
33
|
+
* The sheet whose dialog hosts the flow: the active sheet, the exiting
|
|
34
|
+
* sheet through its exit, and the last host (or the first mounted sheet)
|
|
35
|
+
* while the flow is closed. The switcher's ref and its single-instance
|
|
36
|
+
* attributes resolve to this sheet's dialog.
|
|
37
|
+
*/
|
|
38
|
+
hostSheet: string | null;
|
|
39
|
+
/**
|
|
40
|
+
* Whether this sheet's dialog paints the flow's one scrim right now. During
|
|
41
|
+
* a handoff the retained sheet keeps it, so the entering dialog's backdrop
|
|
42
|
+
* stays transparent above the still-visible previous panel.
|
|
43
|
+
*/
|
|
44
|
+
isScrimOwner: (sheetId: string) => boolean;
|
|
45
|
+
/** The flow is closing: the owning backdrop fades out on the exit curve. */
|
|
46
|
+
isFlowClosing: boolean;
|
|
13
47
|
registerSheetElement: (sheetId: string, element: HTMLElement | null) => void;
|
|
14
|
-
|
|
48
|
+
registerSheetDialog: (sheetId: string, dialog: HTMLDialogElement | null) => void;
|
|
15
49
|
registerSheetPurpose: (sheetId: string, purpose: DialogPurpose | null) => void;
|
|
50
|
+
/**
|
|
51
|
+
* Called by a sheet host just before it presents its dialog modally, so the
|
|
52
|
+
* switcher can remember the page element that opened the flow.
|
|
53
|
+
*/
|
|
54
|
+
onBeforeSheetPresent: (sheetId: string) => void;
|
|
55
|
+
/**
|
|
56
|
+
* Whether a modal sheet dialog that is already open sits beneath another
|
|
57
|
+
* open sheet dialog in the top layer, so it must re-present to become the
|
|
58
|
+
* topmost layer again.
|
|
59
|
+
*/
|
|
60
|
+
isCoveredInTopLayer: (sheetId: string) => boolean;
|
|
16
61
|
onSheetEnterStart: (sheetId: string) => void;
|
|
17
62
|
onSheetTransitionComplete: (event: BottomSheetSwitcherTransitionEvent) => void;
|
|
18
63
|
onSheetScrimOpacityChange: (sheetId: string, opacity: number) => void;
|
|
64
|
+
/** Consumer dialog props the switcher forwards to every sheet dialog. */
|
|
65
|
+
dialogProps: BottomSheetSwitcherDialogProps;
|
|
66
|
+
onDialogCancel: (event: SyntheticEvent<HTMLDialogElement>) => void;
|
|
67
|
+
onDialogClick: (event: ReactMouseEvent<HTMLDialogElement>) => void;
|
|
68
|
+
onDialogKeyDown: (event: ReactKeyboardEvent<HTMLDialogElement>) => void;
|
|
19
69
|
}
|
|
20
70
|
export declare const BottomSheetSwitcherContext: import("react").Context<BottomSheetSwitcherContextValue | null>;
|
|
21
71
|
//# sourceMappingURL=BottomSheetSwitcherContext.d.ts.map
|