@abhivarde/svelte-drawer 0.0.20 → 0.0.21

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
@@ -231,6 +231,43 @@ Snap points allow the drawer to rest at predefined heights, creating an iOS-like
231
231
  - Use `bind:activeSnapPoint` to programmatically control the current position
232
232
  - Use `onSnapPointChange` callback to react to snap changes
233
233
 
234
+ ### Portal Support
235
+
236
+ Render the drawer in a portal to avoid z-index conflicts in complex layouts.
237
+ ```svelte
238
+ <script>
239
+ import { Drawer, DrawerOverlay, DrawerContent, DrawerHandle } from '@abhivarde/svelte-drawer';
240
+
241
+ let open = $state(false);
242
+ </script>
243
+
244
+ <!-- Enable portal (renders at end of body) -->
245
+ <Drawer bind:open portal={true}>
246
+ <DrawerOverlay class="fixed inset-0 bg-black/40" />
247
+ <DrawerContent class="fixed bottom-0 left-0 right-0 bg-white rounded-t-lg p-4">
248
+ <DrawerHandle class="mb-8" />
249
+ <h2>Portal Drawer</h2>
250
+ <p>This drawer is rendered in a portal, preventing z-index issues.</p>
251
+ </DrawerContent>
252
+ </Drawer>
253
+
254
+ <!-- Custom portal container -->
255
+ <Drawer bind:open portal={true} portalContainer="#custom-portal">
256
+ <DrawerOverlay />
257
+ <DrawerContent>
258
+ <h2>Custom Portal</h2>
259
+ </DrawerContent>
260
+ </Drawer>
261
+
262
+ <div id="custom-portal"></div>
263
+ ```
264
+
265
+ **When to use portals:**
266
+ - Complex layouts with nested z-index contexts
267
+ - Third-party component libraries with fixed positioning
268
+ - Modals inside scrollable containers
269
+ - Preventing overflow: hidden conflicts
270
+
234
271
  ## Variants
235
272
 
236
273
  Available variants for `DrawerVariants` component:
@@ -259,9 +296,11 @@ Main wrapper component that manages drawer state and animations.
259
296
  - `onOpenChange` (function, optional) - Callback when open state changes
260
297
  - `direction` ('bottom' | 'top' | 'left' | 'right', default: 'bottom') - Direction from which drawer slides
261
298
  - `closeOnEscape` (boolean, optional, default: true) - Whether Escape key closes the drawer
262
- - `snapPoints` (number[], optional) - Array of snap positions between 0-1, where 1 is fully open (e.g., `[0.25, 0.5, 0.9]`)
299
+ - `snapPoints` (number[], optional) - Array of snap positions between 0-1
263
300
  - `activeSnapPoint` (number, bindable, optional) - Current active snap point value
264
- - `onSnapPointChange` (function, optional) - Callback fired when the drawer snaps to a different point
301
+ - `onSnapPointChange` (function, optional) - Callback fired when snap changes
302
+ - `portal` (boolean, optional, default: false) - Render drawer in a portal
303
+ - `portalContainer` (HTMLElement | string, optional) - Custom portal container element or selector
265
304
 
266
305
  ### DrawerOverlay
267
306
 
@@ -2,6 +2,7 @@
2
2
  import { Tween } from "svelte/motion";
3
3
  import { expoOut } from "svelte/easing";
4
4
  import { setContext, onMount } from "svelte";
5
+ import DrawerPortal from "./DrawerPortal.svelte";
5
6
 
6
7
  let {
7
8
  open = $bindable(false),
@@ -11,6 +12,8 @@
11
12
  snapPoints = undefined,
12
13
  activeSnapPoint = $bindable(undefined),
13
14
  onSnapPointChange = undefined,
15
+ portal = false,
16
+ portalContainer = undefined,
14
17
  children,
15
18
  } = $props();
16
19
 
@@ -143,4 +146,10 @@
143
146
  });
144
147
  </script>
145
148
 
