@surdeddd/bottom-sheet 0.2.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 (49) hide show
  1. package/README.md +51 -21
  2. package/dist/{BottomSheetEngine-CIT9Htti.d.cts → BottomSheetEngine-CAymrH-P.d.cts} +67 -1
  3. package/dist/{BottomSheetEngine-Df9MwBbm.d.ts → BottomSheetEngine-DcqcuudN.d.ts} +67 -1
  4. package/dist/element.cjs +699 -116
  5. package/dist/element.d.cts +7 -2
  6. package/dist/element.d.ts +7 -2
  7. package/dist/element.iife.global.js +2 -2
  8. package/dist/element.js +699 -116
  9. package/dist/index.cjs +715 -145
  10. package/dist/index.d.cts +17 -3
  11. package/dist/index.d.ts +17 -3
  12. package/dist/index.js +713 -146
  13. package/dist/integrations/formik.d.cts +1 -1
  14. package/dist/integrations/formik.d.ts +1 -1
  15. package/dist/integrations/react-hook-form.d.cts +1 -1
  16. package/dist/integrations/react-hook-form.d.ts +1 -1
  17. package/dist/overlay.cjs +168 -35
  18. package/dist/overlay.d.cts +13 -0
  19. package/dist/overlay.d.ts +13 -0
  20. package/dist/overlay.js +168 -35
  21. package/dist/preact.d.cts +1 -1
  22. package/dist/preact.d.ts +1 -1
  23. package/dist/qwik.cjs +619 -119
  24. package/dist/qwik.d.cts +2 -2
  25. package/dist/qwik.d.ts +2 -2
  26. package/dist/qwik.js +620 -120
  27. package/dist/react.cjs +821 -191
  28. package/dist/react.d.cts +20 -3
  29. package/dist/react.d.ts +20 -3
  30. package/dist/react.js +821 -191
  31. package/dist/solid.cjs +656 -161
  32. package/dist/solid.d.cts +263 -4
  33. package/dist/solid.d.ts +263 -4
  34. package/dist/solid.js +657 -162
  35. package/dist/solid.source.jsx +3215 -0
  36. package/dist/styles.css +10 -10
  37. package/dist/svelte-core.cjs +3149 -0
  38. package/dist/svelte-core.js +3147 -0
  39. package/dist/svelte-src/BottomSheet.svelte +210 -0
  40. package/dist/svelte-src/index.js +2 -0
  41. package/dist/svelte.cjs +618 -124
  42. package/dist/svelte.d.cts +100 -0
  43. package/dist/svelte.d.ts +7 -3
  44. package/dist/svelte.js +619 -125
  45. package/dist/vue.cjs +612 -119
  46. package/dist/vue.d.cts +78 -0
  47. package/dist/vue.d.ts +6 -2
  48. package/dist/vue.js +612 -119
  49. package/package.json +103 -43
