@surdeddd/bottom-sheet 0.1.0 → 0.3.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 (57) hide show
  1. package/README.md +57 -21
  2. package/dist/BottomSheetEngine-CAymrH-P.d.cts +285 -0
  3. package/dist/BottomSheetEngine-DcqcuudN.d.ts +285 -0
  4. package/dist/element.cjs +775 -537
  5. package/dist/element.d.cts +9 -57
  6. package/dist/element.d.ts +9 -57
  7. package/dist/element.iife.global.js +2 -2
  8. package/dist/element.js +775 -537
  9. package/dist/index.cjs +760 -600
  10. package/dist/index.d.cts +18 -85
  11. package/dist/index.d.ts +18 -85
  12. package/dist/index.js +758 -601
  13. package/dist/integrations/formik.d.cts +2 -8
  14. package/dist/integrations/formik.d.ts +2 -8
  15. package/dist/integrations/react-hook-form.d.cts +2 -11
  16. package/dist/integrations/react-hook-form.d.ts +2 -11
  17. package/dist/overlay.cjs +168 -122
  18. package/dist/overlay.d.cts +14 -137
  19. package/dist/overlay.d.ts +14 -137
  20. package/dist/overlay.js +168 -122
  21. package/dist/preact.d.cts +2 -2
  22. package/dist/preact.d.ts +2 -2
  23. package/dist/preact.js +0 -1
  24. package/dist/qwik.cjs +667 -519
  25. package/dist/qwik.d.cts +3 -24
  26. package/dist/qwik.d.ts +3 -24
  27. package/dist/qwik.js +668 -520
  28. package/dist/react.cjs +873 -648
  29. package/dist/react.d.cts +34 -159
  30. package/dist/react.d.ts +34 -159
  31. package/dist/react.js +873 -648
  32. package/dist/solid.cjs +703 -560
  33. package/dist/solid.d.cts +264 -32
  34. package/dist/solid.d.ts +264 -32
  35. package/dist/solid.js +704 -561
  36. package/dist/solid.source.jsx +3215 -0
  37. package/dist/styles.css +37 -112
  38. package/dist/svelte-core.cjs +3149 -0
  39. package/dist/svelte-core.js +3147 -0
  40. package/dist/svelte-src/BottomSheet.svelte +210 -0
  41. package/dist/svelte-src/index.js +2 -0
  42. package/dist/svelte.cjs +718 -547
  43. package/dist/svelte.d.cts +100 -0
  44. package/dist/svelte.d.ts +15 -4
  45. package/dist/svelte.js +719 -548
  46. package/dist/themes/ios.css +0 -3
  47. package/dist/themes/material.css +0 -3
  48. package/dist/themes/vercel.css +0 -3
  49. package/dist/{transform-Brkf-wzo.d.cts → transform-jVfAikE9.d.cts} +0 -1
  50. package/dist/{transform-Brkf-wzo.d.ts → transform-jVfAikE9.d.ts} +0 -1
  51. package/dist/vue.cjs +677 -526
  52. package/dist/vue.d.cts +78 -0
  53. package/dist/vue.d.ts +12 -2
  54. package/dist/vue.js +678 -527
  55. package/package.json +105 -45
  56. package/dist/BottomSheetEngine-CvSVbo6c.d.cts +0 -704
  57. package/dist/BottomSheetEngine-DbO8rW_3.d.ts +0 -704
package/dist/react.d.cts CHANGED
@@ -1,143 +1,79 @@
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';
1
+ import { c as EngineOptions, E as EngineState, A as AnchorOptions, S as ScrimStagesOptions, p as ScrimStageDef, q as ScrimUpdate, m as ScrimOverlayOptions, B as BottomSheetEngine, a as SnapPointDef, b as SheetMode } from './BottomSheetEngine-CAymrH-P.cjs';
2
+ export { d as SnapPoint } from './BottomSheetEngine-CAymrH-P.cjs';
3
3
  import { OverlayOptions, OverlayState, Overlay as OverlayEngine } from './overlay.cjs';
4
4
  export { OverlayEdge } from './overlay.cjs';
5
5
  import * as react from 'react';
6
6
  import { CSSProperties, ReactNode } from 'react';