146
- {@render children()}
149
+ {#if portal}
150
+ <DrawerPortal container={portalContainer}>
151
+ {@render children()}
152
+ </DrawerPortal>
153
+ {:else}
154
+ {@render children()}
155
+ {/if}
@@ -6,6 +6,8 @@ declare const Drawer: import("svelte").Component<{
6
6
  snapPoints?: any;
7
7
  activeSnapPoint?: any;
8
8
  onSnapPointChange?: any;
9
+ portal?: boolean;
10
+ portalContainer?: any;
9
11
  children: any;
10
12
  }, {}, "open" | "activeSnapPoint">;
11
13
  type Drawer = ReturnType<typeof Drawer>;
@@ -0,0 +1,53 @@
1
+ <script lang="ts">
2
+ import { onMount } from "svelte";
3
+
4
+ let {
5
+ children,
6
+ container = undefined,
7
+ }: {
8
+ children?: any;
9
+ container?: HTMLElement | string;
10
+ } = $props();
11
+
12
+ let portalContainer = $state<HTMLElement | null>(null);
13
+ let mounted = $state(false);
14
+
15
+ onMount(() => {
16
+ if (container) {
17
+ if (typeof container === "string") {
18
+ portalContainer = document.querySelector(container);
19
+ } else {
20
+ portalContainer = container;
21
+ }
22
+ } else {
23
+ portalContainer = document.createElement("div");
24
+ portalContainer.setAttribute("data-drawer-portal", "");
25
+ document.body.appendChild(portalContainer);
26
+ }
27
+
28
+ mounted = true;
29
+
30
+ return () => {
31
+ if (
32
+ !container &&
33
+ portalContainer &&
34
+ document.body.contains(portalContainer)
35
+ ) {
36
+ document.body.removeChild(portalContainer);
37
+ }
38
+ };
39
+ });
40
+ </script>
41
+
42
+ {#if mounted && portalContainer}
43
+ {#each [children] as child}
44
+ {@render child?.()}
45
+ {/each}
46
+ {/if}
47
+
48
+ <style>
49
+ :global([data-drawer-portal]) {
50
+ position: relative;
51
+ z-index: 9999;
52
+ }
53
+ </style>
@@ -0,0 +1,7 @@
1
+ type $$ComponentProps = {
2
+ children?: any;
3
+ container?: HTMLElement | string;
4
+ };
5
+ declare const DrawerPortal: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type DrawerPortal = ReturnType<typeof DrawerPortal>;
7
+ export default DrawerPortal;
package/dist/index.d.ts CHANGED
@@ -3,4 +3,5 @@ export { default as DrawerContent } from "./components/DrawerContent.svelte";
3
3
  export { default as DrawerOverlay } from "./components/DrawerOverlay.svelte";
4
4
  export { default as DrawerVariants } from "./components/DrawerVariants.svelte";
5
5
  export { default as DrawerHandle } from "./components/DrawerHandle.svelte";
6
- export type { DrawerProps, DrawerContentProps, DrawerOverlayProps, DrawerHandleProps, DrawerVariant, DrawerVariantsProps, } from "./types";
6
+ export { default as DrawerPortal } from "./components/DrawerPortal.svelte";
7
+ export type { DrawerProps, DrawerContentProps, DrawerOverlayProps, DrawerHandleProps, DrawerVariant, DrawerVariantsProps, DrawerPortalProps, } from "./types";
package/dist/index.js CHANGED
@@ -3,3 +3,4 @@ export { default as DrawerContent } from "./components/DrawerContent.svelte";
3
3
  export { default as DrawerOverlay } from "./components/DrawerOverlay.svelte";
4
4
  export { default as DrawerVariants } from "./components/DrawerVariants.svelte";
5
5
  export { default as DrawerHandle } from "./components/DrawerHandle.svelte";
6
+ export { default as DrawerPortal } from "./components/DrawerPortal.svelte";
package/dist/types.d.ts CHANGED
@@ -6,6 +6,8 @@ export interface DrawerProps {
6
6
  snapPoints?: number[];
7
7
  activeSnapPoint?: number;
8
8
  onSnapPointChange?: (snapPoint: number) => void;
9
+ portal?: boolean;
10
+ portalContainer?: HTMLElement | string;
9
11
  }
10
12
  export interface DrawerContentProps {
11
13
  class?: string;
@@ -17,6 +19,9 @@ export interface DrawerOverlayProps {
17
19
  export interface DrawerHandleProps {
18
20
  class?: string;
19
21
  }
22
+ export interface DrawerPortalProps {
23
+ container?: HTMLElement | string;
24
+ }
20
25
  export type DrawerVariant = "default" | "sheet" | "dialog" | "minimal" | "sidebar";
21
26
  export interface DrawerVariantsProps {
22
27
  variant?: DrawerVariant;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abhivarde/svelte-drawer",
3
- "version": "0.0.20",
3
+ "version": "0.0.21",
4
4
  "description": "A drawer component for Svelte 5, inspired by Vaul",
5
5
  "author": "Abhi Varde",
6
6
  "license": "MIT",