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