@surdeddd/bottom-sheet 0.2.0 → 0.4.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-BJrH7qY3.d.cts} +105 -3
  3. package/dist/{BottomSheetEngine-Df9MwBbm.d.ts → BottomSheetEngine-L05jGZvU.d.ts} +105 -3
  4. package/dist/element.cjs +1170 -196
  5. package/dist/element.d.cts +29 -5
  6. package/dist/element.d.ts +29 -5
  7. package/dist/element.iife.global.js +2 -2
  8. package/dist/element.js +1170 -196
  9. package/dist/index.cjs +1051 -220
  10. package/dist/index.d.cts +18 -3
  11. package/dist/index.d.ts +18 -3
  12. package/dist/index.js +1049 -221
  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 +181 -37
  18. package/dist/overlay.d.cts +13 -0
  19. package/dist/overlay.d.ts +13 -0
  20. package/dist/overlay.js +181 -37
  21. package/dist/preact.d.cts +1 -1
  22. package/dist/preact.d.ts +1 -1
  23. package/dist/qwik.cjs +966 -195
  24. package/dist/qwik.d.cts +4 -2
  25. package/dist/qwik.d.ts +4 -2
  26. package/dist/qwik.js +967 -196
  27. package/dist/react.cjs +1242 -272
  28. package/dist/react.d.cts +47 -5
  29. package/dist/react.d.ts +47 -5
  30. package/dist/react.js +1242 -272
  31. package/dist/solid.cjs +992 -236
  32. package/dist/solid.d.cts +299 -4
  33. package/dist/solid.d.ts +299 -4
  34. package/dist/solid.js +993 -237
  35. package/dist/solid.source.jsx +3476 -0
  36. package/dist/styles.css +67 -66
  37. package/dist/svelte-core.cjs +3415 -0
  38. package/dist/svelte-core.js +3413 -0
  39. package/dist/svelte-src/BottomSheet.svelte +308 -0
  40. package/dist/svelte-src/index.js +2 -0
  41. package/dist/svelte.cjs +1034 -207
  42. package/dist/svelte.d.cts +121 -0
  43. package/dist/svelte.d.ts +28 -3
  44. package/dist/svelte.js +1035 -208
  45. package/dist/vue.cjs +1191 -205
  46. package/dist/vue.d.cts +127 -0
  47. package/dist/vue.d.ts +57 -4
  48. package/dist/vue.js +1192 -206
  49. package/package.json +105 -45
