@surdeddd/bottom-sheet 0.13.0 → 0.14.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 (66) hide show
  1. package/README.md +33 -0
  2. package/dist/{BottomSheetCore-CsIjyq7C.d.cts → BottomSheetCore-Cp7dWy91.d.cts} +26 -1
  3. package/dist/{BottomSheetCore-D16lsa6g.d.ts → BottomSheetCore-DJYwWOqt.d.ts} +26 -1
  4. package/dist/{BottomSheetEngine-BYjAVrmd.d.cts → BottomSheetEngine-Lm7HIVHv.d.cts} +1 -1
  5. package/dist/{BottomSheetEngine-YuCNugZn.d.ts → BottomSheetEngine-O5PbeKfe.d.ts} +1 -1
  6. package/dist/core.cjs +231 -27
  7. package/dist/core.d.cts +2 -2
  8. package/dist/core.d.ts +2 -2
  9. package/dist/core.js +231 -27
  10. package/dist/debug.d.cts +1 -1
  11. package/dist/debug.d.ts +1 -1
  12. package/dist/element.cjs +300 -102
  13. package/dist/element.d.cts +2 -2
  14. package/dist/element.d.ts +2 -2
  15. package/dist/element.iife.global.js +2 -2
  16. package/dist/element.js +300 -102
  17. package/dist/features.cjs +6 -50
  18. package/dist/features.d.cts +2 -2
  19. package/dist/features.d.ts +2 -2
  20. package/dist/features.js +6 -50
  21. package/dist/index-Bb5TRmyg.d.cts +9 -0
  22. package/dist/index-Cl9ebCP2.d.ts +9 -0
  23. package/dist/index.cjs +238 -823
  24. package/dist/index.d.cts +42 -45
  25. package/dist/index.d.ts +42 -45
  26. package/dist/index.js +239 -810
  27. package/dist/integrations/formik.d.cts +1 -1
  28. package/dist/integrations/formik.d.ts +1 -1
  29. package/dist/integrations/react-hook-form.d.cts +1 -1
  30. package/dist/integrations/react-hook-form.d.ts +1 -1
  31. package/dist/overlay.cjs +5 -5
  32. package/dist/overlay.js +5 -5
  33. package/dist/preact.d.cts +2 -2
  34. package/dist/preact.d.ts +2 -2
  35. package/dist/qwik-lib/index.qwik.cjs +228 -77
  36. package/dist/qwik-lib/index.qwik.mjs +228 -77
  37. package/dist/qwik.cjs +245 -77
  38. package/dist/qwik.d.cts +4 -2
  39. package/dist/qwik.d.ts +4 -2
  40. package/dist/qwik.js +245 -77
  41. package/dist/react.cjs +250 -79
  42. package/dist/react.d.cts +3 -4
  43. package/dist/react.d.ts +3 -4
  44. package/dist/react.js +250 -79
  45. package/dist/solid.cjs +251 -77
  46. package/dist/solid.d.cts +27 -0
  47. package/dist/solid.d.ts +27 -0
  48. package/dist/solid.js +251 -77
  49. package/dist/solid.source.jsx +259 -77
  50. package/dist/styles.css +24 -4
  51. package/dist/svelte-core.cjs +237 -77
  52. package/dist/svelte-core.js +237 -77
  53. package/dist/svelte-src/BottomSheet.svelte +14 -0
  54. package/dist/svelte.cjs +247 -77
  55. package/dist/svelte.d.cts +2 -0
  56. package/dist/svelte.d.ts +2 -0
  57. package/dist/svelte.js +247 -77
  58. package/dist/vue.cjs +253 -77
  59. package/dist/vue.js +253 -77
  60. package/dist/webgl.cjs +583 -0
  61. package/dist/webgl.d.cts +17 -0
  62. package/dist/webgl.d.ts +17 -0
  63. package/dist/webgl.js +581 -0
  64. package/package.json +36 -12
  65. package/dist/index-DdYLOIIT.d.ts +0 -15
  66. package/dist/index-dfrzw-lI.d.cts +0 -15
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
 
5
- // src/core/lifecycle/sheetStack.ts
5
+ // src/core/lifecycle/sheet-stack.ts
6
6
  var BASE_Z = 100;
7
7
  var STEP = 10;
8
8
  var SheetStack = class {
@@ -84,12 +84,6 @@ function buildTransformTemplate(axis) {
84
84
  return (offset) => `translate3d(${offset}px, 0, 0)`;
85
85
  }
86
86
  }
87
- var CLOSED_TRANSFORM = {
88
- bottom: "translate3d(0, 100%, 0)",
89
- top: "translate3d(0, -100%, 0)",
90
- left: "translate3d(-100%, 0, 0)",
91
- right: "translate3d(100%, 0, 0)"
92
- };
93
87
  var layoutAxis = (axis) => axis === "left" || axis === "right" ? "width" : "height";
94
88
 
95
89
  // src/core/primitives/instance-id.ts
@@ -133,7 +127,7 @@ function createEventBus() {
133
127
  };
134
128
  }
135
129
 
136
- // src/core/primitives/cssLength.ts
130
+ // src/core/primitives/css-length.ts
137
131
  var probe = null;
138
132
  var PROBE_ATTR = "data-bs-probe";
