@abhivarde/svelte-drawer 0.0.23 → 0.0.25
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 +100 -1
- package/dist/components/Drawer.svelte +41 -8
- package/dist/components/Drawer.svelte.d.ts +3 -0
- package/dist/components/DrawerOverlay.svelte +43 -29
- package/dist/components/DrawerOverlay.svelte.d.ts +2 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/types.d.ts +4 -0
- package/dist/utils/storage.d.ts +8 -0
- package/dist/utils/storage.js +39 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -55,6 +55,42 @@ npm install @abhivarde/svelte-drawer
|
|
|
55
55
|
</Drawer>
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
+
|
|
59
|
+
### Backdrop Blur
|
|
60
|
+
|
|
61
|
+
Add a premium blur effect to the overlay background:
|
|
62
|
+
```svelte
|
|
63
|
+
<script>
|
|
64
|
+
import { Drawer, DrawerOverlay, DrawerContent, DrawerHandle } from '@abhivarde/svelte-drawer';
|
|
65
|
+
|
|
66
|
+
let open = $state(false);
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<Drawer bind:open>
|
|
70
|
+
<!-- Default medium blur -->
|
|
71
|
+
<DrawerOverlay blur class="fixed inset-0 bg-black/40" />
|
|
72
|
+
|
|
73
|
+
<!-- Or specify blur intensity -->
|
|
74
|
+
<!-- <DrawerOverlay blur="sm" class="fixed inset-0 bg-black/40" /> -->
|
|
75
|
+
<!-- <DrawerOverlay blur="lg" class="fixed inset-0 bg-black/40" /> -->
|
|
76
|
+
<!-- <DrawerOverlay blur="xl" class="fixed inset-0 bg-black/40" /> -->
|
|
77
|
+
|
|
78
|
+
<DrawerContent class="fixed bottom-0 left-0 right-0 bg-white rounded-t-lg p-4">
|
|
79
|
+
<DrawerHandle class="mb-8" />
|
|
80
|
+
<h2>Blurred Backdrop</h2>
|
|
81
|
+
<p>Notice the premium blur effect behind this drawer.</p>
|
|
82
|
+
</DrawerContent>
|
|
83
|
+
</Drawer>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Available blur intensities:**
|
|
87
|
+
- `blur={true}` or `blur="md"` - Medium blur (default)
|
|
88
|
+
- `blur="sm"` - Small blur
|
|
89
|
+
- `blur="lg"` - Large blur
|
|
90
|
+
- `blur="xl"` - Extra large blur
|
|
91
|
+
- `blur="2xl"` - 2x extra large blur
|
|
92
|
+
- `blur="3xl"` - 3x extra large blur
|
|
93
|
+
|
|
58
94
|
### Side Drawer
|
|
59
95
|
|
|
60
96
|
```svelte
|
|
@@ -362,6 +398,61 @@ Optional pre-styled header and footer components for quick setup.
|
|
|
362
398
|
|
|
363
399
|
**Note:** These components are **optional**. You can still build custom headers and footers using plain HTML/Svelte markup without importing these components.
|
|
364
400
|
|
|
401
|
+
### Persistent State
|
|
402
|
+
|
|
403
|
+
Automatically save and restore drawer state across page reloads.
|
|
404
|
+
```svelte
|
|
405
|
+
<script>
|
|
406
|
+
import { Drawer, DrawerOverlay, DrawerContent } from '@abhivarde/svelte-drawer';
|
|
407
|
+
|
|
408
|
+
let open = $state(false);
|
|
409
|
+
</script>
|
|
410
|
+
|
|
411
|
+
<Drawer
|
|
412
|
+
bind:open
|
|
413
|
+
persistState={true}
|
|
414
|
+
persistKey="main-drawer"
|
|
415
|
+
>
|
|
416
|
+
<DrawerOverlay />
|
|
417
|
+
<DrawerContent class="...">
|
|
418
|
+
<h2>This drawer remembers if it was open!</h2>
|
|
419
|
+
<p>Reload the page and it will restore its state.</p>
|
|
420
|
+
</DrawerContent>
|
|
421
|
+
</Drawer>
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
**With snap points:**
|
|
425
|
+
```svelte
|
|
426
|
+
<Drawer
|
|
427
|
+
bind:open
|
|
428
|
+
snapPoints={[0.25, 0.5, 0.9]}
|
|
429
|
+
bind:activeSnapPoint
|
|
430
|
+
persistState={true}
|
|
431
|
+
persistKey="snap-drawer"
|
|
432
|
+
persistSnapPoint={true}
|
|
433
|
+
>
|
|
434
|
+
<DrawerOverlay />
|
|
435
|
+
<DrawerContent class="...">
|
|
436
|
+
<h2>Position is saved too!</h2>
|
|
437
|
+
<p>The snap point will be restored on reload.</p>
|
|
438
|
+
</DrawerContent>
|
|
439
|
+
</Drawer>
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
**Clear saved state programmatically:**
|
|
443
|
+
```svelte
|
|
444
|
+
<script>
|
|
445
|
+
import { clearDrawerState } from '@abhivarde/svelte-drawer';
|
|
446
|
+
|
|
447
|
+
function resetDrawer() {
|
|
448
|
+
clearDrawerState('main-drawer');
|
|
449
|
+
// Drawer will reset to default state on next load
|
|
450
|
+
}
|
|
451
|
+
</script>
|
|
452
|
+
|
|
453
|
+
<button onclick={resetDrawer}>Reset Drawer State</button>
|
|
454
|
+
```
|
|
455
|
+
|
|
365
456
|
## Variants
|
|
366
457
|
|
|
367
458
|
Available variants for `DrawerVariants` component:
|
|
@@ -395,6 +486,9 @@ Main wrapper component that manages drawer state and animations.
|
|
|
395
486
|
- `onSnapPointChange` (function, optional) - Callback fired when snap changes
|
|
396
487
|
- `portal` (boolean, optional, default: false) - Render drawer in a portal
|
|
397
488
|
- `portalContainer` (HTMLElement | string, optional) - Custom portal container element or selector
|
|
489
|
+
- `persistState` (boolean, optional, default: false) - Enable persistent state
|
|
490
|
+
- `persistKey` (string, optional, default: "default") - Unique identifier for this drawer
|
|
491
|
+
- `persistSnapPoint` (boolean, optional, default: false) - Whether to persist snap point position
|
|
398
492
|
|
|
399
493
|
### DrawerOverlay
|
|
400
494
|
|
|
@@ -403,6 +497,7 @@ Overlay component that appears behind the drawer.
|
|
|
403
497
|
**Props:**
|
|
404
498
|
|
|
405
499
|
- `class` (string, optional) - CSS classes for styling
|
|
500
|
+
- `blur` (boolean | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl', optional) - Enable backdrop blur effect
|
|
406
501
|
|
|
407
502
|
### DrawerContent
|
|
408
503
|
|
|
@@ -487,6 +582,10 @@ Optional pre-styled footer component.
|
|
|
487
582
|
|
|
488
583
|
Visit [drawer.abhivarde.in](https://drawer.abhivarde.in) to see live examples.
|
|
489
584
|
|
|
585
|
+
## Star History
|
|
586
|
+
|
|
587
|
+
[](https://star-history.com/#AbhiVarde/svelte-drawer&Date)
|
|
588
|
+
|
|
490
589
|
## License
|
|
491
590
|
|
|
492
591
|
This project is licensed under the MIT License.
|
|
@@ -494,4 +593,4 @@ See the [LICENSE](./LICENSE) file for details.
|
|
|
494
593
|
|
|
495
594
|
## Credits
|
|
496
595
|
|
|
497
|
-
Inspired by [Vaul](https://github.com/emilkowalski/vaul) by Emil Kowalski.
|
|
596
|
+
Inspired by [Vaul](https://github.com/emilkowalski/vaul) by Emil Kowalski.
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { expoOut } from "svelte/easing";
|
|
4
4
|
import { setContext, onMount } from "svelte";
|
|
5
5
|
import DrawerPortal from "./DrawerPortal.svelte";
|
|
6
|
+
import { saveDrawerState, loadDrawerState } from "../utils/storage"; // NEW
|
|
6
7
|
|
|
7
8
|
let {
|
|
8
9
|
open = $bindable(false),
|
|
@@ -14,6 +15,9 @@
|
|
|
14
15
|
onSnapPointChange = undefined,
|
|
15
16
|
portal = false,
|
|
16
17
|
portalContainer = undefined,
|
|
18
|
+
persistState = false,
|
|
19
|
+
persistKey = "default",
|
|
20
|
+
persistSnapPoint = false,
|
|
17
21
|
children,
|
|
18
22
|
} = $props();
|
|
19
23
|
|
|
@@ -30,6 +34,43 @@
|
|
|
30
34
|
let previouslyFocusedElement: HTMLElement | null = null;
|
|
31
35
|
let visible = false;
|
|
32
36
|
let previousSnapPoint: number | undefined = undefined;
|
|
37
|
+
let stateLoaded = false;
|
|
38
|
+
|
|
39
|
+
onMount(() => {
|
|
40
|
+
if (persistState && !stateLoaded) {
|
|
41
|
+
const savedState = loadDrawerState(persistKey);
|
|
42
|
+
|
|
43
|
+
if (savedState) {
|
|
44
|
+
open = savedState.open;
|
|
45
|
+
|
|
46
|
+
if (
|
|
47
|
+
persistSnapPoint &&
|
|
48
|
+
savedState.snapPoint !== undefined &&
|
|
49
|
+
snapPoints
|
|
50
|
+
) {
|
|
51
|
+
activeSnapPoint = savedState.snapPoint;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
stateLoaded = true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
window.addEventListener("keydown", handleKeydown);
|
|
59
|
+
return () => {
|
|
60
|
+
window.removeEventListener("keydown", handleKeydown);
|
|
61
|
+
document.body.style.overflow = "";
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
$effect(() => {
|
|
66
|
+
if (persistState && stateLoaded) {
|
|
67
|
+
saveDrawerState(
|
|
68
|
+
persistKey,
|
|
69
|
+
open,
|
|
70
|
+
persistSnapPoint ? activeSnapPoint : undefined
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
33
74
|
|
|
34
75
|
$effect(() => {
|
|
35
76
|
if (
|
|
@@ -108,14 +149,6 @@
|
|
|
108
149
|
}
|
|
109
150
|
}
|
|
110
151
|
|
|
111
|
-
onMount(() => {
|
|
112
|
-
window.addEventListener("keydown", handleKeydown);
|
|
113
|
-
return () => {
|
|
114
|
-
window.removeEventListener("keydown", handleKeydown);
|
|
115
|
-
document.body.style.overflow = "";
|
|
116
|
-
};
|
|
117
|
-
});
|
|
118
|
-
|
|
119
152
|
setContext("drawer", {
|
|
120
153
|
get open() {
|
|
121
154
|
return open;
|
|
@@ -8,6 +8,9 @@ declare const Drawer: import("svelte").Component<{
|
|
|
8
8
|
onSnapPointChange?: any;
|
|
9
9
|
portal?: boolean;
|
|
10
10
|
portalContainer?: any;
|
|
11
|
+
persistState?: boolean;
|
|
12
|
+
persistKey?: string;
|
|
13
|
+
persistSnapPoint?: boolean;
|
|
11
14
|
children: any;
|
|
12
15
|
}, {}, "open" | "activeSnapPoint">;
|
|
13
16
|
type Drawer = ReturnType<typeof Drawer>;
|
|
@@ -1,33 +1,47 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
2
|
+
import { getContext } from "svelte";
|
|
3
|
+
|
|
4
|
+
let { class: className = "", blur = false, ...restProps } = $props();
|
|
5
|
+
|
|
6
|
+
const drawer = getContext("drawer");
|
|
7
|
+
|
|
8
|
+
const blurClass = $derived(() => {
|
|
9
|
+
if (!blur) return "";
|
|
10
|
+
|
|
11
|
+
if (blur === true) return "backdrop-blur-md";
|
|
12
|
+
|
|
13
|
+
const blurMap = {
|
|
14
|
+
sm: "backdrop-blur-sm",
|
|
15
|
+
md: "backdrop-blur-md",
|
|
16
|
+
lg: "backdrop-blur-lg",
|
|
17
|
+
xl: "backdrop-blur-xl",
|
|
18
|
+
"2xl": "backdrop-blur-2xl",
|
|
19
|
+
"3xl": "backdrop-blur-3xl",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
return blurMap[blur] || "backdrop-blur-md";
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {KeyboardEvent} e
|
|
27
|
+
*/
|
|
28
|
+
function handleKeydown(e) {
|
|
29
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
30
|
+
e.preventDefault();
|
|
31
|
+
drawer.closeDrawer();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
20
34
|
</script>
|
|
21
35
|
|
|
22
36
|
{#if drawer.open}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
{/if}
|
|
37
|
+
<div
|
|
38
|
+
class="fixed inset-0 bg-black/40 cursor-pointer {blurClass()} {className}"
|
|
39
|
+
style="opacity: {drawer.overlayOpacity.current}; z-index: 40;"
|
|
40
|
+
onclick={drawer.closeDrawer}
|
|
41
|
+
onkeydown={handleKeydown}
|
|
42
|
+
role="button"
|
|
43
|
+
tabindex="0"
|
|
44
|
+
aria-label="Close drawer"
|
|
45
|
+
{...restProps}
|
|
46
|
+
></div>
|
|
47
|
+
{/if}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,4 +6,5 @@ export { default as DrawerHandle } from "./components/DrawerHandle.svelte";
|
|
|
6
6
|
export { default as DrawerPortal } from "./components/DrawerPortal.svelte";
|
|
7
7
|
export { default as DrawerHeader } from "./components/DrawerHeader.svelte";
|
|
8
8
|
export { default as DrawerFooter } from "./components/DrawerFooter.svelte";
|
|
9
|
+
export { saveDrawerState, loadDrawerState, clearDrawerState, } from "./utils/storage";
|
|
9
10
|
export type { DrawerProps, DrawerContentProps, DrawerOverlayProps, DrawerHandleProps, DrawerVariant, DrawerVariantsProps, DrawerPortalProps, DrawerHeaderProps, DrawerFooterProps, } from "./types";
|
package/dist/index.js
CHANGED
|
@@ -6,3 +6,4 @@ export { default as DrawerHandle } from "./components/DrawerHandle.svelte";
|
|
|
6
6
|
export { default as DrawerPortal } from "./components/DrawerPortal.svelte";
|
|
7
7
|
export { default as DrawerHeader } from "./components/DrawerHeader.svelte";
|
|
8
8
|
export { default as DrawerFooter } from "./components/DrawerFooter.svelte";
|
|
9
|
+
export { saveDrawerState, loadDrawerState, clearDrawerState, } from "./utils/storage";
|
package/dist/types.d.ts
CHANGED
|
@@ -8,6 +8,9 @@ export interface DrawerProps {
|
|
|
8
8
|
onSnapPointChange?: (snapPoint: number) => void;
|
|
9
9
|
portal?: boolean;
|
|
10
10
|
portalContainer?: HTMLElement | string;
|
|
11
|
+
persistState?: boolean;
|
|
12
|
+
persistKey?: string;
|
|
13
|
+
persistSnapPoint?: boolean;
|
|
11
14
|
}
|
|
12
15
|
export interface DrawerContentProps {
|
|
13
16
|
class?: string;
|
|
@@ -15,6 +18,7 @@ export interface DrawerContentProps {
|
|
|
15
18
|
}
|
|
16
19
|
export interface DrawerOverlayProps {
|
|
17
20
|
class?: string;
|
|
21
|
+
blur?: boolean | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl";
|
|
18
22
|
}
|
|
19
23
|
export interface DrawerHandleProps {
|
|
20
24
|
class?: string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface DrawerState {
|
|
2
|
+
open: boolean;
|
|
3
|
+
snapPoint?: number;
|
|
4
|
+
}
|
|
5
|
+
export declare function saveDrawerState(key: string, open: boolean, snapPoint?: number): void;
|
|
6
|
+
export declare function loadDrawerState(key: string): DrawerState | null;
|
|
7
|
+
export declare function clearDrawerState(key: string): void;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const STORAGE_PREFIX = "svelte-drawer-";
|
|
2
|
+
export function saveDrawerState(key, open, snapPoint) {
|
|
3
|
+
if (typeof window === "undefined")
|
|
4
|
+
return;
|
|
5
|
+
try {
|
|
6
|
+
const state = { open };
|
|
7
|
+
if (snapPoint !== undefined) {
|
|
8
|
+
state.snapPoint = snapPoint;
|
|
9
|
+
}
|
|
10
|
+
localStorage.setItem(`${STORAGE_PREFIX}${key}`, JSON.stringify(state));
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
console.warn("Failed to save drawer state:", error);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function loadDrawerState(key) {
|
|
17
|
+
if (typeof window === "undefined")
|
|
18
|
+
return null;
|
|
19
|
+
try {
|
|
20
|
+
const stored = localStorage.getItem(`${STORAGE_PREFIX}${key}`);
|
|
21
|
+
if (!stored)
|
|
22
|
+
return null;
|
|
23
|
+
return JSON.parse(stored);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
console.warn("Failed to load drawer state:", error);
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function clearDrawerState(key) {
|
|
31
|
+
if (typeof window === "undefined")
|
|
32
|
+
return;
|
|
33
|
+
try {
|
|
34
|
+
localStorage.removeItem(`${STORAGE_PREFIX}${key}`);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.warn("Failed to clear drawer state:", error);
|
|
38
|
+
}
|
|
39
|
+
}
|