@surdeddd/bottom-sheet 0.11.0 → 0.13.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 (58) hide show
  1. package/README.md +68 -1
  2. package/dist/{BottomSheetEngine-DzsIwD28.d.cts → BottomSheetCore-CsIjyq7C.d.cts} +61 -5
  3. package/dist/{BottomSheetEngine-DRjCU73e.d.ts → BottomSheetCore-D16lsa6g.d.ts} +61 -5
  4. package/dist/BottomSheetEngine-BYjAVrmd.d.cts +7 -0
  5. package/dist/BottomSheetEngine-YuCNugZn.d.ts +7 -0
  6. package/dist/core.cjs +3476 -0
  7. package/dist/core.d.cts +3 -0
  8. package/dist/core.d.ts +3 -0
  9. package/dist/core.js +3474 -0
  10. package/dist/debug.cjs +109 -0
  11. package/dist/debug.d.cts +22 -0
  12. package/dist/debug.d.ts +22 -0
  13. package/dist/debug.js +107 -0
  14. package/dist/element.cjs +994 -697
  15. package/dist/element.d.cts +2 -1
  16. package/dist/element.d.ts +2 -1
  17. package/dist/element.iife.global.js +2 -2
  18. package/dist/element.js +994 -697
  19. package/dist/features.cjs +533 -0
  20. package/dist/features.d.cts +13 -0
  21. package/dist/features.d.ts +13 -0
  22. package/dist/features.js +526 -0
  23. package/dist/index-DdYLOIIT.d.ts +15 -0
  24. package/dist/index-dfrzw-lI.d.cts +15 -0
  25. package/dist/index.cjs +823 -542
  26. package/dist/index.d.cts +6 -15
  27. package/dist/index.d.ts +6 -15
  28. package/dist/index.js +817 -543
  29. package/dist/integrations/formik.d.cts +1 -1
  30. package/dist/integrations/formik.d.ts +1 -1
  31. package/dist/integrations/react-hook-form.d.cts +1 -1
  32. package/dist/integrations/react-hook-form.d.ts +1 -1
  33. package/dist/overlay.cjs +13 -8
  34. package/dist/overlay.js +13 -8
  35. package/dist/preact.d.cts +2 -1
  36. package/dist/preact.d.ts +2 -1
  37. package/dist/qwik-lib/index.qwik.cjs +4267 -0
  38. package/dist/qwik-lib/index.qwik.mjs +4267 -0
  39. package/dist/qwik.cjs +816 -542
  40. package/dist/qwik.d.cts +2 -2
  41. package/dist/qwik.d.ts +2 -2
  42. package/dist/qwik.js +816 -542
  43. package/dist/react.cjs +816 -542
  44. package/dist/react.d.cts +3 -2
  45. package/dist/react.d.ts +3 -2
  46. package/dist/react.js +816 -542
  47. package/dist/solid.cjs +816 -542
  48. package/dist/solid.d.cts +64 -4
  49. package/dist/solid.d.ts +64 -4
  50. package/dist/solid.js +816 -542
  51. package/dist/solid.source.jsx +816 -542
  52. package/dist/svelte-core.cjs +816 -542
  53. package/dist/svelte-core.js +816 -542
  54. package/dist/svelte.cjs +816 -542
  55. package/dist/svelte.js +816 -542
  56. package/dist/vue.cjs +927 -645
  57. package/dist/vue.js +927 -645
  58. package/package.json +63 -11
package/README.md CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  > Universal, headless bottom-sheet engine. **One core, eight adapters, GPU-accelerated, fully tested.**
4
4
 
