@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
|
@@ -1834,30 +1834,44 @@ class SampleRing {
|
|
|
1834
1834
|
this.size = 0;
|
|
1835
1835
|
}
|
|
1836
1836
|
}
|
|
1837
|
-
const installGestures = (handle, mode, callbacks) => {
|
|
1837
|
+
const installGestures = (handle, mode, callbacks, options = {}) => {
|
|
1838
1838
|
let activePointerId = null;
|
|
1839
1839
|
let activePointerType = "touch";
|
|
1840
1840
|
let startCoord = 0;
|
|
1841
1841
|
let lastCoord = 0;
|
|
1842
|
+
let pendingStart = false;
|
|
1842
1843
|
const VELOCITY_WINDOW_MS = (kind) => kind === "mouse" ? 160 : 120;
|
|
1843
1844
|
const MAX_SAMPLES = 32;
|
|
1844
1845
|
const samples = new SampleRing(MAX_SAMPLES);
|
|
1845
1846
|
const axis = isAxisVertical(mode) ? "Y" : "X";
|
|
1846
1847
|
const sign = mode === "bottom" || mode === "right" ? -1 : 1;
|
|
1847
1848
|
const coordOf = (e) => axis === "Y" ? e.clientY : e.clientX;
|
|
1849
|
+
const capture = (pointerId) => {
|
|
1850
|
+
try {
|
|
1851
|
+
handle.setPointerCapture(pointerId);
|
|
1852
|
+
} catch {
|
|
1853
|
+
}
|
|
1854
|
+
};
|
|
1855
|
+
const releaseTracking = () => {
|
|
1856
|
+
activePointerId = null;
|
|
1857
|
+
pendingStart = false;
|
|
1858
|
+
samples.reset();
|
|
1859
|
+
};
|
|
1848
1860
|
const onPointerDown = (e) => {
|
|
1849
1861
|
if (activePointerId !== null) return;
|
|
1850
1862
|
if (e.button !== void 0 && e.button !== 0) return;
|
|
1863
|
+
if (options.shouldStart && !options.shouldStart(e)) return;
|
|
1851
1864
|
activePointerId = e.pointerId;
|
|
1852
1865
|
activePointerType = e.pointerType || "touch";
|
|
1853
1866
|
startCoord = coordOf(e);
|
|
1854
1867
|
lastCoord = startCoord;
|
|
1855
1868
|
samples.reset();
|
|
1856
1869
|
samples.push(e.timeStamp, startCoord);
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1870
|
+
if (options.deferStart) {
|
|
1871
|
+
pendingStart = true;
|
|
1872
|
+
return;
|
|
1860
1873
|
}
|
|
1874
|
+
capture(e.pointerId);
|
|
1861
1875
|
callbacks.onStart(startCoord, activePointerType);
|
|
1862
1876
|
};
|
|
1863
1877
|
const onPointerMove = (e) => {
|
|
@@ -1865,6 +1879,22 @@ const installGestures = (handle, mode, callbacks) => {
|
|
|
1865
1879
|
const coord = coordOf(e);
|
|
1866
1880
|
const rawDelta = coord - startCoord;
|
|
1867
1881
|
const delta = rawDelta * sign;
|
|
1882
|
+
if (pendingStart) {
|
|
1883
|
+
const verdict = options.deferStart(e, delta);
|
|
1884
|
+
if (verdict === false) {
|
|
1885
|
+
releaseTracking();
|
|
1886
|
+
return;
|
|
1887
|
+
}
|
|
1888
|
+
if (verdict !== true) return;
|
|
1889
|
+
pendingStart = false;
|
|
1890
|
+
startCoord = coord;
|
|
1891
|
+
lastCoord = coord;
|
|
1892
|
+
samples.reset();
|
|
1893
|
+
samples.push(e.timeStamp, coord);
|
|
1894
|
+
capture(e.pointerId);
|
|
1895
|
+
callbacks.onStart(startCoord, activePointerType);
|
|
1896
|
+
return;
|
|
1897
|
+
}
|
|
1868
1898
|
lastCoord = coord;
|
|
1869
1899
|
samples.push(e.timeStamp, coord);
|
|
1870
1900
|
const cutoff = e.timeStamp - VELOCITY_WINDOW_MS(activePointerType);
|
|
@@ -1873,6 +1903,10 @@ const installGestures = (handle, mode, callbacks) => {
|
|
|
1873
1903
|
};
|
|
1874
1904
|
const finishGesture = (e) => {
|
|
1875
1905
|
if (e.pointerId !== activePointerId) return;
|
|
1906
|
+
if (pendingStart) {
|
|
1907
|
+
releaseTracking();
|
|
1908
|
+
return;
|
|
1909
|
+
}
|
|
1876
1910
|
const rawDelta = lastCoord - startCoord;
|
|
1877
1911
|
const delta = rawDelta * sign;
|
|
1878
1912
|
let velocity = 0;
|
|
@@ -1895,22 +1929,26 @@ const installGestures = (handle, mode, callbacks) => {
|
|
|
1895
1929
|
};
|
|
1896
1930
|
const onPointerCancel = (e) => {
|
|
1897
1931
|
if (e.pointerId !== activePointerId) return;
|
|
1898
|
-
|
|
1899
|
-
|
|
1932
|
+
const wasPending = pendingStart;
|
|
1933
|
+
releaseTracking();
|
|
1934
|
+
if (wasPending) return;
|
|
1900
1935
|
callbacks.onCancel?.();
|
|
1901
1936
|
};
|
|
1902
1937
|
handle.addEventListener("pointerdown", onPointerDown);
|
|
1903
1938
|
handle.addEventListener("pointermove", onPointerMove);
|
|
1904
1939
|
handle.addEventListener("pointerup", finishGesture);
|
|
1905
1940
|
handle.addEventListener("pointercancel", onPointerCancel);
|
|
1941
|
+
const managesTouchAction = options.manageTouchAction !== false;
|
|
1906
1942
|
const prevTouchAction = handle.style.touchAction;
|
|
1907
|
-
|
|
1943
|
+
if (managesTouchAction) {
|
|
1944
|
+
handle.style.touchAction = isAxisVertical(mode) ? "pan-x" : "pan-y";
|
|
1945
|
+
}
|
|
1908
1946
|
return () => {
|
|
1909
1947
|
handle.removeEventListener("pointerdown", onPointerDown);
|
|
1910
1948
|
handle.removeEventListener("pointermove", onPointerMove);
|
|
1911
1949
|
handle.removeEventListener("pointerup", finishGesture);
|
|
1912
1950
|
handle.removeEventListener("pointercancel", onPointerCancel);
|
|
1913
|
-
handle.style.touchAction = prevTouchAction;
|
|
1951
|
+
if (managesTouchAction) handle.style.touchAction = prevTouchAction;
|
|
1914
1952
|
if (activePointerId !== null && handle.hasPointerCapture(activePointerId)) {
|
|
1915
1953
|
handle.releasePointerCapture(activePointerId);
|
|
1916
1954
|
}
|
|
@@ -2028,7 +2066,7 @@ class GestureController {
|
|
|
2028
2066
|
const restoreTo = this.dragStartSize;
|
|
2029
2067
|
void this.deps.animateTo(restoreTo, 0);
|
|
2030
2068
|
}
|
|
2031
|
-
});
|
|
2069
|
+
}, this.deps.gestureOptions);
|
|
2032
2070
|
return this.detach;
|
|
2033
2071
|
}
|
|
2034
2072
|
forceClearDragState() {
|
|
@@ -2039,6 +2077,37 @@ class GestureController {
|
|
|
2039
2077
|
this.deps.element.style.willChange = "";
|
|
2040
2078
|
}
|
|
2041
2079
|
}
|
|
2080
|
+
const DRAG_ZONE_SELECTOR = "[data-bs-drag]";
|
|
2081
|
+
const NO_DRAG_SELECTOR = "[data-bs-no-drag]";
|
|
2082
|
+
const asElement = (target) => {
|
|
2083
|
+
const candidate = target;
|
|
2084
|
+
return candidate && typeof candidate.closest === "function" ? candidate : null;
|
|
2085
|
+
};
|
|
2086
|
+
function isDragAllowedFrom(target, mode) {
|
|
2087
|
+
const el = asElement(target);
|
|
2088
|
+
if (!el) return mode !== "zones";
|
|
2089
|
+
if (el.closest(NO_DRAG_SELECTOR)) return false;
|
|
2090
|
+
if (mode === "zones") return el.closest(DRAG_ZONE_SELECTOR) !== null;
|
|
2091
|
+
return true;
|
|
2092
|
+
}
|
|
2093
|
+
const CONTENT_DRAG_SLOP = 6;
|
|
2094
|
+
function decideContentGesture(input) {
|
|
2095
|
+
const slop = input.slop ?? CONTENT_DRAG_SLOP;
|
|
2096
|
+
if (Math.abs(input.delta) < slop) return "pending";
|
|
2097
|
+
if (input.scrollTop > 0) return "scroll";
|
|
2098
|
+
if (input.delta > 0 && input.atMaxSnap) return "scroll";
|
|
2099
|
+
return "drag";
|
|
2100
|
+
}
|
|
2101
|
+
function installTouchScrollGuard(surface, isDragging) {
|
|
2102
|
+
const onTouchMove = (e) => {
|
|
2103
|
+
if (!isDragging()) return;
|
|
2104
|
+
if (e.cancelable) e.preventDefault();
|
|
2105
|
+
};
|
|
2106
|
+
surface.addEventListener("touchmove", onTouchMove, {
|
|
2107
|
+
passive: false
|
|
2108
|
+
});
|
|
2109
|
+
return () => surface.removeEventListener("touchmove", onTouchMove);
|
|
2110
|
+
}
|
|
2042
2111
|
class AriaSliderWriter {
|
|
2043
2112
|
constructor(handle, mode) {
|
|
2044
2113
|
__publicField(this, "handle");
|
|
@@ -2432,6 +2501,8 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2432
2501
|
mode: opts.mode ?? "bottom",
|
|
2433
2502
|
flickVelocity: opts.flickVelocity ?? DEFAULT_FLICK_VELOCITY,
|
|
2434
2503
|
dragThreshold: opts.dragThreshold ?? DEFAULT_DRAG_THRESHOLD,
|
|
2504
|
+
dragFrom: opts.dragFrom ?? (opts.handle ? "handle" : "sheet"),
|
|
2505
|
+
dragFromContent: opts.dragFromContent ?? true,
|
|
2435
2506
|
rubberBandEnabled: opts.rubberBand ?? true,
|
|
2436
2507
|
closeOnBack: opts.closeOnBack ?? false,
|
|
2437
2508
|
persistent: opts.persistent ?? false,
|
|
@@ -2513,6 +2584,8 @@ class BottomSheetCore {
|
|
|
2513
2584
|
__publicField(this, "mode");
|
|
2514
2585
|
__publicField(this, "flickVelocity");
|
|
2515
2586
|
__publicField(this, "dragThreshold");
|
|
2587
|
+
__publicField(this, "dragFromMode");
|
|
2588
|
+
__publicField(this, "dragFromContentDefault");
|
|
2516
2589
|
__publicField(this, "rubberBandEnabled");
|
|
2517
2590
|
__publicField(this, "scrim");
|
|
2518
2591
|
__publicField(this, "aria");
|
|
@@ -2530,8 +2603,11 @@ class BottomSheetCore {
|
|
|
2530
2603
|
__publicField(this, "activeId");
|
|
2531
2604
|
__publicField(this, "size", 0);
|
|
2532
2605
|
__publicField(this, "gesture");
|
|
2606
|
+
__publicField(this, "contentGesture");
|
|
2607
|
+
__publicField(this, "detachSheetGesture", null);
|
|
2533
2608
|
__publicField(this, "rootEl", null);
|
|
2534
2609
|
__publicField(this, "destroyed", false);
|
|
2610
|
+
__publicField(this, "restClosed", false);
|
|
2535
2611
|
__publicField(this, "currentViewTransition", null);
|
|
2536
2612
|
__publicField(this, "currentAbort", new AbortController());
|
|
2537
2613
|
__publicField(this, "sizeWriteSentinel", new WriteSentinel());
|
|
@@ -2585,6 +2661,8 @@ class BottomSheetCore {
|
|
|
2585
2661
|
this.aria = new AriaSliderWriter(this.handle, this.mode);
|
|
2586
2662
|
this.flickVelocity = resolved.flickVelocity;
|
|
2587
2663
|
this.dragThreshold = resolved.dragThreshold;
|
|
2664
|
+
this.dragFromMode = resolved.dragFrom;
|
|
2665
|
+
this.dragFromContentDefault = resolved.dragFromContent;
|
|
2588
2666
|
this.rubberBandEnabled = resolved.rubberBandEnabled;
|
|
2589
2667
|
this.scrim = new ScrimController({
|
|
2590
2668
|
mode: this.mode,
|
|
@@ -2607,7 +2685,7 @@ class BottomSheetCore {
|
|
|
2607
2685
|
getRootEl: () => this.rootEl,
|
|
2608
2686
|
applySize: (size) => this.applySize(size),
|
|
2609
2687
|
getSize: () => this.size,
|
|
2610
|
-
isDragging: () => this.
|
|
2688
|
+
isDragging: () => this.isDraggingAny(),
|
|
2611
2689
|
applyAux: (size) => this.applySize(size, true),
|
|
2612
2690
|
getTransformFor: (size) => this.transformTemplate(this.snaps.getMaxAxisSize() - size)
|
|
2613
2691
|
}, resolved.animation);
|
|
@@ -2657,6 +2735,7 @@ class BottomSheetCore {
|
|
|
2657
2735
|
const initial = this.snaps.findById(this.activeId);
|
|
2658
2736
|
if (initial) this.size = initial.size;
|
|
2659
2737
|
this.applySize(this.size);
|
|
2738
|
+
this.setRestClosed(this.size === 0);
|
|
2660
2739
|
this.updateAriaSlider();
|
|
2661
2740
|
this.scrollCache = createScrollCache({
|
|
2662
2741
|
scrollContainer: this.scrollContainer,
|
|
@@ -2684,7 +2763,7 @@ class BottomSheetCore {
|
|
|
2684
2763
|
scrollContainer: this.scrollContainer,
|
|
2685
2764
|
hasFitSnap: () => this.snapPointsRaw.some((p) => p.size === "fit" || p.size === "content"),
|
|
2686
2765
|
isDestroyed: () => this.destroyed,
|
|
2687
|
-
isDragging: () => this.
|
|
2766
|
+
isDragging: () => this.isDraggingAny(),
|
|
2688
2767
|
recompute: () => this.recompute()
|
|
2689
2768
|
}));
|
|
2690
2769
|
if (resolved.radius !== void 0) this.setRadius(resolved.radius);
|
|
@@ -2709,7 +2788,7 @@ class BottomSheetCore {
|
|
|
2709
2788
|
autoCollapseAfter
|
|
2710
2789
|
},
|
|
2711
2790
|
isDestroyed: () => this.destroyed,
|
|
2712
|
-
isDragging: () => this.
|
|
2791
|
+
isDragging: () => this.isDraggingAny(),
|
|
2713
2792
|
isAnimating: () => this.animation.isAnimating,
|
|
2714
2793
|
isTopSheet: () => this.isTopSheet,
|
|
2715
2794
|
isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
|
|
@@ -2739,6 +2818,7 @@ class BottomSheetCore {
|
|
|
2739
2818
|
void this.snapTo(id);
|
|
2740
2819
|
},
|
|
2741
2820
|
close: (reason) => this.close(reason),
|
|
2821
|
+
attachDragSurface: (surface, kind) => this.attachDragSurface(surface, kind),
|
|
2742
2822
|
on: (event, fn) => this.on(event, fn),
|
|
2743
2823
|
addTeardown: (fn) => this.teardowns.add(fn)
|
|
2744
2824
|
};
|
|
@@ -2763,7 +2843,7 @@ class BottomSheetCore {
|
|
|
2763
2843
|
return {
|
|
2764
2844
|
size: this.size,
|
|
2765
2845
|
activeId: this.activeId,
|
|
2766
|
-
isDragging: this.
|
|
2846
|
+
isDragging: this.isDraggingAny(),
|
|
2767
2847
|
isAnimating: this.animation.isAnimating,
|
|
2768
2848
|
progress: this.computeProgress(this.size)
|
|
2769
2849
|
};
|
|
@@ -2885,9 +2965,16 @@ class BottomSheetCore {
|
|
|
2885
2965
|
progress: this.computeProgress(this.size)
|
|
2886
2966
|
});
|
|
2887
2967
|
if (withHaptic) this.haptic();
|
|
2968
|
+
this.setRestClosed(targetSize === 0);
|
|
2888
2969
|
if (wasClosed && targetSize > 0) this.emitOpenSequence(id);
|
|
2889
2970
|
if (targetSize === 0) this.emitCloseSequence();
|
|
2890
2971
|
}
|
|
2972
|
+
setRestClosed(closed) {
|
|
2973
|
+
if (closed === this.restClosed) return;
|
|
2974
|
+
this.restClosed = closed;
|
|
2975
|
+
if (closed) this.element.setAttribute("data-bs-rest", "closed");
|
|
2976
|
+
else this.element.removeAttribute("data-bs-rest");
|
|
2977
|
+
}
|
|
2891
2978
|
emitOpenSequence(id) {
|
|
2892
2979
|
this.emit("open", {
|
|
2893
2980
|
id
|
|
@@ -2951,6 +3038,20 @@ class BottomSheetCore {
|
|
|
2951
3038
|
if (this.destroyed) return;
|
|
2952
3039
|
this.disableDragFlag = value;
|
|
2953
3040
|
}
|
|
3041
|
+
setDragFromContent(value) {
|
|
3042
|
+
if (this.destroyed) return;
|
|
3043
|
+
this.dragFromContentDefault = value;
|
|
3044
|
+
}
|
|
3045
|
+
setDragFrom(mode) {
|
|
3046
|
+
if (this.destroyed || mode === this.dragFromMode) return;
|
|
3047
|
+
this.gesture?.forceClearDragState();
|
|
3048
|
+
this.detachSheetGesture?.();
|
|
3049
|
+
this.dragFromMode = mode;
|
|
3050
|
+
this.mountSheetGesture();
|
|
3051
|
+
}
|
|
3052
|
+
getDragFrom() {
|
|
3053
|
+
return this.dragFromMode;
|
|
3054
|
+
}
|
|
2954
3055
|
isTop() {
|
|
2955
3056
|
return this.isTopSheet;
|
|
2956
3057
|
}
|
|
@@ -3097,12 +3198,24 @@ class BottomSheetCore {
|
|
|
3097
3198
|
auditVhUsage(points);
|
|
3098
3199
|
this.auditDuplicateSnapIds(points);
|
|
3099
3200
|
this.snaps.setRaw(points);
|
|
3100
|
-
if (allowed)
|
|
3201
|
+
if (allowed) {
|
|
3202
|
+
this.snaps.setAllowedIds(allowed);
|
|
3203
|
+
} else {
|
|
3204
|
+
const present = this.snaps.getResolvedSnaps().map((s) => s.id);
|
|
3205
|
+
const kept = this.snaps.getAllowedIds().filter((id) => present.includes(id));
|
|
3206
|
+
this.snaps.setAllowedIds(kept.length ? kept : present);
|
|
3207
|
+
}
|
|
3101
3208
|
this.scrollCache.clear();
|
|
3102
3209
|
this.scrim.invalidateOpacityCache();
|
|
3103
3210
|
const current = this.snaps.findById(this.activeId);
|
|
3104
3211
|
if (current) {
|
|
3105
3212
|
this.applySize(current.size);
|
|
3213
|
+
} else {
|
|
3214
|
+
const fallback = this.snaps.getResolvedSnaps().find((s) => this.snaps.getAllowedIds().includes(s.id)) ?? this.snaps.getResolvedSnaps()[0];
|
|
3215
|
+
if (fallback) {
|
|
3216
|
+
this.activeId = fallback.id;
|
|
3217
|
+
this.applySize(fallback.size);
|
|
3218
|
+
}
|
|
3106
3219
|
}
|
|
3107
3220
|
this.updateAriaSlider();
|
|
3108
3221
|
}
|
|
@@ -3112,7 +3225,7 @@ class BottomSheetCore {
|
|
|
3112
3225
|
this.snaps.recompute();
|
|
3113
3226
|
this.maxHeight.clampTo();
|
|
3114
3227
|
this.scrim.invalidateOpacityCache();
|
|
3115
|
-
if (this.
|
|
3228
|
+
if (this.isDraggingAny()) return;
|
|
3116
3229
|
this.healActiveSnap();
|
|
3117
3230
|
}
|
|
3118
3231
|
healActiveSnap() {
|
|
@@ -3134,6 +3247,8 @@ class BottomSheetCore {
|
|
|
3134
3247
|
this.bus.clear();
|
|
3135
3248
|
this.animation.cancel();
|
|
3136
3249
|
this.gesture?.forceClearDragState();
|
|
3250
|
+
this.contentGesture?.forceClearDragState();
|
|
3251
|
+
this.setRestClosed(false);
|
|
3137
3252
|
this.teardowns.drain();
|
|
3138
3253
|
this.scrim.destroy();
|
|
3139
3254
|
this.animation.destroy();
|
|
@@ -3244,11 +3359,12 @@ class BottomSheetCore {
|
|
|
3244
3359
|
const scale = Math.max(1 - depth * 0.04, 0.86);
|
|
3245
3360
|
this.element.style.scale = scale === 1 ? "" : String(scale);
|
|
3246
3361
|
}
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
handle:
|
|
3362
|
+
buildGestureDeps(surface, gestureOptions) {
|
|
3363
|
+
return {
|
|
3364
|
+
handle: surface,
|
|
3250
3365
|
element: this.element,
|
|
3251
3366
|
mode: this.mode,
|
|
3367
|
+
gestureOptions,
|
|
3252
3368
|
getRoot: () => this.rootEl,
|
|
3253
3369
|
getDragContext: () => {
|
|
3254
3370
|
const buf = this.dragContextBuf;
|
|
@@ -3267,8 +3383,81 @@ class BottomSheetCore {
|
|
|
3267
3383
|
settleAfterDrag: (delta, velocity, kind) => this.settleAfterDrag(delta, velocity, kind),
|
|
3268
3384
|
emit: (event, payload) => this.emit(event, payload),
|
|
3269
3385
|
listenerCount: (event) => this.bus.listenerCount(event)
|
|
3386
|
+
};
|
|
3387
|
+
}
|
|
3388
|
+
isContentDragAllowed() {
|
|
3389
|
+
if (this.disableDragFlag) return false;
|
|
3390
|
+
const point = this.snapPointsRaw.find((p) => p.id === this.activeId);
|
|
3391
|
+
return point?.dragFromContent ?? this.dragFromContentDefault;
|
|
3392
|
+
}
|
|
3393
|
+
decideContentDrag(surface, e, delta) {
|
|
3394
|
+
if (this.destroyed) return false;
|
|
3395
|
+
if (e.pointerType === "mouse") return false;
|
|
3396
|
+
if (this.gesture?.isDragging) return false;
|
|
3397
|
+
if (!this.isContentDragAllowed()) return false;
|
|
3398
|
+
if (!isDragAllowedFrom(e.target, "sheet")) return false;
|
|
3399
|
+
const decision = decideContentGesture({
|
|
3400
|
+
delta,
|
|
3401
|
+
scrollTop: surface.scrollTop,
|
|
3402
|
+
atMaxSnap: this.size >= this.getAllowedRange().max - 0.5
|
|
3403
|
+
});
|
|
3404
|
+
if (decision === "pending") return null;
|
|
3405
|
+
return decision === "drag";
|
|
3406
|
+
}
|
|
3407
|
+
attachDragSurface(surface, kind) {
|
|
3408
|
+
if (this.destroyed || kind !== "content") return;
|
|
3409
|
+
if (this.contentGesture) return;
|
|
3410
|
+
const controller = new GestureController(this.buildGestureDeps(surface, {
|
|
3411
|
+
manageTouchAction: false,
|
|
3412
|
+
deferStart: (e, delta) => this.decideContentDrag(surface, e, delta)
|
|
3413
|
+
}));
|
|
3414
|
+
this.contentGesture = controller;
|
|
3415
|
+
const detachGestures = controller.install();
|
|
3416
|
+
const detachGuard = installTouchScrollGuard(surface, () => controller.isDragging);
|
|
3417
|
+
return () => {
|
|
3418
|
+
detachGuard();
|
|
3419
|
+
detachGestures();
|
|
3420
|
+
if (this.contentGesture === controller) this.contentGesture = void 0;
|
|
3421
|
+
};
|
|
3422
|
+
}
|
|
3423
|
+
sheetDragSurface() {
|
|
3424
|
+
return this.dragFromMode === "handle" ? this.handle : this.element;
|
|
3425
|
+
}
|
|
3426
|
+
canStartSheetDrag(e) {
|
|
3427
|
+
if (this.contentGesture?.isDragging) return false;
|
|
3428
|
+
const target = e.target;
|
|
3429
|
+
const scoped = typeof target?.closest === "function";
|
|
3430
|
+
if (scoped && target.closest(NO_DRAG_SELECTOR)) return false;
|
|
3431
|
+
if (this.handle !== this.element && scoped && this.handle.contains(target)) {
|
|
3432
|
+
return true;
|
|
3433
|
+
}
|
|
3434
|
+
if (!isDragAllowedFrom(e.target, this.dragFromMode)) return false;
|
|
3435
|
+
if (this.dragFromMode === "handle") return true;
|
|
3436
|
+
if (this.scrollContainer && scoped && this.scrollContainer.contains(target) && !target.closest(DRAG_ZONE_SELECTOR)) {
|
|
3437
|
+
return false;
|
|
3438
|
+
}
|
|
3439
|
+
return true;
|
|
3440
|
+
}
|
|
3441
|
+
mountSheetGesture() {
|
|
3442
|
+
const surface = this.sheetDragSurface();
|
|
3443
|
+
const controller = new GestureController(this.buildGestureDeps(surface, {
|
|
3444
|
+
shouldStart: (e) => this.canStartSheetDrag(e),
|
|
3445
|
+
manageTouchAction: this.dragFromMode === "handle"
|
|
3446
|
+
}));
|
|
3447
|
+
this.gesture = controller;
|
|
3448
|
+
const detachGestures = controller.install();
|
|
3449
|
+
const detachGuard = this.dragFromMode === "handle" ? null : installTouchScrollGuard(surface, () => controller.isDragging);
|
|
3450
|
+
this.detachSheetGesture = () => {
|
|
3451
|
+
detachGuard?.();
|
|
3452
|
+
detachGestures();
|
|
3453
|
+
};
|
|
3454
|
+
}
|
|
3455
|
+
attach() {
|
|
3456
|
+
this.mountSheetGesture();
|
|
3457
|
+
this.teardowns.add(() => {
|
|
3458
|
+
this.detachSheetGesture?.();
|
|
3459
|
+
this.detachSheetGesture = null;
|
|
3270
3460
|
});
|
|
3271
|
-
this.teardowns.add(this.gesture.install());
|
|
3272
3461
|
try {
|
|
3273
3462
|
this.attachFeatures();
|
|
3274
3463
|
} catch (err) {
|
|
@@ -3305,7 +3494,7 @@ class BottomSheetCore {
|
|
|
3305
3494
|
element: this.element,
|
|
3306
3495
|
getMode: () => this.mode,
|
|
3307
3496
|
isDestroyed: () => this.destroyed,
|
|
3308
|
-
isDragging: () => this.
|
|
3497
|
+
isDragging: () => this.isDraggingAny(),
|
|
3309
3498
|
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
3310
3499
|
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
3311
3500
|
getSize: () => this.size,
|
|
@@ -3395,8 +3584,11 @@ class BottomSheetCore {
|
|
|
3395
3584
|
this.completeSnap(target.id, target.size, previousSize, previousSnapSize === 0, true);
|
|
3396
3585
|
});
|
|
3397
3586
|
}
|
|
3587
|
+
isDraggingAny() {
|
|
3588
|
+
return (this.gesture?.isDragging ?? false) || (this.contentGesture?.isDragging ?? false);
|
|
3589
|
+
}
|
|
3398
3590
|
clearWillChangeIfIdle() {
|
|
3399
|
-
if (this.animation.isAnimating || this.
|
|
3591
|
+
if (this.animation.isAnimating || this.isDraggingAny()) return;
|
|
3400
3592
|
this.element.style.willChange = "";
|
|
3401
3593
|
}
|
|
3402
3594
|
haptic() {
|
|
@@ -3409,8 +3601,9 @@ class BottomSheetCore {
|
|
|
3409
3601
|
}
|
|
3410
3602
|
applySize(size, skipTransform = false) {
|
|
3411
3603
|
const cap = this.snaps.getMaxAxisSize();
|
|
3412
|
-
const clamped = cap > 0 && size > cap && !this.
|
|
3604
|
+
const clamped = cap > 0 && size > cap && !this.isDraggingAny() && !this.allowOvershoot ? cap : size;
|
|
3413
3605
|
this.size = clamped;
|
|
3606
|
+
if (clamped > 0) this.setRestClosed(false);
|
|
3414
3607
|
const offset = cap - clamped;
|
|
3415
3608
|
const style = this.element.style;
|
|
3416
3609
|
if (!skipTransform) style.transform = this.transformTemplate(offset);
|
|
@@ -3782,55 +3975,9 @@ function installAutoCollapse(deps) {
|
|
|
3782
3975
|
unsubscribe();
|
|
3783
3976
|
};
|
|
3784
3977
|
}
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
let startY = 0;
|
|
3789
|
-
let startScrollTop = 0;
|
|
3790
|
-
let moved = false;
|
|
3791
|
-
const onTouchStart = (e) => {
|
|
3792
|
-
const t = e.touches[0];
|
|
3793
|
-
if (!t) return;
|
|
3794
|
-
startY = t.clientY;
|
|
3795
|
-
startScrollTop = container.scrollTop;
|
|
3796
|
-
moved = false;
|
|
3797
|
-
};
|
|
3798
|
-
const onTouchMove = (e) => {
|
|
3799
|
-
const t = e.touches[0];
|
|
3800
|
-
if (!t) return;
|
|
3801
|
-
if (Math.abs(t.clientY - startY) > CONTENT_PULL_THRESHOLD) moved = true;
|
|
3802
|
-
};
|
|
3803
|
-
const onTouchEnd = (e) => {
|
|
3804
|
-
if (!moved) return;
|
|
3805
|
-
if (deps.isDragging() || deps.isAnimating()) return;
|
|
3806
|
-
if (container.scrollTop !== startScrollTop) return;
|
|
3807
|
-
const t = e.changedTouches[0];
|
|
3808
|
-
if (!t) return;
|
|
3809
|
-
const deltaY = t.clientY - startY;
|
|
3810
|
-
const atTop = container.scrollTop <= 0;
|
|
3811
|
-
const allowed = deps.getAllowedIds();
|
|
3812
|
-
const idx = allowed.indexOf(deps.getActiveId());
|
|
3813
|
-
if (idx === -1) return;
|
|
3814
|
-
if (atTop && deltaY > CONTENT_PULL_THRESHOLD && idx > 0) {
|
|
3815
|
-
deps.snapTo(allowed[idx - 1]);
|
|
3816
|
-
} else if (deltaY < -CONTENT_PULL_THRESHOLD && idx < allowed.length - 1) {
|
|
3817
|
-
deps.snapTo(allowed[idx + 1]);
|
|
3818
|
-
}
|
|
3819
|
-
};
|
|
3820
|
-
container.addEventListener("touchstart", onTouchStart, {
|
|
3821
|
-
passive: true
|
|
3822
|
-
});
|
|
3823
|
-
container.addEventListener("touchmove", onTouchMove, {
|
|
3824
|
-
passive: true
|
|
3825
|
-
});
|
|
3826
|
-
container.addEventListener("touchend", onTouchEnd, {
|
|
3827
|
-
passive: true
|
|
3828
|
-
});
|
|
3829
|
-
return () => {
|
|
3830
|
-
container.removeEventListener("touchstart", onTouchStart);
|
|
3831
|
-
container.removeEventListener("touchmove", onTouchMove);
|
|
3832
|
-
container.removeEventListener("touchend", onTouchEnd);
|
|
3833
|
-
};
|
|
3978
|
+
function installContentDrag(deps) {
|
|
3979
|
+
const detach = deps.attachDragSurface(deps.container, "content");
|
|
3980
|
+
return () => detach?.();
|
|
3834
3981
|
}
|
|
3835
3982
|
const SAFETY_PAD = 8;
|
|
3836
3983
|
function installVisualViewport(deps) {
|
|
@@ -3932,13 +4079,9 @@ function contentSwipeFeature() {
|
|
|
3932
4079
|
stage: "attach",
|
|
3933
4080
|
install: (ctx) => {
|
|
3934
4081
|
if (!ctx.scrollContainer) return;
|
|
3935
|
-
return
|
|
4082
|
+
return installContentDrag({
|
|
3936
4083
|
container: ctx.scrollContainer,
|
|
3937
|
-
|
|
3938
|
-
isAnimating: ctx.isAnimating,
|
|
3939
|
-
getAllowedIds: ctx.allowedIdsBySize,
|
|
3940
|
-
getActiveId: ctx.getActiveId,
|
|
3941
|
-
snapTo: ctx.snapTo
|
|
4084
|
+
attachDragSurface: ctx.attachDragSurface
|
|
3942
4085
|
});
|
|
3943
4086
|
}
|
|
3944
4087
|
};
|
|
@@ -4069,6 +4212,8 @@ const BottomSheet = qwik.component$((props) => {
|
|
|
4069
4212
|
persistent: props.persistent,
|
|
4070
4213
|
disableClose: props.disableClose,
|
|
4071
4214
|
disableDrag: props.disableDrag,
|
|
4215
|
+
dragFrom: props.dragFrom,
|
|
4216
|
+
dragFromContent: props.dragFromContent,
|
|
4072
4217
|
closeOnRouteChange: props.closeOnRouteChange,
|
|
4073
4218
|
stackEffect: props.stackEffect,
|
|
4074
4219
|
returnFocusTo: props.returnFocusTo,
|
|
@@ -4176,11 +4321,17 @@ const BottomSheet = qwik.component$((props) => {
|
|
|
4176
4321
|
const persistent = track(() => props.persistent);
|
|
4177
4322
|
const disableClose = track(() => props.disableClose);
|
|
4178
4323
|
const disableDrag = track(() => props.disableDrag);
|
|
4324
|
+
const dragFromContent = track(() => props.dragFromContent);
|
|
4325
|
+
const dragFrom = track(() => props.dragFrom);
|
|
4179
4326
|
const engine = engineStore.engine;
|
|
4180
4327
|
if (!engine) return;
|
|
4181
4328
|
if (persistent !== void 0) engine.setPersistent(persistent);
|
|
4182
4329
|
if (disableClose !== void 0) engine.setDisableClose(disableClose);
|
|
4183
4330
|
if (disableDrag !== void 0) engine.setDisableDrag(disableDrag);
|
|
4331
|
+
if (dragFromContent !== void 0) {
|
|
4332
|
+
engine.setDragFromContent(dragFromContent);
|
|
4333
|
+
}
|
|
4334
|
+
if (dragFrom !== void 0) engine.setDragFrom(dragFrom);
|
|
4184
4335
|
});
|
|
4185
4336
|
const showBackdrop = props.backdrop !== false;
|
|
4186
4337
|
const mode = props.mode ?? "bottom";
|