@johly/vaul-svelte 1.0.0-next.11 → 1.0.0-next.12

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.
@@ -6,11 +6,14 @@
6
6
  import { CLOSE_THRESHOLD, SCROLL_LOCK_TIMEOUT } from "../../internal/constants.js";
7
7
  import { useDrawerRoot } from "../../use-drawer-root.svelte.js";
8
8
  import type { ParentDrawerState } from "../../types.js";
9
+ import {
10
+ registerDrawer,
11
+ unregisterDrawer,
12
+ getCurrentParentDrawer,
13
+ } from "../../drawer-registry.js";
9
14
 
10
15
  let {
11
16
  open = $bindable(false),
12
- drawerState = $bindable(),
13
- parentDrawer,
14
17
  onOpenChange = noop,
15
18
  onDrag: onDragProp = noop,
16
19
  onRelease: onReleaseProp = noop,
@@ -38,35 +41,47 @@
38
41
  autoFocus = false,
39
42
  disablePreventScroll = true,
40
43
  ...restProps
41
- }: RootProps & {
42
- drawerState?: ParentDrawerState;
43
- parentDrawer?: ParentDrawerState;
44
- } = $props();
44
+ }: RootProps = $props();
45
+
46
+ // Track the auto-detected parent drawer
47
+ // If drawer starts open, try to auto-detect immediately
48
+ const initialParent = open && !nested ? getCurrentParentDrawer() : undefined;
49
+ let resolvedParentDrawer = $state<ParentDrawerState | undefined>(initialParent);
50
+
51
+ // Auto-detect parent when opening (for drawers that open after mount)
52
+ let wasOpen = open;
53
+ $effect.pre(() => {
54
+ // Detect parent on open transition (false -> true)
55
+ if (open && !wasOpen && !nested) {
56
+ resolvedParentDrawer = getCurrentParentDrawer();
57
+ }
58
+ wasOpen = open;
59
+ });
45
60
 
46
- // When parentDrawer is provided, this drawer behaves as nested
47
- const isNestedViaParent = $derived(!!parentDrawer);
61
+ // When parentDrawer is provided or auto-detected, this drawer behaves as nested
62
+ const isNestedViaParent = $derived(!!resolvedParentDrawer);
48
63
  const effectiveNested = $derived(nested || isNestedViaParent);
49
64
 
50
65
  // Wrap onDrag to also notify parent drawer
