@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/solid.source.jsx
CHANGED
|
@@ -354,74 +354,6 @@ var SnapResolver = class {
|
|
|
354
354
|
}
|
|
355
355
|
};
|
|
356
356
|
|
|
357
|
-
// src/core/features/persist.ts
|
|
358
|
-
function readPersistedId(key) {
|
|
359
|
-
if (!key) return null;
|
|
360
|
-
if (typeof window === "undefined") return null;
|
|
361
|
-
if (typeof localStorage === "undefined") return null;
|
|
362
|
-
try {
|
|
363
|
-
return localStorage.getItem(key);
|
|
364
|
-
} catch {
|
|
365
|
-
return null;
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
function installPersist(engine, key) {
|
|
369
|
-
const unsubscribe = engine.on("snap", ({ id }) => {
|
|
370
|
-
if (typeof window === "undefined") return;
|
|
371
|
-
if (typeof localStorage === "undefined") return;
|
|
372
|
-
try {
|
|
373
|
-
localStorage.setItem(key, id);
|
|
374
|
-
} catch {
|
|
375
|
-
}
|
|
376
|
-
});
|
|
377
|
-
return unsubscribe;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
// src/core/features/auto-collapse.ts
|
|
381
|
-
function installAutoCollapse(deps) {
|
|
382
|
-
const { ms } = deps;
|
|
383
|
-
if (ms === void 0 || ms <= 0) {
|
|
384
|
-
return () => {
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
|
-
let timer = null;
|
|
388
|
-
const clearTimer = () => {
|
|
389
|
-
if (timer !== null) {
|
|
390
|
-
clearTimeout(timer);
|
|
391
|
-
timer = null;
|
|
392
|
-
}
|
|
393
|
-
};
|
|
394
|
-
const fire = () => {
|
|
395
|
-
if (deps.isDestroyed()) return;
|
|
396
|
-
if (deps.isDragging()) return;
|
|
397
|
-
const active = deps.resolveSnap(deps.getActiveId());
|
|
398
|
-
if (!active || active.size === 0) return;
|
|
399
|
-
let target = null;
|
|
400
|
-
for (const id of deps.getAllowedIds()) {
|
|
401
|
-
const snap = deps.resolveSnap(id);
|
|
402
|
-
if (!snap || snap.size <= 0) continue;
|
|
403
|
-
if (!target || snap.size < target.size) target = snap;
|
|
404
|
-
}
|
|
405
|
-
if (!target) return;
|
|
406
|
-
if (target.id === active.id || target.size >= active.size) return;
|
|
407
|
-
deps.snapTo(target.id);
|
|
408
|
-
};
|
|
409
|
-
const reset = () => {
|
|
410
|
-
clearTimer();
|
|
411
|
-
if (deps.isDestroyed()) return;
|
|
412
|
-
timer = setTimeout(() => {
|
|
413
|
-
timer = null;
|
|
414
|
-
fire();
|
|
415
|
-
}, ms);
|
|
416
|
-
};
|
|
417
|
-
const unsubscribe = deps.on("snap", () => reset());
|
|
418
|
-
if ((deps.resolveSnap(deps.getActiveId())?.size ?? 0) > 0) reset();
|
|
419
|
-
return () => {
|
|
420
|
-
clearTimer();
|
|
421
|
-
unsubscribe();
|
|
422
|
-
};
|
|
423
|
-
}
|
|
424
|
-
|
|
425
357
|
// src/core/features/linked-sheets.ts
|
|
426
358
|
function notifyLinkedSheets(sheets, self) {
|
|
427
359
|
if (sheets.length === 0) return;
|
|
@@ -444,390 +376,65 @@ function notifyLinkedSheets(sheets, self) {
|
|
|
444
376
|
}
|
|
445
377
|
}
|
|
446
378
|
|
|
447
|
-
// src/core/features/
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
var pendingRebrand = null;
|
|
453
|
-
var listenerInstalled = false;
|
|
454
|
-
var patchInstalled = false;
|
|
455
|
-
var origPushState = null;
|
|
456
|
-
var origReplaceState = null;
|
|
457
|
-
var patchedPushState = null;
|
|
458
|
-
var patchedReplaceState = null;
|
|
459
|
-
var hasWindow = () => typeof window !== "undefined";
|
|
460
|
-
var hasHistory = () => typeof history !== "undefined";
|
|
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;
|
|
379
|
+
// src/core/features/resize-observer.ts
|
|
380
|
+
function installResizeObserver(deps) {
|
|
381
|
+
if (typeof window === "undefined") {
|
|
382
|
+
return () => {
|
|
383
|
+
};
|
|
527
384
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
const
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
if (entry.surface.isTop()) {
|
|
538
|
-
target = entry;
|
|
539
|
-
targetIdx = i;
|
|
540
|
-
break;
|
|
385
|
+
const onResize = () => {
|
|
386
|
+
if (deps.isDestroyed()) return;
|
|
387
|
+
deps.recomputeSnaps();
|
|
388
|
+
const mode = deps.getMode();
|
|
389
|
+
const isVerticalAxis = mode === "bottom" || mode === "top";
|
|
390
|
+
const viewportSize2 = isVerticalAxis ? window.innerHeight : window.innerWidth;
|
|
391
|
+
const max = deps.getMaxAxisSize();
|
|
392
|
+
if (viewportSize2 > 0 && viewportSize2 < max) {
|
|
393
|
+
deps.setMaxAxisSize(viewportSize2);
|
|
541
394
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
void Promise.resolve(settled.surface.close()).then(() => {
|
|
553
|
-
if (settled.surface.isOpen()) restore(settled);
|
|
554
|
-
});
|
|
555
|
-
maybeTeardownListener();
|
|
556
|
-
}
|
|
557
|
-
function restore(entry) {
|
|
558
|
-
if (!hasWindow() || !hasHistory()) return;
|
|
559
|
-
entry.live = true;
|
|
560
|
-
runInternal(() => {
|
|
561
|
-
try {
|
|
562
|
-
history.pushState(entry.surface.markerState(), "", entry.surface.url);
|
|
563
|
-
} catch {
|
|
564
|
-
entry.live = false;
|
|
395
|
+
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
396
|
+
deps.cancelInFlight();
|
|
397
|
+
deps.newCycle();
|
|
398
|
+
const current = deps.resolveActiveSnap();
|
|
399
|
+
const newMax = deps.getMaxAxisSize();
|
|
400
|
+
const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
|
|
401
|
+
deps.setSize(targetSize);
|
|
402
|
+
if (current && !deps.isDragging()) {
|
|
403
|
+
deps.applySize(targetSize);
|
|
404
|
+
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
565
405
|
}
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
406
|
+
};
|
|
407
|
+
let resizeObserver = null;
|
|
408
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
409
|
+
resizeObserver = new ResizeObserver(onResize);
|
|
410
|
+
resizeObserver.observe(document.documentElement);
|
|
411
|
+
} else {
|
|
412
|
+
window.addEventListener("resize", onResize);
|
|
570
413
|
}
|
|
414
|
+
window.addEventListener("orientationchange", onResize);
|
|
415
|
+
const onVisibility = () => {
|
|
416
|
+
if (deps.isDestroyed()) return;
|
|
417
|
+
if (document.hidden) deps.cancelInFlight();
|
|
418
|
+
};
|
|
419
|
+
document.addEventListener("visibilitychange", onVisibility);
|
|
420
|
+
return () => {
|
|
421
|
+
resizeObserver?.disconnect();
|
|
422
|
+
window.removeEventListener("resize", onResize);
|
|
423
|
+
window.removeEventListener("orientationchange", onResize);
|
|
424
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
425
|
+
};
|
|
571
426
|
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
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
|
-
rebrandSurface.markerState(),
|
|
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);
|
|
427
|
+
|
|
428
|
+
// src/core/features/fit-observer.ts
|
|
429
|
+
var contentTargets = (scroller) => {
|
|
430
|
+
if (!scroller) return [];
|
|
431
|
+
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
432
|
+
const out = [];
|
|
433
|
+
for (const child of Array.from(scroller.children)) {
|
|
434
|
+
if (hasSlot && child instanceof HTMLSlotElement) {
|
|
435
|
+
for (const el of child.assignedElements()) out.push(el);
|
|
436
|
+
} else {
|
|
437
|
+
out.push(child);
|
|
831
438
|
}
|
|
832
439
|
}
|
|
833
440
|
return out;
|
|
@@ -947,11 +554,15 @@ function createMaxHeightController(deps) {
|
|
|
947
554
|
|
|
948
555
|
// src/core/features/fit-measurement.ts
|
|
949
556
|
var measureSheetNatural = (element, content, vertical) => {
|
|
950
|
-
if (!content) {
|
|
951
|
-
return vertical ? element.offsetHeight : element.offsetWidth;
|
|
952
|
-
}
|
|
953
557
|
const axis = vertical ? "height" : "width";
|
|
954
558
|
const sheetStyle = element.style;
|
|
559
|
+
if (!content) {
|
|
560
|
+
const prev = sheetStyle[axis];
|
|
561
|
+
sheetStyle[axis] = "auto";
|
|
562
|
+
const poked2 = vertical ? element.offsetHeight : element.offsetWidth;
|
|
563
|
+
sheetStyle[axis] = prev;
|
|
564
|
+
return poked2;
|
|
565
|
+
}
|
|
955
566
|
const cs = content.style;
|
|
956
567
|
const prevSheet = sheetStyle[axis];
|
|
957
568
|
const prevFlex = cs.flex;
|
|
@@ -1663,6 +1274,52 @@ function resolveAnimationPreset(animation) {
|
|
|
1663
1274
|
}
|
|
1664
1275
|
}
|
|
1665
1276
|
|
|
1277
|
+
// src/core/animation/waapi-settle.ts
|
|
1278
|
+
var SIM_HZ = 240;
|
|
1279
|
+
var SAMPLE_STRIDE = 4;
|
|
1280
|
+
var MAX_SIM_MS = 3e3;
|
|
1281
|
+
function sampleSpringSettle(from, to, velocityPxPerS, config) {
|
|
1282
|
+
const cfg = { ...DEFAULT_SPRING, ...config };
|
|
1283
|
+
const subDt = 1 / SIM_HZ;
|
|
1284
|
+
const stepMs = SAMPLE_STRIDE / SIM_HZ * 1e3;
|
|
1285
|
+
const maxSteps = Math.ceil(MAX_SIM_MS / 1e3 * SIM_HZ);
|
|
1286
|
+
const values = [from];
|
|
1287
|
+
let x = from;
|
|
1288
|
+
let v = velocityPxPerS;
|
|
1289
|
+
for (let i = 1; i <= maxSteps; i += 1) {
|
|
1290
|
+
const force = -cfg.stiffness * (x - to) - cfg.damping * v;
|
|
1291
|
+
v += force / cfg.mass * subDt;
|
|
1292
|
+
x += v * subDt;
|
|
1293
|
+
if (!Number.isFinite(x) || !Number.isFinite(v)) {
|
|
1294
|
+
values.push(to);
|
|
1295
|
+
break;
|
|
1296
|
+
}
|
|
1297
|
+
if (i % SAMPLE_STRIDE === 0) values.push(x);
|
|
1298
|
+
const atRest = Math.abs(to - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
|
|
1299
|
+
if (atRest) break;
|
|
1300
|
+
}
|
|
1301
|
+
if (values[values.length - 1] !== to) values.push(to);
|
|
1302
|
+
return {
|
|
1303
|
+
values,
|
|
1304
|
+
stepMs,
|
|
1305
|
+
durationMs: (values.length - 1) * stepMs
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
1308
|
+
function sampleTweenSettle(from, to, durationMs, easing) {
|
|
1309
|
+
const count = Math.max(2, Math.min(60, Math.round(durationMs / 16)));
|
|
1310
|
+
const values = [];
|
|
1311
|
+
for (let i = 0; i <= count; i += 1) {
|
|
1312
|
+
const t = i / count;
|
|
1313
|
+
values.push(from + (to - from) * easing(t));
|
|
1314
|
+
}
|
|
1315
|
+
values[values.length - 1] = to;
|
|
1316
|
+
return {
|
|
1317
|
+
values,
|
|
1318
|
+
stepMs: durationMs / count,
|
|
1319
|
+
durationMs
|
|
1320
|
+
};
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1666
1323
|
// src/core/controllers/animation-runner.ts
|
|
1667
1324
|
var DEFAULT_DURATION2 = 220;
|
|
1668
1325
|
var VELOCITY_PX_PER_S = 1e3;
|
|
@@ -1672,6 +1329,10 @@ var AnimationRunner = class {
|
|
|
1672
1329
|
applySizeFn;
|
|
1673
1330
|
getSize;
|
|
1674
1331
|
isDragging;
|
|
1332
|
+
applyAux;
|
|
1333
|
+
getTransformFor;
|
|
1334
|
+
settleWaapi;
|
|
1335
|
+
currentWaapi = null;
|
|
1675
1336
|
animationKind;
|
|
1676
1337
|
springConfig;
|
|
1677
1338
|
duration;
|
|
@@ -1688,6 +1349,9 @@ var AnimationRunner = class {
|
|
|
1688
1349
|
this.applySizeFn = deps.applySize;
|
|
1689
1350
|
this.getSize = deps.getSize;
|
|
1690
1351
|
this.isDragging = deps.isDragging;
|
|
1352
|
+
this.applyAux = deps.applyAux;
|
|
1353
|
+
this.getTransformFor = deps.getTransformFor;
|
|
1354
|
+
this.settleWaapi = opts.settleAnimation === "waapi";
|
|
1691
1355
|
const preset = resolveAnimationPreset(opts.animation);
|
|
1692
1356
|
this.animationKind = preset.kind;
|
|
1693
1357
|
this.duration = opts.duration ?? preset.duration ?? DEFAULT_DURATION2;
|
|
@@ -1712,11 +1376,20 @@ var AnimationRunner = class {
|
|
|
1712
1376
|
}
|
|
1713
1377
|
}
|
|
1714
1378
|
get isAnimating() {
|
|
1715
|
-
return this.currentTween !== null || this.currentSpring !== null;
|
|
1379
|
+
return this.currentTween !== null || this.currentSpring !== null || this.currentWaapi !== null;
|
|
1716
1380
|
}
|
|
1717
1381
|
cancel() {
|
|
1718
1382
|
this.currentTween?.cancel();
|
|
1719
1383
|
this.currentSpring?.cancel();
|
|
1384
|
+
if (this.currentWaapi) {
|
|
1385
|
+
const entry = this.currentWaapi;
|
|
1386
|
+
this.currentWaapi = null;
|
|
1387
|
+
entry.stop();
|
|
1388
|
+
try {
|
|
1389
|
+
entry.anim.cancel();
|
|
1390
|
+
} catch {
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1720
1393
|
}
|
|
1721
1394
|
async animateTo(target, velocityPxPerMs) {
|
|
1722
1395
|
if (target === this.getSize()) {
|
|
@@ -1735,7 +1408,28 @@ var AnimationRunner = class {
|
|
|
1735
1408
|
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1736
1409
|
return;
|
|
1737
1410
|
}
|
|
1738
|
-
if (this.
|
|
1411
|
+
if (this.settleWaapi && this.applyAux && this.getTransformFor && typeof this.element.animate === "function") {
|
|
1412
|
+
const samples = this.animationKind === "spring" ? sampleSpringSettle(
|
|
1413
|
+
this.getSize(),
|
|
1414
|
+
target,
|
|
1415
|
+
velocityPxPerMs * VELOCITY_PX_PER_S,
|
|
1416
|
+
this.springConfig
|
|
1417
|
+
) : sampleTweenSettle(
|
|
1418
|
+
this.getSize(),
|
|
1419
|
+
target,
|
|
1420
|
+
this.duration,
|
|
1421
|
+
this.easing
|
|
1422
|
+
);
|
|
1423
|
+
if (samples.values.length >= 2 && samples.durationMs > 0) {
|
|
1424
|
+
await this.runWaapiSettle(samples, target);
|
|
1425
|
+
if (!this.isAnimating) {
|
|
1426
|
+
this.getRootEl()?.removeAttribute("data-animating");
|
|
1427
|
+
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1428
|
+
}
|
|
1429
|
+
return;
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
if (this.animationKind === "spring") {
|
|
1739
1433
|
const spring = runSpring({
|
|
1740
1434
|
from: this.getSize(),
|
|
1741
1435
|
to: target,
|
|
@@ -1763,11 +1457,66 @@ var AnimationRunner = class {
|
|
|
1763
1457
|
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1764
1458
|
}
|
|
1765
1459
|
}
|
|
1460
|
+
async runWaapiSettle(samples, target) {
|
|
1461
|
+
const applyAux = this.applyAux;
|
|
1462
|
+
const getTransformFor = this.getTransformFor;
|
|
1463
|
+
const frames = samples.values.map((v) => ({
|
|
1464
|
+
transform: getTransformFor(v)
|
|
1465
|
+
}));
|
|
1466
|
+
const anim = this.element.animate(frames, {
|
|
1467
|
+
duration: samples.durationMs,
|
|
1468
|
+
easing: "linear",
|
|
1469
|
+
fill: "forwards"
|
|
1470
|
+
});
|
|
1471
|
+
let stopped = false;
|
|
1472
|
+
let auxRaf = 0;
|
|
1473
|
+
const start = performance.now();
|
|
1474
|
+
const lastIdx = samples.values.length - 1;
|
|
1475
|
+
const auxTick = () => {
|
|
1476
|
+
if (stopped) return;
|
|
1477
|
+
const elapsed = performance.now() - start;
|
|
1478
|
+
const idx = Math.min(Math.floor(elapsed / samples.stepMs), lastIdx);
|
|
1479
|
+
applyAux(samples.values[idx]);
|
|
1480
|
+
auxRaf = requestAnimationFrame(auxTick);
|
|
1481
|
+
};
|
|
1482
|
+
auxRaf = requestAnimationFrame(auxTick);
|
|
1483
|
+
const entry = {
|
|
1484
|
+
anim,
|
|
1485
|
+
stop: () => {
|
|
1486
|
+
stopped = true;
|
|
1487
|
+
cancelAnimationFrame(auxRaf);
|
|
1488
|
+
}
|
|
1489
|
+
};
|
|
1490
|
+
this.currentWaapi = entry;
|
|
1491
|
+
try {
|
|
1492
|
+
await anim.finished;
|
|
1493
|
+
} catch {
|
|
1494
|
+
}
|
|
1495
|
+
entry.stop();
|
|
1496
|
+
const wasCurrent = this.currentWaapi === entry;
|
|
1497
|
+
if (wasCurrent) this.currentWaapi = null;
|
|
1498
|
+
if (wasCurrent && anim.playState === "finished") {
|
|
1499
|
+
this.applySizeFn(target);
|
|
1500
|
+
try {
|
|
1501
|
+
anim.cancel();
|
|
1502
|
+
} catch {
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1766
1506
|
destroy() {
|
|
1767
1507
|
this.detachReducedMotion?.();
|
|
1768
1508
|
this.detachReducedMotion = null;
|
|
1769
1509
|
this.currentTween = null;
|
|
1770
1510
|
this.currentSpring = null;
|
|
1511
|
+
if (this.currentWaapi) {
|
|
1512
|
+
const entry = this.currentWaapi;
|
|
1513
|
+
this.currentWaapi = null;
|
|
1514
|
+
entry.stop();
|
|
1515
|
+
try {
|
|
1516
|
+
entry.anim.cancel();
|
|
1517
|
+
} catch {
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1771
1520
|
}
|
|
1772
1521
|
};
|
|
1773
1522
|
|
|
@@ -2625,7 +2374,7 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2625
2374
|
const initialAllowed = opts.allowed ?? opts.snapPoints.map((p) => p.id);
|
|
2626
2375
|
let initialId = opts.initial ?? initialAllowed[0] ?? opts.snapPoints[0]?.id ?? "default";
|
|
2627
2376
|
if (opts.persistKey) {
|
|
2628
|
-
const restored =
|
|
2377
|
+
const restored = readPersistedIdSafe(opts.persistKey);
|
|
2629
2378
|
if (restored && initialAllowed.includes(restored)) {
|
|
2630
2379
|
initialId = restored;
|
|
2631
2380
|
}
|
|
@@ -2656,6 +2405,7 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2656
2405
|
},
|
|
2657
2406
|
animation: {
|
|
2658
2407
|
animation: opts.animation,
|
|
2408
|
+
settleAnimation: opts.settleAnimation,
|
|
2659
2409
|
duration: opts.duration,
|
|
2660
2410
|
easing: opts.easing,
|
|
2661
2411
|
spring: opts.spring,
|
|
@@ -2673,6 +2423,15 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2673
2423
|
}
|
|
2674
2424
|
};
|
|
2675
2425
|
}
|
|
2426
|
+
var readPersistedIdSafe = (key) => {
|
|
2427
|
+
if (typeof window === "undefined") return null;
|
|
2428
|
+
if (typeof localStorage === "undefined") return null;
|
|
2429
|
+
try {
|
|
2430
|
+
return localStorage.getItem(key);
|
|
2431
|
+
} catch {
|
|
2432
|
+
return null;
|
|
2433
|
+
}
|
|
2434
|
+
};
|
|
2676
2435
|
|
|
2677
2436
|
// src/core/primitives/teardown-stack.ts
|
|
2678
2437
|
var TeardownStack = class {
|
|
@@ -2693,9 +2452,9 @@ var TeardownStack = class {
|
|
|
2693
2452
|
}
|
|
2694
2453
|
};
|
|
2695
2454
|
|
|
2696
|
-
// src/core/
|
|
2455
|
+
// src/core/BottomSheetCore.ts
|
|
2697
2456
|
var HAPTIC_DURATION_MS = 8;
|
|
2698
|
-
var
|
|
2457
|
+
var BottomSheetCore = class {
|
|
2699
2458
|
id = nextInstanceId("bs");
|
|
2700
2459
|
element;
|
|
2701
2460
|
handle;
|
|
@@ -2755,6 +2514,8 @@ var BottomSheetEngine = class {
|
|
|
2755
2514
|
stackEffectPrimed = false;
|
|
2756
2515
|
fitDeps;
|
|
2757
2516
|
transformTemplate;
|
|
2517
|
+
featureList = [];
|
|
2518
|
+
featureCtx;
|
|
2758
2519
|
constructor(opts) {
|
|
2759
2520
|
const resolved = resolveEngineOptions(opts, {
|
|
2760
2521
|
shouldApplyInertSiblings: () => {
|
|
@@ -2802,7 +2563,9 @@ var BottomSheetEngine = class {
|
|
|
2802
2563
|
getRootEl: () => this.rootEl,
|
|
2803
2564
|
applySize: (size) => this.applySize(size),
|
|
2804
2565
|
getSize: () => this.size,
|
|
2805
|
-
isDragging: () => this.gesture?.isDragging ?? false
|
|
2566
|
+
isDragging: () => this.gesture?.isDragging ?? false,
|
|
2567
|
+
applyAux: (size) => this.applySize(size, true),
|
|
2568
|
+
getTransformFor: (size) => this.transformTemplate(this.snaps.getMaxAxisSize() - size)
|
|
2806
2569
|
},
|
|
2807
2570
|
resolved.animation
|
|
2808
2571
|
);
|
|
@@ -2825,6 +2588,11 @@ var BottomSheetEngine = class {
|
|
|
2825
2588
|
if (opts.linkedSheets) {
|
|
2826
2589
|
this.linkedSheets = opts.linkedSheets;
|
|
2827
2590
|
}
|
|
2591
|
+
const byName = /* @__PURE__ */ new Map();
|
|
2592
|
+
for (const feature of opts.features ?? []) {
|
|
2593
|
+
byName.set(feature.name, feature);
|
|
2594
|
+
}
|
|
2595
|
+
this.featureList = Array.from(byName.values());
|
|
2828
2596
|
this.activeId = resolved.initialId;
|
|
2829
2597
|
auditVhUsage(this.snapPointsRaw);
|
|
2830
2598
|
this.auditDuplicateSnapIds(this.snapPointsRaw);
|
|
@@ -2861,6 +2629,7 @@ var BottomSheetEngine = class {
|
|
|
2861
2629
|
scrollContainer: this.scrollContainer,
|
|
2862
2630
|
getMaxAxisSize: () => this.snaps.getMaxAxisSize()
|
|
2863
2631
|
});
|
|
2632
|
+
this.featureCtx = this.buildFeatureContext(opts.autoCollapseAfter);
|
|
2864
2633
|
this.attach();
|
|
2865
2634
|
this.registerInStack();
|
|
2866
2635
|
if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
|
|
@@ -2869,12 +2638,7 @@ var BottomSheetEngine = class {
|
|
|
2869
2638
|
if (!entry.isIntersecting) continue;
|
|
2870
2639
|
if (this.destroyed) return;
|
|
2871
2640
|
this.snaps.recompute();
|
|
2872
|
-
|
|
2873
|
-
if (current) {
|
|
2874
|
-
this.size = current.size;
|
|
2875
|
-
this.applySize(this.size);
|
|
2876
|
-
this.updateAriaSlider();
|
|
2877
|
-
}
|
|
2641
|
+
this.healActiveSnap();
|
|
2878
2642
|
io.disconnect();
|
|
2879
2643
|
return;
|
|
2880
2644
|
}
|
|
@@ -2897,46 +2661,77 @@ var BottomSheetEngine = class {
|
|
|
2897
2661
|
if (resolved.radius !== void 0) this.setRadius(resolved.radius);
|
|
2898
2662
|
if (resolved.maxHeight !== void 0) this.setMaxHeight(resolved.maxHeight);
|
|
2899
2663
|
this.applyAutoAriaLabelledBy();
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
getSize: () => this.size,
|
|
2905
|
-
close: () => this.close()
|
|
2906
|
-
})
|
|
2907
|
-
);
|
|
2908
|
-
}
|
|
2909
|
-
if (this.persistKey) {
|
|
2910
|
-
this.teardowns.add(installPersist(this, this.persistKey));
|
|
2664
|
+
this.runFeatureStage("post");
|
|
2665
|
+
this.warnOrphanFeatureOptions();
|
|
2666
|
+
if (this.size > 0) {
|
|
2667
|
+
this.handleOpen();
|
|
2911
2668
|
}
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
resolveSnap: (id) => this.snaps.findById(id),
|
|
2920
|
-
snapTo: (id) => {
|
|
2921
|
-
void this.snapTo(id);
|
|
2922
|
-
},
|
|
2923
|
-
on: (event, fn) => this.on(event, fn)
|
|
2924
|
-
})
|
|
2925
|
-
);
|
|
2926
|
-
this.teardowns.add(
|
|
2927
|
-
installRoute({
|
|
2669
|
+
}
|
|
2670
|
+
buildFeatureContext(autoCollapseAfter) {
|
|
2671
|
+
return {
|
|
2672
|
+
element: this.element,
|
|
2673
|
+
scrollContainer: this.scrollContainer,
|
|
2674
|
+
sheetId: this.id,
|
|
2675
|
+
options: {
|
|
2928
2676
|
routedTo: this.routedTo,
|
|
2929
2677
|
closeOnBack: this.closeOnBack,
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
this.
|
|
2678
|
+
closeOnRouteChange: this.closeOnRouteChange,
|
|
2679
|
+
persistKey: this.persistKey,
|
|
2680
|
+
autoCollapseAfter
|
|
2681
|
+
},
|
|
2682
|
+
isDestroyed: () => this.destroyed,
|
|
2683
|
+
isDragging: () => this.gesture?.isDragging ?? false,
|
|
2684
|
+
isAnimating: () => this.animation.isAnimating,
|
|
2685
|
+
isTopSheet: () => this.isTopSheet,
|
|
2686
|
+
isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
|
|
2687
|
+
getSize: () => this.size,
|
|
2688
|
+
getActiveId: () => this.activeId,
|
|
2689
|
+
getAllowedIds: () => this.snaps.getAllowedIds().slice(),
|
|
2690
|
+
allowedIdsBySize: () => this.allowedIdsBySize(),
|
|
2691
|
+
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
2692
|
+
resolveSnap: (id) => this.snaps.findById(id),
|
|
2693
|
+
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
2694
|
+
setSize: (size) => {
|
|
2695
|
+
this.size = size;
|
|
2696
|
+
},
|
|
2697
|
+
setMaxAxisSize: (size) => {
|
|
2698
|
+
this.snaps.setMaxAxisSize(size);
|
|
2699
|
+
},
|
|
2700
|
+
applySize: (size) => this.applySize(size),
|
|
2701
|
+
recomputeSnaps: () => this.recomputeSnaps(),
|
|
2702
|
+
newCycle: () => {
|
|
2703
|
+
this.newCycle();
|
|
2704
|
+
},
|
|
2705
|
+
cancelInFlight: () => {
|
|
2706
|
+
this.animation.cancel();
|
|
2707
|
+
},
|
|
2708
|
+
resyncAfterResize: () => this.resyncAfterResize(),
|
|
2709
|
+
snapTo: (id) => {
|
|
2710
|
+
void this.snapTo(id);
|
|
2711
|
+
},
|
|
2712
|
+
close: (reason) => this.close(reason),
|
|
2713
|
+
on: (event, fn) => this.on(event, fn),
|
|
2714
|
+
addTeardown: (fn) => this.teardowns.add(fn)
|
|
2715
|
+
};
|
|
2716
|
+
}
|
|
2717
|
+
runFeatureStage(stage) {
|
|
2718
|
+
for (const feature of this.featureList) {
|
|
2719
|
+
if ((feature.stage ?? "post") !== stage) continue;
|
|
2720
|
+
const teardown = feature.install(this.featureCtx);
|
|
2721
|
+
if (teardown) this.teardowns.add(teardown);
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
warnOrphanFeatureOptions() {
|
|
2725
|
+
const names = new Set(this.featureList.map((f) => f.name));
|
|
2726
|
+
if ((this.closeOnBack || this.routedTo !== void 0 || this.closeOnRouteChange) && !names.has("route")) {
|
|
2727
|
+
devWarn(
|
|
2728
|
+
"[BottomSheet] closeOnBack/routedTo/closeOnRouteChange need routeFeature() \u2014 option ignored"
|
|
2729
|
+
);
|
|
2730
|
+
}
|
|
2731
|
+
if (this.persistKey && !names.has("persist")) {
|
|
2732
|
+
devWarn(
|
|
2733
|
+
"[BottomSheet] persistKey needs persistFeature() \u2014 snaps will not be saved"
|
|
2734
|
+
);
|
|
2940
2735
|
}
|
|
2941
2736
|
}
|
|
2942
2737
|
get state() {
|
|
@@ -3038,6 +2833,8 @@ var BottomSheetEngine = class {
|
|
|
3038
2833
|
const vt = document.startViewTransition(() => {
|
|
3039
2834
|
this.applySize(target.size);
|
|
3040
2835
|
});
|
|
2836
|
+
vt.ready?.catch(() => {
|
|
2837
|
+
});
|
|
3041
2838
|
this.currentViewTransition = vt;
|
|
3042
2839
|
try {
|
|
3043
2840
|
await vt.finished;
|
|
@@ -3289,11 +3086,16 @@ var BottomSheetEngine = class {
|
|
|
3289
3086
|
this.maxHeight.clampTo();
|
|
3290
3087
|
this.scrim.invalidateOpacityCache();
|
|
3291
3088
|
if (this.gesture?.isDragging) return;
|
|
3089
|
+
this.healActiveSnap();
|
|
3090
|
+
}
|
|
3091
|
+
healActiveSnap() {
|
|
3292
3092
|
const current = this.snaps.findById(this.activeId);
|
|
3293
|
-
if (current)
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3093
|
+
if (!current) return;
|
|
3094
|
+
this.size = current.size;
|
|
3095
|
+
this.applySize(this.size);
|
|
3096
|
+
this.updateAriaSlider();
|
|
3097
|
+
if (this.size > 0 && !this.lifecycle.isInstalled && !this.opening && !this.animation.isAnimating) {
|
|
3098
|
+
this.emitOpenSequence(this.activeId);
|
|
3297
3099
|
}
|
|
3298
3100
|
}
|
|
3299
3101
|
destroy() {
|
|
@@ -3472,18 +3274,7 @@ var BottomSheetEngine = class {
|
|
|
3472
3274
|
}
|
|
3473
3275
|
}
|
|
3474
3276
|
attachFeatures() {
|
|
3475
|
-
|
|
3476
|
-
this.teardowns.add(installContentSwipe({
|
|
3477
|
-
container: this.scrollContainer,
|
|
3478
|
-
isDragging: () => this.gesture?.isDragging ?? false,
|
|
3479
|
-
isAnimating: () => this.animation.isAnimating,
|
|
3480
|
-
getAllowedIds: () => this.allowedIdsBySize(),
|
|
3481
|
-
getActiveId: () => this.activeId,
|
|
3482
|
-
snapTo: (id) => {
|
|
3483
|
-
void this.snapTo(id);
|
|
3484
|
-
}
|
|
3485
|
-
}));
|
|
3486
|
-
}
|
|
3277
|
+
this.runFeatureStage("attach");
|
|
3487
3278
|
if (typeof window !== "undefined") {
|
|
3488
3279
|
this.teardowns.add(installResizeObserver({
|
|
3489
3280
|
element: this.element,
|
|
@@ -3523,31 +3314,6 @@ var BottomSheetEngine = class {
|
|
|
3523
3314
|
() => document.removeEventListener("keydown", onKey)
|
|
3524
3315
|
);
|
|
3525
3316
|
}
|
|
3526
|
-
this.teardowns.add(installVisualViewport({
|
|
3527
|
-
element: this.element,
|
|
3528
|
-
isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
|
|
3529
|
-
isDestroyed: () => this.destroyed,
|
|
3530
|
-
isDragging: () => this.gesture?.isDragging ?? false,
|
|
3531
|
-
recomputeSnaps: () => this.recomputeSnaps(),
|
|
3532
|
-
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
3533
|
-
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
3534
|
-
getSize: () => this.size,
|
|
3535
|
-
setMaxAxisSize: (size) => {
|
|
3536
|
-
this.snaps.setMaxAxisSize(size);
|
|
3537
|
-
},
|
|
3538
|
-
setSize: (size) => {
|
|
3539
|
-
this.size = size;
|
|
3540
|
-
},
|
|
3541
|
-
applySize: (size) => this.applySize(size),
|
|
3542
|
-
cancelInFlight: () => {
|
|
3543
|
-
this.animation.cancel();
|
|
3544
|
-
},
|
|
3545
|
-
newCycle: () => {
|
|
3546
|
-
this.newCycle();
|
|
3547
|
-
},
|
|
3548
|
-
isAnimating: () => this.animation.isAnimating,
|
|
3549
|
-
resyncAfterCancel: () => this.resyncAfterResize()
|
|
3550
|
-
}));
|
|
3551
3317
|
}
|
|
3552
3318
|
this.teardowns.add(installSliderKeyboard({
|
|
3553
3319
|
handle: this.handle,
|
|
@@ -3624,13 +3390,13 @@ var BottomSheetEngine = class {
|
|
|
3624
3390
|
}
|
|
3625
3391
|
}
|
|
3626
3392
|
}
|
|
3627
|
-
applySize(size) {
|
|
3393
|
+
applySize(size, skipTransform = false) {
|
|
3628
3394
|
const cap = this.snaps.getMaxAxisSize();
|
|
3629
3395
|
const clamped = cap > 0 && size > cap && !this.gesture?.isDragging && !this.allowOvershoot ? cap : size;
|
|
3630
3396
|
this.size = clamped;
|
|
3631
3397
|
const offset = cap - clamped;
|
|
3632
3398
|
const style = this.element.style;
|
|
3633
|
-
style.transform = this.transformTemplate(offset);
|
|
3399
|
+
if (!skipTransform) style.transform = this.transformTemplate(offset);
|
|
3634
3400
|
if (this.sizeWriteSentinel.shouldWrite(clamped, SIZE_WRITE_EPSILON)) {
|
|
3635
3401
|
style.setProperty("--bs-size", `${clamped}px`);
|
|
3636
3402
|
if (this.scrimParent) {
|
|
@@ -3708,6 +3474,514 @@ var BottomSheetEngine = class {
|
|
|
3708
3474
|
}
|
|
3709
3475
|
};
|
|
3710
3476
|
|
|
3477
|
+
// src/core/features/history-coordinator.ts
|
|
3478
|
+
var entries = [];
|
|
3479
|
+
var subscribers = /* @__PURE__ */ new Set();
|
|
3480
|
+
var suppress = 0;
|
|
3481
|
+
var internalDepth = 0;
|
|
3482
|
+
var pendingRebrands = [];
|
|
3483
|
+
var listenerInstalled = false;
|
|
3484
|
+
var patchInstalled = false;
|
|
3485
|
+
var origPushState = null;
|
|
3486
|
+
var origReplaceState = null;
|
|
3487
|
+
var patchedPushState = null;
|
|
3488
|
+
var patchedReplaceState = null;
|
|
3489
|
+
var hasWindow = () => typeof window !== "undefined";
|
|
3490
|
+
var hasHistory = () => typeof history !== "undefined";
|
|
3491
|
+
var brandMarker = (surface) => ({
|
|
3492
|
+
...surface.markerState(),
|
|
3493
|
+
__bs: true
|
|
3494
|
+
});
|
|
3495
|
+
var runInternal = (fn) => {
|
|
3496
|
+
internalDepth += 1;
|
|
3497
|
+
try {
|
|
3498
|
+
fn();
|
|
3499
|
+
} finally {
|
|
3500
|
+
internalDepth -= 1;
|
|
3501
|
+
}
|
|
3502
|
+
};
|
|
3503
|
+
var notifyRouteChange = () => {
|
|
3504
|
+
const snapshot = Array.from(subscribers);
|
|
3505
|
+
for (const fn of snapshot) fn();
|
|
3506
|
+
};
|
|
3507
|
+
var ensureListener = () => {
|
|
3508
|
+
if (listenerInstalled || !hasWindow()) return;
|
|
3509
|
+
window.addEventListener("popstate", onPopState);
|
|
3510
|
+
listenerInstalled = true;
|
|
3511
|
+
};
|
|
3512
|
+
var maybeTeardownListener = () => {
|
|
3513
|
+
if (!listenerInstalled) return;
|
|
3514
|
+
if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
|
|
3515
|
+
if (hasWindow()) window.removeEventListener("popstate", onPopState);
|
|
3516
|
+
listenerInstalled = false;
|
|
3517
|
+
};
|
|
3518
|
+
var installPatch = () => {
|
|
3519
|
+
if (patchInstalled || !hasHistory()) return;
|
|
3520
|
+
origPushState = history.pushState;
|
|
3521
|
+
origReplaceState = history.replaceState;
|
|
3522
|
+
patchedPushState = function(...args) {
|
|
3523
|
+
origPushState.apply(this, args);
|
|
3524
|
+
if (internalDepth === 0) notifyRouteChange();
|
|
3525
|
+
};
|
|
3526
|
+
patchedReplaceState = function(...args) {
|
|
3527
|
+
origReplaceState.apply(this, args);
|
|
3528
|
+
if (internalDepth === 0) notifyRouteChange();
|
|
3529
|
+
};
|
|
3530
|
+
history.pushState = patchedPushState;
|
|
3531
|
+
history.replaceState = patchedReplaceState;
|
|
3532
|
+
patchInstalled = true;
|
|
3533
|
+
};
|
|
3534
|
+
var removePatch = () => {
|
|
3535
|
+
if (!patchInstalled) return;
|
|
3536
|
+
if (history.pushState === patchedPushState && origPushState) {
|
|
3537
|
+
history.pushState = origPushState;
|
|
3538
|
+
}
|
|
3539
|
+
if (history.replaceState === patchedReplaceState && origReplaceState) {
|
|
3540
|
+
history.replaceState = origReplaceState;
|
|
3541
|
+
}
|
|
3542
|
+
origPushState = null;
|
|
3543
|
+
origReplaceState = null;
|
|
3544
|
+
patchedPushState = null;
|
|
3545
|
+
patchedReplaceState = null;
|
|
3546
|
+
patchInstalled = false;
|
|
3547
|
+
};
|
|
3548
|
+
function onPopState() {
|
|
3549
|
+
if (suppress > 0) {
|
|
3550
|
+
suppress -= 1;
|
|
3551
|
+
const rebrand = pendingRebrands.shift();
|
|
3552
|
+
if (rebrand) rebrand();
|
|
3553
|
+
maybeTeardownListener();
|
|
3554
|
+
return;
|
|
3555
|
+
}
|
|
3556
|
+
if (entries.length === 0) {
|
|
3557
|
+
notifyRouteChange();
|
|
3558
|
+
maybeTeardownListener();
|
|
3559
|
+
return;
|
|
3560
|
+
}
|
|
3561
|
+
let target = null;
|
|
3562
|
+
let targetIdx = -1;
|
|
3563
|
+
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
3564
|
+
const entry = entries[i];
|
|
3565
|
+
if (!entry.surface.isOpen()) continue;
|
|
3566
|
+
if (!target) {
|
|
3567
|
+
target = entry;
|
|
3568
|
+
targetIdx = i;
|
|
3569
|
+
}
|
|
3570
|
+
if (entry.surface.isTop()) {
|
|
3571
|
+
target = entry;
|
|
3572
|
+
targetIdx = i;
|
|
3573
|
+
break;
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
3576
|
+
if (!target) {
|
|
3577
|
+
const removed = entries.pop();
|
|
3578
|
+
if (removed) removed.live = false;
|
|
3579
|
+
maybeTeardownListener();
|
|
3580
|
+
return;
|
|
3581
|
+
}
|
|
3582
|
+
target.live = false;
|
|
3583
|
+
entries.splice(targetIdx, 1);
|
|
3584
|
+
const settled = target;
|
|
3585
|
+
void Promise.resolve(settled.surface.close()).then(() => {
|
|
3586
|
+
if (settled.surface.isOpen()) restore(settled);
|
|
3587
|
+
});
|
|
3588
|
+
maybeTeardownListener();
|
|
3589
|
+
}
|
|
3590
|
+
function restore(entry) {
|
|
3591
|
+
if (!hasWindow() || !hasHistory()) return;
|
|
3592
|
+
entry.live = true;
|
|
3593
|
+
runInternal(() => {
|
|
3594
|
+
try {
|
|
3595
|
+
history.pushState(brandMarker(entry.surface), "", entry.surface.url);
|
|
3596
|
+
} catch {
|
|
3597
|
+
entry.live = false;
|
|
3598
|
+
}
|
|
3599
|
+
});
|
|
3600
|
+
if (entry.live) {
|
|
3601
|
+
entries.push(entry);
|
|
3602
|
+
ensureListener();
|
|
3603
|
+
}
|
|
3604
|
+
}
|
|
3605
|
+
function pushBackMarker(surface) {
|
|
3606
|
+
const entry = { surface, priorUrl: void 0, live: false };
|
|
3607
|
+
if (!hasWindow() || !hasHistory()) {
|
|
3608
|
+
return entry;
|
|
3609
|
+
}
|
|
3610
|
+
entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
|
|
3611
|
+
runInternal(() => {
|
|
3612
|
+
try {
|
|
3613
|
+
history.pushState(brandMarker(surface), "", surface.url);
|
|
3614
|
+
entry.live = true;
|
|
3615
|
+
} catch {
|
|
3616
|
+
entry.live = false;
|
|
3617
|
+
}
|
|
3618
|
+
});
|
|
3619
|
+
if (entry.live) {
|
|
3620
|
+
entries.push(entry);
|
|
3621
|
+
ensureListener();
|
|
3622
|
+
}
|
|
3623
|
+
return entry;
|
|
3624
|
+
}
|
|
3625
|
+
function popBackMarker(handle) {
|
|
3626
|
+
if (!hasWindow() || !hasHistory()) return;
|
|
3627
|
+
const entry = handle;
|
|
3628
|
+
const idx = entries.indexOf(entry);
|
|
3629
|
+
if (idx === -1 || !entry.live) return;
|
|
3630
|
+
const last = entries.length - 1;
|
|
3631
|
+
entry.live = false;
|
|
3632
|
+
entries.splice(idx, 1);
|
|
3633
|
+
let rebrand = null;
|
|
3634
|
+
if (idx !== last) {
|
|
3635
|
+
const rebrandSurface = entries[entries.length - 1].surface;
|
|
3636
|
+
const rebrandUrl = entry.priorUrl;
|
|
3637
|
+
rebrand = () => {
|
|
3638
|
+
runInternal(() => {
|
|
3639
|
+
history.replaceState(
|
|
3640
|
+
brandMarker(rebrandSurface),
|
|
3641
|
+
"",
|
|
3642
|
+
rebrandUrl !== void 0 ? rebrandUrl : location.href
|
|
3643
|
+
);
|
|
3644
|
+
});
|
|
3645
|
+
};
|
|
3646
|
+
}
|
|
3647
|
+
pendingRebrands.push(rebrand);
|
|
3648
|
+
suppress += 1;
|
|
3649
|
+
runInternal(() => {
|
|
3650
|
+
try {
|
|
3651
|
+
history.back();
|
|
3652
|
+
} catch {
|
|
3653
|
+
suppress = Math.max(0, suppress - 1);
|
|
3654
|
+
pendingRebrands.pop();
|
|
3655
|
+
}
|
|
3656
|
+
});
|
|
3657
|
+
maybeTeardownListener();
|
|
3658
|
+
}
|
|
3659
|
+
function subscribeRouteChange(fn) {
|
|
3660
|
+
if (!hasWindow() || !hasHistory()) return () => {
|
|
3661
|
+
};
|
|
3662
|
+
subscribers.add(fn);
|
|
3663
|
+
if (subscribers.size === 1) installPatch();
|
|
3664
|
+
ensureListener();
|
|
3665
|
+
return () => {
|
|
3666
|
+
if (!subscribers.has(fn)) return;
|
|
3667
|
+
subscribers.delete(fn);
|
|
3668
|
+
if (subscribers.size === 0) removePatch();
|
|
3669
|
+
maybeTeardownListener();
|
|
3670
|
+
};
|
|
3671
|
+
}
|
|
3672
|
+
|
|
3673
|
+
// src/core/features/route.ts
|
|
3674
|
+
function installRoute(deps) {
|
|
3675
|
+
if (typeof window === "undefined") {
|
|
3676
|
+
return () => {
|
|
3677
|
+
};
|
|
3678
|
+
}
|
|
3679
|
+
if (!deps.routedTo && !deps.closeOnBack) {
|
|
3680
|
+
return () => {
|
|
3681
|
+
};
|
|
3682
|
+
}
|
|
3683
|
+
let handle = null;
|
|
3684
|
+
const onOpen = () => {
|
|
3685
|
+
if (handle) return;
|
|
3686
|
+
handle = pushBackMarker({
|
|
3687
|
+
isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
|
|
3688
|
+
isTop: deps.isTopSheet,
|
|
3689
|
+
close: deps.close,
|
|
3690
|
+
markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
|
|
3691
|
+
url: deps.routedTo
|
|
3692
|
+
});
|
|
3693
|
+
};
|
|
3694
|
+
const onClose = () => {
|
|
3695
|
+
if (!handle) return;
|
|
3696
|
+
popBackMarker(handle);
|
|
3697
|
+
handle = null;
|
|
3698
|
+
};
|
|
3699
|
+
const unsubscribeOpen = deps.on("open", onOpen);
|
|
3700
|
+
const unsubscribeClose = deps.on("close", onClose);
|
|
3701
|
+
if (deps.getSize() > 0) onOpen();
|
|
3702
|
+
return () => {
|
|
3703
|
+
unsubscribeOpen();
|
|
3704
|
+
unsubscribeClose();
|
|
3705
|
+
if (handle) {
|
|
3706
|
+
popBackMarker(handle);
|
|
3707
|
+
handle = null;
|
|
3708
|
+
}
|
|
3709
|
+
};
|
|
3710
|
+
}
|
|
3711
|
+
function installRouteChange(deps) {
|
|
3712
|
+
return subscribeRouteChange(() => {
|
|
3713
|
+
if (deps.isDestroyed() || deps.getSize() <= 0) return;
|
|
3714
|
+
void deps.close();
|
|
3715
|
+
});
|
|
3716
|
+
}
|
|
3717
|
+
|
|
3718
|
+
// src/core/features/persist.ts
|
|
3719
|
+
function installPersist(engine, key) {
|
|
3720
|
+
const unsubscribe = engine.on("snap", ({ id }) => {
|
|
3721
|
+
if (typeof window === "undefined") return;
|
|
3722
|
+
if (typeof localStorage === "undefined") return;
|
|
3723
|
+
try {
|
|
3724
|
+
localStorage.setItem(key, id);
|
|
3725
|
+
} catch {
|
|
3726
|
+
}
|
|
3727
|
+
});
|
|
3728
|
+
return unsubscribe;
|
|
3729
|
+
}
|
|
3730
|
+
|
|
3731
|
+
// src/core/features/auto-collapse.ts
|
|
3732
|
+
function installAutoCollapse(deps) {
|
|
3733
|
+
const { ms } = deps;
|
|
3734
|
+
if (ms === void 0 || ms <= 0) {
|
|
3735
|
+
return () => {
|
|
3736
|
+
};
|
|
3737
|
+
}
|
|
3738
|
+
let timer = null;
|
|
3739
|
+
const clearTimer = () => {
|
|
3740
|
+
if (timer !== null) {
|
|
3741
|
+
clearTimeout(timer);
|
|
3742
|
+
timer = null;
|
|
3743
|
+
}
|
|
3744
|
+
};
|
|
3745
|
+
const fire = () => {
|
|
3746
|
+
if (deps.isDestroyed()) return;
|
|
3747
|
+
if (deps.isDragging()) return;
|
|
3748
|
+
const active = deps.resolveSnap(deps.getActiveId());
|
|
3749
|
+
if (!active || active.size === 0) return;
|
|
3750
|
+
let target = null;
|
|
3751
|
+
for (const id of deps.getAllowedIds()) {
|
|
3752
|
+
const snap = deps.resolveSnap(id);
|
|
3753
|
+
if (!snap || snap.size <= 0) continue;
|
|
3754
|
+
if (!target || snap.size < target.size) target = snap;
|
|
3755
|
+
}
|
|
3756
|
+
if (!target) return;
|
|
3757
|
+
if (target.id === active.id || target.size >= active.size) return;
|
|
3758
|
+
deps.snapTo(target.id);
|
|
3759
|
+
};
|
|
3760
|
+
const reset = () => {
|
|
3761
|
+
clearTimer();
|
|
3762
|
+
if (deps.isDestroyed()) return;
|
|
3763
|
+
timer = setTimeout(() => {
|
|
3764
|
+
timer = null;
|
|
3765
|
+
fire();
|
|
3766
|
+
}, ms);
|
|
3767
|
+
};
|
|
3768
|
+
const unsubscribe = deps.on("snap", () => reset());
|
|
3769
|
+
if ((deps.resolveSnap(deps.getActiveId())?.size ?? 0) > 0) reset();
|
|
3770
|
+
return () => {
|
|
3771
|
+
clearTimer();
|
|
3772
|
+
unsubscribe();
|
|
3773
|
+
};
|
|
3774
|
+
}
|
|
3775
|
+
|
|
3776
|
+
// src/core/features/content-swipe.ts
|
|
3777
|
+
var CONTENT_PULL_THRESHOLD = 60;
|
|
3778
|
+
function installContentSwipe(deps) {
|
|
3779
|
+
const { container } = deps;
|
|
3780
|
+
let startY = 0;
|
|
3781
|
+
let startScrollTop = 0;
|
|
3782
|
+
let moved = false;
|
|
3783
|
+
const onTouchStart = (e) => {
|
|
3784
|
+
const t = e.touches[0];
|
|
3785
|
+
if (!t) return;
|
|
3786
|
+
startY = t.clientY;
|
|
3787
|
+
startScrollTop = container.scrollTop;
|
|
3788
|
+
moved = false;
|
|
3789
|
+
};
|
|
3790
|
+
const onTouchMove = (e) => {
|
|
3791
|
+
const t = e.touches[0];
|
|
3792
|
+
if (!t) return;
|
|
3793
|
+
if (Math.abs(t.clientY - startY) > CONTENT_PULL_THRESHOLD) moved = true;
|
|
3794
|
+
};
|
|
3795
|
+
const onTouchEnd = (e) => {
|
|
3796
|
+
if (!moved) return;
|
|
3797
|
+
if (deps.isDragging() || deps.isAnimating()) return;
|
|
3798
|
+
if (container.scrollTop !== startScrollTop) return;
|
|
3799
|
+
const t = e.changedTouches[0];
|
|
3800
|
+
if (!t) return;
|
|
3801
|
+
const deltaY = t.clientY - startY;
|
|
3802
|
+
const atTop = container.scrollTop <= 0;
|
|
3803
|
+
const allowed = deps.getAllowedIds();
|
|
3804
|
+
const idx = allowed.indexOf(deps.getActiveId());
|
|
3805
|
+
if (idx === -1) return;
|
|
3806
|
+
if (atTop && deltaY > CONTENT_PULL_THRESHOLD && idx > 0) {
|
|
3807
|
+
deps.snapTo(allowed[idx - 1]);
|
|
3808
|
+
} else if (deltaY < -CONTENT_PULL_THRESHOLD && idx < allowed.length - 1) {
|
|
3809
|
+
deps.snapTo(allowed[idx + 1]);
|
|
3810
|
+
}
|
|
3811
|
+
};
|
|
3812
|
+
container.addEventListener("touchstart", onTouchStart, { passive: true });
|
|
3813
|
+
container.addEventListener("touchmove", onTouchMove, { passive: true });
|
|
3814
|
+
container.addEventListener("touchend", onTouchEnd, { passive: true });
|
|
3815
|
+
return () => {
|
|
3816
|
+
container.removeEventListener("touchstart", onTouchStart);
|
|
3817
|
+
container.removeEventListener("touchmove", onTouchMove);
|
|
3818
|
+
container.removeEventListener("touchend", onTouchEnd);
|
|
3819
|
+
};
|
|
3820
|
+
}
|
|
3821
|
+
|
|
3822
|
+
// src/core/features/visual-viewport.ts
|
|
3823
|
+
var SAFETY_PAD = 8;
|
|
3824
|
+
function installVisualViewport(deps) {
|
|
3825
|
+
if (typeof window === "undefined" || !window.visualViewport) {
|
|
3826
|
+
return () => {
|
|
3827
|
+
};
|
|
3828
|
+
}
|
|
3829
|
+
const vv = window.visualViewport;
|
|
3830
|
+
let rafId = null;
|
|
3831
|
+
const onResize = () => {
|
|
3832
|
+
if (rafId !== null) return;
|
|
3833
|
+
rafId = requestAnimationFrame(() => {
|
|
3834
|
+
rafId = null;
|
|
3835
|
+
if (deps.isDestroyed()) return;
|
|
3836
|
+
deps.recomputeSnaps();
|
|
3837
|
+
const isVertical = deps.isVerticalAxis();
|
|
3838
|
+
const visible = isVertical ? vv.height : vv.width;
|
|
3839
|
+
const windowSize = isVertical ? window.innerHeight : window.innerWidth;
|
|
3840
|
+
const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
|
|
3841
|
+
if (clamp < deps.getMaxAxisSize()) {
|
|
3842
|
+
deps.setMaxAxisSize(clamp);
|
|
3843
|
+
}
|
|
3844
|
+
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
3845
|
+
deps.cancelInFlight();
|
|
3846
|
+
deps.newCycle();
|
|
3847
|
+
const max = deps.getMaxAxisSize();
|
|
3848
|
+
deps.setSize(Math.min(deps.getSize(), max));
|
|
3849
|
+
const current = deps.resolveActiveSnap();
|
|
3850
|
+
if (current && !deps.isDragging()) {
|
|
3851
|
+
deps.applySize(Math.min(current.size, max));
|
|
3852
|
+
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
3853
|
+
} else {
|
|
3854
|
+
deps.applySize(deps.getSize());
|
|
3855
|
+
}
|
|
3856
|
+
});
|
|
3857
|
+
};
|
|
3858
|
+
vv.addEventListener("resize", onResize);
|
|
3859
|
+
return () => {
|
|
3860
|
+
vv.removeEventListener("resize", onResize);
|
|
3861
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
3862
|
+
};
|
|
3863
|
+
}
|
|
3864
|
+
|
|
3865
|
+
// src/core/features/engine-features.ts
|
|
3866
|
+
function routeFeature() {
|
|
3867
|
+
return {
|
|
3868
|
+
name: "route",
|
|
3869
|
+
install: (ctx) => {
|
|
3870
|
+
const teardowns = new TeardownStack();
|
|
3871
|
+
if (ctx.options.closeOnRouteChange) {
|
|
3872
|
+
teardowns.add(
|
|
3873
|
+
installRouteChange({
|
|
3874
|
+
isDestroyed: ctx.isDestroyed,
|
|
3875
|
+
getSize: ctx.getSize,
|
|
3876
|
+
close: () => ctx.close()
|
|
3877
|
+
})
|
|
3878
|
+
);
|
|
3879
|
+
}
|
|
3880
|
+
teardowns.add(
|
|
3881
|
+
installRoute({
|
|
3882
|
+
routedTo: ctx.options.routedTo,
|
|
3883
|
+
closeOnBack: ctx.options.closeOnBack,
|
|
3884
|
+
isTopSheet: ctx.isTopSheet,
|
|
3885
|
+
getSize: ctx.getSize,
|
|
3886
|
+
isDestroyed: ctx.isDestroyed,
|
|
3887
|
+
close: () => ctx.close("back"),
|
|
3888
|
+
on: ctx.on,
|
|
3889
|
+
sheetId: ctx.sheetId
|
|
3890
|
+
})
|
|
3891
|
+
);
|
|
3892
|
+
return () => teardowns.drain();
|
|
3893
|
+
}
|
|
3894
|
+
};
|
|
3895
|
+
}
|
|
3896
|
+
function persistFeature() {
|
|
3897
|
+
return {
|
|
3898
|
+
name: "persist",
|
|
3899
|
+
install: (ctx) => {
|
|
3900
|
+
const key = ctx.options.persistKey;
|
|
3901
|
+
if (!key) return;
|
|
3902
|
+
return installPersist({ on: ctx.on }, key);
|
|
3903
|
+
}
|
|
3904
|
+
};
|
|
3905
|
+
}
|
|
3906
|
+
function autoCollapseFeature() {
|
|
3907
|
+
return {
|
|
3908
|
+
name: "auto-collapse",
|
|
3909
|
+
install: (ctx) => installAutoCollapse({
|
|
3910
|
+
ms: ctx.options.autoCollapseAfter,
|
|
3911
|
+
isDestroyed: ctx.isDestroyed,
|
|
3912
|
+
isDragging: ctx.isDragging,
|
|
3913
|
+
getAllowedIds: ctx.getAllowedIds,
|
|
3914
|
+
getActiveId: ctx.getActiveId,
|
|
3915
|
+
resolveSnap: ctx.resolveSnap,
|
|
3916
|
+
snapTo: ctx.snapTo,
|
|
3917
|
+
on: ctx.on
|
|
3918
|
+
})
|
|
3919
|
+
};
|
|
3920
|
+
}
|
|
3921
|
+
function contentSwipeFeature() {
|
|
3922
|
+
return {
|
|
3923
|
+
name: "content-swipe",
|
|
3924
|
+
stage: "attach",
|
|
3925
|
+
install: (ctx) => {
|
|
3926
|
+
if (!ctx.scrollContainer) return;
|
|
3927
|
+
return installContentSwipe({
|
|
3928
|
+
container: ctx.scrollContainer,
|
|
3929
|
+
isDragging: ctx.isDragging,
|
|
3930
|
+
isAnimating: ctx.isAnimating,
|
|
3931
|
+
getAllowedIds: ctx.allowedIdsBySize,
|
|
3932
|
+
getActiveId: ctx.getActiveId,
|
|
3933
|
+
snapTo: ctx.snapTo
|
|
3934
|
+
});
|
|
3935
|
+
}
|
|
3936
|
+
};
|
|
3937
|
+
}
|
|
3938
|
+
function visualViewportFeature() {
|
|
3939
|
+
return {
|
|
3940
|
+
name: "visual-viewport",
|
|
3941
|
+
install: (ctx) => {
|
|
3942
|
+
if (typeof window === "undefined") return;
|
|
3943
|
+
return installVisualViewport({
|
|
3944
|
+
element: ctx.element,
|
|
3945
|
+
isVerticalAxis: ctx.isVerticalAxis,
|
|
3946
|
+
isDestroyed: ctx.isDestroyed,
|
|
3947
|
+
isDragging: ctx.isDragging,
|
|
3948
|
+
recomputeSnaps: ctx.recomputeSnaps,
|
|
3949
|
+
resolveActiveSnap: ctx.resolveActiveSnap,
|
|
3950
|
+
getMaxAxisSize: ctx.getMaxAxisSize,
|
|
3951
|
+
getSize: ctx.getSize,
|
|
3952
|
+
setMaxAxisSize: ctx.setMaxAxisSize,
|
|
3953
|
+
setSize: ctx.setSize,
|
|
3954
|
+
applySize: ctx.applySize,
|
|
3955
|
+
cancelInFlight: ctx.cancelInFlight,
|
|
3956
|
+
newCycle: ctx.newCycle,
|
|
3957
|
+
isAnimating: ctx.isAnimating,
|
|
3958
|
+
resyncAfterCancel: ctx.resyncAfterResize
|
|
3959
|
+
});
|
|
3960
|
+
}
|
|
3961
|
+
};
|
|
3962
|
+
}
|
|
3963
|
+
|
|
3964
|
+
// src/core/default-features.ts
|
|
3965
|
+
function defaultEngineFeatures() {
|
|
3966
|
+
return [
|
|
3967
|
+
contentSwipeFeature(),
|
|
3968
|
+
visualViewportFeature(),
|
|
3969
|
+
persistFeature(),
|
|
3970
|
+
autoCollapseFeature(),
|
|
3971
|
+
routeFeature()
|
|
3972
|
+
];
|
|
3973
|
+
}
|
|
3974
|
+
|
|
3975
|
+
// src/core/BottomSheetEngine.ts
|
|
3976
|
+
var BottomSheetEngine = class extends BottomSheetCore {
|
|
3977
|
+
constructor(opts) {
|
|
3978
|
+
super({
|
|
3979
|
+
...opts,
|
|
3980
|
+
features: [...defaultEngineFeatures(), ...opts.features ?? []]
|
|
3981
|
+
});
|
|
3982
|
+
}
|
|
3983
|
+
};
|
|
3984
|
+
|
|
3711
3985
|
// src/core/features/teleport.ts
|
|
3712
3986
|
var resolveTeleportTarget = (target) => {
|
|
3713
3987
|
if (!target) return null;
|