5
- ![bundle](https://img.shields.io/badge/core-%E2%89%A422.5%20KB%20gzip%20budget-1a1614?style=flat-square)
5
+ ![bundle](https://img.shields.io/badge/core-%E2%89%A424%20KB%20gzip%20budget-1a1614?style=flat-square)
6
+ ![slim](https://img.shields.io/badge/slim%20core-%E2%89%A419.5%20KB%20gzip-1a1614?style=flat-square)
6
7
  ![tests](https://img.shields.io/badge/tests-500%2B%20unit-2ea44f?style=flat-square)
7
8
  ![ts](https://img.shields.io/badge/TypeScript-strict-3178c6?style=flat-square&logo=typescript&logoColor=white)
8
9
  ![license](https://img.shields.io/badge/license-MIT-dc3522?style=flat-square)
@@ -13,6 +14,8 @@ stacking — and the exact same engine behind every adapter.
13
14
 
14
15
  ## 🚀 [Live demo → bottom-sheet-demo.vercel.app](https://bottom-sheet-demo.vercel.app)
15
16
 
17
+ 📚 [API reference (typedoc) → surdeddd.github.io/BottomSheet](https://surdeddd.github.io/BottomSheet/)
18
+
16
19
  <p align="center">
17
20
  <picture>
18
21
  <source media="(prefers-color-scheme: dark)" srcset="docs/screenshots/sheet-dark.png" />
@@ -226,6 +229,8 @@ type SnapPoint =
226
229
  | `initial` | first allowed | Snap id to start at |
227
230
  | `mode` | `"bottom"` | `bottom`, `top`, `left`, `right` |
228
231
  | `animation` | `"spring"` | `spring`, `tween`, `ios-spring`, `material-bounce`, `linear`, `snappy` |
232
+ | `settleAnimation` | off | `"waapi"` — settle runs as a compositor-driven Web Animation (pre-sampled spring keyframes); falls back to rAF automatically |
233
+ | `features` | all defaults | `EngineFeature[]` — override/extend the composable feature set (see Slim core below) |
229
234
  | `spring` | snappy | `{ stiffness, damping, mass }` |
230
235
  | `flickVelocity` | `0.65 px/ms` | Mobile flick threshold |
231
236
  | `dragThreshold` | `18 px` | Below this, drag snaps back |
@@ -317,6 +322,14 @@ engine.depth(); // open sheets above this one
317
322
  engine.destroy(); // remove listeners + cancel animation
318
323
  ```
319
324
 
325
+ `initial` starts the sheet **born open** at any snap whose size resolves `> 0`
326
+ (no `open` / `opened` event fires — there is no transition to announce). Calling
327
+ `open()` / `snapTo()` **synchronously in the mount tick is safe** — no
328
+ `requestAnimationFrame` / `nextTick` delay is needed, including `fit` / `content`
329
+ and teleported sheets. A sheet mounted hidden (`display:none` ancestor) heals
330
+ and emits its open sequence once on reveal. See
331
+ [Architecture → Opening at construction](docs/ARCHITECTURE.md).
332
+
320
333
  ### Scrim runtime API
321
334
 
322
335
  The scrim is the dim layer behind/around the sheet (`screenComponent`). All
@@ -380,6 +393,52 @@ Three deliberate choices keep things 60 fps even on mid-range Android:
380
393
  propagate via CSS variables (`--bs-progress`, `--bs-size`) and direct
381
394
  imperative subscriptions — no React re-renders on every frame.
382
395
 
396
+ ## Slim core & composable features
397
+
398
+ The default `BottomSheetEngine` ships every optional behavior preinstalled.
399
+ If you only need the essentials, import the slim core (~17.5 KB gzip vs
400
+ ~23 KB) and register just the features you use:
401
+
402
+ ```ts
403
+ import { BottomSheetCore } from '@surdeddd/bottom-sheet/core';
404
+ import { routeFeature, contentSwipeFeature } from '@surdeddd/bottom-sheet/features';
405
+
406
+ const engine = new BottomSheetCore({
407
+ element, handle, snapPoints,
408
+ closeOnBack: true,
409
+ features: [routeFeature(), contentSwipeFeature()],
410
+ });
411
+ ```
412
+
413
+ Optional features: `routeFeature()` (`closeOnBack` / `routedTo` /
414
+ `closeOnRouteChange`), `visualViewportFeature()` (soft-keyboard clamp),
415
+ `contentSwipeFeature()`, `persistFeature()`, `autoCollapseFeature()`.
416
+ Everything else (gestures, snap math, resize self-heal, a11y slider, focus
417
+ trap, scroll lock, scrim, stacking) is core. Setting an option whose feature
418
+ is missing dev-warns once and is ignored in production. Custom features
419
+ implement `{ name, install(ctx) }` — the same seam the built-ins use.
420
+
421
+ ### Debug overlay
422
+
423
+ ```ts
424
+ import { attachDebugOverlay } from '@surdeddd/bottom-sheet/debug';
425
+
426
+ const detach = attachDebugOverlay(engine);
427
+ ```
428
+
429
+ A fixed dev panel showing the active snap, live size/progress, drag/animate
430
+ flags and the resolved snap list — driven purely by public engine events,
431
+ shipped as its own entry so it costs nothing in app bundles.
432
+
433
+ ### Qwik SSR
434
+
435
+ The package declares a `qwik` field pointing at
436
+ `dist/qwik-lib/index.qwik.mjs`. Qwik apps pick the adapter up automatically
437
+ as a vendor root: the consumer optimizer segments it into QRL chunks and
438
+ `renderToString` emits a resumable (`q:container="paused"`) sheet. No extra
439
+ configuration — `import { BottomSheet } from '@surdeddd/bottom-sheet/qwik'`
440
+ keeps working for CSR, and Qwik City SSR now works out of the box.
441
+
383
442
  ## Theming
384
443
 
385
444
  All visuals are driven by CSS custom properties. Override anywhere:
@@ -408,6 +467,14 @@ element — drive any CSS animation from drag without touching JS:
408
467
  }
409
468
  ```
410
469
 
470
+ > **z-index is engine-owned.** The stack controller rewrites inline `z-index` on
471
+ > `.bs-sheet`, `.bs-backdrop` and anchor wrappers on every stack change (base
472
+ > `100`, step `10` per depth), so a value you set is overwritten and races the
473
+ > stack. To position the sheet layer against app UI, move the container
474
+ > (teleport target / `.bs-root` parent) or change the open order — don't style
475
+ > `z-index` on bs-managed elements. See
476
+ > [Architecture → z-index & the sheet stack](docs/ARCHITECTURE.md).
477
+
411
478
  ### Scrim, blur & high contrast
412
479
 
413
480
  | Token | Default | Region |
@@ -103,6 +103,7 @@ type EngineOptions = {
103
103
  scrimTapToClose?: boolean;
104
104
  scrimPreset?: ScrimPreset;
105
105
  animation?: "spring" | "tween" | "ios-spring" | "material-bounce" | "linear" | "snappy";
106
+ settleAnimation?: "waapi";
106
107
  spring?: {
107
108
  stiffness?: number;
108
109
  damping?: number;
@@ -127,15 +128,64 @@ type EngineOptions = {
127
128
  linkedSheets?: BottomSheetEngineLike[];
128
129
  viewTransitions?: boolean;
129
130
  stackEffect?: boolean;
131
+ features?: EngineFeature[];
130
132
  };
131
133
 
132
- type BottomSheetEngineLike = BottomSheetEngine;
134
+ type BottomSheetEngineLike = BottomSheetCore;
135
+ type EngineFeatureStage = "attach" | "post";
136
+ type EngineFeatureOptions = {
137
+ routedTo?: string;
138
+ closeOnBack: boolean;
139
+ closeOnRouteChange: boolean;
140
+ persistKey?: string;
141
+ autoCollapseAfter?: number;
142
+ };
143
+ type EngineFeatureContext = {
144
+ element: HTMLElement;
145
+ scrollContainer?: HTMLElement;
146
+ sheetId: string;
147
+ options: EngineFeatureOptions;
148
+ isDestroyed: () => boolean;
149
+ isDragging: () => boolean;
150
+ isAnimating: () => boolean;
151
+ isTopSheet: () => boolean;
152
+ isVerticalAxis: () => boolean;
153
+ getSize: () => number;
154
+ getActiveId: () => string;
155
+ getAllowedIds: () => string[];
156
+ allowedIdsBySize: () => string[];
157
+ getMaxAxisSize: () => number;
158
+ resolveSnap: (id: string) => {
159
+ id: string;
160
+ size: number;
161
+ } | null;
162
+ resolveActiveSnap: () => {
163
+ id: string;
164
+ size: number;
165
+ } | null;
166
+ setSize: (size: number) => void;
167
+ setMaxAxisSize: (size: number) => void;
168
+ applySize: (size: number) => void;
169
+ recomputeSnaps: () => void;
170
+ newCycle: () => void;
171
+ cancelInFlight: () => void;
172
+ resyncAfterResize: () => void;
173
+ snapTo: (id: string) => void;
174
+ close: (reason?: CloseReason) => Promise<void>;
175
+ on: <K extends keyof SheetEventMap>(event: K, fn: (payload: SheetEventMap[K]) => void) => () => void;
176
+ addTeardown: (fn: (() => void) | null | undefined) => void;
177
+ };
178
+ type EngineFeature = {
179
+ name: string;
180
+ stage?: EngineFeatureStage;
181
+ install: (ctx: EngineFeatureContext) => (() => void) | void;
182
+ };
133
183
  type TeardownScope = {
134
184
  add: (fn: (() => void) | null | undefined) => void;
135
185
  };
136
186
  type Plugin = {
137
187
  name: string;
138
- install: (engine: BottomSheetEngine, scope: TeardownScope) => void | (() => void);
188
+ install: (engine: BottomSheetCore, scope: TeardownScope) => void | (() => void);
139
189
  };
140
190
  type EngineState = {
141
191
  size: number;
@@ -200,7 +250,7 @@ type ScrimStagesOptions = {
200
250
  };
201
251
 
202
252
  type Listener<K extends keyof SheetEventMap> = (payload: SheetEventMap[K]) => void;
203
- declare class BottomSheetEngine {
253
+ declare class BottomSheetCore {
204
254
  private id;
205
255
  private element;
206
256
  private handle;
@@ -252,11 +302,16 @@ declare class BottomSheetEngine {
252
302
  private stackEffectPrimed;
253
303
  private fitDeps;
254
304
  private transformTemplate;
305
+ private featureList;
306
+ private featureCtx;
255
307
  constructor(opts: EngineOptions);
308
+ private buildFeatureContext;
309
+ private runFeatureStage;
310
+ private warnOrphanFeatureOptions;
256
311
  get state(): EngineState;
257
312
  on<K extends keyof SheetEventMap>(event: K, fn: Listener<K>): () => void;
258
313
  use(plugin: Plugin): this;
259
- setLinkedSheets(sheets: BottomSheetEngine[]): void;
314
+ setLinkedSheets(sheets: BottomSheetCore[]): void;
260
315
  getAllowedIds(): string[];
261
316
  getResolvedSnaps(): readonly {
262
317
  id: string;
@@ -304,6 +359,7 @@ declare class BottomSheetEngine {
304
359
  };
305
360
  setSnapPoints(points: EngineOptions["snapPoints"], allowed?: string[]): void;
306
361
  recompute(): void;
362
+ private healActiveSnap;
307
363
  destroy(): void;
308
364
  private emit;
309
365
  private newCycle;
@@ -329,4 +385,4 @@ declare class BottomSheetEngine {
329
385
  private handleClose;
330
386
  }
331
387
 
332
- export { type AnchorOptions as A, BottomSheetEngine as B, type CloseReason as C, type EngineState as E, type Plugin as P, type ScrimStagesOptions as S, type TeardownScope as T, type SnapPointDef as a, type SheetMode as b, type EngineOptions as c, type SheetEventMap as d, type SnapPoint as e, type ScrimOverlayPosition as f, type AnchorAnimationPreset as g, type AnchorAnimationSpec as h, type AnchorHandle as i, type AnchorPosition as j, type AnchorState as k, SCRIM_PRESETS as l, type ScrimOverlayOptions as m, type ScrimPreset as n, type ScrimPresetConfig as o, type ScrimStageDef as p, type ScrimUpdate as q, type SnapId as r, runAnchorTransition as s };
388
+ export { type AnchorOptions as A, BottomSheetCore as B, type CloseReason as C, type EngineState as E, type Plugin as P, type ScrimStagesOptions as S, type TeardownScope as T, type EngineOptions as a, type SnapPointDef as b, type SheetMode as c, type SheetEventMap as d, type SnapPoint as e, type ScrimOverlayPosition as f, type AnchorAnimationPreset as g, type AnchorAnimationSpec as h, type AnchorHandle as i, type AnchorPosition as j, type AnchorState as k, type EngineFeature as l, type EngineFeatureContext as m, type EngineFeatureOptions as n, type EngineFeatureStage as o, SCRIM_PRESETS as p, type ScrimOverlayOptions as q, type ScrimPreset as r, type ScrimPresetConfig as s, type ScrimStageDef as t, type ScrimUpdate as u, type SnapId as v, runAnchorTransition as w };
@@ -103,6 +103,7 @@ type EngineOptions = {
103
103
  scrimTapToClose?: boolean;
104
104
  scrimPreset?: ScrimPreset;
105
105
  animation?: "spring" | "tween" | "ios-spring" | "material-bounce" | "linear" | "snappy";
106
+ settleAnimation?: "waapi";
106
107
  spring?: {
107
108
  stiffness?: number;
108
109
  damping?: number;
@@ -127,15 +128,64 @@ type EngineOptions = {
127
128
  linkedSheets?: BottomSheetEngineLike[];
128
129
  viewTransitions?: boolean;
129
130
  stackEffect?: boolean;
131
+ features?: EngineFeature[];
130
132
  };
131
133
 
132
- type BottomSheetEngineLike = BottomSheetEngine;
134
+ type BottomSheetEngineLike = BottomSheetCore;
135
+ type EngineFeatureStage = "attach" | "post";
136
+ type EngineFeatureOptions = {
137
+ routedTo?: string;
138
+ closeOnBack: boolean;
139
+ closeOnRouteChange: boolean;
140
+ persistKey?: string;
141
+ autoCollapseAfter?: number;
142
+ };
143
+ type EngineFeatureContext = {
144
+ element: HTMLElement;
145
+ scrollContainer?: HTMLElement;
146
+ sheetId: string;
147
+ options: EngineFeatureOptions;
148
+ isDestroyed: () => boolean;
149
+ isDragging: () => boolean;
150
+ isAnimating: () => boolean;
151
+ isTopSheet: () => boolean;
152
+ isVerticalAxis: () => boolean;
153
+ getSize: () => number;
154
+ getActiveId: () => string;
155
+ getAllowedIds: () => string[];
156
+ allowedIdsBySize: () => string[];
157
+ getMaxAxisSize: () => number;
158
+ resolveSnap: (id: string) => {
159
+ id: string;
160
+ size: number;
161
+ } | null;
162
+ resolveActiveSnap: () => {
163
+ id: string;
164
+ size: number;
165
+ } | null;
166
+ setSize: (size: number) => void;
167
+ setMaxAxisSize: (size: number) => void;
168
+ applySize: (size: number) => void;
169
+ recomputeSnaps: () => void;
170
+ newCycle: () => void;
171
+ cancelInFlight: () => void;
172
+ resyncAfterResize: () => void;
173
+ snapTo: (id: string) => void;
174
+ close: (reason?: CloseReason) => Promise<void>;
175
+ on: <K extends keyof SheetEventMap>(event: K, fn: (payload: SheetEventMap[K]) => void) => () => void;
176
+ addTeardown: (fn: (() => void) | null | undefined) => void;
177
+ };
178
+ type EngineFeature = {
179
+ name: string;
180
+ stage?: EngineFeatureStage;
181
+ install: (ctx: EngineFeatureContext) => (() => void) | void;
182
+ };
133
183
  type TeardownScope = {
134
184
  add: (fn: (() => void) | null | undefined) => void;
135
185
  };
136
186
  type Plugin = {
137
187
  name: string;
138
- install: (engine: BottomSheetEngine, scope: TeardownScope) => void | (() => void);
188
+ install: (engine: BottomSheetCore, scope: TeardownScope) => void | (() => void);
139
189
  };
140
190
  type EngineState = {
141
191
  size: number;
@@ -200,7 +250,7 @@ type ScrimStagesOptions = {
200
250
  };
201
251
 
202
252
  type Listener<K extends keyof SheetEventMap> = (payload: SheetEventMap[K]) => void;
203
- declare class BottomSheetEngine {
253
+ declare class BottomSheetCore {
204
254
  private id;
205
255
  private element;
206
256
  private handle;
@@ -252,11 +302,16 @@ declare class BottomSheetEngine {
252
302
  private stackEffectPrimed;
253
303
  private fitDeps;
254
304
  private transformTemplate;
305
+ private featureList;
306
+ private featureCtx;
255
307
  constructor(opts: EngineOptions);
308
+ private buildFeatureContext;
309
+ private runFeatureStage;
310
+ private warnOrphanFeatureOptions;
256
311
  get state(): EngineState;
257
312
  on<K extends keyof SheetEventMap>(event: K, fn: Listener<K>): () => void;
258
313
  use(plugin: Plugin): this;
259
- setLinkedSheets(sheets: BottomSheetEngine[]): void;
314
+ setLinkedSheets(sheets: BottomSheetCore[]): void;
260
315
  getAllowedIds(): string[];
261
316
  getResolvedSnaps(): readonly {
262
317
  id: string;
@@ -304,6 +359,7 @@ declare class BottomSheetEngine {
304
359
  };
305
360
  setSnapPoints(points: EngineOptions["snapPoints"], allowed?: string[]): void;
306
361
  recompute(): void;
362
+ private healActiveSnap;
307
363
  destroy(): void;
308
364
  private emit;
309
365
  private newCycle;
@@ -329,4 +385,4 @@ declare class BottomSheetEngine {
329
385
  private handleClose;
330
386
  }
331
387
 
332
- export { type AnchorOptions as A, BottomSheetEngine as B, type CloseReason as C, type EngineState as E, type Plugin as P, type ScrimStagesOptions as S, type TeardownScope as T, type SnapPointDef as a, type SheetMode as b, type EngineOptions as c, type SheetEventMap as d, type SnapPoint as e, type ScrimOverlayPosition as f, type AnchorAnimationPreset as g, type AnchorAnimationSpec as h, type AnchorHandle as i, type AnchorPosition as j, type AnchorState as k, SCRIM_PRESETS as l, type ScrimOverlayOptions as m, type ScrimPreset as n, type ScrimPresetConfig as o, type ScrimStageDef as p, type ScrimUpdate as q, type SnapId as r, runAnchorTransition as s };
388
+ export { type AnchorOptions as A, BottomSheetCore as B, type CloseReason as C, type EngineState as E, type Plugin as P, type ScrimStagesOptions as S, type TeardownScope as T, type EngineOptions as a, type SnapPointDef as b, type SheetMode as c, type SheetEventMap as d, type SnapPoint as e, type ScrimOverlayPosition as f, type AnchorAnimationPreset as g, type AnchorAnimationSpec as h, type AnchorHandle as i, type AnchorPosition as j, type AnchorState as k, type EngineFeature as l, type EngineFeatureContext as m, type EngineFeatureOptions as n, type EngineFeatureStage as o, SCRIM_PRESETS as p, type ScrimOverlayOptions as q, type ScrimPreset as r, type ScrimPresetConfig as s, type ScrimStageDef as t, type ScrimUpdate as u, type SnapId as v, runAnchorTransition as w };
@@ -0,0 +1,7 @@
1
+ import { B as BottomSheetCore, a as EngineOptions } from './BottomSheetCore-CsIjyq7C.cjs';
2
+
3
+ declare class BottomSheetEngine extends BottomSheetCore {
4
+ constructor(opts: EngineOptions);
5
+ }
6
+
7
+ export { BottomSheetEngine as B };
@@ -0,0 +1,7 @@
1
+ import { B as BottomSheetCore, a as EngineOptions } from './BottomSheetCore-D16lsa6g.js';
2
+
3
+ declare class BottomSheetEngine extends BottomSheetCore {
4
+ constructor(opts: EngineOptions);
5
+ }
6
+
7
+ export { BottomSheetEngine as B };