@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 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
+ [![Star History Chart](https://api.star-history.com/svg?repos=AbhiVarde/svelte-drawer&type=Date)](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
- import { getContext } from 'svelte';
3
-
4
- let {
5
- class: className = '',
6
- ...restProps
7
- } = $props();
8
-
9
- const drawer = getContext('drawer');
10
-
11
- /**
12
- * @param {KeyboardEvent} e
13
- */
14
- function handleKeydown(e) {
15
- if (e.key === 'Enter' || e.key === ' ') {
16
- e.preventDefault();
17
- drawer.closeDrawer();
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
- <div
24
- class="fixed inset-0 bg-black/40 cursor-pointer {className}"
25
- style="opacity: {drawer.overlayOpacity.current}; z-index: 40;"
26
- onclick={drawer.closeDrawer}
27
- onkeydown={handleKeydown}
28
- role="button"
29
- tabindex="0"
30
- aria-label="Close drawer"
31
- {...restProps}
32
- ></div>
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}
@@ -5,7 +5,9 @@ type DrawerOverlay = {
5
5
  };
6
6
  declare const DrawerOverlay: import("svelte").Component<{
7
7
  class?: string;
8
+ blur?: boolean;
8
9
  } & Record<string, any>, {}, "">;
9
10
  type $$ComponentProps = {
10
11
  class?: string;
12
+ blur?: boolean;
11
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;
@@ -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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abhivarde/svelte-drawer",
3
- "version": "0.0.23",
3
+ "version": "0.0.25",
4
4
  "description": "A drawer component for Svelte 5, inspired by Vaul",
5
5
  "author": "Abhi Varde",
6
6
  "license": "MIT",