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