@surdeddd/bottom-sheet 0.23.4 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +513 -527
- package/README.ru.md +533 -545
- package/dist/{BottomSheetCore-C5tJYVMY.d.cts → BottomSheetCore-B_r4KCQL.d.cts} +48 -13
- package/dist/{BottomSheetCore-DxSrC4QC.d.ts → BottomSheetCore-B_r4KCQL.d.ts} +48 -13
- package/dist/{BottomSheetEngine-B3F9qukX.d.cts → BottomSheetEngine-0F7mjyvF.d.cts} +1 -1
- package/dist/{BottomSheetEngine-BchzgqGG.d.ts → BottomSheetEngine-CJV_DDrM.d.ts} +1 -1
- package/dist/core.cjs +810 -436
- package/dist/core.d.cts +2 -3
- package/dist/core.d.ts +2 -3
- package/dist/core.js +810 -436
- package/dist/debug.d.cts +0 -1
- package/dist/debug.d.ts +0 -1
- package/dist/{default-features-DwVTzDwP.d.ts → default-features-4Xwv6aVt.d.ts} +4 -2
- package/dist/{default-features-BGiCSmV1.d.cts → default-features-DX2NOxP6.d.cts} +4 -2
- package/dist/element.cjs +1421 -697
- package/dist/element.d.cts +11 -3
- package/dist/element.d.ts +11 -3
- package/dist/element.iife.global.js +2 -2
- package/dist/element.js +1421 -697
- package/dist/features.cjs +334 -190
- package/dist/features.d.cts +3 -4
- package/dist/features.d.ts +3 -4
- package/dist/features.js +334 -191
- package/dist/{index-C7TSQkVK.d.cts → index-2shlxhcG.d.cts} +1 -1
- package/dist/{index-CdM1tke5.d.ts → index-CNCRQnpc.d.ts} +1 -1
- package/dist/index.cjs +1129 -631
- package/dist/index.d.cts +11 -6
- package/dist/index.d.ts +11 -6
- package/dist/index.js +1129 -632
- package/dist/integrations/formik.cjs +21 -10
- package/dist/integrations/formik.d.cts +0 -1
- package/dist/integrations/formik.d.ts +0 -1
- package/dist/integrations/formik.js +22 -11
- package/dist/integrations/react-hook-form.cjs +21 -12
- package/dist/integrations/react-hook-form.d.cts +0 -1
- package/dist/integrations/react-hook-form.d.ts +0 -1
- package/dist/integrations/react-hook-form.js +21 -12
- package/dist/option-keys-DItuAjUw.d.cts +6 -0
- package/dist/option-keys-a5DYNwwO.d.ts +6 -0
- package/dist/overlay.cjs +386 -189
- package/dist/overlay.d.cts +1 -3
- package/dist/overlay.d.ts +1 -3
- package/dist/overlay.js +386 -189
- package/dist/preact.d.cts +3 -4
- package/dist/preact.d.ts +3 -4
- package/dist/qwik-lib/index.qwik.cjs +1306 -671
- package/dist/qwik-lib/index.qwik.mjs +1306 -671
- package/dist/qwik.cjs +1326 -701
- package/dist/qwik.d.cts +12 -30
- package/dist/qwik.d.ts +12 -30
- package/dist/qwik.js +1326 -701
- package/dist/react.cjs +1373 -750
- package/dist/react.d.cts +26 -12
- package/dist/react.d.ts +26 -12
- package/dist/react.js +1375 -752
- package/dist/solid.cjs +1332 -727
- package/dist/solid.d.cts +13 -438
- package/dist/solid.d.ts +13 -438
- package/dist/solid.js +1334 -729
- package/dist/solid.source.jsx +1374 -751
- package/dist/styles.css +20 -6
- package/dist/svelte-core.cjs +1209 -676
- package/dist/svelte-core.js +1207 -677
- package/dist/svelte-src/BottomSheet.svelte +101 -58
- package/dist/svelte.cjs +1323 -705
- package/dist/svelte.d.cts +45 -25
- package/dist/svelte.d.ts +45 -25
- package/dist/svelte.js +1323 -705
- package/dist/vue.cjs +1354 -773
- package/dist/vue.d.cts +20 -3
- package/dist/vue.d.ts +20 -3
- package/dist/vue.js +1354 -773
- package/dist/webgl.cjs +159 -53
- package/dist/webgl.d.cts +2 -2
- package/dist/webgl.d.ts +2 -2
- package/dist/webgl.js +159 -53
- package/llms.txt +330 -0
- package/package.json +42 -20
- package/dist/transform-jVfAikE9.d.cts +0 -3
- package/dist/transform-jVfAikE9.d.ts +0 -3
package/llms.txt
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
# @surdeddd/bottom-sheet
|
|
2
|
+
|
|
3
|
+
> A bottom sheet, drawer and modal sheet for the web. One gesture engine with snap points, spring physics and keyboard accessibility, and the same engine behind adapters for React, Vue 3, Svelte 5, Solid, Qwik and Preact and behind a `<bottom-sheet>` custom element for Angular, Lit, Astro and plain HTML. MIT, TypeScript, no runtime dependencies.
|
|
4
|
+
|
|
5
|
+
Install: `npm i @surdeddd/bottom-sheet`. Frameworks are optional peer dependencies.
|
|
6
|
+
|
|
7
|
+
This file is a complete reference written for AI coding assistants. Every name below is real; do not invent options, props or events that are not listed here.
|
|
8
|
+
|
|
9
|
+
## Entry points
|
|
10
|
+
|
|
11
|
+
| Import | What it gives |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| `@surdeddd/bottom-sheet` | `BottomSheetEngine`, `BottomSheetCore`, `createSheetManager`, `historySettled`, types |
|
|
14
|
+
| `@surdeddd/bottom-sheet/react` | `BottomSheet`, `useBottomSheet`, `Overlay`, `useOverlay`, `BottomSheetFromConfig` |
|
|
15
|
+
| `@surdeddd/bottom-sheet/preact` | The React entry, for use with `preact/compat` |
|
|
16
|
+
| `@surdeddd/bottom-sheet/vue` | `BottomSheet`, `useBottomSheet` |
|
|
17
|
+
| `@surdeddd/bottom-sheet/svelte` | `BottomSheet`, `createBottomSheet` |
|
|
18
|
+
| `@surdeddd/bottom-sheet/solid` | `BottomSheet` |
|
|
19
|
+
| `@surdeddd/bottom-sheet/qwik` | `BottomSheet` |
|
|
20
|
+
| `@surdeddd/bottom-sheet/element` | Registers `<bottom-sheet>`; `BottomSheetElement`, `defineBottomSheet` |
|
|
21
|
+
| `@surdeddd/bottom-sheet/overlay` | `OverlayEngine`: a two-state slide-in panel without snap points |
|
|
22
|
+
| `@surdeddd/bottom-sheet/core` | `BottomSheetCore`: the engine without optional features |
|
|
23
|
+
| `@surdeddd/bottom-sheet/features` | `routeFeature`, `visualViewportFeature`, `contentSwipeFeature`, `contentFitFeature`, `persistFeature`, `autoCollapseFeature` |
|
|
24
|
+
| `@surdeddd/bottom-sheet/webgl` | `webglRenderer`: optional GPU renderer |
|
|
25
|
+
| `@surdeddd/bottom-sheet/debug` | `attachDebugOverlay(engine)` |
|
|
26
|
+
| `@surdeddd/bottom-sheet/integrations/react-hook-form` | `useFormGuard(sheetRef, form)` |
|
|
27
|
+
| `@surdeddd/bottom-sheet/integrations/formik` | `useFormikGuard(sheetRef, formikRef)` |
|
|
28
|
+
| `@surdeddd/bottom-sheet/styles` | The stylesheet. Required by everything except the custom element |
|
|
29
|
+
| `@surdeddd/bottom-sheet/themes/ios`, `/themes/material`, `/themes/vercel` | Optional themes; classes `bs-theme-ios`, `bs-theme-material`, `bs-theme-vercel` on an ancestor |
|
|
30
|
+
|
|
31
|
+
## The canonical example
|
|
32
|
+
|
|
33
|
+
A modal sheet opened by a button, in React:
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { useState } from "react";
|
|
37
|
+
import { BottomSheet } from "@surdeddd/bottom-sheet/react";
|
|
38
|
+
import "@surdeddd/bottom-sheet/styles";
|
|
39
|
+
|
|
40
|
+
export function Filters() {
|
|
41
|
+
const [open, setOpen] = useState(false);
|
|
42
|
+
return (
|
|
43
|
+
<>
|
|
44
|
+
<button onClick={() => setOpen(true)}>Filters</button>
|
|
45
|
+
<BottomSheet
|
|
46
|
+
open={open}
|
|
47
|
+
onOpenChange={setOpen}
|
|
48
|
+
snapPoints={[
|
|
49
|
+
{ id: "closed", size: 0 },
|
|
50
|
+
{ id: "open", size: "fit" },
|
|
51
|
+
]}
|
|
52
|
+
focusTrap
|
|
53
|
+
inertSiblings
|
|
54
|
+
header={<h2>Filters</h2>}
|
|
55
|
+
>
|
|
56
|
+
<FilterForm />
|
|
57
|
+
</BottomSheet>
|
|
58
|
+
</>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
A sheet that stays on screen (the maps pattern) has no closed point and no `open` prop:
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
<BottomSheet
|
|
67
|
+
snapPoints={[
|
|
68
|
+
{ id: "peek", size: 96 },
|
|
69
|
+
{ id: "half", size: "45dvh" },
|
|
70
|
+
{ id: "full", size: "90%" },
|
|
71
|
+
]}
|
|
72
|
+
initial="peek"
|
|
73
|
+
>
|
|
74
|
+
<PlaceList />
|
|
75
|
+
</BottomSheet>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Rules that prevent the usual mistakes
|
|
79
|
+
|
|
80
|
+
1. Snap points are objects, `{ id, size }`, and everything refers to them by `id`. `size` is a number of pixels, `"50%"`, `"fit"` (the content's own height), `"full"`, or any CSS length such as `"50dvh"`.
|
|
81
|
+
2. A sheet can close only if it has a snap point of size `0`. The `open` prop, `v-model:open`, `bind:open` and `close()` all depend on it. By convention its id is `"closed"`.
|
|
82
|
+
3. Import `@surdeddd/bottom-sheet/styles` once. Without it the sheet is unstyled and unpositioned. The custom element does not need it.
|
|
83
|
+
4. Do not set `z-index` on `.bs-sheet`, `.bs-backdrop` or anchors. The engine writes it. Use `teleportTo` to place the sheet in another stacking context.
|
|
84
|
+
5. `cancel()` in `before-snap` and `before-close` must be called synchronously. An async handler cannot veto.
|
|
85
|
+
6. Unmount a sheet in `closed`, not in `close`. `close` fires when the exit starts.
|
|
86
|
+
7. A modal sheet wants `focusTrap` and `inertSiblings`. Both are off by default.
|
|
87
|
+
8. To let a finger scroll the content at a half point, set `fitContentToSnap` and `dragFromContent: false` (globally or per snap point). By default a swipe on the content drags the sheet until it is fully open.
|
|
88
|
+
9. `backdropRange` is a range of progress, not of opacity. `backdropOpacity` is the opacity.
|
|
89
|
+
10. `--bs-progress` and `--bs-size` are set on the sheet and on `.bs-root`. Elements outside `.bs-root` cannot read them; use the `progress` event there.
|
|
90
|
+
11. `persistent` stops the user from closing the sheet; `close()` still works. `disableClose` stops `close()` too.
|
|
91
|
+
12. In the Next.js App Router the component file needs `"use client"`.
|
|
92
|
+
13. Options other than the ones listed as reactive are read once at mount. Change them by remounting with a new `key`.
|
|
93
|
+
|
|
94
|
+
## Engine options
|
|
95
|
+
|
|
96
|
+
Shared by `new BottomSheetEngine(options)` and every adapter (as props).
|
|
97
|
+
|
|
98
|
+
Elements, engine only: `element` (required), `handle`, `scrollContainer`, `backdrop`, `scrim`.
|
|
99
|
+
|
|
100
|
+
| Option | Type | Default | Meaning |
|
|
101
|
+
| --- | --- | --- | --- |
|
|
102
|
+
| `snapPoints` | `{ id: string; size: SnapPoint; dragFromContent?: boolean }[]` | required | The sizes the sheet can rest at |
|
|
103
|
+
| `allowed` | `string[]` | all ids | Ids the sheet may rest at now |
|
|
104
|
+
| `initial` | `string` | first allowed | Id to start at |
|
|
105
|
+
| `mode` | `"bottom" \| "top" \| "left" \| "right" \| "start" \| "end"` | `"bottom"` | Edge |
|
|
106
|
+
| `maxHeight` | `number \| string` | none | Cap on the size |
|
|
107
|
+
| `radius` | `number \| string` | `20px` | Corner radius |
|
|
108
|
+
| `fitContentToSnap` | `boolean` | `false` | Keep the scroll area and footer reachable at every point |
|
|
109
|
+
| `animation` | `"spring" \| "ios-spring" \| "material-bounce" \| "snappy" \| "tween" \| "linear"` | `"spring"` | Motion preset |
|
|
110
|
+
| `spring` | `{ stiffness?, damping?, mass? }` | preset | Spring parameters |
|
|
111
|
+
| `duration` | `number` | `220` | Tween length, ms |
|
|
112
|
+
| `easing` | `(t: number) => number` | ease-out-back | Tween curve |
|
|
113
|
+
| `settleAnimation` | `"waapi"` | off | Run the settle as a Web Animation |
|
|
114
|
+
| `respectReducedMotion` | `boolean` | `true` | Jump under `prefers-reduced-motion` |
|
|
115
|
+
| `viewTransitions` | `boolean` | `false` | Use `document.startViewTransition()` |
|
|
116
|
+
| `dragFrom` | `"handle" \| "sheet" \| "zones"` | `"handle"` | Where a drag may start. `zones` = `[data-bs-drag]` subtrees. `[data-bs-no-drag]` opts out |
|
|
117
|
+
| `dragFromContent` | `boolean` | `true` | A touch on the scroll area drags the sheet |
|
|
118
|
+
| `disableDrag` | `boolean` | `false` | No gesture |
|
|
119
|
+
| `rubberBand` | `boolean` | `true` | Soft over-drag |
|
|
120
|
+
| `flickVelocity` | `number` | `0.65` | px/ms for a touch flick |
|
|
121
|
+
| `dragThreshold` | `number` | `18` | px before a touch drag counts |
|
|
122
|
+
| `closeOnEscape` | `boolean` | `true` | Escape closes the top sheet |
|
|
123
|
+
| `closeOnBack` | `boolean` | `false` | The Back button closes the sheet |
|
|
124
|
+
| `routedTo` | `string` | none | URL shown while open |
|
|
125
|
+
| `closeOnRouteChange` | `boolean` | `false` | Close when the URL changes |
|
|
126
|
+
| `persistent` | `boolean` | `false` | The user cannot dismiss |
|
|
127
|
+
| `disableClose` | `boolean` | `false` | Nothing closes |
|
|
128
|
+
| `focusTrap` | `boolean` | `false` | Trap and restore focus |
|
|
129
|
+
| `initialFocus` | `string \| HTMLElement \| false` | first focusable | With `focusTrap`: what gets focus on open |
|
|
130
|
+
| `returnFocusTo` | `string \| HTMLElement \| (() => HTMLElement \| null)` | none | Where focus goes on close |
|
|
131
|
+
| `inertSiblings` | `boolean` | `false` | Make the rest of the page `inert` |
|
|
132
|
+
| `lockBodyScroll` | `boolean` | `true` | Lock page scroll while open |
|
|
133
|
+
| `backdropRange` | `[number, number]` | `[0, 1]` | Progress range over which the backdrop fades in |
|
|
134
|
+
| `backdropOpacity` | `number` | `1` | Opacity the backdrop reaches |
|
|
135
|
+
| `backdropColor` | `string` | stylesheet | Colour of the backdrop |
|
|
136
|
+
| `screenRange` | `[number, number]` | `[0, 1]` | Progress range for the scrim layer |
|
|
137
|
+
| `scrimMode` | `"full" \| "above-sheet" \| "off"` | `"full"` | Extent of the scrim layer |
|
|
138
|
+
| `scrimPreset` | `"subtle" \| "standard" \| "monitoring" \| "cinematic"` | none | Colour, blur and range together |
|
|
139
|
+
| `scrimColor` | `string` | none | Scrim fill |
|
|
140
|
+
| `scrimBlur` | `string` | none | Scrim blur radius, e.g. `"8px"` |
|
|
141
|
+
| `scrimInteractive` | `boolean` | `false` | Scrim takes pointer input |
|
|
142
|
+
| `scrimTapToClose` | `boolean` | `false` | Tap on the scrim closes |
|
|
143
|
+
| `stackEffect` | `boolean` | `false` | Scale the sheets under the top one |
|
|
144
|
+
| `persistKey` | `string` | none | `localStorage` key for the last point |
|
|
145
|
+
| `autoCollapseAfter` | `number` | off | ms of rest before collapsing |
|
|
146
|
+
| `linkedSheets` | `BottomSheetEngine[]` | none | Engines that collapse when this one opens |
|
|
147
|
+
| `features` | `EngineFeature[]` | all | Features for `BottomSheetCore` |
|
|
148
|
+
|
|
149
|
+
## Engine methods
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
sheet.open(id?): Promise<void> // to the first allowed open point; no-op on an open sheet without id
|
|
153
|
+
sheet.close(reason?): Promise<void> // to the point of size 0; without one, the smallest point
|
|
154
|
+
sheet.snapTo(id, { velocity?, signal? }?): Promise<void>
|
|
155
|
+
sheet.expand(): Promise<void> // largest allowed point
|
|
156
|
+
sheet.collapse(): Promise<void> // smallest allowed open point
|
|
157
|
+
sheet.dragTo(sizePx, { velocity?, signal? }?): Promise<void>
|
|
158
|
+
|
|
159
|
+
sheet.setAllowed(ids, snapTo?)
|
|
160
|
+
sheet.setSnapPoints(points, allowed?)
|
|
161
|
+
sheet.recompute() // re-measure "fit"
|
|
162
|
+
sheet.getAllowedIds(); sheet.getResolvedSnaps()
|
|
163
|
+
|
|
164
|
+
sheet.setMode(mode); sheet.getMode()
|
|
165
|
+
sheet.setPersistent(bool); sheet.setDisableClose(bool); sheet.setDisableDrag(bool)
|
|
166
|
+
sheet.setDragFrom(mode); sheet.setDragFromContent(bool)
|
|
167
|
+
sheet.setRadius(value); sheet.setMaxHeight(value)
|
|
168
|
+
|
|
169
|
+
sheet.setBackdropRange([from, to]); sheet.setBackdropOpacity(n); sheet.setBackdropColor(color | null)
|
|
170
|
+
sheet.setScreenRange([from, to]); sheet.setScrimMode(mode); sheet.setScrimEnabled(bool)
|
|
171
|
+
sheet.setScrimColor(color | null); sheet.setScrimBlur(blur | null)
|
|
172
|
+
sheet.setScrimInteractive(bool); sheet.setScrimTapToClose(bool)
|
|
173
|
+
sheet.setScrim({ preset?, color?, blur?, range?, mode?, interactive?, tapToClose?, enabled? })
|
|
174
|
+
sheet.setScrimOverlay({ children, position?, inset?, interactive? }): () => void
|
|
175
|
+
sheet.addAnchor({ element, position?, inset?, showOn?, fadeRange?, interactive?, animation? }): () => void
|
|
176
|
+
sheet.setScrimStages({ stages } | null): () => void
|
|
177
|
+
|
|
178
|
+
sheet.state // { activeId, size, progress, phase, isDragging, isAnimating }
|
|
179
|
+
sheet.canDismiss(); sheet.isTop(); sheet.depth()
|
|
180
|
+
sheet.on(event, listener): () => void
|
|
181
|
+
sheet.use(plugin); sheet.destroy()
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
`phase` is `"closed" | "opening" | "open" | "closing"`. `progress` is 0 at the smallest allowed point and 1 at the largest.
|
|
185
|
+
|
|
186
|
+
## Events
|
|
187
|
+
|
|
188
|
+
| Event | Payload | When |
|
|
189
|
+
| --- | --- | --- |
|
|
190
|
+
| `open` | `{ id }` | The sheet starts to appear |
|
|
191
|
+
| `opened` | `{ id }` | It has landed |
|
|
192
|
+
| `close` | none | It starts to leave |
|
|
193
|
+
| `closed` | none | It is gone |
|
|
194
|
+
| `snap` | `{ id, size, progress }` | It settled on a point |
|
|
195
|
+
| `before-snap` | `{ id, size, previousId, cancel }` | Before a move; `cancel()` vetoes |
|
|
196
|
+
| `before-close` | `{ reason, cancel }` | Before a close; `reason`: `"programmatic" \| "backdrop" \| "escape" \| "back"` |
|
|
197
|
+
| `dragstart` | `{ size }` | A drag begins |
|
|
198
|
+
| `drag` | `{ size, delta }` | Every frame of a drag |
|
|
199
|
+
| `dragend` | `{ size, velocity }` | A drag ends |
|
|
200
|
+
| `progress` | `{ value, size }` | Every frame of any motion |
|
|
201
|
+
|
|
202
|
+
## Adapters
|
|
203
|
+
|
|
204
|
+
All components take every engine option as a prop, plus: `backdrop` (default `true`), `closeOnBackdrop` (default `true`), `teleportTo`, `ariaLabel` (default `"Bottom sheet"`), `handleLabel`, `contentLabel`.
|
|
205
|
+
|
|
206
|
+
### React (`/react`)
|
|
207
|
+
|
|
208
|
+
- Controlled open: `open`, `onOpenChange`.
|
|
209
|
+
- Regions: `header`, `footer` (node or `(state) => node`), `leftButton`, `rightButton`, `screen`, `children`.
|
|
210
|
+
- Callbacks: `onSnap(id)`, `onOpen(id)`, `onOpened(id)`, `onClose()`, `onClosed()`, `onBeforeSnap(e)`, `onBeforeClose(e)`, `onDragStart(e)`, `onDragEnd(e)`, `onDrag(e)`, `onProgress(e)`, `onChange(state)`.
|
|
211
|
+
- Other props: `className` and `style` (on the sheet element), `ariaLabelledBy`, `anchors`, `scrimStages`, `noSSR`.
|
|
212
|
+
- Ref (`BottomSheetHandle`): `snapTo`, `open`, `close`, `expand`, `collapse`, `setAllowed`, `setSnapPoints`, `recompute`, `isTop`, `depth`, `setScrim`, `setScrimOverlay`, `addAnchor`, `setScrimStages`, `on`, `getEngine`, `state`.
|
|
213
|
+
- Reactive props: `open`, `snapPoints`, `allowed`, `mode`, `radius`, `maxHeight`, `persistent`, `disableClose`, `disableDrag`, `dragFrom`, `dragFromContent`, `backdropColor`, `backdropOpacity`.
|
|
214
|
+
- Headless: `useBottomSheet(options)` returns `sheetRef`, `handleRef`, `contentRef`, `backdropRef`, `screenRef`, `state` and the methods. You render `.bs-root > .bs-backdrop + .bs-sheet > .bs-handle + .bs-content`.
|
|
215
|
+
|
|
216
|
+
### Vue 3 (`/vue`)
|
|
217
|
+
|
|
218
|
+
- Props in kebab-case in templates: `:snap-points`, `focus-trap`.
|
|
219
|
+
- `v-model:open`, `v-model:snap`.
|
|
220
|
+
- Slots: default, `header`, `footer` (both get `{ state }`), `button-left`, `button-right`, `screen`, `anchor-<id>`.
|
|
221
|
+
- Events: `@snap`, `@open`, `@opened`, `@close`, `@closed`, `@before-snap`, `@before-close`, `@drag-start`, `@drag-end`, `@drag`, `@progress`, `@change`.
|
|
222
|
+
- `teleport` defaults to `true` and `teleport-to` to `"body"`.
|
|
223
|
+
- Template ref exposes the methods and `state`.
|
|
224
|
+
- Headless: `useBottomSheet(options)`.
|
|
225
|
+
|
|
226
|
+
### Svelte 5 (`/svelte`)
|
|
227
|
+
|
|
228
|
+
- `bind:open`, `bind:snap`.
|
|
229
|
+
- Snippets: `children`, `header`, `footer`, `leftButton`, `rightButton`, `screen`.
|
|
230
|
+
- Callbacks, lower case: `onsnap`, `onopen`, `onopened`, `onclose`, `onclosed`, `onbeforesnap`, `onbeforeclose`, `ondragstart`, `ondragend`, `ondrag`, `onprogress`, `onchange`.
|
|
231
|
+
- `bind:this` exposes the methods and `getState()`, `getEngine()`.
|
|
232
|
+
- Headless: `createBottomSheet(options)` with `attach({ element, handle, scrollContainer, backdrop })` inside `$effect`.
|
|
233
|
+
|
|
234
|
+
### Solid (`/solid`)
|
|
235
|
+
|
|
236
|
+
- Controlled open: `open`, `onOpenChange`.
|
|
237
|
+
- `header`, `footer`, `leftButton`, `rightButton`, `screen` are JSX props.
|
|
238
|
+
- Callbacks as in React. `engineRef={engine => …}` gives the engine.
|
|
239
|
+
|
|
240
|
+
### Qwik (`/qwik`)
|
|
241
|
+
|
|
242
|
+
- Controlled: `open` with `onOpenChange$`, `snap` with `onSnap$`. There is no ref.
|
|
243
|
+
- Slots: default, `q:slot="header"`, `"footer"`, `"leftButton"`, `"rightButton"`, `"screen"`.
|
|
244
|
+
- Callbacks: `onSnap$`, `onOpen$`, `onOpened$`, `onClose$`, `onClosed$`, `onDragStart$`, `onDragEnd$`, `onChange$`.
|
|
245
|
+
- There is no `onBeforeSnap$`, `onBeforeClose$`, `onDrag$` or `onProgress$`, and no `easing`, `linkedSheets` or `features` props.
|
|
246
|
+
|
|
247
|
+
### Custom element (`/element`)
|
|
248
|
+
|
|
249
|
+
```html
|
|
250
|
+
<bottom-sheet snap-points="closed:0,half:50%,full:90%" focus-trap="true">
|
|
251
|
+
<h2 slot="header">Title</h2>
|
|
252
|
+
<p>Content</p>
|
|
253
|
+
<button slot="footer">Done</button>
|
|
254
|
+
</bottom-sheet>
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
- Attributes: `snap-points` (shorthand `id:size,…` or JSON), `allowed`, `initial`, `snap`, `open`, `mode`, `animation`, `focus-trap`, `close-on-escape`, `close-on-route-change`, `lock-body-scroll`, `backdrop`, `backdrop-color`, `scrim-color`, `persistent`, `disable-close`, `disable-drag`, `drag-from`, `drag-from-content`, `fit-content-to-snap`, `stack-effect`, `radius`, `max-height`, `return-focus-to`, `sheet-label`, `handle-label`, `content-label`, `stylesheet`, `options` (JSON of any other engine option).
|
|
258
|
+
- Boolean attributes take the strings `"true"` and `"false"`.
|
|
259
|
+
- Property `options` for values JSON cannot hold.
|
|
260
|
+
- Methods: `open()`, `close()`, `snapTo(id)`, `expand()`, `collapse()`, `setAllowed()`, `setMode()`, `setRadius()`, `setMaxHeight()`, `recompute()`, `isTop()`, `depth()`, `canDismiss()`, `addAnchor()`, `setScrimStages()`, `getEngine()`. Properties: `snap`, `sheetState`.
|
|
261
|
+
- Events (`CustomEvent`, payload in `detail`): `snap`, `open`, `opened`, `close`, `closed`, `before-snap`, `before-close`, `drag-start`, `drag`, `drag-end`, `progress`. Veto `before-snap` and `before-close` with `event.preventDefault()`.
|
|
262
|
+
- Slots: default, `header`, `footer`, `leftButton`, `rightButton`, `screen`, `anchor`.
|
|
263
|
+
- Parts: `sheet`, `handle`, `header`, `content`, `footer`, `backdrop`, `screen`, `left-button`, `right-button`.
|
|
264
|
+
- Angular: add `CUSTOM_ELEMENTS_SCHEMA`. Astro: import the module from a client `<script>`, not from the frontmatter.
|
|
265
|
+
|
|
266
|
+
### Without a framework
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
import { BottomSheetEngine } from "@surdeddd/bottom-sheet";
|
|
270
|
+
import "@surdeddd/bottom-sheet/styles";
|
|
271
|
+
|
|
272
|
+
const sheet = new BottomSheetEngine({
|
|
273
|
+
element: document.querySelector(".bs-sheet"),
|
|
274
|
+
handle: document.querySelector(".bs-handle"),
|
|
275
|
+
scrollContainer: document.querySelector(".bs-content"),
|
|
276
|
+
backdrop: document.querySelector(".bs-backdrop"),
|
|
277
|
+
snapPoints: [{ id: "closed", size: 0 }, { id: "open", size: "fit" }],
|
|
278
|
+
initial: "closed",
|
|
279
|
+
});
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Markup: `div.bs-root > div.bs-backdrop + section.bs-sheet[data-mode="bottom"] > div.bs-handle[role="slider"][tabindex="0"] + div.bs-header? + div.bs-content + div.bs-footer?`. The engine does not listen to the backdrop: add `backdrop.addEventListener("click", () => sheet.canDismiss() && sheet.close("backdrop"))`.
|
|
283
|
+
|
|
284
|
+
## Styling
|
|
285
|
+
|
|
286
|
+
CSS custom properties, set on `.bs-root`, an ancestor or `:root`; they cross the custom element's shadow boundary.
|
|
287
|
+
|
|
288
|
+
`--bs-surface`, `--bs-surface-border`, `--bs-radius`, `--bs-shadow`, `--bs-handle-color`, `--bs-handle-width`, `--bs-handle-height`, `--bs-handle-padding`, `--bs-header-padding`, `--bs-header-min-height`, `--bs-content-padding`, `--bs-footer-padding`, `--bs-backdrop-color`, `--bs-scrim-color`, `--bs-scrim-blur`.
|
|
289
|
+
|
|
290
|
+
Written by the engine, read-only: `--bs-size` (px), `--bs-progress` (0 to 1), `--bs-keyboard-inset` (px).
|
|
291
|
+
|
|
292
|
+
Class names: `bs-root`, `bs-backdrop`, `bs-screen`, `bs-sheet`, `bs-handle`, `bs-header`, `bs-content`, `bs-footer`, `bs-button-slot`.
|
|
293
|
+
|
|
294
|
+
## Behaviour worth knowing
|
|
295
|
+
|
|
296
|
+
- The handle is a keyboard slider: the arrow pointing away from the sheet's edge grows it, the opposite one shrinks it, `Home` and `End` go to the smallest and largest point, `Escape` closes.
|
|
297
|
+
- Sheets stack. Each open sheet goes on top; Escape, Back and the focus trap act on the top one.
|
|
298
|
+
- A bottom sheet rests on top of the on-screen keyboard.
|
|
299
|
+
- Every adapter renders on the server. A sheet that starts closed is hidden in the server markup.
|
|
300
|
+
- `open` and `close` fire when a transition starts, `opened` and `closed` when it lands.
|
|
301
|
+
|
|
302
|
+
## Documentation
|
|
303
|
+
|
|
304
|
+
- [README](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/README.md): overview, option tables, methods, events
|
|
305
|
+
- [React](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/react.md)
|
|
306
|
+
- [Vue](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/vue.md)
|
|
307
|
+
- [Svelte](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/svelte.md)
|
|
308
|
+
- [Solid](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/solid.md)
|
|
309
|
+
- [Qwik](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/qwik.md)
|
|
310
|
+
- [Preact](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/preact.md)
|
|
311
|
+
- [Custom element](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/web-component.md)
|
|
312
|
+
- [Without a framework](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/vanilla.md)
|
|
313
|
+
- [Angular](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/angular.md), [Lit](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/lit.md), [Astro](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/astro.md)
|
|
314
|
+
- [Theming](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/theming.md): tokens, themes, backdrop, scrim, stacking
|
|
315
|
+
- [Content at every snap point](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/content-fit.md): `fitContentToSnap`
|
|
316
|
+
- [Anchors and scrim stages](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/anchors.md)
|
|
317
|
+
- [Overlay](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/overlay.md)
|
|
318
|
+
- [Recipes](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/recipes/README.md): ten worked examples
|
|
319
|
+
- [Migrating from vaul or react-modal-sheet](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/MIGRATION.md)
|
|
320
|
+
- [Changelog](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/CHANGELOG.md)
|
|
321
|
+
|
|
322
|
+
## Optional
|
|
323
|
+
|
|
324
|
+
- [Architecture](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/ARCHITECTURE.md)
|
|
325
|
+
- [API stability](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/api-stability.md)
|
|
326
|
+
- [WebGL renderer](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/webgl.md)
|
|
327
|
+
- [Plugins](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/plugins.md)
|
|
328
|
+
- [RTL](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/rtl.md)
|
|
329
|
+
- [Browser support](https://raw.githubusercontent.com/Surdeddd/BottomSheet/main/docs/browser-support.md)
|
|
330
|
+
- [Live demo](https://bottom-sheet-demo-ashy.vercel.app)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@surdeddd/bottom-sheet",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.24.1",
|
|
4
|
+
"description": "Bottom sheet, drawer and modal sheet with snap points, spring physics and touch gestures. One engine for React, Vue 3, Svelte 5, Solid, Qwik, Preact and a <bottom-sheet> web component. Accessible, SSR-safe, no dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Surdeddd",
|
|
@@ -9,28 +9,45 @@
|
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "git+https://github.com/Surdeddd/BottomSheet.git"
|
|
11
11
|
},
|
|
12
|
-
"homepage": "https://
|
|
12
|
+
"homepage": "https://bottom-sheet-demo-ashy.vercel.app",
|
|
13
13
|
"bugs": {
|
|
14
14
|
"url": "https://github.com/Surdeddd/BottomSheet/issues"
|
|
15
15
|
},
|
|
16
16
|
"keywords": [
|
|
17
17
|
"bottom-sheet",
|
|
18
|
-
"
|
|
18
|
+
"bottomsheet",
|
|
19
|
+
"sheet",
|
|
19
20
|
"drawer",
|
|
20
|
-
"
|
|
21
|
-
"
|
|
21
|
+
"modal",
|
|
22
|
+
"modal-sheet",
|
|
23
|
+
"action-sheet",
|
|
24
|
+
"slide-up-panel",
|
|
25
|
+
"swipeable",
|
|
26
|
+
"draggable",
|
|
27
|
+
"snap-points",
|
|
28
|
+
"gesture",
|
|
29
|
+
"touch",
|
|
30
|
+
"mobile",
|
|
31
|
+
"spring",
|
|
22
32
|
"react",
|
|
33
|
+
"react-component",
|
|
23
34
|
"vue",
|
|
35
|
+
"vue3",
|
|
24
36
|
"svelte",
|
|
37
|
+
"svelte5",
|
|
25
38
|
"solid-js",
|
|
26
39
|
"qwik",
|
|
27
40
|
"preact",
|
|
28
41
|
"lit",
|
|
42
|
+
"angular",
|
|
29
43
|
"web-component",
|
|
44
|
+
"custom-element",
|
|
45
|
+
"headless",
|
|
46
|
+
"framework-agnostic",
|
|
47
|
+
"typescript",
|
|
30
48
|
"ssr",
|
|
31
49
|
"a11y",
|
|
32
|
-
"
|
|
33
|
-
"gesture",
|
|
50
|
+
"accessibility",
|
|
34
51
|
"pointer-events"
|
|
35
52
|
],
|
|
36
53
|
"sideEffects": [
|
|
@@ -45,6 +62,8 @@
|
|
|
45
62
|
"main": "./dist/index.cjs",
|
|
46
63
|
"module": "./dist/index.js",
|
|
47
64
|
"types": "./dist/index.d.ts",
|
|
65
|
+
"unpkg": "./dist/element.iife.global.js",
|
|
66
|
+
"jsdelivr": "./dist/element.iife.global.js",
|
|
48
67
|
"qwik": "./dist/qwik-lib/index.qwik.mjs",
|
|
49
68
|
"exports": {
|
|
50
69
|
".": {
|
|
@@ -240,37 +259,37 @@
|
|
|
240
259
|
{
|
|
241
260
|
"name": "core (engine + types)",
|
|
242
261
|
"path": "dist/index.js",
|
|
243
|
-
"limit": "
|
|
262
|
+
"limit": "25.66 KB",
|
|
244
263
|
"gzip": true
|
|
245
264
|
},
|
|
246
265
|
{
|
|
247
266
|
"name": "react adapter",
|
|
248
267
|
"path": "dist/react.js",
|
|
249
|
-
"limit": "
|
|
268
|
+
"limit": "33.26 KB",
|
|
250
269
|
"gzip": true
|
|
251
270
|
},
|
|
252
271
|
{
|
|
253
272
|
"name": "vue adapter",
|
|
254
273
|
"path": "dist/vue.js",
|
|
255
|
-
"limit": "
|
|
274
|
+
"limit": "28.94 KB",
|
|
256
275
|
"gzip": true
|
|
257
276
|
},
|
|
258
277
|
{
|
|
259
278
|
"name": "svelte adapter",
|
|
260
279
|
"path": "dist/svelte.js",
|
|
261
|
-
"limit": "
|
|
280
|
+
"limit": "28.48 KB",
|
|
262
281
|
"gzip": true
|
|
263
282
|
},
|
|
264
283
|
{
|
|
265
284
|
"name": "solid adapter",
|
|
266
285
|
"path": "dist/solid.js",
|
|
267
|
-
"limit": "
|
|
286
|
+
"limit": "27.41 KB",
|
|
268
287
|
"gzip": true
|
|
269
288
|
},
|
|
270
289
|
{
|
|
271
290
|
"name": "qwik adapter",
|
|
272
291
|
"path": "dist/qwik.js",
|
|
273
|
-
"limit": "
|
|
292
|
+
"limit": "27.44 KB",
|
|
274
293
|
"gzip": true
|
|
275
294
|
},
|
|
276
295
|
{
|
|
@@ -285,19 +304,19 @@
|
|
|
285
304
|
{
|
|
286
305
|
"name": "web component (self-contained)",
|
|
287
306
|
"path": "dist/element.js",
|
|
288
|
-
"limit": "
|
|
307
|
+
"limit": "33.35 KB",
|
|
289
308
|
"gzip": true
|
|
290
309
|
},
|
|
291
310
|
{
|
|
292
311
|
"name": "web component (IIFE / CDN)",
|
|
293
312
|
"path": "dist/element.iife.global.js",
|
|
294
|
-
"limit": "
|
|
313
|
+
"limit": "32.85 KB",
|
|
295
314
|
"gzip": true
|
|
296
315
|
},
|
|
297
316
|
{
|
|
298
317
|
"name": "overlay (subpath)",
|
|
299
318
|
"path": "dist/overlay.js",
|
|
300
|
-
"limit": "
|
|
319
|
+
"limit": "8.39 KB",
|
|
301
320
|
"gzip": true
|
|
302
321
|
},
|
|
303
322
|
{
|
|
@@ -309,19 +328,19 @@
|
|
|
309
328
|
{
|
|
310
329
|
"name": "slim core (subpath, no optional features)",
|
|
311
330
|
"path": "dist/core.js",
|
|
312
|
-
"limit": "
|
|
331
|
+
"limit": "21.88 KB",
|
|
313
332
|
"gzip": true
|
|
314
333
|
},
|
|
315
334
|
{
|
|
316
335
|
"name": "features (subpath)",
|
|
317
336
|
"path": "dist/features.js",
|
|
318
|
-
"limit": "
|
|
337
|
+
"limit": "4.21 KB",
|
|
319
338
|
"gzip": true
|
|
320
339
|
},
|
|
321
340
|
{
|
|
322
341
|
"name": "webgl renderer (subpath)",
|
|
323
342
|
"path": "dist/webgl.js",
|
|
324
|
-
"limit": "
|
|
343
|
+
"limit": "6.44 KB",
|
|
325
344
|
"gzip": true
|
|
326
345
|
}
|
|
327
346
|
],
|
|
@@ -329,6 +348,7 @@
|
|
|
329
348
|
"dist",
|
|
330
349
|
"!dist/**/*.map",
|
|
331
350
|
"README.md",
|
|
351
|
+
"llms.txt",
|
|
332
352
|
"LICENSE"
|
|
333
353
|
],
|
|
334
354
|
"scripts": {
|
|
@@ -348,6 +368,8 @@
|
|
|
348
368
|
"bench": "vitest bench",
|
|
349
369
|
"bench:check": "node ./scripts/bench-check.mjs",
|
|
350
370
|
"check:qwik-ssr": "node ./scripts/qwik-ssr-check.mjs",
|
|
371
|
+
"check:qwik-client": "node ./scripts/qwik-client-check.mjs",
|
|
372
|
+
"check:types": "tsc -p type-tests",
|
|
351
373
|
"size": "size-limit",
|
|
352
374
|
"docs:api": "typedoc",
|
|
353
375
|
"lhci": "lhci autorun --config=./lighthouserc.json",
|