@abhivarde/svelte-drawer 0.0.7 → 0.0.8

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.
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { Tween } from "svelte/motion";
3
- import { cubicOut } from "svelte/easing";
3
+ import { expoOut } from "svelte/easing";
4
4
  import { setContext, onMount } from "svelte";
5
5
 
6
6
  let {
@@ -11,21 +11,31 @@
11
11
  children,
12
12
  } = $props();
13
13
 
14
- let overlayOpacity = new Tween(0, { duration: 300, easing: cubicOut });
15
- let drawerPosition = new Tween(100, { duration: 300, easing: cubicOut });
14
+ let overlayOpacity = new Tween(0, {
15
+ duration: 150,
16
+ easing: expoOut,
17
+ });
18
+
19
+ let drawerPosition = new Tween(100, {
20
+ duration: 220,
21
+ easing: expoOut,
22
+ });
23
+
16
24
  let previouslyFocusedElement: HTMLElement | null = null;
17
25
 
26
+ let visible = false;
27
+
18
28
  $effect(() => {
19
29
  if (open) {
30
+ visible = true;
20
31
  previouslyFocusedElement = document.activeElement as HTMLElement;
21
-
22
32
  document.body.style.overflow = "hidden";
23
33
 
24
34
  overlayOpacity.set(1);
25
35
  drawerPosition.set(0);
26
- } else {
27
- overlayOpacity.set(0);
28
- drawerPosition.set(100);
36
+ } else if (visible) {
37
+ overlayOpacity.set(0, { duration: 120 });
38
+ drawerPosition.set(100, { duration: 180 });
29
39
 
30
40
  document.body.style.overflow = "";
31
41
 
@@ -33,12 +43,16 @@
33
43
  previouslyFocusedElement.focus();
34
44
  previouslyFocusedElement = null;
35
45
  }
46
+
47
+ setTimeout(() => {
48
+ visible = false;
49
+ }, 180);
36
50
  }
37
51
  });
38
52
 
39
53
  function closeDrawer() {
40
54
  open = false;
41
- if (onOpenChange) onOpenChange(false);
55
+ onOpenChange?.(false);
42
56
  }
43
57
 
44
58
  function handleKeydown(e: KeyboardEvent) {
@@ -60,6 +74,9 @@
60
74
  get open() {
61
75
  return open;
62
76
  },
77
+ get visible() {
78
+ return visible;
79
+ },
63
80
  get overlayOpacity() {
64
81
  return overlayOpacity;
65
82
  },
@@ -3,8 +3,9 @@
3
3
 
4
4
  type DrawerContext = {
5
5
  open: boolean;
6
- overlayOpacity: { current: number; set: (v: number) => void };
7
- drawerPosition: { current: number; set: (v: number) => void };
6
+ visible: boolean;
7
+ overlayOpacity: { current: number; set: (v: number, opts?: any) => void };
8
+ drawerPosition: { current: number; set: (v: number, opts?: any) => void };
8
9
  direction: "bottom" | "top" | "left" | "right";
9
10
  closeDrawer: () => void;
10
11
  };
@@ -33,8 +34,6 @@
33
34
  return `translateX(-${pos}%)`;
34
35
  case "right":
35
36
  return `translateX(${pos}%)`;
36
- default:
37
- return `translateY(${pos}%)`;
38
37
  }
39
38
  }
40
39
 
@@ -90,9 +89,8 @@
90
89
  document.body.style.cursor = "default";
91
90
 
92
91
  const pos = drawer.drawerPosition.current;
93
- const deltaThreshold = 30;
94
92
 
95
- if (pos > deltaThreshold) {
93
+ if (pos > 30) {
96
94
  drawer.closeDrawer();
97
95
  } else {
98
96
  drawer.drawerPosition.set(0);
@@ -104,53 +102,36 @@
104
102
 
105
103
  function getFocusableElements(): HTMLElement[] {
106
104
  if (!contentElement) return [];
107
-
108
- const focusableSelectors = [
109
- "a[href]",
110
- "button:not([disabled])",
111
- "textarea:not([disabled])",
112
- "input:not([disabled])",
113
- "select:not([disabled])",
114
- '[tabindex]:not([tabindex="-1"])',
115
- ];
116
-
117
105
  return Array.from(
118
- contentElement.querySelectorAll(focusableSelectors.join(","))
106
+ contentElement.querySelectorAll(
107
+ 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
108
+ )
119
109
  ) as HTMLElement[];
120
110
  }
121
111
 
122
112
  function handleFocusTrap(e: KeyboardEvent) {
123
- if (!trapFocus || !drawer.open) return;
124
- if (e.key !== "Tab") return;
113
+ if (!trapFocus || !drawer.open || e.key !== "Tab") return;
125
114
 
126
- const focusableElements = getFocusableElements();
127
- if (focusableElements.length === 0) return;
115
+ const focusable = getFocusableElements();
116
+ if (!focusable.length) return;
128
117
 
129
- const firstElement = focusableElements[0];
130
- const lastElement = focusableElements[focusableElements.length - 1];
118
+ const first = focusable[0];
119
+ const last = focusable[focusable.length - 1];
131
120
 
132
- if (e.shiftKey) {
133
- if (document.activeElement === firstElement) {
134
- e.preventDefault();
135
- lastElement.focus();
136
- }
137
- } else {
138
- if (document.activeElement === lastElement) {
139
- e.preventDefault();
140
- firstElement.focus();
141
- }
121
+ if (e.shiftKey && document.activeElement === first) {
122
+ e.preventDefault();
123
+ last.focus();
124
+ } else if (!e.shiftKey && document.activeElement === last) {
125
+ e.preventDefault();
126
+ first.focus();
142
127
  }
143
128
  }
144
129
 
145
130
  $effect(() => {
146
131
  if (drawer.open && trapFocus && contentElement) {
147
132
  tick().then(() => {
148
- const focusableElements = getFocusableElements();
149
- if (focusableElements.length > 0) {
150
- focusableElements[0].focus();
151
- } else {
152
- contentElement?.focus();
153
- }
133
+ const focusable = getFocusableElements();
134
+ (focusable[0] ?? contentElement)?.focus();
154
135
  });
155
136
  }
156
137
  });
@@ -163,11 +144,11 @@
163
144
  });
164
145
  </script>
165
146
 
166
- {#if drawer.open}
147
+ {#if drawer.open || drawer.visible}
167
148
  <div
168
149
  bind:this={contentElement}
169
150
  class={className}
170
- style="transform: {getTransform()}; z-index: 50; cursor: grab; transition: transform 300ms cubic-bezier(0.33, 1, 0.68, 1);"
151
+ style="transform: {getTransform()}; z-index: 50; cursor: grab;"
171
152
  onpointerdown={onPointerDown}
172
153
  tabindex="-1"
173
154
  role="dialog"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abhivarde/svelte-drawer",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "A drawer component for Svelte 5, inspired by Vaul",
5
5
  "author": "Abhi Varde",
6
6
  "license": "MIT",