51
66
  function onDrag(event: PointerEvent, percentageDragged: number) {
52
67
  onDragProp(event, percentageDragged);
53
- if (parentDrawer) {
54
- parentDrawer.onNestedDrag(event, percentageDragged);
68
+ if (resolvedParentDrawer) {
69
+ resolvedParentDrawer.onNestedDrag(event, percentageDragged);
55
70
  }
56
71
  }
57
72
 
58
73
  // Wrap onRelease to also notify parent drawer
59
74
  function onRelease(event: PointerEvent, isOpen: boolean) {
60
75
  onReleaseProp(event, isOpen);
61
- if (parentDrawer) {
62
- parentDrawer.onNestedRelease(event, isOpen);
76
+ if (resolvedParentDrawer) {
77
+ resolvedParentDrawer.onNestedRelease(event, isOpen);
63
78
  }
64
79
  }
65
80
 
66
81
  // Watch open state to notify parent drawer
67
82
  $effect(() => {
68
- if (parentDrawer) {
69
- parentDrawer.onNestedOpenChange(open);
83
+ if (resolvedParentDrawer) {
84
+ resolvedParentDrawer.onNestedOpenChange(open);
70
85
  }
71
86
  });
72
87
 
@@ -111,9 +126,25 @@
111
126
  onAnimationEnd: box.with(() => onAnimationEnd),
112
127
  });
113
128
 
114
- // Expose drawer state for parent-child relationships with global/portal drawers
129
+ // Get stable reference to drawer state for registry
130
+ const stableDrawerState = rootState.parentDrawerState;
131
+
132
+ // Register/unregister with global drawer registry
133
+ $effect(() => {
134
+ if (open) {
135
+ registerDrawer(stableDrawerState);
136
+ return () => unregisterDrawer(stableDrawerState);
137
+ }
138
+ });
139
+
140
+ // Clear auto-detected parent after drawer closes (separate effect to avoid loops)
115
141
  $effect(() => {
116
- drawerState = rootState.parentDrawerState;
142
+ if (!open && resolvedParentDrawer) {
143
+ // Use queueMicrotask to avoid triggering other effects synchronously
144
+ queueMicrotask(() => {
145
+ resolvedParentDrawer = undefined;
146
+ });
147
+ }
117
148
  });
118
149
  </script>
119
150
 
@@ -1,9 +1,3 @@
1
- import type { RootProps } from "./index.js";
2
- import type { ParentDrawerState } from "../../types.js";
3
- type $$ComponentProps = RootProps & {
4
- drawerState?: ParentDrawerState;
5
- parentDrawer?: ParentDrawerState;
6
- };
7
- declare const Drawer: import("svelte").Component<$$ComponentProps, {}, "open" | "activeSnapPoint" | "drawerState">;
1
+ declare const Drawer: import("svelte").Component<import("../../types.js").DrawerRootPropsWithoutHTML, {}, "open" | "activeSnapPoint">;
8
2
  type Drawer = ReturnType<typeof Drawer>;
9
3
  export default Drawer;
@@ -0,0 +1,15 @@
1
+ import type { ParentDrawerState } from "./types.js";
2
+ /**
3
+ * Register a drawer as open.
4
+ */
5
+ export declare function registerDrawer(state: ParentDrawerState): void;
6
+ /**
7
+ * Unregister a drawer when it closes.
8
+ */
9
+ export declare function unregisterDrawer(state: ParentDrawerState): void;
10
+ /**
11
+ * Get the current topmost drawer state (if any).
12
+ * Used to auto-detect parent drawer when a new drawer opens.
13
+ * Returns the most recently opened drawer, which becomes the parent of the new drawer.
14
+ */
15
+ export declare function getCurrentParentDrawer(): ParentDrawerState | undefined;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Global registry for tracking open drawers.
3
+ * Enables automatic parent-child relationships without manual prop passing.
4
+ *
5
+ * NOTE: This is intentionally NOT using $state to avoid creating reactive
6
+ * dependencies that would cause infinite effect loops.
7
+ */
8
+ // Stack of open drawers (most recent last) - intentionally non-reactive
9
+ let openDrawers = [];
10
+ /**
11
+ * Register a drawer as open.
12
+ */
13
+ export function registerDrawer(state) {
14
+ openDrawers.push(state);
15
+ }
16
+ /**
17
+ * Unregister a drawer when it closes.
18
+ */
19
+ export function unregisterDrawer(state) {
20
+ const index = openDrawers.indexOf(state);
21
+ if (index !== -1) {
22
+ openDrawers.splice(index, 1);
23
+ }
24
+ }
25
+ /**
26
+ * Get the current topmost drawer state (if any).
27
+ * Used to auto-detect parent drawer when a new drawer opens.
28
+ * Returns the most recently opened drawer, which becomes the parent of the new drawer.
29
+ */
30
+ export function getCurrentParentDrawer() {
31
+ return openDrawers.at(-1);
32
+ }
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from "./components/index.js";
2
2
  export * from "./types.js";
3
+ export { getCurrentParentDrawer } from "./drawer-registry.js";
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from "./components/index.js";
2
2
  export * from "./types.js";
3
+ export { getCurrentParentDrawer } from "./drawer-registry.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@johly/vaul-svelte",
3
- "version": "1.0.0-next.11",
3
+ "version": "1.0.0-next.12",
4
4
  "license": "MIT",
5
5
  "repository": "github:johanohly/vaul-svelte",
6
6
  "exports": {