7
- import './transform-Brkf-wzo.cjs';
7
+ import './transform-jVfAikE9.cjs';
8
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
- */
9
+ type EngineOptionsForProps = Omit<EngineOptions, "element" | "handle" | "scrollContainer" | "backdrop" | "scrim">;
21
10
  type HeaderProp = ReactNode | ((state: EngineState) => ReactNode);
11
+ type BottomSheetAnchorProp = Omit<AnchorOptions, "element"> & {
12
+ node: ReactNode;
13
+ };
14
+ type BottomSheetScrimStageProp = Omit<ScrimStageDef, "element"> & {
15
+ node: ReactNode;
16
+ };
17
+ type BottomSheetScrimStagesProp = Omit<ScrimStagesOptions, "stages"> & {
18
+ stages: BottomSheetScrimStageProp[];
19
+ };
22
20
  type BottomSheetProps = EngineOptionsForProps & {
23
- /** Render the dimmed overlay behind the sheet. Default: true. */
24
21
  backdrop?: boolean;
25
- /** Close when the backdrop is clicked. Default: true. */
26
22
  closeOnBackdrop?: boolean;
27
- /** Optional className appended to the root sheet element. */
28
23
  className?: string;
29
24
  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
25
  header?: HeaderProp;
38
- /** Children become the scrollable content area. */
39
26
  children?: ReactNode;
40
- /** Slot above the sheet, anchored to the left. */
41
27
  leftButton?: ReactNode;
42
- /** Slot above the sheet, anchored to the right. */
43
28
  rightButton?: ReactNode;
44
- /** Element rendered behind the sheet, fading in with progress. */
45
29
  screen?: ReactNode;
46
- /** Fired whenever active snap changes. */
30
+ anchors?: BottomSheetAnchorProp[];
31
+ scrimStages?: BottomSheetScrimStagesProp;
47
32
  onChange?: (state: EngineState) => void;
48
- /** Visually hidden label for screen readers. */
49
33
  ariaLabel?: string;
50
- /** ID of an existing heading element inside the sheet (preferred over ariaLabel). */
51
34
  ariaLabelledBy?: string;
52
- /** Skip rendering on the server to avoid hydration mismatches. Default: false. */
53
35
  noSSR?: boolean;
54
36
  };
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
37
  type BottomSheetHandle<TId extends string = string> = {
77
38
  snapTo: (id: TId) => Promise<void>;
78
39
  open: (id?: TId) => Promise<void>;
79
40
  close: () => Promise<void>;
80
41
  setAllowed: (ids: TId[], snap?: TId) => void;
42
+ setSnapPoints: (points: EngineOptions["snapPoints"], allowed?: string[]) => void;
43
+ setScrim: (opts: ScrimUpdate) => void;
44
+ setScrimOverlay: (opts: ScrimOverlayOptions) => () => void;
45
+ addAnchor: (opts: AnchorOptions) => () => void;
46
+ setScrimStages: (opts: ScrimStagesOptions | null) => () => void;
81
47
  state: EngineState & {
82
48
  activeId: TId;
83
49
  };
50
+ getEngine: () => BottomSheetEngine | null;
84
51
  };
85
- /**
86
- * React component built on the headless engine. For full control, use
87
- * `useBottomSheet` directly and assemble your own JSX.
88
- */
89
52
  declare const BottomSheet: react.ForwardRefExoticComponent<EngineOptionsForProps & {
90
- /** Render the dimmed overlay behind the sheet. Default: true. */
91
53
  backdrop?: boolean;
92
- /** Close when the backdrop is clicked. Default: true. */
93
54
  closeOnBackdrop?: boolean;
94
- /** Optional className appended to the root sheet element. */
95
55
  className?: string;
96
56
  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
57
  header?: HeaderProp;
105
- /** Children become the scrollable content area. */
106
58
  children?: ReactNode;
107
- /** Slot above the sheet, anchored to the left. */
108
59
  leftButton?: ReactNode;
109
- /** Slot above the sheet, anchored to the right. */
110
60
  rightButton?: ReactNode;
111
- /** Element rendered behind the sheet, fading in with progress. */
112
61
  screen?: ReactNode;
113
- /** Fired whenever active snap changes. */
62
+ anchors?: BottomSheetAnchorProp[];
63
+ scrimStages?: BottomSheetScrimStagesProp;
114
64
  onChange?: (state: EngineState) => void;
115
- /** Visually hidden label for screen readers. */
116
65
  ariaLabel?: string;
117
- /** ID of an existing heading element inside the sheet (preferred over ariaLabel). */
118
66
  ariaLabelledBy?: string;
119
- /** Skip rendering on the server to avoid hydration mismatches. Default: false. */
120
67
  noSSR?: boolean;
121
68
  } & react.RefAttributes<BottomSheetHandle<string>>>;
