@surdeddd/bottom-sheet 0.4.1 → 0.6.0

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.
Files changed (41) hide show
  1. package/dist/{BottomSheetEngine-L05jGZvU.d.ts → BottomSheetEngine-BHjKFtnM.d.ts} +2 -0
  2. package/dist/{BottomSheetEngine-BJrH7qY3.d.cts → BottomSheetEngine-CqiCz64W.d.cts} +2 -0
  3. package/dist/element.cjs +111 -12
  4. package/dist/element.d.cts +1 -1
  5. package/dist/element.d.ts +1 -1
  6. package/dist/element.iife.global.js +2 -2
  7. package/dist/element.js +111 -12
  8. package/dist/index.cjs +91 -8
  9. package/dist/index.d.cts +2 -2
  10. package/dist/index.d.ts +2 -2
  11. package/dist/index.js +91 -8
  12. package/dist/integrations/formik.d.cts +1 -1
  13. package/dist/integrations/formik.d.ts +1 -1
  14. package/dist/integrations/react-hook-form.d.cts +1 -1
  15. package/dist/integrations/react-hook-form.d.ts +1 -1
  16. package/dist/preact.d.cts +1 -1
  17. package/dist/preact.d.ts +1 -1
  18. package/dist/qwik.cjs +94 -10
  19. package/dist/qwik.d.cts +2 -2
  20. package/dist/qwik.d.ts +2 -2
  21. package/dist/qwik.js +94 -10
  22. package/dist/react.cjs +151 -10
  23. package/dist/react.d.cts +9 -2
  24. package/dist/react.d.ts +9 -2
  25. package/dist/react.js +151 -10
  26. package/dist/solid.cjs +122 -18
  27. package/dist/solid.d.cts +3 -0
  28. package/dist/solid.d.ts +3 -0
  29. package/dist/solid.js +124 -20
  30. package/dist/solid.source.jsx +100 -12
  31. package/dist/styles.css +17 -0
  32. package/dist/svelte-core.cjs +137 -9
  33. package/dist/svelte-core.js +137 -9
  34. package/dist/svelte-src/BottomSheet.svelte +5 -3
  35. package/dist/svelte.cjs +189 -46
  36. package/dist/svelte.d.cts +1 -0
  37. package/dist/svelte.d.ts +1 -0
  38. package/dist/svelte.js +189 -46
  39. package/dist/vue.cjs +176 -32
  40. package/dist/vue.js +176 -32
  41. package/package.json +1 -1
package/dist/vue.cjs CHANGED
@@ -2897,11 +2897,54 @@ var BottomSheetEngine = class {
2897
2897
  this.updateAriaSlider();
2898
2898
  }
2899
2899
  }
