@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.
- package/README.md +33 -0
- package/dist/{BottomSheetCore-CsIjyq7C.d.cts → BottomSheetCore-Cp7dWy91.d.cts} +26 -1
- package/dist/{BottomSheetCore-D16lsa6g.d.ts → BottomSheetCore-DJYwWOqt.d.ts} +26 -1
- package/dist/{BottomSheetEngine-BYjAVrmd.d.cts → BottomSheetEngine-Lm7HIVHv.d.cts} +1 -1
- package/dist/{BottomSheetEngine-YuCNugZn.d.ts → BottomSheetEngine-O5PbeKfe.d.ts} +1 -1
- package/dist/core.cjs +231 -27
- package/dist/core.d.cts +2 -2
- package/dist/core.d.ts +2 -2
- package/dist/core.js +231 -27
- package/dist/debug.d.cts +1 -1
- package/dist/debug.d.ts +1 -1
- package/dist/element.cjs +300 -102
- package/dist/element.d.cts +2 -2
- package/dist/element.d.ts +2 -2
- package/dist/element.iife.global.js +2 -2
- package/dist/element.js +300 -102
- package/dist/features.cjs +6 -50
- package/dist/features.d.cts +2 -2
- package/dist/features.d.ts +2 -2
- package/dist/features.js +6 -50
- package/dist/index-Bb5TRmyg.d.cts +9 -0
- package/dist/index-Cl9ebCP2.d.ts +9 -0
- package/dist/index.cjs +238 -823
- package/dist/index.d.cts +42 -45
- package/dist/index.d.ts +42 -45
- package/dist/index.js +239 -810
- package/dist/integrations/formik.d.cts +1 -1
- package/dist/integrations/formik.d.ts +1 -1
- package/dist/integrations/react-hook-form.d.cts +1 -1
- package/dist/integrations/react-hook-form.d.ts +1 -1
- package/dist/overlay.cjs +5 -5
- package/dist/overlay.js +5 -5
- package/dist/preact.d.cts +2 -2
- package/dist/preact.d.ts +2 -2
- package/dist/qwik-lib/index.qwik.cjs +228 -77
- package/dist/qwik-lib/index.qwik.mjs +228 -77
- package/dist/qwik.cjs +245 -77
- package/dist/qwik.d.cts +4 -2
- package/dist/qwik.d.ts +4 -2
- package/dist/qwik.js +245 -77
- package/dist/react.cjs +250 -79
- package/dist/react.d.cts +3 -4
- package/dist/react.d.ts +3 -4
- package/dist/react.js +250 -79
- package/dist/solid.cjs +251 -77
- package/dist/solid.d.cts +27 -0
- package/dist/solid.d.ts +27 -0
- package/dist/solid.js +251 -77
- package/dist/solid.source.jsx +259 -77
- package/dist/styles.css +24 -4
- package/dist/svelte-core.cjs +237 -77
- package/dist/svelte-core.js +237 -77
- package/dist/svelte-src/BottomSheet.svelte +14 -0
- package/dist/svelte.cjs +247 -77
- package/dist/svelte.d.cts +2 -0
- package/dist/svelte.d.ts +2 -0
- package/dist/svelte.js +247 -77
- package/dist/vue.cjs +253 -77
- package/dist/vue.js +253 -77
- package/dist/webgl.cjs +583 -0
- package/dist/webgl.d.cts +17 -0
- package/dist/webgl.d.ts +17 -0
- package/dist/webgl.js +581 -0
- package/package.json +36 -12
- package/dist/index-DdYLOIIT.d.ts +0 -15
- package/dist/index-dfrzw-lI.d.cts +0 -15
|
@@ -1832,30 +1832,44 @@ class SampleRing {
|
|
|
1832
1832
|
this.size = 0;
|
|
1833
1833
|
}
|
|
1834
1834
|
}
|
|
1835
|
-
const installGestures = (handle, mode, callbacks) => {
|
|
1835
|
+
const installGestures = (handle, mode, callbacks, options = {}) => {
|
|
1836
1836
|
let activePointerId = null;
|
|
1837
1837
|
let activePointerType = "touch";
|
|
1838
1838
|
let startCoord = 0;
|
|
1839
1839
|
let lastCoord = 0;
|
|
1840
|
+
let pendingStart = false;
|
|
1840
1841
|
const VELOCITY_WINDOW_MS = (kind) => kind === "mouse" ? 160 : 120;
|
|
1841
1842
|
const MAX_SAMPLES = 32;
|
|
1842
1843
|
const samples = new SampleRing(MAX_SAMPLES);
|
|
1843
1844
|
const axis = isAxisVertical(mode) ? "Y" : "X";
|
|
1844
1845
|
const sign = mode === "bottom" || mode === "right" ? -1 : 1;
|
|
1845
1846
|
const coordOf = (e) => axis === "Y" ? e.clientY : e.clientX;
|
|
1847
|
+
const capture = (pointerId) => {
|
|
1848
|
+
try {
|
|
1849
|
+
handle.setPointerCapture(pointerId);
|
|
1850
|
+
} catch {
|
|
1851
|
+
}
|
|
1852
|
+
};
|
|
1853
|
+
const releaseTracking = () => {
|
|
1854
|
+
activePointerId = null;
|
|
1855
|
+
pendingStart = false;
|
|
1856
|
+
samples.reset();
|
|
1857
|
+
};
|
|
1846
1858
|
const onPointerDown = (e) => {
|
|
1847
1859
|
if (activePointerId !== null) return;
|
|
1848
1860
|
if (e.button !== void 0 && e.button !== 0) return;
|
|
1861
|
+
if (options.shouldStart && !options.shouldStart(e)) return;
|
|
1849
1862
|
activePointerId = e.pointerId;
|
|
1850
1863
|
activePointerType = e.pointerType || "touch";
|
|
1851
1864
|
startCoord = coordOf(e);
|
|
1852
1865
|
lastCoord = startCoord;
|
|
1853
1866
|
samples.reset();
|
|
1854
1867
|
samples.push(e.timeStamp, startCoord);
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1868
|
+
if (options.deferStart) {
|
|
1869
|
+
pendingStart = true;
|
|
1870
|
+
return;
|
|
1858
1871
|
}
|
|
1872
|
+
capture(e.pointerId);
|
|
1859
1873
|
callbacks.onStart(startCoord, activePointerType);
|
|
1860
1874
|
};
|
|
1861
1875
|
const onPointerMove = (e) => {
|
|
@@ -1863,6 +1877,22 @@ const installGestures = (handle, mode, callbacks) => {
|
|
|
1863
1877
|
const coord = coordOf(e);
|
|
1864
1878
|
const rawDelta = coord - startCoord;
|
|
1865
1879
|
const delta = rawDelta * sign;
|
|
1880
|
+
if (pendingStart) {
|
|
1881
|
+
const verdict = options.deferStart(e, delta);
|
|
1882
|
+
if (verdict === false) {
|
|
1883
|
+
releaseTracking();
|
|
1884
|
+
return;
|
|
1885
|
+
}
|
|
1886
|
+
if (verdict !== true) return;
|
|
1887
|
+
pendingStart = false;
|
|
1888
|
+
startCoord = coord;
|
|
1889
|
+
lastCoord = coord;
|
|
1890
|
+
samples.reset();
|
|
1891
|
+
samples.push(e.timeStamp, coord);
|
|
1892
|
+
capture(e.pointerId);
|
|
1893
|
+
callbacks.onStart(startCoord, activePointerType);
|
|
1894
|
+
return;
|
|
1895
|
+
}
|
|
1866
1896
|
lastCoord = coord;
|
|
1867
1897
|
samples.push(e.timeStamp, coord);
|
|
1868
1898
|
const cutoff = e.timeStamp - VELOCITY_WINDOW_MS(activePointerType);
|
|
@@ -1871,6 +1901,10 @@ const installGestures = (handle, mode, callbacks) => {
|
|
|
1871
1901
|
};
|
|
1872
1902
|
const finishGesture = (e) => {
|
|
1873
1903
|
if (e.pointerId !== activePointerId) return;
|
|
1904
|
+
if (pendingStart) {
|
|
1905
|
+
releaseTracking();
|
|
1906
|
+
return;
|
|
1907
|
+
}
|
|
1874
1908
|
const rawDelta = lastCoord - startCoord;
|
|
1875
1909
|
const delta = rawDelta * sign;
|
|
1876
1910
|
let velocity = 0;
|
|
@@ -1893,22 +1927,26 @@ const installGestures = (handle, mode, callbacks) => {
|
|
|
1893
1927
|
};
|
|
1894
1928
|
const onPointerCancel = (e) => {
|
|
1895
1929
|
if (e.pointerId !== activePointerId) return;
|
|
1896
|
-
|
|
1897
|
-
|
|
1930
|
+
const wasPending = pendingStart;
|
|
1931
|
+
releaseTracking();
|
|
1932
|
+
if (wasPending) return;
|
|
1898
1933
|
callbacks.onCancel?.();
|
|
1899
1934
|
};
|
|
1900
1935
|
handle.addEventListener("pointerdown", onPointerDown);
|
|
1901
1936
|
handle.addEventListener("pointermove", onPointerMove);
|
|
1902
1937
|
handle.addEventListener("pointerup", finishGesture);
|
|
1903
1938
|
handle.addEventListener("pointercancel", onPointerCancel);
|
|
1939
|
+
const managesTouchAction = options.manageTouchAction !== false;
|
|
1904
1940
|
const prevTouchAction = handle.style.touchAction;
|
|
1905
|
-
|
|
1941
|
+
if (managesTouchAction) {
|
|
1942
|
+
handle.style.touchAction = isAxisVertical(mode) ? "pan-x" : "pan-y";
|
|
1943
|
+
}
|
|
1906
1944
|
return () => {
|
|
1907
1945
|
handle.removeEventListener("pointerdown", onPointerDown);
|
|
1908
1946
|
handle.removeEventListener("pointermove", onPointerMove);
|
|
1909
1947
|
handle.removeEventListener("pointerup", finishGesture);
|
|
1910
1948
|
handle.removeEventListener("pointercancel", onPointerCancel);
|
|
1911
|
-
handle.style.touchAction = prevTouchAction;
|
|
1949
|
+
if (managesTouchAction) handle.style.touchAction = prevTouchAction;
|
|
1912
1950
|
if (activePointerId !== null && handle.hasPointerCapture(activePointerId)) {
|
|
1913
1951
|
handle.releasePointerCapture(activePointerId);
|
|
1914
1952
|
}
|
|
@@ -2026,7 +2064,7 @@ class GestureController {
|
|
|
2026
2064
|
const restoreTo = this.dragStartSize;
|
|
2027
2065
|
void this.deps.animateTo(restoreTo, 0);
|
|
2028
2066
|
}
|
|
2029
|
-
});
|
|
2067
|
+
}, this.deps.gestureOptions);
|
|
2030
2068
|
return this.detach;
|
|
2031
2069
|
}
|
|
2032
2070
|
forceClearDragState() {
|
|
@@ -2037,6 +2075,37 @@ class GestureController {
|
|
|
2037
2075
|
this.deps.element.style.willChange = "";
|
|
2038
2076
|
}
|
|
2039
2077
|
}
|
|
2078
|
+
const DRAG_ZONE_SELECTOR = "[data-bs-drag]";
|
|
2079
|
+
const NO_DRAG_SELECTOR = "[data-bs-no-drag]";
|
|
2080
|
+
const asElement = (target) => {
|
|
2081
|
+
const candidate = target;
|
|
2082
|
+
return candidate && typeof candidate.closest === "function" ? candidate : null;
|
|
2083
|
+
};
|
|
2084
|
+
function isDragAllowedFrom(target, mode) {
|
|
2085
|
+
const el = asElement(target);
|
|
2086
|
+
if (!el) return mode !== "zones";
|
|
2087
|
+
if (el.closest(NO_DRAG_SELECTOR)) return false;
|
|
2088
|
+
if (mode === "zones") return el.closest(DRAG_ZONE_SELECTOR) !== null;
|
|
2089
|
+
return true;
|
|
2090
|
+
}
|
|
2091
|
+
const CONTENT_DRAG_SLOP = 6;
|
|
2092
|
+
function decideContentGesture(input) {
|
|
2093
|
+
const slop = input.slop ?? CONTENT_DRAG_SLOP;
|
|
2094
|
+
if (Math.abs(input.delta) < slop) return "pending";
|
|
2095
|
+
if (input.scrollTop > 0) return "scroll";
|
|
2096
|
+
if (input.delta > 0 && input.atMaxSnap) return "scroll";
|
|
2097
|
+
return "drag";
|
|
2098
|
+
}
|
|
2099
|
+
function installTouchScrollGuard(surface, isDragging) {
|
|
2100
|
+
const onTouchMove = (e) => {
|
|
2101
|
+
if (!isDragging()) return;
|
|
2102
|
+
if (e.cancelable) e.preventDefault();
|
|
2103
|
+
};
|
|
2104
|
+
surface.addEventListener("touchmove", onTouchMove, {
|
|
2105
|
+
passive: false
|
|
2106
|
+
});
|
|
2107
|
+
return () => surface.removeEventListener("touchmove", onTouchMove);
|
|
2108
|
+
}
|
|
2040
2109
|
class AriaSliderWriter {
|
|
2041
2110
|
constructor(handle, mode) {
|
|
2042
2111
|
__publicField(this, "handle");
|
|
@@ -2430,6 +2499,8 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2430
2499
|
mode: opts.mode ?? "bottom",
|
|
2431
2500
|
flickVelocity: opts.flickVelocity ?? DEFAULT_FLICK_VELOCITY,
|
|
2432
2501
|
dragThreshold: opts.dragThreshold ?? DEFAULT_DRAG_THRESHOLD,
|
|
2502
|
+
dragFrom: opts.dragFrom ?? (opts.handle ? "handle" : "sheet"),
|
|
2503
|
+
dragFromContent: opts.dragFromContent ?? true,
|
|
2433
2504
|
rubberBandEnabled: opts.rubberBand ?? true,
|
|
2434
2505
|
closeOnBack: opts.closeOnBack ?? false,
|
|
2435
2506
|
persistent: opts.persistent ?? false,
|
|
@@ -2511,6 +2582,8 @@ class BottomSheetCore {
|
|
|
2511
2582
|
__publicField(this, "mode");
|
|
2512
2583
|
__publicField(this, "flickVelocity");
|
|
2513
2584
|
__publicField(this, "dragThreshold");
|
|
2585
|
+
__publicField(this, "dragFromMode");
|
|
2586
|
+
__publicField(this, "dragFromContentDefault");
|
|
2514
2587
|
__publicField(this, "rubberBandEnabled");
|
|
2515
2588
|
__publicField(this, "scrim");
|
|
2516
2589
|
__publicField(this, "aria");
|
|
@@ -2528,8 +2601,11 @@ class BottomSheetCore {
|
|
|
2528
2601
|
__publicField(this, "activeId");
|
|
2529
2602
|
__publicField(this, "size", 0);
|
|
2530
2603
|
__publicField(this, "gesture");
|
|
2604
|
+
__publicField(this, "contentGesture");
|
|
2605
|
+
__publicField(this, "detachSheetGesture", null);
|
|
2531
2606
|
__publicField(this, "rootEl", null);
|
|
2532
2607
|
__publicField(this, "destroyed", false);
|
|
2608
|
+
__publicField(this, "restClosed", false);
|
|
2533
2609
|
__publicField(this, "currentViewTransition", null);
|
|
2534
2610
|
__publicField(this, "currentAbort", new AbortController());
|
|
2535
2611
|
__publicField(this, "sizeWriteSentinel", new WriteSentinel());
|
|
@@ -2583,6 +2659,8 @@ class BottomSheetCore {
|
|
|
2583
2659
|
this.aria = new AriaSliderWriter(this.handle, this.mode);
|
|
2584
2660
|
this.flickVelocity = resolved.flickVelocity;
|
|
2585
2661
|
this.dragThreshold = resolved.dragThreshold;
|
|
2662
|
+
this.dragFromMode = resolved.dragFrom;
|
|
2663
|
+
this.dragFromContentDefault = resolved.dragFromContent;
|
|
2586
2664
|
this.rubberBandEnabled = resolved.rubberBandEnabled;
|
|
2587
2665
|
this.scrim = new ScrimController({
|
|
2588
2666
|
mode: this.mode,
|
|
@@ -2605,7 +2683,7 @@ class BottomSheetCore {
|
|
|
2605
2683
|
getRootEl: () => this.rootEl,
|
|
2606
2684
|
applySize: (size) => this.applySize(size),
|
|
2607
2685
|
getSize: () => this.size,
|
|
2608
|
-
isDragging: () => this.
|
|
2686
|
+
isDragging: () => this.isDraggingAny(),
|
|
2609
2687
|
applyAux: (size) => this.applySize(size, true),
|
|
2610
2688
|
getTransformFor: (size) => this.transformTemplate(this.snaps.getMaxAxisSize() - size)
|
|
2611
2689
|
}, resolved.animation);
|
|
@@ -2655,6 +2733,7 @@ class BottomSheetCore {
|
|
|
2655
2733
|
const initial = this.snaps.findById(this.activeId);
|
|
2656
2734
|
if (initial) this.size = initial.size;
|
|
2657
2735
|
this.applySize(this.size);
|
|
2736
|
+
this.setRestClosed(this.size === 0);
|
|
2658
2737
|
this.updateAriaSlider();
|
|
2659
2738
|
this.scrollCache = createScrollCache({
|
|
2660
2739
|
scrollContainer: this.scrollContainer,
|
|
@@ -2682,7 +2761,7 @@ class BottomSheetCore {
|
|
|
2682
2761
|
scrollContainer: this.scrollContainer,
|
|
2683
2762
|
hasFitSnap: () => this.snapPointsRaw.some((p) => p.size === "fit" || p.size === "content"),
|
|
2684
2763
|
isDestroyed: () => this.destroyed,
|
|
2685
|
-
isDragging: () => this.
|
|
2764
|
+
isDragging: () => this.isDraggingAny(),
|
|
2686
2765
|
recompute: () => this.recompute()
|
|
2687
2766
|
}));
|
|
2688
2767
|
if (resolved.radius !== void 0) this.setRadius(resolved.radius);
|
|
@@ -2707,7 +2786,7 @@ class BottomSheetCore {
|
|
|
2707
2786
|
autoCollapseAfter
|
|
2708
2787
|
},
|
|
2709
2788
|
isDestroyed: () => this.destroyed,
|
|
2710
|
-
isDragging: () => this.
|
|
2789
|
+
isDragging: () => this.isDraggingAny(),
|
|
2711
2790
|
isAnimating: () => this.animation.isAnimating,
|
|
2712
2791
|
isTopSheet: () => this.isTopSheet,
|
|
2713
2792
|
isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
|
|
@@ -2737,6 +2816,7 @@ class BottomSheetCore {
|
|
|
2737
2816
|
void this.snapTo(id);
|
|
2738
2817
|
},
|
|
2739
2818
|
close: (reason) => this.close(reason),
|
|
2819
|
+
attachDragSurface: (surface, kind) => this.attachDragSurface(surface, kind),
|
|
2740
2820
|
on: (event, fn) => this.on(event, fn),
|
|
2741
2821
|
addTeardown: (fn) => this.teardowns.add(fn)
|
|
2742
2822
|
};
|
|
@@ -2761,7 +2841,7 @@ class BottomSheetCore {
|
|
|
2761
2841
|
return {
|
|
2762
2842
|
size: this.size,
|
|
2763
2843
|
activeId: this.activeId,
|
|
2764
|
-
isDragging: this.
|
|
2844
|
+
isDragging: this.isDraggingAny(),
|
|
2765
2845
|
isAnimating: this.animation.isAnimating,
|
|
2766
2846
|
progress: this.computeProgress(this.size)
|
|
2767
2847
|
};
|
|
@@ -2883,9 +2963,16 @@ class BottomSheetCore {
|
|
|
2883
2963
|
progress: this.computeProgress(this.size)
|
|
2884
2964
|
});
|
|
2885
2965
|
if (withHaptic) this.haptic();
|
|
2966
|
+
this.setRestClosed(targetSize === 0);
|
|
2886
2967
|
if (wasClosed && targetSize > 0) this.emitOpenSequence(id);
|
|
2887
2968
|
if (targetSize === 0) this.emitCloseSequence();
|
|
2888
2969
|
}
|
|
2970
|
+
setRestClosed(closed) {
|
|
2971
|
+
if (closed === this.restClosed) return;
|
|
2972
|
+
this.restClosed = closed;
|
|
2973
|
+
if (closed) this.element.setAttribute("data-bs-rest", "closed");
|
|
2974
|
+
else this.element.removeAttribute("data-bs-rest");
|
|
2975
|
+
}
|
|
2889
2976
|
emitOpenSequence(id) {
|
|
2890
2977
|
this.emit("open", {
|
|
2891
2978
|
id
|
|
@@ -2949,6 +3036,20 @@ class BottomSheetCore {
|
|
|
2949
3036
|
if (this.destroyed) return;
|
|
2950
3037
|
this.disableDragFlag = value;
|
|
2951
3038
|
}
|
|
3039
|
+
setDragFromContent(value) {
|
|
3040
|
+
if (this.destroyed) return;
|
|
3041
|
+
this.dragFromContentDefault = value;
|
|
3042
|
+
}
|
|
3043
|
+
setDragFrom(mode) {
|
|
3044
|
+
if (this.destroyed || mode === this.dragFromMode) return;
|
|
3045
|
+
this.gesture?.forceClearDragState();
|
|
3046
|
+
this.detachSheetGesture?.();
|
|
3047
|
+
this.dragFromMode = mode;
|
|
3048
|
+
this.mountSheetGesture();
|
|
3049
|
+
}
|
|
3050
|
+
getDragFrom() {
|
|
3051
|
+
return this.dragFromMode;
|
|
3052
|
+
}
|
|
2952
3053
|
isTop() {
|
|
2953
3054
|
return this.isTopSheet;
|
|
2954
3055
|
}
|
|
@@ -3095,12 +3196,24 @@ class BottomSheetCore {
|
|
|
3095
3196
|
auditVhUsage(points);
|
|
3096
3197
|
this.auditDuplicateSnapIds(points);
|
|
3097
3198
|
this.snaps.setRaw(points);
|
|
3098
|
-
if (allowed)
|
|
3199
|
+
if (allowed) {
|
|
3200
|
+
this.snaps.setAllowedIds(allowed);
|
|
3201
|
+
} else {
|
|
3202
|
+
const present = this.snaps.getResolvedSnaps().map((s) => s.id);
|
|
3203
|
+
const kept = this.snaps.getAllowedIds().filter((id) => present.includes(id));
|
|
3204
|
+
this.snaps.setAllowedIds(kept.length ? kept : present);
|
|
3205
|
+
}
|
|
3099
3206
|
this.scrollCache.clear();
|
|
3100
3207
|
this.scrim.invalidateOpacityCache();
|
|
3101
3208
|
const current = this.snaps.findById(this.activeId);
|
|
3102
3209
|
if (current) {
|
|
3103
3210
|
this.applySize(current.size);
|
|
3211
|
+
} else {
|
|
3212
|
+
const fallback = this.snaps.getResolvedSnaps().find((s) => this.snaps.getAllowedIds().includes(s.id)) ?? this.snaps.getResolvedSnaps()[0];
|
|
3213
|
+
if (fallback) {
|
|
3214
|
+
this.activeId = fallback.id;
|
|
3215
|
+
this.applySize(fallback.size);
|
|
3216
|
+
}
|
|
3104
3217
|
}
|
|
3105
3218
|
this.updateAriaSlider();
|
|
3106
3219
|
}
|
|
@@ -3110,7 +3223,7 @@ class BottomSheetCore {
|
|
|
3110
3223
|
this.snaps.recompute();
|
|
3111
3224
|
this.maxHeight.clampTo();
|
|
3112
3225
|
this.scrim.invalidateOpacityCache();
|
|
3113
|
-
if (this.
|
|
3226
|
+
if (this.isDraggingAny()) return;
|
|
3114
3227
|
this.healActiveSnap();
|
|
3115
3228
|
}
|
|
3116
3229
|
healActiveSnap() {
|
|
@@ -3132,6 +3245,8 @@ class BottomSheetCore {
|
|
|
3132
3245
|
this.bus.clear();
|
|
3133
3246
|
this.animation.cancel();
|
|
3134
3247
|
this.gesture?.forceClearDragState();
|
|
3248
|
+
this.contentGesture?.forceClearDragState();
|
|
3249
|
+
this.setRestClosed(false);
|
|
3135
3250
|
this.teardowns.drain();
|
|
3136
3251
|
this.scrim.destroy();
|
|
3137
3252
|
this.animation.destroy();
|
|
@@ -3242,11 +3357,12 @@ class BottomSheetCore {
|
|
|
3242
3357
|
const scale = Math.max(1 - depth * 0.04, 0.86);
|
|
3243
3358
|
this.element.style.scale = scale === 1 ? "" : String(scale);
|
|
3244
3359
|
}
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
handle:
|
|
3360
|
+
buildGestureDeps(surface, gestureOptions) {
|
|
3361
|
+
return {
|
|
3362
|
+
handle: surface,
|
|
3248
3363
|
element: this.element,
|
|
3249
3364
|
mode: this.mode,
|
|
3365
|
+
gestureOptions,
|
|
3250
3366
|
getRoot: () => this.rootEl,
|
|
3251
3367
|
getDragContext: () => {
|
|
3252
3368
|
const buf = this.dragContextBuf;
|
|
@@ -3265,8 +3381,81 @@ class BottomSheetCore {
|
|
|
3265
3381
|
settleAfterDrag: (delta, velocity, kind) => this.settleAfterDrag(delta, velocity, kind),
|
|
3266
3382
|
emit: (event, payload) => this.emit(event, payload),
|
|
3267
3383
|
listenerCount: (event) => this.bus.listenerCount(event)
|
|
3384
|
+
};
|
|
3385
|
+
}
|
|
3386
|
+
isContentDragAllowed() {
|
|
3387
|
+
if (this.disableDragFlag) return false;
|
|
3388
|
+
const point = this.snapPointsRaw.find((p) => p.id === this.activeId);
|
|
3389
|
+
return point?.dragFromContent ?? this.dragFromContentDefault;
|
|
3390
|
+
}
|
|
3391
|
+
decideContentDrag(surface, e, delta) {
|
|
3392
|
+
if (this.destroyed) return false;
|
|
3393
|
+
if (e.pointerType === "mouse") return false;
|
|
3394
|
+
if (this.gesture?.isDragging) return false;
|
|
3395
|
+
if (!this.isContentDragAllowed()) return false;
|
|
3396
|
+
if (!isDragAllowedFrom(e.target, "sheet")) return false;
|
|
3397
|
+
const decision = decideContentGesture({
|
|
3398
|
+
delta,
|
|
3399
|
+
scrollTop: surface.scrollTop,
|
|
3400
|
+
atMaxSnap: this.size >= this.getAllowedRange().max - 0.5
|
|
3401
|
+
});
|
|
3402
|
+
if (decision === "pending") return null;
|
|
3403
|
+
return decision === "drag";
|
|
3404
|
+
}
|
|
3405
|
+
attachDragSurface(surface, kind) {
|
|
3406
|
+
if (this.destroyed || kind !== "content") return;
|
|
3407
|
+
if (this.contentGesture) return;
|
|
3408
|
+
const controller = new GestureController(this.buildGestureDeps(surface, {
|
|
3409
|
+
manageTouchAction: false,
|
|
3410
|
+
deferStart: (e, delta) => this.decideContentDrag(surface, e, delta)
|
|
3411
|
+
}));
|
|
3412
|
+
this.contentGesture = controller;
|
|
3413
|
+
const detachGestures = controller.install();
|
|
3414
|
+
const detachGuard = installTouchScrollGuard(surface, () => controller.isDragging);
|
|
3415
|
+
return () => {
|
|
3416
|
+
detachGuard();
|
|
3417
|
+
detachGestures();
|
|
3418
|
+
if (this.contentGesture === controller) this.contentGesture = void 0;
|
|
3419
|
+
};
|
|
3420
|
+
}
|
|
3421
|
+
sheetDragSurface() {
|
|
3422
|
+
return this.dragFromMode === "handle" ? this.handle : this.element;
|
|
3423
|
+
}
|
|
3424
|
+
canStartSheetDrag(e) {
|
|
3425
|
+
if (this.contentGesture?.isDragging) return false;
|
|
3426
|
+
const target = e.target;
|
|
3427
|
+
const scoped = typeof target?.closest === "function";
|
|
3428
|
+
if (scoped && target.closest(NO_DRAG_SELECTOR)) return false;
|
|
3429
|
+
if (this.handle !== this.element && scoped && this.handle.contains(target)) {
|
|
3430
|
+
return true;
|
|
3431
|
+
}
|
|
3432
|
+
if (!isDragAllowedFrom(e.target, this.dragFromMode)) return false;
|
|
3433
|
+
if (this.dragFromMode === "handle") return true;
|
|
3434
|
+
if (this.scrollContainer && scoped && this.scrollContainer.contains(target) && !target.closest(DRAG_ZONE_SELECTOR)) {
|
|
3435
|
+
return false;
|
|
3436
|
+
}
|
|
3437
|
+
return true;
|
|
3438
|
+
}
|
|
3439
|
+
mountSheetGesture() {
|
|
3440
|
+
const surface = this.sheetDragSurface();
|
|
3441
|
+
const controller = new GestureController(this.buildGestureDeps(surface, {
|
|
3442
|
+
shouldStart: (e) => this.canStartSheetDrag(e),
|
|
3443
|
+
manageTouchAction: this.dragFromMode === "handle"
|
|
3444
|
+
}));
|
|
3445
|
+
this.gesture = controller;
|
|
3446
|
+
const detachGestures = controller.install();
|
|
3447
|
+
const detachGuard = this.dragFromMode === "handle" ? null : installTouchScrollGuard(surface, () => controller.isDragging);
|
|
3448
|
+
this.detachSheetGesture = () => {
|
|
3449
|
+
detachGuard?.();
|
|
3450
|
+
detachGestures();
|
|
3451
|
+
};
|
|
3452
|
+
}
|
|
3453
|
+
attach() {
|
|
3454
|
+
this.mountSheetGesture();
|
|
3455
|
+
this.teardowns.add(() => {
|
|
3456
|
+
this.detachSheetGesture?.();
|
|
3457
|
+
this.detachSheetGesture = null;
|
|
3268
3458
|
});
|
|
3269
|
-
this.teardowns.add(this.gesture.install());
|
|
3270
3459
|
try {
|
|
3271
3460
|
this.attachFeatures();
|
|
3272
3461
|
} catch (err) {
|
|
@@ -3303,7 +3492,7 @@ class BottomSheetCore {
|
|
|
3303
3492
|
element: this.element,
|
|
3304
3493
|
getMode: () => this.mode,
|
|
3305
3494
|
isDestroyed: () => this.destroyed,
|
|
3306
|
-
isDragging: () => this.
|
|
3495
|
+
isDragging: () => this.isDraggingAny(),
|
|
3307
3496
|
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
3308
3497
|
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
3309
3498
|
getSize: () => this.size,
|
|
@@ -3393,8 +3582,11 @@ class BottomSheetCore {
|
|
|
3393
3582
|
this.completeSnap(target.id, target.size, previousSize, previousSnapSize === 0, true);
|
|
3394
3583
|
});
|
|
3395
3584
|
}
|
|
3585
|
+
isDraggingAny() {
|
|
3586
|
+
return (this.gesture?.isDragging ?? false) || (this.contentGesture?.isDragging ?? false);
|
|
3587
|
+
}
|
|
3396
3588
|
clearWillChangeIfIdle() {
|
|
3397
|
-
if (this.animation.isAnimating || this.
|
|
3589
|
+
if (this.animation.isAnimating || this.isDraggingAny()) return;
|
|
3398
3590
|
this.element.style.willChange = "";
|
|
3399
3591
|
}
|
|
3400
3592
|
haptic() {
|
|
@@ -3407,8 +3599,9 @@ class BottomSheetCore {
|
|
|
3407
3599
|
}
|
|
3408
3600
|
applySize(size, skipTransform = false) {
|
|
3409
3601
|
const cap = this.snaps.getMaxAxisSize();
|
|
3410
|
-
const clamped = cap > 0 && size > cap && !this.
|
|
3602
|
+
const clamped = cap > 0 && size > cap && !this.isDraggingAny() && !this.allowOvershoot ? cap : size;
|
|
3411
3603
|
this.size = clamped;
|
|
3604
|
+
if (clamped > 0) this.setRestClosed(false);
|
|
3412
3605
|
const offset = cap - clamped;
|
|
3413
3606
|
const style = this.element.style;
|
|
3414
3607
|
if (!skipTransform) style.transform = this.transformTemplate(offset);
|
|
@@ -3780,55 +3973,9 @@ function installAutoCollapse(deps) {
|
|
|
3780
3973
|
unsubscribe();
|
|
3781
3974
|
};
|
|
3782
3975
|
}
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
let startY = 0;
|
|
3787
|
-
let startScrollTop = 0;
|
|
3788
|
-
let moved = false;
|
|
3789
|
-
const onTouchStart = (e) => {
|
|
3790
|
-
const t = e.touches[0];
|
|
3791
|
-
if (!t) return;
|
|
3792
|
-
startY = t.clientY;
|
|
3793
|
-
startScrollTop = container.scrollTop;
|
|
3794
|
-
moved = false;
|
|
3795
|
-
};
|
|
3796
|
-
const onTouchMove = (e) => {
|
|
3797
|
-
const t = e.touches[0];
|
|
3798
|
-
if (!t) return;
|
|
3799
|
-
if (Math.abs(t.clientY - startY) > CONTENT_PULL_THRESHOLD) moved = true;
|
|
3800
|
-
};
|
|
3801
|
-
const onTouchEnd = (e) => {
|
|
3802
|
-
if (!moved) return;
|
|
3803
|
-
if (deps.isDragging() || deps.isAnimating()) return;
|
|
3804
|
-
if (container.scrollTop !== startScrollTop) return;
|
|
3805
|
-
const t = e.changedTouches[0];
|
|
3806
|
-
if (!t) return;
|
|
3807
|
-
const deltaY = t.clientY - startY;
|
|
3808
|
-
const atTop = container.scrollTop <= 0;
|
|
3809
|
-
const allowed = deps.getAllowedIds();
|
|
3810
|
-
const idx = allowed.indexOf(deps.getActiveId());
|
|
3811
|
-
if (idx === -1) return;
|
|
3812
|
-
if (atTop && deltaY > CONTENT_PULL_THRESHOLD && idx > 0) {
|
|
3813
|
-
deps.snapTo(allowed[idx - 1]);
|
|
3814
|
-
} else if (deltaY < -CONTENT_PULL_THRESHOLD && idx < allowed.length - 1) {
|
|
3815
|
-
deps.snapTo(allowed[idx + 1]);
|
|
3816
|
-
}
|
|
3817
|
-
};
|
|
3818
|
-
container.addEventListener("touchstart", onTouchStart, {
|
|
3819
|
-
passive: true
|
|
3820
|
-
});
|
|
3821
|
-
container.addEventListener("touchmove", onTouchMove, {
|
|
3822
|
-
passive: true
|
|
3823
|
-
});
|
|
3824
|
-
container.addEventListener("touchend", onTouchEnd, {
|
|
3825
|
-
passive: true
|
|
3826
|
-
});
|
|
3827
|
-
return () => {
|
|
3828
|
-
container.removeEventListener("touchstart", onTouchStart);
|
|
3829
|
-
container.removeEventListener("touchmove", onTouchMove);
|
|
3830
|
-
container.removeEventListener("touchend", onTouchEnd);
|
|
3831
|
-
};
|
|
3976
|
+
function installContentDrag(deps) {
|
|
3977
|
+
const detach = deps.attachDragSurface(deps.container, "content");
|
|
3978
|
+
return () => detach?.();
|
|
3832
3979
|
}
|
|
3833
3980
|
const SAFETY_PAD = 8;
|
|
3834
3981
|
function installVisualViewport(deps) {
|
|
@@ -3930,13 +4077,9 @@ function contentSwipeFeature() {
|
|
|
3930
4077
|
stage: "attach",
|
|
3931
4078
|
install: (ctx) => {
|
|
3932
4079
|
if (!ctx.scrollContainer) return;
|
|
3933
|
-
return
|
|
4080
|
+
return installContentDrag({
|
|
3934
4081
|
container: ctx.scrollContainer,
|
|
3935
|
-
|
|
3936
|
-
isAnimating: ctx.isAnimating,
|
|
3937
|
-
getAllowedIds: ctx.allowedIdsBySize,
|
|
3938
|
-
getActiveId: ctx.getActiveId,
|
|
3939
|
-
snapTo: ctx.snapTo
|
|
4082
|
+
attachDragSurface: ctx.attachDragSurface
|
|
3940
4083
|
});
|
|
3941
4084
|
}
|
|
3942
4085
|
};
|
|
@@ -4067,6 +4210,8 @@ const BottomSheet = component$((props) => {
|
|
|
4067
4210
|
persistent: props.persistent,
|
|
4068
4211
|
disableClose: props.disableClose,
|
|
4069
4212
|
disableDrag: props.disableDrag,
|
|
4213
|
+
dragFrom: props.dragFrom,
|
|
4214
|
+
dragFromContent: props.dragFromContent,
|
|
4070
4215
|
closeOnRouteChange: props.closeOnRouteChange,
|
|
4071
4216
|
stackEffect: props.stackEffect,
|
|
4072
4217
|
returnFocusTo: props.returnFocusTo,
|
|
@@ -4174,11 +4319,17 @@ const BottomSheet = component$((props) => {
|
|
|
4174
4319
|
const persistent = track(() => props.persistent);
|
|
4175
4320
|
const disableClose = track(() => props.disableClose);
|
|
4176
4321
|
const disableDrag = track(() => props.disableDrag);
|
|
4322
|
+
const dragFromContent = track(() => props.dragFromContent);
|
|
4323
|
+
const dragFrom = track(() => props.dragFrom);
|
|
4177
4324
|
const engine = engineStore.engine;
|
|
4178
4325
|
if (!engine) return;
|
|
4179
4326
|
if (persistent !== void 0) engine.setPersistent(persistent);
|
|
4180
4327
|
if (disableClose !== void 0) engine.setDisableClose(disableClose);
|
|
4181
4328
|
if (disableDrag !== void 0) engine.setDisableDrag(disableDrag);
|
|
4329
|
+
if (dragFromContent !== void 0) {
|
|
4330
|
+
engine.setDragFromContent(dragFromContent);
|
|
4331
|
+
}
|
|
4332
|
+
if (dragFrom !== void 0) engine.setDragFrom(dragFrom);
|
|
4182
4333
|
});
|
|
4183
4334
|
const showBackdrop = props.backdrop !== false;
|
|
4184
4335
|
const mode = props.mode ?? "bottom";
|