@abhivarde/svelte-drawer 0.0.24 → 1.0.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.
- package/README.md +58 -0
- package/dist/components/Drawer.svelte +41 -8
- package/dist/components/Drawer.svelte.d.ts +3 -0
- package/dist/components/DrawerOverlay.svelte +11 -10
- package/dist/components/DrawerOverlay.svelte.d.ts +3 -12
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/types.d.ts +3 -0
- package/dist/utils/storage.d.ts +8 -0
- package/dist/utils/storage.js +39 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -398,6 +398,61 @@ Optional pre-styled header and footer components for quick setup.
|
|
|
398
398
|
|
|
399
399
|
**Note:** These components are **optional**. You can still build custom headers and footers using plain HTML/Svelte markup without importing these components.
|
|
400
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
|
+
|
|
401
456
|
## Variants
|
|
402
457
|
|
|
403
458
|
Available variants for `DrawerVariants` component:
|
|
@@ -431,6 +486,9 @@ Main wrapper component that manages drawer state and animations.
|
|
|
431
486
|
- `onSnapPointChange` (function, optional) - Callback fired when snap changes
|
|
432
487
|
- `portal` (boolean, optional, default: false) - Render drawer in a portal
|
|
433
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
|
|
434
492
|
|
|
435
493
|
### DrawerOverlay
|
|
436
494
|
|
|
@@ -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,16 +1,20 @@
|
|
|
1
|
-
<script>
|
|
1
|
+
<script lang="ts">
|
|
2
2
|
import { getContext } from "svelte";
|
|
3
|
+
import type { DrawerOverlayProps } from "../types";
|
|
3
4
|
|
|
4
|
-
let {
|
|
5
|
+
let {
|
|
6
|
+
class: className = "",
|
|
7
|
+
blur = false,
|
|
8
|
+
...restProps
|
|
9
|
+
}: DrawerOverlayProps = $props();
|
|
5
10
|
|
|
6
|
-
const drawer = getContext("drawer");
|
|
11
|
+
const drawer = getContext<any>("drawer");
|
|
7
12
|
|
|
8
13
|
const blurClass = $derived(() => {
|
|
9
14
|
if (!blur) return "";
|
|
10
|
-
|
|
11
15
|
if (blur === true) return "backdrop-blur-md";
|
|
12
16
|
|
|
13
|
-
const blurMap = {
|
|
17
|
+
const blurMap: Record<string, string> = {
|
|
14
18
|
sm: "backdrop-blur-sm",
|
|
15
19
|
md: "backdrop-blur-md",
|
|
16
20
|
lg: "backdrop-blur-lg",
|
|
@@ -19,13 +23,10 @@
|
|
|
19
23
|
"3xl": "backdrop-blur-3xl",
|
|
20
24
|
};
|
|
21
25
|
|
|
22
|
-
return blurMap[blur] || "backdrop-blur-md";
|
|
26
|
+
return blurMap[blur as string] || "backdrop-blur-md";
|
|
23
27
|
});
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
* @param {KeyboardEvent} e
|
|
27
|
-
*/
|
|
28
|
-
function handleKeydown(e) {
|
|
29
|
+
function handleKeydown(e: KeyboardEvent) {
|
|
29
30
|
if (e.key === "Enter" || e.key === " ") {
|
|
30
31
|
e.preventDefault();
|
|
31
32
|
drawer.closeDrawer();
|
|
@@ -1,13 +1,4 @@
|
|
|
1
|
+
import type { DrawerOverlayProps } from "../types";
|
|
2
|
+
declare const DrawerOverlay: import("svelte").Component<DrawerOverlayProps, {}, "">;
|
|
3
|
+
type DrawerOverlay = ReturnType<typeof DrawerOverlay>;
|
|
1
4
|
export default DrawerOverlay;
|
|
2
|
-
type DrawerOverlay = {
|
|
3
|
-
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
-
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
-
};
|
|
6
|
-
declare const DrawerOverlay: import("svelte").Component<{
|
|
7
|
-
class?: string;
|
|
8
|
-
blur?: boolean;
|
|
9
|
-
} & Record<string, any>, {}, "">;
|
|
10
|
-
type $$ComponentProps = {
|
|
11
|
-
class?: string;
|
|
12
|
-
blur?: boolean;
|
|
13
|
-
} & Record<string, any>;
|
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;
|
|
@@ -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
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abhivarde/svelte-drawer",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "A drawer component for Svelte 5, inspired by Vaul",
|
|
5
5
|
"author": "Abhi Varde",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,18 +29,18 @@
|
|
|
29
29
|
"!dist/**/*.spec.*"
|
|
30
30
|
],
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"svelte": "^5.
|
|
32
|
+
"svelte": "^5.46.4"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@sveltejs/adapter-auto": "^7.0.0",
|
|
36
|
-
"@sveltejs/kit": "^2.
|
|
36
|
+
"@sveltejs/kit": "^2.53.0",
|
|
37
37
|
"@sveltejs/package": "^2.5.7",
|
|
38
|
-
"@sveltejs/vite-plugin-svelte": "^
|
|
38
|
+
"@sveltejs/vite-plugin-svelte": "^7.0.0",
|
|
39
39
|
"publint": "^0.2.12",
|
|
40
|
-
"svelte": "^5.
|
|
40
|
+
"svelte": "^5.46.4",
|
|
41
41
|
"svelte-check": "^4.3.4",
|
|
42
42
|
"typescript": "^5.9.3",
|
|
43
|
-
"vite": "^
|
|
43
|
+
"vite": "^8.0.0"
|
|
44
44
|
},
|
|
45
45
|
"svelte": "./dist/index.js",
|
|
46
46
|
"types": "./dist/index.d.ts",
|