@surdeddd/bottom-sheet 0.5.0 → 0.6.1

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/dist/react.d.cts CHANGED
@@ -84,6 +84,8 @@ declare const BottomSheet: react.ForwardRefExoticComponent<EngineOptionsForProps
84
84
  noSSR?: boolean;
85
85
  } & react.RefAttributes<BottomSheetHandle<string>>>;
86
86
 
87
+ type TeleportTarget = HTMLElement | string | null | undefined;
88
+
87
89
  type UseBottomSheetRefs = {
88
90
  sheetRef: React.RefObject<HTMLElement | null>;
89
91
  handleRef: React.RefObject<HTMLElement | null>;
@@ -113,6 +115,9 @@ type HookOpts<TId extends string> = Omit<EngineOptions, "element" | "handle" | "
113
115
  snapPoints: SnapPointDef<TId>[] | ReadonlyArray<SnapPointDef<TId>>;
114
116
  allowed?: TId[] | ReadonlyArray<TId>;
115
117
  initial?: TId;
118
+ teleportTo?: TeleportTarget;
119
+ backdropColor?: string;
120
+ backdropOpacity?: number;
116
121
  onSnap?: (id: TId) => void;
117
122
  onBeforeClose?: (payload: SheetEventMap["before-close"]) => void;
118
123
  onOpened?: (id: TId) => void;
package/dist/react.d.ts CHANGED
@@ -84,6 +84,8 @@ declare const BottomSheet: react.ForwardRefExoticComponent<EngineOptionsForProps
84
84
  noSSR?: boolean;
85
85
  } & react.RefAttributes<BottomSheetHandle<string>>>;
86
86
 