2900
+ contentTargets() {
2901
+ const scroller = this.scrollContainer;
2902
+ if (!scroller) return [];
2903
+ const hasSlot = typeof HTMLSlotElement !== "undefined";
2904
+ const out = [];
2905
+ for (const child of Array.from(scroller.children)) {
2906
+ if (hasSlot && child instanceof HTMLSlotElement) {
2907
+ for (const el of child.assignedElements()) out.push(el);
2908
+ } else {
2909
+ out.push(child);
2910
+ }
2911
+ }
2912
+ return out;
2913
+ }
2914
+ measureContentExtent(vertical) {
2915
+ const content = this.scrollContainer;
2916
+ if (!content) return 0;
2917
+ const targets = this.contentTargets();
2918
+ if (targets.length === 0) {
2919
+ return vertical ? content.scrollHeight : content.scrollWidth;
2920
+ }
2921
+ let min = Infinity;
2922
+ let max = -Infinity;
2923
+ for (const el of targets) {
2924
+ const r = el.getBoundingClientRect();
2925
+ if (vertical) {
2926
+ if (r.top < min) min = r.top;
2927
+ if (r.bottom > max) max = r.bottom;
2928
+ } else {
2929
+ if (r.left < min) min = r.left;
2930
+ if (r.right > max) max = r.right;
2931
+ }
2932
+ }
2933
+ if (!isFinite(min) || !isFinite(max) || max <= min) {
2934
+ return vertical ? content.scrollHeight : content.scrollWidth;
2935
+ }
2936
+ let pad = 0;
2937
+ if (typeof getComputedStyle !== "undefined") {
2938
+ const cs = getComputedStyle(content);
2939
+ pad = vertical ? (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.paddingBottom) || 0) : (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.paddingRight) || 0);
2940
+ }
2941
+ return max - min + pad;
2942
+ }
2900
2943
  measureFitSize() {
2901
2944
  const vertical = layoutAxis(this.mode) === "height";
2902
2945
  const handleSize = vertical ? this.handle.offsetHeight : this.handle.offsetWidth;
2903
2946
  const content = this.scrollContainer;
2904
- const natural = content ? handleSize + (vertical ? content.scrollHeight : content.scrollWidth) : handleSize;
2947
+ const natural = content ? handleSize + this.measureContentExtent(vertical) : handleSize;
2905
2948
  if (typeof window === "undefined") return natural;
2906
2949
  const viewport = vertical ? window.innerHeight : window.innerWidth;
2907
2950
  return viewport > 0 ? Math.min(natural, viewport) : natural;
@@ -2910,22 +2953,62 @@ var BottomSheetEngine = class {
2910
2953
  if (typeof ResizeObserver === "undefined") return;
2911
2954
  if (!this.snapPointsRaw.some((p) => p.size === "fit" || p.size === "content"))
2912
2955
  return;
2913
- const targets = [this.handle];
2914
- if (this.scrollContainer && this.scrollContainer !== this.handle) {
2915
- targets.push(this.scrollContainer);
2916
- }
2917
2956
  let raf = 0;
2918
- const ro = new ResizeObserver(() => {
2957
+ const schedule = () => {
2919
2958
  if (raf) return;
2920
2959
  raf = requestAnimationFrame(() => {
2921
2960
  raf = 0;
2922
2961
  if (this.destroyed || this.gesture?.isDragging) return;
2923
2962
  this.recompute();
2924
2963
  });
2925
- });
2926
- for (const t of targets) ro.observe(t);
2964
+ };
2965
+ const ro = new ResizeObserver(schedule);
2966
+ ro.observe(this.handle);
2967
+ const scroller = this.scrollContainer;
2968
+ const observed = /* @__PURE__ */ new Set();
2969
+ const slots = /* @__PURE__ */ new Set();
2970
+ const hasSlot = typeof HTMLSlotElement !== "undefined";
2971
+ const onSlotChange = () => resync();
2972
+ const trackSlots = () => {
2973
+ if (!scroller || !hasSlot) return;
2974
+ for (const child of Array.from(scroller.children)) {
2975
+ if (child instanceof HTMLSlotElement && !slots.has(child)) {
2976
+ child.addEventListener("slotchange", onSlotChange);
2977
+ slots.add(child);
2978
+ }
2979
+ }
2980
+ };
2981
+ const resync = () => {
2982
+ trackSlots();
2983
+ const targets = this.contentTargets();
2984
+ for (const el of observed) {
2985
+ if (!targets.includes(el)) {
2986
+ ro.unobserve(el);
2987
+ observed.delete(el);
2988
+ }
2989
+ }
2990
+ for (const el of targets) {
2991
+ if (!observed.has(el)) {
2992
+ ro.observe(el);
2993
+ observed.add(el);
2994
+ }
2995
+ }
2996
+ schedule();
2997
+ };
2998
+ let mo;
2999
+ if (scroller) {
3000
+ resync();
3001
+ if (typeof MutationObserver !== "undefined") {
3002
+ mo = new MutationObserver(resync);
3003
+ mo.observe(scroller, { childList: true });
3004
+ }
3005
+ }
2927
3006
  this.teardowns.add(() => {
2928
3007
  ro.disconnect();
3008
+ mo?.disconnect();
3009
+ for (const slot of slots) {
3010
+ slot.removeEventListener("slotchange", onSlotChange);
3011
+ }
2929
3012
  if (raf) cancelAnimationFrame(raf);
2930
3013
  });
2931
3014
  }
@@ -3346,6 +3429,38 @@ var BottomSheetEngine = class {
3346
3429
  }
3347
3430
  };
