@abhivarde/svelte-drawer 1.0.4 → 1.0.6
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
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A drawer component for Svelte 5, inspired by [Vaul](https://github.com/emilkowalski/vaul).
|
|
4
4
|
|
|
5
|
+
[](https://skills.sh/AbhiVarde/svelte-drawer)
|
|
5
6
|
[](https://www.npmjs.com/package/@abhivarde/svelte-drawer) [](https://npmx.dev/package/@abhivarde/svelte-drawer)
|
|
6
7
|
|
|
7
8
|
## Features
|
|
@@ -160,6 +161,24 @@ Add a premium blur effect to the overlay background:
|
|
|
160
161
|
</Drawer>
|
|
161
162
|
```
|
|
162
163
|
|
|
164
|
+
### Close Threshold
|
|
165
|
+
|
|
166
|
+
Control how far the user needs to drag before the drawer dismisses.
|
|
167
|
+
|
|
168
|
+
```svelte
|
|
169
|
+
<!-- easier to dismiss (short drag) -->
|
|
170
|
+
<Drawer bind:open closeThreshold={0.15}>
|
|
171
|
+
...
|
|
172
|
+
</Drawer>
|
|
173
|
+
|
|
174
|
+
<!-- harder to dismiss (long drag required) -->
|
|
175
|
+
<Drawer bind:open closeThreshold={0.5}>
|
|
176
|
+
...
|
|
177
|
+
</Drawer>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Values range from `0` to `1`. Default is `0.3` (30% of the viewport).
|
|
181
|
+
|
|
163
182
|
### Using Variants
|
|
164
183
|
|
|
165
184
|
```svelte
|
|
@@ -463,31 +482,34 @@ Automatically save and restore drawer state across page reloads.
|
|
|
463
482
|
|
|
464
483
|
### Auto Height (AI & Dynamic Content)
|
|
465
484
|
|
|
466
|
-
Use `autoHeight` on `DrawerContent` when your drawer content changes height at runtime
|
|
485
|
+
Use `autoHeight` on `DrawerContent` when your drawer content changes height at runtime like AI streaming responses, multi-step forms, search results, or dynamic lists.
|
|
467
486
|
|
|
468
487
|
```svelte
|
|
469
488
|
<script>
|
|
470
|
-
import {
|
|
489
|
+
import {
|
|
490
|
+
Drawer,
|
|
491
|
+
DrawerOverlay,
|
|
492
|
+
DrawerContent,
|
|
493
|
+
DrawerHandle
|
|
494
|
+
} from '@abhivarde/svelte-drawer';
|
|
471
495
|
|
|
472
496
|
let open = $state(false);
|
|
473
497
|
let streaming = $state(false);
|
|
474
498
|
let text = $state('');
|
|
475
499
|
|
|
476
|
-
const lines = [
|
|
477
|
-
'Sure! Here is what autoHeight does.',
|
|
478
|
-
'\n\nIt watches your content as it changes.',
|
|
479
|
-
'\n\nWhen content grows, the drawer follows automatically.',
|
|
480
|
-
'\n\nNo magic numbers. No hardcoded heights. Just works.',
|
|
481
|
-
];
|
|
482
|
-
|
|
483
500
|
async function simulate() {
|
|
484
501
|
open = true;
|
|
485
502
|
streaming = true;
|
|
486
503
|
text = '';
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
504
|
+
|
|
505
|
+
const content =
|
|
506
|
+
'Sure! Here is what autoHeight does. It watches your content with a ResizeObserver. When content grows, the drawer follows automatically. No magic numbers, no hardcoded heights, it just works smoothly with streaming UI like AI chat apps.';
|
|
507
|
+
|
|
508
|
+
for (let i = 0; i < content.length; i++) {
|
|
509
|
+
text += content[i];
|
|
510
|
+
await new Promise(r => setTimeout(r, 18));
|
|
490
511
|
}
|
|
512
|
+
|
|
491
513
|
streaming = false;
|
|
492
514
|
}
|
|
493
515
|
</script>
|
|
@@ -496,12 +518,22 @@ Use `autoHeight` on `DrawerContent` when your drawer content changes height at r
|
|
|
496
518
|
|
|
497
519
|
<Drawer bind:open>
|
|
498
520
|
<DrawerOverlay />
|
|
499
|
-
|
|
521
|
+
|
|
522
|
+
<DrawerContent
|
|
523
|
+
autoHeight
|
|
524
|
+
class="bg-gray-100 flex flex-col rounded-t-[10px] fixed bottom-0 left-0 right-0 outline-none"
|
|
525
|
+
>
|
|
500
526
|
<div class="p-4 bg-white rounded-t-[10px]">
|
|
501
527
|
<DrawerHandle class="mb-8" />
|
|
502
|
-
|
|
528
|
+
|
|
529
|
+
<p class="font-medium mb-2 text-gray-900">
|
|
530
|
+
AI Response
|
|
531
|
+
</p>
|
|
532
|
+
|
|
503
533
|
{#if text}
|
|
504
|
-
<p class="text-sm text-gray-600
|
|
534
|
+
<p class="text-sm text-gray-600 leading-relaxed">
|
|
535
|
+
{text}{streaming ? '▌' : ''}
|
|
536
|
+
</p>
|
|
505
537
|
{/if}
|
|
506
538
|
</div>
|
|
507
539
|
</DrawerContent>
|
|
@@ -512,8 +544,9 @@ Use `autoHeight` on `DrawerContent` when your drawer content changes height at r
|
|
|
512
544
|
|
|
513
545
|
- `height: auto` is applied to the drawer when `autoHeight` is true
|
|
514
546
|
- The drawer grows and shrinks naturally as content changes
|
|
515
|
-
-
|
|
516
|
-
-
|
|
547
|
+
- Perfect for AI streaming, dynamic lists, forms, and async content
|
|
548
|
+
- The slide animation remains smooth since it uses CSS transforms separately
|
|
549
|
+
- Fully compatible with snap points, portals, and existing props
|
|
517
550
|
- Zero impact on drawers that do not use `autoHeight` (opt-in, default `false`)
|
|
518
551
|
|
|
519
552
|
## Variants
|
|
@@ -544,6 +577,7 @@ Main wrapper component that manages drawer state and animations.
|
|
|
544
577
|
- `onOpenChange` (function, optional) - Callback when open state changes
|
|
545
578
|
- `direction` ('bottom' | 'top' | 'left' | 'right', default: 'bottom') - Direction from which drawer slides
|
|
546
579
|
- `closeOnEscape` (boolean, optional, default: true) - Whether Escape key closes the drawer
|
|
580
|
+
- `closeThreshold` (number, optional, default: 0.3) - How far the user must drag to dismiss (0–1). Lower = easier to close, higher = requires a longer drag.
|
|
547
581
|
- `snapPoints` (number[], optional) - Array of snap positions between 0-1
|
|
548
582
|
- `activeSnapPoint` (number, bindable, optional) - Current active snap point value
|
|
549
583
|
- `onSnapPointChange` (function, optional) - Callback fired when snap changes
|
|
@@ -15,9 +15,10 @@
|
|
|
15
15
|
onSnapPointChange = undefined,
|
|
16
16
|
portal = false,
|
|
17
17
|
portalContainer = undefined,
|
|
18
|
-
persistState = false,
|
|
19
|
-
persistKey = "default",
|
|
20
|
-
persistSnapPoint = false,
|
|
18
|
+
persistState = false,
|
|
19
|
+
persistKey = "default",
|
|
20
|
+
persistSnapPoint = false,
|
|
21
|
+
closeThreshold = 0.3,
|
|
21
22
|
children,
|
|
22
23
|
} = $props();
|
|
23
24
|
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
let previouslyFocusedElement: HTMLElement | null = null;
|
|
35
36
|
let visible = false;
|
|
36
37
|
let previousSnapPoint: number | undefined = undefined;
|
|
37
|
-
let stateLoaded = false;
|
|
38
|
+
let stateLoaded = false;
|
|
38
39
|
|
|
39
40
|
onMount(() => {
|
|
40
41
|
if (persistState && !stateLoaded) {
|
|
@@ -67,7 +68,7 @@
|
|
|
67
68
|
saveDrawerState(
|
|
68
69
|
persistKey,
|
|
69
70
|
open,
|
|
70
|
-
persistSnapPoint ? activeSnapPoint : undefined
|
|
71
|
+
persistSnapPoint ? activeSnapPoint : undefined,
|
|
71
72
|
);
|
|
72
73
|
}
|
|
73
74
|
});
|
|
@@ -171,6 +172,9 @@
|
|
|
171
172
|
get activeSnapPoint() {
|
|
172
173
|
return activeSnapPoint;
|
|
173
174
|
},
|
|
175
|
+
get closeThreshold() {
|
|
176
|
+
return closeThreshold;
|
|
177
|
+
},
|
|
174
178
|
setActiveSnapPoint(point: number) {
|
|
175
179
|
activeSnapPoint = point;
|
|
176
180
|
onSnapPointChange?.(point);
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
snapPoints?: number[];
|
|
12
12
|
activeSnapPoint?: number;
|
|
13
13
|
setActiveSnapPoint?: (point: number) => void;
|
|
14
|
+
closeThreshold: number;
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
let {
|
|
@@ -134,6 +135,7 @@
|
|
|
134
135
|
dragging = false;
|
|
135
136
|
|
|
136
137
|
const pos = drawer.drawerPosition.current;
|
|
138
|
+
const threshold = drawer.closeThreshold * 100;
|
|
137
139
|
|
|
138
140
|
if (drawer.snapPoints && drawer.snapPoints.length > 0) {
|
|
139
141
|
const nearestSnapPoint = findNearestSnapPoint(pos);
|
|
@@ -142,14 +144,14 @@
|
|
|
142
144
|
const lowestSnapPoint = Math.min(...drawer.snapPoints);
|
|
143
145
|
const lowestSnapPos = snapPointToPosition(lowestSnapPoint);
|
|
144
146
|
|
|
145
|
-
if (pos > lowestSnapPos +
|
|
147
|
+
if (pos > lowestSnapPos + threshold) {
|
|
146
148
|
drawer.closeDrawer();
|
|
147
149
|
} else {
|
|
148
150
|
drawer.drawerPosition.set(snapPos);
|
|
149
151
|
drawer.setActiveSnapPoint?.(nearestSnapPoint);
|
|
150
152
|
}
|
|
151
153
|
} else {
|
|
152
|
-
if (pos >
|
|
154
|
+
if (pos > threshold) {
|
|
153
155
|
drawer.closeDrawer();
|
|
154
156
|
} else {
|
|
155
157
|
drawer.drawerPosition.set(0);
|
package/dist/types.d.ts
CHANGED