@surdeddd/bottom-sheet 0.9.1 → 0.10.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 (50) hide show
  1. package/README.md +108 -66
  2. package/dist/{BottomSheetEngine-CBRcBwV-.d.ts → BottomSheetEngine-DRjCU73e.d.ts} +6 -5
  3. package/dist/{BottomSheetEngine-BcyruNP1.d.cts → BottomSheetEngine-DzsIwD28.d.cts} +6 -5
  4. package/dist/element.cjs +161 -99
  5. package/dist/element.d.cts +1 -1
  6. package/dist/element.d.ts +1 -1
  7. package/dist/element.iife.global.js +2 -2
  8. package/dist/element.js +161 -99
  9. package/dist/index.cjs +155 -115
  10. package/dist/index.d.cts +2 -2
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.js +155 -115
  13. package/dist/integrations/formik.d.cts +1 -1
  14. package/dist/integrations/formik.d.ts +1 -1
  15. package/dist/integrations/react-hook-form.d.cts +1 -1
  16. package/dist/integrations/react-hook-form.d.ts +1 -1
  17. package/dist/overlay.cjs +34 -25
  18. package/dist/overlay.d.cts +3 -0
  19. package/dist/overlay.d.ts +3 -0
  20. package/dist/overlay.js +34 -25
  21. package/dist/preact.d.cts +2 -1
  22. package/dist/preact.d.ts +2 -1
  23. package/dist/qwik.cjs +179 -93
  24. package/dist/qwik.d.cts +11 -2
  25. package/dist/qwik.d.ts +11 -2
  26. package/dist/qwik.js +179 -93
  27. package/dist/react.cjs +266 -181
  28. package/dist/react.d.cts +26 -4
  29. package/dist/react.d.ts +26 -4
  30. package/dist/react.js +266 -181
  31. package/dist/solid.cjs +145 -92
  32. package/dist/solid.d.cts +14 -4
  33. package/dist/solid.d.ts +14 -4
  34. package/dist/solid.js +145 -92
  35. package/dist/solid.source.jsx +145 -92
  36. package/dist/styles.css +17 -1
  37. package/dist/svelte-core.cjs +128 -90
  38. package/dist/svelte-core.js +128 -90
  39. package/dist/svelte-src/BottomSheet.svelte +6 -0
  40. package/dist/svelte.cjs +130 -90
  41. package/dist/svelte.d.cts +2 -0
  42. package/dist/svelte.d.ts +2 -0
  43. package/dist/svelte.js +130 -90
  44. package/dist/teleport-7uYNiEAT.d.cts +3 -0
  45. package/dist/teleport-7uYNiEAT.d.ts +3 -0
  46. package/dist/vue.cjs +136 -91
  47. package/dist/vue.d.cts +3 -1
  48. package/dist/vue.d.ts +3 -1
  49. package/dist/vue.js +136 -91
  50. package/package.json +6 -6
package/dist/overlay.js CHANGED
@@ -118,6 +118,13 @@ var resolveSnap = (point, mode, measureFit) => {
118
118
  }
119
119
  };
120
120
 
121
+ // src/core/primitives/devWarn.ts
122
+ function devWarn(...args) {
123
+ if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
124
+ console.warn(...args);
125
+ }
126
+ }
127
+
121
128
  // src/core/primitives/instance-id.ts
122
129
  var counters = {};
123
130
  function nextInstanceId(prefix) {
@@ -520,7 +527,7 @@ function installOverlaySwipe(deps) {
520
527
  };
521
528
  }
522
529
 