3348
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
+
3349
3464
  // src/vue/useBottomSheet.ts
3350
3465
  function useBottomSheet(opts) {
3351
3466
  const sheetRef = vue.ref(null);
@@ -3362,13 +3477,20 @@ function useBottomSheet(opts) {
3362
3477
  isAnimating: false,
3363
3478
  progress: 0
3364
3479
  });
3480
+ let restoreTeleport = null;
3365
3481
  const sync = () => {
3366
3482
  if (!engine) return;
3367
3483
  Object.assign(state, engine.state);
3368
3484
  };
3369
3485
  vue.onMounted(() => {
3370
3486
  if (!sheetRef.value) return;
3371
- const { onSnap, ...engineOpts } = opts;
3487
+ const {
3488
+ onSnap,
3489
+ teleportTo,
3490
+ backdropColor,
3491
+ backdropOpacity,
3492
+ ...engineOpts
3493
+ } = opts;
3372
3494
  engine = new BottomSheetEngine({
3373
3495
  ...engineOpts,
3374
3496
  element: sheetRef.value,
@@ -3378,6 +3500,17 @@ function useBottomSheet(opts) {
3378
3500
  scrim: screenRef.value ?? void 0
3379
3501
  });
3380
3502
  sync();
3503
+ const target = resolveTeleportTarget(teleportTo);
3504
+ if (target) {
3505
+ restoreTeleport = teleportElements(
3506
+ [backdropRef.value, screenRef.value, sheetRef.value],
3507
+ target
3508
+ );
3509
+ }
3510
+ if (backdropColor !== void 0) engine.setScrimColor(backdropColor);
3511
+ if (backdropOpacity !== void 0) {
3512
+ engine.setBackdropRange([0, backdropOpacity]);
3513
+ }
3381
3514
  engine.on("snap", (payload) => {
3382
3515
  sync();
3383
3516
  onSnap?.(payload.id);
@@ -3393,6 +3526,8 @@ function useBottomSheet(opts) {
3393
3526
  pending.length = 0;
3394
3527
  });
3395
3528
  vue.onBeforeUnmount(() => {
3529
+ restoreTeleport?.();
3530
+ restoreTeleport = null;
3396
3531
  engine?.destroy();
3397
3532
  engine = null;
3398
3533
  });
@@ -3621,6 +3756,23 @@ var _sfc_main = /* @__PURE__ */ vue.defineComponent({
3621
3756
  type: null,
3622
3757
  required: false
3623
3758
  },
3759
+ teleportTo: {
3760
+ type: [
3761
+ String,
3762
+ null,
3763
+ Object
3764
+ ],
3765
+ required: false,
3766
+ default: "body"
3767
+ },
3768
+ backdropColor: {
3769
+ type: String,
3770
+ required: false
3771
+ },
3772
+ backdropOpacity: {
3773
+ type: Number,
3774
+ required: false
3775
+ },
3624
3776
  onSnap: {
3625
3777
  type: Function,
3626
3778
  required: false
@@ -3653,11 +3805,6 @@ var _sfc_main = /* @__PURE__ */ vue.defineComponent({
3653
3805
  required: false,
3654
3806
  default: true
3655
3807
  },
3656
- teleportTo: {
3657
- type: null,
3658
- required: false,
3659
- default: "body"
3660
- },
3661
3808
  anchors: {
3662
3809
  type: Array,
3663
3810
  required: false
@@ -3665,14 +3812,6 @@ var _sfc_main = /* @__PURE__ */ vue.defineComponent({
3665
3812
  scrimStages: {
3666
3813
  type: [Object, null],
3667
3814
  required: false
3668
- },
3669
- backdropColor: {
3670
- type: String,
3671
- required: false
3672
- },
3673
- backdropOpacity: {
3674
- type: Number,
3675
- required: false
3676
3815
  }
3677
3816
  },
3678
3817
  emits: [
@@ -3900,23 +4039,27 @@ var _hoisted_4 = [
3900
4039
  "aria-valuetext"
3901
4040
  ];
3902
4041
  var _hoisted_5 = {
4042
+ key: 0,
4043
+ class: "bs-header"
4044
+ };
4045
+ var _hoisted_6 = {
3903
4046
  ref: "contentRef",
3904
4047
  class: "bs-content",
3905
4048
  tabindex: "0",
3906
4049
  role: "region",
3907
4050
  "aria-label": "Sheet content"
3908
4051
  };
3909
- var _hoisted_6 = {
3910
- key: 0,
4052
+ var _hoisted_7 = {
4053
+ key: 1,
3911
4054
  class: "bs-footer"
3912
4055
  };
3913
- var _hoisted_7 = {
4056
+ var _hoisted_8 = {
3914
4057
  class: "bs-sr-only",
3915
4058
  role: "status",
3916
4059
  "aria-live": "polite"
3917
4060
  };
3918
- var _hoisted_8 = ["data-mode"];
3919
4061
  var _hoisted_9 = ["data-mode"];
4062
+ var _hoisted_10 = ["data-mode"];
3920
4063
  function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
3921
4064
  return vue.openBlock(), vue.createBlock(vue.Teleport, {
3922
4065
  to: $props.teleportTo,
@@ -3962,18 +4105,19 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
3962
4105
  "aria-valuenow": $setup.activeIdx,
3963
4106
  "aria-valuetext": $setup.state.activeId,
3964
4107
  "aria-label": "Resize sheet"
3965
- }, [vue.renderSlot(_ctx.$slots, "header", { state: $setup.state })], 8, _hoisted_4),
4108
+ }, null, 8, _hoisted_4),
4109
+ _ctx.$slots.header ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_5, [vue.renderSlot(_ctx.$slots, "header", { state: $setup.state })])) : vue.createCommentVNode("v-if", true),
3966
4110
  vue.createElementVNode(
3967
4111
  "div",
3968
- _hoisted_5,
4112
+ _hoisted_6,
3969
4113
  [vue.renderSlot(_ctx.$slots, "default")],
3970
4114
  512
3971
4115
  /* NEED_PATCH */
3972
4116
  ),
3973
- _ctx.$slots.footer ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_6, [vue.renderSlot(_ctx.$slots, "footer", { state: $setup.state })])) : vue.createCommentVNode("v-if", true),
4117
+ _ctx.$slots.footer ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_7, [vue.renderSlot(_ctx.$slots, "footer", { state: $setup.state })])) : vue.createCommentVNode("v-if", true),
3974
4118
  vue.createElementVNode(
3975
4119
  "span",
3976
- _hoisted_7,
4120
+ _hoisted_8,
3977
4121
  vue.toDisplayString($setup.state.activeId),
3978
4122
  1
3979
4123
  /* TEXT */
@@ -3984,13 +4128,13 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
3984
4128
  class: "bs-button-slot",
3985
4129
  "data-side": "left",
3986
4130
  "data-mode": $setup.props.mode ?? "bottom"
3987
- }, [vue.renderSlot(_ctx.$slots, "button-left")], 8, _hoisted_8)) : vue.createCommentVNode("v-if", true),
4131
+ }, [vue.renderSlot(_ctx.$slots, "button-left")], 8, _hoisted_9)) : vue.createCommentVNode("v-if", true),
3988
4132
  _ctx.$slots["button-right"] ? (vue.openBlock(), vue.createElementBlock("div", {
3989
4133
  key: 2,
3990
4134
  class: "bs-button-slot",
3991
4135
  "data-side": "right",
3992
4136
  "data-mode": $setup.props.mode ?? "bottom"
3993
- }, [vue.renderSlot(_ctx.$slots, "button-right")], 8, _hoisted_9)) : vue.createCommentVNode("v-if", true)
4137
+ }, [vue.renderSlot(_ctx.$slots, "button-right")], 8, _hoisted_10)) : vue.createCommentVNode("v-if", true)
3994
4138
  ]), (vue.openBlock(true), vue.createElementBlock(
3995
4139
  vue.Fragment,
3996
4140
  null,
package/dist/vue.js CHANGED
@@ -2895,11 +2895,54 @@ var BottomSheetEngine = class {
2895
2895
  this.updateAriaSlider();
2896
2896
  }
2897
2897
  }
2898
+ contentTargets() {
2899
+ const scroller = this.scrollContainer;
2900
+ if (!scroller) return [];
2901
+ const hasSlot = typeof HTMLSlotElement !== "undefined";
2902
+ const out = [];
2903
+ for (const child of Array.from(scroller.children)) {
2904
+ if (hasSlot && child instanceof HTMLSlotElement) {
2905
+ for (const el of child.assignedElements()) out.push(el);
2906
+ } else {
2907
+ out.push(child);
2908
+ }
2909
+ }
2910
+ return out;
2911
+ }
2912
+ measureContentExtent(vertical) {
2913
+ const content = this.scrollContainer;
2914
+ if (!content) return 0;
2915
+ const targets = this.contentTargets();
2916
+ if (targets.length === 0) {
2917
+ return vertical ? content.scrollHeight : content.scrollWidth;
2918
+ }
2919
+ let min = Infinity;
2920
+ let max = -Infinity;
2921
+ for (const el of targets) {
2922
+ const r = el.getBoundingClientRect();
2923
+ if (vertical) {
2924
+ if (r.top < min) min = r.top;
2925
+ if (r.bottom > max) max = r.bottom;
2926
+ } else {
2927
+ if (r.left < min) min = r.left;
2928
+ if (r.right > max) max = r.right;
2929
+ }
2930
+ }
2931
+ if (!isFinite(min) || !isFinite(max) || max <= min) {
2932
+ return vertical ? content.scrollHeight : content.scrollWidth;
2933
+ }
2934
+ let pad = 0;
2935
+ if (typeof getComputedStyle !== "undefined") {
2936
+ const cs = getComputedStyle(content);
2937
+ pad = vertical ? (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.paddingBottom) || 0) : (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.paddingRight) || 0);
2938
+ }
2939
+ return max - min + pad;
2940
+ }
2898
2941
  measureFitSize() {
2899
2942
  const vertical = layoutAxis(this.mode) === "height";
2900
2943
  const handleSize = vertical ? this.handle.offsetHeight : this.handle.offsetWidth;
2901
2944
  const content = this.scrollContainer;
2902
- const natural = content ? handleSize + (vertical ? content.scrollHeight : content.scrollWidth) : handleSize;
2945
+ const natural = content ? handleSize + this.measureContentExtent(vertical) : handleSize;
2903
2946
  if (typeof window === "undefined") return natural;
2904
2947
  const viewport = vertical ? window.innerHeight : window.innerWidth;
2905
2948
  return viewport > 0 ? Math.min(natural, viewport) : natural;
@@ -2908,22 +2951,62 @@ var BottomSheetEngine = class {
2908
2951
  if (typeof ResizeObserver === "undefined") return;
2909
2952
  if (!this.snapPointsRaw.some((p) => p.size === "fit" || p.size === "content"))
2910
2953
  return;
2911
- const targets = [this.handle];
2912
- if (this.scrollContainer && this.scrollContainer !== this.handle) {
2913
- targets.push(this.scrollContainer);
2914
- }
2915
2954
  let raf = 0;
2916
- const ro = new ResizeObserver(() => {
2955
+ const schedule = () => {
2917
2956
  if (raf) return;
2918
2957
  raf = requestAnimationFrame(() => {
2919
2958
  raf = 0;
2920
2959
  if (this.destroyed || this.gesture?.isDragging) return;
2921
2960
  this.recompute();
2922
2961
  });
2923
- });
2924
- for (const t of targets) ro.observe(t);
2962
+ };
2963
+ const ro = new ResizeObserver(schedule);
2964
+ ro.observe(this.handle);
2965
+ const scroller = this.scrollContainer;
2966
+ const observed = /* @__PURE__ */ new Set();
2967
+ const slots = /* @__PURE__ */ new Set();
2968
+ const hasSlot = typeof HTMLSlotElement !== "undefined";
2969
+ const onSlotChange = () => resync();
2970
+ const trackSlots = () => {
2971
+ if (!scroller || !hasSlot) return;
2972
+ for (const child of Array.from(scroller.children)) {
2973
+ if (child instanceof HTMLSlotElement && !slots.has(child)) {
2974
+ child.addEventListener("slotchange", onSlotChange);
2975
+ slots.add(child);
2976
+ }
2977
+ }
2978
+ };
2979
+ const resync = () => {
2980
+ trackSlots();
2981
+ const targets = this.contentTargets();
2982
+ for (const el of observed) {
2983
+ if (!targets.includes(el)) {
2984
+ ro.unobserve(el);
2985
+ observed.delete(el);
2986
+ }
2987
+ }
2988
+ for (const el of targets) {
2989
+ if (!observed.has(el)) {
2990
+ ro.observe(el);
2991
+ observed.add(el);
2992
+ }
2993
+ }
2994
+ schedule();
2995
+ };
2996
+ let mo;
2997
+ if (scroller) {
2998
+ resync();
2999
+ if (typeof MutationObserver !== "undefined") {
3000
+ mo = new MutationObserver(resync);
3001
+ mo.observe(scroller, { childList: true });
3002
+ }
3003
+ }
2925
3004
  this.teardowns.add(() => {
2926
3005
  ro.disconnect();
3006
+ mo?.disconnect();
3007
+ for (const slot of slots) {
3008
+ slot.removeEventListener("slotchange", onSlotChange);
3009
+ }
2927
3010
  if (raf) cancelAnimationFrame(raf);
2928
3011
  });
2929
3012
  }
@@ -3344,6 +3427,38 @@ var BottomSheetEngine = class {
3344
3427
  }
3345
3428
  };
