@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.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +377 -0
  3. package/dist/BottomSheetEngine-CvSVbo6c.d.cts +704 -0
  4. package/dist/BottomSheetEngine-DbO8rW_3.d.ts +704 -0
  5. package/dist/element.cjs +3442 -0
  6. package/dist/element.d.cts +88 -0
  7. package/dist/element.d.ts +88 -0
  8. package/dist/element.iife.global.js +3 -0
  9. package/dist/element.js +3442 -0
  10. package/dist/index.cjs +3693 -0
  11. package/dist/index.d.cts +184 -0
  12. package/dist/index.d.ts +184 -0
  13. package/dist/index.js +3669 -0
  14. package/dist/integrations/formik.cjs +27 -0
  15. package/dist/integrations/formik.d.cts +27 -0
  16. package/dist/integrations/formik.d.ts +27 -0
  17. package/dist/integrations/formik.js +25 -0
  18. package/dist/integrations/react-hook-form.cjs +28 -0
  19. package/dist/integrations/react-hook-form.d.cts +30 -0
  20. package/dist/integrations/react-hook-form.d.ts +30 -0
  21. package/dist/integrations/react-hook-form.js +26 -0
  22. package/dist/overlay.cjs +1058 -0
  23. package/dist/overlay.d.cts +282 -0
  24. package/dist/overlay.d.ts +282 -0
  25. package/dist/overlay.js +1053 -0
  26. package/dist/preact.cjs +2 -0
  27. package/dist/preact.d.cts +5 -0
  28. package/dist/preact.d.ts +5 -0
  29. package/dist/preact.js +2 -0
  30. package/dist/qwik.cjs +3046 -0
  31. package/dist/qwik.d.cts +55 -0
  32. package/dist/qwik.d.ts +55 -0
  33. package/dist/qwik.js +3044 -0
  34. package/dist/react.cjs +4162 -0
  35. package/dist/react.d.cts +301 -0
  36. package/dist/react.d.ts +301 -0
  37. package/dist/react.js +4156 -0
  38. package/dist/solid.cjs +3063 -0
  39. package/dist/solid.d.cts +66 -0
  40. package/dist/solid.d.ts +66 -0
  41. package/dist/solid.js +3061 -0
  42. package/dist/styles.css +508 -0
  43. package/dist/svelte.cjs +3200 -0
  44. package/dist/svelte.d.ts +89 -0
  45. package/dist/svelte.js +3177 -0
  46. package/dist/themes/ios.css +24 -0
  47. package/dist/themes/material.css +24 -0
  48. package/dist/themes/vercel.css +24 -0
  49. package/dist/transform-Brkf-wzo.d.cts +4 -0
  50. package/dist/transform-Brkf-wzo.d.ts +4 -0
  51. package/dist/vue.cjs +3361 -0
  52. package/dist/vue.d.ts +68 -0
  53. package/dist/vue.js +3358 -0
  54. package/package.json +288 -0
@@ -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 };
@@ -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 };