@surdeddd/bottom-sheet 0.12.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 +85 -1
- package/dist/{BottomSheetEngine-D6oiEfZ4.d.cts → BottomSheetCore-Cp7dWy91.d.cts} +85 -5
- package/dist/{BottomSheetEngine-Dhy0X_e9.d.ts → BottomSheetCore-DJYwWOqt.d.ts} +85 -5
- package/dist/BottomSheetEngine-Lm7HIVHv.d.cts +7 -0
- package/dist/BottomSheetEngine-O5PbeKfe.d.ts +7 -0
- package/dist/core.cjs +3680 -0
- package/dist/core.d.cts +3 -0
- package/dist/core.d.ts +3 -0
- package/dist/core.js +3678 -0
- package/dist/debug.cjs +109 -0
- package/dist/debug.d.cts +22 -0
- package/dist/debug.d.ts +22 -0
- package/dist/debug.js +107 -0
- package/dist/element.cjs +1314 -829
- package/dist/element.d.cts +2 -1
- package/dist/element.d.ts +2 -1
- package/dist/element.iife.global.js +2 -2
- package/dist/element.js +1314 -829
- package/dist/features.cjs +489 -0
- package/dist/features.d.cts +13 -0
- package/dist/features.d.ts +13 -0
- package/dist/features.js +482 -0
- package/dist/index-Bb5TRmyg.d.cts +9 -0
- package/dist/index-Cl9ebCP2.d.ts +9 -0
- package/dist/index.cjs +979 -1293
- package/dist/index.d.cts +43 -55
- package/dist/index.d.ts +43 -55
- package/dist/index.js +973 -1280
- 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 +11 -10
- package/dist/overlay.js +11 -10
- package/dist/preact.d.cts +2 -1
- package/dist/preact.d.ts +2 -1
- package/dist/qwik-lib/index.qwik.cjs +4418 -0
- package/dist/qwik-lib/index.qwik.mjs +4418 -0
- package/dist/qwik.cjs +1089 -657
- package/dist/qwik.d.cts +4 -2
- package/dist/qwik.d.ts +4 -2
- package/dist/qwik.js +1089 -657
- package/dist/react.cjs +1100 -665
- package/dist/react.d.cts +3 -3
- package/dist/react.d.ts +3 -3
- package/dist/react.js +1100 -665
- package/dist/solid.cjs +1095 -657
- package/dist/solid.d.cts +90 -4
- package/dist/solid.d.ts +90 -4
- package/dist/solid.js +1095 -657
- package/dist/solid.source.jsx +1103 -657
- package/dist/styles.css +24 -4
- package/dist/svelte-core.cjs +981 -557
- package/dist/svelte-core.js +981 -557
- package/dist/svelte-src/BottomSheet.svelte +14 -0
- package/dist/svelte.cjs +1091 -657
- package/dist/svelte.d.cts +2 -0
- package/dist/svelte.d.ts +2 -0
- package/dist/svelte.js +1091 -657
- package/dist/vue.cjs +1105 -657
- package/dist/vue.js +1105 -657
- 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 +88 -12
package/dist/svelte-core.cjs
CHANGED
|
@@ -6,7 +6,7 @@ var __defProp = Object.defineProperty;
|
|
|
6
6
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
7
7
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
8
8
|
|
|
9
|
-
// src/core/lifecycle/
|
|
9
|
+
// src/core/lifecycle/sheet-stack.ts
|
|
10
10
|
var BASE_Z = 100;
|
|
11
11
|
var STEP = 10;
|
|
12
12
|
var SheetStack = class {
|
|
@@ -131,7 +131,7 @@ function createEventBus() {
|
|
|
131
131
|
};
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
// src/core/primitives/
|
|
134
|
+
// src/core/primitives/css-length.ts
|
|
135
135
|
var probe = null;
|
|
136
136
|
var PROBE_ATTR = "data-bs-probe";
|
|
137
137
|
var ensureProbe = (axis) => {
|
|
@@ -185,7 +185,7 @@ var resolveSnap = (point, mode, measureFit) => {
|
|
|
185
185
|
return Math.max(0, el.getBoundingClientRect().width);
|
|
186
186
|
};
|
|
187
187
|
|
|
188
|
-
// src/core/primitives/
|
|
188
|
+
// src/core/primitives/dev-warn.ts
|
|
189
189
|
function devWarn(...args) {
|
|
190
190
|
if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
|
|
191
191
|
console.warn(...args);
|
|
@@ -350,74 +350,6 @@ var SnapResolver = class {
|
|
|
350
350
|
}
|
|
351
351
|
};
|
|
352
352
|
|
|
353
|
-
// src/core/features/persist.ts
|
|
354
|
-
function readPersistedId(key) {
|
|
355
|
-
if (!key) return null;
|
|
356
|
-
if (typeof window === "undefined") return null;
|
|
357
|
-
if (typeof localStorage === "undefined") return null;
|
|
358
|
-
try {
|
|
359
|
-
return localStorage.getItem(key);
|
|
360
|
-
} catch {
|
|
361
|
-
return null;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
function installPersist(engine, key) {
|
|
365
|
-
const unsubscribe = engine.on("snap", ({ id }) => {
|
|
366
|
-
if (typeof window === "undefined") return;
|
|
367
|
-
if (typeof localStorage === "undefined") return;
|
|
368
|
-
try {
|
|
369
|
-
localStorage.setItem(key, id);
|
|
370
|
-
} catch {
|
|
371
|
-
}
|
|
372
|
-
});
|
|
373
|
-
return unsubscribe;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
// src/core/features/auto-collapse.ts
|
|
377
|
-
function installAutoCollapse(deps) {
|
|
378
|
-
const { ms } = deps;
|
|
379
|
-
if (ms === void 0 || ms <= 0) {
|
|
380
|
-
return () => {
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
let timer = null;
|
|
384
|
-
const clearTimer = () => {
|
|
385
|
-
if (timer !== null) {
|
|
386
|
-
clearTimeout(timer);
|
|
387
|
-
timer = null;
|
|
388
|
-
}
|
|
389
|
-
};
|
|
390
|
-
const fire = () => {
|
|
391
|
-
if (deps.isDestroyed()) return;
|
|
392
|
-
if (deps.isDragging()) return;
|
|
393
|
-
const active = deps.resolveSnap(deps.getActiveId());
|
|
394
|
-
if (!active || active.size === 0) return;
|
|
395
|
-
let target = null;
|
|
396
|
-
for (const id of deps.getAllowedIds()) {
|
|
397
|
-
const snap = deps.resolveSnap(id);
|
|
398
|
-
if (!snap || snap.size <= 0) continue;
|
|
399
|
-
if (!target || snap.size < target.size) target = snap;
|
|
400
|
-
}
|
|
401
|
-
if (!target) return;
|
|
402
|
-
if (target.id === active.id || target.size >= active.size) return;
|
|
403
|
-
deps.snapTo(target.id);
|
|
404
|
-
};
|
|
405
|
-
const reset = () => {
|
|
406
|
-
clearTimer();
|
|
407
|
-
if (deps.isDestroyed()) return;
|
|
408
|
-
timer = setTimeout(() => {
|
|
409
|
-
timer = null;
|
|
410
|
-
fire();
|
|
411
|
-
}, ms);
|
|
412
|
-
};
|
|
413
|
-
const unsubscribe = deps.on("snap", () => reset());
|
|
414
|
-
if ((deps.resolveSnap(deps.getActiveId())?.size ?? 0) > 0) reset();
|
|
415
|
-
return () => {
|
|
416
|
-
clearTimer();
|
|
417
|
-
unsubscribe();
|
|
418
|
-
};
|
|
419
|
-
}
|
|
420
|
-
|
|
421
353
|
// src/core/features/linked-sheets.ts
|
|
422
354
|
function notifyLinkedSheets(sheets, self) {
|
|
423
355
|
if (sheets.length === 0) return;
|
|
@@ -440,394 +372,65 @@ function notifyLinkedSheets(sheets, self) {
|
|
|
440
372
|
}
|
|
441
373
|
}
|
|
442
374
|
|
|
443
|
-
// src/core/features/
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
var pendingRebrand = null;
|
|
449
|
-
var listenerInstalled = false;
|
|
450
|
-
var patchInstalled = false;
|
|
451
|
-
var origPushState = null;
|
|
452
|
-
var origReplaceState = null;
|
|
453
|
-
var patchedPushState = null;
|
|
454
|
-
var patchedReplaceState = null;
|
|
455
|
-
var hasWindow = () => typeof window !== "undefined";
|
|
456
|
-
var hasHistory = () => typeof history !== "undefined";
|
|
457
|
-
var brandMarker = (surface) => ({
|
|
458
|
-
...surface.markerState(),
|
|
459
|
-
__bs: true
|
|
460
|
-
});
|
|
461
|
-
var runInternal = (fn) => {
|
|
462
|
-
internalDepth += 1;
|
|
463
|
-
try {
|
|
464
|
-
fn();
|
|
465
|
-
} finally {
|
|
466
|
-
internalDepth -= 1;
|
|
467
|
-
}
|
|
468
|
-
};
|
|
469
|
-
var notifyRouteChange = () => {
|
|
470
|
-
const snapshot = Array.from(subscribers);
|
|
471
|
-
for (const fn of snapshot) fn();
|
|
472
|
-
};
|
|
473
|
-
var ensureListener = () => {
|
|
474
|
-
if (listenerInstalled || !hasWindow()) return;
|
|
475
|
-
window.addEventListener("popstate", onPopState);
|
|
476
|
-
listenerInstalled = true;
|
|
477
|
-
};
|
|
478
|
-
var maybeTeardownListener = () => {
|
|
479
|
-
if (!listenerInstalled) return;
|
|
480
|
-
if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
|
|
481
|
-
if (hasWindow()) window.removeEventListener("popstate", onPopState);
|
|
482
|
-
listenerInstalled = false;
|
|
483
|
-
};
|
|
484
|
-
var installPatch = () => {
|
|
485
|
-
if (patchInstalled || !hasHistory()) return;
|
|
486
|
-
origPushState = history.pushState;
|
|
487
|
-
origReplaceState = history.replaceState;
|
|
488
|
-
patchedPushState = function(...args) {
|
|
489
|
-
origPushState.apply(this, args);
|
|
490
|
-
if (internalDepth === 0) notifyRouteChange();
|
|
491
|
-
};
|
|
492
|
-
patchedReplaceState = function(...args) {
|
|
493
|
-
origReplaceState.apply(this, args);
|
|
494
|
-
if (internalDepth === 0) notifyRouteChange();
|
|
495
|
-
};
|
|
496
|
-
history.pushState = patchedPushState;
|
|
497
|
-
history.replaceState = patchedReplaceState;
|
|
498
|
-
patchInstalled = true;
|
|
499
|
-
};
|
|
500
|
-
var removePatch = () => {
|
|
501
|
-
if (!patchInstalled) return;
|
|
502
|
-
if (history.pushState === patchedPushState && origPushState) {
|
|
503
|
-
history.pushState = origPushState;
|
|
504
|
-
}
|
|
505
|
-
if (history.replaceState === patchedReplaceState && origReplaceState) {
|
|
506
|
-
history.replaceState = origReplaceState;
|
|
507
|
-
}
|
|
508
|
-
origPushState = null;
|
|
509
|
-
origReplaceState = null;
|
|
510
|
-
patchedPushState = null;
|
|
511
|
-
patchedReplaceState = null;
|
|
512
|
-
patchInstalled = false;
|
|
513
|
-
};
|
|
514
|
-
function onPopState() {
|
|
515
|
-
if (suppress > 0) {
|
|
516
|
-
suppress -= 1;
|
|
517
|
-
const rebrand = pendingRebrand;
|
|
518
|
-
pendingRebrand = null;
|
|
519
|
-
if (rebrand) rebrand();
|
|
520
|
-
maybeTeardownListener();
|
|
521
|
-
return;
|
|
522
|
-
}
|
|
523
|
-
if (entries.length === 0) {
|
|
524
|
-
notifyRouteChange();
|
|
525
|
-
maybeTeardownListener();
|
|
526
|
-
return;
|
|
375
|
+
// src/core/features/resize-observer.ts
|
|
376
|
+
function installResizeObserver(deps) {
|
|
377
|
+
if (typeof window === "undefined") {
|
|
378
|
+
return () => {
|
|
379
|
+
};
|
|
527
380
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
const
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
381
|
+
const onResize = () => {
|
|
382
|
+
if (deps.isDestroyed()) return;
|
|
383
|
+
deps.recomputeSnaps();
|
|
384
|
+
const mode = deps.getMode();
|
|
385
|
+
const isVerticalAxis = mode === "bottom" || mode === "top";
|
|
386
|
+
const viewportSize2 = isVerticalAxis ? window.innerHeight : window.innerWidth;
|
|
387
|
+
const max = deps.getMaxAxisSize();
|
|
388
|
+
if (viewportSize2 > 0 && viewportSize2 < max) {
|
|
389
|
+
deps.setMaxAxisSize(viewportSize2);
|
|
536
390
|
}
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
391
|
+
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
392
|
+
deps.cancelInFlight();
|
|
393
|
+
deps.newCycle();
|
|
394
|
+
const current = deps.resolveActiveSnap();
|
|
395
|
+
const newMax = deps.getMaxAxisSize();
|
|
396
|
+
const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
|
|
397
|
+
deps.setSize(targetSize);
|
|
398
|
+
if (current && !deps.isDragging()) {
|
|
399
|
+
deps.applySize(targetSize);
|
|
400
|
+
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
541
401
|
}
|
|
402
|
+
};
|
|
403
|
+
let resizeObserver = null;
|
|
404
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
405
|
+
resizeObserver = new ResizeObserver(onResize);
|
|
406
|
+
resizeObserver.observe(document.documentElement);
|
|
407
|
+
} else {
|
|
408
|
+
window.addEventListener("resize", onResize);
|
|
542
409
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
if (
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
}
|
|
555
|
-
maybeTeardownListener();
|
|
410
|
+
window.addEventListener("orientationchange", onResize);
|
|
411
|
+
const onVisibility = () => {
|
|
412
|
+
if (deps.isDestroyed()) return;
|
|
413
|
+
if (document.hidden) deps.cancelInFlight();
|
|
414
|
+
};
|
|
415
|
+
document.addEventListener("visibilitychange", onVisibility);
|
|
416
|
+
return () => {
|
|
417
|
+
resizeObserver?.disconnect();
|
|
418
|
+
window.removeEventListener("resize", onResize);
|
|
419
|
+
window.removeEventListener("orientationchange", onResize);
|
|
420
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
421
|
+
};
|
|
556
422
|
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
entries.push(entry);
|
|
569
|
-
ensureListener();
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
function pushBackMarker(surface) {
|
|
573
|
-
const entry = { surface, priorUrl: void 0, live: false };
|
|
574
|
-
if (!hasWindow() || !hasHistory()) {
|
|
575
|
-
return entry;
|
|
576
|
-
}
|
|
577
|
-
entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
|
|
578
|
-
runInternal(() => {
|
|
579
|
-
try {
|
|
580
|
-
history.pushState(brandMarker(surface), "", surface.url);
|
|
581
|
-
entry.live = true;
|
|
582
|
-
} catch {
|
|
583
|
-
entry.live = false;
|
|
584
|
-
}
|
|
585
|
-
});
|
|
586
|
-
if (entry.live) {
|
|
587
|
-
entries.push(entry);
|
|
588
|
-
ensureListener();
|
|
589
|
-
}
|
|
590
|
-
return entry;
|
|
591
|
-
}
|
|
592
|
-
function popBackMarker(handle) {
|
|
593
|
-
if (!hasWindow() || !hasHistory()) return;
|
|
594
|
-
const entry = handle;
|
|
595
|
-
const idx = entries.indexOf(entry);
|
|
596
|
-
if (idx === -1 || !entry.live) return;
|
|
597
|
-
const last = entries.length - 1;
|
|
598
|
-
entry.live = false;
|
|
599
|
-
entries.splice(idx, 1);
|
|
600
|
-
if (idx !== last) {
|
|
601
|
-
const rebrandSurface = entries[entries.length - 1].surface;
|
|
602
|
-
const rebrandUrl = entry.priorUrl;
|
|
603
|
-
pendingRebrand = () => {
|
|
604
|
-
runInternal(() => {
|
|
605
|
-
history.replaceState(
|
|
606
|
-
brandMarker(rebrandSurface),
|
|
607
|
-
"",
|
|
608
|
-
rebrandUrl !== void 0 ? rebrandUrl : location.href
|
|
609
|
-
);
|
|
610
|
-
});
|
|
611
|
-
};
|
|
612
|
-
}
|
|
613
|
-
suppress += 1;
|
|
614
|
-
runInternal(() => {
|
|
615
|
-
try {
|
|
616
|
-
history.back();
|
|
617
|
-
} catch {
|
|
618
|
-
suppress = Math.max(0, suppress - 1);
|
|
619
|
-
pendingRebrand = null;
|
|
620
|
-
}
|
|
621
|
-
});
|
|
622
|
-
maybeTeardownListener();
|
|
623
|
-
}
|
|
624
|
-
function subscribeRouteChange(fn) {
|
|
625
|
-
if (!hasWindow() || !hasHistory()) return () => {
|
|
626
|
-
};
|
|
627
|
-
subscribers.add(fn);
|
|
628
|
-
if (subscribers.size === 1) installPatch();
|
|
629
|
-
ensureListener();
|
|
630
|
-
return () => {
|
|
631
|
-
if (!subscribers.has(fn)) return;
|
|
632
|
-
subscribers.delete(fn);
|
|
633
|
-
if (subscribers.size === 0) removePatch();
|
|
634
|
-
maybeTeardownListener();
|
|
635
|
-
};
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
// src/core/features/route.ts
|
|
639
|
-
function installRoute(deps) {
|
|
640
|
-
if (typeof window === "undefined") {
|
|
641
|
-
return () => {
|
|
642
|
-
};
|
|
643
|
-
}
|
|
644
|
-
if (!deps.routedTo && !deps.closeOnBack) {
|
|
645
|
-
return () => {
|
|
646
|
-
};
|
|
647
|
-
}
|
|
648
|
-
let handle = null;
|
|
649
|
-
const onOpen = () => {
|
|
650
|
-
if (handle) return;
|
|
651
|
-
handle = pushBackMarker({
|
|
652
|
-
isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
|
|
653
|
-
isTop: deps.isTopSheet,
|
|
654
|
-
close: deps.close,
|
|
655
|
-
markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
|
|
656
|
-
url: deps.routedTo
|
|
657
|
-
});
|
|
658
|
-
};
|
|
659
|
-
const onClose = () => {
|
|
660
|
-
if (!handle) return;
|
|
661
|
-
popBackMarker(handle);
|
|
662
|
-
handle = null;
|
|
663
|
-
};
|
|
664
|
-
const unsubscribeOpen = deps.on("open", onOpen);
|
|
665
|
-
const unsubscribeClose = deps.on("close", onClose);
|
|
666
|
-
if (deps.getSize() > 0) onOpen();
|
|
667
|
-
return () => {
|
|
668
|
-
unsubscribeOpen();
|
|
669
|
-
unsubscribeClose();
|
|
670
|
-
if (handle) {
|
|
671
|
-
popBackMarker(handle);
|
|
672
|
-
handle = null;
|
|
673
|
-
}
|
|
674
|
-
};
|
|
675
|
-
}
|
|
676
|
-
function installRouteChange(deps) {
|
|
677
|
-
return subscribeRouteChange(() => {
|
|
678
|
-
if (deps.isDestroyed() || deps.getSize() <= 0) return;
|
|
679
|
-
void deps.close();
|
|
680
|
-
});
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
// src/core/features/content-swipe.ts
|
|
684
|
-
var CONTENT_PULL_THRESHOLD = 60;
|
|
685
|
-
function installContentSwipe(deps) {
|
|
686
|
-
const { container } = deps;
|
|
687
|
-
let startY = 0;
|
|
688
|
-
let startScrollTop = 0;
|
|
689
|
-
let moved = false;
|
|
690
|
-
const onTouchStart = (e) => {
|
|
691
|
-
const t = e.touches[0];
|
|
692
|
-
if (!t) return;
|
|
693
|
-
startY = t.clientY;
|
|
694
|
-
startScrollTop = container.scrollTop;
|
|
695
|
-
moved = false;
|
|
696
|
-
};
|
|
697
|
-
const onTouchMove = (e) => {
|
|
698
|
-
const t = e.touches[0];
|
|
699
|
-
if (!t) return;
|
|
700
|
-
if (Math.abs(t.clientY - startY) > CONTENT_PULL_THRESHOLD) moved = true;
|
|
701
|
-
};
|
|
702
|
-
const onTouchEnd = (e) => {
|
|
703
|
-
if (!moved) return;
|
|
704
|
-
if (deps.isDragging() || deps.isAnimating()) return;
|
|
705
|
-
if (container.scrollTop !== startScrollTop) return;
|
|
706
|
-
const t = e.changedTouches[0];
|
|
707
|
-
if (!t) return;
|
|
708
|
-
const deltaY = t.clientY - startY;
|
|
709
|
-
const atTop = container.scrollTop <= 0;
|
|
710
|
-
const allowed = deps.getAllowedIds();
|
|
711
|
-
const idx = allowed.indexOf(deps.getActiveId());
|
|
712
|
-
if (idx === -1) return;
|
|
713
|
-
if (atTop && deltaY > CONTENT_PULL_THRESHOLD && idx > 0) {
|
|
714
|
-
deps.snapTo(allowed[idx - 1]);
|
|
715
|
-
} else if (deltaY < -CONTENT_PULL_THRESHOLD && idx < allowed.length - 1) {
|
|
716
|
-
deps.snapTo(allowed[idx + 1]);
|
|
717
|
-
}
|
|
718
|
-
};
|
|
719
|
-
container.addEventListener("touchstart", onTouchStart, { passive: true });
|
|
720
|
-
container.addEventListener("touchmove", onTouchMove, { passive: true });
|
|
721
|
-
container.addEventListener("touchend", onTouchEnd, { passive: true });
|
|
722
|
-
return () => {
|
|
723
|
-
container.removeEventListener("touchstart", onTouchStart);
|
|
724
|
-
container.removeEventListener("touchmove", onTouchMove);
|
|
725
|
-
container.removeEventListener("touchend", onTouchEnd);
|
|
726
|
-
};
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
// src/core/features/visual-viewport.ts
|
|
730
|
-
var SAFETY_PAD = 8;
|
|
731
|
-
function installVisualViewport(deps) {
|
|
732
|
-
if (typeof window === "undefined" || !window.visualViewport) {
|
|
733
|
-
return () => {
|
|
734
|
-
};
|
|
735
|
-
}
|
|
736
|
-
const vv = window.visualViewport;
|
|
737
|
-
let rafId = null;
|
|
738
|
-
const onResize = () => {
|
|
739
|
-
if (rafId !== null) return;
|
|
740
|
-
rafId = requestAnimationFrame(() => {
|
|
741
|
-
rafId = null;
|
|
742
|
-
if (deps.isDestroyed()) return;
|
|
743
|
-
deps.recomputeSnaps();
|
|
744
|
-
const isVertical = deps.isVerticalAxis();
|
|
745
|
-
const visible = isVertical ? vv.height : vv.width;
|
|
746
|
-
const windowSize = isVertical ? window.innerHeight : window.innerWidth;
|
|
747
|
-
const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
|
|
748
|
-
if (clamp < deps.getMaxAxisSize()) {
|
|
749
|
-
deps.setMaxAxisSize(clamp);
|
|
750
|
-
}
|
|
751
|
-
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
752
|
-
deps.cancelInFlight();
|
|
753
|
-
deps.newCycle();
|
|
754
|
-
const max = deps.getMaxAxisSize();
|
|
755
|
-
deps.setSize(Math.min(deps.getSize(), max));
|
|
756
|
-
const current = deps.resolveActiveSnap();
|
|
757
|
-
if (current && !deps.isDragging()) {
|
|
758
|
-
deps.applySize(Math.min(current.size, max));
|
|
759
|
-
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
760
|
-
} else {
|
|
761
|
-
deps.applySize(deps.getSize());
|
|
762
|
-
}
|
|
763
|
-
});
|
|
764
|
-
};
|
|
765
|
-
vv.addEventListener("resize", onResize);
|
|
766
|
-
return () => {
|
|
767
|
-
vv.removeEventListener("resize", onResize);
|
|
768
|
-
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
769
|
-
};
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
// src/core/features/resize-observer.ts
|
|
773
|
-
function installResizeObserver(deps) {
|
|
774
|
-
if (typeof window === "undefined") {
|
|
775
|
-
return () => {
|
|
776
|
-
};
|
|
777
|
-
}
|
|
778
|
-
const onResize = () => {
|
|
779
|
-
if (deps.isDestroyed()) return;
|
|
780
|
-
deps.recomputeSnaps();
|
|
781
|
-
const mode = deps.getMode();
|
|
782
|
-
const isVerticalAxis = mode === "bottom" || mode === "top";
|
|
783
|
-
const viewportSize2 = isVerticalAxis ? window.innerHeight : window.innerWidth;
|
|
784
|
-
const max = deps.getMaxAxisSize();
|
|
785
|
-
if (viewportSize2 > 0 && viewportSize2 < max) {
|
|
786
|
-
deps.setMaxAxisSize(viewportSize2);
|
|
787
|
-
}
|
|
788
|
-
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
789
|
-
deps.cancelInFlight();
|
|
790
|
-
deps.newCycle();
|
|
791
|
-
const current = deps.resolveActiveSnap();
|
|
792
|
-
const newMax = deps.getMaxAxisSize();
|
|
793
|
-
const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
|
|
794
|
-
deps.setSize(targetSize);
|
|
795
|
-
if (current && !deps.isDragging()) {
|
|
796
|
-
deps.applySize(targetSize);
|
|
797
|
-
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
798
|
-
}
|
|
799
|
-
};
|
|
800
|
-
let resizeObserver = null;
|
|
801
|
-
if (typeof ResizeObserver !== "undefined") {
|
|
802
|
-
resizeObserver = new ResizeObserver(onResize);
|
|
803
|
-
resizeObserver.observe(document.documentElement);
|
|
804
|
-
} else {
|
|
805
|
-
window.addEventListener("resize", onResize);
|
|
806
|
-
}
|
|
807
|
-
window.addEventListener("orientationchange", onResize);
|
|
808
|
-
const onVisibility = () => {
|
|
809
|
-
if (deps.isDestroyed()) return;
|
|
810
|
-
if (document.hidden) deps.cancelInFlight();
|
|
811
|
-
};
|
|
812
|
-
document.addEventListener("visibilitychange", onVisibility);
|
|
813
|
-
return () => {
|
|
814
|
-
resizeObserver?.disconnect();
|
|
815
|
-
window.removeEventListener("resize", onResize);
|
|
816
|
-
window.removeEventListener("orientationchange", onResize);
|
|
817
|
-
document.removeEventListener("visibilitychange", onVisibility);
|
|
818
|
-
};
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
// src/core/features/fit-observer.ts
|
|
822
|
-
var contentTargets = (scroller) => {
|
|
823
|
-
if (!scroller) return [];
|
|
824
|
-
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
825
|
-
const out = [];
|
|
826
|
-
for (const child of Array.from(scroller.children)) {
|
|
827
|
-
if (hasSlot && child instanceof HTMLSlotElement) {
|
|
828
|
-
for (const el of child.assignedElements()) out.push(el);
|
|
829
|
-
} else {
|
|
830
|
-
out.push(child);
|
|
423
|
+
|
|
424
|
+
// src/core/features/fit-observer.ts
|
|
425
|
+
var contentTargets = (scroller) => {
|
|
426
|
+
if (!scroller) return [];
|
|
427
|
+
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
428
|
+
const out = [];
|
|
429
|
+
for (const child of Array.from(scroller.children)) {
|
|
430
|
+
if (hasSlot && child instanceof HTMLSlotElement) {
|
|
431
|
+
for (const el of child.assignedElements()) out.push(el);
|
|
432
|
+
} else {
|
|
433
|
+
out.push(child);
|
|
831
434
|
}
|
|
832
435
|
}
|
|
833
436
|
return out;
|
|
@@ -1669,6 +1272,52 @@ function resolveAnimationPreset(animation) {
|
|
|
1669
1272
|
}
|
|
1670
1273
|
}
|
|
1671
1274
|
|
|
1275
|
+
// src/core/animation/waapi-settle.ts
|
|
1276
|
+
var SIM_HZ = 240;
|
|
1277
|
+
var SAMPLE_STRIDE = 4;
|
|
1278
|
+
var MAX_SIM_MS = 3e3;
|
|
1279
|
+
function sampleSpringSettle(from, to, velocityPxPerS, config) {
|
|
1280
|
+
const cfg = { ...DEFAULT_SPRING, ...config };
|
|
1281
|
+
const subDt = 1 / SIM_HZ;
|
|
1282
|
+
const stepMs = SAMPLE_STRIDE / SIM_HZ * 1e3;
|
|
1283
|
+
const maxSteps = Math.ceil(MAX_SIM_MS / 1e3 * SIM_HZ);
|
|
1284
|
+
const values = [from];
|
|
1285
|
+
let x = from;
|
|
1286
|
+
let v = velocityPxPerS;
|
|
1287
|
+
for (let i = 1; i <= maxSteps; i += 1) {
|
|
1288
|
+
const force = -cfg.stiffness * (x - to) - cfg.damping * v;
|
|
1289
|
+
v += force / cfg.mass * subDt;
|
|
1290
|
+
x += v * subDt;
|
|
1291
|
+
if (!Number.isFinite(x) || !Number.isFinite(v)) {
|
|
1292
|
+
values.push(to);
|
|
1293
|
+
break;
|
|
1294
|
+
}
|
|
1295
|
+
if (i % SAMPLE_STRIDE === 0) values.push(x);
|
|
1296
|
+
const atRest = Math.abs(to - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
|
|
1297
|
+
if (atRest) break;
|
|
1298
|
+
}
|
|
1299
|
+
if (values[values.length - 1] !== to) values.push(to);
|
|
1300
|
+
return {
|
|
1301
|
+
values,
|
|
1302
|
+
stepMs,
|
|
1303
|
+
durationMs: (values.length - 1) * stepMs
|
|
1304
|
+
};
|
|
1305
|
+
}
|
|
1306
|
+
function sampleTweenSettle(from, to, durationMs, easing) {
|
|
1307
|
+
const count = Math.max(2, Math.min(60, Math.round(durationMs / 16)));
|
|
1308
|
+
const values = [];
|
|
1309
|
+
for (let i = 0; i <= count; i += 1) {
|
|
1310
|
+
const t = i / count;
|
|
1311
|
+
values.push(from + (to - from) * easing(t));
|
|
1312
|
+
}
|
|
1313
|
+
values[values.length - 1] = to;
|
|
1314
|
+
return {
|
|
1315
|
+
values,
|
|
1316
|
+
stepMs: durationMs / count,
|
|
1317
|
+
durationMs
|
|
1318
|
+
};
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1672
1321
|
// src/core/controllers/animation-runner.ts
|
|
1673
1322
|
var DEFAULT_DURATION2 = 220;
|
|
1674
1323
|
var VELOCITY_PX_PER_S = 1e3;
|
|
@@ -1679,6 +1328,10 @@ var AnimationRunner = class {
|
|
|
1679
1328
|
__publicField(this, "applySizeFn");
|
|
1680
1329
|
__publicField(this, "getSize");
|
|
1681
1330
|
__publicField(this, "isDragging");
|
|
1331
|
+
__publicField(this, "applyAux");
|
|
1332
|
+
__publicField(this, "getTransformFor");
|
|
1333
|
+
__publicField(this, "settleWaapi");
|
|
1334
|
+
__publicField(this, "currentWaapi", null);
|
|
1682
1335
|
__publicField(this, "animationKind");
|
|
1683
1336
|
__publicField(this, "springConfig");
|
|
1684
1337
|
__publicField(this, "duration");
|
|
@@ -1694,6 +1347,9 @@ var AnimationRunner = class {
|
|
|
1694
1347
|
this.applySizeFn = deps.applySize;
|
|
1695
1348
|
this.getSize = deps.getSize;
|
|
1696
1349
|
this.isDragging = deps.isDragging;
|
|
1350
|
+
this.applyAux = deps.applyAux;
|
|
1351
|
+
this.getTransformFor = deps.getTransformFor;
|
|
1352
|
+
this.settleWaapi = opts.settleAnimation === "waapi";
|
|
1697
1353
|
const preset = resolveAnimationPreset(opts.animation);
|
|
1698
1354
|
this.animationKind = preset.kind;
|
|
1699
1355
|
this.duration = opts.duration ?? preset.duration ?? DEFAULT_DURATION2;
|
|
@@ -1718,11 +1374,20 @@ var AnimationRunner = class {
|
|
|
1718
1374
|
}
|
|
1719
1375
|
}
|
|
1720
1376
|
get isAnimating() {
|
|
1721
|
-
return this.currentTween !== null || this.currentSpring !== null;
|
|
1377
|
+
return this.currentTween !== null || this.currentSpring !== null || this.currentWaapi !== null;
|
|
1722
1378
|
}
|
|
1723
1379
|
cancel() {
|
|
1724
1380
|
this.currentTween?.cancel();
|
|
1725
1381
|
this.currentSpring?.cancel();
|
|
1382
|
+
if (this.currentWaapi) {
|
|
1383
|
+
const entry = this.currentWaapi;
|
|
1384
|
+
this.currentWaapi = null;
|
|
1385
|
+
entry.stop();
|
|
1386
|
+
try {
|
|
1387
|
+
entry.anim.cancel();
|
|
1388
|
+
} catch {
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1726
1391
|
}
|
|
1727
1392
|
async animateTo(target, velocityPxPerMs) {
|
|
1728
1393
|
if (target === this.getSize()) {
|
|
@@ -1741,6 +1406,27 @@ var AnimationRunner = class {
|
|
|
1741
1406
|
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1742
1407
|
return;
|
|
1743
1408
|
}
|
|
1409
|
+
if (this.settleWaapi && this.applyAux && this.getTransformFor && typeof this.element.animate === "function") {
|
|
1410
|
+
const samples = this.animationKind === "spring" ? sampleSpringSettle(
|
|
1411
|
+
this.getSize(),
|
|
1412
|
+
target,
|
|
1413
|
+
velocityPxPerMs * VELOCITY_PX_PER_S,
|
|
1414
|
+
this.springConfig
|
|
1415
|
+
) : sampleTweenSettle(
|
|
1416
|
+
this.getSize(),
|
|
1417
|
+
target,
|
|
1418
|
+
this.duration,
|
|
1419
|
+
this.easing
|
|
1420
|
+
);
|
|
1421
|
+
if (samples.values.length >= 2 && samples.durationMs > 0) {
|
|
1422
|
+
await this.runWaapiSettle(samples, target);
|
|
1423
|
+
if (!this.isAnimating) {
|
|
1424
|
+
this.getRootEl()?.removeAttribute("data-animating");
|
|
1425
|
+
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1426
|
+
}
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1744
1430
|
if (this.animationKind === "spring") {
|
|
1745
1431
|
const spring = runSpring({
|
|
1746
1432
|
from: this.getSize(),
|
|
@@ -1769,15 +1455,70 @@ var AnimationRunner = class {
|
|
|
1769
1455
|
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1770
1456
|
}
|
|
1771
1457
|
}
|
|
1458
|
+
async runWaapiSettle(samples, target) {
|
|
1459
|
+
const applyAux = this.applyAux;
|
|
1460
|
+
const getTransformFor = this.getTransformFor;
|
|
1461
|
+
const frames = samples.values.map((v) => ({
|
|
1462
|
+
transform: getTransformFor(v)
|
|
1463
|
+
}));
|
|
1464
|
+
const anim = this.element.animate(frames, {
|
|
1465
|
+
duration: samples.durationMs,
|
|
1466
|
+
easing: "linear",
|
|
1467
|
+
fill: "forwards"
|
|
1468
|
+
});
|
|
1469
|
+
let stopped = false;
|
|
1470
|
+
let auxRaf = 0;
|
|
1471
|
+
const start = performance.now();
|
|
1472
|
+
const lastIdx = samples.values.length - 1;
|
|
1473
|
+
const auxTick = () => {
|
|
1474
|
+
if (stopped) return;
|
|
1475
|
+
const elapsed = performance.now() - start;
|
|
1476
|
+
const idx = Math.min(Math.floor(elapsed / samples.stepMs), lastIdx);
|
|
1477
|
+
applyAux(samples.values[idx]);
|
|
1478
|
+
auxRaf = requestAnimationFrame(auxTick);
|
|
1479
|
+
};
|
|
1480
|
+
auxRaf = requestAnimationFrame(auxTick);
|
|
1481
|
+
const entry = {
|
|
1482
|
+
anim,
|
|
1483
|
+
stop: () => {
|
|
1484
|
+
stopped = true;
|
|
1485
|
+
cancelAnimationFrame(auxRaf);
|
|
1486
|
+
}
|
|
1487
|
+
};
|
|
1488
|
+
this.currentWaapi = entry;
|
|
1489
|
+
try {
|
|
1490
|
+
await anim.finished;
|
|
1491
|
+
} catch {
|
|
1492
|
+
}
|
|
1493
|
+
entry.stop();
|
|
1494
|
+
const wasCurrent = this.currentWaapi === entry;
|
|
1495
|
+
if (wasCurrent) this.currentWaapi = null;
|
|
1496
|
+
if (wasCurrent && anim.playState === "finished") {
|
|
1497
|
+
this.applySizeFn(target);
|
|
1498
|
+
try {
|
|
1499
|
+
anim.cancel();
|
|
1500
|
+
} catch {
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1772
1504
|
destroy() {
|
|
1773
1505
|
this.detachReducedMotion?.();
|
|
1774
1506
|
this.detachReducedMotion = null;
|
|
1775
1507
|
this.currentTween = null;
|
|
1776
1508
|
this.currentSpring = null;
|
|
1509
|
+
if (this.currentWaapi) {
|
|
1510
|
+
const entry = this.currentWaapi;
|
|
1511
|
+
this.currentWaapi = null;
|
|
1512
|
+
entry.stop();
|
|
1513
|
+
try {
|
|
1514
|
+
entry.anim.cancel();
|
|
1515
|
+
} catch {
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1777
1518
|
}
|
|
1778
1519
|
};
|
|
1779
1520
|
|
|
1780
|
-
// src/core/lifecycle/
|
|
1521
|
+
// src/core/lifecycle/focus-trap.ts
|
|
1781
1522
|
var FOCUSABLE = [
|
|
1782
1523
|
"a[href]",
|
|
1783
1524
|
"area[href]",
|
|
@@ -1895,7 +1636,7 @@ var installFocusTrap = (container, options = {}) => {
|
|
|
1895
1636
|
};
|
|
1896
1637
|
};
|
|
1897
1638
|
|
|
1898
|
-
// src/core/lifecycle/
|
|
1639
|
+
// src/core/lifecycle/scroll-lock.ts
|
|
1899
1640
|
var lockCount = 0;
|
|
1900
1641
|
var savedStyles = null;
|
|
1901
1642
|
var lockBodyScroll = () => {
|
|
@@ -2077,30 +1818,44 @@ var SampleRing = class {
|
|
|
2077
1818
|
this.size = 0;
|
|
2078
1819
|
}
|
|
2079
1820
|
};
|
|
2080
|
-
var installGestures = (handle, mode, callbacks) => {
|
|
1821
|
+
var installGestures = (handle, mode, callbacks, options = {}) => {
|
|
2081
1822
|
let activePointerId = null;
|
|
2082
1823
|
let activePointerType = "touch";
|
|
2083
1824
|
let startCoord = 0;
|
|
2084
1825
|
let lastCoord = 0;
|
|
1826
|
+
let pendingStart = false;
|
|
2085
1827
|
const VELOCITY_WINDOW_MS = (kind) => kind === "mouse" ? 160 : 120;
|
|
2086
1828
|
const MAX_SAMPLES = 32;
|
|
2087
1829
|
const samples = new SampleRing(MAX_SAMPLES);
|
|
2088
1830
|
const axis = isAxisVertical(mode) ? "Y" : "X";
|
|
2089
1831
|
const sign = mode === "bottom" || mode === "right" ? -1 : 1;
|
|
2090
1832
|
const coordOf = (e) => axis === "Y" ? e.clientY : e.clientX;
|
|
1833
|
+
const capture = (pointerId) => {
|
|
1834
|
+
try {
|
|
1835
|
+
handle.setPointerCapture(pointerId);
|
|
1836
|
+
} catch {
|
|
1837
|
+
}
|
|
1838
|
+
};
|
|
1839
|
+
const releaseTracking = () => {
|
|
1840
|
+
activePointerId = null;
|
|
1841
|
+
pendingStart = false;
|
|
1842
|
+
samples.reset();
|
|
1843
|
+
};
|
|
2091
1844
|
const onPointerDown = (e) => {
|
|
2092
1845
|
if (activePointerId !== null) return;
|
|
2093
1846
|
if (e.button !== void 0 && e.button !== 0) return;
|
|
1847
|
+
if (options.shouldStart && !options.shouldStart(e)) return;
|
|
2094
1848
|
activePointerId = e.pointerId;
|
|
2095
1849
|
activePointerType = e.pointerType || "touch";
|
|
2096
1850
|
startCoord = coordOf(e);
|
|
2097
1851
|
lastCoord = startCoord;
|
|
2098
1852
|
samples.reset();
|
|
2099
1853
|
samples.push(e.timeStamp, startCoord);
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
1854
|
+
if (options.deferStart) {
|
|
1855
|
+
pendingStart = true;
|
|
1856
|
+
return;
|
|
2103
1857
|
}
|
|
1858
|
+
capture(e.pointerId);
|
|
2104
1859
|
callbacks.onStart(startCoord, activePointerType);
|
|
2105
1860
|
};
|
|
2106
1861
|
const onPointerMove = (e) => {
|
|
@@ -2108,6 +1863,22 @@ var installGestures = (handle, mode, callbacks) => {
|
|
|
2108
1863
|
const coord = coordOf(e);
|
|
2109
1864
|
const rawDelta = coord - startCoord;
|
|
2110
1865
|
const delta = rawDelta * sign;
|
|
1866
|
+
if (pendingStart) {
|
|
1867
|
+
const verdict = options.deferStart(e, delta);
|
|
1868
|
+
if (verdict === false) {
|
|
1869
|
+
releaseTracking();
|
|
1870
|
+
return;
|
|
1871
|
+
}
|
|
1872
|
+
if (verdict !== true) return;
|
|
1873
|
+
pendingStart = false;
|
|
1874
|
+
startCoord = coord;
|
|
1875
|
+
lastCoord = coord;
|
|
1876
|
+
samples.reset();
|
|
1877
|
+
samples.push(e.timeStamp, coord);
|
|
1878
|
+
capture(e.pointerId);
|
|
1879
|
+
callbacks.onStart(startCoord, activePointerType);
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
2111
1882
|
lastCoord = coord;
|
|
2112
1883
|
samples.push(e.timeStamp, coord);
|
|
2113
1884
|
const cutoff = e.timeStamp - VELOCITY_WINDOW_MS(activePointerType);
|
|
@@ -2116,6 +1887,10 @@ var installGestures = (handle, mode, callbacks) => {
|
|
|
2116
1887
|
};
|
|
2117
1888
|
const finishGesture = (e) => {
|
|
2118
1889
|
if (e.pointerId !== activePointerId) return;
|
|
1890
|
+
if (pendingStart) {
|
|
1891
|
+
releaseTracking();
|
|
1892
|
+
return;
|
|
1893
|
+
}
|
|
2119
1894
|
const rawDelta = lastCoord - startCoord;
|
|
2120
1895
|
const delta = rawDelta * sign;
|
|
2121
1896
|
let velocity = 0;
|
|
@@ -2138,22 +1913,26 @@ var installGestures = (handle, mode, callbacks) => {
|
|
|
2138
1913
|
};
|
|
2139
1914
|
const onPointerCancel = (e) => {
|
|
2140
1915
|
if (e.pointerId !== activePointerId) return;
|
|
2141
|
-
|
|
2142
|
-
|
|
1916
|
+
const wasPending = pendingStart;
|
|
1917
|
+
releaseTracking();
|
|
1918
|
+
if (wasPending) return;
|
|
2143
1919
|
callbacks.onCancel?.();
|
|
2144
1920
|
};
|
|
2145
1921
|
handle.addEventListener("pointerdown", onPointerDown);
|
|
2146
1922
|
handle.addEventListener("pointermove", onPointerMove);
|
|
2147
1923
|
handle.addEventListener("pointerup", finishGesture);
|
|
2148
1924
|
handle.addEventListener("pointercancel", onPointerCancel);
|
|
1925
|
+
const managesTouchAction = options.manageTouchAction !== false;
|
|
2149
1926
|
const prevTouchAction = handle.style.touchAction;
|
|
2150
|
-
|
|
1927
|
+
if (managesTouchAction) {
|
|
1928
|
+
handle.style.touchAction = isAxisVertical(mode) ? "pan-x" : "pan-y";
|
|
1929
|
+
}
|
|
2151
1930
|
return () => {
|
|
2152
1931
|
handle.removeEventListener("pointerdown", onPointerDown);
|
|
2153
1932
|
handle.removeEventListener("pointermove", onPointerMove);
|
|
2154
1933
|
handle.removeEventListener("pointerup", finishGesture);
|
|
2155
1934
|
handle.removeEventListener("pointercancel", onPointerCancel);
|
|
2156
|
-
handle.style.touchAction = prevTouchAction;
|
|
1935
|
+
if (managesTouchAction) handle.style.touchAction = prevTouchAction;
|
|
2157
1936
|
if (activePointerId !== null && handle.hasPointerCapture(activePointerId)) {
|
|
2158
1937
|
handle.releasePointerCapture(activePointerId);
|
|
2159
1938
|
}
|
|
@@ -2272,7 +2051,7 @@ var GestureController = class {
|
|
|
2272
2051
|
const restoreTo = this.dragStartSize;
|
|
2273
2052
|
void this.deps.animateTo(restoreTo, 0);
|
|
2274
2053
|
}
|
|
2275
|
-
});
|
|
2054
|
+
}, this.deps.gestureOptions);
|
|
2276
2055
|
return this.detach;
|
|
2277
2056
|
}
|
|
2278
2057
|
forceClearDragState() {
|
|
@@ -2284,6 +2063,41 @@ var GestureController = class {
|
|
|
2284
2063
|
}
|
|
2285
2064
|
};
|
|
2286
2065
|
|
|
2066
|
+
// src/core/primitives/drag-zones.ts
|
|
2067
|
+
var DRAG_ZONE_SELECTOR = "[data-bs-drag]";
|
|
2068
|
+
var NO_DRAG_SELECTOR = "[data-bs-no-drag]";
|
|
2069
|
+
var asElement = (target) => {
|
|
2070
|
+
const candidate = target;
|
|
2071
|
+
return candidate && typeof candidate.closest === "function" ? candidate : null;
|
|
2072
|
+
};
|
|
2073
|
+
function isDragAllowedFrom(target, mode) {
|
|
2074
|
+
const el = asElement(target);
|
|
2075
|
+
if (!el) return mode !== "zones";
|
|
2076
|
+
if (el.closest(NO_DRAG_SELECTOR)) return false;
|
|
2077
|
+
if (mode === "zones") return el.closest(DRAG_ZONE_SELECTOR) !== null;
|
|
2078
|
+
return true;
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
// src/core/primitives/content-gesture.ts
|
|
2082
|
+
var CONTENT_DRAG_SLOP = 6;
|
|
2083
|
+
function decideContentGesture(input) {
|
|
2084
|
+
const slop = input.slop ?? CONTENT_DRAG_SLOP;
|
|
2085
|
+
if (Math.abs(input.delta) < slop) return "pending";
|
|
2086
|
+
if (input.scrollTop > 0) return "scroll";
|
|
2087
|
+
if (input.delta > 0 && input.atMaxSnap) return "scroll";
|
|
2088
|
+
return "drag";
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
// src/core/primitives/touch-scroll-guard.ts
|
|
2092
|
+
function installTouchScrollGuard(surface, isDragging) {
|
|
2093
|
+
const onTouchMove = (e) => {
|
|
2094
|
+
if (!isDragging()) return;
|
|
2095
|
+
if (e.cancelable) e.preventDefault();
|
|
2096
|
+
};
|
|
2097
|
+
surface.addEventListener("touchmove", onTouchMove, { passive: false });
|
|
2098
|
+
return () => surface.removeEventListener("touchmove", onTouchMove);
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2287
2101
|
// src/core/primitives/aria-slider-writer.ts
|
|
2288
2102
|
var AriaSliderWriter = class {
|
|
2289
2103
|
constructor(handle, mode) {
|
|
@@ -2630,7 +2444,7 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2630
2444
|
const initialAllowed = opts.allowed ?? opts.snapPoints.map((p) => p.id);
|
|
2631
2445
|
let initialId = opts.initial ?? initialAllowed[0] ?? opts.snapPoints[0]?.id ?? "default";
|
|
2632
2446
|
if (opts.persistKey) {
|
|
2633
|
-
const restored =
|
|
2447
|
+
const restored = readPersistedIdSafe(opts.persistKey);
|
|
2634
2448
|
if (restored && initialAllowed.includes(restored)) {
|
|
2635
2449
|
initialId = restored;
|
|
2636
2450
|
}
|
|
@@ -2639,6 +2453,8 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2639
2453
|
mode: opts.mode ?? "bottom",
|
|
2640
2454
|
flickVelocity: opts.flickVelocity ?? DEFAULT_FLICK_VELOCITY,
|
|
2641
2455
|
dragThreshold: opts.dragThreshold ?? DEFAULT_DRAG_THRESHOLD,
|
|
2456
|
+
dragFrom: opts.dragFrom ?? (opts.handle ? "handle" : "sheet"),
|
|
2457
|
+
dragFromContent: opts.dragFromContent ?? true,
|
|
2642
2458
|
rubberBandEnabled: opts.rubberBand ?? true,
|
|
2643
2459
|
closeOnBack: opts.closeOnBack ?? false,
|
|
2644
2460
|
persistent: opts.persistent ?? false,
|
|
@@ -2661,6 +2477,7 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2661
2477
|
},
|
|
2662
2478
|
animation: {
|
|
2663
2479
|
animation: opts.animation,
|
|
2480
|
+
settleAnimation: opts.settleAnimation,
|
|
2664
2481
|
duration: opts.duration,
|
|
2665
2482
|
easing: opts.easing,
|
|
2666
2483
|
spring: opts.spring,
|
|
@@ -2678,6 +2495,15 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2678
2495
|
}
|
|
2679
2496
|
};
|
|
2680
2497
|
}
|
|
2498
|
+
var readPersistedIdSafe = (key) => {
|
|
2499
|
+
if (typeof window === "undefined") return null;
|
|
2500
|
+
if (typeof localStorage === "undefined") return null;
|
|
2501
|
+
try {
|
|
2502
|
+
return localStorage.getItem(key);
|
|
2503
|
+
} catch {
|
|
2504
|
+
return null;
|
|
2505
|
+
}
|
|
2506
|
+
};
|
|
2681
2507
|
|
|
2682
2508
|
// src/core/primitives/teardown-stack.ts
|
|
2683
2509
|
var TeardownStack = class {
|
|
@@ -2700,9 +2526,9 @@ var TeardownStack = class {
|
|
|
2700
2526
|
}
|
|
2701
2527
|
};
|
|
2702
2528
|
|
|
2703
|
-
// src/core/
|
|
2529
|
+
// src/core/BottomSheetCore.ts
|
|
2704
2530
|
var HAPTIC_DURATION_MS = 8;
|
|
2705
|
-
var
|
|
2531
|
+
var BottomSheetCore = class {
|
|
2706
2532
|
constructor(opts) {
|
|
2707
2533
|
__publicField(this, "id", nextInstanceId("bs"));
|
|
2708
2534
|
__publicField(this, "element");
|
|
@@ -2714,6 +2540,8 @@ var BottomSheetEngine = class {
|
|
|
2714
2540
|
__publicField(this, "mode");
|
|
2715
2541
|
__publicField(this, "flickVelocity");
|
|
2716
2542
|
__publicField(this, "dragThreshold");
|
|
2543
|
+
__publicField(this, "dragFromMode");
|
|
2544
|
+
__publicField(this, "dragFromContentDefault");
|
|
2717
2545
|
__publicField(this, "rubberBandEnabled");
|
|
2718
2546
|
__publicField(this, "scrim");
|
|
2719
2547
|
__publicField(this, "aria");
|
|
@@ -2731,8 +2559,11 @@ var BottomSheetEngine = class {
|
|
|
2731
2559
|
__publicField(this, "activeId");
|
|
2732
2560
|
__publicField(this, "size", 0);
|
|
2733
2561
|
__publicField(this, "gesture");
|
|
2562
|
+
__publicField(this, "contentGesture");
|
|
2563
|
+
__publicField(this, "detachSheetGesture", null);
|
|
2734
2564
|
__publicField(this, "rootEl", null);
|
|
2735
2565
|
__publicField(this, "destroyed", false);
|
|
2566
|
+
__publicField(this, "restClosed", false);
|
|
2736
2567
|
__publicField(this, "currentViewTransition", null);
|
|
2737
2568
|
__publicField(this, "currentAbort", new AbortController());
|
|
2738
2569
|
__publicField(this, "sizeWriteSentinel", new WriteSentinel());
|
|
@@ -2763,6 +2594,8 @@ var BottomSheetEngine = class {
|
|
|
2763
2594
|
__publicField(this, "stackEffectPrimed", false);
|
|
2764
2595
|
__publicField(this, "fitDeps");
|
|
2765
2596
|
__publicField(this, "transformTemplate");
|
|
2597
|
+
__publicField(this, "featureList", []);
|
|
2598
|
+
__publicField(this, "featureCtx");
|
|
2766
2599
|
const resolved = resolveEngineOptions(opts, {
|
|
2767
2600
|
shouldApplyInertSiblings: () => {
|
|
2768
2601
|
if (typeof document === "undefined") return false;
|
|
@@ -2783,6 +2616,8 @@ var BottomSheetEngine = class {
|
|
|
2783
2616
|
this.aria = new AriaSliderWriter(this.handle, this.mode);
|
|
2784
2617
|
this.flickVelocity = resolved.flickVelocity;
|
|
2785
2618
|
this.dragThreshold = resolved.dragThreshold;
|
|
2619
|
+
this.dragFromMode = resolved.dragFrom;
|
|
2620
|
+
this.dragFromContentDefault = resolved.dragFromContent;
|
|
2786
2621
|
this.rubberBandEnabled = resolved.rubberBandEnabled;
|
|
2787
2622
|
this.scrim = new ScrimController(
|
|
2788
2623
|
{
|
|
@@ -2809,7 +2644,9 @@ var BottomSheetEngine = class {
|
|
|
2809
2644
|
getRootEl: () => this.rootEl,
|
|
2810
2645
|
applySize: (size) => this.applySize(size),
|
|
2811
2646
|
getSize: () => this.size,
|
|
2812
|
-
isDragging: () => this.
|
|
2647
|
+
isDragging: () => this.isDraggingAny(),
|
|
2648
|
+
applyAux: (size) => this.applySize(size, true),
|
|
2649
|
+
getTransformFor: (size) => this.transformTemplate(this.snaps.getMaxAxisSize() - size)
|
|
2813
2650
|
},
|
|
2814
2651
|
resolved.animation
|
|
2815
2652
|
);
|
|
@@ -2832,6 +2669,11 @@ var BottomSheetEngine = class {
|
|
|
2832
2669
|
if (opts.linkedSheets) {
|
|
2833
2670
|
this.linkedSheets = opts.linkedSheets;
|
|
2834
2671
|
}
|
|
2672
|
+
const byName = /* @__PURE__ */ new Map();
|
|
2673
|
+
for (const feature of opts.features ?? []) {
|
|
2674
|
+
byName.set(feature.name, feature);
|
|
2675
|
+
}
|
|
2676
|
+
this.featureList = Array.from(byName.values());
|
|
2835
2677
|
this.activeId = resolved.initialId;
|
|
2836
2678
|
auditVhUsage(this.snapPointsRaw);
|
|
2837
2679
|
this.auditDuplicateSnapIds(this.snapPointsRaw);
|
|
@@ -2863,11 +2705,13 @@ var BottomSheetEngine = class {
|
|
|
2863
2705
|
const initial = this.snaps.findById(this.activeId);
|
|
2864
2706
|
if (initial) this.size = initial.size;
|
|
2865
2707
|
this.applySize(this.size);
|
|
2708
|
+
this.setRestClosed(this.size === 0);
|
|
2866
2709
|
this.updateAriaSlider();
|
|
2867
2710
|
this.scrollCache = createScrollCache({
|
|
2868
2711
|
scrollContainer: this.scrollContainer,
|
|
2869
2712
|
getMaxAxisSize: () => this.snaps.getMaxAxisSize()
|
|
2870
2713
|
});
|
|
2714
|
+
this.featureCtx = this.buildFeatureContext(opts.autoCollapseAfter);
|
|
2871
2715
|
this.attach();
|
|
2872
2716
|
this.registerInStack();
|
|
2873
2717
|
if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
|
|
@@ -2892,60 +2736,92 @@ var BottomSheetEngine = class {
|
|
|
2892
2736
|
(p) => p.size === "fit" || p.size === "content"
|
|
2893
2737
|
),
|
|
2894
2738
|
isDestroyed: () => this.destroyed,
|
|
2895
|
-
isDragging: () => this.
|
|
2739
|
+
isDragging: () => this.isDraggingAny(),
|
|
2896
2740
|
recompute: () => this.recompute()
|
|
2897
2741
|
})
|
|
2898
2742
|
);
|
|
2899
2743
|
if (resolved.radius !== void 0) this.setRadius(resolved.radius);
|
|
2900
2744
|
if (resolved.maxHeight !== void 0) this.setMaxHeight(resolved.maxHeight);
|
|
2901
2745
|
this.applyAutoAriaLabelledBy();
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
getSize: () => this.size,
|
|
2907
|
-
close: () => this.close()
|
|
2908
|
-
})
|
|
2909
|
-
);
|
|
2910
|
-
}
|
|
2911
|
-
if (this.persistKey) {
|
|
2912
|
-
this.teardowns.add(installPersist(this, this.persistKey));
|
|
2746
|
+
this.runFeatureStage("post");
|
|
2747
|
+
this.warnOrphanFeatureOptions();
|
|
2748
|
+
if (this.size > 0) {
|
|
2749
|
+
this.handleOpen();
|
|
2913
2750
|
}
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
resolveSnap: (id) => this.snaps.findById(id),
|
|
2922
|
-
snapTo: (id) => {
|
|
2923
|
-
void this.snapTo(id);
|
|
2924
|
-
},
|
|
2925
|
-
on: (event, fn) => this.on(event, fn)
|
|
2926
|
-
})
|
|
2927
|
-
);
|
|
2928
|
-
this.teardowns.add(
|
|
2929
|
-
installRoute({
|
|
2751
|
+
}
|
|
2752
|
+
buildFeatureContext(autoCollapseAfter) {
|
|
2753
|
+
return {
|
|
2754
|
+
element: this.element,
|
|
2755
|
+
scrollContainer: this.scrollContainer,
|
|
2756
|
+
sheetId: this.id,
|
|
2757
|
+
options: {
|
|
2930
2758
|
routedTo: this.routedTo,
|
|
2931
2759
|
closeOnBack: this.closeOnBack,
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
this.
|
|
2760
|
+
closeOnRouteChange: this.closeOnRouteChange,
|
|
2761
|
+
persistKey: this.persistKey,
|
|
2762
|
+
autoCollapseAfter
|
|
2763
|
+
},
|
|
2764
|
+
isDestroyed: () => this.destroyed,
|
|
2765
|
+
isDragging: () => this.isDraggingAny(),
|
|
2766
|
+
isAnimating: () => this.animation.isAnimating,
|
|
2767
|
+
isTopSheet: () => this.isTopSheet,
|
|
2768
|
+
isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
|
|
2769
|
+
getSize: () => this.size,
|
|
2770
|
+
getActiveId: () => this.activeId,
|
|
2771
|
+
getAllowedIds: () => this.snaps.getAllowedIds().slice(),
|
|
2772
|
+
allowedIdsBySize: () => this.allowedIdsBySize(),
|
|
2773
|
+
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
2774
|
+
resolveSnap: (id) => this.snaps.findById(id),
|
|
2775
|
+
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
2776
|
+
setSize: (size) => {
|
|
2777
|
+
this.size = size;
|
|
2778
|
+
},
|
|
2779
|
+
setMaxAxisSize: (size) => {
|
|
2780
|
+
this.snaps.setMaxAxisSize(size);
|
|
2781
|
+
},
|
|
2782
|
+
applySize: (size) => this.applySize(size),
|
|
2783
|
+
recomputeSnaps: () => this.recomputeSnaps(),
|
|
2784
|
+
newCycle: () => {
|
|
2785
|
+
this.newCycle();
|
|
2786
|
+
},
|
|
2787
|
+
cancelInFlight: () => {
|
|
2788
|
+
this.animation.cancel();
|
|
2789
|
+
},
|
|
2790
|
+
resyncAfterResize: () => this.resyncAfterResize(),
|
|
2791
|
+
snapTo: (id) => {
|
|
2792
|
+
void this.snapTo(id);
|
|
2793
|
+
},
|
|
2794
|
+
close: (reason) => this.close(reason),
|
|
2795
|
+
attachDragSurface: (surface, kind) => this.attachDragSurface(surface, kind),
|
|
2796
|
+
on: (event, fn) => this.on(event, fn),
|
|
2797
|
+
addTeardown: (fn) => this.teardowns.add(fn)
|
|
2798
|
+
};
|
|
2799
|
+
}
|
|
2800
|
+
runFeatureStage(stage) {
|
|
2801
|
+
for (const feature of this.featureList) {
|
|
2802
|
+
if ((feature.stage ?? "post") !== stage) continue;
|
|
2803
|
+
const teardown = feature.install(this.featureCtx);
|
|
2804
|
+
if (teardown) this.teardowns.add(teardown);
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
warnOrphanFeatureOptions() {
|
|
2808
|
+
const names = new Set(this.featureList.map((f) => f.name));
|
|
2809
|
+
if ((this.closeOnBack || this.routedTo !== void 0 || this.closeOnRouteChange) && !names.has("route")) {
|
|
2810
|
+
devWarn(
|
|
2811
|
+
"[BottomSheet] closeOnBack/routedTo/closeOnRouteChange need routeFeature() \u2014 option ignored"
|
|
2812
|
+
);
|
|
2813
|
+
}
|
|
2814
|
+
if (this.persistKey && !names.has("persist")) {
|
|
2815
|
+
devWarn(
|
|
2816
|
+
"[BottomSheet] persistKey needs persistFeature() \u2014 snaps will not be saved"
|
|
2817
|
+
);
|
|
2942
2818
|
}
|
|
2943
2819
|
}
|
|
2944
2820
|
get state() {
|
|
2945
2821
|
return {
|
|
2946
2822
|
size: this.size,
|
|
2947
2823
|
activeId: this.activeId,
|
|
2948
|
-
isDragging: this.
|
|
2824
|
+
isDragging: this.isDraggingAny(),
|
|
2949
2825
|
isAnimating: this.animation.isAnimating,
|
|
2950
2826
|
progress: this.computeProgress(this.size)
|
|
2951
2827
|
};
|
|
@@ -3065,9 +2941,16 @@ var BottomSheetEngine = class {
|
|
|
3065
2941
|
progress: this.computeProgress(this.size)
|
|
3066
2942
|
});
|
|
3067
2943
|
if (withHaptic) this.haptic();
|
|
2944
|
+
this.setRestClosed(targetSize === 0);
|
|
3068
2945
|
if (wasClosed && targetSize > 0) this.emitOpenSequence(id);
|
|
3069
2946
|
if (targetSize === 0) this.emitCloseSequence();
|
|
3070
2947
|
}
|
|
2948
|
+
setRestClosed(closed) {
|
|
2949
|
+
if (closed === this.restClosed) return;
|
|
2950
|
+
this.restClosed = closed;
|
|
2951
|
+
if (closed) this.element.setAttribute("data-bs-rest", "closed");
|
|
2952
|
+
else this.element.removeAttribute("data-bs-rest");
|
|
2953
|
+
}
|
|
3071
2954
|
emitOpenSequence(id) {
|
|
3072
2955
|
this.emit("open", { id });
|
|
3073
2956
|
this.handleOpen();
|
|
@@ -3123,6 +3006,20 @@ var BottomSheetEngine = class {
|
|
|
3123
3006
|
if (this.destroyed) return;
|
|
3124
3007
|
this.disableDragFlag = value;
|
|
3125
3008
|
}
|
|
3009
|
+
setDragFromContent(value) {
|
|
3010
|
+
if (this.destroyed) return;
|
|
3011
|
+
this.dragFromContentDefault = value;
|
|
3012
|
+
}
|
|
3013
|
+
setDragFrom(mode) {
|
|
3014
|
+
if (this.destroyed || mode === this.dragFromMode) return;
|
|
3015
|
+
this.gesture?.forceClearDragState();
|
|
3016
|
+
this.detachSheetGesture?.();
|
|
3017
|
+
this.dragFromMode = mode;
|
|
3018
|
+
this.mountSheetGesture();
|
|
3019
|
+
}
|
|
3020
|
+
getDragFrom() {
|
|
3021
|
+
return this.dragFromMode;
|
|
3022
|
+
}
|
|
3126
3023
|
isTop() {
|
|
3127
3024
|
return this.isTopSheet;
|
|
3128
3025
|
}
|
|
@@ -3277,12 +3174,24 @@ var BottomSheetEngine = class {
|
|
|
3277
3174
|
auditVhUsage(points);
|
|
3278
3175
|
this.auditDuplicateSnapIds(points);
|
|
3279
3176
|
this.snaps.setRaw(points);
|
|
3280
|
-
if (allowed)
|
|
3177
|
+
if (allowed) {
|
|
3178
|
+
this.snaps.setAllowedIds(allowed);
|
|
3179
|
+
} else {
|
|
3180
|
+
const present = this.snaps.getResolvedSnaps().map((s) => s.id);
|
|
3181
|
+
const kept = this.snaps.getAllowedIds().filter((id) => present.includes(id));
|
|
3182
|
+
this.snaps.setAllowedIds(kept.length ? kept : present);
|
|
3183
|
+
}
|
|
3281
3184
|
this.scrollCache.clear();
|
|
3282
3185
|
this.scrim.invalidateOpacityCache();
|
|
3283
3186
|
const current = this.snaps.findById(this.activeId);
|
|
3284
3187
|
if (current) {
|
|
3285
3188
|
this.applySize(current.size);
|
|
3189
|
+
} else {
|
|
3190
|
+
const fallback = this.snaps.getResolvedSnaps().find((s) => this.snaps.getAllowedIds().includes(s.id)) ?? this.snaps.getResolvedSnaps()[0];
|
|
3191
|
+
if (fallback) {
|
|
3192
|
+
this.activeId = fallback.id;
|
|
3193
|
+
this.applySize(fallback.size);
|
|
3194
|
+
}
|
|
3286
3195
|
}
|
|
3287
3196
|
this.updateAriaSlider();
|
|
3288
3197
|
}
|
|
@@ -3292,7 +3201,7 @@ var BottomSheetEngine = class {
|
|
|
3292
3201
|
this.snaps.recompute();
|
|
3293
3202
|
this.maxHeight.clampTo();
|
|
3294
3203
|
this.scrim.invalidateOpacityCache();
|
|
3295
|
-
if (this.
|
|
3204
|
+
if (this.isDraggingAny()) return;
|
|
3296
3205
|
this.healActiveSnap();
|
|
3297
3206
|
}
|
|
3298
3207
|
healActiveSnap() {
|
|
@@ -3314,6 +3223,8 @@ var BottomSheetEngine = class {
|
|
|
3314
3223
|
this.bus.clear();
|
|
3315
3224
|
this.animation.cancel();
|
|
3316
3225
|
this.gesture?.forceClearDragState();
|
|
3226
|
+
this.contentGesture?.forceClearDragState();
|
|
3227
|
+
this.setRestClosed(false);
|
|
3317
3228
|
this.teardowns.drain();
|
|
3318
3229
|
this.scrim.destroy();
|
|
3319
3230
|
this.animation.destroy();
|
|
@@ -3426,11 +3337,12 @@ var BottomSheetEngine = class {
|
|
|
3426
3337
|
const scale = Math.max(1 - depth * 0.04, 0.86);
|
|
3427
3338
|
this.element.style.scale = scale === 1 ? "" : String(scale);
|
|
3428
3339
|
}
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
handle:
|
|
3340
|
+
buildGestureDeps(surface, gestureOptions) {
|
|
3341
|
+
return {
|
|
3342
|
+
handle: surface,
|
|
3432
3343
|
element: this.element,
|
|
3433
3344
|
mode: this.mode,
|
|
3345
|
+
gestureOptions,
|
|
3434
3346
|
getRoot: () => this.rootEl,
|
|
3435
3347
|
getDragContext: () => {
|
|
3436
3348
|
const buf = this.dragContextBuf;
|
|
@@ -3449,8 +3361,88 @@ var BottomSheetEngine = class {
|
|
|
3449
3361
|
settleAfterDrag: (delta, velocity, kind) => this.settleAfterDrag(delta, velocity, kind),
|
|
3450
3362
|
emit: (event, payload) => this.emit(event, payload),
|
|
3451
3363
|
listenerCount: (event) => this.bus.listenerCount(event)
|
|
3364
|
+
};
|
|
3365
|
+
}
|
|
3366
|
+
isContentDragAllowed() {
|
|
3367
|
+
if (this.disableDragFlag) return false;
|
|
3368
|
+
const point = this.snapPointsRaw.find((p) => p.id === this.activeId);
|
|
3369
|
+
return point?.dragFromContent ?? this.dragFromContentDefault;
|
|
3370
|
+
}
|
|
3371
|
+
decideContentDrag(surface, e, delta) {
|
|
3372
|
+
if (this.destroyed) return false;
|
|
3373
|
+
if (e.pointerType === "mouse") return false;
|
|
3374
|
+
if (this.gesture?.isDragging) return false;
|
|
3375
|
+
if (!this.isContentDragAllowed()) return false;
|
|
3376
|
+
if (!isDragAllowedFrom(e.target, "sheet")) return false;
|
|
3377
|
+
const decision = decideContentGesture({
|
|
3378
|
+
delta,
|
|
3379
|
+
scrollTop: surface.scrollTop,
|
|
3380
|
+
atMaxSnap: this.size >= this.getAllowedRange().max - 0.5
|
|
3381
|
+
});
|
|
3382
|
+
if (decision === "pending") return null;
|
|
3383
|
+
return decision === "drag";
|
|
3384
|
+
}
|
|
3385
|
+
attachDragSurface(surface, kind) {
|
|
3386
|
+
if (this.destroyed || kind !== "content") return;
|
|
3387
|
+
if (this.contentGesture) return;
|
|
3388
|
+
const controller = new GestureController(
|
|
3389
|
+
this.buildGestureDeps(surface, {
|
|
3390
|
+
manageTouchAction: false,
|
|
3391
|
+
deferStart: (e, delta) => this.decideContentDrag(surface, e, delta)
|
|
3392
|
+
})
|
|
3393
|
+
);
|
|
3394
|
+
this.contentGesture = controller;
|
|
3395
|
+
const detachGestures = controller.install();
|
|
3396
|
+
const detachGuard = installTouchScrollGuard(
|
|
3397
|
+
surface,
|
|
3398
|
+
() => controller.isDragging
|
|
3399
|
+
);
|
|
3400
|
+
return () => {
|
|
3401
|
+
detachGuard();
|
|
3402
|
+
detachGestures();
|
|
3403
|
+
if (this.contentGesture === controller) this.contentGesture = void 0;
|
|
3404
|
+
};
|
|
3405
|
+
}
|
|
3406
|
+
sheetDragSurface() {
|
|
3407
|
+
return this.dragFromMode === "handle" ? this.handle : this.element;
|
|
3408
|
+
}
|
|
3409
|
+
canStartSheetDrag(e) {
|
|
3410
|
+
if (this.contentGesture?.isDragging) return false;
|
|
3411
|
+
const target = e.target;
|
|
3412
|
+
const scoped = typeof target?.closest === "function";
|
|
3413
|
+
if (scoped && target.closest(NO_DRAG_SELECTOR)) return false;
|
|
3414
|
+
if (this.handle !== this.element && scoped && this.handle.contains(target)) {
|
|
3415
|
+
return true;
|
|
3416
|
+
}
|
|
3417
|
+
if (!isDragAllowedFrom(e.target, this.dragFromMode)) return false;
|
|
3418
|
+
if (this.dragFromMode === "handle") return true;
|
|
3419
|
+
if (this.scrollContainer && scoped && this.scrollContainer.contains(target) && !target.closest(DRAG_ZONE_SELECTOR)) {
|
|
3420
|
+
return false;
|
|
3421
|
+
}
|
|
3422
|
+
return true;
|
|
3423
|
+
}
|
|
3424
|
+
mountSheetGesture() {
|
|
3425
|
+
const surface = this.sheetDragSurface();
|
|
3426
|
+
const controller = new GestureController(
|
|
3427
|
+
this.buildGestureDeps(surface, {
|
|
3428
|
+
shouldStart: (e) => this.canStartSheetDrag(e),
|
|
3429
|
+
manageTouchAction: this.dragFromMode === "handle"
|
|
3430
|
+
})
|
|
3431
|
+
);
|
|
3432
|
+
this.gesture = controller;
|
|
3433
|
+
const detachGestures = controller.install();
|
|
3434
|
+
const detachGuard = this.dragFromMode === "handle" ? null : installTouchScrollGuard(surface, () => controller.isDragging);
|
|
3435
|
+
this.detachSheetGesture = () => {
|
|
3436
|
+
detachGuard?.();
|
|
3437
|
+
detachGestures();
|
|
3438
|
+
};
|
|
3439
|
+
}
|
|
3440
|
+
attach() {
|
|
3441
|
+
this.mountSheetGesture();
|
|
3442
|
+
this.teardowns.add(() => {
|
|
3443
|
+
this.detachSheetGesture?.();
|
|
3444
|
+
this.detachSheetGesture = null;
|
|
3452
3445
|
});
|
|
3453
|
-
this.teardowns.add(this.gesture.install());
|
|
3454
3446
|
try {
|
|
3455
3447
|
this.attachFeatures();
|
|
3456
3448
|
} catch (err) {
|
|
@@ -3481,24 +3473,13 @@ var BottomSheetEngine = class {
|
|
|
3481
3473
|
}
|
|
3482
3474
|
}
|
|
3483
3475
|
attachFeatures() {
|
|
3484
|
-
|
|
3485
|
-
this.teardowns.add(installContentSwipe({
|
|
3486
|
-
container: this.scrollContainer,
|
|
3487
|
-
isDragging: () => this.gesture?.isDragging ?? false,
|
|
3488
|
-
isAnimating: () => this.animation.isAnimating,
|
|
3489
|
-
getAllowedIds: () => this.allowedIdsBySize(),
|
|
3490
|
-
getActiveId: () => this.activeId,
|
|
3491
|
-
snapTo: (id) => {
|
|
3492
|
-
void this.snapTo(id);
|
|
3493
|
-
}
|
|
3494
|
-
}));
|
|
3495
|
-
}
|
|
3476
|
+
this.runFeatureStage("attach");
|
|
3496
3477
|
if (typeof window !== "undefined") {
|
|
3497
3478
|
this.teardowns.add(installResizeObserver({
|
|
3498
3479
|
element: this.element,
|
|
3499
3480
|
getMode: () => this.mode,
|
|
3500
3481
|
isDestroyed: () => this.destroyed,
|
|
3501
|
-
isDragging: () => this.
|
|
3482
|
+
isDragging: () => this.isDraggingAny(),
|
|
3502
3483
|
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
3503
3484
|
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
3504
3485
|
getSize: () => this.size,
|
|
@@ -3532,31 +3513,6 @@ var BottomSheetEngine = class {
|
|
|
3532
3513
|
() => document.removeEventListener("keydown", onKey)
|
|
3533
3514
|
);
|
|
3534
3515
|
}
|
|
3535
|
-
this.teardowns.add(installVisualViewport({
|
|
3536
|
-
element: this.element,
|
|
3537
|
-
isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
|
|
3538
|
-
isDestroyed: () => this.destroyed,
|
|
3539
|
-
isDragging: () => this.gesture?.isDragging ?? false,
|
|
3540
|
-
recomputeSnaps: () => this.recomputeSnaps(),
|
|
3541
|
-
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
3542
|
-
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
3543
|
-
getSize: () => this.size,
|
|
3544
|
-
setMaxAxisSize: (size) => {
|
|
3545
|
-
this.snaps.setMaxAxisSize(size);
|
|
3546
|
-
},
|
|
3547
|
-
setSize: (size) => {
|
|
3548
|
-
this.size = size;
|
|
3549
|
-
},
|
|
3550
|
-
applySize: (size) => this.applySize(size),
|
|
3551
|
-
cancelInFlight: () => {
|
|
3552
|
-
this.animation.cancel();
|
|
3553
|
-
},
|
|
3554
|
-
newCycle: () => {
|
|
3555
|
-
this.newCycle();
|
|
3556
|
-
},
|
|
3557
|
-
isAnimating: () => this.animation.isAnimating,
|
|
3558
|
-
resyncAfterCancel: () => this.resyncAfterResize()
|
|
3559
|
-
}));
|
|
3560
3516
|
}
|
|
3561
3517
|
this.teardowns.add(installSliderKeyboard({
|
|
3562
3518
|
handle: this.handle,
|
|
@@ -3621,8 +3577,11 @@ var BottomSheetEngine = class {
|
|
|
3621
3577
|
);
|
|
3622
3578
|
});
|
|
3623
3579
|
}
|
|
3580
|
+
isDraggingAny() {
|
|
3581
|
+
return (this.gesture?.isDragging ?? false) || (this.contentGesture?.isDragging ?? false);
|
|
3582
|
+
}
|
|
3624
3583
|
clearWillChangeIfIdle() {
|
|
3625
|
-
if (this.animation.isAnimating || this.
|
|
3584
|
+
if (this.animation.isAnimating || this.isDraggingAny()) return;
|
|
3626
3585
|
this.element.style.willChange = "";
|
|
3627
3586
|
}
|
|
3628
3587
|
haptic() {
|
|
@@ -3633,13 +3592,14 @@ var BottomSheetEngine = class {
|
|
|
3633
3592
|
}
|
|
3634
3593
|
}
|
|
3635
3594
|
}
|
|
3636
|
-
applySize(size) {
|
|
3595
|
+
applySize(size, skipTransform = false) {
|
|
3637
3596
|
const cap = this.snaps.getMaxAxisSize();
|
|
3638
|
-
const clamped = cap > 0 && size > cap && !this.
|
|
3597
|
+
const clamped = cap > 0 && size > cap && !this.isDraggingAny() && !this.allowOvershoot ? cap : size;
|
|
3639
3598
|
this.size = clamped;
|
|
3599
|
+
if (clamped > 0) this.setRestClosed(false);
|
|
3640
3600
|
const offset = cap - clamped;
|
|
3641
3601
|
const style = this.element.style;
|
|
3642
|
-
style.transform = this.transformTemplate(offset);
|
|
3602
|
+
if (!skipTransform) style.transform = this.transformTemplate(offset);
|
|
3643
3603
|
if (this.sizeWriteSentinel.shouldWrite(clamped, SIZE_WRITE_EPSILON)) {
|
|
3644
3604
|
style.setProperty("--bs-size", `${clamped}px`);
|
|
3645
3605
|
if (this.scrimParent) {
|
|
@@ -3717,6 +3677,470 @@ var BottomSheetEngine = class {
|
|
|
3717
3677
|
}
|
|
3718
3678
|
};
|
|
3719
3679
|
|
|
3680
|
+
// src/core/features/history-coordinator.ts
|
|
3681
|
+
var entries = [];
|
|
3682
|
+
var subscribers = /* @__PURE__ */ new Set();
|
|
3683
|
+
var suppress = 0;
|
|
3684
|
+
var internalDepth = 0;
|
|
3685
|
+
var pendingRebrands = [];
|
|
3686
|
+
var listenerInstalled = false;
|
|
3687
|
+
var patchInstalled = false;
|
|
3688
|
+
var origPushState = null;
|
|
3689
|
+
var origReplaceState = null;
|
|
3690
|
+
var patchedPushState = null;
|
|
3691
|
+
var patchedReplaceState = null;
|
|
3692
|
+
var hasWindow = () => typeof window !== "undefined";
|
|
3693
|
+
var hasHistory = () => typeof history !== "undefined";
|
|
3694
|
+
var brandMarker = (surface) => ({
|
|
3695
|
+
...surface.markerState(),
|
|
3696
|
+
__bs: true
|
|
3697
|
+
});
|
|
3698
|
+
var runInternal = (fn) => {
|
|
3699
|
+
internalDepth += 1;
|
|
3700
|
+
try {
|
|
3701
|
+
fn();
|
|
3702
|
+
} finally {
|
|
3703
|
+
internalDepth -= 1;
|
|
3704
|
+
}
|
|
3705
|
+
};
|
|
3706
|
+
var notifyRouteChange = () => {
|
|
3707
|
+
const snapshot = Array.from(subscribers);
|
|
3708
|
+
for (const fn of snapshot) fn();
|
|
3709
|
+
};
|
|
3710
|
+
var ensureListener = () => {
|
|
3711
|
+
if (listenerInstalled || !hasWindow()) return;
|
|
3712
|
+
window.addEventListener("popstate", onPopState);
|
|
3713
|
+
listenerInstalled = true;
|
|
3714
|
+
};
|
|
3715
|
+
var maybeTeardownListener = () => {
|
|
3716
|
+
if (!listenerInstalled) return;
|
|
3717
|
+
if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
|
|
3718
|
+
if (hasWindow()) window.removeEventListener("popstate", onPopState);
|
|
3719
|
+
listenerInstalled = false;
|
|
3720
|
+
};
|
|
3721
|
+
var installPatch = () => {
|
|
3722
|
+
if (patchInstalled || !hasHistory()) return;
|
|
3723
|
+
origPushState = history.pushState;
|
|
3724
|
+
origReplaceState = history.replaceState;
|
|
3725
|
+
patchedPushState = function(...args) {
|
|
3726
|
+
origPushState.apply(this, args);
|
|
3727
|
+
if (internalDepth === 0) notifyRouteChange();
|
|
3728
|
+
};
|
|
3729
|
+
patchedReplaceState = function(...args) {
|
|
3730
|
+
origReplaceState.apply(this, args);
|
|
3731
|
+
if (internalDepth === 0) notifyRouteChange();
|
|
3732
|
+
};
|
|
3733
|
+
history.pushState = patchedPushState;
|
|
3734
|
+
history.replaceState = patchedReplaceState;
|
|
3735
|
+
patchInstalled = true;
|
|
3736
|
+
};
|
|
3737
|
+
var removePatch = () => {
|
|
3738
|
+
if (!patchInstalled) return;
|
|
3739
|
+
if (history.pushState === patchedPushState && origPushState) {
|
|
3740
|
+
history.pushState = origPushState;
|
|
3741
|
+
}
|
|
3742
|
+
if (history.replaceState === patchedReplaceState && origReplaceState) {
|
|
3743
|
+
history.replaceState = origReplaceState;
|
|
3744
|
+
}
|
|
3745
|
+
origPushState = null;
|
|
3746
|
+
origReplaceState = null;
|
|
3747
|
+
patchedPushState = null;
|
|
3748
|
+
patchedReplaceState = null;
|
|
3749
|
+
patchInstalled = false;
|
|
3750
|
+
};
|
|
3751
|
+
function onPopState() {
|
|
3752
|
+
if (suppress > 0) {
|
|
3753
|
+
suppress -= 1;
|
|
3754
|
+
const rebrand = pendingRebrands.shift();
|
|
3755
|
+
if (rebrand) rebrand();
|
|
3756
|
+
maybeTeardownListener();
|
|
3757
|
+
return;
|
|
3758
|
+
}
|
|
3759
|
+
if (entries.length === 0) {
|
|
3760
|
+
notifyRouteChange();
|
|
3761
|
+
maybeTeardownListener();
|
|
3762
|
+
return;
|
|
3763
|
+
}
|
|
3764
|
+
let target = null;
|
|
3765
|
+
let targetIdx = -1;
|
|
3766
|
+
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
3767
|
+
const entry = entries[i];
|
|
3768
|
+
if (!entry.surface.isOpen()) continue;
|
|
3769
|
+
if (!target) {
|
|
3770
|
+
target = entry;
|
|
3771
|
+
targetIdx = i;
|
|
3772
|
+
}
|
|
3773
|
+
if (entry.surface.isTop()) {
|
|
3774
|
+
target = entry;
|
|
3775
|
+
targetIdx = i;
|
|
3776
|
+
break;
|
|
3777
|
+
}
|
|
3778
|
+
}
|
|
3779
|
+
if (!target) {
|
|
3780
|
+
const removed = entries.pop();
|
|
3781
|
+
if (removed) removed.live = false;
|
|
3782
|
+
maybeTeardownListener();
|
|
3783
|
+
return;
|
|
3784
|
+
}
|
|
3785
|
+
target.live = false;
|
|
3786
|
+
entries.splice(targetIdx, 1);
|
|
3787
|
+
const settled = target;
|
|
3788
|
+
void Promise.resolve(settled.surface.close()).then(() => {
|
|
3789
|
+
if (settled.surface.isOpen()) restore(settled);
|
|
3790
|
+
});
|
|
3791
|
+
maybeTeardownListener();
|
|
3792
|
+
}
|
|
3793
|
+
function restore(entry) {
|
|
3794
|
+
if (!hasWindow() || !hasHistory()) return;
|
|
3795
|
+
entry.live = true;
|
|
3796
|
+
runInternal(() => {
|
|
3797
|
+
try {
|
|
3798
|
+
history.pushState(brandMarker(entry.surface), "", entry.surface.url);
|
|
3799
|
+
} catch {
|
|
3800
|
+
entry.live = false;
|
|
3801
|
+
}
|
|
3802
|
+
});
|
|
3803
|
+
if (entry.live) {
|
|
3804
|
+
entries.push(entry);
|
|
3805
|
+
ensureListener();
|
|
3806
|
+
}
|
|
3807
|
+
}
|
|
3808
|
+
function pushBackMarker(surface) {
|
|
3809
|
+
const entry = { surface, priorUrl: void 0, live: false };
|
|
3810
|
+
if (!hasWindow() || !hasHistory()) {
|
|
3811
|
+
return entry;
|
|
3812
|
+
}
|
|
3813
|
+
entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
|
|
3814
|
+
runInternal(() => {
|
|
3815
|
+
try {
|
|
3816
|
+
history.pushState(brandMarker(surface), "", surface.url);
|
|
3817
|
+
entry.live = true;
|
|
3818
|
+
} catch {
|
|
3819
|
+
entry.live = false;
|
|
3820
|
+
}
|
|
3821
|
+
});
|
|
3822
|
+
if (entry.live) {
|
|
3823
|
+
entries.push(entry);
|
|
3824
|
+
ensureListener();
|
|
3825
|
+
}
|
|
3826
|
+
return entry;
|
|
3827
|
+
}
|
|
3828
|
+
function popBackMarker(handle) {
|
|
3829
|
+
if (!hasWindow() || !hasHistory()) return;
|
|
3830
|
+
const entry = handle;
|
|
3831
|
+
const idx = entries.indexOf(entry);
|
|
3832
|
+
if (idx === -1 || !entry.live) return;
|
|
3833
|
+
const last = entries.length - 1;
|
|
3834
|
+
entry.live = false;
|
|
3835
|
+
entries.splice(idx, 1);
|
|
3836
|
+
let rebrand = null;
|
|
3837
|
+
if (idx !== last) {
|
|
3838
|
+
const rebrandSurface = entries[entries.length - 1].surface;
|
|
3839
|
+
const rebrandUrl = entry.priorUrl;
|
|
3840
|
+
rebrand = () => {
|
|
3841
|
+
runInternal(() => {
|
|
3842
|
+
history.replaceState(
|
|
3843
|
+
brandMarker(rebrandSurface),
|
|
3844
|
+
"",
|
|
3845
|
+
rebrandUrl !== void 0 ? rebrandUrl : location.href
|
|
3846
|
+
);
|
|
3847
|
+
});
|
|
3848
|
+
};
|
|
3849
|
+
}
|
|
3850
|
+
pendingRebrands.push(rebrand);
|
|
3851
|
+
suppress += 1;
|
|
3852
|
+
runInternal(() => {
|
|
3853
|
+
try {
|
|
3854
|
+
history.back();
|
|
3855
|
+
} catch {
|
|
3856
|
+
suppress = Math.max(0, suppress - 1);
|
|
3857
|
+
pendingRebrands.pop();
|
|
3858
|
+
}
|
|
3859
|
+
});
|
|
3860
|
+
maybeTeardownListener();
|
|
3861
|
+
}
|
|
3862
|
+
function subscribeRouteChange(fn) {
|
|
3863
|
+
if (!hasWindow() || !hasHistory()) return () => {
|
|
3864
|
+
};
|
|
3865
|
+
subscribers.add(fn);
|
|
3866
|
+
if (subscribers.size === 1) installPatch();
|
|
3867
|
+
ensureListener();
|
|
3868
|
+
return () => {
|
|
3869
|
+
if (!subscribers.has(fn)) return;
|
|
3870
|
+
subscribers.delete(fn);
|
|
3871
|
+
if (subscribers.size === 0) removePatch();
|
|
3872
|
+
maybeTeardownListener();
|
|
3873
|
+
};
|
|
3874
|
+
}
|
|
3875
|
+
|
|
3876
|
+
// src/core/features/route.ts
|
|
3877
|
+
function installRoute(deps) {
|
|
3878
|
+
if (typeof window === "undefined") {
|
|
3879
|
+
return () => {
|
|
3880
|
+
};
|
|
3881
|
+
}
|
|
3882
|
+
if (!deps.routedTo && !deps.closeOnBack) {
|
|
3883
|
+
return () => {
|
|
3884
|
+
};
|
|
3885
|
+
}
|
|
3886
|
+
let handle = null;
|
|
3887
|
+
const onOpen = () => {
|
|
3888
|
+
if (handle) return;
|
|
3889
|
+
handle = pushBackMarker({
|
|
3890
|
+
isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
|
|
3891
|
+
isTop: deps.isTopSheet,
|
|
3892
|
+
close: deps.close,
|
|
3893
|
+
markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
|
|
3894
|
+
url: deps.routedTo
|
|
3895
|
+
});
|
|
3896
|
+
};
|
|
3897
|
+
const onClose = () => {
|
|
3898
|
+
if (!handle) return;
|
|
3899
|
+
popBackMarker(handle);
|
|
3900
|
+
handle = null;
|
|
3901
|
+
};
|
|
3902
|
+
const unsubscribeOpen = deps.on("open", onOpen);
|
|
3903
|
+
const unsubscribeClose = deps.on("close", onClose);
|
|
3904
|
+
if (deps.getSize() > 0) onOpen();
|
|
3905
|
+
return () => {
|
|
3906
|
+
unsubscribeOpen();
|
|
3907
|
+
unsubscribeClose();
|
|
3908
|
+
if (handle) {
|
|
3909
|
+
popBackMarker(handle);
|
|
3910
|
+
handle = null;
|
|
3911
|
+
}
|
|
3912
|
+
};
|
|
3913
|
+
}
|
|
3914
|
+
function installRouteChange(deps) {
|
|
3915
|
+
return subscribeRouteChange(() => {
|
|
3916
|
+
if (deps.isDestroyed() || deps.getSize() <= 0) return;
|
|
3917
|
+
void deps.close();
|
|
3918
|
+
});
|
|
3919
|
+
}
|
|
3920
|
+
|
|
3921
|
+
// src/core/features/persist.ts
|
|
3922
|
+
function installPersist(engine, key) {
|
|
3923
|
+
const unsubscribe = engine.on("snap", ({ id }) => {
|
|
3924
|
+
if (typeof window === "undefined") return;
|
|
3925
|
+
if (typeof localStorage === "undefined") return;
|
|
3926
|
+
try {
|
|
3927
|
+
localStorage.setItem(key, id);
|
|
3928
|
+
} catch {
|
|
3929
|
+
}
|
|
3930
|
+
});
|
|
3931
|
+
return unsubscribe;
|
|
3932
|
+
}
|
|
3933
|
+
|
|
3934
|
+
// src/core/features/auto-collapse.ts
|
|
3935
|
+
function installAutoCollapse(deps) {
|
|
3936
|
+
const { ms } = deps;
|
|
3937
|
+
if (ms === void 0 || ms <= 0) {
|
|
3938
|
+
return () => {
|
|
3939
|
+
};
|
|
3940
|
+
}
|
|
3941
|
+
let timer = null;
|
|
3942
|
+
const clearTimer = () => {
|
|
3943
|
+
if (timer !== null) {
|
|
3944
|
+
clearTimeout(timer);
|
|
3945
|
+
timer = null;
|
|
3946
|
+
}
|
|
3947
|
+
};
|
|
3948
|
+
const fire = () => {
|
|
3949
|
+
if (deps.isDestroyed()) return;
|
|
3950
|
+
if (deps.isDragging()) return;
|
|
3951
|
+
const active = deps.resolveSnap(deps.getActiveId());
|
|
3952
|
+
if (!active || active.size === 0) return;
|
|
3953
|
+
let target = null;
|
|
3954
|
+
for (const id of deps.getAllowedIds()) {
|
|
3955
|
+
const snap = deps.resolveSnap(id);
|
|
3956
|
+
if (!snap || snap.size <= 0) continue;
|
|
3957
|
+
if (!target || snap.size < target.size) target = snap;
|
|
3958
|
+
}
|
|
3959
|
+
if (!target) return;
|
|
3960
|
+
if (target.id === active.id || target.size >= active.size) return;
|
|
3961
|
+
deps.snapTo(target.id);
|
|
3962
|
+
};
|
|
3963
|
+
const reset = () => {
|
|
3964
|
+
clearTimer();
|
|
3965
|
+
if (deps.isDestroyed()) return;
|
|
3966
|
+
timer = setTimeout(() => {
|
|
3967
|
+
timer = null;
|
|
3968
|
+
fire();
|
|
3969
|
+
}, ms);
|
|
3970
|
+
};
|
|
3971
|
+
const unsubscribe = deps.on("snap", () => reset());
|
|
3972
|
+
if ((deps.resolveSnap(deps.getActiveId())?.size ?? 0) > 0) reset();
|
|
3973
|
+
return () => {
|
|
3974
|
+
clearTimer();
|
|
3975
|
+
unsubscribe();
|
|
3976
|
+
};
|
|
3977
|
+
}
|
|
3978
|
+
|
|
3979
|
+
// src/core/features/content-drag.ts
|
|
3980
|
+
function installContentDrag(deps) {
|
|
3981
|
+
const detach = deps.attachDragSurface(deps.container, "content");
|
|
3982
|
+
return () => detach?.();
|
|
3983
|
+
}
|
|
3984
|
+
|
|
3985
|
+
// src/core/features/visual-viewport.ts
|
|
3986
|
+
var SAFETY_PAD = 8;
|
|
3987
|
+
function installVisualViewport(deps) {
|
|
3988
|
+
if (typeof window === "undefined" || !window.visualViewport) {
|
|
3989
|
+
return () => {
|
|
3990
|
+
};
|
|
3991
|
+
}
|
|
3992
|
+
const vv = window.visualViewport;
|
|
3993
|
+
let rafId = null;
|
|
3994
|
+
const onResize = () => {
|
|
3995
|
+
if (rafId !== null) return;
|
|
3996
|
+
rafId = requestAnimationFrame(() => {
|
|
3997
|
+
rafId = null;
|
|
3998
|
+
if (deps.isDestroyed()) return;
|
|
3999
|
+
deps.recomputeSnaps();
|
|
4000
|
+
const isVertical = deps.isVerticalAxis();
|
|
4001
|
+
const visible = isVertical ? vv.height : vv.width;
|
|
4002
|
+
const windowSize = isVertical ? window.innerHeight : window.innerWidth;
|
|
4003
|
+
const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
|
|
4004
|
+
if (clamp < deps.getMaxAxisSize()) {
|
|
4005
|
+
deps.setMaxAxisSize(clamp);
|
|
4006
|
+
}
|
|
4007
|
+
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
4008
|
+
deps.cancelInFlight();
|
|
4009
|
+
deps.newCycle();
|
|
4010
|
+
const max = deps.getMaxAxisSize();
|
|
4011
|
+
deps.setSize(Math.min(deps.getSize(), max));
|
|
4012
|
+
const current = deps.resolveActiveSnap();
|
|
4013
|
+
if (current && !deps.isDragging()) {
|
|
4014
|
+
deps.applySize(Math.min(current.size, max));
|
|
4015
|
+
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
4016
|
+
} else {
|
|
4017
|
+
deps.applySize(deps.getSize());
|
|
4018
|
+
}
|
|
4019
|
+
});
|
|
4020
|
+
};
|
|
4021
|
+
vv.addEventListener("resize", onResize);
|
|
4022
|
+
return () => {
|
|
4023
|
+
vv.removeEventListener("resize", onResize);
|
|
4024
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
4025
|
+
};
|
|
4026
|
+
}
|
|
4027
|
+
|
|
4028
|
+
// src/core/features/engine-features.ts
|
|
4029
|
+
function routeFeature() {
|
|
4030
|
+
return {
|
|
4031
|
+
name: "route",
|
|
4032
|
+
install: (ctx) => {
|
|
4033
|
+
const teardowns = new TeardownStack();
|
|
4034
|
+
if (ctx.options.closeOnRouteChange) {
|
|
4035
|
+
teardowns.add(
|
|
4036
|
+
installRouteChange({
|
|
4037
|
+
isDestroyed: ctx.isDestroyed,
|
|
4038
|
+
getSize: ctx.getSize,
|
|
4039
|
+
close: () => ctx.close()
|
|
4040
|
+
})
|
|
4041
|
+
);
|
|
4042
|
+
}
|
|
4043
|
+
teardowns.add(
|
|
4044
|
+
installRoute({
|
|
4045
|
+
routedTo: ctx.options.routedTo,
|
|
4046
|
+
closeOnBack: ctx.options.closeOnBack,
|
|
4047
|
+
isTopSheet: ctx.isTopSheet,
|
|
4048
|
+
getSize: ctx.getSize,
|
|
4049
|
+
isDestroyed: ctx.isDestroyed,
|
|
4050
|
+
close: () => ctx.close("back"),
|
|
4051
|
+
on: ctx.on,
|
|
4052
|
+
sheetId: ctx.sheetId
|
|
4053
|
+
})
|
|
4054
|
+
);
|
|
4055
|
+
return () => teardowns.drain();
|
|
4056
|
+
}
|
|
4057
|
+
};
|
|
4058
|
+
}
|
|
4059
|
+
function persistFeature() {
|
|
4060
|
+
return {
|
|
4061
|
+
name: "persist",
|
|
4062
|
+
install: (ctx) => {
|
|
4063
|
+
const key = ctx.options.persistKey;
|
|
4064
|
+
if (!key) return;
|
|
4065
|
+
return installPersist({ on: ctx.on }, key);
|
|
4066
|
+
}
|
|
4067
|
+
};
|
|
4068
|
+
}
|
|
4069
|
+
function autoCollapseFeature() {
|
|
4070
|
+
return {
|
|
4071
|
+
name: "auto-collapse",
|
|
4072
|
+
install: (ctx) => installAutoCollapse({
|
|
4073
|
+
ms: ctx.options.autoCollapseAfter,
|
|
4074
|
+
isDestroyed: ctx.isDestroyed,
|
|
4075
|
+
isDragging: ctx.isDragging,
|
|
4076
|
+
getAllowedIds: ctx.getAllowedIds,
|
|
4077
|
+
getActiveId: ctx.getActiveId,
|
|
4078
|
+
resolveSnap: ctx.resolveSnap,
|
|
4079
|
+
snapTo: ctx.snapTo,
|
|
4080
|
+
on: ctx.on
|
|
4081
|
+
})
|
|
4082
|
+
};
|
|
4083
|
+
}
|
|
4084
|
+
function contentSwipeFeature() {
|
|
4085
|
+
return {
|
|
4086
|
+
name: "content-swipe",
|
|
4087
|
+
stage: "attach",
|
|
4088
|
+
install: (ctx) => {
|
|
4089
|
+
if (!ctx.scrollContainer) return;
|
|
4090
|
+
return installContentDrag({
|
|
4091
|
+
container: ctx.scrollContainer,
|
|
4092
|
+
attachDragSurface: ctx.attachDragSurface
|
|
4093
|
+
});
|
|
4094
|
+
}
|
|
4095
|
+
};
|
|
4096
|
+
}
|
|
4097
|
+
function visualViewportFeature() {
|
|
4098
|
+
return {
|
|
4099
|
+
name: "visual-viewport",
|
|
4100
|
+
install: (ctx) => {
|
|
4101
|
+
if (typeof window === "undefined") return;
|
|
4102
|
+
return installVisualViewport({
|
|
4103
|
+
element: ctx.element,
|
|
4104
|
+
isVerticalAxis: ctx.isVerticalAxis,
|
|
4105
|
+
isDestroyed: ctx.isDestroyed,
|
|
4106
|
+
isDragging: ctx.isDragging,
|
|
4107
|
+
recomputeSnaps: ctx.recomputeSnaps,
|
|
4108
|
+
resolveActiveSnap: ctx.resolveActiveSnap,
|
|
4109
|
+
getMaxAxisSize: ctx.getMaxAxisSize,
|
|
4110
|
+
getSize: ctx.getSize,
|
|
4111
|
+
setMaxAxisSize: ctx.setMaxAxisSize,
|
|
4112
|
+
setSize: ctx.setSize,
|
|
4113
|
+
applySize: ctx.applySize,
|
|
4114
|
+
cancelInFlight: ctx.cancelInFlight,
|
|
4115
|
+
newCycle: ctx.newCycle,
|
|
4116
|
+
isAnimating: ctx.isAnimating,
|
|
4117
|
+
resyncAfterCancel: ctx.resyncAfterResize
|
|
4118
|
+
});
|
|
4119
|
+
}
|
|
4120
|
+
};
|
|
4121
|
+
}
|
|
4122
|
+
|
|
4123
|
+
// src/core/default-features.ts
|
|
4124
|
+
function defaultEngineFeatures() {
|
|
4125
|
+
return [
|
|
4126
|
+
contentSwipeFeature(),
|
|
4127
|
+
visualViewportFeature(),
|
|
4128
|
+
persistFeature(),
|
|
4129
|
+
autoCollapseFeature(),
|
|
4130
|
+
routeFeature()
|
|
4131
|
+
];
|
|
4132
|
+
}
|
|
4133
|
+
|
|
4134
|
+
// src/core/BottomSheetEngine.ts
|
|
4135
|
+
var BottomSheetEngine = class extends BottomSheetCore {
|
|
4136
|
+
constructor(opts) {
|
|
4137
|
+
super({
|
|
4138
|
+
...opts,
|
|
4139
|
+
features: [...defaultEngineFeatures(), ...opts.features ?? []]
|
|
4140
|
+
});
|
|
4141
|
+
}
|
|
4142
|
+
};
|
|
4143
|
+
|
|
3720
4144
|
// src/core/features/teleport.ts
|
|
3721
4145
|
var resolveTeleportTarget = (target) => {
|
|
3722
4146
|
if (!target) return null;
|