3346
3429
 
3430
+ // src/core/features/teleport.ts
3431
+ var resolveTeleportTarget = (target) => {
3432
+ if (!target) return null;
3433
+ if (typeof target !== "string") return target;
3434
+ if (typeof document === "undefined") return null;
3435
+ if (target === "body") return document.body;
3436
+ return document.querySelector(target);
3437
+ };
3438
+ var teleportElements = (els, target) => {
3439
+ const records = [];
3440
+ for (const el of els) {
3441
+ if (!el || el.parentNode === target) continue;
3442
+ records.push({ el, parent: el.parentNode, next: el.nextSibling });
3443
+ target.appendChild(el);
3444
+ }
3445
+ return () => {
3446
+ for (let i = records.length - 1; i >= 0; i--) {
3447
+ const { el, parent, next } = records[i];
3448
+ if (parent && parent.isConnected) {
3449
+ const before = next && next.parentNode === parent ? next : null;
3450
+ try {
3451
+ parent.insertBefore(el, before);
3452
+ } catch {
3453
+ el.parentNode?.removeChild(el);
3454
+ }
3455
+ } else {
3456
+ el.parentNode?.removeChild(el);
3457
+ }
3458
+ }
3459
+ };
3460
+ };
3461
+
3347
3462
  // src/vue/useBottomSheet.ts