87
+ type TeleportTarget = HTMLElement | string | null | undefined;
88
+
87
89
  type UseBottomSheetRefs = {
88
90
  sheetRef: React.RefObject<HTMLElement | null>;
89
91
  handleRef: React.RefObject<HTMLElement | null>;
@@ -113,6 +115,9 @@ type HookOpts<TId extends string> = Omit<EngineOptions, "element" | "handle" | "
113
115
  snapPoints: SnapPointDef<TId>[] | ReadonlyArray<SnapPointDef<TId>>;
114
116
  allowed?: TId[] | ReadonlyArray<TId>;
115
117
  initial?: TId;
118
+ teleportTo?: TeleportTarget;
119
+ backdropColor?: string;
120
+ backdropOpacity?: number;
116
121
  onSnap?: (id: TId) => void;
117
122
  onBeforeClose?: (payload: SheetEventMap["before-close"]) => void;
118
123
  onOpened?: (id: TId) => void;
package/dist/react.js CHANGED
@@ -2628,7 +2628,9 @@ var BottomSheetEngine = class {
2628
2628
  const previousSize = this.size;
2629
2629
  this.scrollCache.cache(previousId, previousSize, target.size);
2630
2630
  this.activeId = id;
2631
- if (wasClosed && target.size > 0) {
2631
+ const rawTargetSize = this.snapPointsRaw.find((p) => p.id === id)?.size;
2632
+ const opensToRest = id === "closed" || rawTargetSize === 0;
2633
+ if (wasClosed && !opensToRest) {
2632
2634
  this.opening = true;
2633
2635
  sheetStack.promote(this.id);
2634
2636
  }
@@ -3435,6 +3437,38 @@ var BottomSheetEngine = class {
3435
3437
  }
3436
3438
  };
3437
3439
 
3440
+ // src/core/features/teleport.ts
3441
+ var resolveTeleportTarget = (target) => {
3442
+ if (!target) return null;
3443
+ if (typeof target !== "string") return target;
3444
+ if (typeof document === "undefined") return null;
3445
+ if (target === "body") return document.body;
3446
+ return document.querySelector(target);
3447
+ };
3448
+ var teleportElements = (els, target) => {
3449
+ const records = [];
3450
+ for (const el of els) {
3451
+ if (!el || el.parentNode === target) continue;
3452
+ records.push({ el, parent: el.parentNode, next: el.nextSibling });
3453
+ target.appendChild(el);
3454
+ }
3455
+ return () => {
3456
+ for (let i = records.length - 1; i >= 0; i--) {
3457
+ const { el, parent, next } = records[i];
3458
+ if (parent && parent.isConnected) {
3459
+ const before = next && next.parentNode === parent ? next : null;
3460
+ try {
3461
+ parent.insertBefore(el, before);
3462
+ } catch {
3463
+ el.parentNode?.removeChild(el);
3464
+ }
3465
+ } else {
3466
+ el.parentNode?.removeChild(el);
3467
+ }
3468
+ }
3469
+ };
3470
+ };
3471
+
3438
3472
  // src/react/useBottomSheet.ts
3439
3473
  var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
3440
3474
  var SSR_STATE = Object.freeze({
@@ -3468,6 +3502,17 @@ function useBottomSheet(opts) {
3468
3502
  scrim: screenRef.current ?? void 0
3469
3503
  });
3470
3504
  engineRef.current = engine;
3505
+ const target = resolveTeleportTarget(optsRef.current.teleportTo);
3506
+ const restoreTeleport = target ? teleportElements(
3507
+ [backdropRef.current, screenRef.current, sheetRef.current],
3508
+ target
3509
+ ) : null;
3510
+ if (optsRef.current.backdropColor !== void 0) {
3511
+ engine.setScrimColor(optsRef.current.backdropColor);
3512
+ }
3513
+ if (optsRef.current.backdropOpacity !== void 0) {
3514
+ engine.setBackdropRange([0, optsRef.current.backdropOpacity]);
3515
+ }
3471
3516
  cachedSnapshotRef.current = { ...engine.state };
3472
3517
  setMounted((n) => n + 1);
3473
3518
  const refresh = () => {
@@ -3499,6 +3544,7 @@ function useBottomSheet(opts) {
3499
3544
  ];
3500
3545
  return () => {
3501
3546
  offs.forEach((off) => off());
3547
+ restoreTeleport?.();
3502
3548
  engine.destroy();
3503
3549
  engineRef.current = null;
3504
3550
  cachedSnapshotRef.current = SSR_STATE;
@@ -3514,6 +3560,18 @@ function useBottomSheet(opts) {
3514
3560
  const ids = opts.allowed ? Array.from(opts.allowed) : opts.snapPoints.map((p) => p.id);
3515
3561
  engineRef.current.setAllowed(ids);
3516
3562
  }, [allowedKey, snapKey]);
3563
+ useEffect(() => {
3564
+ if (!engineRef.current) return;
3565
+ if (opts.backdropColor !== void 0) {
3566
+ engineRef.current.setScrimColor(opts.backdropColor);
3567
+ }
3568
+ }, [opts.backdropColor]);
3569
+ useEffect(() => {
3570
+ if (!engineRef.current) return;
3571
+ if (opts.backdropOpacity !== void 0) {
3572
+ engineRef.current.setBackdropRange([0, opts.backdropOpacity]);
3573
+ }
3574
+ }, [opts.backdropOpacity]);
3517
3575
  const subscribe = useCallback((fn) => {
3518
3576
  subscribersRef.current.add(fn);
3519
3577
  return () => subscribersRef.current.delete(fn);
package/dist/solid.cjs CHANGED
@@ -2623,7 +2623,9 @@ var BottomSheetEngine = class {
2623
2623
  const previousSize = this.size;
2624
2624
  this.scrollCache.cache(previousId, previousSize, target.size);
2625
2625
  this.activeId = id;
2626
- if (wasClosed && target.size > 0) {
2626
+ const rawTargetSize = this.snapPointsRaw.find((p) => p.id === id)?.size;
2627
+ const opensToRest = id === "closed" || rawTargetSize === 0;
2628
+ if (wasClosed && !opensToRest) {
2627
2629
  this.opening = true;
2628
2630
  sheetStack.promote(this.id);
2629
2631
  }
package/dist/solid.js CHANGED
@@ -2621,7 +2621,9 @@ var BottomSheetEngine = class {
2621
2621
  const previousSize = this.size;
2622
2622
  this.scrollCache.cache(previousId, previousSize, target.size);
2623
2623
  this.activeId = id;
2624
- if (wasClosed && target.size > 0) {
2624
+ const rawTargetSize = this.snapPointsRaw.find((p) => p.id === id)?.size;
2625
+ const opensToRest = id === "closed" || rawTargetSize === 0;
2626
+ if (wasClosed && !opensToRest) {
2625
2627
  this.opening = true;
2626
2628
  sheetStack.promote(this.id);
2627
2629
  }
@@ -2623,7 +2623,9 @@ var BottomSheetEngine = class {
2623
2623
  const previousSize = this.size;
2624
2624
  this.scrollCache.cache(previousId, previousSize, target.size);
2625
2625
  this.activeId = id;
2626
- if (wasClosed && target.size > 0) {
2626
+ const rawTargetSize = this.snapPointsRaw.find((p) => p.id === id)?.size;
2627
+ const opensToRest = id === "closed" || rawTargetSize === 0;
2628
+ if (wasClosed && !opensToRest) {
2627
2629
  this.opening = true;
2628
2630
  sheetStack.promote(this.id);
2629
2631
  }
@@ -2622,7 +2622,9 @@ var BottomSheetEngine = class {
2622
2622
  const previousSize = this.size;
2623
2623
  this.scrollCache.cache(previousId, previousSize, target.size);
2624
2624
  this.activeId = id;
2625
- if (wasClosed && target.size > 0) {
2625
+ const rawTargetSize = this.snapPointsRaw.find((p) => p.id === id)?.size;
2626
+ const opensToRest = id === "closed" || rawTargetSize === 0;
2627
+ if (wasClosed && !opensToRest) {
2626
2628
  this.opening = true;
2627
2629
  sheetStack.promote(this.id);
2628
2630
  }
@@ -3429,6 +3431,38 @@ var BottomSheetEngine = class {
3429
3431
  }
3430
3432
  };
3431
3433
 
3434
+ // src/core/features/teleport.ts
3435
+ var resolveTeleportTarget = (target) => {
3436
+ if (!target) return null;
3437
+ if (typeof target !== "string") return target;
3438
+ if (typeof document === "undefined") return null;
3439
+ if (target === "body") return document.body;
3440
+ return document.querySelector(target);
3441
+ };
3442
+ var teleportElements = (els, target) => {
3443
+ const records = [];
3444
+ for (const el of els) {
3445
+ if (!el || el.parentNode === target) continue;
3446
+ records.push({ el, parent: el.parentNode, next: el.nextSibling });
3447
+ target.appendChild(el);
3448
+ }
3449
+ return () => {
3450
+ for (let i = records.length - 1; i >= 0; i--) {
3451
+ const { el, parent, next } = records[i];
3452
+ if (parent && parent.isConnected) {
3453
+ const before = next && next.parentNode === parent ? next : null;
3454
+ try {
3455
+ parent.insertBefore(el, before);
3456
+ } catch {
3457
+ el.parentNode?.removeChild(el);
3458
+ }
3459
+ } else {
3460
+ el.parentNode?.removeChild(el);
3461
+ }
3462
+ }
3463
+ };
3464
+ };
3465
+
3432
3466
  // src/svelte/useBottomSheet.svelte.ts
3433
3467
  var SSR_STATE = Object.freeze({
3434
3468
  size: 0,
@@ -3442,9 +3476,21 @@ function createBottomSheet(opts) {
3442
3476
  const pending = [];
3443
3477
  const attach = (refs) => {
3444
3478
  if (engine) engine.destroy();
3445
- const { onSnap, ...engineOpts } = opts;
3479
+ const {
3480
+ onSnap,
3481
+ teleportTo,
3482
+ backdropColor,
3483
+ backdropOpacity,
3484
+ ...engineOpts
3485
+ } = opts;
3446
3486
  const created = new BottomSheetEngine({ ...engineOpts, ...refs });
3447
3487
  engine = created;
3488
+ const target = resolveTeleportTarget(teleportTo);
3489
+ const restoreTeleport = target ? teleportElements([refs.backdrop, refs.scrim, refs.element], target) : null;
3490
+ if (backdropColor !== void 0) created.setScrimColor(backdropColor);
3491
+ if (backdropOpacity !== void 0) {
3492
+ created.setBackdropRange([0, backdropOpacity]);
3493
+ }
3448
3494
  if (onSnap) {
3449
3495
  created.on("snap", (payload) => onSnap(payload.id));
3450
3496
  }
@@ -3453,6 +3499,7 @@ function createBottomSheet(opts) {
3453
3499
  }
3454
3500
  pending.length = 0;
3455
3501
  return () => {
3502
+ restoreTeleport?.();
3456
3503
  created.destroy();
3457
3504
  if (engine === created) engine = null;
3458
3505
  };
@@ -2620,7 +2620,9 @@ var BottomSheetEngine = class {
2620
2620
  const previousSize = this.size;
2621
2621
  this.scrollCache.cache(previousId, previousSize, target.size);
2622
2622
  this.activeId = id;
2623
- if (wasClosed && target.size > 0) {
2623
+ const rawTargetSize = this.snapPointsRaw.find((p) => p.id === id)?.size;
2624
+ const opensToRest = id === "closed" || rawTargetSize === 0;
2625
+ if (wasClosed && !opensToRest) {
2624
2626
  this.opening = true;
2625
2627
  sheetStack.promote(this.id);
2626
2628
  }
@@ -3427,6 +3429,38 @@ var BottomSheetEngine = class {
3427
3429
  }
3428
3430
  };
3429
3431
 
3432
+ // src/core/features/teleport.ts
3433
+ var resolveTeleportTarget = (target) => {
3434
+ if (!target) return null;
3435
+ if (typeof target !== "string") return target;
3436
+ if (typeof document === "undefined") return null;
3437
+ if (target === "body") return document.body;
3438
+ return document.querySelector(target);
3439
+ };
3440
+ var teleportElements = (els, target) => {
3441
+ const records = [];
3442
+ for (const el of els) {
3443
+ if (!el || el.parentNode === target) continue;
3444
+ records.push({ el, parent: el.parentNode, next: el.nextSibling });
3445
+ target.appendChild(el);
3446
+ }
3447
+ return () => {
3448
+ for (let i = records.length - 1; i >= 0; i--) {
3449
+ const { el, parent, next } = records[i];
3450
+ if (parent && parent.isConnected) {
3451
+ const before = next && next.parentNode === parent ? next : null;
3452
+ try {
3453
+ parent.insertBefore(el, before);
3454
+ } catch {
3455
+ el.parentNode?.removeChild(el);
3456
+ }
3457
+ } else {
3458
+ el.parentNode?.removeChild(el);
3459
+ }
3460
+ }
3461
+ };
3462
+ };
3463
+
3430
3464
  // src/svelte/useBottomSheet.svelte.ts
3431
3465
  var SSR_STATE = Object.freeze({
3432
3466
  size: 0,
@@ -3440,9 +3474,21 @@ function createBottomSheet(opts) {
3440
3474
  const pending = [];
3441
3475
  const attach = (refs) => {
3442
3476
  if (engine) engine.destroy();
3443
- const { onSnap, ...engineOpts } = opts;
3477
+ const {
3478
+ onSnap,
3479
+ teleportTo,
3480
+ backdropColor,
3481
+ backdropOpacity,
3482
+ ...engineOpts
3483
+ } = opts;
3444
3484
  const created = new BottomSheetEngine({ ...engineOpts, ...refs });
3445
3485
  engine = created;
3486
+ const target = resolveTeleportTarget(teleportTo);
3487
+ const restoreTeleport = target ? teleportElements([refs.backdrop, refs.scrim, refs.element], target) : null;
3488
+ if (backdropColor !== void 0) created.setScrimColor(backdropColor);
3489
+ if (backdropOpacity !== void 0) {
3490
+ created.setBackdropRange([0, backdropOpacity]);
3491
+ }
3446
3492
  if (onSnap) {
3447
3493
  created.on("snap", (payload) => onSnap(payload.id));
3448
3494
  }
@@ -3451,6 +3497,7 @@ function createBottomSheet(opts) {
3451
3497
  }
3452
3498
  pending.length = 0;
3453
3499
  return () => {
3500
+ restoreTeleport?.();
3454
3501
  created.destroy();
3455
3502
  if (engine === created) engine = null;
3456
3503
  };
package/dist/svelte.cjs CHANGED
@@ -2644,7 +2644,9 @@ var BottomSheetEngine = class {
2644
2644
  const previousSize = this.size;
2645
2645
  this.scrollCache.cache(previousId, previousSize, target.size);
2646
2646
  this.activeId = id;
2647
- if (wasClosed && target.size > 0) {
2647
+ const rawTargetSize = this.snapPointsRaw.find((p) => p.id === id)?.size;
2648
+ const opensToRest = id === "closed" || rawTargetSize === 0;
2649
+ if (wasClosed && !opensToRest) {
2648
2650
  this.opening = true;
2649
2651
  sheetStack.promote(this.id);
2650
2652
  }
@@ -3451,6 +3453,38 @@ var BottomSheetEngine = class {
3451
3453
  }
3452
3454
  };
3453
3455
 
3456
+ // src/core/features/teleport.ts
3457
+ var resolveTeleportTarget = (target) => {
3458
+ if (!target) return null;
3459
+ if (typeof target !== "string") return target;
3460
+ if (typeof document === "undefined") return null;
3461
+ if (target === "body") return document.body;
3462
+ return document.querySelector(target);
3463
+ };
3464
+ var teleportElements = (els, target) => {
3465
+ const records = [];
3466
+ for (const el of els) {
3467
+ if (!el || el.parentNode === target) continue;
3468
+ records.push({ el, parent: el.parentNode, next: el.nextSibling });
3469
+ target.appendChild(el);
3470
+ }
3471
+ return () => {
3472
+ for (let i = records.length - 1; i >= 0; i--) {
3473
+ const { el, parent, next } = records[i];
3474
+ if (parent && parent.isConnected) {
3475
+ const before = next && next.parentNode === parent ? next : null;
3476
+ try {
3477
+ parent.insertBefore(el, before);
3478
+ } catch {
3479
+ el.parentNode?.removeChild(el);
3480
+ }
3481
+ } else {
3482
+ el.parentNode?.removeChild(el);
3483
+ }
3484
+ }
3485
+ };
3486
+ };
3487
+
3454
3488
  // src/svelte/useBottomSheet.svelte.ts
3455
3489
  var SSR_STATE = Object.freeze({
3456
3490
  size: 0,
@@ -3464,9 +3498,21 @@ function createBottomSheet(opts) {
3464
3498
  const pending = [];
3465
3499
  const attach = (refs) => {
3466
3500
  if (engine) engine.destroy();
3467
- const { onSnap, ...engineOpts } = opts;
3501
+ const {
3502
+ onSnap,
3503
+ teleportTo,
3504
+ backdropColor,
3505
+ backdropOpacity,
3506
+ ...engineOpts
3507
+ } = opts;
3468
3508
  const created = new BottomSheetEngine({ ...engineOpts, ...refs });
3469
3509
  engine = created;
3510
+ const target = resolveTeleportTarget(teleportTo);
3511
+ const restoreTeleport = target ? teleportElements([refs.backdrop, refs.scrim, refs.element], target) : null;
3512
+ if (backdropColor !== void 0) created.setScrimColor(backdropColor);
3513
+ if (backdropOpacity !== void 0) {
3514
+ created.setBackdropRange([0, backdropOpacity]);
3515
+ }
3470
3516
  if (onSnap) {
3471
3517
  created.on("snap", (payload) => onSnap(payload.id));
3472
3518
  }
@@ -3475,6 +3521,7 @@ function createBottomSheet(opts) {
3475
3521
  }
3476
3522
  pending.length = 0;
3477
3523
  return () => {
3524
+ restoreTeleport?.();
3478
3525
  created.destroy();
3479
3526
  if (engine === created) engine = null;
3480
3527
  };
package/dist/svelte.d.cts CHANGED
@@ -27,6 +27,9 @@ export type SvelteBottomSheetOpts<TId extends string = string> = Omit<
27
27
  snapPoints: SnapPointDef<TId>[] | ReadonlyArray<SnapPointDef<TId>>;
28
28
  allowed?: TId[] | ReadonlyArray<TId>;
29
29
  initial?: TId;
30
+ teleportTo?: string | HTMLElement | null;
31
+ backdropColor?: string;
32
+ backdropOpacity?: number;
30
33
  onSnap?: (id: TId) => void;
31
34
  };
32
35
 
package/dist/svelte.d.ts CHANGED
@@ -27,6 +27,9 @@ export type SvelteBottomSheetOpts<TId extends string = string> = Omit<
27
27
  snapPoints: SnapPointDef<TId>[] | ReadonlyArray<SnapPointDef<TId>>;
28
28
  allowed?: TId[] | ReadonlyArray<TId>;
29
29
  initial?: TId;
30
+ teleportTo?: string | HTMLElement | null;
31
+ backdropColor?: string;
32
+ backdropOpacity?: number;
30
33
  onSnap?: (id: TId) => void;
31
34
  };
32
35
 
package/dist/svelte.js CHANGED
@@ -2622,7 +2622,9 @@ var BottomSheetEngine = class {
2622
2622
  const previousSize = this.size;
2623
2623
  this.scrollCache.cache(previousId, previousSize, target.size);
2624
2624
  this.activeId = id;
2625
- if (wasClosed && target.size > 0) {
2625
+ const rawTargetSize = this.snapPointsRaw.find((p) => p.id === id)?.size;
2626
+ const opensToRest = id === "closed" || rawTargetSize === 0;
2627
+ if (wasClosed && !opensToRest) {
2626
2628
  this.opening = true;
2627
2629
  sheetStack.promote(this.id);
2628
2630
  }
@@ -3429,6 +3431,38 @@ var BottomSheetEngine = class {
3429
3431
  }
3430
3432
  };
3431
3433
 
3434
+ // src/core/features/teleport.ts
3435
+ var resolveTeleportTarget = (target) => {
3436
+ if (!target) return null;
3437
+ if (typeof target !== "string") return target;
3438
+ if (typeof document === "undefined") return null;
3439
+ if (target === "body") return document.body;
3440
+ return document.querySelector(target);
3441
+ };
3442
+ var teleportElements = (els, target) => {
3443
+ const records = [];
3444
+ for (const el of els) {
3445
+ if (!el || el.parentNode === target) continue;
3446
+ records.push({ el, parent: el.parentNode, next: el.nextSibling });
3447
+ target.appendChild(el);
3448
+ }
3449
+ return () => {
3450
+ for (let i = records.length - 1; i >= 0; i--) {
3451
+ const { el, parent, next } = records[i];
3452
+ if (parent && parent.isConnected) {
3453
+ const before = next && next.parentNode === parent ? next : null;
3454
+ try {
3455
+ parent.insertBefore(el, before);
3456
+ } catch {
3457
+ el.parentNode?.removeChild(el);
3458
+ }
3459
+ } else {
3460
+ el.parentNode?.removeChild(el);
3461
+ }
3462
+ }
3463
+ };
3464
+ };
3465
+
3432
3466
  // src/svelte/useBottomSheet.svelte.ts
3433
3467
  var SSR_STATE = Object.freeze({
3434
3468
  size: 0,
@@ -3442,9 +3476,21 @@ function createBottomSheet(opts) {
3442
3476
  const pending = [];
3443
3477
  const attach = (refs) => {
3444
3478
  if (engine) engine.destroy();
3445
- const { onSnap, ...engineOpts } = opts;
3479
+ const {
3480
+ onSnap,
3481
+ teleportTo,
3482
+ backdropColor,
3483
+ backdropOpacity,
3484
+ ...engineOpts
3485
+ } = opts;
3446
3486
  const created = new BottomSheetEngine({ ...engineOpts, ...refs });
3447
3487
  engine = created;
3488
+ const target = resolveTeleportTarget(teleportTo);
3489
+ const restoreTeleport = target ? teleportElements([refs.backdrop, refs.scrim, refs.element], target) : null;
3490
+ if (backdropColor !== void 0) created.setScrimColor(backdropColor);
3491
+ if (backdropOpacity !== void 0) {
3492
+ created.setBackdropRange([0, backdropOpacity]);
3493
+ }
3448
3494
  if (onSnap) {
3449
3495
  created.on("snap", (payload) => onSnap(payload.id));
3450
3496
  }
@@ -3453,6 +3499,7 @@ function createBottomSheet(opts) {
3453
3499
  }
3454
3500
  pending.length = 0;
3455
3501
  return () => {
3502
+ restoreTeleport?.();
3456
3503
  created.destroy();
3457
3504
  if (engine === created) engine = null;
3458
3505
  };
package/dist/vue.cjs CHANGED
@@ -2622,7 +2622,9 @@ var BottomSheetEngine = class {
2622
2622
  const previousSize = this.size;
2623
2623
  this.scrollCache.cache(previousId, previousSize, target.size);
2624
2624
  this.activeId = id;
2625
- if (wasClosed && target.size > 0) {
2625
+ const rawTargetSize = this.snapPointsRaw.find((p) => p.id === id)?.size;
2626
+ const opensToRest = id === "closed" || rawTargetSize === 0;
2627
+ if (wasClosed && !opensToRest) {
2626
2628
  this.opening = true;
2627
2629
  sheetStack.promote(this.id);
2628
2630
  }
@@ -3429,6 +3431,38 @@ var BottomSheetEngine = class {
3429
3431
  }
3430
3432
  };
3431
3433
 
3434
+ // src/core/features/teleport.ts
3435
+ var resolveTeleportTarget = (target) => {
3436
+ if (!target) return null;
3437
+ if (typeof target !== "string") return target;
3438
+ if (typeof document === "undefined") return null;
3439
+ if (target === "body") return document.body;
3440
+ return document.querySelector(target);
3441
+ };
3442
+ var teleportElements = (els, target) => {
3443
+ const records = [];
3444
+ for (const el of els) {
3445
+ if (!el || el.parentNode === target) continue;
3446
+ records.push({ el, parent: el.parentNode, next: el.nextSibling });
3447
+ target.appendChild(el);
3448
+ }
3449
+ return () => {
3450
+ for (let i = records.length - 1; i >= 0; i--) {
3451
+ const { el, parent, next } = records[i];
3452
+ if (parent && parent.isConnected) {
3453
+ const before = next && next.parentNode === parent ? next : null;
3454
+ try {
3455
+ parent.insertBefore(el, before);
3456
+ } catch {
3457
+ el.parentNode?.removeChild(el);
3458
+ }
3459
+ } else {
3460
+ el.parentNode?.removeChild(el);
3461
+ }
3462
+ }
3463
+ };
3464
+ };
3465
+
3432
3466
  // src/vue/useBottomSheet.ts
3433
3467
  function useBottomSheet(opts) {
3434
3468
  const sheetRef = vue.ref(null);
@@ -3445,13 +3479,20 @@ function useBottomSheet(opts) {
3445
3479
  isAnimating: false,
3446
3480
  progress: 0
3447
3481
  });
3482
+ let restoreTeleport = null;
3448
3483
  const sync = () => {
3449
3484
  if (!engine) return;
3450
3485
  Object.assign(state, engine.state);
3451
3486
  };
3452
3487
  vue.onMounted(() => {
3453
3488
  if (!sheetRef.value) return;
3454
- const { onSnap, ...engineOpts } = opts;
3489
+ const {
3490
+ onSnap,
3491
+ teleportTo,
3492
+ backdropColor,
3493
+ backdropOpacity,
3494
+ ...engineOpts
3495
+ } = opts;
3455
3496
  engine = new BottomSheetEngine({
3456
3497
  ...engineOpts,
3457
3498
  element: sheetRef.value,
@@ -3461,6 +3502,17 @@ function useBottomSheet(opts) {
3461
3502
  scrim: screenRef.value ?? void 0
3462
3503
  });
3463
3504
  sync();
3505
+ const target = resolveTeleportTarget(teleportTo);
3506
+ if (target) {
3507
+ restoreTeleport = teleportElements(
3508
+ [backdropRef.value, screenRef.value, sheetRef.value],
3509
+ target
3510
+ );
3511
+ }
3512
+ if (backdropColor !== void 0) engine.setScrimColor(backdropColor);
3513
+ if (backdropOpacity !== void 0) {
3514
+ engine.setBackdropRange([0, backdropOpacity]);
3515
+ }
3464
3516
  engine.on("snap", (payload) => {
3465
3517
  sync();
3466
3518
  onSnap?.(payload.id);
@@ -3476,6 +3528,8 @@ function useBottomSheet(opts) {
3476
3528
  pending.length = 0;
3477
3529
  });
3478
3530
  vue.onBeforeUnmount(() => {
3531
+ restoreTeleport?.();
3532
+ restoreTeleport = null;
3479
3533
  engine?.destroy();
3480
3534
  engine = null;
3481
3535
  });
@@ -3704,6 +3758,23 @@ var _sfc_main = /* @__PURE__ */ vue.defineComponent({
3704
3758
  type: null,
3705
3759
  required: false
3706
3760
  },
3761
+ teleportTo: {
3762
+ type: [
3763
+ String,
3764
+ null,
3765
+ Object
3766
+ ],
3767
+ required: false,
3768
+ default: "body"
3769
+ },
3770
+ backdropColor: {
3771
+ type: String,
3772
+ required: false
3773
+ },
3774
+ backdropOpacity: {
3775
+ type: Number,
3776
+ required: false
3777
+ },
3707
3778
  onSnap: {
3708
3779
  type: Function,
3709
3780
  required: false
@@ -3736,11 +3807,6 @@ var _sfc_main = /* @__PURE__ */ vue.defineComponent({
3736
3807
  required: false,
3737
3808
  default: true
3738
3809
  },
3739
- teleportTo: {
3740
- type: null,
3741
- required: false,
3742
- default: "body"
3743
- },
3744
3810
  anchors: {
3745
3811
  type: Array,
3746
3812
  required: false
@@ -3748,14 +3814,6 @@ var _sfc_main = /* @__PURE__ */ vue.defineComponent({
3748
3814
  scrimStages: {
3749
3815
  type: [Object, null],
3750
3816
  required: false
3751
- },
3752
- backdropColor: {
3753
- type: String,
3754
- required: false
3755
- },
3756
- backdropOpacity: {
3757
- type: Number,
3758
- required: false
3759
3817
  }
3760
3818
  },
3761
3819
  emits: [
package/dist/vue.d.cts CHANGED
@@ -28,6 +28,9 @@ export type UseBottomSheetVueOptions<TId extends string = string> = Omit<
28
28
  snapPoints: SnapPointDef<TId>[] | ReadonlyArray<SnapPointDef<TId>>;
29
29
  allowed?: TId[] | ReadonlyArray<TId>;
30
30
  initial?: TId;
31
+ teleportTo?: string | HTMLElement | null;
32
+ backdropColor?: string;
33
+ backdropOpacity?: number;
31
34
  onSnap?: (id: TId) => void;
32
35
  };
33
36
 
package/dist/vue.d.ts CHANGED
@@ -28,6 +28,9 @@ export type UseBottomSheetVueOptions<TId extends string = string> = Omit<
28
28
  snapPoints: SnapPointDef<TId>[] | ReadonlyArray<SnapPointDef<TId>>;
29
29
  allowed?: TId[] | ReadonlyArray<TId>;
30
30
  initial?: TId;
31
+ teleportTo?: string | HTMLElement | null;
32
+ backdropColor?: string;
33
+ backdropOpacity?: number;
31
34
  onSnap?: (id: TId) => void;
32
35
  };
33
36