@surdeddd/bottom-sheet 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -1
- package/dist/{BottomSheetEngine-DzsIwD28.d.cts → BottomSheetCore-CsIjyq7C.d.cts} +61 -5
- package/dist/{BottomSheetEngine-DRjCU73e.d.ts → BottomSheetCore-D16lsa6g.d.ts} +61 -5
- package/dist/BottomSheetEngine-BYjAVrmd.d.cts +7 -0
- package/dist/BottomSheetEngine-YuCNugZn.d.ts +7 -0
- package/dist/core.cjs +3476 -0
- package/dist/core.d.cts +3 -0
- package/dist/core.d.ts +3 -0
- package/dist/core.js +3474 -0
- package/dist/debug.cjs +109 -0
- package/dist/debug.d.cts +22 -0
- package/dist/debug.d.ts +22 -0
- package/dist/debug.js +107 -0
- package/dist/element.cjs +994 -697
- package/dist/element.d.cts +2 -1
- package/dist/element.d.ts +2 -1
- package/dist/element.iife.global.js +2 -2
- package/dist/element.js +994 -697
- package/dist/features.cjs +533 -0
- package/dist/features.d.cts +13 -0
- package/dist/features.d.ts +13 -0
- package/dist/features.js +526 -0
- package/dist/index-DdYLOIIT.d.ts +15 -0
- package/dist/index-dfrzw-lI.d.cts +15 -0
- package/dist/index.cjs +823 -542
- package/dist/index.d.cts +6 -15
- package/dist/index.d.ts +6 -15
- package/dist/index.js +817 -543
- package/dist/integrations/formik.d.cts +1 -1
- package/dist/integrations/formik.d.ts +1 -1
- package/dist/integrations/react-hook-form.d.cts +1 -1
- package/dist/integrations/react-hook-form.d.ts +1 -1
- package/dist/overlay.cjs +13 -8
- package/dist/overlay.js +13 -8
- package/dist/preact.d.cts +2 -1
- package/dist/preact.d.ts +2 -1
- package/dist/qwik-lib/index.qwik.cjs +4267 -0
- package/dist/qwik-lib/index.qwik.mjs +4267 -0
- package/dist/qwik.cjs +816 -542
- package/dist/qwik.d.cts +2 -2
- package/dist/qwik.d.ts +2 -2
- package/dist/qwik.js +816 -542
- package/dist/react.cjs +816 -542
- package/dist/react.d.cts +3 -2
- package/dist/react.d.ts +3 -2
- package/dist/react.js +816 -542
- package/dist/solid.cjs +816 -542
- package/dist/solid.d.cts +64 -4
- package/dist/solid.d.ts +64 -4
- package/dist/solid.js +816 -542
- package/dist/solid.source.jsx +816 -542
- package/dist/svelte-core.cjs +816 -542
- package/dist/svelte-core.js +816 -542
- package/dist/svelte.cjs +816 -542
- package/dist/svelte.js +816 -542
- package/dist/vue.cjs +927 -645
- package/dist/vue.js +927 -645
- package/package.json +63 -11
package/dist/svelte-core.js
CHANGED
|
@@ -348,74 +348,6 @@ var SnapResolver = class {
|
|
|
348
348
|
}
|
|
349
349
|
};
|
|
350
350
|
|
|
351
|
-
// src/core/features/persist.ts
|
|
352
|
-
function readPersistedId(key) {
|
|
353
|
-
if (!key) return null;
|
|
354
|
-
if (typeof window === "undefined") return null;
|
|
355
|
-
if (typeof localStorage === "undefined") return null;
|
|
356
|
-
try {
|
|
357
|
-
return localStorage.getItem(key);
|
|
358
|
-
} catch {
|
|
359
|
-
return null;
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
function installPersist(engine, key) {
|
|
363
|
-
const unsubscribe = engine.on("snap", ({ id }) => {
|
|
364
|
-
if (typeof window === "undefined") return;
|
|
365
|
-
if (typeof localStorage === "undefined") return;
|
|
366
|
-
try {
|
|
367
|
-
localStorage.setItem(key, id);
|
|
368
|
-
} catch {
|
|
369
|
-
}
|
|
370
|
-
});
|
|
371
|
-
return unsubscribe;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
// src/core/features/auto-collapse.ts
|
|
375
|
-
function installAutoCollapse(deps) {
|
|
376
|
-
const { ms } = deps;
|
|
377
|
-
if (ms === void 0 || ms <= 0) {
|
|
378
|
-
return () => {
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
let timer = null;
|
|
382
|
-
const clearTimer = () => {
|
|
383
|
-
if (timer !== null) {
|
|
384
|
-
clearTimeout(timer);
|
|
385
|
-
timer = null;
|
|
386
|
-
}
|
|
387
|
-
};
|
|
388
|
-
const fire = () => {
|
|
389
|
-
if (deps.isDestroyed()) return;
|
|
390
|
-
if (deps.isDragging()) return;
|
|
391
|
-
const active = deps.resolveSnap(deps.getActiveId());
|
|
392
|
-
if (!active || active.size === 0) return;
|
|
393
|
-
let target = null;
|
|
394
|
-
for (const id of deps.getAllowedIds()) {
|
|
395
|
-
const snap = deps.resolveSnap(id);
|
|
396
|
-
if (!snap || snap.size <= 0) continue;
|
|
397
|
-
if (!target || snap.size < target.size) target = snap;
|
|
398
|
-
}
|
|
399
|
-
if (!target) return;
|
|
400
|
-
if (target.id === active.id || target.size >= active.size) return;
|
|
401
|
-
deps.snapTo(target.id);
|
|
402
|
-
};
|
|
403
|
-
const reset = () => {
|
|
404
|
-
clearTimer();
|
|
405
|
-
if (deps.isDestroyed()) return;
|
|
406
|
-
timer = setTimeout(() => {
|
|
407
|
-
timer = null;
|
|
408
|
-
fire();
|
|
409
|
-
}, ms);
|
|
410
|
-
};
|
|
411
|
-
const unsubscribe = deps.on("snap", () => reset());
|
|
412
|
-
if ((deps.resolveSnap(deps.getActiveId())?.size ?? 0) > 0) reset();
|
|
413
|
-
return () => {
|
|
414
|
-
clearTimer();
|
|
415
|
-
unsubscribe();
|
|
416
|
-
};
|
|
417
|
-
}
|
|
418
|
-
|
|
419
351
|
// src/core/features/linked-sheets.ts
|
|
420
352
|
function notifyLinkedSheets(sheets, self) {
|
|
421
353
|
if (sheets.length === 0) return;
|
|
@@ -438,390 +370,65 @@ function notifyLinkedSheets(sheets, self) {
|
|
|
438
370
|
}
|
|
439
371
|
}
|
|
440
372
|
|
|
441
|
-
// src/core/features/
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
var pendingRebrand = null;
|
|
447
|
-
var listenerInstalled = false;
|
|
448
|
-
var patchInstalled = false;
|
|
449
|
-
var origPushState = null;
|
|
450
|
-
var origReplaceState = null;
|
|
451
|
-
var patchedPushState = null;
|
|
452
|
-
var patchedReplaceState = null;
|
|
453
|
-
var hasWindow = () => typeof window !== "undefined";
|
|
454
|
-
var hasHistory = () => typeof history !== "undefined";
|
|
455
|
-
var runInternal = (fn) => {
|
|
456
|
-
internalDepth += 1;
|
|
457
|
-
try {
|
|
458
|
-
fn();
|
|
459
|
-
} finally {
|
|
460
|
-
internalDepth -= 1;
|
|
461
|
-
}
|
|
462
|
-
};
|
|
463
|
-
var notifyRouteChange = () => {
|
|
464
|
-
const snapshot = Array.from(subscribers);
|
|
465
|
-
for (const fn of snapshot) fn();
|
|
466
|
-
};
|
|
467
|
-
var ensureListener = () => {
|
|
468
|
-
if (listenerInstalled || !hasWindow()) return;
|
|
469
|
-
window.addEventListener("popstate", onPopState);
|
|
470
|
-
listenerInstalled = true;
|
|
471
|
-
};
|
|
472
|
-
var maybeTeardownListener = () => {
|
|
473
|
-
if (!listenerInstalled) return;
|
|
474
|
-
if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
|
|
475
|
-
if (hasWindow()) window.removeEventListener("popstate", onPopState);
|
|
476
|
-
listenerInstalled = false;
|
|
477
|
-
};
|
|
478
|
-
var installPatch = () => {
|
|
479
|
-
if (patchInstalled || !hasHistory()) return;
|
|
480
|
-
origPushState = history.pushState;
|
|
481
|
-
origReplaceState = history.replaceState;
|
|
482
|
-
patchedPushState = function(...args) {
|
|
483
|
-
origPushState.apply(this, args);
|
|
484
|
-
if (internalDepth === 0) notifyRouteChange();
|
|
485
|
-
};
|
|
486
|
-
patchedReplaceState = function(...args) {
|
|
487
|
-
origReplaceState.apply(this, args);
|
|
488
|
-
if (internalDepth === 0) notifyRouteChange();
|
|
489
|
-
};
|
|
490
|
-
history.pushState = patchedPushState;
|
|
491
|
-
history.replaceState = patchedReplaceState;
|
|
492
|
-
patchInstalled = true;
|
|
493
|
-
};
|
|
494
|
-
var removePatch = () => {
|
|
495
|
-
if (!patchInstalled) return;
|
|
496
|
-
if (history.pushState === patchedPushState && origPushState) {
|
|
497
|
-
history.pushState = origPushState;
|
|
498
|
-
}
|
|
499
|
-
if (history.replaceState === patchedReplaceState && origReplaceState) {
|
|
500
|
-
history.replaceState = origReplaceState;
|
|
501
|
-
}
|
|
502
|
-
origPushState = null;
|
|
503
|
-
origReplaceState = null;
|
|
504
|
-
patchedPushState = null;
|
|
505
|
-
patchedReplaceState = null;
|
|
506
|
-
patchInstalled = false;
|
|
507
|
-
};
|
|
508
|
-
function onPopState() {
|
|
509
|
-
if (suppress > 0) {
|
|
510
|
-
suppress -= 1;
|
|
511
|
-
const rebrand = pendingRebrand;
|
|
512
|
-
pendingRebrand = null;
|
|
513
|
-
if (rebrand) rebrand();
|
|
514
|
-
maybeTeardownListener();
|
|
515
|
-
return;
|
|
516
|
-
}
|
|
517
|
-
if (entries.length === 0) {
|
|
518
|
-
notifyRouteChange();
|
|
519
|
-
maybeTeardownListener();
|
|
520
|
-
return;
|
|
373
|
+
// src/core/features/resize-observer.ts
|
|
374
|
+
function installResizeObserver(deps) {
|
|
375
|
+
if (typeof window === "undefined") {
|
|
376
|
+
return () => {
|
|
377
|
+
};
|
|
521
378
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
const
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
if (entry.surface.isTop()) {
|
|
532
|
-
target = entry;
|
|
533
|
-
targetIdx = i;
|
|
534
|
-
break;
|
|
379
|
+
const onResize = () => {
|
|
380
|
+
if (deps.isDestroyed()) return;
|
|
381
|
+
deps.recomputeSnaps();
|
|
382
|
+
const mode = deps.getMode();
|
|
383
|
+
const isVerticalAxis = mode === "bottom" || mode === "top";
|
|
384
|
+
const viewportSize2 = isVerticalAxis ? window.innerHeight : window.innerWidth;
|
|
385
|
+
const max = deps.getMaxAxisSize();
|
|
386
|
+
if (viewportSize2 > 0 && viewportSize2 < max) {
|
|
387
|
+
deps.setMaxAxisSize(viewportSize2);
|
|
535
388
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
void Promise.resolve(settled.surface.close()).then(() => {
|
|
547
|
-
if (settled.surface.isOpen()) restore(settled);
|
|
548
|
-
});
|
|
549
|
-
maybeTeardownListener();
|
|
550
|
-
}
|
|
551
|
-
function restore(entry) {
|
|
552
|
-
if (!hasWindow() || !hasHistory()) return;
|
|
553
|
-
entry.live = true;
|
|
554
|
-
runInternal(() => {
|
|
555
|
-
try {
|
|
556
|
-
history.pushState(entry.surface.markerState(), "", entry.surface.url);
|
|
557
|
-
} catch {
|
|
558
|
-
entry.live = false;
|
|
389
|
+
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
390
|
+
deps.cancelInFlight();
|
|
391
|
+
deps.newCycle();
|
|
392
|
+
const current = deps.resolveActiveSnap();
|
|
393
|
+
const newMax = deps.getMaxAxisSize();
|
|
394
|
+
const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
|
|
395
|
+
deps.setSize(targetSize);
|
|
396
|
+
if (current && !deps.isDragging()) {
|
|
397
|
+
deps.applySize(targetSize);
|
|
398
|
+
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
559
399
|
}
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
400
|
+
};
|
|
401
|
+
let resizeObserver = null;
|
|
402
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
403
|
+
resizeObserver = new ResizeObserver(onResize);
|
|
404
|
+
resizeObserver.observe(document.documentElement);
|
|
405
|
+
} else {
|
|
406
|
+
window.addEventListener("resize", onResize);
|
|
564
407
|
}
|
|
408
|
+
window.addEventListener("orientationchange", onResize);
|
|
409
|
+
const onVisibility = () => {
|
|
410
|
+
if (deps.isDestroyed()) return;
|
|
411
|
+
if (document.hidden) deps.cancelInFlight();
|
|
412
|
+
};
|
|
413
|
+
document.addEventListener("visibilitychange", onVisibility);
|
|
414
|
+
return () => {
|
|
415
|
+
resizeObserver?.disconnect();
|
|
416
|
+
window.removeEventListener("resize", onResize);
|
|
417
|
+
window.removeEventListener("orientationchange", onResize);
|
|
418
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
419
|
+
};
|
|
565
420
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
entry.live = false;
|
|
578
|
-
}
|
|
579
|
-
});
|
|
580
|
-
if (entry.live) {
|
|
581
|
-
entries.push(entry);
|
|
582
|
-
ensureListener();
|
|
583
|
-
}
|
|
584
|
-
return entry;
|
|
585
|
-
}
|
|
586
|
-
function popBackMarker(handle) {
|
|
587
|
-
if (!hasWindow() || !hasHistory()) return;
|
|
588
|
-
const entry = handle;
|
|
589
|
-
const idx = entries.indexOf(entry);
|
|
590
|
-
if (idx === -1 || !entry.live) return;
|
|
591
|
-
const last = entries.length - 1;
|
|
592
|
-
entry.live = false;
|
|
593
|
-
entries.splice(idx, 1);
|
|
594
|
-
if (idx !== last) {
|
|
595
|
-
const rebrandSurface = entries[entries.length - 1].surface;
|
|
596
|
-
const rebrandUrl = entry.priorUrl;
|
|
597
|
-
pendingRebrand = () => {
|
|
598
|
-
runInternal(() => {
|
|
599
|
-
history.replaceState(
|
|
600
|
-
rebrandSurface.markerState(),
|
|
601
|
-
"",
|
|
602
|
-
rebrandUrl !== void 0 ? rebrandUrl : location.href
|
|
603
|
-
);
|
|
604
|
-
});
|
|
605
|
-
};
|
|
606
|
-
}
|
|
607
|
-
suppress += 1;
|
|
608
|
-
runInternal(() => {
|
|
609
|
-
try {
|
|
610
|
-
history.back();
|
|
611
|
-
} catch {
|
|
612
|
-
suppress = Math.max(0, suppress - 1);
|
|
613
|
-
pendingRebrand = null;
|
|
614
|
-
}
|
|
615
|
-
});
|
|
616
|
-
maybeTeardownListener();
|
|
617
|
-
}
|
|
618
|
-
function subscribeRouteChange(fn) {
|
|
619
|
-
if (!hasWindow() || !hasHistory()) return () => {
|
|
620
|
-
};
|
|
621
|
-
subscribers.add(fn);
|
|
622
|
-
if (subscribers.size === 1) installPatch();
|
|
623
|
-
ensureListener();
|
|
624
|
-
return () => {
|
|
625
|
-
if (!subscribers.has(fn)) return;
|
|
626
|
-
subscribers.delete(fn);
|
|
627
|
-
if (subscribers.size === 0) removePatch();
|
|
628
|
-
maybeTeardownListener();
|
|
629
|
-
};
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
// src/core/features/route.ts
|
|
633
|
-
function installRoute(deps) {
|
|
634
|
-
if (typeof window === "undefined") {
|
|
635
|
-
return () => {
|
|
636
|
-
};
|
|
637
|
-
}
|
|
638
|
-
if (!deps.routedTo && !deps.closeOnBack) {
|
|
639
|
-
return () => {
|
|
640
|
-
};
|
|
641
|
-
}
|
|
642
|
-
let handle = null;
|
|
643
|
-
const onOpen = () => {
|
|
644
|
-
if (handle) return;
|
|
645
|
-
handle = pushBackMarker({
|
|
646
|
-
isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
|
|
647
|
-
isTop: deps.isTopSheet,
|
|
648
|
-
close: deps.close,
|
|
649
|
-
markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
|
|
650
|
-
url: deps.routedTo
|
|
651
|
-
});
|
|
652
|
-
};
|
|
653
|
-
const onClose = () => {
|
|
654
|
-
if (!handle) return;
|
|
655
|
-
popBackMarker(handle);
|
|
656
|
-
handle = null;
|
|
657
|
-
};
|
|
658
|
-
const unsubscribeOpen = deps.on("open", onOpen);
|
|
659
|
-
const unsubscribeClose = deps.on("close", onClose);
|
|
660
|
-
if (deps.getSize() > 0) onOpen();
|
|
661
|
-
return () => {
|
|
662
|
-
unsubscribeOpen();
|
|
663
|
-
unsubscribeClose();
|
|
664
|
-
if (handle) {
|
|
665
|
-
popBackMarker(handle);
|
|
666
|
-
handle = null;
|
|
667
|
-
}
|
|
668
|
-
};
|
|
669
|
-
}
|
|
670
|
-
function installRouteChange(deps) {
|
|
671
|
-
return subscribeRouteChange(() => {
|
|
672
|
-
if (deps.isDestroyed() || deps.getSize() <= 0) return;
|
|
673
|
-
void deps.close();
|
|
674
|
-
});
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
// src/core/features/content-swipe.ts
|
|
678
|
-
var CONTENT_PULL_THRESHOLD = 60;
|
|
679
|
-
function installContentSwipe(deps) {
|
|
680
|
-
const { container } = deps;
|
|
681
|
-
let startY = 0;
|
|
682
|
-
let startScrollTop = 0;
|
|
683
|
-
let moved = false;
|
|
684
|
-
const onTouchStart = (e) => {
|
|
685
|
-
const t = e.touches[0];
|
|
686
|
-
if (!t) return;
|
|
687
|
-
startY = t.clientY;
|
|
688
|
-
startScrollTop = container.scrollTop;
|
|
689
|
-
moved = false;
|
|
690
|
-
};
|
|
691
|
-
const onTouchMove = (e) => {
|
|
692
|
-
const t = e.touches[0];
|
|
693
|
-
if (!t) return;
|
|
694
|
-
if (Math.abs(t.clientY - startY) > CONTENT_PULL_THRESHOLD) moved = true;
|
|
695
|
-
};
|
|
696
|
-
const onTouchEnd = (e) => {
|
|
697
|
-
if (!moved) return;
|
|
698
|
-
if (deps.isDragging() || deps.isAnimating()) return;
|
|
699
|
-
if (container.scrollTop !== startScrollTop) return;
|
|
700
|
-
const t = e.changedTouches[0];
|
|
701
|
-
if (!t) return;
|
|
702
|
-
const deltaY = t.clientY - startY;
|
|
703
|
-
const atTop = container.scrollTop <= 0;
|
|
704
|
-
const allowed = deps.getAllowedIds();
|
|
705
|
-
const idx = allowed.indexOf(deps.getActiveId());
|
|
706
|
-
if (idx === -1) return;
|
|
707
|
-
if (atTop && deltaY > CONTENT_PULL_THRESHOLD && idx > 0) {
|
|
708
|
-
deps.snapTo(allowed[idx - 1]);
|
|
709
|
-
} else if (deltaY < -CONTENT_PULL_THRESHOLD && idx < allowed.length - 1) {
|
|
710
|
-
deps.snapTo(allowed[idx + 1]);
|
|
711
|
-
}
|
|
712
|
-
};
|
|
713
|
-
container.addEventListener("touchstart", onTouchStart, { passive: true });
|
|
714
|
-
container.addEventListener("touchmove", onTouchMove, { passive: true });
|
|
715
|
-
container.addEventListener("touchend", onTouchEnd, { passive: true });
|
|
716
|
-
return () => {
|
|
717
|
-
container.removeEventListener("touchstart", onTouchStart);
|
|
718
|
-
container.removeEventListener("touchmove", onTouchMove);
|
|
719
|
-
container.removeEventListener("touchend", onTouchEnd);
|
|
720
|
-
};
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
// src/core/features/visual-viewport.ts
|
|
724
|
-
var SAFETY_PAD = 8;
|
|
725
|
-
function installVisualViewport(deps) {
|
|
726
|
-
if (typeof window === "undefined" || !window.visualViewport) {
|
|
727
|
-
return () => {
|
|
728
|
-
};
|
|
729
|
-
}
|
|
730
|
-
const vv = window.visualViewport;
|
|
731
|
-
let rafId = null;
|
|
732
|
-
const onResize = () => {
|
|
733
|
-
if (rafId !== null) return;
|
|
734
|
-
rafId = requestAnimationFrame(() => {
|
|
735
|
-
rafId = null;
|
|
736
|
-
if (deps.isDestroyed()) return;
|
|
737
|
-
deps.recomputeSnaps();
|
|
738
|
-
const isVertical = deps.isVerticalAxis();
|
|
739
|
-
const visible = isVertical ? vv.height : vv.width;
|
|
740
|
-
const windowSize = isVertical ? window.innerHeight : window.innerWidth;
|
|
741
|
-
const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
|
|
742
|
-
if (clamp < deps.getMaxAxisSize()) {
|
|
743
|
-
deps.setMaxAxisSize(clamp);
|
|
744
|
-
}
|
|
745
|
-
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
746
|
-
deps.cancelInFlight();
|
|
747
|
-
deps.newCycle();
|
|
748
|
-
const max = deps.getMaxAxisSize();
|
|
749
|
-
deps.setSize(Math.min(deps.getSize(), max));
|
|
750
|
-
const current = deps.resolveActiveSnap();
|
|
751
|
-
if (current && !deps.isDragging()) {
|
|
752
|
-
deps.applySize(Math.min(current.size, max));
|
|
753
|
-
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
754
|
-
} else {
|
|
755
|
-
deps.applySize(deps.getSize());
|
|
756
|
-
}
|
|
757
|
-
});
|
|
758
|
-
};
|
|
759
|
-
vv.addEventListener("resize", onResize);
|
|
760
|
-
return () => {
|
|
761
|
-
vv.removeEventListener("resize", onResize);
|
|
762
|
-
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
763
|
-
};
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
// src/core/features/resize-observer.ts
|
|
767
|
-
function installResizeObserver(deps) {
|
|
768
|
-
if (typeof window === "undefined") {
|
|
769
|
-
return () => {
|
|
770
|
-
};
|
|
771
|
-
}
|
|
772
|
-
const onResize = () => {
|
|
773
|
-
if (deps.isDestroyed()) return;
|
|
774
|
-
deps.recomputeSnaps();
|
|
775
|
-
const mode = deps.getMode();
|
|
776
|
-
const isVerticalAxis = mode === "bottom" || mode === "top";
|
|
777
|
-
const viewportSize2 = isVerticalAxis ? window.innerHeight : window.innerWidth;
|
|
778
|
-
const max = deps.getMaxAxisSize();
|
|
779
|
-
if (viewportSize2 > 0 && viewportSize2 < max) {
|
|
780
|
-
deps.setMaxAxisSize(viewportSize2);
|
|
781
|
-
}
|
|
782
|
-
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
783
|
-
deps.cancelInFlight();
|
|
784
|
-
deps.newCycle();
|
|
785
|
-
const current = deps.resolveActiveSnap();
|
|
786
|
-
const newMax = deps.getMaxAxisSize();
|
|
787
|
-
const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
|
|
788
|
-
deps.setSize(targetSize);
|
|
789
|
-
if (current && !deps.isDragging()) {
|
|
790
|
-
deps.applySize(targetSize);
|
|
791
|
-
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
792
|
-
}
|
|
793
|
-
};
|
|
794
|
-
let resizeObserver = null;
|
|
795
|
-
if (typeof ResizeObserver !== "undefined") {
|
|
796
|
-
resizeObserver = new ResizeObserver(onResize);
|
|
797
|
-
resizeObserver.observe(document.documentElement);
|
|
798
|
-
} else {
|
|
799
|
-
window.addEventListener("resize", onResize);
|
|
800
|
-
}
|
|
801
|
-
window.addEventListener("orientationchange", onResize);
|
|
802
|
-
const onVisibility = () => {
|
|
803
|
-
if (deps.isDestroyed()) return;
|
|
804
|
-
if (document.hidden) deps.cancelInFlight();
|
|
805
|
-
};
|
|
806
|
-
document.addEventListener("visibilitychange", onVisibility);
|
|
807
|
-
return () => {
|
|
808
|
-
resizeObserver?.disconnect();
|
|
809
|
-
window.removeEventListener("resize", onResize);
|
|
810
|
-
window.removeEventListener("orientationchange", onResize);
|
|
811
|
-
document.removeEventListener("visibilitychange", onVisibility);
|
|
812
|
-
};
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
// src/core/features/fit-observer.ts
|
|
816
|
-
var contentTargets = (scroller) => {
|
|
817
|
-
if (!scroller) return [];
|
|
818
|
-
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
819
|
-
const out = [];
|
|
820
|
-
for (const child of Array.from(scroller.children)) {
|
|
821
|
-
if (hasSlot && child instanceof HTMLSlotElement) {
|
|
822
|
-
for (const el of child.assignedElements()) out.push(el);
|
|
823
|
-
} else {
|
|
824
|
-
out.push(child);
|
|
421
|
+
|
|
422
|
+
// src/core/features/fit-observer.ts
|
|
423
|
+
var contentTargets = (scroller) => {
|
|
424
|
+
if (!scroller) return [];
|
|
425
|
+
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
426
|
+
const out = [];
|
|
427
|
+
for (const child of Array.from(scroller.children)) {
|
|
428
|
+
if (hasSlot && child instanceof HTMLSlotElement) {
|
|
429
|
+
for (const el of child.assignedElements()) out.push(el);
|
|
430
|
+
} else {
|
|
431
|
+
out.push(child);
|
|
825
432
|
}
|
|
826
433
|
}
|
|
827
434
|
return out;
|
|
@@ -941,11 +548,15 @@ function createMaxHeightController(deps) {
|
|
|
941
548
|
|
|
942
549
|
// src/core/features/fit-measurement.ts
|
|
943
550
|
var measureSheetNatural = (element, content, vertical) => {
|
|
944
|
-
if (!content) {
|
|
945
|
-
return vertical ? element.offsetHeight : element.offsetWidth;
|
|
946
|
-
}
|
|
947
551
|
const axis = vertical ? "height" : "width";
|
|
948
552
|
const sheetStyle = element.style;
|
|
553
|
+
if (!content) {
|
|
554
|
+
const prev = sheetStyle[axis];
|
|
555
|
+
sheetStyle[axis] = "auto";
|
|
556
|
+
const poked2 = vertical ? element.offsetHeight : element.offsetWidth;
|
|
557
|
+
sheetStyle[axis] = prev;
|
|
558
|
+
return poked2;
|
|
559
|
+
}
|
|
949
560
|
const cs = content.style;
|
|
950
561
|
const prevSheet = sheetStyle[axis];
|
|
951
562
|
const prevFlex = cs.flex;
|
|
@@ -1659,6 +1270,52 @@ function resolveAnimationPreset(animation) {
|
|
|
1659
1270
|
}
|
|
1660
1271
|
}
|
|
1661
1272
|
|
|
1273
|
+
// src/core/animation/waapi-settle.ts
|
|
1274
|
+
var SIM_HZ = 240;
|
|
1275
|
+
var SAMPLE_STRIDE = 4;
|
|
1276
|
+
var MAX_SIM_MS = 3e3;
|
|
1277
|
+
function sampleSpringSettle(from, to, velocityPxPerS, config) {
|
|
1278
|
+
const cfg = { ...DEFAULT_SPRING, ...config };
|
|
1279
|
+
const subDt = 1 / SIM_HZ;
|
|
1280
|
+
const stepMs = SAMPLE_STRIDE / SIM_HZ * 1e3;
|
|
1281
|
+
const maxSteps = Math.ceil(MAX_SIM_MS / 1e3 * SIM_HZ);
|
|
1282
|
+
const values = [from];
|
|
1283
|
+
let x = from;
|
|
1284
|
+
let v = velocityPxPerS;
|
|
1285
|
+
for (let i = 1; i <= maxSteps; i += 1) {
|
|
1286
|
+
const force = -cfg.stiffness * (x - to) - cfg.damping * v;
|
|
1287
|
+
v += force / cfg.mass * subDt;
|
|
1288
|
+
x += v * subDt;
|
|
1289
|
+
if (!Number.isFinite(x) || !Number.isFinite(v)) {
|
|
1290
|
+
values.push(to);
|
|
1291
|
+
break;
|
|
1292
|
+
}
|
|
1293
|
+
if (i % SAMPLE_STRIDE === 0) values.push(x);
|
|
1294
|
+
const atRest = Math.abs(to - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
|
|
1295
|
+
if (atRest) break;
|
|
1296
|
+
}
|
|
1297
|
+
if (values[values.length - 1] !== to) values.push(to);
|
|
1298
|
+
return {
|
|
1299
|
+
values,
|
|
1300
|
+
stepMs,
|
|
1301
|
+
durationMs: (values.length - 1) * stepMs
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
function sampleTweenSettle(from, to, durationMs, easing) {
|
|
1305
|
+
const count = Math.max(2, Math.min(60, Math.round(durationMs / 16)));
|
|
1306
|
+
const values = [];
|
|
1307
|
+
for (let i = 0; i <= count; i += 1) {
|
|
1308
|
+
const t = i / count;
|
|
1309
|
+
values.push(from + (to - from) * easing(t));
|
|
1310
|
+
}
|
|
1311
|
+
values[values.length - 1] = to;
|
|
1312
|
+
return {
|
|
1313
|
+
values,
|
|
1314
|
+
stepMs: durationMs / count,
|
|
1315
|
+
durationMs
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1662
1319
|
// src/core/controllers/animation-runner.ts
|
|
1663
1320
|
var DEFAULT_DURATION2 = 220;
|
|
1664
1321
|
var VELOCITY_PX_PER_S = 1e3;
|
|
@@ -1669,6 +1326,10 @@ var AnimationRunner = class {
|
|
|
1669
1326
|
__publicField(this, "applySizeFn");
|
|
1670
1327
|
__publicField(this, "getSize");
|
|
1671
1328
|
__publicField(this, "isDragging");
|
|
1329
|
+
__publicField(this, "applyAux");
|
|
1330
|
+
__publicField(this, "getTransformFor");
|
|
1331
|
+
__publicField(this, "settleWaapi");
|
|
1332
|
+
__publicField(this, "currentWaapi", null);
|
|
1672
1333
|
__publicField(this, "animationKind");
|
|
1673
1334
|
__publicField(this, "springConfig");
|
|
1674
1335
|
__publicField(this, "duration");
|
|
@@ -1684,6 +1345,9 @@ var AnimationRunner = class {
|
|
|
1684
1345
|
this.applySizeFn = deps.applySize;
|
|
1685
1346
|
this.getSize = deps.getSize;
|
|
1686
1347
|
this.isDragging = deps.isDragging;
|
|
1348
|
+
this.applyAux = deps.applyAux;
|
|
1349
|
+
this.getTransformFor = deps.getTransformFor;
|
|
1350
|
+
this.settleWaapi = opts.settleAnimation === "waapi";
|
|
1687
1351
|
const preset = resolveAnimationPreset(opts.animation);
|
|
1688
1352
|
this.animationKind = preset.kind;
|
|
1689
1353
|
this.duration = opts.duration ?? preset.duration ?? DEFAULT_DURATION2;
|
|
@@ -1708,11 +1372,20 @@ var AnimationRunner = class {
|
|
|
1708
1372
|
}
|
|
1709
1373
|
}
|
|
1710
1374
|
get isAnimating() {
|
|
1711
|
-
return this.currentTween !== null || this.currentSpring !== null;
|
|
1375
|
+
return this.currentTween !== null || this.currentSpring !== null || this.currentWaapi !== null;
|
|
1712
1376
|
}
|
|
1713
1377
|
cancel() {
|
|
1714
1378
|
this.currentTween?.cancel();
|
|
1715
1379
|
this.currentSpring?.cancel();
|
|
1380
|
+
if (this.currentWaapi) {
|
|
1381
|
+
const entry = this.currentWaapi;
|
|
1382
|
+
this.currentWaapi = null;
|
|
1383
|
+
entry.stop();
|
|
1384
|
+
try {
|
|
1385
|
+
entry.anim.cancel();
|
|
1386
|
+
} catch {
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1716
1389
|
}
|
|
1717
1390
|
async animateTo(target, velocityPxPerMs) {
|
|
1718
1391
|
if (target === this.getSize()) {
|
|
@@ -1731,7 +1404,28 @@ var AnimationRunner = class {
|
|
|
1731
1404
|
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1732
1405
|
return;
|
|
1733
1406
|
}
|
|
1734
|
-
if (this.
|
|
1407
|
+
if (this.settleWaapi && this.applyAux && this.getTransformFor && typeof this.element.animate === "function") {
|
|
1408
|
+
const samples = this.animationKind === "spring" ? sampleSpringSettle(
|
|
1409
|
+
this.getSize(),
|
|
1410
|
+
target,
|
|
1411
|
+
velocityPxPerMs * VELOCITY_PX_PER_S,
|
|
1412
|
+
this.springConfig
|
|
1413
|
+
) : sampleTweenSettle(
|
|
1414
|
+
this.getSize(),
|
|
1415
|
+
target,
|
|
1416
|
+
this.duration,
|
|
1417
|
+
this.easing
|
|
1418
|
+
);
|
|
1419
|
+
if (samples.values.length >= 2 && samples.durationMs > 0) {
|
|
1420
|
+
await this.runWaapiSettle(samples, target);
|
|
1421
|
+
if (!this.isAnimating) {
|
|
1422
|
+
this.getRootEl()?.removeAttribute("data-animating");
|
|
1423
|
+
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1424
|
+
}
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
if (this.animationKind === "spring") {
|
|
1735
1429
|
const spring = runSpring({
|
|
1736
1430
|
from: this.getSize(),
|
|
1737
1431
|
to: target,
|
|
@@ -1759,11 +1453,66 @@ var AnimationRunner = class {
|
|
|
1759
1453
|
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1760
1454
|
}
|
|
1761
1455
|
}
|
|
1456
|
+
async runWaapiSettle(samples, target) {
|
|
1457
|
+
const applyAux = this.applyAux;
|
|
1458
|
+
const getTransformFor = this.getTransformFor;
|
|
1459
|
+
const frames = samples.values.map((v) => ({
|
|
1460
|
+
transform: getTransformFor(v)
|
|
1461
|
+
}));
|
|
1462
|
+
const anim = this.element.animate(frames, {
|
|
1463
|
+
duration: samples.durationMs,
|
|
1464
|
+
easing: "linear",
|
|
1465
|
+
fill: "forwards"
|
|
1466
|
+
});
|
|
1467
|
+
let stopped = false;
|
|
1468
|
+
let auxRaf = 0;
|
|
1469
|
+
const start = performance.now();
|
|
1470
|
+
const lastIdx = samples.values.length - 1;
|
|
1471
|
+
const auxTick = () => {
|
|
1472
|
+
if (stopped) return;
|
|
1473
|
+
const elapsed = performance.now() - start;
|
|
1474
|
+
const idx = Math.min(Math.floor(elapsed / samples.stepMs), lastIdx);
|
|
1475
|
+
applyAux(samples.values[idx]);
|
|
1476
|
+
auxRaf = requestAnimationFrame(auxTick);
|
|
1477
|
+
};
|
|
1478
|
+
auxRaf = requestAnimationFrame(auxTick);
|
|
1479
|
+
const entry = {
|
|
1480
|
+
anim,
|
|
1481
|
+
stop: () => {
|
|
1482
|
+
stopped = true;
|
|
1483
|
+
cancelAnimationFrame(auxRaf);
|
|
1484
|
+
}
|
|
1485
|
+
};
|
|
1486
|
+
this.currentWaapi = entry;
|
|
1487
|
+
try {
|
|
1488
|
+
await anim.finished;
|
|
1489
|
+
} catch {
|
|
1490
|
+
}
|
|
1491
|
+
entry.stop();
|
|
1492
|
+
const wasCurrent = this.currentWaapi === entry;
|
|
1493
|
+
if (wasCurrent) this.currentWaapi = null;
|
|
1494
|
+
if (wasCurrent && anim.playState === "finished") {
|
|
1495
|
+
this.applySizeFn(target);
|
|
1496
|
+
try {
|
|
1497
|
+
anim.cancel();
|
|
1498
|
+
} catch {
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1762
1502
|
destroy() {
|
|
1763
1503
|
this.detachReducedMotion?.();
|
|
1764
1504
|
this.detachReducedMotion = null;
|
|
1765
1505
|
this.currentTween = null;
|
|
1766
1506
|
this.currentSpring = null;
|
|
1507
|
+
if (this.currentWaapi) {
|
|
1508
|
+
const entry = this.currentWaapi;
|
|
1509
|
+
this.currentWaapi = null;
|
|
1510
|
+
entry.stop();
|
|
1511
|
+
try {
|
|
1512
|
+
entry.anim.cancel();
|
|
1513
|
+
} catch {
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1767
1516
|
}
|
|
1768
1517
|
};
|
|
1769
1518
|
|
|
@@ -2620,7 +2369,7 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2620
2369
|
const initialAllowed = opts.allowed ?? opts.snapPoints.map((p) => p.id);
|
|
2621
2370
|
let initialId = opts.initial ?? initialAllowed[0] ?? opts.snapPoints[0]?.id ?? "default";
|
|
2622
2371
|
if (opts.persistKey) {
|
|
2623
|
-
const restored =
|
|
2372
|
+
const restored = readPersistedIdSafe(opts.persistKey);
|
|
2624
2373
|
if (restored && initialAllowed.includes(restored)) {
|
|
2625
2374
|
initialId = restored;
|
|
2626
2375
|
}
|
|
@@ -2651,6 +2400,7 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2651
2400
|
},
|
|
2652
2401
|
animation: {
|
|
2653
2402
|
animation: opts.animation,
|
|
2403
|
+
settleAnimation: opts.settleAnimation,
|
|
2654
2404
|
duration: opts.duration,
|
|
2655
2405
|
easing: opts.easing,
|
|
2656
2406
|
spring: opts.spring,
|
|
@@ -2668,6 +2418,15 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2668
2418
|
}
|
|
2669
2419
|
};
|
|
2670
2420
|
}
|
|
2421
|
+
var readPersistedIdSafe = (key) => {
|
|
2422
|
+
if (typeof window === "undefined") return null;
|
|
2423
|
+
if (typeof localStorage === "undefined") return null;
|
|
2424
|
+
try {
|
|
2425
|
+
return localStorage.getItem(key);
|
|
2426
|
+
} catch {
|
|
2427
|
+
return null;
|
|
2428
|
+
}
|
|
2429
|
+
};
|
|
2671
2430
|
|
|
2672
2431
|
// src/core/primitives/teardown-stack.ts
|
|
2673
2432
|
var TeardownStack = class {
|
|
@@ -2690,9 +2449,9 @@ var TeardownStack = class {
|
|
|
2690
2449
|
}
|
|
2691
2450
|
};
|
|
2692
2451
|
|
|
2693
|
-
// src/core/
|
|
2452
|
+
// src/core/BottomSheetCore.ts
|
|
2694
2453
|
var HAPTIC_DURATION_MS = 8;
|
|
2695
|
-
var
|
|
2454
|
+
var BottomSheetCore = class {
|
|
2696
2455
|
constructor(opts) {
|
|
2697
2456
|
__publicField(this, "id", nextInstanceId("bs"));
|
|
2698
2457
|
__publicField(this, "element");
|
|
@@ -2753,6 +2512,8 @@ var BottomSheetEngine = class {
|
|
|
2753
2512
|
__publicField(this, "stackEffectPrimed", false);
|
|
2754
2513
|
__publicField(this, "fitDeps");
|
|
2755
2514
|
__publicField(this, "transformTemplate");
|
|
2515
|
+
__publicField(this, "featureList", []);
|
|
2516
|
+
__publicField(this, "featureCtx");
|
|
2756
2517
|
const resolved = resolveEngineOptions(opts, {
|
|
2757
2518
|
shouldApplyInertSiblings: () => {
|
|
2758
2519
|
if (typeof document === "undefined") return false;
|
|
@@ -2799,7 +2560,9 @@ var BottomSheetEngine = class {
|
|
|
2799
2560
|
getRootEl: () => this.rootEl,
|
|
2800
2561
|
applySize: (size) => this.applySize(size),
|
|
2801
2562
|
getSize: () => this.size,
|
|
2802
|
-
isDragging: () => this.gesture?.isDragging ?? false
|
|
2563
|
+
isDragging: () => this.gesture?.isDragging ?? false,
|
|
2564
|
+
applyAux: (size) => this.applySize(size, true),
|
|
2565
|
+
getTransformFor: (size) => this.transformTemplate(this.snaps.getMaxAxisSize() - size)
|
|
2803
2566
|
},
|
|
2804
2567
|
resolved.animation
|
|
2805
2568
|
);
|
|
@@ -2822,6 +2585,11 @@ var BottomSheetEngine = class {
|
|
|
2822
2585
|
if (opts.linkedSheets) {
|
|
2823
2586
|
this.linkedSheets = opts.linkedSheets;
|
|
2824
2587
|
}
|
|
2588
|
+
const byName = /* @__PURE__ */ new Map();
|
|
2589
|
+
for (const feature of opts.features ?? []) {
|
|
2590
|
+
byName.set(feature.name, feature);
|
|
2591
|
+
}
|
|
2592
|
+
this.featureList = Array.from(byName.values());
|
|
2825
2593
|
this.activeId = resolved.initialId;
|
|
2826
2594
|
auditVhUsage(this.snapPointsRaw);
|
|
2827
2595
|
this.auditDuplicateSnapIds(this.snapPointsRaw);
|
|
@@ -2858,6 +2626,7 @@ var BottomSheetEngine = class {
|
|
|
2858
2626
|
scrollContainer: this.scrollContainer,
|
|
2859
2627
|
getMaxAxisSize: () => this.snaps.getMaxAxisSize()
|
|
2860
2628
|
});
|
|
2629
|
+
this.featureCtx = this.buildFeatureContext(opts.autoCollapseAfter);
|
|
2861
2630
|
this.attach();
|
|
2862
2631
|
this.registerInStack();
|
|
2863
2632
|
if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
|
|
@@ -2866,12 +2635,7 @@ var BottomSheetEngine = class {
|
|
|
2866
2635
|
if (!entry.isIntersecting) continue;
|
|
2867
2636
|
if (this.destroyed) return;
|
|
2868
2637
|
this.snaps.recompute();
|
|
2869
|
-
|
|
2870
|
-
if (current) {
|
|
2871
|
-
this.size = current.size;
|
|
2872
|
-
this.applySize(this.size);
|
|
2873
|
-
this.updateAriaSlider();
|
|
2874
|
-
}
|
|
2638
|
+
this.healActiveSnap();
|
|
2875
2639
|
io.disconnect();
|
|
2876
2640
|
return;
|
|
2877
2641
|
}
|
|
@@ -2894,46 +2658,77 @@ var BottomSheetEngine = class {
|
|
|
2894
2658
|
if (resolved.radius !== void 0) this.setRadius(resolved.radius);
|
|
2895
2659
|
if (resolved.maxHeight !== void 0) this.setMaxHeight(resolved.maxHeight);
|
|
2896
2660
|
this.applyAutoAriaLabelledBy();
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
getSize: () => this.size,
|
|
2902
|
-
close: () => this.close()
|
|
2903
|
-
})
|
|
2904
|
-
);
|
|
2905
|
-
}
|
|
2906
|
-
if (this.persistKey) {
|
|
2907
|
-
this.teardowns.add(installPersist(this, this.persistKey));
|
|
2661
|
+
this.runFeatureStage("post");
|
|
2662
|
+
this.warnOrphanFeatureOptions();
|
|
2663
|
+
if (this.size > 0) {
|
|
2664
|
+
this.handleOpen();
|
|
2908
2665
|
}
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
resolveSnap: (id) => this.snaps.findById(id),
|
|
2917
|
-
snapTo: (id) => {
|
|
2918
|
-
void this.snapTo(id);
|
|
2919
|
-
},
|
|
2920
|
-
on: (event, fn) => this.on(event, fn)
|
|
2921
|
-
})
|
|
2922
|
-
);
|
|
2923
|
-
this.teardowns.add(
|
|
2924
|
-
installRoute({
|
|
2666
|
+
}
|
|
2667
|
+
buildFeatureContext(autoCollapseAfter) {
|
|
2668
|
+
return {
|
|
2669
|
+
element: this.element,
|
|
2670
|
+
scrollContainer: this.scrollContainer,
|
|
2671
|
+
sheetId: this.id,
|
|
2672
|
+
options: {
|
|
2925
2673
|
routedTo: this.routedTo,
|
|
2926
2674
|
closeOnBack: this.closeOnBack,
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
this.
|
|
2675
|
+
closeOnRouteChange: this.closeOnRouteChange,
|
|
2676
|
+
persistKey: this.persistKey,
|
|
2677
|
+
autoCollapseAfter
|
|
2678
|
+
},
|
|
2679
|
+
isDestroyed: () => this.destroyed,
|
|
2680
|
+
isDragging: () => this.gesture?.isDragging ?? false,
|
|
2681
|
+
isAnimating: () => this.animation.isAnimating,
|
|
2682
|
+
isTopSheet: () => this.isTopSheet,
|
|
2683
|
+
isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
|
|
2684
|
+
getSize: () => this.size,
|
|
2685
|
+
getActiveId: () => this.activeId,
|
|
2686
|
+
getAllowedIds: () => this.snaps.getAllowedIds().slice(),
|
|
2687
|
+
allowedIdsBySize: () => this.allowedIdsBySize(),
|
|
2688
|
+
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
2689
|
+
resolveSnap: (id) => this.snaps.findById(id),
|
|
2690
|
+
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
2691
|
+
setSize: (size) => {
|
|
2692
|
+
this.size = size;
|
|
2693
|
+
},
|
|
2694
|
+
setMaxAxisSize: (size) => {
|
|
2695
|
+
this.snaps.setMaxAxisSize(size);
|
|
2696
|
+
},
|
|
2697
|
+
applySize: (size) => this.applySize(size),
|
|
2698
|
+
recomputeSnaps: () => this.recomputeSnaps(),
|
|
2699
|
+
newCycle: () => {
|
|
2700
|
+
this.newCycle();
|
|
2701
|
+
},
|
|
2702
|
+
cancelInFlight: () => {
|
|
2703
|
+
this.animation.cancel();
|
|
2704
|
+
},
|
|
2705
|
+
resyncAfterResize: () => this.resyncAfterResize(),
|
|
2706
|
+
snapTo: (id) => {
|
|
2707
|
+
void this.snapTo(id);
|
|
2708
|
+
},
|
|
2709
|
+
close: (reason) => this.close(reason),
|
|
2710
|
+
on: (event, fn) => this.on(event, fn),
|
|
2711
|
+
addTeardown: (fn) => this.teardowns.add(fn)
|
|
2712
|
+
};
|
|
2713
|
+
}
|
|
2714
|
+
runFeatureStage(stage) {
|
|
2715
|
+
for (const feature of this.featureList) {
|
|
2716
|
+
if ((feature.stage ?? "post") !== stage) continue;
|
|
2717
|
+
const teardown = feature.install(this.featureCtx);
|
|
2718
|
+
if (teardown) this.teardowns.add(teardown);
|
|
2719
|
+
}
|
|
2720
|
+
}
|
|
2721
|
+
warnOrphanFeatureOptions() {
|
|
2722
|
+
const names = new Set(this.featureList.map((f) => f.name));
|
|
2723
|
+
if ((this.closeOnBack || this.routedTo !== void 0 || this.closeOnRouteChange) && !names.has("route")) {
|
|
2724
|
+
devWarn(
|
|
2725
|
+
"[BottomSheet] closeOnBack/routedTo/closeOnRouteChange need routeFeature() \u2014 option ignored"
|
|
2726
|
+
);
|
|
2727
|
+
}
|
|
2728
|
+
if (this.persistKey && !names.has("persist")) {
|
|
2729
|
+
devWarn(
|
|
2730
|
+
"[BottomSheet] persistKey needs persistFeature() \u2014 snaps will not be saved"
|
|
2731
|
+
);
|
|
2937
2732
|
}
|
|
2938
2733
|
}
|
|
2939
2734
|
get state() {
|
|
@@ -3035,6 +2830,8 @@ var BottomSheetEngine = class {
|
|
|
3035
2830
|
const vt = document.startViewTransition(() => {
|
|
3036
2831
|
this.applySize(target.size);
|
|
3037
2832
|
});
|
|
2833
|
+
vt.ready?.catch(() => {
|
|
2834
|
+
});
|
|
3038
2835
|
this.currentViewTransition = vt;
|
|
3039
2836
|
try {
|
|
3040
2837
|
await vt.finished;
|
|
@@ -3286,11 +3083,16 @@ var BottomSheetEngine = class {
|
|
|
3286
3083
|
this.maxHeight.clampTo();
|
|
3287
3084
|
this.scrim.invalidateOpacityCache();
|
|
3288
3085
|
if (this.gesture?.isDragging) return;
|
|
3086
|
+
this.healActiveSnap();
|
|
3087
|
+
}
|
|
3088
|
+
healActiveSnap() {
|
|
3289
3089
|
const current = this.snaps.findById(this.activeId);
|
|
3290
|
-
if (current)
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3090
|
+
if (!current) return;
|
|
3091
|
+
this.size = current.size;
|
|
3092
|
+
this.applySize(this.size);
|
|
3093
|
+
this.updateAriaSlider();
|
|
3094
|
+
if (this.size > 0 && !this.lifecycle.isInstalled && !this.opening && !this.animation.isAnimating) {
|
|
3095
|
+
this.emitOpenSequence(this.activeId);
|
|
3294
3096
|
}
|
|
3295
3097
|
}
|
|
3296
3098
|
destroy() {
|
|
@@ -3469,18 +3271,7 @@ var BottomSheetEngine = class {
|
|
|
3469
3271
|
}
|
|
3470
3272
|
}
|
|
3471
3273
|
attachFeatures() {
|
|
3472
|
-
|
|
3473
|
-
this.teardowns.add(installContentSwipe({
|
|
3474
|
-
container: this.scrollContainer,
|
|
3475
|
-
isDragging: () => this.gesture?.isDragging ?? false,
|
|
3476
|
-
isAnimating: () => this.animation.isAnimating,
|
|
3477
|
-
getAllowedIds: () => this.allowedIdsBySize(),
|
|
3478
|
-
getActiveId: () => this.activeId,
|
|
3479
|
-
snapTo: (id) => {
|
|
3480
|
-
void this.snapTo(id);
|
|
3481
|
-
}
|
|
3482
|
-
}));
|
|
3483
|
-
}
|
|
3274
|
+
this.runFeatureStage("attach");
|
|
3484
3275
|
if (typeof window !== "undefined") {
|
|
3485
3276
|
this.teardowns.add(installResizeObserver({
|
|
3486
3277
|
element: this.element,
|
|
@@ -3520,31 +3311,6 @@ var BottomSheetEngine = class {
|
|
|
3520
3311
|
() => document.removeEventListener("keydown", onKey)
|
|
3521
3312
|
);
|
|
3522
3313
|
}
|
|
3523
|
-
this.teardowns.add(installVisualViewport({
|
|
3524
|
-
element: this.element,
|
|
3525
|
-
isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
|
|
3526
|
-
isDestroyed: () => this.destroyed,
|
|
3527
|
-
isDragging: () => this.gesture?.isDragging ?? false,
|
|
3528
|
-
recomputeSnaps: () => this.recomputeSnaps(),
|
|
3529
|
-
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
3530
|
-
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
3531
|
-
getSize: () => this.size,
|
|
3532
|
-
setMaxAxisSize: (size) => {
|
|
3533
|
-
this.snaps.setMaxAxisSize(size);
|
|
3534
|
-
},
|
|
3535
|
-
setSize: (size) => {
|
|
3536
|
-
this.size = size;
|
|
3537
|
-
},
|
|
3538
|
-
applySize: (size) => this.applySize(size),
|
|
3539
|
-
cancelInFlight: () => {
|
|
3540
|
-
this.animation.cancel();
|
|
3541
|
-
},
|
|
3542
|
-
newCycle: () => {
|
|
3543
|
-
this.newCycle();
|
|
3544
|
-
},
|
|
3545
|
-
isAnimating: () => this.animation.isAnimating,
|
|
3546
|
-
resyncAfterCancel: () => this.resyncAfterResize()
|
|
3547
|
-
}));
|
|
3548
3314
|
}
|
|
3549
3315
|
this.teardowns.add(installSliderKeyboard({
|
|
3550
3316
|
handle: this.handle,
|
|
@@ -3621,13 +3387,13 @@ var BottomSheetEngine = class {
|
|
|
3621
3387
|
}
|
|
3622
3388
|
}
|
|
3623
3389
|
}
|
|
3624
|
-
applySize(size) {
|
|
3390
|
+
applySize(size, skipTransform = false) {
|
|
3625
3391
|
const cap = this.snaps.getMaxAxisSize();
|
|
3626
3392
|
const clamped = cap > 0 && size > cap && !this.gesture?.isDragging && !this.allowOvershoot ? cap : size;
|
|
3627
3393
|
this.size = clamped;
|
|
3628
3394
|
const offset = cap - clamped;
|
|
3629
3395
|
const style = this.element.style;
|
|
3630
|
-
style.transform = this.transformTemplate(offset);
|
|
3396
|
+
if (!skipTransform) style.transform = this.transformTemplate(offset);
|
|
3631
3397
|
if (this.sizeWriteSentinel.shouldWrite(clamped, SIZE_WRITE_EPSILON)) {
|
|
3632
3398
|
style.setProperty("--bs-size", `${clamped}px`);
|
|
3633
3399
|
if (this.scrimParent) {
|
|
@@ -3705,6 +3471,514 @@ var BottomSheetEngine = class {
|
|
|
3705
3471
|
}
|
|
3706
3472
|
};
|
|
3707
3473
|
|
|
3474
|
+
// src/core/features/history-coordinator.ts
|
|
3475
|
+
var entries = [];
|
|
3476
|
+
var subscribers = /* @__PURE__ */ new Set();
|
|
3477
|
+
var suppress = 0;
|
|
3478
|
+
var internalDepth = 0;
|
|
3479
|
+
var pendingRebrands = [];
|
|
3480
|
+
var listenerInstalled = false;
|
|
3481
|
+
var patchInstalled = false;
|
|
3482
|
+
var origPushState = null;
|
|
3483
|
+
var origReplaceState = null;
|
|
3484
|
+
var patchedPushState = null;
|
|
3485
|
+
var patchedReplaceState = null;
|
|
3486
|
+
var hasWindow = () => typeof window !== "undefined";
|
|
3487
|
+
var hasHistory = () => typeof history !== "undefined";
|
|
3488
|
+
var brandMarker = (surface) => ({
|
|
3489
|
+
...surface.markerState(),
|
|
3490
|
+
__bs: true
|
|
3491
|
+
});
|
|
3492
|
+
var runInternal = (fn) => {
|
|
3493
|
+
internalDepth += 1;
|
|
3494
|
+
try {
|
|
3495
|
+
fn();
|
|
3496
|
+
} finally {
|
|
3497
|
+
internalDepth -= 1;
|
|
3498
|
+
}
|
|
3499
|
+
};
|
|
3500
|
+
var notifyRouteChange = () => {
|
|
3501
|
+
const snapshot = Array.from(subscribers);
|
|
3502
|
+
for (const fn of snapshot) fn();
|
|
3503
|
+
};
|
|
3504
|
+
var ensureListener = () => {
|
|
3505
|
+
if (listenerInstalled || !hasWindow()) return;
|
|
3506
|
+
window.addEventListener("popstate", onPopState);
|
|
3507
|
+
listenerInstalled = true;
|
|
3508
|
+
};
|
|
3509
|
+
var maybeTeardownListener = () => {
|
|
3510
|
+
if (!listenerInstalled) return;
|
|
3511
|
+
if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
|
|
3512
|
+
if (hasWindow()) window.removeEventListener("popstate", onPopState);
|
|
3513
|
+
listenerInstalled = false;
|
|
3514
|
+
};
|
|
3515
|
+
var installPatch = () => {
|
|
3516
|
+
if (patchInstalled || !hasHistory()) return;
|
|
3517
|
+
origPushState = history.pushState;
|
|
3518
|
+
origReplaceState = history.replaceState;
|
|
3519
|
+
patchedPushState = function(...args) {
|
|
3520
|
+
origPushState.apply(this, args);
|
|
3521
|
+
if (internalDepth === 0) notifyRouteChange();
|
|
3522
|
+
};
|
|
3523
|
+
patchedReplaceState = function(...args) {
|
|
3524
|
+
origReplaceState.apply(this, args);
|
|
3525
|
+
if (internalDepth === 0) notifyRouteChange();
|
|
3526
|
+
};
|
|
3527
|
+
history.pushState = patchedPushState;
|
|
3528
|
+
history.replaceState = patchedReplaceState;
|
|
3529
|
+
patchInstalled = true;
|
|
3530
|
+
};
|
|
3531
|
+
var removePatch = () => {
|
|
3532
|
+
if (!patchInstalled) return;
|
|
3533
|
+
if (history.pushState === patchedPushState && origPushState) {
|
|
3534
|
+
history.pushState = origPushState;
|
|
3535
|
+
}
|
|
3536
|
+
if (history.replaceState === patchedReplaceState && origReplaceState) {
|
|
3537
|
+
history.replaceState = origReplaceState;
|
|
3538
|
+
}
|
|
3539
|
+
origPushState = null;
|
|
3540
|
+
origReplaceState = null;
|
|
3541
|
+
patchedPushState = null;
|
|
3542
|
+
patchedReplaceState = null;
|
|
3543
|
+
patchInstalled = false;
|
|
3544
|
+
};
|
|
3545
|
+
function onPopState() {
|
|
3546
|
+
if (suppress > 0) {
|
|
3547
|
+
suppress -= 1;
|
|
3548
|
+
const rebrand = pendingRebrands.shift();
|
|
3549
|
+
if (rebrand) rebrand();
|
|
3550
|
+
maybeTeardownListener();
|
|
3551
|
+
return;
|
|
3552
|
+
}
|
|
3553
|
+
if (entries.length === 0) {
|
|
3554
|
+
notifyRouteChange();
|
|
3555
|
+
maybeTeardownListener();
|
|
3556
|
+
return;
|
|
3557
|
+
}
|
|
3558
|
+
let target = null;
|
|
3559
|
+
let targetIdx = -1;
|
|
3560
|
+
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
3561
|
+
const entry = entries[i];
|
|
3562
|
+
if (!entry.surface.isOpen()) continue;
|
|
3563
|
+
if (!target) {
|
|
3564
|
+
target = entry;
|
|
3565
|
+
targetIdx = i;
|
|
3566
|
+
}
|
|
3567
|
+
if (entry.surface.isTop()) {
|
|
3568
|
+
target = entry;
|
|
3569
|
+
targetIdx = i;
|
|
3570
|
+
break;
|
|
3571
|
+
}
|
|
3572
|
+
}
|
|
3573
|
+
if (!target) {
|
|
3574
|
+
const removed = entries.pop();
|
|
3575
|
+
if (removed) removed.live = false;
|
|
3576
|
+
maybeTeardownListener();
|
|
3577
|
+
return;
|
|
3578
|
+
}
|
|
3579
|
+
target.live = false;
|
|
3580
|
+
entries.splice(targetIdx, 1);
|
|
3581
|
+
const settled = target;
|
|
3582
|
+
void Promise.resolve(settled.surface.close()).then(() => {
|
|
3583
|
+
if (settled.surface.isOpen()) restore(settled);
|
|
3584
|
+
});
|
|
3585
|
+
maybeTeardownListener();
|
|
3586
|
+
}
|
|
3587
|
+
function restore(entry) {
|
|
3588
|
+
if (!hasWindow() || !hasHistory()) return;
|
|
3589
|
+
entry.live = true;
|
|
3590
|
+
runInternal(() => {
|
|
3591
|
+
try {
|
|
3592
|
+
history.pushState(brandMarker(entry.surface), "", entry.surface.url);
|
|
3593
|
+
} catch {
|
|
3594
|
+
entry.live = false;
|
|
3595
|
+
}
|
|
3596
|
+
});
|
|
3597
|
+
if (entry.live) {
|
|
3598
|
+
entries.push(entry);
|
|
3599
|
+
ensureListener();
|
|
3600
|
+
}
|
|
3601
|
+
}
|
|
3602
|
+
function pushBackMarker(surface) {
|
|
3603
|
+
const entry = { surface, priorUrl: void 0, live: false };
|
|
3604
|
+
if (!hasWindow() || !hasHistory()) {
|
|
3605
|
+
return entry;
|
|
3606
|
+
}
|
|
3607
|
+
entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
|
|
3608
|
+
runInternal(() => {
|
|
3609
|
+
try {
|
|
3610
|
+
history.pushState(brandMarker(surface), "", surface.url);
|
|
3611
|
+
entry.live = true;
|
|
3612
|
+
} catch {
|
|
3613
|
+
entry.live = false;
|
|
3614
|
+
}
|
|
3615
|
+
});
|
|
3616
|
+
if (entry.live) {
|
|
3617
|
+
entries.push(entry);
|
|
3618
|
+
ensureListener();
|
|
3619
|
+
}
|
|
3620
|
+
return entry;
|
|
3621
|
+
}
|
|
3622
|
+
function popBackMarker(handle) {
|
|
3623
|
+
if (!hasWindow() || !hasHistory()) return;
|
|
3624
|
+
const entry = handle;
|
|
3625
|
+
const idx = entries.indexOf(entry);
|
|
3626
|
+
if (idx === -1 || !entry.live) return;
|
|
3627
|
+
const last = entries.length - 1;
|
|
3628
|
+
entry.live = false;
|
|
3629
|
+
entries.splice(idx, 1);
|
|
3630
|
+
let rebrand = null;
|
|
3631
|
+
if (idx !== last) {
|
|
3632
|
+
const rebrandSurface = entries[entries.length - 1].surface;
|
|
3633
|
+
const rebrandUrl = entry.priorUrl;
|
|
3634
|
+
rebrand = () => {
|
|
3635
|
+
runInternal(() => {
|
|
3636
|
+
history.replaceState(
|
|
3637
|
+
brandMarker(rebrandSurface),
|
|
3638
|
+
"",
|
|
3639
|
+
rebrandUrl !== void 0 ? rebrandUrl : location.href
|
|
3640
|
+
);
|
|
3641
|
+
});
|
|
3642
|
+
};
|
|
3643
|
+
}
|
|
3644
|
+
pendingRebrands.push(rebrand);
|
|
3645
|
+
suppress += 1;
|
|
3646
|
+
runInternal(() => {
|
|
3647
|
+
try {
|
|
3648
|
+
history.back();
|
|
3649
|
+
} catch {
|
|
3650
|
+
suppress = Math.max(0, suppress - 1);
|
|
3651
|
+
pendingRebrands.pop();
|
|
3652
|
+
}
|
|
3653
|
+
});
|
|
3654
|
+
maybeTeardownListener();
|
|
3655
|
+
}
|
|
3656
|
+
function subscribeRouteChange(fn) {
|
|
3657
|
+
if (!hasWindow() || !hasHistory()) return () => {
|
|
3658
|
+
};
|
|
3659
|
+
subscribers.add(fn);
|
|
3660
|
+
if (subscribers.size === 1) installPatch();
|
|
3661
|
+
ensureListener();
|
|
3662
|
+
return () => {
|
|
3663
|
+
if (!subscribers.has(fn)) return;
|
|
3664
|
+
subscribers.delete(fn);
|
|
3665
|
+
if (subscribers.size === 0) removePatch();
|
|
3666
|
+
maybeTeardownListener();
|
|
3667
|
+
};
|
|
3668
|
+
}
|
|
3669
|
+
|
|
3670
|
+
// src/core/features/route.ts
|
|
3671
|
+
function installRoute(deps) {
|
|
3672
|
+
if (typeof window === "undefined") {
|
|
3673
|
+
return () => {
|
|
3674
|
+
};
|
|
3675
|
+
}
|
|
3676
|
+
if (!deps.routedTo && !deps.closeOnBack) {
|
|
3677
|
+
return () => {
|
|
3678
|
+
};
|
|
3679
|
+
}
|
|
3680
|
+
let handle = null;
|
|
3681
|
+
const onOpen = () => {
|
|
3682
|
+
if (handle) return;
|
|
3683
|
+
handle = pushBackMarker({
|
|
3684
|
+
isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
|
|
3685
|
+
isTop: deps.isTopSheet,
|
|
3686
|
+
close: deps.close,
|
|
3687
|
+
markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
|
|
3688
|
+
url: deps.routedTo
|
|
3689
|
+
});
|
|
3690
|
+
};
|
|
3691
|
+
const onClose = () => {
|
|
3692
|
+
if (!handle) return;
|
|
3693
|
+
popBackMarker(handle);
|
|
3694
|
+
handle = null;
|
|
3695
|
+
};
|
|
3696
|
+
const unsubscribeOpen = deps.on("open", onOpen);
|
|
3697
|
+
const unsubscribeClose = deps.on("close", onClose);
|
|
3698
|
+
if (deps.getSize() > 0) onOpen();
|
|
3699
|
+
return () => {
|
|
3700
|
+
unsubscribeOpen();
|
|
3701
|
+
unsubscribeClose();
|
|
3702
|
+
if (handle) {
|
|
3703
|
+
popBackMarker(handle);
|
|
3704
|
+
handle = null;
|
|
3705
|
+
}
|
|
3706
|
+
};
|
|
3707
|
+
}
|
|
3708
|
+
function installRouteChange(deps) {
|
|
3709
|
+
return subscribeRouteChange(() => {
|
|
3710
|
+
if (deps.isDestroyed() || deps.getSize() <= 0) return;
|
|
3711
|
+
void deps.close();
|
|
3712
|
+
});
|
|
3713
|
+
}
|
|
3714
|
+
|
|
3715
|
+
// src/core/features/persist.ts
|
|
3716
|
+
function installPersist(engine, key) {
|
|
3717
|
+
const unsubscribe = engine.on("snap", ({ id }) => {
|
|
3718
|
+
if (typeof window === "undefined") return;
|
|
3719
|
+
if (typeof localStorage === "undefined") return;
|
|
3720
|
+
try {
|
|
3721
|
+
localStorage.setItem(key, id);
|
|
3722
|
+
} catch {
|
|
3723
|
+
}
|
|
3724
|
+
});
|
|
3725
|
+
return unsubscribe;
|
|
3726
|
+
}
|
|
3727
|
+
|
|
3728
|
+
// src/core/features/auto-collapse.ts
|
|
3729
|
+
function installAutoCollapse(deps) {
|
|
3730
|
+
const { ms } = deps;
|
|
3731
|
+
if (ms === void 0 || ms <= 0) {
|
|
3732
|
+
return () => {
|
|
3733
|
+
};
|
|
3734
|
+
}
|
|
3735
|
+
let timer = null;
|
|
3736
|
+
const clearTimer = () => {
|
|
3737
|
+
if (timer !== null) {
|
|
3738
|
+
clearTimeout(timer);
|
|
3739
|
+
timer = null;
|
|
3740
|
+
}
|
|
3741
|
+
};
|
|
3742
|
+
const fire = () => {
|
|
3743
|
+
if (deps.isDestroyed()) return;
|
|
3744
|
+
if (deps.isDragging()) return;
|
|
3745
|
+
const active = deps.resolveSnap(deps.getActiveId());
|
|
3746
|
+
if (!active || active.size === 0) return;
|
|
3747
|
+
let target = null;
|
|
3748
|
+
for (const id of deps.getAllowedIds()) {
|
|
3749
|
+
const snap = deps.resolveSnap(id);
|
|
3750
|
+
if (!snap || snap.size <= 0) continue;
|
|
3751
|
+
if (!target || snap.size < target.size) target = snap;
|
|
3752
|
+
}
|
|
3753
|
+
if (!target) return;
|
|
3754
|
+
if (target.id === active.id || target.size >= active.size) return;
|
|
3755
|
+
deps.snapTo(target.id);
|
|
3756
|
+
};
|
|
3757
|
+
const reset = () => {
|
|
3758
|
+
clearTimer();
|
|
3759
|
+
if (deps.isDestroyed()) return;
|
|
3760
|
+
timer = setTimeout(() => {
|
|
3761
|
+
timer = null;
|
|
3762
|
+
fire();
|
|
3763
|
+
}, ms);
|
|
3764
|
+
};
|
|
3765
|
+
const unsubscribe = deps.on("snap", () => reset());
|
|
3766
|
+
if ((deps.resolveSnap(deps.getActiveId())?.size ?? 0) > 0) reset();
|
|
3767
|
+
return () => {
|
|
3768
|
+
clearTimer();
|
|
3769
|
+
unsubscribe();
|
|
3770
|
+
};
|
|
3771
|
+
}
|
|
3772
|
+
|
|
3773
|
+
// src/core/features/content-swipe.ts
|
|
3774
|
+
var CONTENT_PULL_THRESHOLD = 60;
|
|
3775
|
+
function installContentSwipe(deps) {
|
|
3776
|
+
const { container } = deps;
|
|
3777
|
+
let startY = 0;
|
|
3778
|
+
let startScrollTop = 0;
|
|
3779
|
+
let moved = false;
|
|
3780
|
+
const onTouchStart = (e) => {
|
|
3781
|
+
const t = e.touches[0];
|
|
3782
|
+
if (!t) return;
|
|
3783
|
+
startY = t.clientY;
|
|
3784
|
+
startScrollTop = container.scrollTop;
|
|
3785
|
+
moved = false;
|
|
3786
|
+
};
|
|
3787
|
+
const onTouchMove = (e) => {
|
|
3788
|
+
const t = e.touches[0];
|
|
3789
|
+
if (!t) return;
|
|
3790
|
+
if (Math.abs(t.clientY - startY) > CONTENT_PULL_THRESHOLD) moved = true;
|
|
3791
|
+
};
|
|
3792
|
+
const onTouchEnd = (e) => {
|
|
3793
|
+
if (!moved) return;
|
|
3794
|
+
if (deps.isDragging() || deps.isAnimating()) return;
|
|
3795
|
+
if (container.scrollTop !== startScrollTop) return;
|
|
3796
|
+
const t = e.changedTouches[0];
|
|
3797
|
+
if (!t) return;
|
|
3798
|
+
const deltaY = t.clientY - startY;
|
|
3799
|
+
const atTop = container.scrollTop <= 0;
|
|
3800
|
+
const allowed = deps.getAllowedIds();
|
|
3801
|
+
const idx = allowed.indexOf(deps.getActiveId());
|
|
3802
|
+
if (idx === -1) return;
|
|
3803
|
+
if (atTop && deltaY > CONTENT_PULL_THRESHOLD && idx > 0) {
|
|
3804
|
+
deps.snapTo(allowed[idx - 1]);
|
|
3805
|
+
} else if (deltaY < -CONTENT_PULL_THRESHOLD && idx < allowed.length - 1) {
|
|
3806
|
+
deps.snapTo(allowed[idx + 1]);
|
|
3807
|
+
}
|
|
3808
|
+
};
|
|
3809
|
+
container.addEventListener("touchstart", onTouchStart, { passive: true });
|
|
3810
|
+
container.addEventListener("touchmove", onTouchMove, { passive: true });
|
|
3811
|
+
container.addEventListener("touchend", onTouchEnd, { passive: true });
|
|
3812
|
+
return () => {
|
|
3813
|
+
container.removeEventListener("touchstart", onTouchStart);
|
|
3814
|
+
container.removeEventListener("touchmove", onTouchMove);
|
|
3815
|
+
container.removeEventListener("touchend", onTouchEnd);
|
|
3816
|
+
};
|
|
3817
|
+
}
|
|
3818
|
+
|
|
3819
|
+
// src/core/features/visual-viewport.ts
|
|
3820
|
+
var SAFETY_PAD = 8;
|
|
3821
|
+
function installVisualViewport(deps) {
|
|
3822
|
+
if (typeof window === "undefined" || !window.visualViewport) {
|
|
3823
|
+
return () => {
|
|
3824
|
+
};
|
|
3825
|
+
}
|
|
3826
|
+
const vv = window.visualViewport;
|
|
3827
|
+
let rafId = null;
|
|
3828
|
+
const onResize = () => {
|
|
3829
|
+
if (rafId !== null) return;
|
|
3830
|
+
rafId = requestAnimationFrame(() => {
|
|
3831
|
+
rafId = null;
|
|
3832
|
+
if (deps.isDestroyed()) return;
|
|
3833
|
+
deps.recomputeSnaps();
|
|
3834
|
+
const isVertical = deps.isVerticalAxis();
|
|
3835
|
+
const visible = isVertical ? vv.height : vv.width;
|
|
3836
|
+
const windowSize = isVertical ? window.innerHeight : window.innerWidth;
|
|
3837
|
+
const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
|
|
3838
|
+
if (clamp < deps.getMaxAxisSize()) {
|
|
3839
|
+
deps.setMaxAxisSize(clamp);
|
|
3840
|
+
}
|
|
3841
|
+
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
3842
|
+
deps.cancelInFlight();
|
|
3843
|
+
deps.newCycle();
|
|
3844
|
+
const max = deps.getMaxAxisSize();
|
|
3845
|
+
deps.setSize(Math.min(deps.getSize(), max));
|
|
3846
|
+
const current = deps.resolveActiveSnap();
|
|
3847
|
+
if (current && !deps.isDragging()) {
|
|
3848
|
+
deps.applySize(Math.min(current.size, max));
|
|
3849
|
+
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
3850
|
+
} else {
|
|
3851
|
+
deps.applySize(deps.getSize());
|
|
3852
|
+
}
|
|
3853
|
+
});
|
|
3854
|
+
};
|
|
3855
|
+
vv.addEventListener("resize", onResize);
|
|
3856
|
+
return () => {
|
|
3857
|
+
vv.removeEventListener("resize", onResize);
|
|
3858
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
3859
|
+
};
|
|
3860
|
+
}
|
|
3861
|
+
|
|
3862
|
+
// src/core/features/engine-features.ts
|
|
3863
|
+
function routeFeature() {
|
|
3864
|
+
return {
|
|
3865
|
+
name: "route",
|
|
3866
|
+
install: (ctx) => {
|
|
3867
|
+
const teardowns = new TeardownStack();
|
|
3868
|
+
if (ctx.options.closeOnRouteChange) {
|
|
3869
|
+
teardowns.add(
|
|
3870
|
+
installRouteChange({
|
|
3871
|
+
isDestroyed: ctx.isDestroyed,
|
|
3872
|
+
getSize: ctx.getSize,
|
|
3873
|
+
close: () => ctx.close()
|
|
3874
|
+
})
|
|
3875
|
+
);
|
|
3876
|
+
}
|
|
3877
|
+
teardowns.add(
|
|
3878
|
+
installRoute({
|
|
3879
|
+
routedTo: ctx.options.routedTo,
|
|
3880
|
+
closeOnBack: ctx.options.closeOnBack,
|
|
3881
|
+
isTopSheet: ctx.isTopSheet,
|
|
3882
|
+
getSize: ctx.getSize,
|
|
3883
|
+
isDestroyed: ctx.isDestroyed,
|
|
3884
|
+
close: () => ctx.close("back"),
|
|
3885
|
+
on: ctx.on,
|
|
3886
|
+
sheetId: ctx.sheetId
|
|
3887
|
+
})
|
|
3888
|
+
);
|
|
3889
|
+
return () => teardowns.drain();
|
|
3890
|
+
}
|
|
3891
|
+
};
|
|
3892
|
+
}
|
|
3893
|
+
function persistFeature() {
|
|
3894
|
+
return {
|
|
3895
|
+
name: "persist",
|
|
3896
|
+
install: (ctx) => {
|
|
3897
|
+
const key = ctx.options.persistKey;
|
|
3898
|
+
if (!key) return;
|
|
3899
|
+
return installPersist({ on: ctx.on }, key);
|
|
3900
|
+
}
|
|
3901
|
+
};
|
|
3902
|
+
}
|
|
3903
|
+
function autoCollapseFeature() {
|
|
3904
|
+
return {
|
|
3905
|
+
name: "auto-collapse",
|
|
3906
|
+
install: (ctx) => installAutoCollapse({
|
|
3907
|
+
ms: ctx.options.autoCollapseAfter,
|
|
3908
|
+
isDestroyed: ctx.isDestroyed,
|
|
3909
|
+
isDragging: ctx.isDragging,
|
|
3910
|
+
getAllowedIds: ctx.getAllowedIds,
|
|
3911
|
+
getActiveId: ctx.getActiveId,
|
|
3912
|
+
resolveSnap: ctx.resolveSnap,
|
|
3913
|
+
snapTo: ctx.snapTo,
|
|
3914
|
+
on: ctx.on
|
|
3915
|
+
})
|
|
3916
|
+
};
|
|
3917
|
+
}
|
|
3918
|
+
function contentSwipeFeature() {
|
|
3919
|
+
return {
|
|
3920
|
+
name: "content-swipe",
|
|
3921
|
+
stage: "attach",
|
|
3922
|
+
install: (ctx) => {
|
|
3923
|
+
if (!ctx.scrollContainer) return;
|
|
3924
|
+
return installContentSwipe({
|
|
3925
|
+
container: ctx.scrollContainer,
|
|
3926
|
+
isDragging: ctx.isDragging,
|
|
3927
|
+
isAnimating: ctx.isAnimating,
|
|
3928
|
+
getAllowedIds: ctx.allowedIdsBySize,
|
|
3929
|
+
getActiveId: ctx.getActiveId,
|
|
3930
|
+
snapTo: ctx.snapTo
|
|
3931
|
+
});
|
|
3932
|
+
}
|
|
3933
|
+
};
|
|
3934
|
+
}
|
|
3935
|
+
function visualViewportFeature() {
|
|
3936
|
+
return {
|
|
3937
|
+
name: "visual-viewport",
|
|
3938
|
+
install: (ctx) => {
|
|
3939
|
+
if (typeof window === "undefined") return;
|
|
3940
|
+
return installVisualViewport({
|
|
3941
|
+
element: ctx.element,
|
|
3942
|
+
isVerticalAxis: ctx.isVerticalAxis,
|
|
3943
|
+
isDestroyed: ctx.isDestroyed,
|
|
3944
|
+
isDragging: ctx.isDragging,
|
|
3945
|
+
recomputeSnaps: ctx.recomputeSnaps,
|
|
3946
|
+
resolveActiveSnap: ctx.resolveActiveSnap,
|
|
3947
|
+
getMaxAxisSize: ctx.getMaxAxisSize,
|
|
3948
|
+
getSize: ctx.getSize,
|
|
3949
|
+
setMaxAxisSize: ctx.setMaxAxisSize,
|
|
3950
|
+
setSize: ctx.setSize,
|
|
3951
|
+
applySize: ctx.applySize,
|
|
3952
|
+
cancelInFlight: ctx.cancelInFlight,
|
|
3953
|
+
newCycle: ctx.newCycle,
|
|
3954
|
+
isAnimating: ctx.isAnimating,
|
|
3955
|
+
resyncAfterCancel: ctx.resyncAfterResize
|
|
3956
|
+
});
|
|
3957
|
+
}
|
|
3958
|
+
};
|
|
3959
|
+
}
|
|
3960
|
+
|
|
3961
|
+
// src/core/default-features.ts
|
|
3962
|
+
function defaultEngineFeatures() {
|
|
3963
|
+
return [
|
|
3964
|
+
contentSwipeFeature(),
|
|
3965
|
+
visualViewportFeature(),
|
|
3966
|
+
persistFeature(),
|
|
3967
|
+
autoCollapseFeature(),
|
|
3968
|
+
routeFeature()
|
|
3969
|
+
];
|
|
3970
|
+
}
|
|
3971
|
+
|
|
3972
|
+
// src/core/BottomSheetEngine.ts
|
|
3973
|
+
var BottomSheetEngine = class extends BottomSheetCore {
|
|
3974
|
+
constructor(opts) {
|
|
3975
|
+
super({
|
|
3976
|
+
...opts,
|
|
3977
|
+
features: [...defaultEngineFeatures(), ...opts.features ?? []]
|
|
3978
|
+
});
|
|
3979
|
+
}
|
|
3980
|
+
};
|
|
3981
|
+
|
|
3708
3982
|
// src/core/features/teleport.ts
|
|
3709
3983
|
var resolveTeleportTarget = (target) => {
|
|
3710
3984
|
if (!target) return null;
|