3348
3463
  function useBottomSheet(opts) {
3349
3464
  const sheetRef = ref(null);
@@ -3360,13 +3475,20 @@ function useBottomSheet(opts) {
3360
3475
  isAnimating: false,
3361
3476
  progress: 0
3362
3477
  });
3478
+ let restoreTeleport = null;
3363
3479
  const sync = () => {
3364
3480
  if (!engine) return;
3365
3481
  Object.assign(state, engine.state);
3366
3482
  };
3367
3483
  onMounted(() => {
3368
3484
  if (!sheetRef.value) return;
3369
- const { onSnap, ...engineOpts } = opts;
3485
+ const {
3486
+ onSnap,
3487
+ teleportTo,
3488
+ backdropColor,
3489
+ backdropOpacity,
3490
+ ...engineOpts
3491
+ } = opts;
3370
3492
  engine = new BottomSheetEngine({
3371
3493
  ...engineOpts,
3372
3494
  element: sheetRef.value,
@@ -3376,6 +3498,17 @@ function useBottomSheet(opts) {
3376
3498
  scrim: screenRef.value ?? void 0
3377
3499
  });
3378
3500
  sync();
3501
+ const target = resolveTeleportTarget(teleportTo);
3502
+ if (target) {
3503
+ restoreTeleport = teleportElements(
3504
+ [backdropRef.value, screenRef.value, sheetRef.value],
3505
+ target
3506
+ );
3507
+ }
3508
+ if (backdropColor !== void 0) engine.setScrimColor(backdropColor);
3509
+ if (backdropOpacity !== void 0) {
3510
+ engine.setBackdropRange([0, backdropOpacity]);
3511
+ }
3379
3512
  engine.on("snap", (payload) => {
3380
3513
  sync();
3381
3514
  onSnap?.(payload.id);
@@ -3391,6 +3524,8 @@ function useBottomSheet(opts) {
3391
3524
  pending.length = 0;
3392
3525
  });
3393
3526
  onBeforeUnmount(() => {
3527
+ restoreTeleport?.();
3528
+ restoreTeleport = null;
3394
3529
  engine?.destroy();
3395
3530
  engine = null;
3396
3531
  });
@@ -3619,6 +3754,23 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
3619
3754
  type: null,
3620
3755
  required: false
3621
3756
  },
3757
+ teleportTo: {
3758
+ type: [
3759
+ String,
3760
+ null,
3761
+ Object
3762
+ ],
3763
+ required: false,
3764
+ default: "body"
3765
+ },
3766
+ backdropColor: {
3767
+ type: String,
3768
+ required: false
3769
+ },
3770
+ backdropOpacity: {
3771
+ type: Number,
3772
+ required: false
3773
+ },
3622
3774
  onSnap: {
3623
3775
  type: Function,
3624
3776
  required: false
@@ -3651,11 +3803,6 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
3651
3803
  required: false,
3652
3804
  default: true
3653
3805
  },
3654
- teleportTo: {
3655
- type: null,
3656
- required: false,
3657
- default: "body"
3658
- },
3659
3806
  anchors: {
3660
3807
  type: Array,
3661
3808
  required: false
@@ -3663,14 +3810,6 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
3663
3810
  scrimStages: {
3664
3811
  type: [Object, null],
3665
3812
  required: false
3666
- },
3667
- backdropColor: {
3668
- type: String,
3669
- required: false
3670
- },
3671
- backdropOpacity: {
3672
- type: Number,
3673
- required: false
3674
3813
  }
3675
3814
  },
3676
3815
  emits: [
@@ -3898,23 +4037,27 @@ var _hoisted_4 = [
3898
4037
  "aria-valuetext"
3899
4038
  ];
3900
4039
  var _hoisted_5 = {
4040
+ key: 0,
4041
+ class: "bs-header"
4042
+ };
4043
+ var _hoisted_6 = {
3901
4044
  ref: "contentRef",
3902
4045
  class: "bs-content",
3903
4046
  tabindex: "0",
3904
4047
  role: "region",
3905
4048
  "aria-label": "Sheet content"
3906
4049
  };
3907
- var _hoisted_6 = {
3908
- key: 0,
4050
+ var _hoisted_7 = {
4051
+ key: 1,
3909
4052
  class: "bs-footer"
3910
4053
  };
3911
- var _hoisted_7 = {
4054
+ var _hoisted_8 = {
3912
4055
  class: "bs-sr-only",
3913
4056
  role: "status",
3914
4057
  "aria-live": "polite"
3915
4058
  };
3916
- var _hoisted_8 = ["data-mode"];
3917
4059
  var _hoisted_9 = ["data-mode"];
4060
+ var _hoisted_10 = ["data-mode"];
3918
4061
  function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
3919
4062
  return openBlock(), createBlock(Teleport, {
3920
4063
  to: $props.teleportTo,
@@ -3960,18 +4103,19 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
3960
4103
  "aria-valuenow": $setup.activeIdx,
3961
4104
  "aria-valuetext": $setup.state.activeId,
3962
4105
  "aria-label": "Resize sheet"
3963
- }, [renderSlot(_ctx.$slots, "header", { state: $setup.state })], 8, _hoisted_4),
4106
+ }, null, 8, _hoisted_4),
4107
+ _ctx.$slots.header ? (openBlock(), createElementBlock("div", _hoisted_5, [renderSlot(_ctx.$slots, "header", { state: $setup.state })])) : createCommentVNode("v-if", true),
3964
4108
  createElementVNode(
3965
4109
  "div",
3966
- _hoisted_5,
4110
+ _hoisted_6,
3967
4111
  [renderSlot(_ctx.$slots, "default")],
3968
4112
  512
3969
4113
  /* NEED_PATCH */
3970
4114
  ),
3971
- _ctx.$slots.footer ? (openBlock(), createElementBlock("div", _hoisted_6, [renderSlot(_ctx.$slots, "footer", { state: $setup.state })])) : createCommentVNode("v-if", true),
4115
+ _ctx.$slots.footer ? (openBlock(), createElementBlock("div", _hoisted_7, [renderSlot(_ctx.$slots, "footer", { state: $setup.state })])) : createCommentVNode("v-if", true),
3972
4116
  createElementVNode(
3973
4117
  "span",
3974
- _hoisted_7,
4118
+ _hoisted_8,
3975
4119
  toDisplayString($setup.state.activeId),
3976
4120
  1
3977
4121
  /* TEXT */
@@ -3982,13 +4126,13 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
3982
4126
  class: "bs-button-slot",
3983
4127
  "data-side": "left",
3984
4128
  "data-mode": $setup.props.mode ?? "bottom"
3985
- }, [renderSlot(_ctx.$slots, "button-left")], 8, _hoisted_8)) : createCommentVNode("v-if", true),
4129
+ }, [renderSlot(_ctx.$slots, "button-left")], 8, _hoisted_9)) : createCommentVNode("v-if", true),
3986
4130
  _ctx.$slots["button-right"] ? (openBlock(), createElementBlock("div", {
3987
4131
  key: 2,
3988
4132
  class: "bs-button-slot",
3989
4133
  "data-side": "right",
3990
4134
  "data-mode": $setup.props.mode ?? "bottom"
3991
- }, [renderSlot(_ctx.$slots, "button-right")], 8, _hoisted_9)) : createCommentVNode("v-if", true)
4135
+ }, [renderSlot(_ctx.$slots, "button-right")], 8, _hoisted_10)) : createCommentVNode("v-if", true)
3992
4136
  ]), (openBlock(true), createElementBlock(
3993
4137
  Fragment,
3994
4138
  null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@surdeddd/bottom-sheet",
3
- "version": "0.4.1",
3
+ "version": "0.6.0",
4
4
  "description": "Universal, headless bottom sheet — framework-agnostic core with React, Vue 3, Svelte, Solid, Qwik, Preact, Lit and Custom Element adapters. Pointer Events, snap points, momentum, a11y, SSR-safe.",
5
5
  "type": "module",
6
6
  "license": "MIT",