122
69
 
123
70
  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>;
71
+ sheetRef: React.RefObject<HTMLElement | null>;
72
+ handleRef: React.RefObject<HTMLElement | null>;
73
+ contentRef: React.RefObject<HTMLElement | null>;
74
+ backdropRef: React.RefObject<HTMLElement | null>;
75
+ screenRef: React.RefObject<HTMLElement | null>;
129
76
  };
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
77
  type UseBottomSheetReturn<TId extends string = string> = UseBottomSheetRefs & {
142
78
  state: EngineState & {
143
79
  activeId: TId;
@@ -146,43 +82,21 @@ type UseBottomSheetReturn<TId extends string = string> = UseBottomSheetRefs & {
146
82
  open: (id?: TId) => Promise<void>;
147
83
  close: () => Promise<void>;
148
84
  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
- */
85
+ addAnchor: (opts: AnchorOptions) => () => void;
86
+ setScrimStages: (opts: ScrimStagesOptions | null) => () => void;
158
87
  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
88
  getEngine: () => BottomSheetEngine | null;
164
89
  };
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"> & {
90
+ type HookOpts<TId extends string> = Omit<EngineOptions, "element" | "handle" | "scrollContainer" | "backdrop" | "scrim" | "snapPoints" | "allowed" | "initial"> & {
174
91
  snapPoints: SnapPointDef<TId>[] | ReadonlyArray<SnapPointDef<TId>>;
175
92
  allowed?: TId[] | ReadonlyArray<TId>;
176
93
  initial?: TId;
177
- /** Called after a snap commit settles. Mirrors the engine's `snap` event. */
178
94
  onSnap?: (id: TId) => void;
179
95
  };
180
96
  declare function useBottomSheet<TId extends string = string>(opts: HookOpts<TId>): UseBottomSheetReturn<TId>;
181
97
 
182
98
  type OverlayProps = Omit<OverlayOptions, "element" | "backdrop"> & {
183
- /** Controlled open state. If omitted, the overlay is uncontrolled. */
184
99
  open?: boolean;
185
- /** Render the backdrop. Default: true. */
186
100
  backdrop?: boolean;
187
101
  className?: string;
188
102
  style?: CSSProperties;
@@ -197,15 +111,8 @@ type OverlayHandle = {
197
111
  toggle: () => Promise<void>;
198
112
  state: OverlayState;
199
113
  };
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. */
114
+ declare const Overlay: react.ForwardRefExoticComponent<Omit<OverlayOptions, "backdrop" | "element"> & {
207
115
  open?: boolean;
208
- /** Render the backdrop. Default: true. */
209
116
  backdrop?: boolean;
210
117
  className?: string;
211
118
  style?: CSSProperties;
@@ -216,52 +123,31 @@ declare const Overlay: react.ForwardRefExoticComponent<Omit<OverlayOptions, "ele
216
123
  } & react.RefAttributes<OverlayHandle>>;
217
124
 
218
125
  type UseOverlayReturn = {
219
- panelRef: React.RefObject<HTMLElement>;
220
- backdropRef: React.RefObject<HTMLElement>;
126
+ panelRef: React.RefObject<HTMLElement | null>;
127
+ backdropRef: React.RefObject<HTMLElement | null>;
221
128
  state: OverlayState;
222
129
  open: () => Promise<void>;
223
130
  close: () => Promise<void>;
224
131
  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
132
  getEngine: () => OverlayEngine | null;
231
133
  };
232
134
  declare const useOverlay: (opts: Omit<OverlayOptions, "element" | "backdrop">) => UseOverlayReturn;
233
135
 
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
136
  type SheetConfig = {
243
- /** Schema version. Must be `1` for the current wrapper. */
244
137
  version: 1;
245
- /** Ordered list of snap points (smallest → largest). Required. */
246
138
  snapPoints: Array<{
247
139
  id: string;
248
140
  size: number | string;
249
141
  }>;
250
- /** Initial snap id. Falls back to first allowed (or first overall). */
251
142
  initial?: string;
252
- /** Subset of snap-point ids the sheet may settle on right now. */
253
143
  allowed?: string[];
254
- /** Direction the sheet expands from. Default: "bottom". */
255
144
  mode?: SheetMode;
256
- /** Animation strategy. Default: "spring". */
257
145
  animation?: "spring" | "tween";
258
- /** Spring config when `animation: "spring"`. */
259
146
  spring?: {
260
147
  stiffness?: number;
261
148
  damping?: number;
262
149
  mass?: number;
263
150
  };
264
- /** Behavior toggles. All optional; missing keys fall back to engine defaults. */
265
151
  behavior?: {
266
152
  focusTrap?: boolean;
267
153
  closeOnEscape?: boolean;
@@ -269,11 +155,6 @@ type SheetConfig = {
269
155
  lockBodyScroll?: boolean;
270
156
  rubberBand?: boolean;
271
157
  };
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
158
  events?: {
278
159
  onSnap?: string;
279
160
  onOpen?: string;
@@ -288,12 +169,6 @@ type BottomSheetFromConfigProps = {
288
169
  header?: ReactNode;
289
170
  body?: ReactNode;
290
171
  };
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
172
  stableContent?: boolean;
298
173
  };
299
174
  declare const BottomSheetFromConfig: react.ForwardRefExoticComponent<BottomSheetFromConfigProps & react.RefAttributes<BottomSheetHandle>>;
package/dist/react.d.ts CHANGED
@@ -1,143 +1,79 @@
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';
1
+ import { c as EngineOptions, E as EngineState, A as AnchorOptions, S as ScrimStagesOptions, p as ScrimStageDef, q as ScrimUpdate, m as ScrimOverlayOptions, B as BottomSheetEngine, a as SnapPointDef, b as SheetMode } from './BottomSheetEngine-DcqcuudN.js';
2
+ export { d as SnapPoint } from './BottomSheetEngine-DcqcuudN.js';
3
3
  import { OverlayOptions, OverlayState, Overlay as OverlayEngine } from './overlay.js';
4
4
  export { OverlayEdge } from './overlay.js';
5
5
  import * as react from 'react';
6
6
  import { CSSProperties, ReactNode } from 'react';
7
- import './transform-Brkf-wzo.js';
7
+ import './transform-jVfAikE9.js';
8
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
- */
9
+ type EngineOptionsForProps = Omit<EngineOptions, "element" | "handle" | "scrollContainer" | "backdrop" | "scrim">;
21
10
  type HeaderProp = ReactNode | ((state: EngineState) => ReactNode);
11
+ type BottomSheetAnchorProp = Omit<AnchorOptions, "element"> & {
12
+ node: ReactNode;
13
+ };
14
+ type BottomSheetScrimStageProp = Omit<ScrimStageDef, "element"> & {
15
+ node: ReactNode;
16
+ };
17
+ type BottomSheetScrimStagesProp = Omit<ScrimStagesOptions, "stages"> & {
18
+ stages: BottomSheetScrimStageProp[];
19
+ };
22
20
  type BottomSheetProps = EngineOptionsForProps & {
23
- /** Render the dimmed overlay behind the sheet. Default: true. */
24
21
  backdrop?: boolean;
25
- /** Close when the backdrop is clicked. Default: true. */
26
22
  closeOnBackdrop?: boolean;
27
- /** Optional className appended to the root sheet element. */
28
23
  className?: string;
29
24
  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
25
  header?: HeaderProp;
38
- /** Children become the scrollable content area. */
39
26
  children?: ReactNode;
40
- /** Slot above the sheet, anchored to the left. */
41
27
  leftButton?: ReactNode;
42
- /** Slot above the sheet, anchored to the right. */
43
28
  rightButton?: ReactNode;
44
- /** Element rendered behind the sheet, fading in with progress. */
45
29
  screen?: ReactNode;
46
- /** Fired whenever active snap changes. */
30
+ anchors?: BottomSheetAnchorProp[];
31
+ scrimStages?: BottomSheetScrimStagesProp;
47
32
  onChange?: (state: EngineState) => void;
48
- /** Visually hidden label for screen readers. */
49
33
  ariaLabel?: string;
50
- /** ID of an existing heading element inside the sheet (preferred over ariaLabel). */
51
34
  ariaLabelledBy?: string;
52
- /** Skip rendering on the server to avoid hydration mismatches. Default: false. */
53
35
  noSSR?: boolean;
54
36
  };
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
37
  type BottomSheetHandle<TId extends string = string> = {
77
38
  snapTo: (id: TId) => Promise<void>;
78
39
  open: (id?: TId) => Promise<void>;
79
40
  close: () => Promise<void>;
80
41
  setAllowed: (ids: TId[], snap?: TId) => void;
42
+ setSnapPoints: (points: EngineOptions["snapPoints"], allowed?: string[]) => void;
43
+ setScrim: (opts: ScrimUpdate) => void;
44
+ setScrimOverlay: (opts: ScrimOverlayOptions) => () => void;
45
+ addAnchor: (opts: AnchorOptions) => () => void;
46
+ setScrimStages: (opts: ScrimStagesOptions | null) => () => void;
81
47
  state: EngineState & {
82
48
  activeId: TId;
83
49
  };
50
+ getEngine: () => BottomSheetEngine | null;
84
51
  };
85
- /**
86
- * React component built on the headless engine. For full control, use
87
- * `useBottomSheet` directly and assemble your own JSX.
88
- */
89
52
  declare const BottomSheet: react.ForwardRefExoticComponent<EngineOptionsForProps & {
90
- /** Render the dimmed overlay behind the sheet. Default: true. */
91
53
  backdrop?: boolean;
92
- /** Close when the backdrop is clicked. Default: true. */
93
54
  closeOnBackdrop?: boolean;
94
- /** Optional className appended to the root sheet element. */
95
55
  className?: string;
96
56
  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
57
  header?: HeaderProp;
105
- /** Children become the scrollable content area. */
106
58
  children?: ReactNode;
107
- /** Slot above the sheet, anchored to the left. */
108
59
  leftButton?: ReactNode;
109
- /** Slot above the sheet, anchored to the right. */
110
60
  rightButton?: ReactNode;
111
- /** Element rendered behind the sheet, fading in with progress. */
112
61
  screen?: ReactNode;
113
- /** Fired whenever active snap changes. */
62
+ anchors?: BottomSheetAnchorProp[];
63
+ scrimStages?: BottomSheetScrimStagesProp;
114
64
  onChange?: (state: EngineState) => void;
115
- /** Visually hidden label for screen readers. */
116
65
  ariaLabel?: string;
117
- /** ID of an existing heading element inside the sheet (preferred over ariaLabel). */
118
66
  ariaLabelledBy?: string;
119
- /** Skip rendering on the server to avoid hydration mismatches. Default: false. */
120
67
  noSSR?: boolean;
121
68
  } & react.RefAttributes<BottomSheetHandle<string>>>;
122
69
 
123
70
  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>;
71
+ sheetRef: React.RefObject<HTMLElement | null>;
72
+ handleRef: React.RefObject<HTMLElement | null>;
73
+ contentRef: React.RefObject<HTMLElement | null>;
74
+ backdropRef: React.RefObject<HTMLElement | null>;
75
+ screenRef: React.RefObject<HTMLElement | null>;
129
76
  };
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
77
  type UseBottomSheetReturn<TId extends string = string> = UseBottomSheetRefs & {
142
78
  state: EngineState & {
143
79
  activeId: TId;
@@ -146,43 +82,21 @@ type UseBottomSheetReturn<TId extends string = string> = UseBottomSheetRefs & {
146
82
  open: (id?: TId) => Promise<void>;
147
83
  close: () => Promise<void>;
148
84
  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
- */
85
+ addAnchor: (opts: AnchorOptions) => () => void;
86
+ setScrimStages: (opts: ScrimStagesOptions | null) => () => void;
158
87
  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
88
  getEngine: () => BottomSheetEngine | null;
164
89
  };
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"> & {
90
+ type HookOpts<TId extends string> = Omit<EngineOptions, "element" | "handle" | "scrollContainer" | "backdrop" | "scrim" | "snapPoints" | "allowed" | "initial"> & {
174
91
  snapPoints: SnapPointDef<TId>[] | ReadonlyArray<SnapPointDef<TId>>;
175
92
  allowed?: TId[] | ReadonlyArray<TId>;
176
93
  initial?: TId;
177
- /** Called after a snap commit settles. Mirrors the engine's `snap` event. */
178
94
  onSnap?: (id: TId) => void;
179
95
  };
180
96
  declare function useBottomSheet<TId extends string = string>(opts: HookOpts<TId>): UseBottomSheetReturn<TId>;
181
97
 
182
98
  type OverlayProps = Omit<OverlayOptions, "element" | "backdrop"> & {
183
- /** Controlled open state. If omitted, the overlay is uncontrolled. */
184
99
  open?: boolean;
185
- /** Render the backdrop. Default: true. */
186
100
  backdrop?: boolean;
187
101
  className?: string;
188
102
  style?: CSSProperties;
@@ -197,15 +111,8 @@ type OverlayHandle = {
197
111
  toggle: () => Promise<void>;
198
112
  state: OverlayState;
199
113
  };
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. */
114
+ declare const Overlay: react.ForwardRefExoticComponent<Omit<OverlayOptions, "backdrop" | "element"> & {
207
115
  open?: boolean;
208
- /** Render the backdrop. Default: true. */
209
116
  backdrop?: boolean;
210
117
  className?: string;
211
118
  style?: CSSProperties;
@@ -216,52 +123,31 @@ declare const Overlay: react.ForwardRefExoticComponent<Omit<OverlayOptions, "ele
216
123
  } & react.RefAttributes<OverlayHandle>>;
217
124
 
218
125
  type UseOverlayReturn = {
219
- panelRef: React.RefObject<HTMLElement>;
220
- backdropRef: React.RefObject<HTMLElement>;
126
+ panelRef: React.RefObject<HTMLElement | null>;
127
+ backdropRef: React.RefObject<HTMLElement | null>;
221
128
  state: OverlayState;
222
129
  open: () => Promise<void>;
223
130
  close: () => Promise<void>;
224
131
  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
132
  getEngine: () => OverlayEngine | null;
231
133
  };
232
134
  declare const useOverlay: (opts: Omit<OverlayOptions, "element" | "backdrop">) => UseOverlayReturn;
233
135
 
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
136
  type SheetConfig = {
243
- /** Schema version. Must be `1` for the current wrapper. */
244
137
  version: 1;
245
- /** Ordered list of snap points (smallest → largest). Required. */
246
138
  snapPoints: Array<{
247
139
  id: string;
248
140
  size: number | string;
249
141
  }>;
250
- /** Initial snap id. Falls back to first allowed (or first overall). */
251
142
  initial?: string;
252
- /** Subset of snap-point ids the sheet may settle on right now. */
253
143
  allowed?: string[];
254
- /** Direction the sheet expands from. Default: "bottom". */
255
144
  mode?: SheetMode;
256
- /** Animation strategy. Default: "spring". */
257
145
  animation?: "spring" | "tween";
258
- /** Spring config when `animation: "spring"`. */
259
146
  spring?: {
260
147
  stiffness?: number;
261
148
  damping?: number;
262
149
  mass?: number;
263
150
  };
264
- /** Behavior toggles. All optional; missing keys fall back to engine defaults. */
265
151
  behavior?: {
266
152
  focusTrap?: boolean;
267
153
  closeOnEscape?: boolean;
@@ -269,11 +155,6 @@ type SheetConfig = {
269
155
  lockBodyScroll?: boolean;
270
156
  rubberBand?: boolean;
271
157
  };
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
158
  events?: {
278
159
  onSnap?: string;
279
160
  onOpen?: string;
@@ -288,12 +169,6 @@ type BottomSheetFromConfigProps = {
288
169
  header?: ReactNode;
289
170
  body?: ReactNode;
290
171
  };
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
172
  stableContent?: boolean;
298
173
  };
299
174
  declare const BottomSheetFromConfig: react.ForwardRefExoticComponent<BottomSheetFromConfigProps & react.RefAttributes<BottomSheetHandle>>;