139
133
  var ensureProbe = (axis) => {
@@ -187,7 +181,7 @@ var resolveSnap = (point, mode, measureFit) => {
187
181
  return Math.max(0, el.getBoundingClientRect().width);
188
182
  };
189
183
 
190
- // src/core/primitives/devWarn.ts
184
+ // src/core/primitives/dev-warn.ts
191
185
  function devWarn(...args) {
192
186
  if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
193
187
  console.warn(...args);
@@ -1520,7 +1514,7 @@ var AnimationRunner = class {
1520
1514
  }
1521
1515
  };
1522
1516
 
1523
- // src/core/lifecycle/focusTrap.ts
1517
+ // src/core/lifecycle/focus-trap.ts
1524
1518
  var FOCUSABLE = [
1525
1519
  "a[href]",
1526
1520
  "area[href]",
@@ -1638,7 +1632,7 @@ var installFocusTrap = (container, options = {}) => {
1638
1632
  };
1639
1633
  };
1640
1634
 
1641
- // src/core/lifecycle/scrollLock.ts
1635
+ // src/core/lifecycle/scroll-lock.ts
1642
1636
  var lockCount = 0;
1643
1637
  var savedStyles = null;
1644
1638
  var lockBodyScroll = () => {
@@ -1820,30 +1814,44 @@ var SampleRing = class {
1820
1814
  this.size = 0;
1821
1815
  }
1822
1816
  };
1823
- var installGestures = (handle, mode, callbacks) => {
1817
+ var installGestures = (handle, mode, callbacks, options = {}) => {
1824
1818
  let activePointerId = null;
1825
1819
  let activePointerType = "touch";
1826
1820
  let startCoord = 0;
1827
1821
  let lastCoord = 0;
1822
+ let pendingStart = false;
1828
1823
  const VELOCITY_WINDOW_MS = (kind) => kind === "mouse" ? 160 : 120;
1829
1824
  const MAX_SAMPLES = 32;
1830
1825
  const samples = new SampleRing(MAX_SAMPLES);
1831
1826
  const axis = isAxisVertical(mode) ? "Y" : "X";
1832
1827
  const sign = mode === "bottom" || mode === "right" ? -1 : 1;
1833
1828
  const coordOf = (e) => axis === "Y" ? e.clientY : e.clientX;
1829
+ const capture = (pointerId) => {
1830
+ try {
1831
+ handle.setPointerCapture(pointerId);
1832
+ } catch {
1833
+ }
1834
+ };
1835
+ const releaseTracking = () => {
1836
+ activePointerId = null;
1837
+ pendingStart = false;
1838
+ samples.reset();
1839
+ };
1834
1840
  const onPointerDown = (e) => {
1835
1841
  if (activePointerId !== null) return;
1836
1842
  if (e.button !== void 0 && e.button !== 0) return;
1843
+ if (options.shouldStart && !options.shouldStart(e)) return;
1837
1844
  activePointerId = e.pointerId;
1838
1845
  activePointerType = e.pointerType || "touch";
1839
1846
  startCoord = coordOf(e);
1840
1847
  lastCoord = startCoord;
1841
1848
  samples.reset();
1842
1849
  samples.push(e.timeStamp, startCoord);
1843
- try {
1844
- handle.setPointerCapture(e.pointerId);
1845
- } catch {
1850
+ if (options.deferStart) {
1851
+ pendingStart = true;
1852
+ return;
1846
1853
  }
1854
+ capture(e.pointerId);
1847
1855
  callbacks.onStart(startCoord, activePointerType);
1848
1856
  };
1849
1857
  const onPointerMove = (e) => {
@@ -1851,6 +1859,22 @@ var installGestures = (handle, mode, callbacks) => {
1851
1859
  const coord = coordOf(e);
1852
1860
  const rawDelta = coord - startCoord;
1853
1861
  const delta = rawDelta * sign;
1862
+ if (pendingStart) {
1863
+ const verdict = options.deferStart(e, delta);
1864
+ if (verdict === false) {
1865
+ releaseTracking();
1866
+ return;
1867
+ }
1868
+ if (verdict !== true) return;
1869
+ pendingStart = false;
1870
+ startCoord = coord;
1871
+ lastCoord = coord;
1872
+ samples.reset();
1873
+ samples.push(e.timeStamp, coord);
1874
+ capture(e.pointerId);
1875
+ callbacks.onStart(startCoord, activePointerType);
1876
+ return;
1877
+ }
1854
1878
  lastCoord = coord;
1855
1879
  samples.push(e.timeStamp, coord);
1856
1880
  const cutoff = e.timeStamp - VELOCITY_WINDOW_MS(activePointerType);
@@ -1859,6 +1883,10 @@ var installGestures = (handle, mode, callbacks) => {
1859
1883
  };
1860
1884
  const finishGesture = (e) => {
1861
1885
  if (e.pointerId !== activePointerId) return;
1886
+ if (pendingStart) {
1887
+ releaseTracking();
1888
+ return;
1889
+ }
1862
1890
  const rawDelta = lastCoord - startCoord;
1863
1891
  const delta = rawDelta * sign;
1864
1892
  let velocity = 0;
@@ -1881,28 +1909,31 @@ var installGestures = (handle, mode, callbacks) => {
1881
1909
  };
1882
1910
  const onPointerCancel = (e) => {
1883
1911
  if (e.pointerId !== activePointerId) return;
1884
- activePointerId = null;
1885
- samples.reset();
1912
+ const wasPending = pendingStart;
1913
+ releaseTracking();
1914
+ if (wasPending) return;
1886
1915
  callbacks.onCancel?.();
1887
1916
  };
1888
1917
  handle.addEventListener("pointerdown", onPointerDown);
1889
1918
  handle.addEventListener("pointermove", onPointerMove);
1890
1919
  handle.addEventListener("pointerup", finishGesture);
1891
1920
  handle.addEventListener("pointercancel", onPointerCancel);
1921
+ const managesTouchAction = options.manageTouchAction !== false;
1892
1922
  const prevTouchAction = handle.style.touchAction;
1893
- handle.style.touchAction = isAxisVertical(mode) ? "pan-x" : "pan-y";
1923
+ if (managesTouchAction) {
1924
+ handle.style.touchAction = isAxisVertical(mode) ? "pan-x" : "pan-y";
1925
+ }
1894
1926
  return () => {
1895
1927
  handle.removeEventListener("pointerdown", onPointerDown);
1896
1928
  handle.removeEventListener("pointermove", onPointerMove);
1897
1929
  handle.removeEventListener("pointerup", finishGesture);
1898
1930
  handle.removeEventListener("pointercancel", onPointerCancel);
1899
- handle.style.touchAction = prevTouchAction;
1931
+ if (managesTouchAction) handle.style.touchAction = prevTouchAction;
1900
1932
  if (activePointerId !== null && handle.hasPointerCapture(activePointerId)) {
1901
1933
  handle.releasePointerCapture(activePointerId);
1902
1934
  }
1903
1935
  };
1904
1936
  };
1905
- var attachGestures = installGestures;
1906
1937
 
1907
1938
  // src/core/primitives/rubber-band.ts
1908
1939
  function rubberBand(overshoot, maxAxisSize) {
@@ -2016,7 +2047,7 @@ var GestureController = class {
2016
2047
  const restoreTo = this.dragStartSize;
2017
2048
  void this.deps.animateTo(restoreTo, 0);
2018
2049
  }
2019
- });
2050
+ }, this.deps.gestureOptions);
2020
2051
  return this.detach;
2021
2052
  }
2022
2053
  forceClearDragState() {
@@ -2028,6 +2059,41 @@ var GestureController = class {
2028
2059
  }
2029
2060
  };
2030
2061
 
2062
+ // src/core/primitives/drag-zones.ts
2063
+ var DRAG_ZONE_SELECTOR = "[data-bs-drag]";
2064
+ var NO_DRAG_SELECTOR = "[data-bs-no-drag]";
2065
+ var asElement = (target) => {
2066
+ const candidate = target;
2067
+ return candidate && typeof candidate.closest === "function" ? candidate : null;
2068
+ };
2069
+ function isDragAllowedFrom(target, mode) {
2070
+ const el = asElement(target);
2071
+ if (!el) return mode !== "zones";
2072
+ if (el.closest(NO_DRAG_SELECTOR)) return false;
2073
+ if (mode === "zones") return el.closest(DRAG_ZONE_SELECTOR) !== null;
2074
+ return true;
2075
+ }
2076
+
2077
+ // src/core/primitives/content-gesture.ts
2078
+ var CONTENT_DRAG_SLOP = 6;
2079
+ function decideContentGesture(input) {
2080
+ const slop = input.slop ?? CONTENT_DRAG_SLOP;
2081
+ if (Math.abs(input.delta) < slop) return "pending";
2082
+ if (input.scrollTop > 0) return "scroll";
2083
+ if (input.delta > 0 && input.atMaxSnap) return "scroll";
2084
+ return "drag";
2085
+ }
2086
+
2087
+ // src/core/primitives/touch-scroll-guard.ts
2088
+ function installTouchScrollGuard(surface, isDragging) {
2089
+ const onTouchMove = (e) => {
2090
+ if (!isDragging()) return;
2091
+ if (e.cancelable) e.preventDefault();
2092
+ };
2093
+ surface.addEventListener("touchmove", onTouchMove, { passive: false });
2094
+ return () => surface.removeEventListener("touchmove", onTouchMove);
2095
+ }
2096
+
2031
2097
  // src/core/primitives/aria-slider-writer.ts
2032
2098
  var AriaSliderWriter = class {
2033
2099
  constructor(handle, mode) {
@@ -2383,6 +2449,8 @@ function resolveEngineOptions(opts, extras) {
2383
2449
  mode: opts.mode ?? "bottom",
2384
2450
  flickVelocity: opts.flickVelocity ?? DEFAULT_FLICK_VELOCITY,
2385
2451
  dragThreshold: opts.dragThreshold ?? DEFAULT_DRAG_THRESHOLD,
2452
+ dragFrom: opts.dragFrom ?? (opts.handle ? "handle" : "sheet"),
2453
+ dragFromContent: opts.dragFromContent ?? true,
2386
2454
  rubberBandEnabled: opts.rubberBand ?? true,
2387
2455
  closeOnBack: opts.closeOnBack ?? false,
2388
2456
  persistent: opts.persistent ?? false,
@@ -2468,6 +2536,8 @@ var BottomSheetCore = class {
2468
2536
  __publicField(this, "mode");
2469
2537
  __publicField(this, "flickVelocity");
2470
2538
  __publicField(this, "dragThreshold");
2539
+ __publicField(this, "dragFromMode");
2540
+ __publicField(this, "dragFromContentDefault");
2471
2541
  __publicField(this, "rubberBandEnabled");
2472
2542
  __publicField(this, "scrim");
2473
2543
  __publicField(this, "aria");
@@ -2485,8 +2555,11 @@ var BottomSheetCore = class {
2485
2555
  __publicField(this, "activeId");
2486
2556
  __publicField(this, "size", 0);
2487
2557
  __publicField(this, "gesture");
2558
+ __publicField(this, "contentGesture");
2559
+ __publicField(this, "detachSheetGesture", null);
2488
2560
  __publicField(this, "rootEl", null);
2489
2561
  __publicField(this, "destroyed", false);
2562
+ __publicField(this, "restClosed", false);
2490
2563
  __publicField(this, "currentViewTransition", null);
2491
2564
  __publicField(this, "currentAbort", new AbortController());
2492
2565
  __publicField(this, "sizeWriteSentinel", new WriteSentinel());
@@ -2539,6 +2612,8 @@ var BottomSheetCore = class {
2539
2612
  this.aria = new AriaSliderWriter(this.handle, this.mode);
2540
2613
  this.flickVelocity = resolved.flickVelocity;
2541
2614
  this.dragThreshold = resolved.dragThreshold;
2615
+ this.dragFromMode = resolved.dragFrom;
2616
+ this.dragFromContentDefault = resolved.dragFromContent;
2542
2617
  this.rubberBandEnabled = resolved.rubberBandEnabled;
2543
2618
  this.scrim = new ScrimController(
2544
2619
  {
@@ -2565,7 +2640,7 @@ var BottomSheetCore = class {
2565
2640
  getRootEl: () => this.rootEl,
2566
2641
  applySize: (size) => this.applySize(size),
2567
2642
  getSize: () => this.size,
2568
- isDragging: () => this.gesture?.isDragging ?? false,
2643
+ isDragging: () => this.isDraggingAny(),
2569
2644
  applyAux: (size) => this.applySize(size, true),
2570
2645
  getTransformFor: (size) => this.transformTemplate(this.snaps.getMaxAxisSize() - size)
2571
2646
  },
@@ -2626,6 +2701,7 @@ var BottomSheetCore = class {
2626
2701
  const initial = this.snaps.findById(this.activeId);
2627
2702
  if (initial) this.size = initial.size;
2628
2703
  this.applySize(this.size);
2704
+ this.setRestClosed(this.size === 0);
2629
2705
  this.updateAriaSlider();
2630
2706
  this.scrollCache = createScrollCache({
2631
2707
  scrollContainer: this.scrollContainer,
@@ -2656,7 +2732,7 @@ var BottomSheetCore = class {
2656
2732
  (p) => p.size === "fit" || p.size === "content"
2657
2733
  ),
2658
2734
  isDestroyed: () => this.destroyed,
2659
- isDragging: () => this.gesture?.isDragging ?? false,
2735
+ isDragging: () => this.isDraggingAny(),
2660
2736
  recompute: () => this.recompute()
2661
2737
  })
2662
2738
  );
@@ -2682,7 +2758,7 @@ var BottomSheetCore = class {
2682
2758
  autoCollapseAfter
2683
2759
  },
2684
2760
  isDestroyed: () => this.destroyed,
2685
- isDragging: () => this.gesture?.isDragging ?? false,
2761
+ isDragging: () => this.isDraggingAny(),
2686
2762
  isAnimating: () => this.animation.isAnimating,
2687
2763
  isTopSheet: () => this.isTopSheet,
2688
2764
  isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
@@ -2712,6 +2788,7 @@ var BottomSheetCore = class {
2712
2788
  void this.snapTo(id);
2713
2789
  },
2714
2790
  close: (reason) => this.close(reason),
2791
+ attachDragSurface: (surface, kind) => this.attachDragSurface(surface, kind),
2715
2792
  on: (event, fn) => this.on(event, fn),
2716
2793
  addTeardown: (fn) => this.teardowns.add(fn)
2717
2794
  };
@@ -2740,7 +2817,7 @@ var BottomSheetCore = class {
2740
2817
  return {
2741
2818
  size: this.size,
2742
2819
  activeId: this.activeId,
2743
- isDragging: this.gesture?.isDragging ?? false,
2820
+ isDragging: this.isDraggingAny(),
2744
2821
  isAnimating: this.animation.isAnimating,
2745
2822
  progress: this.computeProgress(this.size)
2746
2823
  };
@@ -2860,9 +2937,16 @@ var BottomSheetCore = class {
2860
2937
  progress: this.computeProgress(this.size)
2861
2938
  });
2862
2939
  if (withHaptic) this.haptic();
2940
+ this.setRestClosed(targetSize === 0);
2863
2941
  if (wasClosed && targetSize > 0) this.emitOpenSequence(id);
2864
2942
  if (targetSize === 0) this.emitCloseSequence();
2865
2943
  }
2944
+ setRestClosed(closed) {
2945
+ if (closed === this.restClosed) return;
2946
+ this.restClosed = closed;
2947
+ if (closed) this.element.setAttribute("data-bs-rest", "closed");
2948
+ else this.element.removeAttribute("data-bs-rest");
2949
+ }
2866
2950
  emitOpenSequence(id) {
2867
2951
  this.emit("open", { id });
2868
2952
  this.handleOpen();
@@ -2918,6 +3002,20 @@ var BottomSheetCore = class {
2918
3002
  if (this.destroyed) return;
2919
3003
  this.disableDragFlag = value;
2920
3004
  }
3005
+ setDragFromContent(value) {
3006
+ if (this.destroyed) return;
3007
+ this.dragFromContentDefault = value;
3008
+ }
3009
+ setDragFrom(mode) {
3010
+ if (this.destroyed || mode === this.dragFromMode) return;
3011
+ this.gesture?.forceClearDragState();
3012
+ this.detachSheetGesture?.();
3013
+ this.dragFromMode = mode;
3014
+ this.mountSheetGesture();
3015
+ }
3016
+ getDragFrom() {
3017
+ return this.dragFromMode;
3018
+ }
2921
3019
  isTop() {
2922
3020
  return this.isTopSheet;
2923
3021
  }
@@ -3072,12 +3170,24 @@ var BottomSheetCore = class {
3072
3170
  auditVhUsage(points);
3073
3171
  this.auditDuplicateSnapIds(points);
3074
3172
  this.snaps.setRaw(points);
3075
- if (allowed) this.snaps.setAllowedIds(allowed);
3173
+ if (allowed) {
3174
+ this.snaps.setAllowedIds(allowed);
3175
+ } else {
3176
+ const present = this.snaps.getResolvedSnaps().map((s) => s.id);
3177
+ const kept = this.snaps.getAllowedIds().filter((id) => present.includes(id));
3178
+ this.snaps.setAllowedIds(kept.length ? kept : present);
3179
+ }
3076
3180
  this.scrollCache.clear();
3077
3181
  this.scrim.invalidateOpacityCache();
3078
3182
  const current = this.snaps.findById(this.activeId);
3079
3183
  if (current) {
3080
3184
  this.applySize(current.size);
3185
+ } else {
3186
+ const fallback = this.snaps.getResolvedSnaps().find((s) => this.snaps.getAllowedIds().includes(s.id)) ?? this.snaps.getResolvedSnaps()[0];
3187
+ if (fallback) {
3188
+ this.activeId = fallback.id;
3189
+ this.applySize(fallback.size);
3190
+ }
3081
3191
  }
3082
3192
  this.updateAriaSlider();
3083
3193
  }
@@ -3087,7 +3197,7 @@ var BottomSheetCore = class {
3087
3197
  this.snaps.recompute();
3088
3198
  this.maxHeight.clampTo();
3089
3199
  this.scrim.invalidateOpacityCache();
3090
- if (this.gesture?.isDragging) return;
3200
+ if (this.isDraggingAny()) return;
3091
3201
  this.healActiveSnap();
3092
3202
  }
3093
3203
  healActiveSnap() {
@@ -3109,6 +3219,8 @@ var BottomSheetCore = class {
3109
3219
  this.bus.clear();
3110
3220
  this.animation.cancel();
3111
3221
  this.gesture?.forceClearDragState();
3222
+ this.contentGesture?.forceClearDragState();
3223
+ this.setRestClosed(false);
3112
3224
  this.teardowns.drain();
3113
3225
  this.scrim.destroy();
3114
3226
  this.animation.destroy();
@@ -3221,11 +3333,12 @@ var BottomSheetCore = class {
3221
3333
  const scale = Math.max(1 - depth * 0.04, 0.86);
3222
3334
  this.element.style.scale = scale === 1 ? "" : String(scale);
3223
3335
  }
3224
- attach() {
3225
- this.gesture = new GestureController({
3226
- handle: this.handle,
3336
+ buildGestureDeps(surface, gestureOptions) {
3337
+ return {
3338
+ handle: surface,
3227
3339
  element: this.element,
3228
3340
  mode: this.mode,
3341
+ gestureOptions,
3229
3342
  getRoot: () => this.rootEl,
3230
3343
  getDragContext: () => {
3231
3344
  const buf = this.dragContextBuf;
@@ -3244,8 +3357,88 @@ var BottomSheetCore = class {
3244
3357
  settleAfterDrag: (delta, velocity, kind) => this.settleAfterDrag(delta, velocity, kind),
3245
3358
  emit: (event, payload) => this.emit(event, payload),
3246
3359
  listenerCount: (event) => this.bus.listenerCount(event)
3360
+ };
3361
+ }
3362
+ isContentDragAllowed() {
3363
+ if (this.disableDragFlag) return false;
3364
+ const point = this.snapPointsRaw.find((p) => p.id === this.activeId);
3365
+ return point?.dragFromContent ?? this.dragFromContentDefault;
3366
+ }
3367
+ decideContentDrag(surface, e, delta) {
3368
+ if (this.destroyed) return false;
3369
+ if (e.pointerType === "mouse") return false;
3370
+ if (this.gesture?.isDragging) return false;
3371
+ if (!this.isContentDragAllowed()) return false;
3372
+ if (!isDragAllowedFrom(e.target, "sheet")) return false;
3373
+ const decision = decideContentGesture({
3374
+ delta,
3375
+ scrollTop: surface.scrollTop,
3376
+ atMaxSnap: this.size >= this.getAllowedRange().max - 0.5
3377
+ });
3378
+ if (decision === "pending") return null;
3379
+ return decision === "drag";
3380
+ }
3381
+ attachDragSurface(surface, kind) {
3382
+ if (this.destroyed || kind !== "content") return;
3383
+ if (this.contentGesture) return;
3384
+ const controller = new GestureController(
3385
+ this.buildGestureDeps(surface, {
3386
+ manageTouchAction: false,
3387
+ deferStart: (e, delta) => this.decideContentDrag(surface, e, delta)
3388
+ })
3389
+ );
3390
+ this.contentGesture = controller;
3391
+ const detachGestures = controller.install();
3392
+ const detachGuard = installTouchScrollGuard(
3393
+ surface,
3394
+ () => controller.isDragging
3395
+ );
3396
+ return () => {
3397
+ detachGuard();
3398
+ detachGestures();
3399
+ if (this.contentGesture === controller) this.contentGesture = void 0;
3400
+ };
3401
+ }
3402
+ sheetDragSurface() {
3403
+ return this.dragFromMode === "handle" ? this.handle : this.element;
3404
+ }
3405
+ canStartSheetDrag(e) {
3406
+ if (this.contentGesture?.isDragging) return false;
3407
+ const target = e.target;
3408
+ const scoped = typeof target?.closest === "function";
3409
+ if (scoped && target.closest(NO_DRAG_SELECTOR)) return false;
3410
+ if (this.handle !== this.element && scoped && this.handle.contains(target)) {
3411
+ return true;
3412
+ }
3413
+ if (!isDragAllowedFrom(e.target, this.dragFromMode)) return false;
3414
+ if (this.dragFromMode === "handle") return true;
3415
+ if (this.scrollContainer && scoped && this.scrollContainer.contains(target) && !target.closest(DRAG_ZONE_SELECTOR)) {
3416
+ return false;
3417
+ }
3418
+ return true;
3419
+ }
3420
+ mountSheetGesture() {
3421
+ const surface = this.sheetDragSurface();
3422
+ const controller = new GestureController(
3423
+ this.buildGestureDeps(surface, {
3424
+ shouldStart: (e) => this.canStartSheetDrag(e),
3425
+ manageTouchAction: this.dragFromMode === "handle"
3426
+ })
3427
+ );
3428
+ this.gesture = controller;
3429
+ const detachGestures = controller.install();
3430
+ const detachGuard = this.dragFromMode === "handle" ? null : installTouchScrollGuard(surface, () => controller.isDragging);
3431
+ this.detachSheetGesture = () => {
3432
+ detachGuard?.();
3433
+ detachGestures();
3434
+ };
3435
+ }
3436
+ attach() {
3437
+ this.mountSheetGesture();
3438
+ this.teardowns.add(() => {
3439
+ this.detachSheetGesture?.();
3440
+ this.detachSheetGesture = null;
3247
3441
  });
3248
- this.teardowns.add(this.gesture.install());
3249
3442
  try {
3250
3443
  this.attachFeatures();
3251
3444
  } catch (err) {
@@ -3282,7 +3475,7 @@ var BottomSheetCore = class {
3282
3475
  element: this.element,
3283
3476
  getMode: () => this.mode,
3284
3477
  isDestroyed: () => this.destroyed,
3285
- isDragging: () => this.gesture?.isDragging ?? false,
3478
+ isDragging: () => this.isDraggingAny(),
3286
3479
  resolveActiveSnap: () => this.snaps.findById(this.activeId),
3287
3480
  getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
3288
3481
  getSize: () => this.size,
@@ -3380,8 +3573,11 @@ var BottomSheetCore = class {
3380
3573
  );
3381
3574
  });
3382
3575
  }
3576
+ isDraggingAny() {
3577
+ return (this.gesture?.isDragging ?? false) || (this.contentGesture?.isDragging ?? false);
3578
+ }
3383
3579
  clearWillChangeIfIdle() {
3384
- if (this.animation.isAnimating || this.gesture?.isDragging) return;
3580
+ if (this.animation.isAnimating || this.isDraggingAny()) return;
3385
3581
  this.element.style.willChange = "";
3386
3582
  }
3387
3583
  haptic() {
@@ -3394,8 +3590,9 @@ var BottomSheetCore = class {
3394
3590
  }
3395
3591
  applySize(size, skipTransform = false) {
3396
3592
  const cap = this.snaps.getMaxAxisSize();
3397
- const clamped = cap > 0 && size > cap && !this.gesture?.isDragging && !this.allowOvershoot ? cap : size;
3593
+ const clamped = cap > 0 && size > cap && !this.isDraggingAny() && !this.allowOvershoot ? cap : size;
3398
3594
  this.size = clamped;
3595
+ if (clamped > 0) this.setRestClosed(false);
3399
3596
  const offset = cap - clamped;
3400
3597
  const style = this.element.style;
3401
3598
  if (!skipTransform) style.transform = this.transformTemplate(offset);
@@ -3775,50 +3972,10 @@ function installAutoCollapse(deps) {
3775
3972
  };
3776
3973
  }
3777
3974
 
3778
- // src/core/features/content-swipe.ts
3779
- var CONTENT_PULL_THRESHOLD = 60;
3780
- function installContentSwipe(deps) {
3781
- const { container } = deps;
3782
- let startY = 0;
3783
- let startScrollTop = 0;
3784
- let moved = false;
3785
- const onTouchStart = (e) => {
3786
- const t = e.touches[0];
3787
- if (!t) return;
3788
- startY = t.clientY;
3789
- startScrollTop = container.scrollTop;
3790
- moved = false;
3791
- };
3792
- const onTouchMove = (e) => {
3793
- const t = e.touches[0];
3794
- if (!t) return;
3795
- if (Math.abs(t.clientY - startY) > CONTENT_PULL_THRESHOLD) moved = true;
3796
- };
3797
- const onTouchEnd = (e) => {
3798
- if (!moved) return;
3799
- if (deps.isDragging() || deps.isAnimating()) return;
3800
- if (container.scrollTop !== startScrollTop) return;
3801
- const t = e.changedTouches[0];
3802
- if (!t) return;
3803
- const deltaY = t.clientY - startY;
3804
- const atTop = container.scrollTop <= 0;
3805
- const allowed = deps.getAllowedIds();
3806
- const idx = allowed.indexOf(deps.getActiveId());
3807
- if (idx === -1) return;
3808
- if (atTop && deltaY > CONTENT_PULL_THRESHOLD && idx > 0) {
3809
- deps.snapTo(allowed[idx - 1]);
3810
- } else if (deltaY < -CONTENT_PULL_THRESHOLD && idx < allowed.length - 1) {
3811
- deps.snapTo(allowed[idx + 1]);
3812
- }
3813
- };
3814
- container.addEventListener("touchstart", onTouchStart, { passive: true });
3815
- container.addEventListener("touchmove", onTouchMove, { passive: true });
3816
- container.addEventListener("touchend", onTouchEnd, { passive: true });
3817
- return () => {
3818
- container.removeEventListener("touchstart", onTouchStart);
3819
- container.removeEventListener("touchmove", onTouchMove);
3820
- container.removeEventListener("touchend", onTouchEnd);
3821
- };
3975
+ // src/core/features/content-drag.ts
3976
+ function installContentDrag(deps) {
3977
+ const detach = deps.attachDragSurface(deps.container, "content");
3978
+ return () => detach?.();
3822
3979
  }
3823
3980
 
3824
3981
  // src/core/features/visual-viewport.ts
@@ -3926,13 +4083,9 @@ function contentSwipeFeature() {
3926
4083
  stage: "attach",
3927
4084
  install: (ctx) => {
3928
4085
  if (!ctx.scrollContainer) return;
3929
- return installContentSwipe({
4086
+ return installContentDrag({
3930
4087
  container: ctx.scrollContainer,
3931
- isDragging: ctx.isDragging,
3932
- isAnimating: ctx.isAnimating,
3933
- getAllowedIds: ctx.allowedIdsBySize,
3934
- getActiveId: ctx.getActiveId,
3935
- snapTo: ctx.snapTo
4088
+ attachDragSurface: ctx.attachDragSurface
3936
4089
  });
3937
4090
  }
3938
4091
  };
@@ -3984,7 +4137,7 @@ var BottomSheetEngine = class extends BottomSheetCore {
3984
4137
  }
3985
4138
  };
3986
4139
 
3987
- // src/core/lifecycle/sheetManager.ts
4140
+ // src/core/lifecycle/sheet-manager.ts
3988
4141
  var createSheetManager = (initial = {}) => {
3989
4142
  const registry = /* @__PURE__ */ new Map();
3990
4143
  for (const [key, config] of Object.entries(initial)) {
@@ -4010,730 +4163,6 @@ var createSheetManager = (initial = {}) => {
4010
4163
  };
4011
4164
  };
4012
4165
 
4013
- // src/core/primitives/overlay-transforms.ts
4014
- var closedTransform = (edge) => CLOSED_TRANSFORM[edge];
4015
- var closedTransformFor = (edge, animation, peekPx) => {
4016
- switch (animation) {
4017
- case "fade":
4018
- return "translate3d(0, 0, 0)";
4019
- case "scale":
4020
- return "translate3d(0, 0, 0) scale(0.94)";
4021
- case "slide":
4022
- default:
4023
- if (peekPx !== void 0 && edge === "bottom") {
4024
- return `translate3d(0, calc(100% - ${peekPx}px), 0)`;
4025
- }
4026
- return closedTransform(edge);
4027
- }
4028
- };
4029
- var openTransformFor = (animation) => animation === "scale" ? "translate3d(0, 0, 0) scale(1)" : "translate3d(0, 0, 0)";
4030
-
4031
- // src/core/features/overlay-swipe.ts
4032
- function installOverlaySwipe(deps) {
4033
- const el = deps.element;
4034
- const edge = deps.edge;
4035
- const isVertical = edge === "bottom" || edge === "top";
4036
- const sign = edge === "bottom" || edge === "right" ? 1 : -1;
4037
- const SLOP = 8;
4038
- let startX = 0;
4039
- let startY = 0;
4040
- let startT = 0;
4041
- let tracking = false;
4042
- let dragging = false;
4043
- let pointerId = null;
4044
- const previousTouchAction = el.style.touchAction;
4045
- el.style.touchAction = isVertical ? "pan-x" : "pan-y";
4046
- const onDown = (e) => {
4047
- if (e.button !== void 0 && e.button !== 0) return;
4048
- pointerId = e.pointerId;
4049
- startX = e.clientX;
4050
- startY = e.clientY;
4051
- startT = performance.now();
4052
- tracking = true;
4053
- dragging = false;
4054
- };
4055
- const onMove = (e) => {
4056
- if (!tracking || e.pointerId !== pointerId) return;
4057
- const delta = isVertical ? e.clientY - startY : e.clientX - startX;
4058
- if (!dragging) {
4059
- if (Math.abs(delta) < SLOP) return;
4060
- dragging = true;
4061
- el.style.transition = "none";
4062
- try {
4063
- el.setPointerCapture(e.pointerId);
4064
- } catch {
4065
- }
4066
- }
4067
- const offset = Math.max(0, sign * delta);
4068
- el.style.transform = isVertical ? `translate3d(0, ${sign * offset}px, 0)` : `translate3d(${sign * offset}px, 0, 0)`;
4069
- };
4070
- const finish = (e) => {
4071
- if (!tracking || e.pointerId !== pointerId) return;
4072
- tracking = false;
4073
- pointerId = null;
4074
- if (!dragging) return;
4075
- dragging = false;
4076
- const dt = performance.now() - startT || 1;
4077
- const delta = isVertical ? e.clientY - startY : e.clientX - startX;
4078
- const offset = Math.max(0, sign * delta);
4079
- const velocity = sign * delta / dt;
4080
- const size = isVertical ? el.offsetHeight : el.offsetWidth;
4081
- const past = offset > size * deps.getThreshold() || velocity > deps.getVelocityThreshold();
4082
- el.style.transition = deps.getExitTransition();
4083
- if (past) {
4084
- deps.close();
4085
- } else {
4086
- el.style.transform = deps.getOpenTransform();
4087
- }
4088
- };
4089
- el.addEventListener("pointerdown", onDown);
4090
- el.addEventListener("pointermove", onMove);
4091
- el.addEventListener("pointerup", finish);
4092
- el.addEventListener("pointercancel", finish);
4093
- return () => {
4094
- el.style.touchAction = previousTouchAction;
4095
- el.removeEventListener("pointerdown", onDown);
4096
- el.removeEventListener("pointermove", onMove);
4097
- el.removeEventListener("pointerup", finish);
4098
- el.removeEventListener("pointercancel", finish);
4099
- };
4100
- }
4101
-
4102
- // src/core/overlay-options.ts
4103
- var OVERLAY_PRESETS = Object.freeze({
4104
- sheet: Object.freeze({
4105
- enterAnimation: "slide",
4106
- exitAnimation: "slide",
4107
- backdropOpacity: 0.5,
4108
- backdropFilter: void 0,
4109
- swipeToClose: true
4110
- }),
4111
- dialog: Object.freeze({
4112
- enterAnimation: "scale",
4113
- exitAnimation: "scale",
4114
- backdropOpacity: 0.6,
4115
- backdropFilter: "blur(8px)",
4116
- swipeToClose: false
4117
- }),
4118
- sidebar: Object.freeze({
4119
- enterAnimation: "slide",
4120
- exitAnimation: "slide",
4121
- backdropOpacity: 0.4,
4122
- backdropFilter: void 0,
4123
- swipeToClose: true
4124
- }),
4125
- toast: Object.freeze({
4126
- enterAnimation: "fade",
4127
- exitAnimation: "fade",
4128
- backdropOpacity: 0,
4129
- backdropFilter: void 0,
4130
- swipeToClose: false
4131
- })
4132
- });
4133
-
4134
- // src/core/overlay.ts
4135
- var OverlayEngine = class {
4136
- constructor(opts) {
4137
- __publicField(this, "id", nextInstanceId("ovl"));
4138
- __publicField(this, "element");
4139
- __publicField(this, "backdrop");
4140
- __publicField(this, "edge");
4141
- __publicField(this, "closeOnEscape");
4142
- __publicField(this, "closeOnBackdropEnabled");
4143
- __publicField(this, "focusTrapEnabled");
4144
- __publicField(this, "initialFocus");
4145
- __publicField(this, "bodyScrollLockEnabled");
4146
- __publicField(this, "inertSiblingsEnabled");
4147
- __publicField(this, "closeOnBackEnabled");
4148
- __publicField(this, "duration");
4149
- __publicField(this, "enterEasing");
4150
- __publicField(this, "exitEasing");
4151
- __publicField(this, "backdropOpacity");
4152
- __publicField(this, "backdropFilter");
4153
- __publicField(this, "swipeToCloseEnabled");
4154
- __publicField(this, "swipeThreshold");
4155
- __publicField(this, "swipeVelocityThreshold");
4156
- __publicField(this, "enterAnimation");
4157
- __publicField(this, "exitAnimation");
4158
- __publicField(this, "mountTarget");
4159
- __publicField(this, "originalParent", null);
4160
- __publicField(this, "originalNextSibling", null);
4161
- __publicField(this, "mounted", false);
4162
- __publicField(this, "peekRaw");
4163
- __publicField(this, "peekPx");
4164
- __publicField(this, "closeOnOutsidePointerEnabled");
4165
- __publicField(this, "detachOutsidePointer", null);
4166
- __publicField(this, "detachSwipe", null);
4167
- __publicField(this, "respectReducedMotionEnabled");
4168
- __publicField(this, "isTop", true);
4169
- __publicField(this, "backMarker", null);
4170
- __publicField(this, "movedToTarget", false);
4171
- __publicField(this, "onOpenCb");
4172
- __publicField(this, "onCloseCb");
4173
- __publicField(this, "isOpen_", false);
4174
- __publicField(this, "isAnimating_", false);
4175
- __publicField(this, "destroyed", false);
4176
- __publicField(this, "hasInjectedChildren", false);
4177
- __publicField(this, "cycleNonce", 0);
4178
- __publicField(this, "bus", createEventBus());
4179
- __publicField(this, "detachEscape", null);
4180
- __publicField(this, "detachBackdrop", null);
4181
- __publicField(this, "releaseStackEntry", null);
4182
- __publicField(this, "lifecycle");
4183
- this.element = opts.element;
4184
- this.backdrop = opts.backdrop;
4185
- this.edge = opts.edge ?? "bottom";
4186
- this.closeOnEscape = opts.closeOnEscape ?? true;
4187
- this.closeOnBackdropEnabled = opts.closeOnBackdrop ?? true;
4188
- this.focusTrapEnabled = opts.focusTrap ?? true;
4189
- this.initialFocus = opts.initialFocus;
4190
- this.bodyScrollLockEnabled = opts.lockBodyScroll ?? true;
4191
- this.inertSiblingsEnabled = opts.inertSiblings ?? false;
4192
- this.closeOnBackEnabled = opts.closeOnBack ?? false;
4193
- this.duration = opts.duration ?? 320;
4194
- this.enterEasing = opts.enterEasing ?? "cubic-bezier(0.29, 1.24, 0.84, 0.99)";
4195
- this.exitEasing = opts.exitEasing ?? "cubic-bezier(0.4, 0, 1, 1)";
4196
- const preset = opts.preset ? OVERLAY_PRESETS[opts.preset] : void 0;
4197
- this.backdropOpacity = opts.backdropOpacity ?? preset?.backdropOpacity ?? 1;
4198
- this.backdropFilter = opts.backdropFilter ?? preset?.backdropFilter ?? void 0;
4199
- const swipeRaw = opts.swipeToClose !== void 0 ? opts.swipeToClose : preset?.swipeToClose;
4200
- this.assignSwipeFromConfig(swipeRaw);
4201
- this.enterAnimation = opts.enterAnimation ?? preset?.enterAnimation ?? "slide";
4202
- this.exitAnimation = opts.exitAnimation ?? preset?.exitAnimation ?? this.enterAnimation;
4203
- this.mountTarget = opts.mountTo;
4204
- this.peekRaw = opts.peek;
4205
- this.closeOnOutsidePointerEnabled = opts.closeOnOutsidePointer ?? false;
4206
- this.respectReducedMotionEnabled = opts.respectReducedMotion ?? true;
4207
- this.onOpenCb = opts.onOpen;
4208
- this.onCloseCb = opts.onClose;
4209
- if (this.peekRaw !== void 0 && this.edge !== "bottom") {
4210
- devWarn(
4211
- "[OverlayEngine] `peek` is only supported on edge: 'bottom' \u2014 ignoring."
4212
- );
4213
- this.peekRaw = void 0;
4214
- }
4215
- if (this.peekRaw !== void 0) {
4216
- this.peekPx = this.resolvePeekPx(this.peekRaw);
4217
- }
4218
- this.lifecycle = new LifecycleController(
4219
- {
4220
- element: this.element,
4221
- close: () => this.close("escape")
4222
- },
4223
- {
4224
- focusTrap: this.focusTrapEnabled,
4225
- initialFocus: this.initialFocus,
4226
- closeOnEscape: this.closeOnEscape,
4227
- lockBodyScroll: this.bodyScrollLockEnabled,
4228
- inertSiblings: this.inertSiblingsEnabled,
4229
- shouldApplyInertSiblings: () => {
4230
- const bodyChildren = Array.from(document.body.children);
4231
- return bodyChildren.some(
4232
- (c) => c === this.element || c.contains(this.element)
4233
- );
4234
- },
4235
- returnFocus: opts.returnFocus
4236
- }
4237
- );
4238
- this.applyClosedStyles();
4239
- this.registerInStack();
4240
- if (opts.initialOpen) void this.open();
4241
- }
4242
- get state() {
4243
- return { isOpen: this.isOpen_, isAnimating: this.isAnimating_ };
4244
- }
4245
- on(event, fn) {
4246
- return this.bus.on(event, fn);
4247
- }
4248
- open() {
4249
- if (this.destroyed || this.isOpen_) return Promise.resolve();
4250
- this.maybeMount();
4251
- this.emit("before-open", void 0);
4252
- this.isOpen_ = true;
4253
- this.isAnimating_ = true;
4254
- sheetStack.promote(this.id);
4255
- this.element.removeAttribute("hidden");
4256
- this.element.setAttribute("data-state", "entering");
4257
- if (this.focusTrapEnabled) {
4258
- this.element.setAttribute("aria-modal", "true");
4259
- }
4260
- const dur = this.effectiveDuration();
4261
- const transitionStr = `transform ${dur}ms ${this.enterEasing}, opacity ${dur}ms ease-out`;
4262
- this.element.style.transition = transitionStr;
4263
- if (this.backdrop) {
4264
- this.backdrop.style.transition = `opacity ${dur}ms ease-out`;
4265
- }
4266
- this.setWillChange(true);
4267
- const cycle = ++this.cycleNonce;
4268
- return new Promise((resolve) => {
4269
- requestAnimationFrame(() => {
4270
- if (this.destroyed || cycle !== this.cycleNonce) return resolve();
4271
- requestAnimationFrame(() => {
4272
- if (this.destroyed || cycle !== this.cycleNonce) return resolve();
4273
- this.element.style.transform = openTransformFor(this.enterAnimation);
4274
- this.element.style.opacity = "1";
4275
- if (this.backdrop) {
4276
- this.backdrop.style.opacity = String(this.backdropOpacity);
4277
- this.syncBackdropPointerEvents();
4278
- if (this.backdropFilter) {
4279
- this.applyBackdropFilter(this.backdropFilter);
4280
- }
4281
- }
4282
- try {
4283
- this.installInteractiveListeners();
4284
- } catch (err) {
4285
- this.releaseInteractiveListeners();
4286
- this.isOpen_ = false;
4287
- this.isAnimating_ = false;
4288
- this.setWillChange(false);
4289
- this.element.style.transform = closedTransformFor(
4290
- this.edge,
4291
- this.enterAnimation,
4292
- this.peekPx
4293
- );
4294
- this.element.style.opacity = "0";
4295
- if (this.backdrop) {
4296
- this.backdrop.style.opacity = "0";
4297
- this.backdrop.style.pointerEvents = "none";
4298
- if (this.backdropFilter) {
4299
- this.applyBackdropFilter(void 0);
4300
- }
4301
- }
4302
- this.element.setAttribute("data-state", "closed");
4303
- this.element.setAttribute("hidden", "");
4304
- if (this.focusTrapEnabled) {
4305
- this.element.removeAttribute("aria-modal");
4306
- }
4307
- queueMicrotask(() => {
4308
- throw err;
4309
- });
4310
- return resolve();
4311
- }
4312
- this.awaitTransition(
4313
- cycle,
4314
- this.enterAnimation === "fade" ? "opacity" : "transform"
4315
- ).then(() => {
4316
- if (this.destroyed || cycle !== this.cycleNonce) return resolve();
4317
- this.isAnimating_ = false;
4318
- this.setWillChange(false);
4319
- this.element.setAttribute("data-state", "open");
4320
- this.emit("open", void 0);
4321
- this.onOpenCb?.();
4322
- resolve();
4323
- });
4324
- });
4325
- });
4326
- });
4327
- }
4328
- close(reason = "programmatic") {
4329
- if (this.destroyed || !this.isOpen_) return Promise.resolve();
4330
- this.emit("before-close", void 0);
4331
- this.isOpen_ = false;
4332
- this.isAnimating_ = true;
4333
- sheetStack.update();
4334
- if (reason !== "back" && this.backMarker) {
4335
- popBackMarker(this.backMarker);
4336
- }
4337
- this.backMarker = null;
4338
- this.element.setAttribute("data-state", "exiting");
4339
- const dur = this.effectiveDuration();
4340
- const transitionStr = `transform ${dur}ms ${this.exitEasing}, opacity ${dur}ms ease-in`;
4341
- this.element.style.transition = transitionStr;
4342
- if (this.backdrop) {
4343
- this.backdrop.style.transition = `opacity ${dur}ms ease-in`;
4344
- }
4345
- this.setWillChange(true);
4346
- const cycle = ++this.cycleNonce;
4347
- return new Promise((resolve) => {
4348
- requestAnimationFrame(() => {
4349
- if (this.destroyed || cycle !== this.cycleNonce) return resolve();
4350
- this.element.style.transform = closedTransformFor(
4351
- this.edge,
4352
- this.exitAnimation,
4353
- this.peekPx
4354
- );
4355
- this.element.style.opacity = this.peekPx !== void 0 ? "1" : "0";
4356
- if (this.backdrop) {
4357
- this.backdrop.style.opacity = "0";
4358
- this.backdrop.style.pointerEvents = "none";
4359
- if (this.backdropFilter) {
4360
- this.applyBackdropFilter(void 0);
4361
- }
4362
- }
4363
- this.releaseInteractiveListeners();
4364
- this.awaitTransition(
4365
- cycle,
4366
- this.exitAnimation === "fade" ? "opacity" : "transform"
4367
- ).then(() => {
4368
- if (this.destroyed || cycle !== this.cycleNonce) return resolve();
4369
- this.isAnimating_ = false;
4370
- this.setWillChange(false);
4371
- if (this.peekPx === void 0) {
4372
- this.element.setAttribute("hidden", "");
4373
- }
4374
- this.element.setAttribute("data-state", "closed");
4375
- if (this.focusTrapEnabled) {
4376
- this.element.removeAttribute("aria-modal");
4377
- }
4378
- this.emit("close", { reason });
4379
- this.onCloseCb?.();
4380
- resolve();
4381
- });
4382
- });
4383
- });
4384
- }
4385
- toggle() {
4386
- if (this.destroyed) return Promise.resolve();
4387
- return this.isOpen_ ? this.close() : this.open();
4388
- }
4389
- destroy() {
4390
- this.destroyed = true;
4391
- this.cycleNonce++;
4392
- this.bus.clear();
4393
- this.setWillChange(false);
4394
- this.releaseInteractiveListeners();
4395
- if (this.backMarker) {
4396
- popBackMarker(this.backMarker);
4397
- this.backMarker = null;
4398
- }
4399
- this.releaseStackEntry?.();
4400
- this.releaseStackEntry = null;
4401
- const hadOriginalParent = this.originalParent !== null;
4402
- this.restoreMount();
4403
- if (this.movedToTarget && !hadOriginalParent && this.element.parentNode) {
4404
- this.element.parentNode.removeChild(this.element);
4405
- }
4406
- }
4407
- setBackdropOpacity(opacity) {
4408
- if (this.destroyed) return;
4409
- this.backdropOpacity = opacity;
4410
- if (this.isOpen_ && this.backdrop) {
4411
- this.backdrop.style.opacity = String(opacity);
4412
- this.syncBackdropPointerEvents();
4413
- }
4414
- }
4415
- setBackdropFilter(filter) {
4416
- if (this.destroyed) return;
4417
- this.backdropFilter = filter;
4418
- if (!this.isOpen_ || !this.backdrop) return;
4419
- this.applyBackdropFilter(filter);
4420
- }
4421
- setSwipeToClose(config) {
4422
- if (this.destroyed) return;
4423
- const wasEnabled = this.swipeToCloseEnabled;
4424
- this.assignSwipeFromConfig(config);
4425
- if (!this.isOpen_) return;
4426
- if (this.swipeToCloseEnabled && !this.detachSwipe) {
4427
- this.detachSwipe = this.installSwipeToClose();
4428
- } else if (!this.swipeToCloseEnabled && wasEnabled && this.detachSwipe) {
4429
- this.detachSwipe();
4430
- this.detachSwipe = null;
4431
- }
4432
- }
4433
- setEnterAnimation(animation) {
4434
- if (this.destroyed) return;
4435
- this.enterAnimation = animation;
4436
- }
4437
- setExitAnimation(animation) {
4438
- if (this.destroyed) return;
4439
- this.exitAnimation = animation;
4440
- }
4441
- setReturnFocus(target) {
4442
- if (this.destroyed) return;
4443
- this.lifecycle.setReturnFocus(target);
4444
- }
4445
- setOverlay(opts) {
4446
- if (this.destroyed) return;
4447
- const preset = opts.preset ? OVERLAY_PRESETS[opts.preset] : void 0;
4448
- const merged = preset ? {
4449
- backdropOpacity: preset.backdropOpacity,
4450
- backdropFilter: preset.backdropFilter === void 0 ? null : preset.backdropFilter,
4451
- swipeToClose: preset.swipeToClose,
4452
- enterAnimation: preset.enterAnimation,
4453
- exitAnimation: preset.exitAnimation
4454
- } : {};
4455
- if (opts.backdropOpacity !== void 0) {
4456
- merged.backdropOpacity = opts.backdropOpacity;
4457
- }
4458
- if (opts.backdropFilter !== void 0) {
4459
- merged.backdropFilter = opts.backdropFilter;
4460
- }
4461
- if (opts.swipeToClose !== void 0) {
4462
- merged.swipeToClose = opts.swipeToClose;
4463
- }
4464
- if (opts.enterAnimation !== void 0) {
4465
- merged.enterAnimation = opts.enterAnimation;
4466
- }
4467
- if (opts.exitAnimation !== void 0) {
4468
- merged.exitAnimation = opts.exitAnimation;
4469
- }
4470
- if (merged.enterAnimation !== void 0) {
4471
- this.enterAnimation = merged.enterAnimation;
4472
- }
4473
- if (merged.exitAnimation !== void 0) {
4474
- this.exitAnimation = merged.exitAnimation;
4475
- }
4476
- if (merged.swipeToClose !== void 0) {
4477
- this.setSwipeToClose(merged.swipeToClose);
4478
- }
4479
- if (merged.backdropOpacity !== void 0) {
4480
- this.backdropOpacity = merged.backdropOpacity;
4481
- }
4482
- if (merged.backdropFilter !== void 0) {
4483
- this.backdropFilter = merged.backdropFilter === null ? void 0 : merged.backdropFilter;
4484
- }
4485
- if (this.isOpen_ && this.backdrop) {
4486
- if (merged.backdropOpacity !== void 0) {
4487
- this.backdrop.style.opacity = String(this.backdropOpacity);
4488
- this.syncBackdropPointerEvents();
4489
- }
4490
- if (merged.backdropFilter !== void 0) {
4491
- this.applyBackdropFilter(this.backdropFilter);
4492
- }
4493
- }
4494
- if (opts.duration !== void 0) this.duration = opts.duration;
4495
- if (opts.enterEasing !== void 0) this.enterEasing = opts.enterEasing;
4496
- if (opts.exitEasing !== void 0) this.exitEasing = opts.exitEasing;
4497
- if (opts.closeOnEscape !== void 0) {
4498
- this.closeOnEscape = opts.closeOnEscape;
4499
- if (!opts.closeOnEscape) {
4500
- this.detachEscape?.();
4501
- this.detachEscape = null;
4502
- } else if (this.isOpen_) {
4503
- this.installInteractiveListeners();
4504
- }
4505
- }
4506
- if (opts.closeOnBackdrop !== void 0) {
4507
- this.closeOnBackdropEnabled = opts.closeOnBackdrop;
4508
- if (!opts.closeOnBackdrop) {
4509
- this.detachBackdrop?.();
4510
- this.detachBackdrop = null;
4511
- } else if (this.isOpen_) {
4512
- this.installInteractiveListeners();
4513
- }
4514
- }
4515
- if (opts.closeOnOutsidePointer !== void 0) {
4516
- this.closeOnOutsidePointerEnabled = opts.closeOnOutsidePointer;
4517
- if (!opts.closeOnOutsidePointer) {
4518
- this.detachOutsidePointer?.();
4519
- this.detachOutsidePointer = null;
4520
- } else if (this.isOpen_) {
4521
- this.installInteractiveListeners();
4522
- }
4523
- }
4524
- if (opts.children !== void 0) {
4525
- if (opts.children === null) {
4526
- this.clearOverlayChildren();
4527
- } else {
4528
- this.setOverlayChildren(opts.children);
4529
- }
4530
- }
4531
- }
4532
- setOverlayChildren(children) {
4533
- if (this.destroyed) return;
4534
- const node = typeof children === "function" ? children() : children;
4535
- this.element.replaceChildren(node);
4536
- this.hasInjectedChildren = true;
4537
- }
4538
- clearOverlayChildren() {
4539
- if (this.destroyed || !this.hasInjectedChildren) return;
4540
- this.element.replaceChildren();
4541
- this.hasInjectedChildren = false;
4542
- }
4543
- assignSwipeFromConfig(swipe) {
4544
- if (typeof swipe === "object" && swipe !== null) {
4545
- this.swipeToCloseEnabled = swipe.enabled ?? true;
4546
- this.swipeThreshold = swipe.threshold ?? 0.3;
4547
- this.swipeVelocityThreshold = swipe.velocityThreshold ?? 0.5;
4548
- } else {
4549
- this.swipeToCloseEnabled = swipe ?? false;
4550
- this.swipeThreshold = 0.3;
4551
- this.swipeVelocityThreshold = 0.5;
4552
- }
4553
- }
4554
- emit(event, payload) {
4555
- this.bus.emit(event, payload);
4556
- }
4557
- effectiveDuration() {
4558
- return this.respectReducedMotionEnabled && prefersReducedMotion() ? 0 : this.duration;
4559
- }
4560
- resolvePeekPx(raw) {
4561
- if (typeof raw === "number") return Math.max(0, raw);
4562
- try {
4563
- return Math.max(0, resolveSnap(raw, "bottom"));
4564
- } catch {
4565
- return 0;
4566
- }
4567
- }
4568
- maybeMount() {
4569
- if (this.mounted || !this.mountTarget || this.mountTarget === "parent") {
4570
- this.mounted = true;
4571
- return;
4572
- }
4573
- const target = this.mountTarget === "body" ? document.body : this.mountTarget;
4574
- if (!target) {
4575
- this.mounted = true;
4576
- return;
4577
- }
4578
- this.originalParent = this.element.parentNode;
4579
- this.originalNextSibling = this.element.nextSibling;
4580
- target.appendChild(this.element);
4581
- this.movedToTarget = true;
4582
- this.mounted = true;
4583
- }
4584
- restoreMount() {
4585
- if (!this.originalParent) return;
4586
- try {
4587
- if (this.originalNextSibling && this.originalNextSibling.parentNode === this.originalParent) {
4588
- this.originalParent.insertBefore(this.element, this.originalNextSibling);
4589
- } else {
4590
- this.originalParent.appendChild(this.element);
4591
- }
4592
- } catch {
4593
- }
4594
- this.originalParent = null;
4595
- this.originalNextSibling = null;
4596
- }
4597
- applyClosedStyles() {
4598
- this.element.style.transform = closedTransformFor(
4599
- this.edge,
4600
- this.enterAnimation,
4601
- this.peekPx
4602
- );
4603
- this.element.style.opacity = this.peekPx !== void 0 ? "1" : "0";
4604
- if (this.peekPx === void 0) {
4605
- this.element.setAttribute("hidden", "");
4606
- }
4607
- this.element.setAttribute("data-state", "closed");
4608
- if (this.backdrop) {
4609
- this.backdrop.style.opacity = "0";
4610
- this.backdrop.style.pointerEvents = "none";
4611
- }
4612
- }
4613
- syncBackdropPointerEvents() {
4614
- if (!this.backdrop) return;
4615
- this.backdrop.style.pointerEvents = this.backdropOpacity > 0 ? "auto" : "none";
4616
- }
4617
- applyBackdropFilter(filter) {
4618
- if (!this.backdrop) return;
4619
- const style = this.backdrop.style;
4620
- if (filter) {
4621
- this.backdrop.style.backdropFilter = filter;
4622
- style.webkitBackdropFilter = filter;
4623
- } else {
4624
- this.backdrop.style.backdropFilter = "";
4625
- style.webkitBackdropFilter = "";
4626
- }
4627
- }
4628
- setWillChange(on) {
4629
- this.element.style.willChange = on ? "transform, opacity" : "";
4630
- if (this.backdrop) {
4631
- this.backdrop.style.willChange = on ? "opacity" : "";
4632
- }
4633
- }
4634
- awaitTransition(cycle, property = "transform") {
4635
- return new Promise((resolve) => {
4636
- let done = false;
4637
- const finish = () => {
4638
- if (done) return;
4639
- done = true;
4640
- this.element.removeEventListener("transitionend", onEnd);
4641
- clearTimeout(timer);
4642
- resolve();
4643
- };
4644
- const onEnd = (e) => {
4645
- if (cycle !== this.cycleNonce) {
4646
- finish();
4647
- return;
4648
- }
4649
- if (e.target === this.element && e.propertyName === property) finish();
4650
- };
4651
- this.element.addEventListener("transitionend", onEnd);
4652
- const timer = window.setTimeout(finish, this.effectiveDuration() + 50);
4653
- });
4654
- }
4655
- installInteractiveListeners() {
4656
- this.lifecycle.install();
4657
- if (this.swipeToCloseEnabled && !this.detachSwipe) {
4658
- this.detachSwipe = this.installSwipeToClose();
4659
- }
4660
- if (this.closeOnEscape && !this.detachEscape) {
4661
- const handler = (e) => {
4662
- if (e.defaultPrevented) return;
4663
- if (e.key === "Escape" && this.isOpen_ && this.isTop) {
4664
- void this.close("escape");
4665
- }
4666
- };
4667
- document.addEventListener("keydown", handler);
4668
- this.detachEscape = () => document.removeEventListener("keydown", handler);
4669
- }
4670
- if (this.closeOnBackdropEnabled && this.backdrop && !this.detachBackdrop) {
4671
- const handler = () => void this.close("backdrop");
4672
- this.backdrop.addEventListener("click", handler);
4673
- this.detachBackdrop = () => this.backdrop?.removeEventListener("click", handler);
4674
- }
4675
- if (this.closeOnOutsidePointerEnabled && !this.detachOutsidePointer) {
4676
- const handler = (e) => {
4677
- if (!this.isOpen_) return;
4678
- const target = e.target;
4679
- if (!target) return;
4680
- if (this.element.contains(target)) return;
4681
- if (this.backdrop && this.backdrop.contains(target)) return;
4682
- void this.close("outside-pointer");
4683
- };
4684
- document.addEventListener("pointerdown", handler, true);
4685
- this.detachOutsidePointer = () => document.removeEventListener("pointerdown", handler, true);
4686
- }
4687
- if (this.closeOnBackEnabled && this.backMarker === null && typeof window !== "undefined") {
4688
- this.backMarker = pushBackMarker({
4689
- isOpen: () => this.isOpen_,
4690
- isTop: () => this.isTop,
4691
- close: () => this.close("back"),
4692
- markerState: () => ({ __bsOverlay: this.id })
4693
- });
4694
- }
4695
- }
4696
- releaseInteractiveListeners() {
4697
- this.detachEscape?.();
4698
- this.detachEscape = null;
4699
- this.detachBackdrop?.();
4700
- this.detachBackdrop = null;
4701
- this.detachSwipe?.();
4702
- this.detachSwipe = null;
4703
- this.detachOutsidePointer?.();
4704
- this.detachOutsidePointer = null;
4705
- this.lifecycle.release();
4706
- }
4707
- installSwipeToClose() {
4708
- return installOverlaySwipe({
4709
- element: this.element,
4710
- edge: this.edge,
4711
- getThreshold: () => this.swipeThreshold,
4712
- getVelocityThreshold: () => this.swipeVelocityThreshold,
4713
- getExitTransition: () => `transform ${this.effectiveDuration()}ms ${this.exitEasing}`,
4714
- getOpenTransform: () => openTransformFor(this.enterAnimation),
4715
- close: () => void this.close("swipe")
4716
- });
4717
- }
4718
- registerInStack() {
4719
- this.releaseStackEntry = sheetStack.push({
4720
- id: this.id,
4721
- setZIndex: (z) => {
4722
- this.element.style.zIndex = String(z);
4723
- if (this.backdrop) this.backdrop.style.zIndex = String(z - 1);
4724
- },
4725
- setIsTop: (isTop) => {
4726
- this.isTop = isTop;
4727
- if (this.backdrop) {
4728
- this.backdrop.style.display = isTop ? "" : "none";
4729
- }
4730
- },
4731
- isOpen: () => this.isOpen_
4732
- });
4733
- }
4734
- };
4735
- var createOverlay = (opts) => new OverlayEngine(opts);
4736
-
4737
- export { BottomSheetCore, BottomSheetEngine, DEFAULT_SPRING, OVERLAY_PRESETS, OverlayEngine as Overlay, OverlayEngine, SCRIM_PRESETS, allowedRange, applyOverlayPosition, attachGestures, autoCollapseFeature, contentSwipeFeature, createOverlay, createSheetManager, defaultEngineFeatures, easeOutBack, easeOutCubic, findById, findNearest, installFocusTrap, installGestures, lockBodyScroll, persistFeature, prefersReducedMotion, resolveSheetAnchoredStyle, resolveSnap, resolveSnapList, routeFeature, runAnchorTransition, runSpring, sheetStack, tween, visualViewportFeature };
4166
+ export { BottomSheetCore, BottomSheetEngine, SCRIM_PRESETS, applyOverlayPosition, autoCollapseFeature, contentSwipeFeature, createSheetManager, defaultEngineFeatures, installFocusTrap, installGestures, lockBodyScroll, persistFeature, resolveSheetAnchoredStyle, resolveSnap, resolveSnapList, routeFeature, runAnchorTransition, sheetStack, visualViewportFeature };
4738
4167
  //# sourceMappingURL=index.js.map
4739
4168
  //# sourceMappingURL=index.js.map