@surdeddd/bottom-sheet 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +377 -0
- package/dist/BottomSheetEngine-CvSVbo6c.d.cts +704 -0
- package/dist/BottomSheetEngine-DbO8rW_3.d.ts +704 -0
- package/dist/element.cjs +3442 -0
- package/dist/element.d.cts +88 -0
- package/dist/element.d.ts +88 -0
- package/dist/element.iife.global.js +3 -0
- package/dist/element.js +3442 -0
- package/dist/index.cjs +3693 -0
- package/dist/index.d.cts +184 -0
- package/dist/index.d.ts +184 -0
- package/dist/index.js +3669 -0
- package/dist/integrations/formik.cjs +27 -0
- package/dist/integrations/formik.d.cts +27 -0
- package/dist/integrations/formik.d.ts +27 -0
- package/dist/integrations/formik.js +25 -0
- package/dist/integrations/react-hook-form.cjs +28 -0
- package/dist/integrations/react-hook-form.d.cts +30 -0
- package/dist/integrations/react-hook-form.d.ts +30 -0
- package/dist/integrations/react-hook-form.js +26 -0
- package/dist/overlay.cjs +1058 -0
- package/dist/overlay.d.cts +282 -0
- package/dist/overlay.d.ts +282 -0
- package/dist/overlay.js +1053 -0
- package/dist/preact.cjs +2 -0
- package/dist/preact.d.cts +5 -0
- package/dist/preact.d.ts +5 -0
- package/dist/preact.js +2 -0
- package/dist/qwik.cjs +3046 -0
- package/dist/qwik.d.cts +55 -0
- package/dist/qwik.d.ts +55 -0
- package/dist/qwik.js +3044 -0
- package/dist/react.cjs +4162 -0
- package/dist/react.d.cts +301 -0
- package/dist/react.d.ts +301 -0
- package/dist/react.js +4156 -0
- package/dist/solid.cjs +3063 -0
- package/dist/solid.d.cts +66 -0
- package/dist/solid.d.ts +66 -0
- package/dist/solid.js +3061 -0
- package/dist/styles.css +508 -0
- package/dist/svelte.cjs +3200 -0
- package/dist/svelte.d.ts +89 -0
- package/dist/svelte.js +3177 -0
- package/dist/themes/ios.css +24 -0
- package/dist/themes/material.css +24 -0
- package/dist/themes/vercel.css +24 -0
- package/dist/transform-Brkf-wzo.d.cts +4 -0
- package/dist/transform-Brkf-wzo.d.ts +4 -0
- package/dist/vue.cjs +3361 -0
- package/dist/vue.d.ts +68 -0
- package/dist/vue.js +3358 -0
- package/package.json +288 -0
package/dist/react.d.cts
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { b as EngineOptions, E as EngineState, B as BottomSheetEngine, S as SnapPointDef, a as SheetMode } from './BottomSheetEngine-CvSVbo6c.cjs';
|
|
2
|
+
export { c as SnapPoint } from './BottomSheetEngine-CvSVbo6c.cjs';
|
|
3
|
+
import { OverlayOptions, OverlayState, Overlay as OverlayEngine } from './overlay.cjs';
|
|
4
|
+
export { OverlayEdge } from './overlay.cjs';
|
|
5
|
+
import * as react from 'react';
|
|
6
|
+
import { CSSProperties, ReactNode } from 'react';
|
|
7
|
+
import './transform-Brkf-wzo.cjs';
|
|
8
|
+
|
|
9
|
+
type EngineOptionsForProps = Omit<EngineOptions, "element" | "handle" | "scrollContainer" | "backdrop" | "screenComponent">;
|
|
10
|
+
/**
|
|
11
|
+
* Header content for the sheet. Two forms are supported:
|
|
12
|
+
* - **Static node**: `header={<h2>Title</h2>}` — rendered once and never
|
|
13
|
+
* updated when the active snap changes.
|
|
14
|
+
* - **Render function**: `header={state => <h2>{state.activeId}</h2>}` —
|
|
15
|
+
* called on every settled snap change with the current `EngineState`,
|
|
16
|
+
* so the header can morph per snap (e.g. minimized header vs full
|
|
17
|
+
* header). The function fires from the same `useSyncExternalStore`
|
|
18
|
+
* subscription that drives the rest of the component, so identity is
|
|
19
|
+
* stable between snaps and only re-renders on transitions.
|
|
20
|
+
*/
|
|
21
|
+
type HeaderProp = ReactNode | ((state: EngineState) => ReactNode);
|
|
22
|
+
type BottomSheetProps = EngineOptionsForProps & {
|
|
23
|
+
/** Render the dimmed overlay behind the sheet. Default: true. */
|
|
24
|
+
backdrop?: boolean;
|
|
25
|
+
/** Close when the backdrop is clicked. Default: true. */
|
|
26
|
+
closeOnBackdrop?: boolean;
|
|
27
|
+
/** Optional className appended to the root sheet element. */
|
|
28
|
+
className?: string;
|
|
29
|
+
style?: CSSProperties;
|
|
30
|
+
/**
|
|
31
|
+
* Header content (above the scrollable content; doubles as drag handle
|
|
32
|
+
* area). Accepts either a static `ReactNode` or a function
|
|
33
|
+
* `(state: EngineState) => ReactNode` that re-renders on every snap
|
|
34
|
+
* transition — letting consumers show different markup per snap state
|
|
35
|
+
* (e.g. minimized vs half vs full).
|
|
36
|
+
*/
|
|
37
|
+
header?: HeaderProp;
|
|
38
|
+
/** Children become the scrollable content area. */
|
|
39
|
+
children?: ReactNode;
|
|
40
|
+
/** Slot above the sheet, anchored to the left. */
|
|
41
|
+
leftButton?: ReactNode;
|
|
42
|
+
/** Slot above the sheet, anchored to the right. */
|
|
43
|
+
rightButton?: ReactNode;
|
|
44
|
+
/** Element rendered behind the sheet, fading in with progress. */
|
|
45
|
+
screen?: ReactNode;
|
|
46
|
+
/** Fired whenever active snap changes. */
|
|
47
|
+
onChange?: (state: EngineState) => void;
|
|
48
|
+
/** Visually hidden label for screen readers. */
|
|
49
|
+
ariaLabel?: string;
|
|
50
|
+
/** ID of an existing heading element inside the sheet (preferred over ariaLabel). */
|
|
51
|
+
ariaLabelledBy?: string;
|
|
52
|
+
/** Skip rendering on the server to avoid hydration mismatches. Default: false. */
|
|
53
|
+
noSSR?: boolean;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Imperative handle returned by `<BottomSheet ref={…}>`.
|
|
57
|
+
*
|
|
58
|
+
* Opt-in literal-id typing — pass a string-literal union as `TId` to get
|
|
59
|
+
* compile-time errors on typos:
|
|
60
|
+
*
|
|
61
|
+
* ```ts
|
|
62
|
+
* // Default (back-compat): TId = string, anything goes
|
|
63
|
+
* const ref = useRef<BottomSheetHandle>(null);
|
|
64
|
+
* ref.current?.snapTo("anything"); // ✓ compiles, fails silently at runtime
|
|
65
|
+
*
|
|
66
|
+
* // Opt-in: typo-safe
|
|
67
|
+
* const ref = useRef<BottomSheetHandle<"min" | "half" | "full">>(null);
|
|
68
|
+
* ref.current?.snapTo("haf"); // ❌ TS2345
|
|
69
|
+
* ref.current?.snapTo("half"); // ✓
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* `TId` defaults to `string` so existing call sites compile unchanged.
|
|
73
|
+
* The underlying engine stays `string`-typed; the literal narrowing is a
|
|
74
|
+
* TS-only convenience layered on top of the runtime.
|
|
75
|
+
*/
|
|
76
|
+
type BottomSheetHandle<TId extends string = string> = {
|
|
77
|
+
snapTo: (id: TId) => Promise<void>;
|
|
78
|
+
open: (id?: TId) => Promise<void>;
|
|
79
|
+
close: () => Promise<void>;
|
|
80
|
+
setAllowed: (ids: TId[], snap?: TId) => void;
|
|
81
|
+
state: EngineState & {
|
|
82
|
+
activeId: TId;
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* React component built on the headless engine. For full control, use
|
|
87
|
+
* `useBottomSheet` directly and assemble your own JSX.
|
|
88
|
+
*/
|
|
89
|
+
declare const BottomSheet: react.ForwardRefExoticComponent<EngineOptionsForProps & {
|
|
90
|
+
/** Render the dimmed overlay behind the sheet. Default: true. */
|
|
91
|
+
backdrop?: boolean;
|
|
92
|
+
/** Close when the backdrop is clicked. Default: true. */
|
|
93
|
+
closeOnBackdrop?: boolean;
|
|
94
|
+
/** Optional className appended to the root sheet element. */
|
|
95
|
+
className?: string;
|
|
96
|
+
style?: CSSProperties;
|
|
97
|
+
/**
|
|
98
|
+
* Header content (above the scrollable content; doubles as drag handle
|
|
99
|
+
* area). Accepts either a static `ReactNode` or a function
|
|
100
|
+
* `(state: EngineState) => ReactNode` that re-renders on every snap
|
|
101
|
+
* transition — letting consumers show different markup per snap state
|
|
102
|
+
* (e.g. minimized vs half vs full).
|
|
103
|
+
*/
|
|
104
|
+
header?: HeaderProp;
|
|
105
|
+
/** Children become the scrollable content area. */
|
|
106
|
+
children?: ReactNode;
|
|
107
|
+
/** Slot above the sheet, anchored to the left. */
|
|
108
|
+
leftButton?: ReactNode;
|
|
109
|
+
/** Slot above the sheet, anchored to the right. */
|
|
110
|
+
rightButton?: ReactNode;
|
|
111
|
+
/** Element rendered behind the sheet, fading in with progress. */
|
|
112
|
+
screen?: ReactNode;
|
|
113
|
+
/** Fired whenever active snap changes. */
|
|
114
|
+
onChange?: (state: EngineState) => void;
|
|
115
|
+
/** Visually hidden label for screen readers. */
|
|
116
|
+
ariaLabel?: string;
|
|
117
|
+
/** ID of an existing heading element inside the sheet (preferred over ariaLabel). */
|
|
118
|
+
ariaLabelledBy?: string;
|
|
119
|
+
/** Skip rendering on the server to avoid hydration mismatches. Default: false. */
|
|
120
|
+
noSSR?: boolean;
|
|
121
|
+
} & react.RefAttributes<BottomSheetHandle<string>>>;
|
|
122
|
+
|
|
123
|
+
type UseBottomSheetRefs = {
|
|
124
|
+
sheetRef: React.RefObject<HTMLElement>;
|
|
125
|
+
handleRef: React.RefObject<HTMLElement>;
|
|
126
|
+
contentRef: React.RefObject<HTMLElement>;
|
|
127
|
+
backdropRef: React.RefObject<HTMLElement>;
|
|
128
|
+
screenRef: React.RefObject<HTMLElement>;
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Return shape of `useBottomSheet`. Optionally narrows to a literal-id union
|
|
132
|
+
* `TId` when the consumer explicitly types the call site:
|
|
133
|
+
*
|
|
134
|
+
* ```ts
|
|
135
|
+
* const sheet = useBottomSheet<"min" | "full">({ snapPoints: [...] });
|
|
136
|
+
* sheet.snapTo("min"); // ✓
|
|
137
|
+
* ```
|
|
138
|
+
*
|
|
139
|
+
* Without an explicit type argument `TId` defaults to `string`.
|
|
140
|
+
*/
|
|
141
|
+
type UseBottomSheetReturn<TId extends string = string> = UseBottomSheetRefs & {
|
|
142
|
+
state: EngineState & {
|
|
143
|
+
activeId: TId;
|
|
144
|
+
};
|
|
145
|
+
snapTo: (id: TId) => Promise<void>;
|
|
146
|
+
open: (id?: TId) => Promise<void>;
|
|
147
|
+
close: () => Promise<void>;
|
|
148
|
+
setAllowed: (ids: TId[], snap?: TId) => void;
|
|
149
|
+
/**
|
|
150
|
+
* @deprecated React Strict Mode double-invokes the layout effect — the
|
|
151
|
+
* effect tears down (engineRef.current = null), the next render reads
|
|
152
|
+
* this field as `null` for one frame, and only the second mount restores
|
|
153
|
+
* a live engine. Consumers calling methods through this field during that
|
|
154
|
+
* window get `null`. Use `getEngine()` instead — it lazy-reads the live
|
|
155
|
+
* ref and is safe across Strict Mode and across resize/setSnapPoints
|
|
156
|
+
* paths that don't fire React-tracked events. Will be removed in v2.
|
|
157
|
+
*/
|
|
158
|
+
engine: BottomSheetEngine | null;
|
|
159
|
+
/** Lazy accessor — always reads the live engine, even after external
|
|
160
|
+
* mutations (resize, setSnapPoints) that don't fire React-tracked events.
|
|
161
|
+
* Strict-Mode-safe: returns the current ref at call time, not a stale
|
|
162
|
+
* snapshot from the last commit. */
|
|
163
|
+
getEngine: () => BottomSheetEngine | null;
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* Headless React hook. Wires the engine to refs and subscribes to its events
|
|
167
|
+
* via `useSyncExternalStore` for tear-free state in concurrent mode.
|
|
168
|
+
*
|
|
169
|
+
* The snapshot is cached in a ref and only refreshed when a notify fires,
|
|
170
|
+
* so React's identity check doesn't trigger an infinite loop (the engine's
|
|
171
|
+
* `state` getter constructs a fresh object every call).
|
|
172
|
+
*/
|
|
173
|
+
type HookOpts<TId extends string> = Omit<EngineOptions, "element" | "handle" | "scrollContainer" | "backdrop" | "screenComponent" | "snapPoints" | "allowed" | "initial"> & {
|
|
174
|
+
snapPoints: SnapPointDef<TId>[] | ReadonlyArray<SnapPointDef<TId>>;
|
|
175
|
+
allowed?: TId[] | ReadonlyArray<TId>;
|
|
176
|
+
initial?: TId;
|
|
177
|
+
/** Called after a snap commit settles. Mirrors the engine's `snap` event. */
|
|
178
|
+
onSnap?: (id: TId) => void;
|
|
179
|
+
};
|
|
180
|
+
declare function useBottomSheet<TId extends string = string>(opts: HookOpts<TId>): UseBottomSheetReturn<TId>;
|
|
181
|
+
|
|
182
|
+
type OverlayProps = Omit<OverlayOptions, "element" | "backdrop"> & {
|
|
183
|
+
/** Controlled open state. If omitted, the overlay is uncontrolled. */
|
|
184
|
+
open?: boolean;
|
|
185
|
+
/** Render the backdrop. Default: true. */
|
|
186
|
+
backdrop?: boolean;
|
|
187
|
+
className?: string;
|
|
188
|
+
style?: CSSProperties;
|
|
189
|
+
children?: ReactNode;
|
|
190
|
+
ariaLabel?: string;
|
|
191
|
+
ariaLabelledBy?: string;
|
|
192
|
+
onChange?: (state: OverlayState) => void;
|
|
193
|
+
};
|
|
194
|
+
type OverlayHandle = {
|
|
195
|
+
open: () => Promise<void>;
|
|
196
|
+
close: () => Promise<void>;
|
|
197
|
+
toggle: () => Promise<void>;
|
|
198
|
+
state: OverlayState;
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* Bottom-anchored slide-up overlay panel. Distinct from `<BottomSheet>`:
|
|
202
|
+
* no drag, no snap points, single binary state. CSS-transition animated
|
|
203
|
+
* (no spring) — lighter weight, predictable timing.
|
|
204
|
+
*/
|
|
205
|
+
declare const Overlay: react.ForwardRefExoticComponent<Omit<OverlayOptions, "element" | "backdrop"> & {
|
|
206
|
+
/** Controlled open state. If omitted, the overlay is uncontrolled. */
|
|
207
|
+
open?: boolean;
|
|
208
|
+
/** Render the backdrop. Default: true. */
|
|
209
|
+
backdrop?: boolean;
|
|
210
|
+
className?: string;
|
|
211
|
+
style?: CSSProperties;
|
|
212
|
+
children?: ReactNode;
|
|
213
|
+
ariaLabel?: string;
|
|
214
|
+
ariaLabelledBy?: string;
|
|
215
|
+
onChange?: (state: OverlayState) => void;
|
|
216
|
+
} & react.RefAttributes<OverlayHandle>>;
|
|
217
|
+
|
|
218
|
+
type UseOverlayReturn = {
|
|
219
|
+
panelRef: React.RefObject<HTMLElement>;
|
|
220
|
+
backdropRef: React.RefObject<HTMLElement>;
|
|
221
|
+
state: OverlayState;
|
|
222
|
+
open: () => Promise<void>;
|
|
223
|
+
close: () => Promise<void>;
|
|
224
|
+
toggle: () => Promise<void>;
|
|
225
|
+
/**
|
|
226
|
+
* Lazy accessor for the underlying engine. Returns null on SSR or before
|
|
227
|
+
* the layout effect mounts the engine. Use this — not a snapshot — so you
|
|
228
|
+
* always read the current instance.
|
|
229
|
+
*/
|
|
230
|
+
getEngine: () => OverlayEngine | null;
|
|
231
|
+
};
|
|
232
|
+
declare const useOverlay: (opts: Omit<OverlayOptions, "element" | "backdrop">) => UseOverlayReturn;
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* JSON-serializable sheet configuration for CMS-driven / A-B / plugin /
|
|
236
|
+
* server-driven UI. Functions can't be JSON, so handlers live in the
|
|
237
|
+
* sibling `eventHandlers` prop keyed by `events.{onSnap,onOpen,onClose}`.
|
|
238
|
+
*
|
|
239
|
+
* Treat configs as immutable — derived props are memoized by config
|
|
240
|
+
* identity, mutating in place leaves stale snap geometry behind.
|
|
241
|
+
*/
|
|
242
|
+
type SheetConfig = {
|
|
243
|
+
/** Schema version. Must be `1` for the current wrapper. */
|
|
244
|
+
version: 1;
|
|
245
|
+
/** Ordered list of snap points (smallest → largest). Required. */
|
|
246
|
+
snapPoints: Array<{
|
|
247
|
+
id: string;
|
|
248
|
+
size: number | string;
|
|
249
|
+
}>;
|
|
250
|
+
/** Initial snap id. Falls back to first allowed (or first overall). */
|
|
251
|
+
initial?: string;
|
|
252
|
+
/** Subset of snap-point ids the sheet may settle on right now. */
|
|
253
|
+
allowed?: string[];
|
|
254
|
+
/** Direction the sheet expands from. Default: "bottom". */
|
|
255
|
+
mode?: SheetMode;
|
|
256
|
+
/** Animation strategy. Default: "spring". */
|
|
257
|
+
animation?: "spring" | "tween";
|
|
258
|
+
/** Spring config when `animation: "spring"`. */
|
|
259
|
+
spring?: {
|
|
260
|
+
stiffness?: number;
|
|
261
|
+
damping?: number;
|
|
262
|
+
mass?: number;
|
|
263
|
+
};
|
|
264
|
+
/** Behavior toggles. All optional; missing keys fall back to engine defaults. */
|
|
265
|
+
behavior?: {
|
|
266
|
+
focusTrap?: boolean;
|
|
267
|
+
closeOnEscape?: boolean;
|
|
268
|
+
closeOnBackdrop?: boolean;
|
|
269
|
+
lockBodyScroll?: boolean;
|
|
270
|
+
rubberBand?: boolean;
|
|
271
|
+
};
|
|
272
|
+
/**
|
|
273
|
+
* Map event name → handler key. The actual functions live in the
|
|
274
|
+
* `eventHandlers` prop on the wrapper component, keyed by the same
|
|
275
|
+
* string. Missing handler keys are tolerated (warn + no-op).
|
|
276
|
+
*/
|
|
277
|
+
events?: {
|
|
278
|
+
onSnap?: string;
|
|
279
|
+
onOpen?: string;
|
|
280
|
+
onClose?: string;
|
|
281
|
+
};
|
|
282
|
+
};
|
|
283
|
+
type SheetEventHandler = ((id: string) => void) | (() => void);
|
|
284
|
+
type BottomSheetFromConfigProps = {
|
|
285
|
+
config: SheetConfig;
|
|
286
|
+
eventHandlers?: Record<string, SheetEventHandler>;
|
|
287
|
+
slotContent?: {
|
|
288
|
+
header?: ReactNode;
|
|
289
|
+
body?: ReactNode;
|
|
290
|
+
};
|
|
291
|
+
/**
|
|
292
|
+
* Memoize derived props by content (JSON.stringify) instead of identity.
|
|
293
|
+
* Set when fetching via SWR / TanStack Query / RSC loaders that hand back
|
|
294
|
+
* a fresh object on every cache hit — prevents engine rebuilds on byte-
|
|
295
|
+
* identical revalidations. Default false keeps the cheap identity path.
|
|
296
|
+
*/
|
|
297
|
+
stableContent?: boolean;
|
|
298
|
+
};
|
|
299
|
+
declare const BottomSheetFromConfig: react.ForwardRefExoticComponent<BottomSheetFromConfigProps & react.RefAttributes<BottomSheetHandle>>;
|
|
300
|
+
|
|
301
|
+
export { BottomSheet, BottomSheetFromConfig, type BottomSheetFromConfigProps, type BottomSheetHandle, type BottomSheetProps, EngineState, type HeaderProp, Overlay, type OverlayHandle, OverlayOptions, type OverlayProps, OverlayState, type SheetConfig, SheetMode, SnapPointDef, type UseBottomSheetRefs, type UseBottomSheetReturn, type UseOverlayReturn, useBottomSheet, useOverlay };
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { b as EngineOptions, E as EngineState, B as BottomSheetEngine, S as SnapPointDef, a as SheetMode } from './BottomSheetEngine-DbO8rW_3.js';
|
|
2
|
+
export { c as SnapPoint } from './BottomSheetEngine-DbO8rW_3.js';
|
|
3
|
+
import { OverlayOptions, OverlayState, Overlay as OverlayEngine } from './overlay.js';
|
|
4
|
+
export { OverlayEdge } from './overlay.js';
|
|
5
|
+
import * as react from 'react';
|
|
6
|
+
import { CSSProperties, ReactNode } from 'react';
|
|
7
|
+
import './transform-Brkf-wzo.js';
|
|
8
|
+
|
|
9
|
+
type EngineOptionsForProps = Omit<EngineOptions, "element" | "handle" | "scrollContainer" | "backdrop" | "screenComponent">;
|
|
10
|
+
/**
|
|
11
|
+
* Header content for the sheet. Two forms are supported:
|
|
12
|
+
* - **Static node**: `header={<h2>Title</h2>}` — rendered once and never
|
|
13
|
+
* updated when the active snap changes.
|
|
14
|
+
* - **Render function**: `header={state => <h2>{state.activeId}</h2>}` —
|
|
15
|
+
* called on every settled snap change with the current `EngineState`,
|
|
16
|
+
* so the header can morph per snap (e.g. minimized header vs full
|
|
17
|
+
* header). The function fires from the same `useSyncExternalStore`
|
|
18
|
+
* subscription that drives the rest of the component, so identity is
|
|
19
|
+
* stable between snaps and only re-renders on transitions.
|
|
20
|
+
*/
|
|
21
|
+
type HeaderProp = ReactNode | ((state: EngineState) => ReactNode);
|
|
22
|
+
type BottomSheetProps = EngineOptionsForProps & {
|
|
23
|
+
/** Render the dimmed overlay behind the sheet. Default: true. */
|
|
24
|
+
backdrop?: boolean;
|
|
25
|
+
/** Close when the backdrop is clicked. Default: true. */
|
|
26
|
+
closeOnBackdrop?: boolean;
|
|
27
|
+
/** Optional className appended to the root sheet element. */
|
|
28
|
+
className?: string;
|
|
29
|
+
style?: CSSProperties;
|
|
30
|
+
/**
|
|
31
|
+
* Header content (above the scrollable content; doubles as drag handle
|
|
32
|
+
* area). Accepts either a static `ReactNode` or a function
|
|
33
|
+
* `(state: EngineState) => ReactNode` that re-renders on every snap
|
|
34
|
+
* transition — letting consumers show different markup per snap state
|
|
35
|
+
* (e.g. minimized vs half vs full).
|
|
36
|
+
*/
|
|
37
|
+
header?: HeaderProp;
|
|
38
|
+
/** Children become the scrollable content area. */
|
|
39
|
+
children?: ReactNode;
|
|
40
|
+
/** Slot above the sheet, anchored to the left. */
|
|
41
|
+
leftButton?: ReactNode;
|
|
42
|
+
/** Slot above the sheet, anchored to the right. */
|
|
43
|
+
rightButton?: ReactNode;
|
|
44
|
+
/** Element rendered behind the sheet, fading in with progress. */
|
|
45
|
+
screen?: ReactNode;
|
|
46
|
+
/** Fired whenever active snap changes. */
|
|
47
|
+
onChange?: (state: EngineState) => void;
|
|
48
|
+
/** Visually hidden label for screen readers. */
|
|
49
|
+
ariaLabel?: string;
|
|
50
|
+
/** ID of an existing heading element inside the sheet (preferred over ariaLabel). */
|
|
51
|
+
ariaLabelledBy?: string;
|
|
52
|
+
/** Skip rendering on the server to avoid hydration mismatches. Default: false. */
|
|
53
|
+
noSSR?: boolean;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Imperative handle returned by `<BottomSheet ref={…}>`.
|
|
57
|
+
*
|
|
58
|
+
* Opt-in literal-id typing — pass a string-literal union as `TId` to get
|
|
59
|
+
* compile-time errors on typos:
|
|
60
|
+
*
|
|
61
|
+
* ```ts
|
|
62
|
+
* // Default (back-compat): TId = string, anything goes
|
|
63
|
+
* const ref = useRef<BottomSheetHandle>(null);
|
|
64
|
+
* ref.current?.snapTo("anything"); // ✓ compiles, fails silently at runtime
|
|
65
|
+
*
|
|
66
|
+
* // Opt-in: typo-safe
|
|
67
|
+
* const ref = useRef<BottomSheetHandle<"min" | "half" | "full">>(null);
|
|
68
|
+
* ref.current?.snapTo("haf"); // ❌ TS2345
|
|
69
|
+
* ref.current?.snapTo("half"); // ✓
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* `TId` defaults to `string` so existing call sites compile unchanged.
|
|
73
|
+
* The underlying engine stays `string`-typed; the literal narrowing is a
|
|
74
|
+
* TS-only convenience layered on top of the runtime.
|
|
75
|
+
*/
|
|
76
|
+
type BottomSheetHandle<TId extends string = string> = {
|
|
77
|
+
snapTo: (id: TId) => Promise<void>;
|
|
78
|
+
open: (id?: TId) => Promise<void>;
|
|
79
|
+
close: () => Promise<void>;
|
|
80
|
+
setAllowed: (ids: TId[], snap?: TId) => void;
|
|
81
|
+
state: EngineState & {
|
|
82
|
+
activeId: TId;
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* React component built on the headless engine. For full control, use
|
|
87
|
+
* `useBottomSheet` directly and assemble your own JSX.
|
|
88
|
+
*/
|
|
89
|
+
declare const BottomSheet: react.ForwardRefExoticComponent<EngineOptionsForProps & {
|
|
90
|
+
/** Render the dimmed overlay behind the sheet. Default: true. */
|
|
91
|
+
backdrop?: boolean;
|
|
92
|
+
/** Close when the backdrop is clicked. Default: true. */
|
|
93
|
+
closeOnBackdrop?: boolean;
|
|
94
|
+
/** Optional className appended to the root sheet element. */
|
|
95
|
+
className?: string;
|
|
96
|
+
style?: CSSProperties;
|
|
97
|
+
/**
|
|
98
|
+
* Header content (above the scrollable content; doubles as drag handle
|
|
99
|
+
* area). Accepts either a static `ReactNode` or a function
|
|
100
|
+
* `(state: EngineState) => ReactNode` that re-renders on every snap
|
|
101
|
+
* transition — letting consumers show different markup per snap state
|
|
102
|
+
* (e.g. minimized vs half vs full).
|
|
103
|
+
*/
|
|
104
|
+
header?: HeaderProp;
|
|
105
|
+
/** Children become the scrollable content area. */
|
|
106
|
+
children?: ReactNode;
|
|
107
|
+
/** Slot above the sheet, anchored to the left. */
|
|
108
|
+
leftButton?: ReactNode;
|
|
109
|
+
/** Slot above the sheet, anchored to the right. */
|
|
110
|
+
rightButton?: ReactNode;
|
|
111
|
+
/** Element rendered behind the sheet, fading in with progress. */
|
|
112
|
+
screen?: ReactNode;
|
|
113
|
+
/** Fired whenever active snap changes. */
|
|
114
|
+
onChange?: (state: EngineState) => void;
|
|
115
|
+
/** Visually hidden label for screen readers. */
|
|
116
|
+
ariaLabel?: string;
|
|
117
|
+
/** ID of an existing heading element inside the sheet (preferred over ariaLabel). */
|
|
118
|
+
ariaLabelledBy?: string;
|
|
119
|
+
/** Skip rendering on the server to avoid hydration mismatches. Default: false. */
|
|
120
|
+
noSSR?: boolean;
|
|
121
|
+
} & react.RefAttributes<BottomSheetHandle<string>>>;
|
|
122
|
+
|
|
123
|
+
type UseBottomSheetRefs = {
|
|
124
|
+
sheetRef: React.RefObject<HTMLElement>;
|
|
125
|
+
handleRef: React.RefObject<HTMLElement>;
|
|
126
|
+
contentRef: React.RefObject<HTMLElement>;
|
|
127
|
+
backdropRef: React.RefObject<HTMLElement>;
|
|
128
|
+
screenRef: React.RefObject<HTMLElement>;
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Return shape of `useBottomSheet`. Optionally narrows to a literal-id union
|
|
132
|
+
* `TId` when the consumer explicitly types the call site:
|
|
133
|
+
*
|
|
134
|
+
* ```ts
|
|
135
|
+
* const sheet = useBottomSheet<"min" | "full">({ snapPoints: [...] });
|
|
136
|
+
* sheet.snapTo("min"); // ✓
|
|
137
|
+
* ```
|
|
138
|
+
*
|
|
139
|
+
* Without an explicit type argument `TId` defaults to `string`.
|
|
140
|
+
*/
|
|
141
|
+
type UseBottomSheetReturn<TId extends string = string> = UseBottomSheetRefs & {
|
|
142
|
+
state: EngineState & {
|
|
143
|
+
activeId: TId;
|
|
144
|
+
};
|
|
145
|
+
snapTo: (id: TId) => Promise<void>;
|
|
146
|
+
open: (id?: TId) => Promise<void>;
|
|
147
|
+
close: () => Promise<void>;
|
|
148
|
+
setAllowed: (ids: TId[], snap?: TId) => void;
|
|
149
|
+
/**
|
|
150
|
+
* @deprecated React Strict Mode double-invokes the layout effect — the
|
|
151
|
+
* effect tears down (engineRef.current = null), the next render reads
|
|
152
|
+
* this field as `null` for one frame, and only the second mount restores
|
|
153
|
+
* a live engine. Consumers calling methods through this field during that
|
|
154
|
+
* window get `null`. Use `getEngine()` instead — it lazy-reads the live
|
|
155
|
+
* ref and is safe across Strict Mode and across resize/setSnapPoints
|
|
156
|
+
* paths that don't fire React-tracked events. Will be removed in v2.
|
|
157
|
+
*/
|
|
158
|
+
engine: BottomSheetEngine | null;
|
|
159
|
+
/** Lazy accessor — always reads the live engine, even after external
|
|
160
|
+
* mutations (resize, setSnapPoints) that don't fire React-tracked events.
|
|
161
|
+
* Strict-Mode-safe: returns the current ref at call time, not a stale
|
|
162
|
+
* snapshot from the last commit. */
|
|
163
|
+
getEngine: () => BottomSheetEngine | null;
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* Headless React hook. Wires the engine to refs and subscribes to its events
|
|
167
|
+
* via `useSyncExternalStore` for tear-free state in concurrent mode.
|
|
168
|
+
*
|
|
169
|
+
* The snapshot is cached in a ref and only refreshed when a notify fires,
|
|
170
|
+
* so React's identity check doesn't trigger an infinite loop (the engine's
|
|
171
|
+
* `state` getter constructs a fresh object every call).
|
|
172
|
+
*/
|
|
173
|
+
type HookOpts<TId extends string> = Omit<EngineOptions, "element" | "handle" | "scrollContainer" | "backdrop" | "screenComponent" | "snapPoints" | "allowed" | "initial"> & {
|
|
174
|
+
snapPoints: SnapPointDef<TId>[] | ReadonlyArray<SnapPointDef<TId>>;
|
|
175
|
+
allowed?: TId[] | ReadonlyArray<TId>;
|
|
176
|
+
initial?: TId;
|
|
177
|
+
/** Called after a snap commit settles. Mirrors the engine's `snap` event. */
|
|
178
|
+
onSnap?: (id: TId) => void;
|
|
179
|
+
};
|
|
180
|
+
declare function useBottomSheet<TId extends string = string>(opts: HookOpts<TId>): UseBottomSheetReturn<TId>;
|
|
181
|
+
|
|
182
|
+
type OverlayProps = Omit<OverlayOptions, "element" | "backdrop"> & {
|
|
183
|
+
/** Controlled open state. If omitted, the overlay is uncontrolled. */
|
|
184
|
+
open?: boolean;
|
|
185
|
+
/** Render the backdrop. Default: true. */
|
|
186
|
+
backdrop?: boolean;
|
|
187
|
+
className?: string;
|
|
188
|
+
style?: CSSProperties;
|
|
189
|
+
children?: ReactNode;
|
|
190
|
+
ariaLabel?: string;
|
|
191
|
+
ariaLabelledBy?: string;
|
|
192
|
+
onChange?: (state: OverlayState) => void;
|
|
193
|
+
};
|
|
194
|
+
type OverlayHandle = {
|
|
195
|
+
open: () => Promise<void>;
|
|
196
|
+
close: () => Promise<void>;
|
|
197
|
+
toggle: () => Promise<void>;
|
|
198
|
+
state: OverlayState;
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* Bottom-anchored slide-up overlay panel. Distinct from `<BottomSheet>`:
|
|
202
|
+
* no drag, no snap points, single binary state. CSS-transition animated
|
|
203
|
+
* (no spring) — lighter weight, predictable timing.
|
|
204
|
+
*/
|
|
205
|
+
declare const Overlay: react.ForwardRefExoticComponent<Omit<OverlayOptions, "element" | "backdrop"> & {
|
|
206
|
+
/** Controlled open state. If omitted, the overlay is uncontrolled. */
|
|
207
|
+
open?: boolean;
|
|
208
|
+
/** Render the backdrop. Default: true. */
|
|
209
|
+
backdrop?: boolean;
|
|
210
|
+
className?: string;
|
|
211
|
+
style?: CSSProperties;
|
|
212
|
+
children?: ReactNode;
|
|
213
|
+
ariaLabel?: string;
|
|
214
|
+
ariaLabelledBy?: string;
|
|
215
|
+
onChange?: (state: OverlayState) => void;
|
|
216
|
+
} & react.RefAttributes<OverlayHandle>>;
|
|
217
|
+
|
|
218
|
+
type UseOverlayReturn = {
|
|
219
|
+
panelRef: React.RefObject<HTMLElement>;
|
|
220
|
+
backdropRef: React.RefObject<HTMLElement>;
|
|
221
|
+
state: OverlayState;
|
|
222
|
+
open: () => Promise<void>;
|
|
223
|
+
close: () => Promise<void>;
|
|
224
|
+
toggle: () => Promise<void>;
|
|
225
|
+
/**
|
|
226
|
+
* Lazy accessor for the underlying engine. Returns null on SSR or before
|
|
227
|
+
* the layout effect mounts the engine. Use this — not a snapshot — so you
|
|
228
|
+
* always read the current instance.
|
|
229
|
+
*/
|
|
230
|
+
getEngine: () => OverlayEngine | null;
|
|
231
|
+
};
|
|
232
|
+
declare const useOverlay: (opts: Omit<OverlayOptions, "element" | "backdrop">) => UseOverlayReturn;
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* JSON-serializable sheet configuration for CMS-driven / A-B / plugin /
|
|
236
|
+
* server-driven UI. Functions can't be JSON, so handlers live in the
|
|
237
|
+
* sibling `eventHandlers` prop keyed by `events.{onSnap,onOpen,onClose}`.
|
|
238
|
+
*
|
|
239
|
+
* Treat configs as immutable — derived props are memoized by config
|
|
240
|
+
* identity, mutating in place leaves stale snap geometry behind.
|
|
241
|
+
*/
|
|
242
|
+
type SheetConfig = {
|
|
243
|
+
/** Schema version. Must be `1` for the current wrapper. */
|
|
244
|
+
version: 1;
|
|
245
|
+
/** Ordered list of snap points (smallest → largest). Required. */
|
|
246
|
+
snapPoints: Array<{
|
|
247
|
+
id: string;
|
|
248
|
+
size: number | string;
|
|
249
|
+
}>;
|
|
250
|
+
/** Initial snap id. Falls back to first allowed (or first overall). */
|
|
251
|
+
initial?: string;
|
|
252
|
+
/** Subset of snap-point ids the sheet may settle on right now. */
|
|
253
|
+
allowed?: string[];
|
|
254
|
+
/** Direction the sheet expands from. Default: "bottom". */
|
|
255
|
+
mode?: SheetMode;
|
|
256
|
+
/** Animation strategy. Default: "spring". */
|
|
257
|
+
animation?: "spring" | "tween";
|
|
258
|
+
/** Spring config when `animation: "spring"`. */
|
|
259
|
+
spring?: {
|
|
260
|
+
stiffness?: number;
|
|
261
|
+
damping?: number;
|
|
262
|
+
mass?: number;
|
|
263
|
+
};
|
|
264
|
+
/** Behavior toggles. All optional; missing keys fall back to engine defaults. */
|
|
265
|
+
behavior?: {
|
|
266
|
+
focusTrap?: boolean;
|
|
267
|
+
closeOnEscape?: boolean;
|
|
268
|
+
closeOnBackdrop?: boolean;
|
|
269
|
+
lockBodyScroll?: boolean;
|
|
270
|
+
rubberBand?: boolean;
|
|
271
|
+
};
|
|
272
|
+
/**
|
|
273
|
+
* Map event name → handler key. The actual functions live in the
|
|
274
|
+
* `eventHandlers` prop on the wrapper component, keyed by the same
|
|
275
|
+
* string. Missing handler keys are tolerated (warn + no-op).
|
|
276
|
+
*/
|
|
277
|
+
events?: {
|
|
278
|
+
onSnap?: string;
|
|
279
|
+
onOpen?: string;
|
|
280
|
+
onClose?: string;
|
|
281
|
+
};
|
|
282
|
+
};
|
|
283
|
+
type SheetEventHandler = ((id: string) => void) | (() => void);
|
|
284
|
+
type BottomSheetFromConfigProps = {
|
|
285
|
+
config: SheetConfig;
|
|
286
|
+
eventHandlers?: Record<string, SheetEventHandler>;
|
|
287
|
+
slotContent?: {
|
|
288
|
+
header?: ReactNode;
|
|
289
|
+
body?: ReactNode;
|
|
290
|
+
};
|
|
291
|
+
/**
|
|
292
|
+
* Memoize derived props by content (JSON.stringify) instead of identity.
|
|
293
|
+
* Set when fetching via SWR / TanStack Query / RSC loaders that hand back
|
|
294
|
+
* a fresh object on every cache hit — prevents engine rebuilds on byte-
|
|
295
|
+
* identical revalidations. Default false keeps the cheap identity path.
|
|
296
|
+
*/
|
|
297
|
+
stableContent?: boolean;
|
|
298
|
+
};
|
|
299
|
+
declare const BottomSheetFromConfig: react.ForwardRefExoticComponent<BottomSheetFromConfigProps & react.RefAttributes<BottomSheetHandle>>;
|
|
300
|
+
|
|
301
|
+
export { BottomSheet, BottomSheetFromConfig, type BottomSheetFromConfigProps, type BottomSheetHandle, type BottomSheetProps, EngineState, type HeaderProp, Overlay, type OverlayHandle, OverlayOptions, type OverlayProps, OverlayState, type SheetConfig, SheetMode, SnapPointDef, type UseBottomSheetRefs, type UseBottomSheetReturn, type UseOverlayReturn, useBottomSheet, useOverlay };
|