@surdeddd/bottom-sheet 0.11.0 → 0.13.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 +68 -1
- package/dist/{BottomSheetEngine-DzsIwD28.d.cts → BottomSheetCore-CsIjyq7C.d.cts} +61 -5
- package/dist/{BottomSheetEngine-DRjCU73e.d.ts → BottomSheetCore-D16lsa6g.d.ts} +61 -5
- package/dist/BottomSheetEngine-BYjAVrmd.d.cts +7 -0
- package/dist/BottomSheetEngine-YuCNugZn.d.ts +7 -0
- package/dist/core.cjs +3476 -0
- package/dist/core.d.cts +3 -0
- package/dist/core.d.ts +3 -0
- package/dist/core.js +3474 -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 +994 -697
- 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 +994 -697
- package/dist/features.cjs +533 -0
- package/dist/features.d.cts +13 -0
- package/dist/features.d.ts +13 -0
- package/dist/features.js +526 -0
- package/dist/index-DdYLOIIT.d.ts +15 -0
- package/dist/index-dfrzw-lI.d.cts +15 -0
- package/dist/index.cjs +823 -542
- package/dist/index.d.cts +6 -15
- package/dist/index.d.ts +6 -15
- package/dist/index.js +817 -543
- 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 +13 -8
- package/dist/overlay.js +13 -8
- package/dist/preact.d.cts +2 -1
- package/dist/preact.d.ts +2 -1
- package/dist/qwik-lib/index.qwik.cjs +4267 -0
- package/dist/qwik-lib/index.qwik.mjs +4267 -0
- package/dist/qwik.cjs +816 -542
- package/dist/qwik.d.cts +2 -2
- package/dist/qwik.d.ts +2 -2
- package/dist/qwik.js +816 -542
- package/dist/react.cjs +816 -542
- package/dist/react.d.cts +3 -2
- package/dist/react.d.ts +3 -2
- package/dist/react.js +816 -542
- package/dist/solid.cjs +816 -542
- package/dist/solid.d.cts +64 -4
- package/dist/solid.d.ts +64 -4
- package/dist/solid.js +816 -542
- package/dist/solid.source.jsx +816 -542
- package/dist/svelte-core.cjs +816 -542
- package/dist/svelte-core.js +816 -542
- package/dist/svelte.cjs +816 -542
- package/dist/svelte.js +816 -542
- package/dist/vue.cjs +927 -645
- package/dist/vue.js +927 -645
- package/package.json +63 -11
package/dist/svelte.cjs
CHANGED
|
@@ -372,74 +372,6 @@ var SnapResolver = class {
|
|
|
372
372
|
}
|
|
373
373
|
};
|
|
374
374
|
|
|
375
|
-
// src/core/features/persist.ts
|
|
376
|
-
function readPersistedId(key) {
|
|
377
|
-
if (!key) return null;
|
|
378
|
-
if (typeof window === "undefined") return null;
|
|
379
|
-
if (typeof localStorage === "undefined") return null;
|
|
380
|
-
try {
|
|
381
|
-
return localStorage.getItem(key);
|
|
382
|
-
} catch {
|
|
383
|
-
return null;
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
function installPersist(engine, key) {
|
|
387
|
-
const unsubscribe = engine.on("snap", ({ id }) => {
|
|
388
|
-
if (typeof window === "undefined") return;
|
|
389
|
-
if (typeof localStorage === "undefined") return;
|
|
390
|
-
try {
|
|
391
|
-
localStorage.setItem(key, id);
|
|
392
|
-
} catch {
|
|
393
|
-
}
|
|
394
|
-
});
|
|
395
|
-
return unsubscribe;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
// src/core/features/auto-collapse.ts
|
|
399
|
-
function installAutoCollapse(deps) {
|
|
400
|
-
const { ms } = deps;
|
|
401
|
-
if (ms === void 0 || ms <= 0) {
|
|
402
|
-
return () => {
|
|
403
|
-
};
|
|
404
|
-
}
|
|
405
|
-
let timer = null;
|
|
406
|
-
const clearTimer = () => {
|
|
407
|
-
if (timer !== null) {
|
|
408
|
-
clearTimeout(timer);
|
|
409
|
-
timer = null;
|
|
410
|
-
}
|
|
411
|
-
};
|
|
412
|
-
const fire = () => {
|
|
413
|
-
if (deps.isDestroyed()) return;
|
|
414
|
-
if (deps.isDragging()) return;
|
|
415
|
-
const active = deps.resolveSnap(deps.getActiveId());
|
|
416
|
-
if (!active || active.size === 0) return;
|
|
417
|
-
let target = null;
|
|
418
|
-
for (const id of deps.getAllowedIds()) {
|
|
419
|
-
const snap = deps.resolveSnap(id);
|
|
420
|
-
if (!snap || snap.size <= 0) continue;
|
|
421
|
-
if (!target || snap.size < target.size) target = snap;
|
|
422
|
-
}
|
|
423
|
-
if (!target) return;
|
|
424
|
-
if (target.id === active.id || target.size >= active.size) return;
|
|
425
|
-
deps.snapTo(target.id);
|
|
426
|
-
};
|
|
427
|
-
const reset2 = () => {
|
|
428
|
-
clearTimer();
|
|
429
|
-
if (deps.isDestroyed()) return;
|
|
430
|
-
timer = setTimeout(() => {
|
|
431
|
-
timer = null;
|
|
432
|
-
fire();
|
|
433
|
-
}, ms);
|
|
434
|
-
};
|
|
435
|
-
const unsubscribe = deps.on("snap", () => reset2());
|
|
436
|
-
if ((deps.resolveSnap(deps.getActiveId())?.size ?? 0) > 0) reset2();
|
|
437
|
-
return () => {
|
|
438
|
-
clearTimer();
|
|
439
|
-
unsubscribe();
|
|
440
|
-
};
|
|
441
|
-
}
|
|
442
|
-
|
|
443
375
|
// src/core/features/linked-sheets.ts
|
|
444
376
|
function notifyLinkedSheets(sheets, self) {
|
|
445
377
|
if (sheets.length === 0) return;
|
|
@@ -462,390 +394,65 @@ function notifyLinkedSheets(sheets, self) {
|
|
|
462
394
|
}
|
|
463
395
|
}
|
|
464
396
|
|
|
465
|
-
// src/core/features/
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
var pendingRebrand = null;
|
|
471
|
-
var listenerInstalled = false;
|
|
472
|
-
var patchInstalled = false;
|
|
473
|
-
var origPushState = null;
|
|
474
|
-
var origReplaceState = null;
|
|
475
|
-
var patchedPushState = null;
|
|
476
|
-
var patchedReplaceState = null;
|
|
477
|
-
var hasWindow = () => typeof window !== "undefined";
|
|
478
|
-
var hasHistory = () => typeof history !== "undefined";
|
|
479
|
-
var runInternal = (fn) => {
|
|
480
|
-
internalDepth += 1;
|
|
481
|
-
try {
|
|
482
|
-
fn();
|
|
483
|
-
} finally {
|
|
484
|
-
internalDepth -= 1;
|
|
485
|
-
}
|
|
486
|
-
};
|
|
487
|
-
var notifyRouteChange = () => {
|
|
488
|
-
const snapshot = Array.from(subscribers);
|
|
489
|
-
for (const fn of snapshot) fn();
|
|
490
|
-
};
|
|
491
|
-
var ensureListener = () => {
|
|
492
|
-
if (listenerInstalled || !hasWindow()) return;
|
|
493
|
-
window.addEventListener("popstate", onPopState);
|
|
494
|
-
listenerInstalled = true;
|
|
495
|
-
};
|
|
496
|
-
var maybeTeardownListener = () => {
|
|
497
|
-
if (!listenerInstalled) return;
|
|
498
|
-
if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
|
|
499
|
-
if (hasWindow()) window.removeEventListener("popstate", onPopState);
|
|
500
|
-
listenerInstalled = false;
|
|
501
|
-
};
|
|
502
|
-
var installPatch = () => {
|
|
503
|
-
if (patchInstalled || !hasHistory()) return;
|
|
504
|
-
origPushState = history.pushState;
|
|
505
|
-
origReplaceState = history.replaceState;
|
|
506
|
-
patchedPushState = function(...args) {
|
|
507
|
-
origPushState.apply(this, args);
|
|
508
|
-
if (internalDepth === 0) notifyRouteChange();
|
|
509
|
-
};
|
|
510
|
-
patchedReplaceState = function(...args) {
|
|
511
|
-
origReplaceState.apply(this, args);
|
|
512
|
-
if (internalDepth === 0) notifyRouteChange();
|
|
513
|
-
};
|
|
514
|
-
history.pushState = patchedPushState;
|
|
515
|
-
history.replaceState = patchedReplaceState;
|
|
516
|
-
patchInstalled = true;
|
|
517
|
-
};
|
|
518
|
-
var removePatch = () => {
|
|
519
|
-
if (!patchInstalled) return;
|
|
520
|
-
if (history.pushState === patchedPushState && origPushState) {
|
|
521
|
-
history.pushState = origPushState;
|
|
522
|
-
}
|
|
523
|
-
if (history.replaceState === patchedReplaceState && origReplaceState) {
|
|
524
|
-
history.replaceState = origReplaceState;
|
|
525
|
-
}
|
|
526
|
-
origPushState = null;
|
|
527
|
-
origReplaceState = null;
|
|
528
|
-
patchedPushState = null;
|
|
529
|
-
patchedReplaceState = null;
|
|
530
|
-
patchInstalled = false;
|
|
531
|
-
};
|
|
532
|
-
function onPopState() {
|
|
533
|
-
if (suppress > 0) {
|
|
534
|
-
suppress -= 1;
|
|
535
|
-
const rebrand = pendingRebrand;
|
|
536
|
-
pendingRebrand = null;
|
|
537
|
-
if (rebrand) rebrand();
|
|
538
|
-
maybeTeardownListener();
|
|
539
|
-
return;
|
|
540
|
-
}
|
|
541
|
-
if (entries.length === 0) {
|
|
542
|
-
notifyRouteChange();
|
|
543
|
-
maybeTeardownListener();
|
|
544
|
-
return;
|
|
397
|
+
// src/core/features/resize-observer.ts
|
|
398
|
+
function installResizeObserver(deps) {
|
|
399
|
+
if (typeof window === "undefined") {
|
|
400
|
+
return () => {
|
|
401
|
+
};
|
|
545
402
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
const
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
if (entry.surface.isTop()) {
|
|
556
|
-
target = entry;
|
|
557
|
-
targetIdx = i;
|
|
558
|
-
break;
|
|
403
|
+
const onResize = () => {
|
|
404
|
+
if (deps.isDestroyed()) return;
|
|
405
|
+
deps.recomputeSnaps();
|
|
406
|
+
const mode = deps.getMode();
|
|
407
|
+
const isVerticalAxis = mode === "bottom" || mode === "top";
|
|
408
|
+
const viewportSize2 = isVerticalAxis ? window.innerHeight : window.innerWidth;
|
|
409
|
+
const max = deps.getMaxAxisSize();
|
|
410
|
+
if (viewportSize2 > 0 && viewportSize2 < max) {
|
|
411
|
+
deps.setMaxAxisSize(viewportSize2);
|
|
559
412
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
void Promise.resolve(settled.surface.close()).then(() => {
|
|
571
|
-
if (settled.surface.isOpen()) restore(settled);
|
|
572
|
-
});
|
|
573
|
-
maybeTeardownListener();
|
|
574
|
-
}
|
|
575
|
-
function restore(entry) {
|
|
576
|
-
if (!hasWindow() || !hasHistory()) return;
|
|
577
|
-
entry.live = true;
|
|
578
|
-
runInternal(() => {
|
|
579
|
-
try {
|
|
580
|
-
history.pushState(entry.surface.markerState(), "", entry.surface.url);
|
|
581
|
-
} catch {
|
|
582
|
-
entry.live = false;
|
|
413
|
+
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
414
|
+
deps.cancelInFlight();
|
|
415
|
+
deps.newCycle();
|
|
416
|
+
const current = deps.resolveActiveSnap();
|
|
417
|
+
const newMax = deps.getMaxAxisSize();
|
|
418
|
+
const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
|
|
419
|
+
deps.setSize(targetSize);
|
|
420
|
+
if (current && !deps.isDragging()) {
|
|
421
|
+
deps.applySize(targetSize);
|
|
422
|
+
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
583
423
|
}
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
424
|
+
};
|
|
425
|
+
let resizeObserver = null;
|
|
426
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
427
|
+
resizeObserver = new ResizeObserver(onResize);
|
|
428
|
+
resizeObserver.observe(document.documentElement);
|
|
429
|
+
} else {
|
|
430
|
+
window.addEventListener("resize", onResize);
|
|
588
431
|
}
|
|
432
|
+
window.addEventListener("orientationchange", onResize);
|
|
433
|
+
const onVisibility = () => {
|
|
434
|
+
if (deps.isDestroyed()) return;
|
|
435
|
+
if (document.hidden) deps.cancelInFlight();
|
|
436
|
+
};
|
|
437
|
+
document.addEventListener("visibilitychange", onVisibility);
|
|
438
|
+
return () => {
|
|
439
|
+
resizeObserver?.disconnect();
|
|
440
|
+
window.removeEventListener("resize", onResize);
|
|
441
|
+
window.removeEventListener("orientationchange", onResize);
|
|
442
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
443
|
+
};
|
|
589
444
|
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
entry.live = false;
|
|
602
|
-
}
|
|
603
|
-
});
|
|
604
|
-
if (entry.live) {
|
|
605
|
-
entries.push(entry);
|
|
606
|
-
ensureListener();
|
|
607
|
-
}
|
|
608
|
-
return entry;
|
|
609
|
-
}
|
|
610
|
-
function popBackMarker(handle) {
|
|
611
|
-
if (!hasWindow() || !hasHistory()) return;
|
|
612
|
-
const entry = handle;
|
|
613
|
-
const idx = entries.indexOf(entry);
|
|
614
|
-
if (idx === -1 || !entry.live) return;
|
|
615
|
-
const last = entries.length - 1;
|
|
616
|
-
entry.live = false;
|
|
617
|
-
entries.splice(idx, 1);
|
|
618
|
-
if (idx !== last) {
|
|
619
|
-
const rebrandSurface = entries[entries.length - 1].surface;
|
|
620
|
-
const rebrandUrl = entry.priorUrl;
|
|
621
|
-
pendingRebrand = () => {
|
|
622
|
-
runInternal(() => {
|
|
623
|
-
history.replaceState(
|
|
624
|
-
rebrandSurface.markerState(),
|
|
625
|
-
"",
|
|
626
|
-
rebrandUrl !== void 0 ? rebrandUrl : location.href
|
|
627
|
-
);
|
|
628
|
-
});
|
|
629
|
-
};
|
|
630
|
-
}
|
|
631
|
-
suppress += 1;
|
|
632
|
-
runInternal(() => {
|
|
633
|
-
try {
|
|
634
|
-
history.back();
|
|
635
|
-
} catch {
|
|
636
|
-
suppress = Math.max(0, suppress - 1);
|
|
637
|
-
pendingRebrand = null;
|
|
638
|
-
}
|
|
639
|
-
});
|
|
640
|
-
maybeTeardownListener();
|
|
641
|
-
}
|
|
642
|
-
function subscribeRouteChange(fn) {
|
|
643
|
-
if (!hasWindow() || !hasHistory()) return () => {
|
|
644
|
-
};
|
|
645
|
-
subscribers.add(fn);
|
|
646
|
-
if (subscribers.size === 1) installPatch();
|
|
647
|
-
ensureListener();
|
|
648
|
-
return () => {
|
|
649
|
-
if (!subscribers.has(fn)) return;
|
|
650
|
-
subscribers.delete(fn);
|
|
651
|
-
if (subscribers.size === 0) removePatch();
|
|
652
|
-
maybeTeardownListener();
|
|
653
|
-
};
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
// src/core/features/route.ts
|
|
657
|
-
function installRoute(deps) {
|
|
658
|
-
if (typeof window === "undefined") {
|
|
659
|
-
return () => {
|
|
660
|
-
};
|
|
661
|
-
}
|
|
662
|
-
if (!deps.routedTo && !deps.closeOnBack) {
|
|
663
|
-
return () => {
|
|
664
|
-
};
|
|
665
|
-
}
|
|
666
|
-
let handle = null;
|
|
667
|
-
const onOpen = () => {
|
|
668
|
-
if (handle) return;
|
|
669
|
-
handle = pushBackMarker({
|
|
670
|
-
isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
|
|
671
|
-
isTop: deps.isTopSheet,
|
|
672
|
-
close: deps.close,
|
|
673
|
-
markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
|
|
674
|
-
url: deps.routedTo
|
|
675
|
-
});
|
|
676
|
-
};
|
|
677
|
-
const onClose = () => {
|
|
678
|
-
if (!handle) return;
|
|
679
|
-
popBackMarker(handle);
|
|
680
|
-
handle = null;
|
|
681
|
-
};
|
|
682
|
-
const unsubscribeOpen = deps.on("open", onOpen);
|
|
683
|
-
const unsubscribeClose = deps.on("close", onClose);
|
|
684
|
-
if (deps.getSize() > 0) onOpen();
|
|
685
|
-
return () => {
|
|
686
|
-
unsubscribeOpen();
|
|
687
|
-
unsubscribeClose();
|
|
688
|
-
if (handle) {
|
|
689
|
-
popBackMarker(handle);
|
|
690
|
-
handle = null;
|
|
691
|
-
}
|
|
692
|
-
};
|
|
693
|
-
}
|
|
694
|
-
function installRouteChange(deps) {
|
|
695
|
-
return subscribeRouteChange(() => {
|
|
696
|
-
if (deps.isDestroyed() || deps.getSize() <= 0) return;
|
|
697
|
-
void deps.close();
|
|
698
|
-
});
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
// src/core/features/content-swipe.ts
|
|
702
|
-
var CONTENT_PULL_THRESHOLD = 60;
|
|
703
|
-
function installContentSwipe(deps) {
|
|
704
|
-
const { container } = deps;
|
|
705
|
-
let startY = 0;
|
|
706
|
-
let startScrollTop = 0;
|
|
707
|
-
let moved = false;
|
|
708
|
-
const onTouchStart = (e) => {
|
|
709
|
-
const t = e.touches[0];
|
|
710
|
-
if (!t) return;
|
|
711
|
-
startY = t.clientY;
|
|
712
|
-
startScrollTop = container.scrollTop;
|
|
713
|
-
moved = false;
|
|
714
|
-
};
|
|
715
|
-
const onTouchMove = (e) => {
|
|
716
|
-
const t = e.touches[0];
|
|
717
|
-
if (!t) return;
|
|
718
|
-
if (Math.abs(t.clientY - startY) > CONTENT_PULL_THRESHOLD) moved = true;
|
|
719
|
-
};
|
|
720
|
-
const onTouchEnd = (e) => {
|
|
721
|
-
if (!moved) return;
|
|
722
|
-
if (deps.isDragging() || deps.isAnimating()) return;
|
|
723
|
-
if (container.scrollTop !== startScrollTop) return;
|
|
724
|
-
const t = e.changedTouches[0];
|
|
725
|
-
if (!t) return;
|
|
726
|
-
const deltaY = t.clientY - startY;
|
|
727
|
-
const atTop = container.scrollTop <= 0;
|
|
728
|
-
const allowed = deps.getAllowedIds();
|
|
729
|
-
const idx = allowed.indexOf(deps.getActiveId());
|
|
730
|
-
if (idx === -1) return;
|
|
731
|
-
if (atTop && deltaY > CONTENT_PULL_THRESHOLD && idx > 0) {
|
|
732
|
-
deps.snapTo(allowed[idx - 1]);
|
|
733
|
-
} else if (deltaY < -CONTENT_PULL_THRESHOLD && idx < allowed.length - 1) {
|
|
734
|
-
deps.snapTo(allowed[idx + 1]);
|
|
735
|
-
}
|
|
736
|
-
};
|
|
737
|
-
container.addEventListener("touchstart", onTouchStart, { passive: true });
|
|
738
|
-
container.addEventListener("touchmove", onTouchMove, { passive: true });
|
|
739
|
-
container.addEventListener("touchend", onTouchEnd, { passive: true });
|
|
740
|
-
return () => {
|
|
741
|
-
container.removeEventListener("touchstart", onTouchStart);
|
|
742
|
-
container.removeEventListener("touchmove", onTouchMove);
|
|
743
|
-
container.removeEventListener("touchend", onTouchEnd);
|
|
744
|
-
};
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
// src/core/features/visual-viewport.ts
|
|
748
|
-
var SAFETY_PAD = 8;
|
|
749
|
-
function installVisualViewport(deps) {
|
|
750
|
-
if (typeof window === "undefined" || !window.visualViewport) {
|
|
751
|
-
return () => {
|
|
752
|
-
};
|
|
753
|
-
}
|
|
754
|
-
const vv = window.visualViewport;
|
|
755
|
-
let rafId = null;
|
|
756
|
-
const onResize = () => {
|
|
757
|
-
if (rafId !== null) return;
|
|
758
|
-
rafId = requestAnimationFrame(() => {
|
|
759
|
-
rafId = null;
|
|
760
|
-
if (deps.isDestroyed()) return;
|
|
761
|
-
deps.recomputeSnaps();
|
|
762
|
-
const isVertical = deps.isVerticalAxis();
|
|
763
|
-
const visible = isVertical ? vv.height : vv.width;
|
|
764
|
-
const windowSize = isVertical ? window.innerHeight : window.innerWidth;
|
|
765
|
-
const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
|
|
766
|
-
if (clamp < deps.getMaxAxisSize()) {
|
|
767
|
-
deps.setMaxAxisSize(clamp);
|
|
768
|
-
}
|
|
769
|
-
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
770
|
-
deps.cancelInFlight();
|
|
771
|
-
deps.newCycle();
|
|
772
|
-
const max = deps.getMaxAxisSize();
|
|
773
|
-
deps.setSize(Math.min(deps.getSize(), max));
|
|
774
|
-
const current = deps.resolveActiveSnap();
|
|
775
|
-
if (current && !deps.isDragging()) {
|
|
776
|
-
deps.applySize(Math.min(current.size, max));
|
|
777
|
-
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
778
|
-
} else {
|
|
779
|
-
deps.applySize(deps.getSize());
|
|
780
|
-
}
|
|
781
|
-
});
|
|
782
|
-
};
|
|
783
|
-
vv.addEventListener("resize", onResize);
|
|
784
|
-
return () => {
|
|
785
|
-
vv.removeEventListener("resize", onResize);
|
|
786
|
-
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
787
|
-
};
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
// src/core/features/resize-observer.ts
|
|
791
|
-
function installResizeObserver(deps) {
|
|
792
|
-
if (typeof window === "undefined") {
|
|
793
|
-
return () => {
|
|
794
|
-
};
|
|
795
|
-
}
|
|
796
|
-
const onResize = () => {
|
|
797
|
-
if (deps.isDestroyed()) return;
|
|
798
|
-
deps.recomputeSnaps();
|
|
799
|
-
const mode = deps.getMode();
|
|
800
|
-
const isVerticalAxis = mode === "bottom" || mode === "top";
|
|
801
|
-
const viewportSize2 = isVerticalAxis ? window.innerHeight : window.innerWidth;
|
|
802
|
-
const max = deps.getMaxAxisSize();
|
|
803
|
-
if (viewportSize2 > 0 && viewportSize2 < max) {
|
|
804
|
-
deps.setMaxAxisSize(viewportSize2);
|
|
805
|
-
}
|
|
806
|
-
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
807
|
-
deps.cancelInFlight();
|
|
808
|
-
deps.newCycle();
|
|
809
|
-
const current = deps.resolveActiveSnap();
|
|
810
|
-
const newMax = deps.getMaxAxisSize();
|
|
811
|
-
const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
|
|
812
|
-
deps.setSize(targetSize);
|
|
813
|
-
if (current && !deps.isDragging()) {
|
|
814
|
-
deps.applySize(targetSize);
|
|
815
|
-
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
816
|
-
}
|
|
817
|
-
};
|
|
818
|
-
let resizeObserver = null;
|
|
819
|
-
if (typeof ResizeObserver !== "undefined") {
|
|
820
|
-
resizeObserver = new ResizeObserver(onResize);
|
|
821
|
-
resizeObserver.observe(document.documentElement);
|
|
822
|
-
} else {
|
|
823
|
-
window.addEventListener("resize", onResize);
|
|
824
|
-
}
|
|
825
|
-
window.addEventListener("orientationchange", onResize);
|
|
826
|
-
const onVisibility = () => {
|
|
827
|
-
if (deps.isDestroyed()) return;
|
|
828
|
-
if (document.hidden) deps.cancelInFlight();
|
|
829
|
-
};
|
|
830
|
-
document.addEventListener("visibilitychange", onVisibility);
|
|
831
|
-
return () => {
|
|
832
|
-
resizeObserver?.disconnect();
|
|
833
|
-
window.removeEventListener("resize", onResize);
|
|
834
|
-
window.removeEventListener("orientationchange", onResize);
|
|
835
|
-
document.removeEventListener("visibilitychange", onVisibility);
|
|
836
|
-
};
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
// src/core/features/fit-observer.ts
|
|
840
|
-
var contentTargets = (scroller) => {
|
|
841
|
-
if (!scroller) return [];
|
|
842
|
-
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
843
|
-
const out = [];
|
|
844
|
-
for (const child2 of Array.from(scroller.children)) {
|
|
845
|
-
if (hasSlot && child2 instanceof HTMLSlotElement) {
|
|
846
|
-
for (const el of child2.assignedElements()) out.push(el);
|
|
847
|
-
} else {
|
|
848
|
-
out.push(child2);
|
|
445
|
+
|
|
446
|
+
// src/core/features/fit-observer.ts
|
|
447
|
+
var contentTargets = (scroller) => {
|
|
448
|
+
if (!scroller) return [];
|
|
449
|
+
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
450
|
+
const out = [];
|
|
451
|
+
for (const child2 of Array.from(scroller.children)) {
|
|
452
|
+
if (hasSlot && child2 instanceof HTMLSlotElement) {
|
|
453
|
+
for (const el of child2.assignedElements()) out.push(el);
|
|
454
|
+
} else {
|
|
455
|
+
out.push(child2);
|
|
849
456
|
}
|
|
850
457
|
}
|
|
851
458
|
return out;
|
|
@@ -965,11 +572,15 @@ function createMaxHeightController(deps) {
|
|
|
965
572
|
|
|
966
573
|
// src/core/features/fit-measurement.ts
|
|
967
574
|
var measureSheetNatural = (element, content, vertical) => {
|
|
968
|
-
if (!content) {
|
|
969
|
-
return vertical ? element.offsetHeight : element.offsetWidth;
|
|
970
|
-
}
|
|
971
575
|
const axis = vertical ? "height" : "width";
|
|
972
576
|
const sheetStyle = element.style;
|
|
577
|
+
if (!content) {
|
|
578
|
+
const prev = sheetStyle[axis];
|
|
579
|
+
sheetStyle[axis] = "auto";
|
|
580
|
+
const poked2 = vertical ? element.offsetHeight : element.offsetWidth;
|
|
581
|
+
sheetStyle[axis] = prev;
|
|
582
|
+
return poked2;
|
|
583
|
+
}
|
|
973
584
|
const cs = content.style;
|
|
974
585
|
const prevSheet = sheetStyle[axis];
|
|
975
586
|
const prevFlex = cs.flex;
|
|
@@ -1683,6 +1294,52 @@ function resolveAnimationPreset(animation) {
|
|
|
1683
1294
|
}
|
|
1684
1295
|
}
|
|
1685
1296
|
|
|
1297
|
+
// src/core/animation/waapi-settle.ts
|
|
1298
|
+
var SIM_HZ = 240;
|
|
1299
|
+
var SAMPLE_STRIDE = 4;
|
|
1300
|
+
var MAX_SIM_MS = 3e3;
|
|
1301
|
+
function sampleSpringSettle(from, to, velocityPxPerS, config) {
|
|
1302
|
+
const cfg = { ...DEFAULT_SPRING, ...config };
|
|
1303
|
+
const subDt = 1 / SIM_HZ;
|
|
1304
|
+
const stepMs = SAMPLE_STRIDE / SIM_HZ * 1e3;
|
|
1305
|
+
const maxSteps = Math.ceil(MAX_SIM_MS / 1e3 * SIM_HZ);
|
|
1306
|
+
const values = [from];
|
|
1307
|
+
let x = from;
|
|
1308
|
+
let v = velocityPxPerS;
|
|
1309
|
+
for (let i = 1; i <= maxSteps; i += 1) {
|
|
1310
|
+
const force = -cfg.stiffness * (x - to) - cfg.damping * v;
|
|
1311
|
+
v += force / cfg.mass * subDt;
|
|
1312
|
+
x += v * subDt;
|
|
1313
|
+
if (!Number.isFinite(x) || !Number.isFinite(v)) {
|
|
1314
|
+
values.push(to);
|
|
1315
|
+
break;
|
|
1316
|
+
}
|
|
1317
|
+
if (i % SAMPLE_STRIDE === 0) values.push(x);
|
|
1318
|
+
const atRest = Math.abs(to - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
|
|
1319
|
+
if (atRest) break;
|
|
1320
|
+
}
|
|
1321
|
+
if (values[values.length - 1] !== to) values.push(to);
|
|
1322
|
+
return {
|
|
1323
|
+
values,
|
|
1324
|
+
stepMs,
|
|
1325
|
+
durationMs: (values.length - 1) * stepMs
|
|
1326
|
+
};
|
|
1327
|
+
}
|
|
1328
|
+
function sampleTweenSettle(from, to, durationMs, easing) {
|
|
1329
|
+
const count = Math.max(2, Math.min(60, Math.round(durationMs / 16)));
|
|
1330
|
+
const values = [];
|
|
1331
|
+
for (let i = 0; i <= count; i += 1) {
|
|
1332
|
+
const t = i / count;
|
|
1333
|
+
values.push(from + (to - from) * easing(t));
|
|
1334
|
+
}
|
|
1335
|
+
values[values.length - 1] = to;
|
|
1336
|
+
return {
|
|
1337
|
+
values,
|
|
1338
|
+
stepMs: durationMs / count,
|
|
1339
|
+
durationMs
|
|
1340
|
+
};
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1686
1343
|
// src/core/controllers/animation-runner.ts
|
|
1687
1344
|
var DEFAULT_DURATION2 = 220;
|
|
1688
1345
|
var VELOCITY_PX_PER_S = 1e3;
|
|
@@ -1693,6 +1350,10 @@ var AnimationRunner = class {
|
|
|
1693
1350
|
__publicField(this, "applySizeFn");
|
|
1694
1351
|
__publicField(this, "getSize");
|
|
1695
1352
|
__publicField(this, "isDragging");
|
|
1353
|
+
__publicField(this, "applyAux");
|
|
1354
|
+
__publicField(this, "getTransformFor");
|
|
1355
|
+
__publicField(this, "settleWaapi");
|
|
1356
|
+
__publicField(this, "currentWaapi", null);
|
|
1696
1357
|
__publicField(this, "animationKind");
|
|
1697
1358
|
__publicField(this, "springConfig");
|
|
1698
1359
|
__publicField(this, "duration");
|
|
@@ -1708,6 +1369,9 @@ var AnimationRunner = class {
|
|
|
1708
1369
|
this.applySizeFn = deps.applySize;
|
|
1709
1370
|
this.getSize = deps.getSize;
|
|
1710
1371
|
this.isDragging = deps.isDragging;
|
|
1372
|
+
this.applyAux = deps.applyAux;
|
|
1373
|
+
this.getTransformFor = deps.getTransformFor;
|
|
1374
|
+
this.settleWaapi = opts.settleAnimation === "waapi";
|
|
1711
1375
|
const preset = resolveAnimationPreset(opts.animation);
|
|
1712
1376
|
this.animationKind = preset.kind;
|
|
1713
1377
|
this.duration = opts.duration ?? preset.duration ?? DEFAULT_DURATION2;
|
|
@@ -1732,11 +1396,20 @@ var AnimationRunner = class {
|
|
|
1732
1396
|
}
|
|
1733
1397
|
}
|
|
1734
1398
|
get isAnimating() {
|
|
1735
|
-
return this.currentTween !== null || this.currentSpring !== null;
|
|
1399
|
+
return this.currentTween !== null || this.currentSpring !== null || this.currentWaapi !== null;
|
|
1736
1400
|
}
|
|
1737
1401
|
cancel() {
|
|
1738
1402
|
this.currentTween?.cancel();
|
|
1739
1403
|
this.currentSpring?.cancel();
|
|
1404
|
+
if (this.currentWaapi) {
|
|
1405
|
+
const entry = this.currentWaapi;
|
|
1406
|
+
this.currentWaapi = null;
|
|
1407
|
+
entry.stop();
|
|
1408
|
+
try {
|
|
1409
|
+
entry.anim.cancel();
|
|
1410
|
+
} catch {
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1740
1413
|
}
|
|
1741
1414
|
async animateTo(target, velocityPxPerMs) {
|
|
1742
1415
|
if (target === this.getSize()) {
|
|
@@ -1755,7 +1428,28 @@ var AnimationRunner = class {
|
|
|
1755
1428
|
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1756
1429
|
return;
|
|
1757
1430
|
}
|
|
1758
|
-
if (this.
|
|
1431
|
+
if (this.settleWaapi && this.applyAux && this.getTransformFor && typeof this.element.animate === "function") {
|
|
1432
|
+
const samples = this.animationKind === "spring" ? sampleSpringSettle(
|
|
1433
|
+
this.getSize(),
|
|
1434
|
+
target,
|
|
1435
|
+
velocityPxPerMs * VELOCITY_PX_PER_S,
|
|
1436
|
+
this.springConfig
|
|
1437
|
+
) : sampleTweenSettle(
|
|
1438
|
+
this.getSize(),
|
|
1439
|
+
target,
|
|
1440
|
+
this.duration,
|
|
1441
|
+
this.easing
|
|
1442
|
+
);
|
|
1443
|
+
if (samples.values.length >= 2 && samples.durationMs > 0) {
|
|
1444
|
+
await this.runWaapiSettle(samples, target);
|
|
1445
|
+
if (!this.isAnimating) {
|
|
1446
|
+
this.getRootEl()?.removeAttribute("data-animating");
|
|
1447
|
+
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1448
|
+
}
|
|
1449
|
+
return;
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
if (this.animationKind === "spring") {
|
|
1759
1453
|
const spring = runSpring({
|
|
1760
1454
|
from: this.getSize(),
|
|
1761
1455
|
to: target,
|
|
@@ -1783,11 +1477,66 @@ var AnimationRunner = class {
|
|
|
1783
1477
|
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1784
1478
|
}
|
|
1785
1479
|
}
|
|
1480
|
+
async runWaapiSettle(samples, target) {
|
|
1481
|
+
const applyAux = this.applyAux;
|
|
1482
|
+
const getTransformFor = this.getTransformFor;
|
|
1483
|
+
const frames = samples.values.map((v) => ({
|
|
1484
|
+
transform: getTransformFor(v)
|
|
1485
|
+
}));
|
|
1486
|
+
const anim = this.element.animate(frames, {
|
|
1487
|
+
duration: samples.durationMs,
|
|
1488
|
+
easing: "linear",
|
|
1489
|
+
fill: "forwards"
|
|
1490
|
+
});
|
|
1491
|
+
let stopped = false;
|
|
1492
|
+
let auxRaf = 0;
|
|
1493
|
+
const start = performance.now();
|
|
1494
|
+
const lastIdx = samples.values.length - 1;
|
|
1495
|
+
const auxTick = () => {
|
|
1496
|
+
if (stopped) return;
|
|
1497
|
+
const elapsed = performance.now() - start;
|
|
1498
|
+
const idx = Math.min(Math.floor(elapsed / samples.stepMs), lastIdx);
|
|
1499
|
+
applyAux(samples.values[idx]);
|
|
1500
|
+
auxRaf = requestAnimationFrame(auxTick);
|
|
1501
|
+
};
|
|
1502
|
+
auxRaf = requestAnimationFrame(auxTick);
|
|
1503
|
+
const entry = {
|
|
1504
|
+
anim,
|
|
1505
|
+
stop: () => {
|
|
1506
|
+
stopped = true;
|
|
1507
|
+
cancelAnimationFrame(auxRaf);
|
|
1508
|
+
}
|
|
1509
|
+
};
|
|
1510
|
+
this.currentWaapi = entry;
|
|
1511
|
+
try {
|
|
1512
|
+
await anim.finished;
|
|
1513
|
+
} catch {
|
|
1514
|
+
}
|
|
1515
|
+
entry.stop();
|
|
1516
|
+
const wasCurrent = this.currentWaapi === entry;
|
|
1517
|
+
if (wasCurrent) this.currentWaapi = null;
|
|
1518
|
+
if (wasCurrent && anim.playState === "finished") {
|
|
1519
|
+
this.applySizeFn(target);
|
|
1520
|
+
try {
|
|
1521
|
+
anim.cancel();
|
|
1522
|
+
} catch {
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1786
1526
|
destroy() {
|
|
1787
1527
|
this.detachReducedMotion?.();
|
|
1788
1528
|
this.detachReducedMotion = null;
|
|
1789
1529
|
this.currentTween = null;
|
|
1790
1530
|
this.currentSpring = null;
|
|
1531
|
+
if (this.currentWaapi) {
|
|
1532
|
+
const entry = this.currentWaapi;
|
|
1533
|
+
this.currentWaapi = null;
|
|
1534
|
+
entry.stop();
|
|
1535
|
+
try {
|
|
1536
|
+
entry.anim.cancel();
|
|
1537
|
+
} catch {
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1791
1540
|
}
|
|
1792
1541
|
};
|
|
1793
1542
|
|
|
@@ -2644,7 +2393,7 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2644
2393
|
const initialAllowed = opts.allowed ?? opts.snapPoints.map((p) => p.id);
|
|
2645
2394
|
let initialId = opts.initial ?? initialAllowed[0] ?? opts.snapPoints[0]?.id ?? "default";
|
|
2646
2395
|
if (opts.persistKey) {
|
|
2647
|
-
const restored =
|
|
2396
|
+
const restored = readPersistedIdSafe(opts.persistKey);
|
|
2648
2397
|
if (restored && initialAllowed.includes(restored)) {
|
|
2649
2398
|
initialId = restored;
|
|
2650
2399
|
}
|
|
@@ -2675,6 +2424,7 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2675
2424
|
},
|
|
2676
2425
|
animation: {
|
|
2677
2426
|
animation: opts.animation,
|
|
2427
|
+
settleAnimation: opts.settleAnimation,
|
|
2678
2428
|
duration: opts.duration,
|
|
2679
2429
|
easing: opts.easing,
|
|
2680
2430
|
spring: opts.spring,
|
|
@@ -2692,6 +2442,15 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2692
2442
|
}
|
|
2693
2443
|
};
|
|
2694
2444
|
}
|
|
2445
|
+
var readPersistedIdSafe = (key) => {
|
|
2446
|
+
if (typeof window === "undefined") return null;
|
|
2447
|
+
if (typeof localStorage === "undefined") return null;
|
|
2448
|
+
try {
|
|
2449
|
+
return localStorage.getItem(key);
|
|
2450
|
+
} catch {
|
|
2451
|
+
return null;
|
|
2452
|
+
}
|
|
2453
|
+
};
|
|
2695
2454
|
|
|
2696
2455
|
// src/core/primitives/teardown-stack.ts
|
|
2697
2456
|
var TeardownStack = class {
|
|
@@ -2714,9 +2473,9 @@ var TeardownStack = class {
|
|
|
2714
2473
|
}
|
|
2715
2474
|
};
|
|
2716
2475
|
|
|
2717
|
-
// src/core/
|
|
2476
|
+
// src/core/BottomSheetCore.ts
|
|
2718
2477
|
var HAPTIC_DURATION_MS = 8;
|
|
2719
|
-
var
|
|
2478
|
+
var BottomSheetCore = class {
|
|
2720
2479
|
constructor(opts) {
|
|
2721
2480
|
__publicField(this, "id", nextInstanceId("bs"));
|
|
2722
2481
|
__publicField(this, "element");
|
|
@@ -2777,6 +2536,8 @@ var BottomSheetEngine = class {
|
|
|
2777
2536
|
__publicField(this, "stackEffectPrimed", false);
|
|
2778
2537
|
__publicField(this, "fitDeps");
|
|
2779
2538
|
__publicField(this, "transformTemplate");
|
|
2539
|
+
__publicField(this, "featureList", []);
|
|
2540
|
+
__publicField(this, "featureCtx");
|
|
2780
2541
|
const resolved = resolveEngineOptions(opts, {
|
|
2781
2542
|
shouldApplyInertSiblings: () => {
|
|
2782
2543
|
if (typeof document === "undefined") return false;
|
|
@@ -2823,7 +2584,9 @@ var BottomSheetEngine = class {
|
|
|
2823
2584
|
getRootEl: () => this.rootEl,
|
|
2824
2585
|
applySize: (size) => this.applySize(size),
|
|
2825
2586
|
getSize: () => this.size,
|
|
2826
|
-
isDragging: () => this.gesture?.isDragging ?? false
|
|
2587
|
+
isDragging: () => this.gesture?.isDragging ?? false,
|
|
2588
|
+
applyAux: (size) => this.applySize(size, true),
|
|
2589
|
+
getTransformFor: (size) => this.transformTemplate(this.snaps.getMaxAxisSize() - size)
|
|
2827
2590
|
},
|
|
2828
2591
|
resolved.animation
|
|
2829
2592
|
);
|
|
@@ -2846,6 +2609,11 @@ var BottomSheetEngine = class {
|
|
|
2846
2609
|
if (opts.linkedSheets) {
|
|
2847
2610
|
this.linkedSheets = opts.linkedSheets;
|
|
2848
2611
|
}
|
|
2612
|
+
const byName = /* @__PURE__ */ new Map();
|
|
2613
|
+
for (const feature of opts.features ?? []) {
|
|
2614
|
+
byName.set(feature.name, feature);
|
|
2615
|
+
}
|
|
2616
|
+
this.featureList = Array.from(byName.values());
|
|
2849
2617
|
this.activeId = resolved.initialId;
|
|
2850
2618
|
auditVhUsage(this.snapPointsRaw);
|
|
2851
2619
|
this.auditDuplicateSnapIds(this.snapPointsRaw);
|
|
@@ -2882,6 +2650,7 @@ var BottomSheetEngine = class {
|
|
|
2882
2650
|
scrollContainer: this.scrollContainer,
|
|
2883
2651
|
getMaxAxisSize: () => this.snaps.getMaxAxisSize()
|
|
2884
2652
|
});
|
|
2653
|
+
this.featureCtx = this.buildFeatureContext(opts.autoCollapseAfter);
|
|
2885
2654
|
this.attach();
|
|
2886
2655
|
this.registerInStack();
|
|
2887
2656
|
if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
|
|
@@ -2890,12 +2659,7 @@ var BottomSheetEngine = class {
|
|
|
2890
2659
|
if (!entry.isIntersecting) continue;
|
|
2891
2660
|
if (this.destroyed) return;
|
|
2892
2661
|
this.snaps.recompute();
|
|
2893
|
-
|
|
2894
|
-
if (current) {
|
|
2895
|
-
this.size = current.size;
|
|
2896
|
-
this.applySize(this.size);
|
|
2897
|
-
this.updateAriaSlider();
|
|
2898
|
-
}
|
|
2662
|
+
this.healActiveSnap();
|
|
2899
2663
|
io.disconnect();
|
|
2900
2664
|
return;
|
|
2901
2665
|
}
|
|
@@ -2918,46 +2682,77 @@ var BottomSheetEngine = class {
|
|
|
2918
2682
|
if (resolved.radius !== void 0) this.setRadius(resolved.radius);
|
|
2919
2683
|
if (resolved.maxHeight !== void 0) this.setMaxHeight(resolved.maxHeight);
|
|
2920
2684
|
this.applyAutoAriaLabelledBy();
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
getSize: () => this.size,
|
|
2926
|
-
close: () => this.close()
|
|
2927
|
-
})
|
|
2928
|
-
);
|
|
2929
|
-
}
|
|
2930
|
-
if (this.persistKey) {
|
|
2931
|
-
this.teardowns.add(installPersist(this, this.persistKey));
|
|
2685
|
+
this.runFeatureStage("post");
|
|
2686
|
+
this.warnOrphanFeatureOptions();
|
|
2687
|
+
if (this.size > 0) {
|
|
2688
|
+
this.handleOpen();
|
|
2932
2689
|
}
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
resolveSnap: (id) => this.snaps.findById(id),
|
|
2941
|
-
snapTo: (id) => {
|
|
2942
|
-
void this.snapTo(id);
|
|
2943
|
-
},
|
|
2944
|
-
on: (event, fn) => this.on(event, fn)
|
|
2945
|
-
})
|
|
2946
|
-
);
|
|
2947
|
-
this.teardowns.add(
|
|
2948
|
-
installRoute({
|
|
2690
|
+
}
|
|
2691
|
+
buildFeatureContext(autoCollapseAfter) {
|
|
2692
|
+
return {
|
|
2693
|
+
element: this.element,
|
|
2694
|
+
scrollContainer: this.scrollContainer,
|
|
2695
|
+
sheetId: this.id,
|
|
2696
|
+
options: {
|
|
2949
2697
|
routedTo: this.routedTo,
|
|
2950
2698
|
closeOnBack: this.closeOnBack,
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
this.
|
|
2699
|
+
closeOnRouteChange: this.closeOnRouteChange,
|
|
2700
|
+
persistKey: this.persistKey,
|
|
2701
|
+
autoCollapseAfter
|
|
2702
|
+
},
|
|
2703
|
+
isDestroyed: () => this.destroyed,
|
|
2704
|
+
isDragging: () => this.gesture?.isDragging ?? false,
|
|
2705
|
+
isAnimating: () => this.animation.isAnimating,
|
|
2706
|
+
isTopSheet: () => this.isTopSheet,
|
|
2707
|
+
isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
|
|
2708
|
+
getSize: () => this.size,
|
|
2709
|
+
getActiveId: () => this.activeId,
|
|
2710
|
+
getAllowedIds: () => this.snaps.getAllowedIds().slice(),
|
|
2711
|
+
allowedIdsBySize: () => this.allowedIdsBySize(),
|
|
2712
|
+
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
2713
|
+
resolveSnap: (id) => this.snaps.findById(id),
|
|
2714
|
+
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
2715
|
+
setSize: (size) => {
|
|
2716
|
+
this.size = size;
|
|
2717
|
+
},
|
|
2718
|
+
setMaxAxisSize: (size) => {
|
|
2719
|
+
this.snaps.setMaxAxisSize(size);
|
|
2720
|
+
},
|
|
2721
|
+
applySize: (size) => this.applySize(size),
|
|
2722
|
+
recomputeSnaps: () => this.recomputeSnaps(),
|
|
2723
|
+
newCycle: () => {
|
|
2724
|
+
this.newCycle();
|
|
2725
|
+
},
|
|
2726
|
+
cancelInFlight: () => {
|
|
2727
|
+
this.animation.cancel();
|
|
2728
|
+
},
|
|
2729
|
+
resyncAfterResize: () => this.resyncAfterResize(),
|
|
2730
|
+
snapTo: (id) => {
|
|
2731
|
+
void this.snapTo(id);
|
|
2732
|
+
},
|
|
2733
|
+
close: (reason) => this.close(reason),
|
|
2734
|
+
on: (event, fn) => this.on(event, fn),
|
|
2735
|
+
addTeardown: (fn) => this.teardowns.add(fn)
|
|
2736
|
+
};
|
|
2737
|
+
}
|
|
2738
|
+
runFeatureStage(stage) {
|
|
2739
|
+
for (const feature of this.featureList) {
|
|
2740
|
+
if ((feature.stage ?? "post") !== stage) continue;
|
|
2741
|
+
const teardown = feature.install(this.featureCtx);
|
|
2742
|
+
if (teardown) this.teardowns.add(teardown);
|
|
2743
|
+
}
|
|
2744
|
+
}
|
|
2745
|
+
warnOrphanFeatureOptions() {
|
|
2746
|
+
const names = new Set(this.featureList.map((f) => f.name));
|
|
2747
|
+
if ((this.closeOnBack || this.routedTo !== void 0 || this.closeOnRouteChange) && !names.has("route")) {
|
|
2748
|
+
devWarn(
|
|
2749
|
+
"[BottomSheet] closeOnBack/routedTo/closeOnRouteChange need routeFeature() \u2014 option ignored"
|
|
2750
|
+
);
|
|
2751
|
+
}
|
|
2752
|
+
if (this.persistKey && !names.has("persist")) {
|
|
2753
|
+
devWarn(
|
|
2754
|
+
"[BottomSheet] persistKey needs persistFeature() \u2014 snaps will not be saved"
|
|
2755
|
+
);
|
|
2961
2756
|
}
|
|
2962
2757
|
}
|
|
2963
2758
|
get state() {
|
|
@@ -3059,6 +2854,8 @@ var BottomSheetEngine = class {
|
|
|
3059
2854
|
const vt = document.startViewTransition(() => {
|
|
3060
2855
|
this.applySize(target.size);
|
|
3061
2856
|
});
|
|
2857
|
+
vt.ready?.catch(() => {
|
|
2858
|
+
});
|
|
3062
2859
|
this.currentViewTransition = vt;
|
|
3063
2860
|
try {
|
|
3064
2861
|
await vt.finished;
|
|
@@ -3310,11 +3107,16 @@ var BottomSheetEngine = class {
|
|
|
3310
3107
|
this.maxHeight.clampTo();
|
|
3311
3108
|
this.scrim.invalidateOpacityCache();
|
|
3312
3109
|
if (this.gesture?.isDragging) return;
|
|
3110
|
+
this.healActiveSnap();
|
|
3111
|
+
}
|
|
3112
|
+
healActiveSnap() {
|
|
3313
3113
|
const current = this.snaps.findById(this.activeId);
|
|
3314
|
-
if (current)
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3114
|
+
if (!current) return;
|
|
3115
|
+
this.size = current.size;
|
|
3116
|
+
this.applySize(this.size);
|
|
3117
|
+
this.updateAriaSlider();
|
|
3118
|
+
if (this.size > 0 && !this.lifecycle.isInstalled && !this.opening && !this.animation.isAnimating) {
|
|
3119
|
+
this.emitOpenSequence(this.activeId);
|
|
3318
3120
|
}
|
|
3319
3121
|
}
|
|
3320
3122
|
destroy() {
|
|
@@ -3493,18 +3295,7 @@ var BottomSheetEngine = class {
|
|
|
3493
3295
|
}
|
|
3494
3296
|
}
|
|
3495
3297
|
attachFeatures() {
|
|
3496
|
-
|
|
3497
|
-
this.teardowns.add(installContentSwipe({
|
|
3498
|
-
container: this.scrollContainer,
|
|
3499
|
-
isDragging: () => this.gesture?.isDragging ?? false,
|
|
3500
|
-
isAnimating: () => this.animation.isAnimating,
|
|
3501
|
-
getAllowedIds: () => this.allowedIdsBySize(),
|
|
3502
|
-
getActiveId: () => this.activeId,
|
|
3503
|
-
snapTo: (id) => {
|
|
3504
|
-
void this.snapTo(id);
|
|
3505
|
-
}
|
|
3506
|
-
}));
|
|
3507
|
-
}
|
|
3298
|
+
this.runFeatureStage("attach");
|
|
3508
3299
|
if (typeof window !== "undefined") {
|
|
3509
3300
|
this.teardowns.add(installResizeObserver({
|
|
3510
3301
|
element: this.element,
|
|
@@ -3544,31 +3335,6 @@ var BottomSheetEngine = class {
|
|
|
3544
3335
|
() => document.removeEventListener("keydown", onKey)
|
|
3545
3336
|
);
|
|
3546
3337
|
}
|
|
3547
|
-
this.teardowns.add(installVisualViewport({
|
|
3548
|
-
element: this.element,
|
|
3549
|
-
isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
|
|
3550
|
-
isDestroyed: () => this.destroyed,
|
|
3551
|
-
isDragging: () => this.gesture?.isDragging ?? false,
|
|
3552
|
-
recomputeSnaps: () => this.recomputeSnaps(),
|
|
3553
|
-
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
3554
|
-
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
3555
|
-
getSize: () => this.size,
|
|
3556
|
-
setMaxAxisSize: (size) => {
|
|
3557
|
-
this.snaps.setMaxAxisSize(size);
|
|
3558
|
-
},
|
|
3559
|
-
setSize: (size) => {
|
|
3560
|
-
this.size = size;
|
|
3561
|
-
},
|
|
3562
|
-
applySize: (size) => this.applySize(size),
|
|
3563
|
-
cancelInFlight: () => {
|
|
3564
|
-
this.animation.cancel();
|
|
3565
|
-
},
|
|
3566
|
-
newCycle: () => {
|
|
3567
|
-
this.newCycle();
|
|
3568
|
-
},
|
|
3569
|
-
isAnimating: () => this.animation.isAnimating,
|
|
3570
|
-
resyncAfterCancel: () => this.resyncAfterResize()
|
|
3571
|
-
}));
|
|
3572
3338
|
}
|
|
3573
3339
|
this.teardowns.add(installSliderKeyboard({
|
|
3574
3340
|
handle: this.handle,
|
|
@@ -3645,13 +3411,13 @@ var BottomSheetEngine = class {
|
|
|
3645
3411
|
}
|
|
3646
3412
|
}
|
|
3647
3413
|
}
|
|
3648
|
-
applySize(size) {
|
|
3414
|
+
applySize(size, skipTransform = false) {
|
|
3649
3415
|
const cap = this.snaps.getMaxAxisSize();
|
|
3650
3416
|
const clamped = cap > 0 && size > cap && !this.gesture?.isDragging && !this.allowOvershoot ? cap : size;
|
|
3651
3417
|
this.size = clamped;
|
|
3652
3418
|
const offset = cap - clamped;
|
|
3653
3419
|
const style = this.element.style;
|
|
3654
|
-
style.transform = this.transformTemplate(offset);
|
|
3420
|
+
if (!skipTransform) style.transform = this.transformTemplate(offset);
|
|
3655
3421
|
if (this.sizeWriteSentinel.shouldWrite(clamped, SIZE_WRITE_EPSILON)) {
|
|
3656
3422
|
style.setProperty("--bs-size", `${clamped}px`);
|
|
3657
3423
|
if (this.scrimParent) {
|
|
@@ -3729,6 +3495,514 @@ var BottomSheetEngine = class {
|
|
|
3729
3495
|
}
|
|
3730
3496
|
};
|
|
3731
3497
|
|
|
3498
|
+
// src/core/features/history-coordinator.ts
|
|
3499
|
+
var entries = [];
|
|
3500
|
+
var subscribers = /* @__PURE__ */ new Set();
|
|
3501
|
+
var suppress = 0;
|
|
3502
|
+
var internalDepth = 0;
|
|
3503
|
+
var pendingRebrands = [];
|
|
3504
|
+
var listenerInstalled = false;
|
|
3505
|
+
var patchInstalled = false;
|
|
3506
|
+
var origPushState = null;
|
|
3507
|
+
var origReplaceState = null;
|
|
3508
|
+
var patchedPushState = null;
|
|
3509
|
+
var patchedReplaceState = null;
|
|
3510
|
+
var hasWindow = () => typeof window !== "undefined";
|
|
3511
|
+
var hasHistory = () => typeof history !== "undefined";
|
|
3512
|
+
var brandMarker = (surface) => ({
|
|
3513
|
+
...surface.markerState(),
|
|
3514
|
+
__bs: true
|
|
3515
|
+
});
|
|
3516
|
+
var runInternal = (fn) => {
|
|
3517
|
+
internalDepth += 1;
|
|
3518
|
+
try {
|
|
3519
|
+
fn();
|
|
3520
|
+
} finally {
|
|
3521
|
+
internalDepth -= 1;
|
|
3522
|
+
}
|
|
3523
|
+
};
|
|
3524
|
+
var notifyRouteChange = () => {
|
|
3525
|
+
const snapshot = Array.from(subscribers);
|
|
3526
|
+
for (const fn of snapshot) fn();
|
|
3527
|
+
};
|
|
3528
|
+
var ensureListener = () => {
|
|
3529
|
+
if (listenerInstalled || !hasWindow()) return;
|
|
3530
|
+
window.addEventListener("popstate", onPopState);
|
|
3531
|
+
listenerInstalled = true;
|
|
3532
|
+
};
|
|
3533
|
+
var maybeTeardownListener = () => {
|
|
3534
|
+
if (!listenerInstalled) return;
|
|
3535
|
+
if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
|
|
3536
|
+
if (hasWindow()) window.removeEventListener("popstate", onPopState);
|
|
3537
|
+
listenerInstalled = false;
|
|
3538
|
+
};
|
|
3539
|
+
var installPatch = () => {
|
|
3540
|
+
if (patchInstalled || !hasHistory()) return;
|
|
3541
|
+
origPushState = history.pushState;
|
|
3542
|
+
origReplaceState = history.replaceState;
|
|
3543
|
+
patchedPushState = function(...args) {
|
|
3544
|
+
origPushState.apply(this, args);
|
|
3545
|
+
if (internalDepth === 0) notifyRouteChange();
|
|
3546
|
+
};
|
|
3547
|
+
patchedReplaceState = function(...args) {
|
|
3548
|
+
origReplaceState.apply(this, args);
|
|
3549
|
+
if (internalDepth === 0) notifyRouteChange();
|
|
3550
|
+
};
|
|
3551
|
+
history.pushState = patchedPushState;
|
|
3552
|
+
history.replaceState = patchedReplaceState;
|
|
3553
|
+
patchInstalled = true;
|
|
3554
|
+
};
|
|
3555
|
+
var removePatch = () => {
|
|
3556
|
+
if (!patchInstalled) return;
|
|
3557
|
+
if (history.pushState === patchedPushState && origPushState) {
|
|
3558
|
+
history.pushState = origPushState;
|
|
3559
|
+
}
|
|
3560
|
+
if (history.replaceState === patchedReplaceState && origReplaceState) {
|
|
3561
|
+
history.replaceState = origReplaceState;
|
|
3562
|
+
}
|
|
3563
|
+
origPushState = null;
|
|
3564
|
+
origReplaceState = null;
|
|
3565
|
+
patchedPushState = null;
|
|
3566
|
+
patchedReplaceState = null;
|
|
3567
|
+
patchInstalled = false;
|
|
3568
|
+
};
|
|
3569
|
+
function onPopState() {
|
|
3570
|
+
if (suppress > 0) {
|
|
3571
|
+
suppress -= 1;
|
|
3572
|
+
const rebrand = pendingRebrands.shift();
|
|
3573
|
+
if (rebrand) rebrand();
|
|
3574
|
+
maybeTeardownListener();
|
|
3575
|
+
return;
|
|
3576
|
+
}
|
|
3577
|
+
if (entries.length === 0) {
|
|
3578
|
+
notifyRouteChange();
|
|
3579
|
+
maybeTeardownListener();
|
|
3580
|
+
return;
|
|
3581
|
+
}
|
|
3582
|
+
let target = null;
|
|
3583
|
+
let targetIdx = -1;
|
|
3584
|
+
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
3585
|
+
const entry = entries[i];
|
|
3586
|
+
if (!entry.surface.isOpen()) continue;
|
|
3587
|
+
if (!target) {
|
|
3588
|
+
target = entry;
|
|
3589
|
+
targetIdx = i;
|
|
3590
|
+
}
|
|
3591
|
+
if (entry.surface.isTop()) {
|
|
3592
|
+
target = entry;
|
|
3593
|
+
targetIdx = i;
|
|
3594
|
+
break;
|
|
3595
|
+
}
|
|
3596
|
+
}
|
|
3597
|
+
if (!target) {
|
|
3598
|
+
const removed = entries.pop();
|
|
3599
|
+
if (removed) removed.live = false;
|
|
3600
|
+
maybeTeardownListener();
|
|
3601
|
+
return;
|
|
3602
|
+
}
|
|
3603
|
+
target.live = false;
|
|
3604
|
+
entries.splice(targetIdx, 1);
|
|
3605
|
+
const settled = target;
|
|
3606
|
+
void Promise.resolve(settled.surface.close()).then(() => {
|
|
3607
|
+
if (settled.surface.isOpen()) restore(settled);
|
|
3608
|
+
});
|
|
3609
|
+
maybeTeardownListener();
|
|
3610
|
+
}
|
|
3611
|
+
function restore(entry) {
|
|
3612
|
+
if (!hasWindow() || !hasHistory()) return;
|
|
3613
|
+
entry.live = true;
|
|
3614
|
+
runInternal(() => {
|
|
3615
|
+
try {
|
|
3616
|
+
history.pushState(brandMarker(entry.surface), "", entry.surface.url);
|
|
3617
|
+
} catch {
|
|
3618
|
+
entry.live = false;
|
|
3619
|
+
}
|
|
3620
|
+
});
|
|
3621
|
+
if (entry.live) {
|
|
3622
|
+
entries.push(entry);
|
|
3623
|
+
ensureListener();
|
|
3624
|
+
}
|
|
3625
|
+
}
|
|
3626
|
+
function pushBackMarker(surface) {
|
|
3627
|
+
const entry = { surface, priorUrl: void 0, live: false };
|
|
3628
|
+
if (!hasWindow() || !hasHistory()) {
|
|
3629
|
+
return entry;
|
|
3630
|
+
}
|
|
3631
|
+
entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
|
|
3632
|
+
runInternal(() => {
|
|
3633
|
+
try {
|
|
3634
|
+
history.pushState(brandMarker(surface), "", surface.url);
|
|
3635
|
+
entry.live = true;
|
|
3636
|
+
} catch {
|
|
3637
|
+
entry.live = false;
|
|
3638
|
+
}
|
|
3639
|
+
});
|
|
3640
|
+
if (entry.live) {
|
|
3641
|
+
entries.push(entry);
|
|
3642
|
+
ensureListener();
|
|
3643
|
+
}
|
|
3644
|
+
return entry;
|
|
3645
|
+
}
|
|
3646
|
+
function popBackMarker(handle) {
|
|
3647
|
+
if (!hasWindow() || !hasHistory()) return;
|
|
3648
|
+
const entry = handle;
|
|
3649
|
+
const idx = entries.indexOf(entry);
|
|
3650
|
+
if (idx === -1 || !entry.live) return;
|
|
3651
|
+
const last = entries.length - 1;
|
|
3652
|
+
entry.live = false;
|
|
3653
|
+
entries.splice(idx, 1);
|
|
3654
|
+
let rebrand = null;
|
|
3655
|
+
if (idx !== last) {
|
|
3656
|
+
const rebrandSurface = entries[entries.length - 1].surface;
|
|
3657
|
+
const rebrandUrl = entry.priorUrl;
|
|
3658
|
+
rebrand = () => {
|
|
3659
|
+
runInternal(() => {
|
|
3660
|
+
history.replaceState(
|
|
3661
|
+
brandMarker(rebrandSurface),
|
|
3662
|
+
"",
|
|
3663
|
+
rebrandUrl !== void 0 ? rebrandUrl : location.href
|
|
3664
|
+
);
|
|
3665
|
+
});
|
|
3666
|
+
};
|
|
3667
|
+
}
|
|
3668
|
+
pendingRebrands.push(rebrand);
|
|
3669
|
+
suppress += 1;
|
|
3670
|
+
runInternal(() => {
|
|
3671
|
+
try {
|
|
3672
|
+
history.back();
|
|
3673
|
+
} catch {
|
|
3674
|
+
suppress = Math.max(0, suppress - 1);
|
|
3675
|
+
pendingRebrands.pop();
|
|
3676
|
+
}
|
|
3677
|
+
});
|
|
3678
|
+
maybeTeardownListener();
|
|
3679
|
+
}
|
|
3680
|
+
function subscribeRouteChange(fn) {
|
|
3681
|
+
if (!hasWindow() || !hasHistory()) return () => {
|
|
3682
|
+
};
|
|
3683
|
+
subscribers.add(fn);
|
|
3684
|
+
if (subscribers.size === 1) installPatch();
|
|
3685
|
+
ensureListener();
|
|
3686
|
+
return () => {
|
|
3687
|
+
if (!subscribers.has(fn)) return;
|
|
3688
|
+
subscribers.delete(fn);
|
|
3689
|
+
if (subscribers.size === 0) removePatch();
|
|
3690
|
+
maybeTeardownListener();
|
|
3691
|
+
};
|
|
3692
|
+
}
|
|
3693
|
+
|
|
3694
|
+
// src/core/features/route.ts
|
|
3695
|
+
function installRoute(deps) {
|
|
3696
|
+
if (typeof window === "undefined") {
|
|
3697
|
+
return () => {
|
|
3698
|
+
};
|
|
3699
|
+
}
|
|
3700
|
+
if (!deps.routedTo && !deps.closeOnBack) {
|
|
3701
|
+
return () => {
|
|
3702
|
+
};
|
|
3703
|
+
}
|
|
3704
|
+
let handle = null;
|
|
3705
|
+
const onOpen = () => {
|
|
3706
|
+
if (handle) return;
|
|
3707
|
+
handle = pushBackMarker({
|
|
3708
|
+
isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
|
|
3709
|
+
isTop: deps.isTopSheet,
|
|
3710
|
+
close: deps.close,
|
|
3711
|
+
markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
|
|
3712
|
+
url: deps.routedTo
|
|
3713
|
+
});
|
|
3714
|
+
};
|
|
3715
|
+
const onClose = () => {
|
|
3716
|
+
if (!handle) return;
|
|
3717
|
+
popBackMarker(handle);
|
|
3718
|
+
handle = null;
|
|
3719
|
+
};
|
|
3720
|
+
const unsubscribeOpen = deps.on("open", onOpen);
|
|
3721
|
+
const unsubscribeClose = deps.on("close", onClose);
|
|
3722
|
+
if (deps.getSize() > 0) onOpen();
|
|
3723
|
+
return () => {
|
|
3724
|
+
unsubscribeOpen();
|
|
3725
|
+
unsubscribeClose();
|
|
3726
|
+
if (handle) {
|
|
3727
|
+
popBackMarker(handle);
|
|
3728
|
+
handle = null;
|
|
3729
|
+
}
|
|
3730
|
+
};
|
|
3731
|
+
}
|
|
3732
|
+
function installRouteChange(deps) {
|
|
3733
|
+
return subscribeRouteChange(() => {
|
|
3734
|
+
if (deps.isDestroyed() || deps.getSize() <= 0) return;
|
|
3735
|
+
void deps.close();
|
|
3736
|
+
});
|
|
3737
|
+
}
|
|
3738
|
+
|
|
3739
|
+
// src/core/features/persist.ts
|
|
3740
|
+
function installPersist(engine, key) {
|
|
3741
|
+
const unsubscribe = engine.on("snap", ({ id }) => {
|
|
3742
|
+
if (typeof window === "undefined") return;
|
|
3743
|
+
if (typeof localStorage === "undefined") return;
|
|
3744
|
+
try {
|
|
3745
|
+
localStorage.setItem(key, id);
|
|
3746
|
+
} catch {
|
|
3747
|
+
}
|
|
3748
|
+
});
|
|
3749
|
+
return unsubscribe;
|
|
3750
|
+
}
|
|
3751
|
+
|
|
3752
|
+
// src/core/features/auto-collapse.ts
|
|
3753
|
+
function installAutoCollapse(deps) {
|
|
3754
|
+
const { ms } = deps;
|
|
3755
|
+
if (ms === void 0 || ms <= 0) {
|
|
3756
|
+
return () => {
|
|
3757
|
+
};
|
|
3758
|
+
}
|
|
3759
|
+
let timer = null;
|
|
3760
|
+
const clearTimer = () => {
|
|
3761
|
+
if (timer !== null) {
|
|
3762
|
+
clearTimeout(timer);
|
|
3763
|
+
timer = null;
|
|
3764
|
+
}
|
|
3765
|
+
};
|
|
3766
|
+
const fire = () => {
|
|
3767
|
+
if (deps.isDestroyed()) return;
|
|
3768
|
+
if (deps.isDragging()) return;
|
|
3769
|
+
const active = deps.resolveSnap(deps.getActiveId());
|
|
3770
|
+
if (!active || active.size === 0) return;
|
|
3771
|
+
let target = null;
|
|
3772
|
+
for (const id of deps.getAllowedIds()) {
|
|
3773
|
+
const snap = deps.resolveSnap(id);
|
|
3774
|
+
if (!snap || snap.size <= 0) continue;
|
|
3775
|
+
if (!target || snap.size < target.size) target = snap;
|
|
3776
|
+
}
|
|
3777
|
+
if (!target) return;
|
|
3778
|
+
if (target.id === active.id || target.size >= active.size) return;
|
|
3779
|
+
deps.snapTo(target.id);
|
|
3780
|
+
};
|
|
3781
|
+
const reset2 = () => {
|
|
3782
|
+
clearTimer();
|
|
3783
|
+
if (deps.isDestroyed()) return;
|
|
3784
|
+
timer = setTimeout(() => {
|
|
3785
|
+
timer = null;
|
|
3786
|
+
fire();
|
|
3787
|
+
}, ms);
|
|
3788
|
+
};
|
|
3789
|
+
const unsubscribe = deps.on("snap", () => reset2());
|
|
3790
|
+
if ((deps.resolveSnap(deps.getActiveId())?.size ?? 0) > 0) reset2();
|
|
3791
|
+
return () => {
|
|
3792
|
+
clearTimer();
|
|
3793
|
+
unsubscribe();
|
|
3794
|
+
};
|
|
3795
|
+
}
|
|
3796
|
+
|
|
3797
|
+
// src/core/features/content-swipe.ts
|
|
3798
|
+
var CONTENT_PULL_THRESHOLD = 60;
|
|
3799
|
+
function installContentSwipe(deps) {
|
|
3800
|
+
const { container } = deps;
|
|
3801
|
+
let startY = 0;
|
|
3802
|
+
let startScrollTop = 0;
|
|
3803
|
+
let moved = false;
|
|
3804
|
+
const onTouchStart = (e) => {
|
|
3805
|
+
const t = e.touches[0];
|
|
3806
|
+
if (!t) return;
|
|
3807
|
+
startY = t.clientY;
|
|
3808
|
+
startScrollTop = container.scrollTop;
|
|
3809
|
+
moved = false;
|
|
3810
|
+
};
|
|
3811
|
+
const onTouchMove = (e) => {
|
|
3812
|
+
const t = e.touches[0];
|
|
3813
|
+
if (!t) return;
|
|
3814
|
+
if (Math.abs(t.clientY - startY) > CONTENT_PULL_THRESHOLD) moved = true;
|
|
3815
|
+
};
|
|
3816
|
+
const onTouchEnd = (e) => {
|
|
3817
|
+
if (!moved) return;
|
|
3818
|
+
if (deps.isDragging() || deps.isAnimating()) return;
|
|
3819
|
+
if (container.scrollTop !== startScrollTop) return;
|
|
3820
|
+
const t = e.changedTouches[0];
|
|
3821
|
+
if (!t) return;
|
|
3822
|
+
const deltaY = t.clientY - startY;
|
|
3823
|
+
const atTop = container.scrollTop <= 0;
|
|
3824
|
+
const allowed = deps.getAllowedIds();
|
|
3825
|
+
const idx = allowed.indexOf(deps.getActiveId());
|
|
3826
|
+
if (idx === -1) return;
|
|
3827
|
+
if (atTop && deltaY > CONTENT_PULL_THRESHOLD && idx > 0) {
|
|
3828
|
+
deps.snapTo(allowed[idx - 1]);
|
|
3829
|
+
} else if (deltaY < -CONTENT_PULL_THRESHOLD && idx < allowed.length - 1) {
|
|
3830
|
+
deps.snapTo(allowed[idx + 1]);
|
|
3831
|
+
}
|
|
3832
|
+
};
|
|
3833
|
+
container.addEventListener("touchstart", onTouchStart, { passive: true });
|
|
3834
|
+
container.addEventListener("touchmove", onTouchMove, { passive: true });
|
|
3835
|
+
container.addEventListener("touchend", onTouchEnd, { passive: true });
|
|
3836
|
+
return () => {
|
|
3837
|
+
container.removeEventListener("touchstart", onTouchStart);
|
|
3838
|
+
container.removeEventListener("touchmove", onTouchMove);
|
|
3839
|
+
container.removeEventListener("touchend", onTouchEnd);
|
|
3840
|
+
};
|
|
3841
|
+
}
|
|
3842
|
+
|
|
3843
|
+
// src/core/features/visual-viewport.ts
|
|
3844
|
+
var SAFETY_PAD = 8;
|
|
3845
|
+
function installVisualViewport(deps) {
|
|
3846
|
+
if (typeof window === "undefined" || !window.visualViewport) {
|
|
3847
|
+
return () => {
|
|
3848
|
+
};
|
|
3849
|
+
}
|
|
3850
|
+
const vv = window.visualViewport;
|
|
3851
|
+
let rafId = null;
|
|
3852
|
+
const onResize = () => {
|
|
3853
|
+
if (rafId !== null) return;
|
|
3854
|
+
rafId = requestAnimationFrame(() => {
|
|
3855
|
+
rafId = null;
|
|
3856
|
+
if (deps.isDestroyed()) return;
|
|
3857
|
+
deps.recomputeSnaps();
|
|
3858
|
+
const isVertical = deps.isVerticalAxis();
|
|
3859
|
+
const visible = isVertical ? vv.height : vv.width;
|
|
3860
|
+
const windowSize = isVertical ? window.innerHeight : window.innerWidth;
|
|
3861
|
+
const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
|
|
3862
|
+
if (clamp < deps.getMaxAxisSize()) {
|
|
3863
|
+
deps.setMaxAxisSize(clamp);
|
|
3864
|
+
}
|
|
3865
|
+
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
3866
|
+
deps.cancelInFlight();
|
|
3867
|
+
deps.newCycle();
|
|
3868
|
+
const max = deps.getMaxAxisSize();
|
|
3869
|
+
deps.setSize(Math.min(deps.getSize(), max));
|
|
3870
|
+
const current = deps.resolveActiveSnap();
|
|
3871
|
+
if (current && !deps.isDragging()) {
|
|
3872
|
+
deps.applySize(Math.min(current.size, max));
|
|
3873
|
+
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
3874
|
+
} else {
|
|
3875
|
+
deps.applySize(deps.getSize());
|
|
3876
|
+
}
|
|
3877
|
+
});
|
|
3878
|
+
};
|
|
3879
|
+
vv.addEventListener("resize", onResize);
|
|
3880
|
+
return () => {
|
|
3881
|
+
vv.removeEventListener("resize", onResize);
|
|
3882
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
3883
|
+
};
|
|
3884
|
+
}
|
|
3885
|
+
|
|
3886
|
+
// src/core/features/engine-features.ts
|
|
3887
|
+
function routeFeature() {
|
|
3888
|
+
return {
|
|
3889
|
+
name: "route",
|
|
3890
|
+
install: (ctx) => {
|
|
3891
|
+
const teardowns = new TeardownStack();
|
|
3892
|
+
if (ctx.options.closeOnRouteChange) {
|
|
3893
|
+
teardowns.add(
|
|
3894
|
+
installRouteChange({
|
|
3895
|
+
isDestroyed: ctx.isDestroyed,
|
|
3896
|
+
getSize: ctx.getSize,
|
|
3897
|
+
close: () => ctx.close()
|
|
3898
|
+
})
|
|
3899
|
+
);
|
|
3900
|
+
}
|
|
3901
|
+
teardowns.add(
|
|
3902
|
+
installRoute({
|
|
3903
|
+
routedTo: ctx.options.routedTo,
|
|
3904
|
+
closeOnBack: ctx.options.closeOnBack,
|
|
3905
|
+
isTopSheet: ctx.isTopSheet,
|
|
3906
|
+
getSize: ctx.getSize,
|
|
3907
|
+
isDestroyed: ctx.isDestroyed,
|
|
3908
|
+
close: () => ctx.close("back"),
|
|
3909
|
+
on: ctx.on,
|
|
3910
|
+
sheetId: ctx.sheetId
|
|
3911
|
+
})
|
|
3912
|
+
);
|
|
3913
|
+
return () => teardowns.drain();
|
|
3914
|
+
}
|
|
3915
|
+
};
|
|
3916
|
+
}
|
|
3917
|
+
function persistFeature() {
|
|
3918
|
+
return {
|
|
3919
|
+
name: "persist",
|
|
3920
|
+
install: (ctx) => {
|
|
3921
|
+
const key = ctx.options.persistKey;
|
|
3922
|
+
if (!key) return;
|
|
3923
|
+
return installPersist({ on: ctx.on }, key);
|
|
3924
|
+
}
|
|
3925
|
+
};
|
|
3926
|
+
}
|
|
3927
|
+
function autoCollapseFeature() {
|
|
3928
|
+
return {
|
|
3929
|
+
name: "auto-collapse",
|
|
3930
|
+
install: (ctx) => installAutoCollapse({
|
|
3931
|
+
ms: ctx.options.autoCollapseAfter,
|
|
3932
|
+
isDestroyed: ctx.isDestroyed,
|
|
3933
|
+
isDragging: ctx.isDragging,
|
|
3934
|
+
getAllowedIds: ctx.getAllowedIds,
|
|
3935
|
+
getActiveId: ctx.getActiveId,
|
|
3936
|
+
resolveSnap: ctx.resolveSnap,
|
|
3937
|
+
snapTo: ctx.snapTo,
|
|
3938
|
+
on: ctx.on
|
|
3939
|
+
})
|
|
3940
|
+
};
|
|
3941
|
+
}
|
|
3942
|
+
function contentSwipeFeature() {
|
|
3943
|
+
return {
|
|
3944
|
+
name: "content-swipe",
|
|
3945
|
+
stage: "attach",
|
|
3946
|
+
install: (ctx) => {
|
|
3947
|
+
if (!ctx.scrollContainer) return;
|
|
3948
|
+
return installContentSwipe({
|
|
3949
|
+
container: ctx.scrollContainer,
|
|
3950
|
+
isDragging: ctx.isDragging,
|
|
3951
|
+
isAnimating: ctx.isAnimating,
|
|
3952
|
+
getAllowedIds: ctx.allowedIdsBySize,
|
|
3953
|
+
getActiveId: ctx.getActiveId,
|
|
3954
|
+
snapTo: ctx.snapTo
|
|
3955
|
+
});
|
|
3956
|
+
}
|
|
3957
|
+
};
|
|
3958
|
+
}
|
|
3959
|
+
function visualViewportFeature() {
|
|
3960
|
+
return {
|
|
3961
|
+
name: "visual-viewport",
|
|
3962
|
+
install: (ctx) => {
|
|
3963
|
+
if (typeof window === "undefined") return;
|
|
3964
|
+
return installVisualViewport({
|
|
3965
|
+
element: ctx.element,
|
|
3966
|
+
isVerticalAxis: ctx.isVerticalAxis,
|
|
3967
|
+
isDestroyed: ctx.isDestroyed,
|
|
3968
|
+
isDragging: ctx.isDragging,
|
|
3969
|
+
recomputeSnaps: ctx.recomputeSnaps,
|
|
3970
|
+
resolveActiveSnap: ctx.resolveActiveSnap,
|
|
3971
|
+
getMaxAxisSize: ctx.getMaxAxisSize,
|
|
3972
|
+
getSize: ctx.getSize,
|
|
3973
|
+
setMaxAxisSize: ctx.setMaxAxisSize,
|
|
3974
|
+
setSize: ctx.setSize,
|
|
3975
|
+
applySize: ctx.applySize,
|
|
3976
|
+
cancelInFlight: ctx.cancelInFlight,
|
|
3977
|
+
newCycle: ctx.newCycle,
|
|
3978
|
+
isAnimating: ctx.isAnimating,
|
|
3979
|
+
resyncAfterCancel: ctx.resyncAfterResize
|
|
3980
|
+
});
|
|
3981
|
+
}
|
|
3982
|
+
};
|
|
3983
|
+
}
|
|
3984
|
+
|
|
3985
|
+
// src/core/default-features.ts
|
|
3986
|
+
function defaultEngineFeatures() {
|
|
3987
|
+
return [
|
|
3988
|
+
contentSwipeFeature(),
|
|
3989
|
+
visualViewportFeature(),
|
|
3990
|
+
persistFeature(),
|
|
3991
|
+
autoCollapseFeature(),
|
|
3992
|
+
routeFeature()
|
|
3993
|
+
];
|
|
3994
|
+
}
|
|
3995
|
+
|
|
3996
|
+
// src/core/BottomSheetEngine.ts
|
|
3997
|
+
var BottomSheetEngine = class extends BottomSheetCore {
|
|
3998
|
+
constructor(opts) {
|
|
3999
|
+
super({
|
|
4000
|
+
...opts,
|
|
4001
|
+
features: [...defaultEngineFeatures(), ...opts.features ?? []]
|
|
4002
|
+
});
|
|
4003
|
+
}
|
|
4004
|
+
};
|
|
4005
|
+
|
|
3732
4006
|
// src/core/features/teleport.ts
|
|
3733
4007
|
var resolveTeleportTarget = (target) => {
|
|
3734
4008
|
if (!target) return null;
|