package/README.md CHANGED
@@ -2,8 +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-15.8%20KB%20gzip-1a1614?style=flat-square)
6
- ![tests](https://img.shields.io/badge/tests-327%20unit-2ea44f?style=flat-square)
5
+ ![bundle](https://img.shields.io/badge/core-16.8%20KB%20gzip-1a1614?style=flat-square)
6
+ ![tests](https://img.shields.io/badge/tests-392%20unit-2ea44f?style=flat-square)
7
7
  ![ts](https://img.shields.io/badge/TypeScript-strict-3178c6?style=flat-square&logo=typescript&logoColor=white)
8
8
  ![license](https://img.shields.io/badge/license-MIT-dc3522?style=flat-square)
9
9
 
@@ -47,7 +47,7 @@ stacking — and the exact same engine behind every adapter.
47
47
  | WCAG 2.1 AA keyboard slider | partial | — | **✓** |
48
48
  | Multi-sheet stacking | — | — | **✓** |
49
49
  | Sheet-manager registry (typed) | — | — | **✓** |
50
- | Tests (unit + e2e) | partial | partial | **253 + 32** |
50
+ | Tests (unit + e2e) | partial | partial | **392 + 164** |
51
51
 
52
52
  ## Install
53
53
 
@@ -170,7 +170,7 @@ Drop-in usage from a static HTML page. The IIFE bundle registers
170
170
  rel="stylesheet"
171
171
  href="https://unpkg.com/@surdeddd/bottom-sheet/dist/styles.css"
172
172
  />
173
- <script src="https://unpkg.com/@surdeddd/bottom-sheet/dist/element.iife.js"></script>
173
+ <script src="https://unpkg.com/@surdeddd/bottom-sheet/dist/element.iife.global.js"></script>
174
174
  <bottom-sheet
175
175
  snap-points='[{"id":"min","size":96},{"id":"full","size":"85%"}]'
176
176
  initial="min"
@@ -217,23 +217,53 @@ type SnapPoint =
217
217
 
218
218
  ### Engine options
219
219
 
220
- | Option | Default | What it does |
221
- | ---------------- | ------------- | -------------------------------------------------- |
222
- | `snapPoints` | required | Ordered list of `{ id, size }` |
223
- | `allowed` | all ids | Subset the sheet may settle on right now |
224
- | `initial` | first allowed | Snap id to start at |
225
- | `mode` | `"bottom"` | `bottom \| top \| left \| right` |
226
- | `animation` | `"spring"` | `spring \| tween` |
227
- | `spring` | snappy | `{ stiffness, damping, mass }` |
228
- | `flickVelocity` | `0.65 px/ms` | Mobile flick threshold |
229
- | `dragThreshold` | `18 px` | Below this, drag snaps back |
230
- | `rubberBand` | `true` | iOS-style soft over-drag |
231
- | `backdropRange` | `[0, 1]` | Progress range over which backdrop fades |
232
- | `focusTrap` | `false` | Trap Tab focus inside the sheet when open |
233
- | `closeOnEscape` | `true` | Listen for Escape and close |
234
- | `closeOnBack` | `false` | Intercept Android back button (history.popstate) |
235
- | `lockBodyScroll` | `true` | iOS-safe body lock (`position: fixed`) |
236
- | `inertSiblings` | `false` | Mark page siblings `inert` while open (full modal) |
220
+ | Option | Default | What it does |
221
+ | ---------------- | ------------- | ---------------------------------------------------------------------- |
222
+ | `snapPoints` | required | Ordered list of `{ id, size }` |
223
+ | `allowed` | all ids | Subset the sheet may settle on right now |
224
+ | `initial` | first allowed | Snap id to start at |
225
+ | `mode` | `"bottom"` | `bottom`, `top`, `left`, `right` |
226
+ | `animation` | `"spring"` | `spring`, `tween`, `ios-spring`, `material-bounce`, `linear`, `snappy` |
227
+ | `spring` | snappy | `{ stiffness, damping, mass }` |
228
+ | `flickVelocity` | `0.65 px/ms` | Mobile flick threshold |
229
+ | `dragThreshold` | `18 px` | Below this, drag snaps back |
230
+ | `rubberBand` | `true` | iOS-style soft over-drag |
231
+ | `backdropRange` | `[0, 1]` | Progress range over which backdrop fades |
232
+ | `focusTrap` | `false` | Trap Tab focus inside the sheet when open |
233
+ | `closeOnEscape` | `true` | Listen for Escape and close |
234
+ | `closeOnBack` | `false` | Intercept Android back button (history.popstate) |
235
+ | `lockBodyScroll` | `true` | iOS-safe body lock (`position: fixed`) |
236
+ | `stackEffect` | `false` | iOS card-stack: back sheets scale down per depth |
237
+ | `inertSiblings` | `false` | Mark page siblings `inert` while open (full modal) |
238
+
239
+ ### Anchored elements, docked bars & scrim stages
240
+
241
+ Pin UI around the sheet — it rides the motion on the compositor (zero JS per
242
+ frame) and shows/hides per state with configurable animations:
243
+
244
+ ```ts
245
+ engine.addAnchor({
246
+ element: closeBtn,
247
+ position: 'sheet-top-right', // rides the sheet edge; 9 screen positions too
248
+ showOn: ['half', 'full'], // snap ids or a predicate
249
+ animation: 'pop', // fade | scale | slide | pop | custom keyframes
250
+ });
251
+
252
+ engine.addAnchor({
253
+ element: tabBar,
254
+ position: 'dock-bottom', // full-width bar; the sheet slides under it
255
+ });
256
+
257
+ engine.setScrimStages({
258
+ stages: [
259
+ { for: 'peek', element: teaser },
260
+ { forRange: [0.5, 1], element: expanded },
261
+ ],
262
+ animation: 'fade',
263
+ });
264
+ ```
265
+
266
+ [Full anchors & stages docs →](docs/anchors.md)
237
267
 
238
268
  ### Events
239
269
 
@@ -109,6 +109,7 @@ type EngineOptions = {
109
109
  autoCollapseAfter?: number;
110
110
  linkedSheets?: BottomSheetEngineLike[];
111
111
  viewTransitions?: boolean;
112
+ stackEffect?: boolean;
112
113
  };
113
114
 
114
115
  type BottomSheetEngineLike = BottomSheetEngine;
@@ -127,6 +128,60 @@ type EngineState = {
127
128
  progress: number;
128
129
  };
129
130
 
131
+ type AnchorAnimationPreset = "fade" | "scale" | "slide" | "pop" | "none";
132
+ type AnchorAnimationSpec = AnchorAnimationPreset | {
133
+ preset?: AnchorAnimationPreset;
134
+ enter?: Keyframe[];
135
+ exit?: Keyframe[];
136
+ duration?: number;
137
+ easing?: string;
138
+ respectReducedMotion?: boolean;
139
+ };
140
+ type AnchorTransitionHandle = {
141
+ finished: Promise<void>;
142
+ cancel: () => void;
143
+ };
144
+ declare function runAnchorTransition(el: HTMLElement, spec: AnchorAnimationSpec | undefined, phase: "enter" | "exit"): AnchorTransitionHandle;
145
+
146
+ type AnchorState = {
147
+ activeId: string;
148
+ size: number;
149
+ progress: number;
150
+ };
151
+ type AnchorPosition = ScrimOverlayPosition | "dock-bottom" | "dock-top";
152
+ type AnchorOptions = {
153
+ element: HTMLElement;
154
+ position?: AnchorPosition;
155
+ inset?: string;
156
+ showOn?: string[] | ((state: AnchorState) => boolean);
157
+ fadeRange?: [number, number];
158
+ interactive?: boolean;
159
+ animation?: AnchorAnimationSpec;
160
+ };
161
+ type AnchorHandle = {
162
+ wrapper: HTMLElement;
163
+ detach: () => void;
164
+ syncZ: (z: number) => void;
165
+ };
166
+
167
+ type ScrimStageDef = {
168
+ id?: string;
169
+ for?: string | string[];
170
+ forRange?: [number, number];
171
+ element: HTMLElement;
172
+ position?: ScrimOverlayPosition;
173
+ inset?: string;
174
+ interactive?: boolean;
175
+ animation?: AnchorAnimationSpec;
176
+ };
177
+ type ScrimStagesOptions = {
178
+ stages: ScrimStageDef[];
179
+ position?: ScrimOverlayPosition;
180
+ inset?: string;
181
+ interactive?: boolean;
182
+ animation?: AnchorAnimationSpec;
183
+ };
184
+
130
185
  type Listener<K extends keyof SheetEventMap> = (payload: SheetEventMap[K]) => void;
131
186
  declare class BottomSheetEngine {
132
187
  private id;
@@ -165,6 +220,12 @@ declare class BottomSheetEngine {
165
220
  private linkedSheets;
166
221
  private scrollCache;
167
222
  private teardowns;
223
+ private anchors;
224
+ private anchorHost;
225
+ private stackZ;
226
+ private detachScrimStages;
227
+ private stackEffectEnabled;
228
+ private stackEffectPrimed;
168
229
  private transformTemplate;
169
230
  constructor(opts: EngineOptions);
170
231
  get state(): EngineState;
@@ -193,6 +254,8 @@ declare class BottomSheetEngine {
193
254
  setScrimTapToClose(enabled: boolean): void;
194
255
  setScrimEnabled(enabled: boolean): void;
195
256
  setScrimOverlay(opts: ScrimOverlayOptions): () => void;
257
+ addAnchor(opts: AnchorOptions): () => void;
258
+ setScrimStages(opts: ScrimStagesOptions | null): () => void;
196
259
  getScrimState(): {
197
260
  mode: "full" | "above-sheet" | "off";
198
261
  enabled: boolean;
@@ -204,8 +267,10 @@ declare class BottomSheetEngine {
204
267
  private emitBeforeSnap;
205
268
  private recomputeSnaps;
206
269
  private getAllowedRange;
270
+ private allowedIdsBySize;
207
271
  private updateAriaSlider;
208
272
  private registerInStack;
273
+ private applyStackDepth;
209
274
  private attach;
210
275
  private attachFeatures;
211
276
  private settleAfterDrag;
@@ -213,7 +278,8 @@ declare class BottomSheetEngine {
213
278
  private applySize;
214
279
  private computeProgress;
215
280
  private handleOpen;
281
+ private resyncAfterResize;
216
282
  private handleClose;
217
283
  }
218
284
 
219
- export { BottomSheetEngine as B, type EngineState as E, type Plugin as P, type SnapPointDef as S, type TeardownScope as T, type SheetMode as a, type EngineOptions as b, type SnapPoint as c, type SheetEventMap as d, SCRIM_PRESETS as e, type ScrimOverlayOptions as f, type ScrimOverlayPosition as g, type ScrimPreset as h, type ScrimPresetConfig as i, type ScrimUpdate as j, type SnapId as k };
285
+ export { type AnchorOptions as A, BottomSheetEngine as B, 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 SnapPoint as d, type SheetEventMap 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 };
@@ -109,6 +109,7 @@ type EngineOptions = {
109
109
  autoCollapseAfter?: number;
110
110
  linkedSheets?: BottomSheetEngineLike[];
111
111
  viewTransitions?: boolean;
112
+ stackEffect?: boolean;
112
113
  };
113
114
 
114
115
  type BottomSheetEngineLike = BottomSheetEngine;
@@ -127,6 +128,60 @@ type EngineState = {
127
128
  progress: number;
128
129
  };
129
130
 
131
+ type AnchorAnimationPreset = "fade" | "scale" | "slide" | "pop" | "none";
132
+ type AnchorAnimationSpec = AnchorAnimationPreset | {
133
+ preset?: AnchorAnimationPreset;
134
+ enter?: Keyframe[];
135
+ exit?: Keyframe[];
136
+ duration?: number;
137
+ easing?: string;
138
+ respectReducedMotion?: boolean;
139
+ };
140
+ type AnchorTransitionHandle = {
141
+ finished: Promise<void>;
142
+ cancel: () => void;
143
+ };
144
+ declare function runAnchorTransition(el: HTMLElement, spec: AnchorAnimationSpec | undefined, phase: "enter" | "exit"): AnchorTransitionHandle;
145
+
146
+ type AnchorState = {
147
+ activeId: string;
148
+ size: number;
149
+ progress: number;
150
+ };
151
+ type AnchorPosition = ScrimOverlayPosition | "dock-bottom" | "dock-top";
152
+ type AnchorOptions = {
153
+ element: HTMLElement;
154
+ position?: AnchorPosition;
155
+ inset?: string;
156
+ showOn?: string[] | ((state: AnchorState) => boolean);
157
+ fadeRange?: [number, number];
158
+ interactive?: boolean;
159
+ animation?: AnchorAnimationSpec;
160
+ };
161
+ type AnchorHandle = {
162
+ wrapper: HTMLElement;
163
+ detach: () => void;
164
+ syncZ: (z: number) => void;
165
+ };
166
+
167
+ type ScrimStageDef = {
168
+ id?: string;
169
+ for?: string | string[];
170
+ forRange?: [number, number];
171
+ element: HTMLElement;
172
+ position?: ScrimOverlayPosition;
173
+ inset?: string;
174
+ interactive?: boolean;
175
+ animation?: AnchorAnimationSpec;
176
+ };
177
+ type ScrimStagesOptions = {
178
+ stages: ScrimStageDef[];
179
+ position?: ScrimOverlayPosition;
180
+ inset?: string;
181
+ interactive?: boolean;
182
+ animation?: AnchorAnimationSpec;
183
+ };
184
+
130
185
  type Listener<K extends keyof SheetEventMap> = (payload: SheetEventMap[K]) => void;
131
186
  declare class BottomSheetEngine {
132
187
  private id;
@@ -165,6 +220,12 @@ declare class BottomSheetEngine {
165
220
  private linkedSheets;
166
221
  private scrollCache;
167
222
  private teardowns;
223
+ private anchors;
224
+ private anchorHost;
225
+ private stackZ;
226
+ private detachScrimStages;
227
+ private stackEffectEnabled;
228
+ private stackEffectPrimed;
168
229
  private transformTemplate;
169
230
  constructor(opts: EngineOptions);
170
231
  get state(): EngineState;
@@ -193,6 +254,8 @@ declare class BottomSheetEngine {
193
254
  setScrimTapToClose(enabled: boolean): void;
194
255
  setScrimEnabled(enabled: boolean): void;
195
256
  setScrimOverlay(opts: ScrimOverlayOptions): () => void;
257
+ addAnchor(opts: AnchorOptions): () => void;
258
+ setScrimStages(opts: ScrimStagesOptions | null): () => void;
196
259
  getScrimState(): {
197
260
  mode: "full" | "above-sheet" | "off";
198
261
  enabled: boolean;
@@ -204,8 +267,10 @@ declare class BottomSheetEngine {
204
267
  private emitBeforeSnap;
205
268
  private recomputeSnaps;
206
269
  private getAllowedRange;
270
+ private allowedIdsBySize;
207
271
  private updateAriaSlider;
208
272
  private registerInStack;
273
+ private applyStackDepth;
209
274
  private attach;
210
275
  private attachFeatures;
211
276
  private settleAfterDrag;
@@ -213,7 +278,8 @@ declare class BottomSheetEngine {
213
278
  private applySize;
214
279
  private computeProgress;
215
280
  private handleOpen;
281
+ private resyncAfterResize;
216
282
  private handleClose;
217
283
  }
218
284
 
219
- export { BottomSheetEngine as B, type EngineState as E, type Plugin as P, type SnapPointDef as S, type TeardownScope as T, type SheetMode as a, type EngineOptions as b, type SnapPoint as c, type SheetEventMap as d, SCRIM_PRESETS as e, type ScrimOverlayOptions as f, type ScrimOverlayPosition as g, type ScrimPreset as h, type ScrimPresetConfig as i, type ScrimUpdate as j, type SnapId as k };
285
+ export { type AnchorOptions as A, BottomSheetEngine as B, 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 SnapPoint as d, type SheetEventMap 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 };