@@ -0,0 +1,308 @@
1
+ <script lang="ts" generics="TId extends string = string">
2
+ import { onMount, onDestroy, untrack, type Snippet } from "svelte";
3
+ import { BottomSheetEngine } from "@surdeddd/bottom-sheet";
4
+ import type {
5
+ EngineState,
6
+ SnapPointDef,
7
+ SheetMode,
8
+ ScrimUpdate,
9
+ ScrimOverlayOptions,
10
+ EngineOptions,
11
+ SheetEventMap,
12
+ } from "@surdeddd/bottom-sheet";
13
+
14
+ type Props = {
15
+ snapPoints: SnapPointDef<TId>[];
16
+ allowed?: TId[];
17
+ initial?: TId;
18
+ mode?: SheetMode;
19
+ animation?: "spring" | "tween";
20
+ spring?: { stiffness?: number; damping?: number; mass?: number };
21
+ focusTrap?: boolean;
22
+ closeOnEscape?: boolean;
23
+ closeOnBack?: boolean;
24
+ lockBodyScroll?: boolean;
25
+ rubberBand?: boolean;
26
+ backdropRange?: [number, number];
27
+ backdrop?: boolean;
28
+ closeOnBackdrop?: boolean;
29
+ persistent?: boolean;
30
+ disableClose?: boolean;
31
+ disableDrag?: boolean;
32
+ closeOnRouteChange?: boolean;
33
+ radius?: string | number;
34
+ maxHeight?: string | number;
35
+ backdropColor?: string;
36
+ backdropOpacity?: number;
37
+ open?: boolean;
38
+ snap?: TId;
39
+ returnFocusTo?: HTMLElement | string | (() => HTMLElement | null);
40
+ ariaLabel?: string;
41
+ header?: Snippet<[EngineState & { activeId: TId }]>;
42
+ leftButton?: Snippet;
43
+ rightButton?: Snippet;
44
+ screen?: Snippet;
45
+ children?: Snippet;
46
+ onsnap?: (id: TId) => void;
47
+ onopen?: (id: TId) => void;
48
+ onclose?: () => void;
49
+ onbeforeclose?: (payload: SheetEventMap["before-close"]) => void;
50
+ onopened?: (id: TId) => void;
51
+ onclosed?: () => void;
52
+ ondragstart?: () => void;
53
+ ondragend?: () => void;
54
+ onchange?: (state: EngineState & { activeId: TId }) => void;
55
+ };
56
+
57
+ let {
58
+ snapPoints,
59
+ allowed,
60
+ initial,
61
+ mode = "bottom",
62
+ animation = "spring",
63
+ spring,
64
+ focusTrap = false,
65
+ closeOnEscape = true,
66
+ closeOnBack = false,
67
+ lockBodyScroll = true,
68
+ rubberBand = true,
69
+ backdropRange,
70
+ backdrop = true,
71
+ closeOnBackdrop = true,
72
+ persistent = false,
73
+ disableClose = false,
74
+ disableDrag = false,
75
+ closeOnRouteChange = false,
76
+ radius,
77
+ maxHeight,
78
+ backdropColor,
79
+ backdropOpacity,
80
+ open: openProp = $bindable(),
81
+ snap = $bindable(),
82
+ returnFocusTo,
83
+ ariaLabel = "Bottom sheet",
84
+ header,
85
+ leftButton,
86
+ rightButton,
87
+ screen,
88
+ children,
89
+ onsnap,
90
+ onopen,
91
+ onclose,
92
+ onbeforeclose,
93
+ onopened,
94
+ onclosed,
95
+ ondragstart,
96
+ ondragend,
97
+ onchange,
98
+ }: Props = $props();
99
+
100
+ let sheetEl: HTMLElement | undefined = $state();
101
+ let handleEl: HTMLElement | undefined = $state();
102
+ let contentEl: HTMLElement | undefined = $state();
103
+ let backdropEl: HTMLElement | undefined = $state();
104
+ let screenEl: HTMLElement | undefined = $state();
105
+
106
+ let viewState: EngineState & { activeId: TId } = $state({
107
+ size: 0,
108
+ activeId: untrack(
109
+ () => (initial ?? snapPoints[0]?.id ?? "default") as TId,
110
+ ),
111
+ isDragging: false,
112
+ isAnimating: false,
113
+ progress: 0,
114
+ });
115
+
116
+ let engine: BottomSheetEngine | null = null;
117
+
118
+ onMount(() => {
119
+ if (!sheetEl) return;
120
+ engine = new BottomSheetEngine({
121
+ element: sheetEl,
122
+ handle: handleEl,
123
+ scrollContainer: contentEl,
124
+ backdrop: backdropEl,
125
+ scrim: screenEl,
126
+ mode,
127
+ snapPoints,
128
+ allowed,
129
+ initial,
130
+ animation,
131
+ spring,
132
+ focusTrap,
133
+ closeOnEscape,
134
+ closeOnBack,
135
+ lockBodyScroll,
136
+ rubberBand,
137
+ backdropRange,
138
+ persistent,
139
+ disableClose,
140
+ disableDrag,
141
+ closeOnRouteChange,
142
+ radius,
143
+ maxHeight,
144
+ returnFocusTo,
145
+ });
146
+ const sync = () => {
147
+ if (!engine) return;
148
+ viewState = { ...engine.state } as EngineState & { activeId: TId };
149
+ onchange?.(viewState);
150
+ };
151
+ sync();
152
+ if (backdropColor !== undefined) engine.setScrimColor(backdropColor);
153
+ if (backdropOpacity !== undefined)
154
+ engine.setBackdropRange([0, backdropOpacity]);
155
+ engine.on("snap", payload => {
156
+ sync();
157
+ snap = payload.id as TId;
158
+ onsnap?.(payload.id as TId);
159
+ });
160
+ engine.on("open", payload => {
161
+ openProp = true;
162
+ onopen?.(payload.id as TId);
163
+ });
164
+ engine.on("close", () => {
165
+ openProp = false;
166
+ onclose?.();
167
+ });
168
+ engine.on("before-close", payload => onbeforeclose?.(payload));
169
+ engine.on("opened", payload => onopened?.(payload.id as TId));
170
+ engine.on("closed", () => onclosed?.());
171
+ engine.on("dragstart", () => {
172
+ sync();
173
+ ondragstart?.();
174
+ });
175
+ engine.on("dragend", () => {
176
+ sync();
177
+ ondragend?.();
178
+ });
179
+ });
180
+
181
+ onDestroy(() => {
182
+ engine?.destroy();
183
+ engine = null;
184
+ });
185
+
186
+ export const snapTo = (id: TId) =>
187
+ engine?.snapTo(id) ?? Promise.resolve();
188
+ export const open = (id?: TId) =>
189
+ engine?.open(id) ?? Promise.resolve();
190
+ export const close = () => engine?.close() ?? Promise.resolve();
191
+ export const expand = () => engine?.expand() ?? Promise.resolve();
192
+ export const collapse = () => engine?.collapse() ?? Promise.resolve();
193
+ export const isTop = (): boolean => engine?.isTop() ?? false;
194
+ export const depth = (): number => engine?.depth() ?? 0;
195
+ export const setAllowed = (ids: TId[], snap?: TId) =>
196
+ engine?.setAllowed(ids as unknown as string[], snap);
197
+ export const setSnapPoints = (
198
+ points: EngineOptions["snapPoints"],
199
+ nextAllowed?: string[],
200
+ ) => engine?.setSnapPoints(points, nextAllowed);
201
+ export const setScrim = (opts: ScrimUpdate) => engine?.setScrim(opts);
202
+ export const setScrimOverlay = (opts: ScrimOverlayOptions): (() => void) =>
203
+ engine?.setScrimOverlay(opts) ?? (() => {});
204
+ export const setRadius = (r: string | number) => engine?.setRadius(r);
205
+ export const setMaxHeight = (h: string | number) => engine?.setMaxHeight(h);
206
+ export const canDismiss = (): boolean => engine?.canDismiss() ?? false;
207
+ export const getState = (): EngineState & { activeId: TId } =>
208
+ (engine?.state ?? viewState) as EngineState & { activeId: TId };
209
+ export const getEngine = (): BottomSheetEngine | null => engine;
210
+
211
+ $effect(() => {
212
+ if (radius !== undefined) engine?.setRadius(radius);
213
+ });
214
+ $effect(() => {
215
+ if (maxHeight !== undefined) engine?.setMaxHeight(maxHeight);
216
+ });
217
+ $effect(() => {
218
+ if (backdropColor !== undefined) engine?.setScrimColor(backdropColor);
219
+ });
220
+ $effect(() => {
221
+ if (backdropOpacity !== undefined)
222
+ engine?.setBackdropRange([0, backdropOpacity]);
223
+ });
224
+ $effect(() => {
225
+ if (snap === undefined) return;
226
+ const next = snap;
227
+ if (!engine || untrack(() => viewState.activeId) === next) return;
228
+ void engine.snapTo(next);
229
+ });
230
+ $effect(() => {
231
+ if (openProp === undefined) return;
232
+ const next = openProp;
233
+ if (!engine) return;
234
+ const isOpen = untrack(() => viewState.size) > 0;
235
+ if (next && !isOpen) void engine.open();
236
+ else if (!next && isOpen) void engine.close();
237
+ });
238
+
239
+ let allowedIds = $derived(
240
+ allowed && allowed.length > 0
241
+ ? allowed
242
+ : snapPoints.map(s => s.id),
243
+ );
244
+ let activeIdx = $derived(allowedIds.indexOf(viewState.activeId));
245
+ let isVerticalAxis = $derived(mode === "bottom" || mode === "top");
246
+ </script>
247
+
248
+ <div class="bs-root">
249
+ {#if backdrop}
250
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
251
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
252
+ <div
253
+ class="bs-backdrop"
254
+ bind:this={backdropEl}
255
+ aria-hidden="true"
256
+ onclick={closeOnBackdrop
257
+ ? () => {
258
+ if (engine?.canDismiss()) void engine.close("backdrop");
259
+ }
260
+ : undefined}
261
+ ></div>
262
+ {/if}
263
+ <div class="bs-screen" bind:this={screenEl}>
264
+ {#if screen}{@render screen()}{/if}
265
+ </div>
266
+ <!-- svelte-ignore a11y_no_noninteractive_element_to_interactive_role -->
267
+ <section
268
+ class="bs-sheet"
269
+ bind:this={sheetEl}
270
+ data-mode={mode}
271
+ data-active={viewState.activeId}
272
+ role="dialog"
273
+ aria-modal={focusTrap ? "true" : undefined}
274
+ aria-label={ariaLabel}
275
+ >
276
+ {#if leftButton}
277
+ <div class="bs-button-slot" data-side="left">
278
+ {@render leftButton()}
279
+ </div>
280
+ {/if}
281
+ {#if rightButton}
282
+ <div class="bs-button-slot" data-side="right">
283
+ {@render rightButton()}
284
+ </div>
285
+ {/if}
286
+ <div
287
+ class="bs-handle"
288
+ bind:this={handleEl}
289
+ role="slider"
290
+ tabindex="0"
291
+ aria-label="Resize sheet"
292
+ aria-orientation={isVerticalAxis ? "vertical" : "horizontal"}
293
+ aria-valuemin={0}
294
+ aria-valuemax={Math.max(0, allowedIds.length - 1)}
295
+ aria-valuenow={Math.max(0, activeIdx)}
296
+ aria-valuetext={viewState.activeId}
297
+ >
298
+ {#if header}{@render header(viewState)}{/if}
299
+ </div>
300
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
301
+ <div class="bs-content" bind:this={contentEl} tabindex="0" role="region" aria-label="Sheet content">
302
+ {#if children}{@render children()}{/if}
303
+ </div>
304
+ <span class="bs-sr-only" role="status" aria-live="polite">
305
+ {viewState.activeId}
306
+ </span>
307
+ </section>
308
+ </div>
@@ -0,0 +1,2 @@
1
+ export { default as BottomSheet } from "./BottomSheet.svelte";
2
+ export { createBottomSheet } from "../svelte-core.js";