@abhivarde/svelte-drawer 1.0.2 → 1.0.4
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 +32 -14
- package/dist/components/DrawerContent.svelte +13 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ A drawer component for Svelte 5, inspired by [Vaul](https://github.com/emilkowal
|
|
|
21
21
|
- ✅ Fully accessible with keyboard navigation
|
|
22
22
|
- ✅ Full **TypeScript** support
|
|
23
23
|
- ✅ Customizable styling with **Tailwind CSS**
|
|
24
|
-
- ✅ **Auto height**
|
|
24
|
+
- ✅ **Auto height** for dynamic content (AI streaming, forms, dynamic lists)
|
|
25
25
|
|
|
26
26
|
## Installation
|
|
27
27
|
|
|
@@ -470,33 +470,51 @@ Use `autoHeight` on `DrawerContent` when your drawer content changes height at r
|
|
|
470
470
|
import { Drawer, DrawerOverlay, DrawerContent, DrawerHandle } from '@abhivarde/svelte-drawer';
|
|
471
471
|
|
|
472
472
|
let open = $state(false);
|
|
473
|
-
let
|
|
473
|
+
let streaming = $state(false);
|
|
474
|
+
let text = $state('');
|
|
474
475
|
|
|
475
|
-
|
|
476
|
-
|
|
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
|
+
async function simulate() {
|
|
477
484
|
open = true;
|
|
478
|
-
|
|
485
|
+
streaming = true;
|
|
486
|
+
text = '';
|
|
487
|
+
for (const line of lines) {
|
|
488
|
+
await new Promise(r => setTimeout(r, 500));
|
|
489
|
+
text += line;
|
|
490
|
+
}
|
|
491
|
+
streaming = false;
|
|
479
492
|
}
|
|
480
493
|
</script>
|
|
481
494
|
|
|
482
|
-
<button onclick={
|
|
495
|
+
<button onclick={simulate}>Ask AI</button>
|
|
483
496
|
|
|
484
497
|
<Drawer bind:open>
|
|
485
|
-
<DrawerOverlay
|
|
486
|
-
<DrawerContent autoHeight class="fixed bottom-0 left-0 right-0
|
|
487
|
-
<
|
|
488
|
-
|
|
498
|
+
<DrawerOverlay />
|
|
499
|
+
<DrawerContent autoHeight class="bg-gray-100 flex flex-col rounded-t-[10px] fixed bottom-0 left-0 right-0 outline-none">
|
|
500
|
+
<div class="p-4 bg-white rounded-t-[10px]">
|
|
501
|
+
<DrawerHandle class="mb-8" />
|
|
502
|
+
<p class="font-medium mb-2 text-gray-900">AI Response</p>
|
|
503
|
+
{#if text}
|
|
504
|
+
<p class="text-sm text-gray-600 whitespace-pre-wrap leading-relaxed">{text}{streaming ? '▌' : ''}</p>
|
|
505
|
+
{/if}
|
|
506
|
+
</div>
|
|
489
507
|
</DrawerContent>
|
|
490
508
|
</Drawer>
|
|
491
509
|
```
|
|
492
510
|
|
|
493
511
|
**How it works:**
|
|
494
512
|
|
|
495
|
-
-
|
|
496
|
-
-
|
|
497
|
-
- The
|
|
513
|
+
- `height: auto` is applied to the drawer when `autoHeight` is true
|
|
514
|
+
- The drawer grows and shrinks naturally as content changes
|
|
515
|
+
- The slide-in animation is unaffected since it runs via CSS transform separately
|
|
498
516
|
- Fully compatible with snap points, portals, and all existing props
|
|
499
|
-
- Zero impact on drawers that
|
|
517
|
+
- Zero impact on drawers that do not use `autoHeight` (opt-in, default `false`)
|
|
500
518
|
|
|
501
519
|
## Variants
|
|
502
520
|
|
|
@@ -189,19 +189,17 @@
|
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
let contentInnerRef = $state<HTMLElement | null>(null);
|
|
193
|
-
let measuredHeight = $state<number | null>(null);
|
|
194
|
-
|
|
195
192
|
$effect(() => {
|
|
196
|
-
if (
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
193
|
+
if (drawer.open && trapFocus && contentElement) {
|
|
194
|
+
tick().then(() => {
|
|
195
|
+
const focusable = getFocusableElements();
|
|
196
|
+
if (focusable[0]) {
|
|
197
|
+
focusable[0].focus({ preventScroll: true });
|
|
198
|
+
} else {
|
|
199
|
+
contentElement?.focus({ preventScroll: true });
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
205
203
|
});
|
|
206
204
|
|
|
207
205
|
onMount(() => {
|
|
@@ -216,9 +214,8 @@
|
|
|
216
214
|
<div
|
|
217
215
|
bind:this={contentElement}
|
|
218
216
|
class={className}
|
|
219
|
-
style="transform: {getTransform()}; z-index: 50; touch-action: none;{autoHeight
|
|
220
|
-
|
|
221
|
-
? ` height: ${measuredHeight}px; transition: height 0.25s cubic-bezier(0.4,0,0.2,1);`
|
|
217
|
+
style="transform: {getTransform()}; z-index: 50; touch-action: none;{autoHeight
|
|
218
|
+
? ' height: auto;'
|
|
222
219
|
: ''}"
|
|
223
220
|
tabindex="-1"
|
|
224
221
|
role="dialog"
|
|
@@ -227,8 +224,6 @@
|
|
|
227
224
|
ontouchstart={onPointerDown}
|
|
228
225
|
{...restProps}
|
|
229
226
|
>
|
|
230
|
-
|
|
231
|
-
{@render children()}
|
|
232
|
-
</div>
|
|
227
|
+
{@render children()}
|
|
233
228
|
</div>
|
|
234
229
|
{/if}
|