@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/qwik.cjs
CHANGED
|
@@ -351,74 +351,6 @@ var SnapResolver = class {
|
|
|
351
351
|
}
|
|
352
352
|
};
|
|
353
353
|
|
|
354
|
-
// src/core/features/persist.ts
|
|
355
|
-
function readPersistedId(key) {
|
|
356
|
-
if (!key) return null;
|
|
357
|
-
if (typeof window === "undefined") return null;
|
|
358
|
-
if (typeof localStorage === "undefined") return null;
|
|
359
|
-
try {
|
|
360
|
-
return localStorage.getItem(key);
|
|
361
|
-
} catch {
|
|
362
|
-
return null;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
function installPersist(engine, key) {
|
|
366
|
-
const unsubscribe = engine.on("snap", ({ id }) => {
|
|
367
|
-
if (typeof window === "undefined") return;
|
|
368
|
-
if (typeof localStorage === "undefined") return;
|
|
369
|
-
try {
|
|
370
|
-
localStorage.setItem(key, id);
|
|
371
|
-
} catch {
|
|
372
|
-
}
|
|
373
|
-
});
|
|
374
|
-
return unsubscribe;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// src/core/features/auto-collapse.ts
|
|
378
|
-
function installAutoCollapse(deps) {
|
|
379
|
-
const { ms } = deps;
|
|
380
|
-
if (ms === void 0 || ms <= 0) {
|
|
381
|
-
return () => {
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
let timer = null;
|
|
385
|
-
const clearTimer = () => {
|
|
386
|
-
if (timer !== null) {
|
|
387
|
-
clearTimeout(timer);
|
|
388
|
-
timer = null;
|
|
389
|
-
}
|
|
390
|
-
};
|
|
391
|
-
const fire = () => {
|
|
392
|
-
if (deps.isDestroyed()) return;
|
|
393
|
-
if (deps.isDragging()) return;
|
|
394
|
-
const active = deps.resolveSnap(deps.getActiveId());
|
|
395
|
-
if (!active || active.size === 0) return;
|
|
396
|
-
let target = null;
|
|
397
|
-
for (const id of deps.getAllowedIds()) {
|
|
398
|
-
const snap = deps.resolveSnap(id);
|
|
399
|
-
if (!snap || snap.size <= 0) continue;
|
|
400
|
-
if (!target || snap.size < target.size) target = snap;
|
|
401
|
-
}
|
|
402
|
-
if (!target) return;
|
|
403
|
-
if (target.id === active.id || target.size >= active.size) return;
|
|
404
|
-
deps.snapTo(target.id);
|
|
405
|
-
};
|
|
406
|
-
const reset = () => {
|
|
407
|
-
clearTimer();
|
|
408
|
-
if (deps.isDestroyed()) return;
|
|
409
|
-
timer = setTimeout(() => {
|
|
410
|
-
timer = null;
|
|
411
|
-
fire();
|
|
412
|
-
}, ms);
|
|
413
|
-
};
|
|
414
|
-
const unsubscribe = deps.on("snap", () => reset());
|
|
415
|
-
if ((deps.resolveSnap(deps.getActiveId())?.size ?? 0) > 0) reset();
|
|
416
|
-
return () => {
|
|
417
|
-
clearTimer();
|
|
418
|
-
unsubscribe();
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
|
|
422
354
|
// src/core/features/linked-sheets.ts
|
|
423
355
|
function notifyLinkedSheets(sheets, self) {
|
|
424
356
|
if (sheets.length === 0) return;
|
|
@@ -441,390 +373,65 @@ function notifyLinkedSheets(sheets, self) {
|
|
|
441
373
|
}
|
|
442
374
|
}
|
|
443
375
|
|
|
444
|
-
// src/core/features/
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
var pendingRebrand = null;
|
|
450
|
-
var listenerInstalled = false;
|
|
451
|
-
var patchInstalled = false;
|
|
452
|
-
var origPushState = null;
|
|
453
|
-
var origReplaceState = null;
|
|
454
|
-
var patchedPushState = null;
|
|
455
|
-
var patchedReplaceState = null;
|
|
456
|
-
var hasWindow = () => typeof window !== "undefined";
|
|
457
|
-
var hasHistory = () => typeof history !== "undefined";
|
|
458
|
-
var runInternal = (fn) => {
|
|
459
|
-
internalDepth += 1;
|
|
460
|
-
try {
|
|
461
|
-
fn();
|
|
462
|
-
} finally {
|
|
463
|
-
internalDepth -= 1;
|
|
464
|
-
}
|
|
465
|
-
};
|
|
466
|
-
var notifyRouteChange = () => {
|
|
467
|
-
const snapshot = Array.from(subscribers);
|
|
468
|
-
for (const fn of snapshot) fn();
|
|
469
|
-
};
|
|
470
|
-
var ensureListener = () => {
|
|
471
|
-
if (listenerInstalled || !hasWindow()) return;
|
|
472
|
-
window.addEventListener("popstate", onPopState);
|
|
473
|
-
listenerInstalled = true;
|
|
474
|
-
};
|
|
475
|
-
var maybeTeardownListener = () => {
|
|
476
|
-
if (!listenerInstalled) return;
|
|
477
|
-
if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
|
|
478
|
-
if (hasWindow()) window.removeEventListener("popstate", onPopState);
|
|
479
|
-
listenerInstalled = false;
|
|
480
|
-
};
|
|
481
|
-
var installPatch = () => {
|
|
482
|
-
if (patchInstalled || !hasHistory()) return;
|
|
483
|
-
origPushState = history.pushState;
|
|
484
|
-
origReplaceState = history.replaceState;
|
|
485
|
-
patchedPushState = function(...args) {
|
|
486
|
-
origPushState.apply(this, args);
|
|
487
|
-
if (internalDepth === 0) notifyRouteChange();
|
|
488
|
-
};
|
|
489
|
-
patchedReplaceState = function(...args) {
|
|
490
|
-
origReplaceState.apply(this, args);
|
|
491
|
-
if (internalDepth === 0) notifyRouteChange();
|
|
492
|
-
};
|
|
493
|
-
history.pushState = patchedPushState;
|
|
494
|
-
history.replaceState = patchedReplaceState;
|
|
495
|
-
patchInstalled = true;
|
|
496
|
-
};
|
|
497
|
-
var removePatch = () => {
|
|
498
|
-
if (!patchInstalled) return;
|
|
499
|
-
if (history.pushState === patchedPushState && origPushState) {
|
|
500
|
-
history.pushState = origPushState;
|
|
501
|
-
}
|
|
502
|
-
if (history.replaceState === patchedReplaceState && origReplaceState) {
|
|
503
|
-
history.replaceState = origReplaceState;
|
|
504
|
-
}
|
|
505
|
-
origPushState = null;
|
|
506
|
-
origReplaceState = null;
|
|
507
|
-
patchedPushState = null;
|
|
508
|
-
patchedReplaceState = null;
|
|
509
|
-
patchInstalled = false;
|
|
510
|
-
};
|
|
511
|
-
function onPopState() {
|
|
512
|
-
if (suppress > 0) {
|
|
513
|
-
suppress -= 1;
|
|
514
|
-
const rebrand = pendingRebrand;
|
|
515
|
-
pendingRebrand = null;
|
|
516
|
-
if (rebrand) rebrand();
|
|
517
|
-
maybeTeardownListener();
|
|
518
|
-
return;
|
|
519
|
-
}
|
|
520
|
-
if (entries.length === 0) {
|
|
521
|
-
notifyRouteChange();
|
|
522
|
-
maybeTeardownListener();
|
|
523
|
-
return;
|
|
376
|
+
// src/core/features/resize-observer.ts
|
|
377
|
+
function installResizeObserver(deps) {
|
|
378
|
+
if (typeof window === "undefined") {
|
|
379
|
+
return () => {
|
|
380
|
+
};
|
|
524
381
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
const
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
if (entry.surface.isTop()) {
|
|
535
|
-
target = entry;
|
|
536
|
-
targetIdx = i;
|
|
537
|
-
break;
|
|
382
|
+
const onResize = () => {
|
|
383
|
+
if (deps.isDestroyed()) return;
|
|
384
|
+
deps.recomputeSnaps();
|
|
385
|
+
const mode = deps.getMode();
|
|
386
|
+
const isVerticalAxis = mode === "bottom" || mode === "top";
|
|
387
|
+
const viewportSize2 = isVerticalAxis ? window.innerHeight : window.innerWidth;
|
|
388
|
+
const max = deps.getMaxAxisSize();
|
|
389
|
+
if (viewportSize2 > 0 && viewportSize2 < max) {
|
|
390
|
+
deps.setMaxAxisSize(viewportSize2);
|
|
538
391
|
}
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
void Promise.resolve(settled.surface.close()).then(() => {
|
|
550
|
-
if (settled.surface.isOpen()) restore(settled);
|
|
551
|
-
});
|
|
552
|
-
maybeTeardownListener();
|
|
553
|
-
}
|
|
554
|
-
function restore(entry) {
|
|
555
|
-
if (!hasWindow() || !hasHistory()) return;
|
|
556
|
-
entry.live = true;
|
|
557
|
-
runInternal(() => {
|
|
558
|
-
try {
|
|
559
|
-
history.pushState(entry.surface.markerState(), "", entry.surface.url);
|
|
560
|
-
} catch {
|
|
561
|
-
entry.live = false;
|
|
392
|
+
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
393
|
+
deps.cancelInFlight();
|
|
394
|
+
deps.newCycle();
|
|
395
|
+
const current = deps.resolveActiveSnap();
|
|
396
|
+
const newMax = deps.getMaxAxisSize();
|
|
397
|
+
const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
|
|
398
|
+
deps.setSize(targetSize);
|
|
399
|
+
if (current && !deps.isDragging()) {
|
|
400
|
+
deps.applySize(targetSize);
|
|
401
|
+
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
562
402
|
}
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
403
|
+
};
|
|
404
|
+
let resizeObserver = null;
|
|
405
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
406
|
+
resizeObserver = new ResizeObserver(onResize);
|
|
407
|
+
resizeObserver.observe(document.documentElement);
|
|
408
|
+
} else {
|
|
409
|
+
window.addEventListener("resize", onResize);
|
|
567
410
|
}
|
|
411
|
+
window.addEventListener("orientationchange", onResize);
|
|
412
|
+
const onVisibility = () => {
|
|
413
|
+
if (deps.isDestroyed()) return;
|
|
414
|
+
if (document.hidden) deps.cancelInFlight();
|
|
415
|
+
};
|
|
416
|
+
document.addEventListener("visibilitychange", onVisibility);
|
|
417
|
+
return () => {
|
|
418
|
+
resizeObserver?.disconnect();
|
|
419
|
+
window.removeEventListener("resize", onResize);
|
|
420
|
+
window.removeEventListener("orientationchange", onResize);
|
|
421
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
422
|
+
};
|
|
568
423
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
entry.live = false;
|
|
581
|
-
}
|
|
582
|
-
});
|
|
583
|
-
if (entry.live) {
|
|
584
|
-
entries.push(entry);
|
|
585
|
-
ensureListener();
|
|
586
|
-
}
|
|
587
|
-
return entry;
|
|
588
|
-
}
|
|
589
|
-
function popBackMarker(handle) {
|
|
590
|
-
if (!hasWindow() || !hasHistory()) return;
|
|
591
|
-
const entry = handle;
|
|
592
|
-
const idx = entries.indexOf(entry);
|
|
593
|
-
if (idx === -1 || !entry.live) return;
|
|
594
|
-
const last = entries.length - 1;
|
|
595
|
-
entry.live = false;
|
|
596
|
-
entries.splice(idx, 1);
|
|
597
|
-
if (idx !== last) {
|
|
598
|
-
const rebrandSurface = entries[entries.length - 1].surface;
|
|
599
|
-
const rebrandUrl = entry.priorUrl;
|
|
600
|
-
pendingRebrand = () => {
|
|
601
|
-
runInternal(() => {
|
|
602
|
-
history.replaceState(
|
|
603
|
-
rebrandSurface.markerState(),
|
|
604
|
-
"",
|
|
605
|
-
rebrandUrl !== void 0 ? rebrandUrl : location.href
|
|
606
|
-
);
|
|
607
|
-
});
|
|
608
|
-
};
|
|
609
|
-
}
|
|
610
|
-
suppress += 1;
|
|
611
|
-
runInternal(() => {
|
|
612
|
-
try {
|
|
613
|
-
history.back();
|
|
614
|
-
} catch {
|
|
615
|
-
suppress = Math.max(0, suppress - 1);
|
|
616
|
-
pendingRebrand = null;
|
|
617
|
-
}
|
|
618
|
-
});
|
|
619
|
-
maybeTeardownListener();
|
|
620
|
-
}
|
|
621
|
-
function subscribeRouteChange(fn) {
|
|
622
|
-
if (!hasWindow() || !hasHistory()) return () => {
|
|
623
|
-
};
|
|
624
|
-
subscribers.add(fn);
|
|
625
|
-
if (subscribers.size === 1) installPatch();
|
|
626
|
-
ensureListener();
|
|
627
|
-
return () => {
|
|
628
|
-
if (!subscribers.has(fn)) return;
|
|
629
|
-
subscribers.delete(fn);
|
|
630
|
-
if (subscribers.size === 0) removePatch();
|
|
631
|
-
maybeTeardownListener();
|
|
632
|
-
};
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
// src/core/features/route.ts
|
|
636
|
-
function installRoute(deps) {
|
|
637
|
-
if (typeof window === "undefined") {
|
|
638
|
-
return () => {
|
|
639
|
-
};
|
|
640
|
-
}
|
|
641
|
-
if (!deps.routedTo && !deps.closeOnBack) {
|
|
642
|
-
return () => {
|
|
643
|
-
};
|
|
644
|
-
}
|
|
645
|
-
let handle = null;
|
|
646
|
-
const onOpen = () => {
|
|
647
|
-
if (handle) return;
|
|
648
|
-
handle = pushBackMarker({
|
|
649
|
-
isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
|
|
650
|
-
isTop: deps.isTopSheet,
|
|
651
|
-
close: deps.close,
|
|
652
|
-
markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
|
|
653
|
-
url: deps.routedTo
|
|
654
|
-
});
|
|
655
|
-
};
|
|
656
|
-
const onClose = () => {
|
|
657
|
-
if (!handle) return;
|
|
658
|
-
popBackMarker(handle);
|
|
659
|
-
handle = null;
|
|
660
|
-
};
|
|
661
|
-
const unsubscribeOpen = deps.on("open", onOpen);
|
|
662
|
-
const unsubscribeClose = deps.on("close", onClose);
|
|
663
|
-
if (deps.getSize() > 0) onOpen();
|
|
664
|
-
return () => {
|
|
665
|
-
unsubscribeOpen();
|
|
666
|
-
unsubscribeClose();
|
|
667
|
-
if (handle) {
|
|
668
|
-
popBackMarker(handle);
|
|
669
|
-
handle = null;
|
|
670
|
-
}
|
|
671
|
-
};
|
|
672
|
-
}
|
|
673
|
-
function installRouteChange(deps) {
|
|
674
|
-
return subscribeRouteChange(() => {
|
|
675
|
-
if (deps.isDestroyed() || deps.getSize() <= 0) return;
|
|
676
|
-
void deps.close();
|
|
677
|
-
});
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
// src/core/features/content-swipe.ts
|
|
681
|
-
var CONTENT_PULL_THRESHOLD = 60;
|
|
682
|
-
function installContentSwipe(deps) {
|
|
683
|
-
const { container } = deps;
|
|
684
|
-
let startY = 0;
|
|
685
|
-
let startScrollTop = 0;
|
|
686
|
-
let moved = false;
|
|
687
|
-
const onTouchStart = (e) => {
|
|
688
|
-
const t = e.touches[0];
|
|
689
|
-
if (!t) return;
|
|
690
|
-
startY = t.clientY;
|
|
691
|
-
startScrollTop = container.scrollTop;
|
|
692
|
-
moved = false;
|
|
693
|
-
};
|
|
694
|
-
const onTouchMove = (e) => {
|
|
695
|
-
const t = e.touches[0];
|
|
696
|
-
if (!t) return;
|
|
697
|
-
if (Math.abs(t.clientY - startY) > CONTENT_PULL_THRESHOLD) moved = true;
|
|
698
|
-
};
|
|
699
|
-
const onTouchEnd = (e) => {
|
|
700
|
-
if (!moved) return;
|
|
701
|
-
if (deps.isDragging() || deps.isAnimating()) return;
|
|
702
|
-
if (container.scrollTop !== startScrollTop) return;
|
|
703
|
-
const t = e.changedTouches[0];
|
|
704
|
-
if (!t) return;
|
|
705
|
-
const deltaY = t.clientY - startY;
|
|
706
|
-
const atTop = container.scrollTop <= 0;
|
|
707
|
-
const allowed = deps.getAllowedIds();
|
|
708
|
-
const idx = allowed.indexOf(deps.getActiveId());
|
|
709
|
-
if (idx === -1) return;
|
|
710
|
-
if (atTop && deltaY > CONTENT_PULL_THRESHOLD && idx > 0) {
|
|
711
|
-
deps.snapTo(allowed[idx - 1]);
|
|
712
|
-
} else if (deltaY < -CONTENT_PULL_THRESHOLD && idx < allowed.length - 1) {
|
|
713
|
-
deps.snapTo(allowed[idx + 1]);
|
|
714
|
-
}
|
|
715
|
-
};
|
|
716
|
-
container.addEventListener("touchstart", onTouchStart, { passive: true });
|
|
717
|
-
container.addEventListener("touchmove", onTouchMove, { passive: true });
|
|
718
|
-
container.addEventListener("touchend", onTouchEnd, { passive: true });
|
|
719
|
-
return () => {
|
|
720
|
-
container.removeEventListener("touchstart", onTouchStart);
|
|
721
|
-
container.removeEventListener("touchmove", onTouchMove);
|
|
722
|
-
container.removeEventListener("touchend", onTouchEnd);
|
|
723
|
-
};
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
// src/core/features/visual-viewport.ts
|
|
727
|
-
var SAFETY_PAD = 8;
|
|
728
|
-
function installVisualViewport(deps) {
|
|
729
|
-
if (typeof window === "undefined" || !window.visualViewport) {
|
|
730
|
-
return () => {
|
|
731
|
-
};
|
|
732
|
-
}
|
|
733
|
-
const vv = window.visualViewport;
|
|
734
|
-
let rafId = null;
|
|
735
|
-
const onResize = () => {
|
|
736
|
-
if (rafId !== null) return;
|
|
737
|
-
rafId = requestAnimationFrame(() => {
|
|
738
|
-
rafId = null;
|
|
739
|
-
if (deps.isDestroyed()) return;
|
|
740
|
-
deps.recomputeSnaps();
|
|
741
|
-
const isVertical = deps.isVerticalAxis();
|
|
742
|
-
const visible = isVertical ? vv.height : vv.width;
|
|
743
|
-
const windowSize = isVertical ? window.innerHeight : window.innerWidth;
|
|
744
|
-
const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
|
|
745
|
-
if (clamp < deps.getMaxAxisSize()) {
|
|
746
|
-
deps.setMaxAxisSize(clamp);
|
|
747
|
-
}
|
|
748
|
-
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
749
|
-
deps.cancelInFlight();
|
|
750
|
-
deps.newCycle();
|
|
751
|
-
const max = deps.getMaxAxisSize();
|
|
752
|
-
deps.setSize(Math.min(deps.getSize(), max));
|
|
753
|
-
const current = deps.resolveActiveSnap();
|
|
754
|
-
if (current && !deps.isDragging()) {
|
|
755
|
-
deps.applySize(Math.min(current.size, max));
|
|
756
|
-
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
757
|
-
} else {
|
|
758
|
-
deps.applySize(deps.getSize());
|
|
759
|
-
}
|
|
760
|
-
});
|
|
761
|
-
};
|
|
762
|
-
vv.addEventListener("resize", onResize);
|
|
763
|
-
return () => {
|
|
764
|
-
vv.removeEventListener("resize", onResize);
|
|
765
|
-
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
766
|
-
};
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
// src/core/features/resize-observer.ts
|
|
770
|
-
function installResizeObserver(deps) {
|
|
771
|
-
if (typeof window === "undefined") {
|
|
772
|
-
return () => {
|
|
773
|
-
};
|
|
774
|
-
}
|
|
775
|
-
const onResize = () => {
|
|
776
|
-
if (deps.isDestroyed()) return;
|
|
777
|
-
deps.recomputeSnaps();
|
|
778
|
-
const mode = deps.getMode();
|
|
779
|
-
const isVerticalAxis = mode === "bottom" || mode === "top";
|
|
780
|
-
const viewportSize2 = isVerticalAxis ? window.innerHeight : window.innerWidth;
|
|
781
|
-
const max = deps.getMaxAxisSize();
|
|
782
|
-
if (viewportSize2 > 0 && viewportSize2 < max) {
|
|
783
|
-
deps.setMaxAxisSize(viewportSize2);
|
|
784
|
-
}
|
|
785
|
-
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
786
|
-
deps.cancelInFlight();
|
|
787
|
-
deps.newCycle();
|
|
788
|
-
const current = deps.resolveActiveSnap();
|
|
789
|
-
const newMax = deps.getMaxAxisSize();
|
|
790
|
-
const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
|
|
791
|
-
deps.setSize(targetSize);
|
|
792
|
-
if (current && !deps.isDragging()) {
|
|
793
|
-
deps.applySize(targetSize);
|
|
794
|
-
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
795
|
-
}
|
|
796
|
-
};
|
|
797
|
-
let resizeObserver = null;
|
|
798
|
-
if (typeof ResizeObserver !== "undefined") {
|
|
799
|
-
resizeObserver = new ResizeObserver(onResize);
|
|
800
|
-
resizeObserver.observe(document.documentElement);
|
|
801
|
-
} else {
|
|
802
|
-
window.addEventListener("resize", onResize);
|
|
803
|
-
}
|
|
804
|
-
window.addEventListener("orientationchange", onResize);
|
|
805
|
-
const onVisibility = () => {
|
|
806
|
-
if (deps.isDestroyed()) return;
|
|
807
|
-
if (document.hidden) deps.cancelInFlight();
|
|
808
|
-
};
|
|
809
|
-
document.addEventListener("visibilitychange", onVisibility);
|
|
810
|
-
return () => {
|
|
811
|
-
resizeObserver?.disconnect();
|
|
812
|
-
window.removeEventListener("resize", onResize);
|
|
813
|
-
window.removeEventListener("orientationchange", onResize);
|
|
814
|
-
document.removeEventListener("visibilitychange", onVisibility);
|
|
815
|
-
};
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
// src/core/features/fit-observer.ts
|
|
819
|
-
var contentTargets = (scroller) => {
|
|
820
|
-
if (!scroller) return [];
|
|
821
|
-
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
822
|
-
const out = [];
|
|
823
|
-
for (const child of Array.from(scroller.children)) {
|
|
824
|
-
if (hasSlot && child instanceof HTMLSlotElement) {
|
|
825
|
-
for (const el of child.assignedElements()) out.push(el);
|
|
826
|
-
} else {
|
|
827
|
-
out.push(child);
|
|
424
|
+
|
|
425
|
+
// src/core/features/fit-observer.ts
|
|
426
|
+
var contentTargets = (scroller) => {
|
|
427
|
+
if (!scroller) return [];
|
|
428
|
+
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
429
|
+
const out = [];
|
|
430
|
+
for (const child of Array.from(scroller.children)) {
|
|
431
|
+
if (hasSlot && child instanceof HTMLSlotElement) {
|
|
432
|
+
for (const el of child.assignedElements()) out.push(el);
|
|
433
|
+
} else {
|
|
434
|
+
out.push(child);
|
|
828
435
|
}
|
|
829
436
|
}
|
|
830
437
|
return out;
|
|
@@ -944,11 +551,15 @@ function createMaxHeightController(deps) {
|
|
|
944
551
|
|
|
945
552
|
// src/core/features/fit-measurement.ts
|
|
946
553
|
var measureSheetNatural = (element, content, vertical) => {
|
|
947
|
-
if (!content) {
|
|
948
|
-
return vertical ? element.offsetHeight : element.offsetWidth;
|
|
949
|
-
}
|
|
950
554
|
const axis = vertical ? "height" : "width";
|
|
951
555
|
const sheetStyle = element.style;
|
|
556
|
+
if (!content) {
|
|
557
|
+
const prev = sheetStyle[axis];
|
|
558
|
+
sheetStyle[axis] = "auto";
|
|
559
|
+
const poked2 = vertical ? element.offsetHeight : element.offsetWidth;
|
|
560
|
+
sheetStyle[axis] = prev;
|
|
561
|
+
return poked2;
|
|
562
|
+
}
|
|
952
563
|
const cs = content.style;
|
|
953
564
|
const prevSheet = sheetStyle[axis];
|
|
954
565
|
const prevFlex = cs.flex;
|
|
@@ -1662,6 +1273,52 @@ function resolveAnimationPreset(animation) {
|
|
|
1662
1273
|
}
|
|
1663
1274
|
}
|
|
1664
1275
|
|
|
1276
|
+
// src/core/animation/waapi-settle.ts
|
|
1277
|
+
var SIM_HZ = 240;
|
|
1278
|
+
var SAMPLE_STRIDE = 4;
|
|
1279
|
+
var MAX_SIM_MS = 3e3;
|
|
1280
|
+
function sampleSpringSettle(from, to, velocityPxPerS, config) {
|
|
1281
|
+
const cfg = { ...DEFAULT_SPRING, ...config };
|
|
1282
|
+
const subDt = 1 / SIM_HZ;
|
|
1283
|
+
const stepMs = SAMPLE_STRIDE / SIM_HZ * 1e3;
|
|
1284
|
+
const maxSteps = Math.ceil(MAX_SIM_MS / 1e3 * SIM_HZ);
|
|
1285
|
+
const values = [from];
|
|
1286
|
+
let x = from;
|
|
1287
|
+
let v = velocityPxPerS;
|
|
1288
|
+
for (let i = 1; i <= maxSteps; i += 1) {
|
|
1289
|
+
const force = -cfg.stiffness * (x - to) - cfg.damping * v;
|
|
1290
|
+
v += force / cfg.mass * subDt;
|
|
1291
|
+
x += v * subDt;
|
|
1292
|
+
if (!Number.isFinite(x) || !Number.isFinite(v)) {
|
|
1293
|
+
values.push(to);
|
|
1294
|
+
break;
|
|
1295
|
+
}
|
|
1296
|
+
if (i % SAMPLE_STRIDE === 0) values.push(x);
|
|
1297
|
+
const atRest = Math.abs(to - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
|
|
1298
|
+
if (atRest) break;
|
|
1299
|
+
}
|
|
1300
|
+
if (values[values.length - 1] !== to) values.push(to);
|
|
1301
|
+
return {
|
|
1302
|
+
values,
|
|
1303
|
+
stepMs,
|
|
1304
|
+
durationMs: (values.length - 1) * stepMs
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
function sampleTweenSettle(from, to, durationMs, easing) {
|
|
1308
|
+
const count = Math.max(2, Math.min(60, Math.round(durationMs / 16)));
|
|
1309
|
+
const values = [];
|
|
1310
|
+
for (let i = 0; i <= count; i += 1) {
|
|
1311
|
+
const t = i / count;
|
|
1312
|
+
values.push(from + (to - from) * easing(t));
|
|
1313
|
+
}
|
|
1314
|
+
values[values.length - 1] = to;
|
|
1315
|
+
return {
|
|
1316
|
+
values,
|
|
1317
|
+
stepMs: durationMs / count,
|
|
1318
|
+
durationMs
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1665
1322
|
// src/core/controllers/animation-runner.ts
|
|
1666
1323
|
var DEFAULT_DURATION2 = 220;
|
|
1667
1324
|
var VELOCITY_PX_PER_S = 1e3;
|
|
@@ -1672,6 +1329,10 @@ var AnimationRunner = class {
|
|
|
1672
1329
|
__publicField(this, "applySizeFn");
|
|
1673
1330
|
__publicField(this, "getSize");
|
|
1674
1331
|
__publicField(this, "isDragging");
|
|
1332
|
+
__publicField(this, "applyAux");
|
|
1333
|
+
__publicField(this, "getTransformFor");
|
|
1334
|
+
__publicField(this, "settleWaapi");
|
|
1335
|
+
__publicField(this, "currentWaapi", null);
|
|
1675
1336
|
__publicField(this, "animationKind");
|
|
1676
1337
|
__publicField(this, "springConfig");
|
|
1677
1338
|
__publicField(this, "duration");
|
|
@@ -1687,6 +1348,9 @@ var AnimationRunner = class {
|
|
|
1687
1348
|
this.applySizeFn = deps.applySize;
|
|
1688
1349
|
this.getSize = deps.getSize;
|
|
1689
1350
|
this.isDragging = deps.isDragging;
|
|
1351
|
+
this.applyAux = deps.applyAux;
|
|
1352
|
+
this.getTransformFor = deps.getTransformFor;
|
|
1353
|
+
this.settleWaapi = opts.settleAnimation === "waapi";
|
|
1690
1354
|
const preset = resolveAnimationPreset(opts.animation);
|
|
1691
1355
|
this.animationKind = preset.kind;
|
|
1692
1356
|
this.duration = opts.duration ?? preset.duration ?? DEFAULT_DURATION2;
|
|
@@ -1711,11 +1375,20 @@ var AnimationRunner = class {
|
|
|
1711
1375
|
}
|
|
1712
1376
|
}
|
|
1713
1377
|
get isAnimating() {
|
|
1714
|
-
return this.currentTween !== null || this.currentSpring !== null;
|
|
1378
|
+
return this.currentTween !== null || this.currentSpring !== null || this.currentWaapi !== null;
|
|
1715
1379
|
}
|
|
1716
1380
|
cancel() {
|
|
1717
1381
|
this.currentTween?.cancel();
|
|
1718
1382
|
this.currentSpring?.cancel();
|
|
1383
|
+
if (this.currentWaapi) {
|
|
1384
|
+
const entry = this.currentWaapi;
|
|
1385
|
+
this.currentWaapi = null;
|
|
1386
|
+
entry.stop();
|
|
1387
|
+
try {
|
|
1388
|
+
entry.anim.cancel();
|
|
1389
|
+
} catch {
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1719
1392
|
}
|
|
1720
1393
|
async animateTo(target, velocityPxPerMs) {
|
|
1721
1394
|
if (target === this.getSize()) {
|
|
@@ -1734,7 +1407,28 @@ var AnimationRunner = class {
|
|
|
1734
1407
|
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1735
1408
|
return;
|
|
1736
1409
|
}
|
|
1737
|
-
if (this.
|
|
1410
|
+
if (this.settleWaapi && this.applyAux && this.getTransformFor && typeof this.element.animate === "function") {
|
|
1411
|
+
const samples = this.animationKind === "spring" ? sampleSpringSettle(
|
|
1412
|
+
this.getSize(),
|
|
1413
|
+
target,
|
|
1414
|
+
velocityPxPerMs * VELOCITY_PX_PER_S,
|
|
1415
|
+
this.springConfig
|
|
1416
|
+
) : sampleTweenSettle(
|
|
1417
|
+
this.getSize(),
|
|
1418
|
+
target,
|
|
1419
|
+
this.duration,
|
|
1420
|
+
this.easing
|
|
1421
|
+
);
|
|
1422
|
+
if (samples.values.length >= 2 && samples.durationMs > 0) {
|
|
1423
|
+
await this.runWaapiSettle(samples, target);
|
|
1424
|
+
if (!this.isAnimating) {
|
|
1425
|
+
this.getRootEl()?.removeAttribute("data-animating");
|
|
1426
|
+
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1427
|
+
}
|
|
1428
|
+
return;
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
if (this.animationKind === "spring") {
|
|
1738
1432
|
const spring = runSpring({
|
|
1739
1433
|
from: this.getSize(),
|
|
1740
1434
|
to: target,
|
|
@@ -1762,11 +1456,66 @@ var AnimationRunner = class {
|
|
|
1762
1456
|
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1763
1457
|
}
|
|
1764
1458
|
}
|
|
1459
|
+
async runWaapiSettle(samples, target) {
|
|
1460
|
+
const applyAux = this.applyAux;
|
|
1461
|
+
const getTransformFor = this.getTransformFor;
|
|
1462
|
+
const frames = samples.values.map((v) => ({
|
|
1463
|
+
transform: getTransformFor(v)
|
|
1464
|
+
}));
|
|
1465
|
+
const anim = this.element.animate(frames, {
|
|
1466
|
+
duration: samples.durationMs,
|
|
1467
|
+
easing: "linear",
|
|
1468
|
+
fill: "forwards"
|
|
1469
|
+
});
|
|
1470
|
+
let stopped = false;
|
|
1471
|
+
let auxRaf = 0;
|
|
1472
|
+
const start = performance.now();
|
|
1473
|
+
const lastIdx = samples.values.length - 1;
|
|
1474
|
+
const auxTick = () => {
|
|
1475
|
+
if (stopped) return;
|
|
1476
|
+
const elapsed = performance.now() - start;
|
|
1477
|
+
const idx = Math.min(Math.floor(elapsed / samples.stepMs), lastIdx);
|
|
1478
|
+
applyAux(samples.values[idx]);
|
|
1479
|
+
auxRaf = requestAnimationFrame(auxTick);
|
|
1480
|
+
};
|
|
1481
|
+
auxRaf = requestAnimationFrame(auxTick);
|
|
1482
|
+
const entry = {
|
|
1483
|
+
anim,
|
|
1484
|
+
stop: () => {
|
|
1485
|
+
stopped = true;
|
|
1486
|
+
cancelAnimationFrame(auxRaf);
|
|
1487
|
+
}
|
|
1488
|
+
};
|
|
1489
|
+
this.currentWaapi = entry;
|
|
1490
|
+
try {
|
|
1491
|
+
await anim.finished;
|
|
1492
|
+
} catch {
|
|
1493
|
+
}
|
|
1494
|
+
entry.stop();
|
|
1495
|
+
const wasCurrent = this.currentWaapi === entry;
|
|
1496
|
+
if (wasCurrent) this.currentWaapi = null;
|
|
1497
|
+
if (wasCurrent && anim.playState === "finished") {
|
|
1498
|
+
this.applySizeFn(target);
|
|
1499
|
+
try {
|
|
1500
|
+
anim.cancel();
|
|
1501
|
+
} catch {
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1765
1505
|
destroy() {
|
|
1766
1506
|
this.detachReducedMotion?.();
|
|
1767
1507
|
this.detachReducedMotion = null;
|
|
1768
1508
|
this.currentTween = null;
|
|
1769
1509
|
this.currentSpring = null;
|
|
1510
|
+
if (this.currentWaapi) {
|
|
1511
|
+
const entry = this.currentWaapi;
|
|
1512
|
+
this.currentWaapi = null;
|
|
1513
|
+
entry.stop();
|
|
1514
|
+
try {
|
|
1515
|
+
entry.anim.cancel();
|
|
1516
|
+
} catch {
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1770
1519
|
}
|
|
1771
1520
|
};
|
|
1772
1521
|
|
|
@@ -2623,7 +2372,7 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2623
2372
|
const initialAllowed = opts.allowed ?? opts.snapPoints.map((p) => p.id);
|
|
2624
2373
|
let initialId = opts.initial ?? initialAllowed[0] ?? opts.snapPoints[0]?.id ?? "default";
|
|
2625
2374
|
if (opts.persistKey) {
|
|
2626
|
-
const restored =
|
|
2375
|
+
const restored = readPersistedIdSafe(opts.persistKey);
|
|
2627
2376
|
if (restored && initialAllowed.includes(restored)) {
|
|
2628
2377
|
initialId = restored;
|
|
2629
2378
|
}
|
|
@@ -2654,6 +2403,7 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2654
2403
|
},
|
|
2655
2404
|
animation: {
|
|
2656
2405
|
animation: opts.animation,
|
|
2406
|
+
settleAnimation: opts.settleAnimation,
|
|
2657
2407
|
duration: opts.duration,
|
|
2658
2408
|
easing: opts.easing,
|
|
2659
2409
|
spring: opts.spring,
|
|
@@ -2671,6 +2421,15 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2671
2421
|
}
|
|
2672
2422
|
};
|
|
2673
2423
|
}
|
|
2424
|
+
var readPersistedIdSafe = (key) => {
|
|
2425
|
+
if (typeof window === "undefined") return null;
|
|
2426
|
+
if (typeof localStorage === "undefined") return null;
|
|
2427
|
+
try {
|
|
2428
|
+
return localStorage.getItem(key);
|
|
2429
|
+
} catch {
|
|
2430
|
+
return null;
|
|
2431
|
+
}
|
|
2432
|
+
};
|
|
2674
2433
|
|
|
2675
2434
|
// src/core/primitives/teardown-stack.ts
|
|
2676
2435
|
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
|
constructor(opts) {
|
|
2700
2459
|
__publicField(this, "id", nextInstanceId("bs"));
|
|
2701
2460
|
__publicField(this, "element");
|
|
@@ -2756,6 +2515,8 @@ var BottomSheetEngine = class {
|
|
|
2756
2515
|
__publicField(this, "stackEffectPrimed", false);
|
|
2757
2516
|
__publicField(this, "fitDeps");
|
|
2758
2517
|
__publicField(this, "transformTemplate");
|
|
2518
|
+
__publicField(this, "featureList", []);
|
|
2519
|
+
__publicField(this, "featureCtx");
|
|
2759
2520
|
const resolved = resolveEngineOptions(opts, {
|
|
2760
2521
|
shouldApplyInertSiblings: () => {
|
|
2761
2522
|
if (typeof document === "undefined") return false;
|
|
@@ -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;
|