523
- // src/core/overlay.ts
530
+ // src/core/overlay-options.ts
524
531
  var OVERLAY_PRESETS = Object.freeze({
525
532
  sheet: Object.freeze({
526
533
  enterAnimation: "slide",
@@ -551,6 +558,8 @@ var OVERLAY_PRESETS = Object.freeze({
551
558
  swipeToClose: false
552
559
  })
553
560
  });
561
+
562
+ // src/core/overlay.ts
554
563
  var OverlayEngine = class {
555
564
  constructor(opts) {
556
565
  __publicField(this, "id", nextInstanceId("ovl"));
@@ -627,7 +636,7 @@ var OverlayEngine = class {
627
636
  this.onOpenCb = opts.onOpen;
628
637
  this.onCloseCb = opts.onClose;
629
638
  if (this.peekRaw !== void 0 && this.edge !== "bottom") {
630
- console.warn(
639
+ devWarn(
631
640
  "[OverlayEngine] `peek` is only supported on edge: 'bottom' \u2014 ignoring."
632
641
  );
633
642
  this.peekRaw = void 0;
@@ -694,10 +703,9 @@ var OverlayEngine = class {
694
703
  this.element.style.opacity = "1";
695
704
  if (this.backdrop) {
696
705
  this.backdrop.style.opacity = String(this.backdropOpacity);
697
- this.backdrop.style.pointerEvents = this.backdropOpacity > 0 ? "auto" : "none";
706
+ this.syncBackdropPointerEvents();
698
707
  if (this.backdropFilter) {
699
- this.backdrop.style.backdropFilter = this.backdropFilter;
700
- this.backdrop.style.webkitBackdropFilter = this.backdropFilter;
708
+ this.applyBackdropFilter(this.backdropFilter);
701
709
  }
702
710
  }
703
711
  try {
@@ -717,8 +725,7 @@ var OverlayEngine = class {
717
725
  this.backdrop.style.opacity = "0";
718
726
  this.backdrop.style.pointerEvents = "none";
719
727
  if (this.backdropFilter) {
720
- this.backdrop.style.backdropFilter = "";
721
- this.backdrop.style.webkitBackdropFilter = "";
728
+ this.applyBackdropFilter(void 0);
722
729
  }
723
730
  }
724
731
  this.element.setAttribute("data-state", "closed");
@@ -776,8 +783,7 @@ var OverlayEngine = class {
776
783
  this.backdrop.style.opacity = "0";
777
784
  this.backdrop.style.pointerEvents = "none";
778
785
  if (this.backdropFilter) {
779
- this.backdrop.style.backdropFilter = "";
780
- this.backdrop.style.webkitBackdropFilter = "";
786
+ this.applyBackdropFilter(void 0);
781
787
  }
782
788
  }
783
789
  this.releaseInteractiveListeners();
@@ -825,20 +831,14 @@ var OverlayEngine = class {
825
831
  this.backdropOpacity = opacity;
826
832
  if (this.isOpen_ && this.backdrop) {
827
833
  this.backdrop.style.opacity = String(opacity);
834
+ this.syncBackdropPointerEvents();
828
835
  }
829
836
  }
830
837
  setBackdropFilter(filter) {
831
838
  if (this.destroyed) return;
832
839
  this.backdropFilter = filter;
833
840
  if (!this.isOpen_ || !this.backdrop) return;
834
- const style = this.backdrop.style;
835
- if (filter) {
836
- this.backdrop.style.backdropFilter = filter;
837
- style.webkitBackdropFilter = filter;
838
- } else {
839
- this.backdrop.style.backdropFilter = "";
840
- style.webkitBackdropFilter = "";
841
- }
841
+ this.applyBackdropFilter(filter);
842
842
  }
843
843
  setSwipeToClose(config) {
844
844
  if (this.destroyed) return;
@@ -907,16 +907,10 @@ var OverlayEngine = class {
907
907
  if (this.isOpen_ && this.backdrop) {
908
908
  if (merged.backdropOpacity !== void 0) {
909
909
  this.backdrop.style.opacity = String(this.backdropOpacity);
910
+ this.syncBackdropPointerEvents();
910
911
  }
911
912
  if (merged.backdropFilter !== void 0) {
912
- const style = this.backdrop.style;
913
- if (this.backdropFilter) {
914
- this.backdrop.style.backdropFilter = this.backdropFilter;
915
- style.webkitBackdropFilter = this.backdropFilter;
916
- } else {
917
- this.backdrop.style.backdropFilter = "";
918
- style.webkitBackdropFilter = "";
919
- }
913
+ this.applyBackdropFilter(this.backdropFilter);
920
914
  }
921
915
  }
922
916
  if (opts.duration !== void 0) this.duration = opts.duration;
@@ -1051,6 +1045,21 @@ var OverlayEngine = class {
1051
1045
  this.backdrop.style.pointerEvents = "none";
1052
1046
  }
1053
1047
  }
1048
+ syncBackdropPointerEvents() {
1049
+ if (!this.backdrop) return;
1050
+ this.backdrop.style.pointerEvents = this.backdropOpacity > 0 ? "auto" : "none";
1051
+ }
1052
+ applyBackdropFilter(filter) {
1053
+ if (!this.backdrop) return;
1054
+ const style = this.backdrop.style;
1055
+ if (filter) {
1056
+ this.backdrop.style.backdropFilter = filter;
1057
+ style.webkitBackdropFilter = filter;
1058
+ } else {
1059
+ this.backdrop.style.backdropFilter = "";
1060
+ style.webkitBackdropFilter = "";
1061
+ }
1062
+ }
1054
1063
  setWillChange(on) {
1055
1064
  this.element.style.willChange = on ? "transform, opacity" : "";
1056
1065
  if (this.backdrop) {
package/dist/preact.d.cts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { BottomSheet, BottomSheetFromConfig, BottomSheetFromConfigProps, BottomSheetHandle, BottomSheetProps, HeaderProp, Overlay, OverlayHandle, OverlayProps, SheetConfig, UseBottomSheetRefs, UseBottomSheetReturn, UseOverlayReturn, useBottomSheet, useOverlay } from './react.cjs';
2
- export { E as EngineState, b as SheetMode, d as SnapPoint, a as SnapPointDef } from './BottomSheetEngine-BcyruNP1.cjs';
2
+ export { E as EngineState, b as SheetMode, e as SnapPoint, a as SnapPointDef } from './BottomSheetEngine-DzsIwD28.cjs';
3
3
  export { OverlayEdge, OverlayOptions, OverlayState } from './overlay.cjs';
4
4
  import 'react';
5
+ import './teleport-7uYNiEAT.cjs';
5
6
  import './transform-jVfAikE9.cjs';
package/dist/preact.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { BottomSheet, BottomSheetFromConfig, BottomSheetFromConfigProps, BottomSheetHandle, BottomSheetProps, HeaderProp, Overlay, OverlayHandle, OverlayProps, SheetConfig, UseBottomSheetRefs, UseBottomSheetReturn, UseOverlayReturn, useBottomSheet, useOverlay } from './react.js';
2
- export { E as EngineState, b as SheetMode, d as SnapPoint, a as SnapPointDef } from './BottomSheetEngine-CBRcBwV-.js';
2
+ export { E as EngineState, b as SheetMode, e as SnapPoint, a as SnapPointDef } from './BottomSheetEngine-DRjCU73e.js';
3
3
  export { OverlayEdge, OverlayOptions, OverlayState } from './overlay.js';
4
4
  import 'react';
5
+ import './teleport-7uYNiEAT.js';
5
6
  import './transform-jVfAikE9.js';
package/dist/qwik.cjs CHANGED
@@ -186,11 +186,18 @@ var resolveSnap = (point, mode, measureFit) => {
186
186
  return Math.max(0, el.getBoundingClientRect().width);
187
187
  };
188
188
 
189
+ // src/core/primitives/devWarn.ts
190
+ function devWarn(...args) {
191
+ if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
192
+ console.warn(...args);
193
+ }
194
+ }
195
+
189
196
  // src/core/primitives/snap-points.ts
190
197
  var resolveSnapList = (points, mode, measureFit) => points.map((p) => {
191
198
  const raw = resolveSnap(p.size, mode, measureFit);
192
199
  if (!Number.isFinite(raw) || raw < 0) {
193
- console.warn(
200
+ devWarn(
194
201
  `[BottomSheet] snap "${p.id}" resolved to invalid size (${String(p.size)} \u2192 ${raw}); clamped to 0.`
195
202
  );
196
203
  return { id: p.id, size: 0 };
@@ -202,7 +209,7 @@ var auditVhUsage = (points) => {
202
209
  for (const p of points) {
203
210
  if (typeof p.size !== "string") continue;
204
211
  if (!VH_NOT_DVH.test(p.size)) continue;
205
- console.warn(
212
+ devWarn(
206
213
  `[BottomSheet] snap "${p.id}" uses "vh" \u2014 prefer "dvh" on mobile (iOS Safari URL bar makes vh unstable). See https://web.dev/blog/viewport-units`
207
214
  );
208
215
  }
@@ -256,6 +263,26 @@ var findDragSettleTarget = (input) => {
256
263
  );
257
264
  };
258
265
 
266
+ // src/core/primitives/cancelable-emit.ts
267
+ function emitCancelable(emit, base, warnLabel) {
268
+ let cancelled = false;
269
+ let frozen = false;
270
+ emit({
271
+ ...base,
272
+ cancel: () => {
273
+ if (frozen) {
274
+ devWarn(
275
+ `[BottomSheet] ${warnLabel}.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener.`
276
+ );
277
+ return;
278
+ }
279
+ cancelled = true;
280
+ }
281
+ });
282
+ frozen = true;
283
+ return cancelled;
284
+ }
285
+
259
286
  // src/core/primitives/snap-resolver.ts
260
287
  var SnapResolver = class {
261
288
  constructor(raw, allowed, mode, measureFit, onMaxAxisSizeChange) {
@@ -400,7 +427,9 @@ function notifyLinkedSheets(sheets, self) {
400
427
  try {
401
428
  if (linked.state.size === 0) continue;
402
429
  const ids = linked.getAllowedIds();
403
- const target = ids.find((id) => id !== "closed");
430
+ const resolved = linked.getResolvedSnaps();
431
+ const sizeOf = (id) => resolved.find((s) => s.id === id)?.size ?? 0;
432
+ const target = ids.find((id) => sizeOf(id) > 0);
404
433
  if (target && target !== linked.state.activeId) {
405
434
  void linked.snapTo(target);
406
435
  }
@@ -617,11 +646,15 @@ function installVisualViewport(deps) {
617
646
  if (clamp < deps.getMaxAxisSize()) {
618
647
  deps.setMaxAxisSize(clamp);
619
648
  }
649
+ const wasAnimating = deps.isAnimating?.() ?? false;
650
+ deps.cancelInFlight();
651
+ deps.newCycle();
620
652
  const max = deps.getMaxAxisSize();
621
653
  deps.setSize(Math.min(deps.getSize(), max));
622
654
  const current = deps.resolveActiveSnap();
623
655
  if (current && !deps.isDragging()) {
624
656
  deps.applySize(Math.min(current.size, max));
657
+ if (wasAnimating) deps.resyncAfterCancel?.();
625
658
  } else {
626
659
  deps.applySize(deps.getSize());
627
660
  }
@@ -762,6 +795,54 @@ function installFitObserver(deps) {
762
795
  };
763
796
  }
764
797
 
798
+ // src/core/features/max-height-controller.ts
799
+ function createMaxHeightController(deps) {
800
+ let maxHeightCap;
801
+ let maxHeightRaw;
802
+ const resolveCap = () => {
803
+ const raw = maxHeightRaw;
804
+ if (raw === void 0) {
805
+ maxHeightCap = void 0;
806
+ return;
807
+ }
808
+ if (typeof raw === "number") {
809
+ maxHeightCap = raw;
810
+ return;
811
+ }
812
+ if (typeof window === "undefined") return;
813
+ const measured = resolveSnap(raw, deps.mode);
814
+ maxHeightCap = measured > 0 ? measured : void 0;
815
+ };
816
+ const clampTo = () => {
817
+ if (maxHeightCap === void 0) return;
818
+ if (deps.getMaxAxisSize() > maxHeightCap) {
819
+ deps.setMaxAxisSize(maxHeightCap);
820
+ }
821
+ };
822
+ return {
823
+ setRadius(r) {
824
+ deps.element.style.setProperty(
825
+ "--bs-radius",
826
+ typeof r === "number" ? `${r}px` : r
827
+ );
828
+ },
829
+ setMaxHeight(h) {
830
+ const value = typeof h === "number" ? `${h}px` : h;
831
+ const axis = layoutAxis(deps.mode);
832
+ deps.element.style.setProperty(
833
+ axis === "height" ? "max-height" : "max-width",
834
+ value
835
+ );
836
+ maxHeightRaw = h;
837
+ resolveCap();
838
+ deps.recompute();
839
+ },
840
+ resolveCap,
841
+ clampTo,
842
+ getCap: () => maxHeightCap
843
+ };
844
+ }
845
+
765
846
  // src/core/features/fit-measurement.ts
766
847
  var measureSheetNatural = (element, content, vertical) => {
767
848
  if (!content) {
@@ -893,13 +974,6 @@ var WriteSentinel = class {
893
974
  }
894
975
  };
895
976
 
896
- // src/core/primitives/devWarn.ts
897
- function devWarn(...args) {
898
- if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
899
- console.warn(...args);
900
- }
901
- }
902
-
903
977
  // src/core/primitives/overlay-position.ts
904
978
  function resolveSheetAnchoredStyle(mode, position, inset) {
905
979
  const sizeOffset = `calc(var(--bs-size, 0px) + ${inset})`;
@@ -2545,8 +2619,7 @@ var BottomSheetEngine = class {
2545
2619
  __publicField(this, "disableCloseFlag");
2546
2620
  __publicField(this, "disableDragFlag");
2547
2621
  __publicField(this, "closeOnRouteChange");
2548
- __publicField(this, "maxHeightCap");
2549
- __publicField(this, "maxHeightRaw");
2622
+ __publicField(this, "maxHeight");
2550
2623
  __publicField(this, "snapPointsRaw");
2551
2624
  __publicField(this, "snaps");
2552
2625
  __publicField(this, "activeId");
@@ -2657,11 +2730,20 @@ var BottomSheetEngine = class {
2657
2730
  auditVhUsage(this.snapPointsRaw);
2658
2731
  this.auditDuplicateSnapIds(this.snapPointsRaw);
2659
2732
  this.rootEl = this.element.closest(".bs-root");
2733
+ this.maxHeight = createMaxHeightController({
2734
+ element: this.element,
2735
+ mode: this.mode,
2736
+ getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
2737
+ setMaxAxisSize: (size) => {
2738
+ this.snaps.setMaxAxisSize(size);
2739
+ },
2740
+ recompute: () => this.recompute()
2741
+ });
2660
2742
  this.fitDeps = {
2661
2743
  element: this.element,
2662
2744
  scrollContainer: this.scrollContainer,
2663
2745
  mode: this.mode,
2664
- getMaxHeightCap: () => this.maxHeightCap
2746
+ getMaxHeightCap: () => this.maxHeight.getCap()
2665
2747
  };
2666
2748
  this.snaps = new SnapResolver(
2667
2749
  this.snapPointsRaw,
@@ -2772,7 +2854,7 @@ var BottomSheetEngine = class {
2772
2854
  }
2773
2855
  use(plugin) {
2774
2856
  if (this.destroyed) {
2775
- console.warn(
2857
+ devWarn(
2776
2858
  `[BottomSheet] use("${plugin.name}") called on destroyed engine \u2014 ignored.`
2777
2859
  );
2778
2860
  return this;
@@ -2814,6 +2896,9 @@ var BottomSheetEngine = class {
2814
2896
  getAllowedIds() {
2815
2897
  return this.snaps.getAllowedIds().slice();
2816
2898
  }
2899
+ getResolvedSnaps() {
2900
+ return this.snaps.getResolvedSnaps();
2901
+ }
2817
2902
  async snapTo(id, velocityOrOpts = 0, _skipBeforeSnap = false) {
2818
2903
  if (this.destroyed) return;
2819
2904
  const opts = typeof velocityOrOpts === "object" ? velocityOrOpts : { velocity: velocityOrOpts };
@@ -2822,11 +2907,11 @@ var BottomSheetEngine = class {
2822
2907
  if (externalSignal?.aborted) return;
2823
2908
  const target = this.snaps.findById(id);
2824
2909
  if (!target) {
2825
- console.warn(`[BottomSheet] unknown snap id: ${id}`);
2910
+ devWarn(`[BottomSheet] unknown snap id: ${id}`);
2826
2911
  return;
2827
2912
  }
2828
2913
  if (!this.snaps.getAllowedIds().includes(id)) {
2829
- console.warn(`[BottomSheet] snap "${id}" is not in allowed list`);
2914
+ devWarn(`[BottomSheet] snap "${id}" is not in allowed list`);
2830
2915
  return;
2831
2916
  }
2832
2917
  if (!_skipBeforeSnap && this.emitBeforeSnap(target, this.activeId)) {
@@ -2958,42 +3043,11 @@ var BottomSheetEngine = class {
2958
3043
  }
2959
3044
  setRadius(r) {
2960
3045
  if (this.destroyed) return;
2961
- this.element.style.setProperty(
2962
- "--bs-radius",
2963
- typeof r === "number" ? `${r}px` : r
2964
- );
3046
+ this.maxHeight.setRadius(r);
2965
3047
  }
2966
3048
  setMaxHeight(h) {
2967
3049
  if (this.destroyed) return;
2968
- const value = typeof h === "number" ? `${h}px` : h;
2969
- const axis = layoutAxis(this.mode);
2970
- this.element.style.setProperty(
2971
- axis === "height" ? "max-height" : "max-width",
2972
- value
2973
- );
2974
- this.maxHeightRaw = h;
2975
- this.resolveMaxHeightCap();
2976
- this.recompute();
2977
- }
2978
- resolveMaxHeightCap() {
2979
- const raw = this.maxHeightRaw;
2980
- if (raw === void 0) {
2981
- this.maxHeightCap = void 0;
2982
- return;
2983
- }
2984
- if (typeof raw === "number") {
2985
- this.maxHeightCap = raw;
2986
- return;
2987
- }
2988
- if (typeof window === "undefined") return;
2989
- const measured = resolveSnap(raw, this.mode);
2990
- this.maxHeightCap = measured > 0 ? measured : void 0;
2991
- }
2992
- clampToMaxHeight() {
2993
- if (this.maxHeightCap === void 0) return;
2994
- if (this.snaps.getMaxAxisSize() > this.maxHeightCap) {
2995
- this.snaps.setMaxAxisSize(this.maxHeightCap);
2996
- }
3050
+ this.maxHeight.setMaxHeight(h);
2997
3051
  }
2998
3052
  setAllowed(ids, snap) {
2999
3053
  if (this.destroyed) return;
@@ -3081,7 +3135,7 @@ var BottomSheetEngine = class {
3081
3135
  };
3082
3136
  const host = this.screenComponent?.parentElement;
3083
3137
  if (!host) {
3084
- console.warn(
3138
+ devWarn(
3085
3139
  "[BottomSheet] setScrimStages: no scrim element mounted \u2014 pass `scrim` to the engine first."
3086
3140
  );
3087
3141
  return () => {
@@ -3131,9 +3185,9 @@ var BottomSheetEngine = class {
3131
3185
  }
3132
3186
  recompute() {
3133
3187
  if (this.destroyed) return;
3134
- this.resolveMaxHeightCap();
3188
+ this.maxHeight.resolveCap();
3135
3189
  this.snaps.recompute();
3136
- this.clampToMaxHeight();
3190
+ this.maxHeight.clampTo();
3137
3191
  this.scrim.invalidateOpacityCache();
3138
3192
  if (this.gesture?.isDragging) return;
3139
3193
  const current = this.snaps.findById(this.activeId);
@@ -3183,42 +3237,18 @@ var BottomSheetEngine = class {
3183
3237
  return this.currentAbort.signal;
3184
3238
  }
3185
3239
  emitBeforeSnap(target, previousId) {
3186
- let cancelled = false;
3187
- let frozen = false;
3188
- this.emit("before-snap", {
3189
- id: target.id,
3190
- size: target.size,
3191
- previousId,
3192
- cancel: () => {
3193
- if (frozen) {
3194
- console.warn(
3195
- "[BottomSheet] before-snap.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener."
3196
- );
3197
- return;
3198
- }
3199
- cancelled = true;
3200
- }
3201
- });
3202
- frozen = true;
3203
- return cancelled;
3240
+ return emitCancelable(
3241
+ (payload) => this.emit("before-snap", payload),
3242
+ { id: target.id, size: target.size, previousId },
3243
+ "before-snap"
3244
+ );
3204
3245
  }
3205
3246
  emitBeforeClose(reason) {
3206
- let cancelled = false;
3207
- let frozen = false;
3208
- this.emit("before-close", {
3209
- reason,
3210
- cancel: () => {
3211
- if (frozen) {
3212
- console.warn(
3213
- "[BottomSheet] before-close.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener."
3214
- );
3215
- return;
3216
- }
3217
- cancelled = true;
3218
- }
3219
- });
3220
- frozen = true;
3221
- return cancelled;
3247
+ return emitCancelable(
3248
+ (payload) => this.emit("before-close", payload),
3249
+ { reason },
3250
+ "before-close"
3251
+ );
3222
3252
  }
3223
3253
  applyAutoAriaLabelledBy() {
3224
3254
  if (typeof document === "undefined") return;
@@ -3233,16 +3263,16 @@ var BottomSheetEngine = class {
3233
3263
  this.element.setAttribute("aria-labelledby", titled.id);
3234
3264
  }
3235
3265
  recomputeSnaps() {
3236
- this.resolveMaxHeightCap();
3266
+ this.maxHeight.resolveCap();
3237
3267
  this.snaps.setRaw(this.snapPointsRaw);
3238
- this.clampToMaxHeight();
3268
+ this.maxHeight.clampTo();
3239
3269
  this.scrim.invalidateOpacityCache();
3240
3270
  }
3241
3271
  auditDuplicateSnapIds(points) {
3242
3272
  const seen = /* @__PURE__ */ new Set();
3243
3273
  for (const p of points) {
3244
3274
  if (seen.has(p.id)) {
3245
- console.warn(
3275
+ devWarn(
3246
3276
  `[BottomSheet] duplicate snap id "${p.id}" \u2014 only the first occurrence is reachable.`
3247
3277
  );
3248
3278
  }
@@ -3409,7 +3439,15 @@ var BottomSheetEngine = class {
3409
3439
  setSize: (size) => {
3410
3440
  this.size = size;
3411
3441
  },
3412
- applySize: (size) => this.applySize(size)
3442
+ applySize: (size) => this.applySize(size),
3443
+ cancelInFlight: () => {
3444
+ this.animation.cancel();
3445
+ },
3446
+ newCycle: () => {
3447
+ this.newCycle();
3448
+ },
3449
+ isAnimating: () => this.animation.isAnimating,
3450
+ resyncAfterCancel: () => this.resyncAfterResize()
3413
3451
  }));
3414
3452
  }
3415
3453
  this.teardowns.add(installSliderKeyboard({
@@ -3570,6 +3608,38 @@ var BottomSheetEngine = class {
3570
3608
  sheetStack.update();
3571
3609
  }
3572
3610
  };
3611
+
3612
+ // src/core/features/teleport.ts
3613
+ var resolveTeleportTarget = (target) => {
3614
+ if (!target) return null;
3615
+ if (typeof target !== "string") return target;
3616
+ if (typeof document === "undefined") return null;
3617
+ if (target === "body") return document.body;
3618
+ return document.querySelector(target);
3619
+ };
3620
+ var teleportElements = (els, target) => {
3621
+ const records = [];
3622
+ for (const el of els) {
3623
+ if (!el || el.parentNode === target) continue;
3624
+ records.push({ el, parent: el.parentNode, next: el.nextSibling });
3625
+ target.appendChild(el);
3626
+ }
3627
+ return () => {
3628
+ for (let i = records.length - 1; i >= 0; i--) {
3629
+ const { el, parent, next } = records[i];
3630
+ if (parent && parent.isConnected) {
3631
+ const before = next && next.parentNode === parent ? next : null;
3632
+ try {
3633
+ parent.insertBefore(el, before);
3634
+ } catch {
3635
+ el.parentNode?.removeChild(el);
3636
+ }
3637
+ } else {
3638
+ el.parentNode?.removeChild(el);
3639
+ }
3640
+ }
3641
+ };
3642
+ };
3573
3643
  var BottomSheet = qwik.component$((props) => {
3574
3644
  const sheetRef = qwik.useSignal();
3575
3645
  const handleRef = qwik.useSignal();
@@ -3592,7 +3662,7 @@ var BottomSheet = qwik.component$((props) => {
3592
3662
  qwik.useVisibleTask$(({ cleanup }) => {
3593
3663
  if (!sheetRef.value) return;
3594
3664
  if (!handleRef.value || !contentRef.value) {
3595
- console.warn(
3665
+ devWarn(
3596
3666
  "[BottomSheet/qwik] handle or content ref missing at attach time \u2014 drag and content-swipe disabled. Make sure ref bindings render before useVisibleTask$ fires."
3597
3667
  );
3598
3668
  }
@@ -3625,6 +3695,11 @@ var BottomSheet = qwik.component$((props) => {
3625
3695
  };
3626
3696
  const engine = new BottomSheetEngine(engineOpts);
3627
3697
  engineStore.engine = qwik.noSerialize(engine);
3698
+ const teleportTarget = props.teleport === false ? null : resolveTeleportTarget(props.teleportTo);
3699
+ const restoreTeleport = teleportTarget ? teleportElements(
3700
+ [backdropRef.value, scrimRef.value, sheetRef.value],
3701
+ teleportTarget
3702
+ ) : null;
3628
3703
  const sync = () => {
3629
3704
  const s = engine.state;
3630
3705
  state.size = s.size;
@@ -3639,8 +3714,18 @@ var BottomSheet = qwik.component$((props) => {
3639
3714
  sync();
3640
3715
  props.onSnap$?.(payload.id);
3641
3716
  });
3642
- engine.on("dragstart", sync);
3643
- engine.on("dragend", sync);
3717
+ engine.on("open", (payload) => props.onOpen$?.(payload.id));
3718
+ engine.on("close", () => props.onClose$?.());
3719
+ engine.on("opened", (payload) => props.onOpened$?.(payload.id));
3720
+ engine.on("closed", () => props.onClosed$?.());
3721
+ engine.on("dragstart", (payload) => {
3722
+ sync();
3723
+ props.onDragStart$?.(payload);
3724
+ });
3725
+ engine.on("dragend", (payload) => {
3726
+ sync();
3727
+ props.onDragEnd$?.(payload);
3728
+ });
3644
3729
  let onBackdropClick;
3645
3730
  if (props.backdrop !== false && props.closeOnBackdrop !== false && backdropRef.value) {
3646
3731
  onBackdropClick = () => {
@@ -3684,6 +3769,7 @@ var BottomSheet = qwik.component$((props) => {
3684
3769
  if (onBackdropClick && backdropRef.value) {
3685
3770
  backdropRef.value.removeEventListener("click", onBackdropClick);
3686
3771
  }
3772
+ restoreTeleport?.();
3687
3773
  engineStore.engine = void 0;
3688
3774
  engine.destroy();
3689
3775
  });
package/dist/qwik.d.cts CHANGED
@@ -1,7 +1,8 @@
1
1
  import * as _builder_io_qwik from '@builder.io/qwik';
2
2
  import { QRL } from '@builder.io/qwik';
3
- import { a as SnapPointDef, b as SheetMode, c as EngineOptions, E as EngineState } from './BottomSheetEngine-BcyruNP1.cjs';
4
- export { d as SnapPoint } from './BottomSheetEngine-BcyruNP1.cjs';
3
+ import { T as TeleportTarget } from './teleport-7uYNiEAT.cjs';
4
+ import { a as SnapPointDef, b as SheetMode, c as EngineOptions, d as SheetEventMap, E as EngineState } from './BottomSheetEngine-DzsIwD28.cjs';
5
+ export { e as SnapPoint } from './BottomSheetEngine-DzsIwD28.cjs';
5
6
  import './transform-jVfAikE9.cjs';
6
7
 
7
8
  type BottomSheetProps<TId extends string = string> = {
@@ -28,11 +29,19 @@ type BottomSheetProps<TId extends string = string> = {
28
29
  disableDrag?: boolean;
29
30
  closeOnRouteChange?: boolean;
30
31
  stackEffect?: boolean;
32
+ teleport?: boolean;
33
+ teleportTo?: TeleportTarget;
31
34
  returnFocusTo?: EngineOptions["returnFocusTo"];
32
35
  ariaLabel?: string;
33
36
  radius?: string | number;
34
37
  maxHeight?: string | number;
35
38
  onSnap$?: QRL<(id: TId) => void>;
39
+ onOpen$?: QRL<(id: TId) => void>;
40
+ onClose$?: QRL<() => void>;
41
+ onOpened$?: QRL<(id: TId) => void>;
42
+ onClosed$?: QRL<() => void>;
43
+ onDragStart$?: QRL<(payload: SheetEventMap["dragstart"]) => void>;
44
+ onDragEnd$?: QRL<(payload: SheetEventMap["dragend"]) => void>;
36
45
  onChange$?: QRL<(state: EngineState & {
37
46
  activeId: TId;
38
47
  }) => void>;
package/dist/qwik.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import * as _builder_io_qwik from '@builder.io/qwik';
2
2
  import { QRL } from '@builder.io/qwik';
3
- import { a as SnapPointDef, b as SheetMode, c as EngineOptions, E as EngineState } from './BottomSheetEngine-CBRcBwV-.js';
4
- export { d as SnapPoint } from './BottomSheetEngine-CBRcBwV-.js';
3
+ import { T as TeleportTarget } from './teleport-7uYNiEAT.js';
4
+ import { a as SnapPointDef, b as SheetMode, c as EngineOptions, d as SheetEventMap, E as EngineState } from './BottomSheetEngine-DRjCU73e.js';
5
+ export { e as SnapPoint } from './BottomSheetEngine-DRjCU73e.js';
5
6
  import './transform-jVfAikE9.js';
6
7
 
7
8
  type BottomSheetProps<TId extends string = string> = {
@@ -28,11 +29,19 @@ type BottomSheetProps<TId extends string = string> = {
28
29
  disableDrag?: boolean;
29
30
  closeOnRouteChange?: boolean;
30
31
  stackEffect?: boolean;
32
+ teleport?: boolean;
33
+ teleportTo?: TeleportTarget;
31
34
  returnFocusTo?: EngineOptions["returnFocusTo"];
32
35
  ariaLabel?: string;
33
36
  radius?: string | number;
34
37
  maxHeight?: string | number;
35
38
  onSnap$?: QRL<(id: TId) => void>;
39
+ onOpen$?: QRL<(id: TId) => void>;
40
+ onClose$?: QRL<() => void>;
41
+ onOpened$?: QRL<(id: TId) => void>;
42
+ onClosed$?: QRL<() => void>;
43
+ onDragStart$?: QRL<(payload: SheetEventMap["dragstart"]) => void>;
44
+ onDragEnd$?: QRL<(payload: SheetEventMap["dragend"]) => void>;
36
45
  onChange$?: QRL<(state: EngineState & {
37
46
  activeId: TId;
38
47
  }) => void>;