@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/react.js
CHANGED
|
@@ -356,74 +356,6 @@ var SnapResolver = class {
|
|
|
356
356
|
}
|
|
357
357
|
};
|
|
358
358
|
|
|
359
|
-
// src/core/features/persist.ts
|
|
360
|
-
function readPersistedId(key) {
|
|
361
|
-
if (!key) return null;
|
|
362
|
-
if (typeof window === "undefined") return null;
|
|
363
|
-
if (typeof localStorage === "undefined") return null;
|
|
364
|
-
try {
|
|
365
|
-
return localStorage.getItem(key);
|
|
366
|
-
} catch {
|
|
367
|
-
return null;
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
function installPersist(engine, key) {
|
|
371
|
-
const unsubscribe = engine.on("snap", ({ id }) => {
|
|
372
|
-
if (typeof window === "undefined") return;
|
|
373
|
-
if (typeof localStorage === "undefined") return;
|
|
374
|
-
try {
|
|
375
|
-
localStorage.setItem(key, id);
|
|
376
|
-
} catch {
|
|
377
|
-
}
|
|
378
|
-
});
|
|
379
|
-
return unsubscribe;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
// src/core/features/auto-collapse.ts
|
|
383
|
-
function installAutoCollapse(deps) {
|
|
384
|
-
const { ms } = deps;
|
|
385
|
-
if (ms === void 0 || ms <= 0) {
|
|
386
|
-
return () => {
|
|
387
|
-
};
|
|
388
|
-
}
|
|
389
|
-
let timer = null;
|
|
390
|
-
const clearTimer = () => {
|
|
391
|
-
if (timer !== null) {
|
|
392
|
-
clearTimeout(timer);
|
|
393
|
-
timer = null;
|
|
394
|
-
}
|
|
395
|
-
};
|
|
396
|
-
const fire = () => {
|
|
397
|
-
if (deps.isDestroyed()) return;
|
|
398
|
-
if (deps.isDragging()) return;
|
|
399
|
-
const active = deps.resolveSnap(deps.getActiveId());
|
|
400
|
-
if (!active || active.size === 0) return;
|
|
401
|
-
let target = null;
|
|
402
|
-
for (const id of deps.getAllowedIds()) {
|
|
403
|
-
const snap = deps.resolveSnap(id);
|
|
404
|
-
if (!snap || snap.size <= 0) continue;
|
|
405
|
-
if (!target || snap.size < target.size) target = snap;
|
|
406
|
-
}
|
|
407
|
-
if (!target) return;
|
|
408
|
-
if (target.id === active.id || target.size >= active.size) return;
|
|
409
|
-
deps.snapTo(target.id);
|
|
410
|
-
};
|
|
411
|
-
const reset = () => {
|
|
412
|
-
clearTimer();
|
|
413
|
-
if (deps.isDestroyed()) return;
|
|
414
|
-
timer = setTimeout(() => {
|
|
415
|
-
timer = null;
|
|
416
|
-
fire();
|
|
417
|
-
}, ms);
|
|
418
|
-
};
|
|
419
|
-
const unsubscribe = deps.on("snap", () => reset());
|
|
420
|
-
if ((deps.resolveSnap(deps.getActiveId())?.size ?? 0) > 0) reset();
|
|
421
|
-
return () => {
|
|
422
|
-
clearTimer();
|
|
423
|
-
unsubscribe();
|
|
424
|
-
};
|
|
425
|
-
}
|
|
426
|
-
|
|
427
359
|
// src/core/features/linked-sheets.ts
|
|
428
360
|
function notifyLinkedSheets(sheets, self) {
|
|
429
361
|
if (sheets.length === 0) return;
|
|
@@ -446,390 +378,65 @@ function notifyLinkedSheets(sheets, self) {
|
|
|
446
378
|
}
|
|
447
379
|
}
|
|
448
380
|
|
|
449
|
-
// src/core/features/
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
var pendingRebrand = null;
|
|
455
|
-
var listenerInstalled = false;
|
|
456
|
-
var patchInstalled = false;
|
|
457
|
-
var origPushState = null;
|
|
458
|
-
var origReplaceState = null;
|
|
459
|
-
var patchedPushState = null;
|
|
460
|
-
var patchedReplaceState = null;
|
|
461
|
-
var hasWindow = () => typeof window !== "undefined";
|
|
462
|
-
var hasHistory = () => typeof history !== "undefined";
|
|
463
|
-
var runInternal = (fn) => {
|
|
464
|
-
internalDepth += 1;
|
|
465
|
-
try {
|
|
466
|
-
fn();
|
|
467
|
-
} finally {
|
|
468
|
-
internalDepth -= 1;
|
|
469
|
-
}
|
|
470
|
-
};
|
|
471
|
-
var notifyRouteChange = () => {
|
|
472
|
-
const snapshot = Array.from(subscribers);
|
|
473
|
-
for (const fn of snapshot) fn();
|
|
474
|
-
};
|
|
475
|
-
var ensureListener = () => {
|
|
476
|
-
if (listenerInstalled || !hasWindow()) return;
|
|
477
|
-
window.addEventListener("popstate", onPopState);
|
|
478
|
-
listenerInstalled = true;
|
|
479
|
-
};
|
|
480
|
-
var maybeTeardownListener = () => {
|
|
481
|
-
if (!listenerInstalled) return;
|
|
482
|
-
if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
|
|
483
|
-
if (hasWindow()) window.removeEventListener("popstate", onPopState);
|
|
484
|
-
listenerInstalled = false;
|
|
485
|
-
};
|
|
486
|
-
var installPatch = () => {
|
|
487
|
-
if (patchInstalled || !hasHistory()) return;
|
|
488
|
-
origPushState = history.pushState;
|
|
489
|
-
origReplaceState = history.replaceState;
|
|
490
|
-
patchedPushState = function(...args) {
|
|
491
|
-
origPushState.apply(this, args);
|
|
492
|
-
if (internalDepth === 0) notifyRouteChange();
|
|
493
|
-
};
|
|
494
|
-
patchedReplaceState = function(...args) {
|
|
495
|
-
origReplaceState.apply(this, args);
|
|
496
|
-
if (internalDepth === 0) notifyRouteChange();
|
|
497
|
-
};
|
|
498
|
-
history.pushState = patchedPushState;
|
|
499
|
-
history.replaceState = patchedReplaceState;
|
|
500
|
-
patchInstalled = true;
|
|
501
|
-
};
|
|
502
|
-
var removePatch = () => {
|
|
503
|
-
if (!patchInstalled) return;
|
|
504
|
-
if (history.pushState === patchedPushState && origPushState) {
|
|
505
|
-
history.pushState = origPushState;
|
|
506
|
-
}
|
|
507
|
-
if (history.replaceState === patchedReplaceState && origReplaceState) {
|
|
508
|
-
history.replaceState = origReplaceState;
|
|
509
|
-
}
|
|
510
|
-
origPushState = null;
|
|
511
|
-
origReplaceState = null;
|
|
512
|
-
patchedPushState = null;
|
|
513
|
-
patchedReplaceState = null;
|
|
514
|
-
patchInstalled = false;
|
|
515
|
-
};
|
|
516
|
-
function onPopState() {
|
|
517
|
-
if (suppress > 0) {
|
|
518
|
-
suppress -= 1;
|
|
519
|
-
const rebrand = pendingRebrand;
|
|
520
|
-
pendingRebrand = null;
|
|
521
|
-
if (rebrand) rebrand();
|
|
522
|
-
maybeTeardownListener();
|
|
523
|
-
return;
|
|
524
|
-
}
|
|
525
|
-
if (entries.length === 0) {
|
|
526
|
-
notifyRouteChange();
|
|
527
|
-
maybeTeardownListener();
|
|
528
|
-
return;
|
|
381
|
+
// src/core/features/resize-observer.ts
|
|
382
|
+
function installResizeObserver(deps) {
|
|
383
|
+
if (typeof window === "undefined") {
|
|
384
|
+
return () => {
|
|
385
|
+
};
|
|
529
386
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
const
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
if (entry.surface.isTop()) {
|
|
540
|
-
target = entry;
|
|
541
|
-
targetIdx = i;
|
|
542
|
-
break;
|
|
387
|
+
const onResize = () => {
|
|
388
|
+
if (deps.isDestroyed()) return;
|
|
389
|
+
deps.recomputeSnaps();
|
|
390
|
+
const mode = deps.getMode();
|
|
391
|
+
const isVerticalAxis = mode === "bottom" || mode === "top";
|
|
392
|
+
const viewportSize2 = isVerticalAxis ? window.innerHeight : window.innerWidth;
|
|
393
|
+
const max = deps.getMaxAxisSize();
|
|
394
|
+
if (viewportSize2 > 0 && viewportSize2 < max) {
|
|
395
|
+
deps.setMaxAxisSize(viewportSize2);
|
|
543
396
|
}
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
void Promise.resolve(settled.surface.close()).then(() => {
|
|
555
|
-
if (settled.surface.isOpen()) restore(settled);
|
|
556
|
-
});
|
|
557
|
-
maybeTeardownListener();
|
|
558
|
-
}
|
|
559
|
-
function restore(entry) {
|
|
560
|
-
if (!hasWindow() || !hasHistory()) return;
|
|
561
|
-
entry.live = true;
|
|
562
|
-
runInternal(() => {
|
|
563
|
-
try {
|
|
564
|
-
history.pushState(entry.surface.markerState(), "", entry.surface.url);
|
|
565
|
-
} catch {
|
|
566
|
-
entry.live = false;
|
|
397
|
+
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
398
|
+
deps.cancelInFlight();
|
|
399
|
+
deps.newCycle();
|
|
400
|
+
const current = deps.resolveActiveSnap();
|
|
401
|
+
const newMax = deps.getMaxAxisSize();
|
|
402
|
+
const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
|
|
403
|
+
deps.setSize(targetSize);
|
|
404
|
+
if (current && !deps.isDragging()) {
|
|
405
|
+
deps.applySize(targetSize);
|
|
406
|
+
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
567
407
|
}
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
408
|
+
};
|
|
409
|
+
let resizeObserver = null;
|
|
410
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
411
|
+
resizeObserver = new ResizeObserver(onResize);
|
|
412
|
+
resizeObserver.observe(document.documentElement);
|
|
413
|
+
} else {
|
|
414
|
+
window.addEventListener("resize", onResize);
|
|
572
415
|
}
|
|
416
|
+
window.addEventListener("orientationchange", onResize);
|
|
417
|
+
const onVisibility = () => {
|
|
418
|
+
if (deps.isDestroyed()) return;
|
|
419
|
+
if (document.hidden) deps.cancelInFlight();
|
|
420
|
+
};
|
|
421
|
+
document.addEventListener("visibilitychange", onVisibility);
|
|
422
|
+
return () => {
|
|
423
|
+
resizeObserver?.disconnect();
|
|
424
|
+
window.removeEventListener("resize", onResize);
|
|
425
|
+
window.removeEventListener("orientationchange", onResize);
|
|
426
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
427
|
+
};
|
|
573
428
|
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
entry.live = false;
|
|
586
|
-
}
|
|
587
|
-
});
|
|
588
|
-
if (entry.live) {
|
|
589
|
-
entries.push(entry);
|
|
590
|
-
ensureListener();
|
|
591
|
-
}
|
|
592
|
-
return entry;
|
|
593
|
-
}
|
|
594
|
-
function popBackMarker(handle) {
|
|
595
|
-
if (!hasWindow() || !hasHistory()) return;
|
|
596
|
-
const entry = handle;
|
|
597
|
-
const idx = entries.indexOf(entry);
|
|
598
|
-
if (idx === -1 || !entry.live) return;
|
|
599
|
-
const last = entries.length - 1;
|
|
600
|
-
entry.live = false;
|
|
601
|
-
entries.splice(idx, 1);
|
|
602
|
-
if (idx !== last) {
|
|
603
|
-
const rebrandSurface = entries[entries.length - 1].surface;
|
|
604
|
-
const rebrandUrl = entry.priorUrl;
|
|
605
|
-
pendingRebrand = () => {
|
|
606
|
-
runInternal(() => {
|
|
607
|
-
history.replaceState(
|
|
608
|
-
rebrandSurface.markerState(),
|
|
609
|
-
"",
|
|
610
|
-
rebrandUrl !== void 0 ? rebrandUrl : location.href
|
|
611
|
-
);
|
|
612
|
-
});
|
|
613
|
-
};
|
|
614
|
-
}
|
|
615
|
-
suppress += 1;
|
|
616
|
-
runInternal(() => {
|
|
617
|
-
try {
|
|
618
|
-
history.back();
|
|
619
|
-
} catch {
|
|
620
|
-
suppress = Math.max(0, suppress - 1);
|
|
621
|
-
pendingRebrand = null;
|
|
622
|
-
}
|
|
623
|
-
});
|
|
624
|
-
maybeTeardownListener();
|
|
625
|
-
}
|
|
626
|
-
function subscribeRouteChange(fn) {
|
|
627
|
-
if (!hasWindow() || !hasHistory()) return () => {
|
|
628
|
-
};
|
|
629
|
-
subscribers.add(fn);
|
|
630
|
-
if (subscribers.size === 1) installPatch();
|
|
631
|
-
ensureListener();
|
|
632
|
-
return () => {
|
|
633
|
-
if (!subscribers.has(fn)) return;
|
|
634
|
-
subscribers.delete(fn);
|
|
635
|
-
if (subscribers.size === 0) removePatch();
|
|
636
|
-
maybeTeardownListener();
|
|
637
|
-
};
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
// src/core/features/route.ts
|
|
641
|
-
function installRoute(deps) {
|
|
642
|
-
if (typeof window === "undefined") {
|
|
643
|
-
return () => {
|
|
644
|
-
};
|
|
645
|
-
}
|
|
646
|
-
if (!deps.routedTo && !deps.closeOnBack) {
|
|
647
|
-
return () => {
|
|
648
|
-
};
|
|
649
|
-
}
|
|
650
|
-
let handle = null;
|
|
651
|
-
const onOpen = () => {
|
|
652
|
-
if (handle) return;
|
|
653
|
-
handle = pushBackMarker({
|
|
654
|
-
isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
|
|
655
|
-
isTop: deps.isTopSheet,
|
|
656
|
-
close: deps.close,
|
|
657
|
-
markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
|
|
658
|
-
url: deps.routedTo
|
|
659
|
-
});
|
|
660
|
-
};
|
|
661
|
-
const onClose = () => {
|
|
662
|
-
if (!handle) return;
|
|
663
|
-
popBackMarker(handle);
|
|
664
|
-
handle = null;
|
|
665
|
-
};
|
|
666
|
-
const unsubscribeOpen = deps.on("open", onOpen);
|
|
667
|
-
const unsubscribeClose = deps.on("close", onClose);
|
|
668
|
-
if (deps.getSize() > 0) onOpen();
|
|
669
|
-
return () => {
|
|
670
|
-
unsubscribeOpen();
|
|
671
|
-
unsubscribeClose();
|
|
672
|
-
if (handle) {
|
|
673
|
-
popBackMarker(handle);
|
|
674
|
-
handle = null;
|
|
675
|
-
}
|
|
676
|
-
};
|
|
677
|
-
}
|
|
678
|
-
function installRouteChange(deps) {
|
|
679
|
-
return subscribeRouteChange(() => {
|
|
680
|
-
if (deps.isDestroyed() || deps.getSize() <= 0) return;
|
|
681
|
-
void deps.close();
|
|
682
|
-
});
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
// src/core/features/content-swipe.ts
|
|
686
|
-
var CONTENT_PULL_THRESHOLD = 60;
|
|
687
|
-
function installContentSwipe(deps) {
|
|
688
|
-
const { container } = deps;
|
|
689
|
-
let startY = 0;
|
|
690
|
-
let startScrollTop = 0;
|
|
691
|
-
let moved = false;
|
|
692
|
-
const onTouchStart = (e) => {
|
|
693
|
-
const t = e.touches[0];
|
|
694
|
-
if (!t) return;
|
|
695
|
-
startY = t.clientY;
|
|
696
|
-
startScrollTop = container.scrollTop;
|
|
697
|
-
moved = false;
|
|
698
|
-
};
|
|
699
|
-
const onTouchMove = (e) => {
|
|
700
|
-
const t = e.touches[0];
|
|
701
|
-
if (!t) return;
|
|
702
|
-
if (Math.abs(t.clientY - startY) > CONTENT_PULL_THRESHOLD) moved = true;
|
|
703
|
-
};
|
|
704
|
-
const onTouchEnd = (e) => {
|
|
705
|
-
if (!moved) return;
|
|
706
|
-
if (deps.isDragging() || deps.isAnimating()) return;
|
|
707
|
-
if (container.scrollTop !== startScrollTop) return;
|
|
708
|
-
const t = e.changedTouches[0];
|
|
709
|
-
if (!t) return;
|
|
710
|
-
const deltaY = t.clientY - startY;
|
|
711
|
-
const atTop = container.scrollTop <= 0;
|
|
712
|
-
const allowed = deps.getAllowedIds();
|
|
713
|
-
const idx = allowed.indexOf(deps.getActiveId());
|
|
714
|
-
if (idx === -1) return;
|
|
715
|
-
if (atTop && deltaY > CONTENT_PULL_THRESHOLD && idx > 0) {
|
|
716
|
-
deps.snapTo(allowed[idx - 1]);
|
|
717
|
-
} else if (deltaY < -CONTENT_PULL_THRESHOLD && idx < allowed.length - 1) {
|
|
718
|
-
deps.snapTo(allowed[idx + 1]);
|
|
719
|
-
}
|
|
720
|
-
};
|
|
721
|
-
container.addEventListener("touchstart", onTouchStart, { passive: true });
|
|
722
|
-
container.addEventListener("touchmove", onTouchMove, { passive: true });
|
|
723
|
-
container.addEventListener("touchend", onTouchEnd, { passive: true });
|
|
724
|
-
return () => {
|
|
725
|
-
container.removeEventListener("touchstart", onTouchStart);
|
|
726
|
-
container.removeEventListener("touchmove", onTouchMove);
|
|
727
|
-
container.removeEventListener("touchend", onTouchEnd);
|
|
728
|
-
};
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
// src/core/features/visual-viewport.ts
|
|
732
|
-
var SAFETY_PAD = 8;
|
|
733
|
-
function installVisualViewport(deps) {
|
|
734
|
-
if (typeof window === "undefined" || !window.visualViewport) {
|
|
735
|
-
return () => {
|
|
736
|
-
};
|
|
737
|
-
}
|
|
738
|
-
const vv = window.visualViewport;
|
|
739
|
-
let rafId = null;
|
|
740
|
-
const onResize = () => {
|
|
741
|
-
if (rafId !== null) return;
|
|
742
|
-
rafId = requestAnimationFrame(() => {
|
|
743
|
-
rafId = null;
|
|
744
|
-
if (deps.isDestroyed()) return;
|
|
745
|
-
deps.recomputeSnaps();
|
|
746
|
-
const isVertical = deps.isVerticalAxis();
|
|
747
|
-
const visible = isVertical ? vv.height : vv.width;
|
|
748
|
-
const windowSize = isVertical ? window.innerHeight : window.innerWidth;
|
|
749
|
-
const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
|
|
750
|
-
if (clamp < deps.getMaxAxisSize()) {
|
|
751
|
-
deps.setMaxAxisSize(clamp);
|
|
752
|
-
}
|
|
753
|
-
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
754
|
-
deps.cancelInFlight();
|
|
755
|
-
deps.newCycle();
|
|
756
|
-
const max = deps.getMaxAxisSize();
|
|
757
|
-
deps.setSize(Math.min(deps.getSize(), max));
|
|
758
|
-
const current = deps.resolveActiveSnap();
|
|
759
|
-
if (current && !deps.isDragging()) {
|
|
760
|
-
deps.applySize(Math.min(current.size, max));
|
|
761
|
-
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
762
|
-
} else {
|
|
763
|
-
deps.applySize(deps.getSize());
|
|
764
|
-
}
|
|
765
|
-
});
|
|
766
|
-
};
|
|
767
|
-
vv.addEventListener("resize", onResize);
|
|
768
|
-
return () => {
|
|
769
|
-
vv.removeEventListener("resize", onResize);
|
|
770
|
-
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
771
|
-
};
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
// src/core/features/resize-observer.ts
|
|
775
|
-
function installResizeObserver(deps) {
|
|
776
|
-
if (typeof window === "undefined") {
|
|
777
|
-
return () => {
|
|
778
|
-
};
|
|
779
|
-
}
|
|
780
|
-
const onResize = () => {
|
|
781
|
-
if (deps.isDestroyed()) return;
|
|
782
|
-
deps.recomputeSnaps();
|
|
783
|
-
const mode = deps.getMode();
|
|
784
|
-
const isVerticalAxis = mode === "bottom" || mode === "top";
|
|
785
|
-
const viewportSize2 = isVerticalAxis ? window.innerHeight : window.innerWidth;
|
|
786
|
-
const max = deps.getMaxAxisSize();
|
|
787
|
-
if (viewportSize2 > 0 && viewportSize2 < max) {
|
|
788
|
-
deps.setMaxAxisSize(viewportSize2);
|
|
789
|
-
}
|
|
790
|
-
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
791
|
-
deps.cancelInFlight();
|
|
792
|
-
deps.newCycle();
|
|
793
|
-
const current = deps.resolveActiveSnap();
|
|
794
|
-
const newMax = deps.getMaxAxisSize();
|
|
795
|
-
const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
|
|
796
|
-
deps.setSize(targetSize);
|
|
797
|
-
if (current && !deps.isDragging()) {
|
|
798
|
-
deps.applySize(targetSize);
|
|
799
|
-
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
800
|
-
}
|
|
801
|
-
};
|
|
802
|
-
let resizeObserver = null;
|
|
803
|
-
if (typeof ResizeObserver !== "undefined") {
|
|
804
|
-
resizeObserver = new ResizeObserver(onResize);
|
|
805
|
-
resizeObserver.observe(document.documentElement);
|
|
806
|
-
} else {
|
|
807
|
-
window.addEventListener("resize", onResize);
|
|
808
|
-
}
|
|
809
|
-
window.addEventListener("orientationchange", onResize);
|
|
810
|
-
const onVisibility = () => {
|
|
811
|
-
if (deps.isDestroyed()) return;
|
|
812
|
-
if (document.hidden) deps.cancelInFlight();
|
|
813
|
-
};
|
|
814
|
-
document.addEventListener("visibilitychange", onVisibility);
|
|
815
|
-
return () => {
|
|
816
|
-
resizeObserver?.disconnect();
|
|
817
|
-
window.removeEventListener("resize", onResize);
|
|
818
|
-
window.removeEventListener("orientationchange", onResize);
|
|
819
|
-
document.removeEventListener("visibilitychange", onVisibility);
|
|
820
|
-
};
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
// src/core/features/fit-observer.ts
|
|
824
|
-
var contentTargets = (scroller) => {
|
|
825
|
-
if (!scroller) return [];
|
|
826
|
-
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
827
|
-
const out = [];
|
|
828
|
-
for (const child of Array.from(scroller.children)) {
|
|
829
|
-
if (hasSlot && child instanceof HTMLSlotElement) {
|
|
830
|
-
for (const el of child.assignedElements()) out.push(el);
|
|
831
|
-
} else {
|
|
832
|
-
out.push(child);
|
|
429
|
+
|
|
430
|
+
// src/core/features/fit-observer.ts
|
|
431
|
+
var contentTargets = (scroller) => {
|
|
432
|
+
if (!scroller) return [];
|
|
433
|
+
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
434
|
+
const out = [];
|
|
435
|
+
for (const child of Array.from(scroller.children)) {
|
|
436
|
+
if (hasSlot && child instanceof HTMLSlotElement) {
|
|
437
|
+
for (const el of child.assignedElements()) out.push(el);
|
|
438
|
+
} else {
|
|
439
|
+
out.push(child);
|
|
833
440
|
}
|
|
834
441
|
}
|
|
835
442
|
return out;
|
|
@@ -949,11 +556,15 @@ function createMaxHeightController(deps) {
|
|
|
949
556
|
|
|
950
557
|
// src/core/features/fit-measurement.ts
|
|
951
558
|
var measureSheetNatural = (element, content, vertical) => {
|
|
952
|
-
if (!content) {
|
|
953
|
-
return vertical ? element.offsetHeight : element.offsetWidth;
|
|
954
|
-
}
|
|
955
559
|
const axis = vertical ? "height" : "width";
|
|
956
560
|
const sheetStyle = element.style;
|
|
561
|
+
if (!content) {
|
|
562
|
+
const prev = sheetStyle[axis];
|
|
563
|
+
sheetStyle[axis] = "auto";
|
|
564
|
+
const poked2 = vertical ? element.offsetHeight : element.offsetWidth;
|
|
565
|
+
sheetStyle[axis] = prev;
|
|
566
|
+
return poked2;
|
|
567
|
+
}
|
|
957
568
|
const cs = content.style;
|
|
958
569
|
const prevSheet = sheetStyle[axis];
|
|
959
570
|
const prevFlex = cs.flex;
|
|
@@ -1667,6 +1278,52 @@ function resolveAnimationPreset(animation) {
|
|
|
1667
1278
|
}
|
|
1668
1279
|
}
|
|
1669
1280
|
|
|
1281
|
+
// src/core/animation/waapi-settle.ts
|
|
1282
|
+
var SIM_HZ = 240;
|
|
1283
|
+
var SAMPLE_STRIDE = 4;
|
|
1284
|
+
var MAX_SIM_MS = 3e3;
|
|
1285
|
+
function sampleSpringSettle(from, to, velocityPxPerS, config) {
|
|
1286
|
+
const cfg = { ...DEFAULT_SPRING, ...config };
|
|
1287
|
+
const subDt = 1 / SIM_HZ;
|
|
1288
|
+
const stepMs = SAMPLE_STRIDE / SIM_HZ * 1e3;
|
|
1289
|
+
const maxSteps = Math.ceil(MAX_SIM_MS / 1e3 * SIM_HZ);
|
|
1290
|
+
const values = [from];
|
|
1291
|
+
let x = from;
|
|
1292
|
+
let v = velocityPxPerS;
|
|
1293
|
+
for (let i = 1; i <= maxSteps; i += 1) {
|
|
1294
|
+
const force = -cfg.stiffness * (x - to) - cfg.damping * v;
|
|
1295
|
+
v += force / cfg.mass * subDt;
|
|
1296
|
+
x += v * subDt;
|
|
1297
|
+
if (!Number.isFinite(x) || !Number.isFinite(v)) {
|
|
1298
|
+
values.push(to);
|
|
1299
|
+
break;
|
|
1300
|
+
}
|
|
1301
|
+
if (i % SAMPLE_STRIDE === 0) values.push(x);
|
|
1302
|
+
const atRest = Math.abs(to - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
|
|
1303
|
+
if (atRest) break;
|
|
1304
|
+
}
|
|
1305
|
+
if (values[values.length - 1] !== to) values.push(to);
|
|
1306
|
+
return {
|
|
1307
|
+
values,
|
|
1308
|
+
stepMs,
|
|
1309
|
+
durationMs: (values.length - 1) * stepMs
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
function sampleTweenSettle(from, to, durationMs, easing) {
|
|
1313
|
+
const count = Math.max(2, Math.min(60, Math.round(durationMs / 16)));
|
|
1314
|
+
const values = [];
|
|
1315
|
+
for (let i = 0; i <= count; i += 1) {
|
|
1316
|
+
const t = i / count;
|
|
1317
|
+
values.push(from + (to - from) * easing(t));
|
|
1318
|
+
}
|
|
1319
|
+
values[values.length - 1] = to;
|
|
1320
|
+
return {
|
|
1321
|
+
values,
|
|
1322
|
+
stepMs: durationMs / count,
|
|
1323
|
+
durationMs
|
|
1324
|
+
};
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1670
1327
|
// src/core/controllers/animation-runner.ts
|
|
1671
1328
|
var DEFAULT_DURATION2 = 220;
|
|
1672
1329
|
var VELOCITY_PX_PER_S = 1e3;
|
|
@@ -1677,6 +1334,10 @@ var AnimationRunner = class {
|
|
|
1677
1334
|
__publicField(this, "applySizeFn");
|
|
1678
1335
|
__publicField(this, "getSize");
|
|
1679
1336
|
__publicField(this, "isDragging");
|
|
1337
|
+
__publicField(this, "applyAux");
|
|
1338
|
+
__publicField(this, "getTransformFor");
|
|
1339
|
+
__publicField(this, "settleWaapi");
|
|
1340
|
+
__publicField(this, "currentWaapi", null);
|
|
1680
1341
|
__publicField(this, "animationKind");
|
|
1681
1342
|
__publicField(this, "springConfig");
|
|
1682
1343
|
__publicField(this, "duration");
|
|
@@ -1692,6 +1353,9 @@ var AnimationRunner = class {
|
|
|
1692
1353
|
this.applySizeFn = deps.applySize;
|
|
1693
1354
|
this.getSize = deps.getSize;
|
|
1694
1355
|
this.isDragging = deps.isDragging;
|
|
1356
|
+
this.applyAux = deps.applyAux;
|
|
1357
|
+
this.getTransformFor = deps.getTransformFor;
|
|
1358
|
+
this.settleWaapi = opts.settleAnimation === "waapi";
|
|
1695
1359
|
const preset = resolveAnimationPreset(opts.animation);
|
|
1696
1360
|
this.animationKind = preset.kind;
|
|
1697
1361
|
this.duration = opts.duration ?? preset.duration ?? DEFAULT_DURATION2;
|
|
@@ -1716,11 +1380,20 @@ var AnimationRunner = class {
|
|
|
1716
1380
|
}
|
|
1717
1381
|
}
|
|
1718
1382
|
get isAnimating() {
|
|
1719
|
-
return this.currentTween !== null || this.currentSpring !== null;
|
|
1383
|
+
return this.currentTween !== null || this.currentSpring !== null || this.currentWaapi !== null;
|
|
1720
1384
|
}
|
|
1721
1385
|
cancel() {
|
|
1722
1386
|
this.currentTween?.cancel();
|
|
1723
1387
|
this.currentSpring?.cancel();
|
|
1388
|
+
if (this.currentWaapi) {
|
|
1389
|
+
const entry = this.currentWaapi;
|
|
1390
|
+
this.currentWaapi = null;
|
|
1391
|
+
entry.stop();
|
|
1392
|
+
try {
|
|
1393
|
+
entry.anim.cancel();
|
|
1394
|
+
} catch {
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1724
1397
|
}
|
|
1725
1398
|
async animateTo(target, velocityPxPerMs) {
|
|
1726
1399
|
if (target === this.getSize()) {
|
|
@@ -1739,7 +1412,28 @@ var AnimationRunner = class {
|
|
|
1739
1412
|
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1740
1413
|
return;
|
|
1741
1414
|
}
|
|
1742
|
-
if (this.
|
|
1415
|
+
if (this.settleWaapi && this.applyAux && this.getTransformFor && typeof this.element.animate === "function") {
|
|
1416
|
+
const samples = this.animationKind === "spring" ? sampleSpringSettle(
|
|
1417
|
+
this.getSize(),
|
|
1418
|
+
target,
|
|
1419
|
+
velocityPxPerMs * VELOCITY_PX_PER_S,
|
|
1420
|
+
this.springConfig
|
|
1421
|
+
) : sampleTweenSettle(
|
|
1422
|
+
this.getSize(),
|
|
1423
|
+
target,
|
|
1424
|
+
this.duration,
|
|
1425
|
+
this.easing
|
|
1426
|
+
);
|
|
1427
|
+
if (samples.values.length >= 2 && samples.durationMs > 0) {
|
|
1428
|
+
await this.runWaapiSettle(samples, target);
|
|
1429
|
+
if (!this.isAnimating) {
|
|
1430
|
+
this.getRootEl()?.removeAttribute("data-animating");
|
|
1431
|
+
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1432
|
+
}
|
|
1433
|
+
return;
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
if (this.animationKind === "spring") {
|
|
1743
1437
|
const spring = runSpring({
|
|
1744
1438
|
from: this.getSize(),
|
|
1745
1439
|
to: target,
|
|
@@ -1767,11 +1461,66 @@ var AnimationRunner = class {
|
|
|
1767
1461
|
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1768
1462
|
}
|
|
1769
1463
|
}
|
|
1464
|
+
async runWaapiSettle(samples, target) {
|
|
1465
|
+
const applyAux = this.applyAux;
|
|
1466
|
+
const getTransformFor = this.getTransformFor;
|
|
1467
|
+
const frames = samples.values.map((v) => ({
|
|
1468
|
+
transform: getTransformFor(v)
|
|
1469
|
+
}));
|
|
1470
|
+
const anim = this.element.animate(frames, {
|
|
1471
|
+
duration: samples.durationMs,
|
|
1472
|
+
easing: "linear",
|
|
1473
|
+
fill: "forwards"
|
|
1474
|
+
});
|
|
1475
|
+
let stopped = false;
|
|
1476
|
+
let auxRaf = 0;
|
|
1477
|
+
const start = performance.now();
|
|
1478
|
+
const lastIdx = samples.values.length - 1;
|
|
1479
|
+
const auxTick = () => {
|
|
1480
|
+
if (stopped) return;
|
|
1481
|
+
const elapsed = performance.now() - start;
|
|
1482
|
+
const idx = Math.min(Math.floor(elapsed / samples.stepMs), lastIdx);
|
|
1483
|
+
applyAux(samples.values[idx]);
|
|
1484
|
+
auxRaf = requestAnimationFrame(auxTick);
|
|
1485
|
+
};
|
|
1486
|
+
auxRaf = requestAnimationFrame(auxTick);
|
|
1487
|
+
const entry = {
|
|
1488
|
+
anim,
|
|
1489
|
+
stop: () => {
|
|
1490
|
+
stopped = true;
|
|
1491
|
+
cancelAnimationFrame(auxRaf);
|
|
1492
|
+
}
|
|
1493
|
+
};
|
|
1494
|
+
this.currentWaapi = entry;
|
|
1495
|
+
try {
|
|
1496
|
+
await anim.finished;
|
|
1497
|
+
} catch {
|
|
1498
|
+
}
|
|
1499
|
+
entry.stop();
|
|
1500
|
+
const wasCurrent = this.currentWaapi === entry;
|
|
1501
|
+
if (wasCurrent) this.currentWaapi = null;
|
|
1502
|
+
if (wasCurrent && anim.playState === "finished") {
|
|
1503
|
+
this.applySizeFn(target);
|
|
1504
|
+
try {
|
|
1505
|
+
anim.cancel();
|
|
1506
|
+
} catch {
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1770
1510
|
destroy() {
|
|
1771
1511
|
this.detachReducedMotion?.();
|
|
1772
1512
|
this.detachReducedMotion = null;
|
|
1773
1513
|
this.currentTween = null;
|
|
1774
1514
|
this.currentSpring = null;
|
|
1515
|
+
if (this.currentWaapi) {
|
|
1516
|
+
const entry = this.currentWaapi;
|
|
1517
|
+
this.currentWaapi = null;
|
|
1518
|
+
entry.stop();
|
|
1519
|
+
try {
|
|
1520
|
+
entry.anim.cancel();
|
|
1521
|
+
} catch {
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1775
1524
|
}
|
|
1776
1525
|
};
|
|
1777
1526
|
|
|
@@ -2628,7 +2377,7 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2628
2377
|
const initialAllowed = opts.allowed ?? opts.snapPoints.map((p) => p.id);
|
|
2629
2378
|
let initialId = opts.initial ?? initialAllowed[0] ?? opts.snapPoints[0]?.id ?? "default";
|
|
2630
2379
|
if (opts.persistKey) {
|
|
2631
|
-
const restored =
|
|
2380
|
+
const restored = readPersistedIdSafe(opts.persistKey);
|
|
2632
2381
|
if (restored && initialAllowed.includes(restored)) {
|
|
2633
2382
|
initialId = restored;
|
|
2634
2383
|
}
|
|
@@ -2659,6 +2408,7 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2659
2408
|
},
|
|
2660
2409
|
animation: {
|
|
2661
2410
|
animation: opts.animation,
|
|
2411
|
+
settleAnimation: opts.settleAnimation,
|
|
2662
2412
|
duration: opts.duration,
|
|
2663
2413
|
easing: opts.easing,
|
|
2664
2414
|
spring: opts.spring,
|
|
@@ -2676,6 +2426,15 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2676
2426
|
}
|
|
2677
2427
|
};
|
|
2678
2428
|
}
|
|
2429
|
+
var readPersistedIdSafe = (key) => {
|
|
2430
|
+
if (typeof window === "undefined") return null;
|
|
2431
|
+
if (typeof localStorage === "undefined") return null;
|
|
2432
|
+
try {
|
|
2433
|
+
return localStorage.getItem(key);
|
|
2434
|
+
} catch {
|
|
2435
|
+
return null;
|
|
2436
|
+
}
|
|
2437
|
+
};
|
|
2679
2438
|
|
|
2680
2439
|
// src/core/primitives/teardown-stack.ts
|
|
2681
2440
|
var TeardownStack = class {
|
|
@@ -2698,9 +2457,9 @@ var TeardownStack = class {
|
|
|
2698
2457
|
}
|
|
2699
2458
|
};
|
|
2700
2459
|
|
|
2701
|
-
// src/core/
|
|
2460
|
+
// src/core/BottomSheetCore.ts
|
|
2702
2461
|
var HAPTIC_DURATION_MS = 8;
|
|
2703
|
-
var
|
|
2462
|
+
var BottomSheetCore = class {
|
|
2704
2463
|
constructor(opts) {
|
|
2705
2464
|
__publicField(this, "id", nextInstanceId("bs"));
|
|
2706
2465
|
__publicField(this, "element");
|
|
@@ -2761,6 +2520,8 @@ var BottomSheetEngine = class {
|
|
|
2761
2520
|
__publicField(this, "stackEffectPrimed", false);
|
|
2762
2521
|
__publicField(this, "fitDeps");
|
|
2763
2522
|
__publicField(this, "transformTemplate");
|
|
2523
|
+
__publicField(this, "featureList", []);
|
|
2524
|
+
__publicField(this, "featureCtx");
|
|
2764
2525
|
const resolved = resolveEngineOptions(opts, {
|
|
2765
2526
|
shouldApplyInertSiblings: () => {
|
|
2766
2527
|
if (typeof document === "undefined") return false;
|
|
@@ -2807,7 +2568,9 @@ var BottomSheetEngine = class {
|
|
|
2807
2568
|
getRootEl: () => this.rootEl,
|
|
2808
2569
|
applySize: (size) => this.applySize(size),
|
|
2809
2570
|
getSize: () => this.size,
|
|
2810
|
-
isDragging: () => this.gesture?.isDragging ?? false
|
|
2571
|
+
isDragging: () => this.gesture?.isDragging ?? false,
|
|
2572
|
+
applyAux: (size) => this.applySize(size, true),
|
|
2573
|
+
getTransformFor: (size) => this.transformTemplate(this.snaps.getMaxAxisSize() - size)
|
|
2811
2574
|
},
|
|
2812
2575
|
resolved.animation
|
|
2813
2576
|
);
|
|
@@ -2830,6 +2593,11 @@ var BottomSheetEngine = class {
|
|
|
2830
2593
|
if (opts.linkedSheets) {
|
|
2831
2594
|
this.linkedSheets = opts.linkedSheets;
|
|
2832
2595
|
}
|
|
2596
|
+
const byName = /* @__PURE__ */ new Map();
|
|
2597
|
+
for (const feature of opts.features ?? []) {
|
|
2598
|
+
byName.set(feature.name, feature);
|
|
2599
|
+
}
|
|
2600
|
+
this.featureList = Array.from(byName.values());
|
|
2833
2601
|
this.activeId = resolved.initialId;
|
|
2834
2602
|
auditVhUsage(this.snapPointsRaw);
|
|
2835
2603
|
this.auditDuplicateSnapIds(this.snapPointsRaw);
|
|
@@ -2866,6 +2634,7 @@ var BottomSheetEngine = class {
|
|
|
2866
2634
|
scrollContainer: this.scrollContainer,
|
|
2867
2635
|
getMaxAxisSize: () => this.snaps.getMaxAxisSize()
|
|
2868
2636
|
});
|
|
2637
|
+
this.featureCtx = this.buildFeatureContext(opts.autoCollapseAfter);
|
|
2869
2638
|
this.attach();
|
|
2870
2639
|
this.registerInStack();
|
|
2871
2640
|
if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
|
|
@@ -2874,12 +2643,7 @@ var BottomSheetEngine = class {
|
|
|
2874
2643
|
if (!entry.isIntersecting) continue;
|
|
2875
2644
|
if (this.destroyed) return;
|
|
2876
2645
|
this.snaps.recompute();
|
|
2877
|
-
|
|
2878
|
-
if (current) {
|
|
2879
|
-
this.size = current.size;
|
|
2880
|
-
this.applySize(this.size);
|
|
2881
|
-
this.updateAriaSlider();
|
|
2882
|
-
}
|
|
2646
|
+
this.healActiveSnap();
|
|
2883
2647
|
io.disconnect();
|
|
2884
2648
|
return;
|
|
2885
2649
|
}
|
|
@@ -2902,46 +2666,77 @@ var BottomSheetEngine = class {
|
|
|
2902
2666
|
if (resolved.radius !== void 0) this.setRadius(resolved.radius);
|
|
2903
2667
|
if (resolved.maxHeight !== void 0) this.setMaxHeight(resolved.maxHeight);
|
|
2904
2668
|
this.applyAutoAriaLabelledBy();
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
getSize: () => this.size,
|
|
2910
|
-
close: () => this.close()
|
|
2911
|
-
})
|
|
2912
|
-
);
|
|
2913
|
-
}
|
|
2914
|
-
if (this.persistKey) {
|
|
2915
|
-
this.teardowns.add(installPersist(this, this.persistKey));
|
|
2669
|
+
this.runFeatureStage("post");
|
|
2670
|
+
this.warnOrphanFeatureOptions();
|
|
2671
|
+
if (this.size > 0) {
|
|
2672
|
+
this.handleOpen();
|
|
2916
2673
|
}
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
resolveSnap: (id) => this.snaps.findById(id),
|
|
2925
|
-
snapTo: (id) => {
|
|
2926
|
-
void this.snapTo(id);
|
|
2927
|
-
},
|
|
2928
|
-
on: (event, fn) => this.on(event, fn)
|
|
2929
|
-
})
|
|
2930
|
-
);
|
|
2931
|
-
this.teardowns.add(
|
|
2932
|
-
installRoute({
|
|
2674
|
+
}
|
|
2675
|
+
buildFeatureContext(autoCollapseAfter) {
|
|
2676
|
+
return {
|
|
2677
|
+
element: this.element,
|
|
2678
|
+
scrollContainer: this.scrollContainer,
|
|
2679
|
+
sheetId: this.id,
|
|
2680
|
+
options: {
|
|
2933
2681
|
routedTo: this.routedTo,
|
|
2934
2682
|
closeOnBack: this.closeOnBack,
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
this.
|
|
2683
|
+
closeOnRouteChange: this.closeOnRouteChange,
|
|
2684
|
+
persistKey: this.persistKey,
|
|
2685
|
+
autoCollapseAfter
|
|
2686
|
+
},
|
|
2687
|
+
isDestroyed: () => this.destroyed,
|
|
2688
|
+
isDragging: () => this.gesture?.isDragging ?? false,
|
|
2689
|
+
isAnimating: () => this.animation.isAnimating,
|
|
2690
|
+
isTopSheet: () => this.isTopSheet,
|
|
2691
|
+
isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
|
|
2692
|
+
getSize: () => this.size,
|
|
2693
|
+
getActiveId: () => this.activeId,
|
|
2694
|
+
getAllowedIds: () => this.snaps.getAllowedIds().slice(),
|
|
2695
|
+
allowedIdsBySize: () => this.allowedIdsBySize(),
|
|
2696
|
+
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
2697
|
+
resolveSnap: (id) => this.snaps.findById(id),
|
|
2698
|
+
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
2699
|
+
setSize: (size) => {
|
|
2700
|
+
this.size = size;
|
|
2701
|
+
},
|
|
2702
|
+
setMaxAxisSize: (size) => {
|
|
2703
|
+
this.snaps.setMaxAxisSize(size);
|
|
2704
|
+
},
|
|
2705
|
+
applySize: (size) => this.applySize(size),
|
|
2706
|
+
recomputeSnaps: () => this.recomputeSnaps(),
|
|
2707
|
+
newCycle: () => {
|
|
2708
|
+
this.newCycle();
|
|
2709
|
+
},
|
|
2710
|
+
cancelInFlight: () => {
|
|
2711
|
+
this.animation.cancel();
|
|
2712
|
+
},
|
|
2713
|
+
resyncAfterResize: () => this.resyncAfterResize(),
|
|
2714
|
+
snapTo: (id) => {
|
|
2715
|
+
void this.snapTo(id);
|
|
2716
|
+
},
|
|
2717
|
+
close: (reason) => this.close(reason),
|
|
2718
|
+
on: (event, fn) => this.on(event, fn),
|
|
2719
|
+
addTeardown: (fn) => this.teardowns.add(fn)
|
|
2720
|
+
};
|
|
2721
|
+
}
|
|
2722
|
+
runFeatureStage(stage) {
|
|
2723
|
+
for (const feature of this.featureList) {
|
|
2724
|
+
if ((feature.stage ?? "post") !== stage) continue;
|
|
2725
|
+
const teardown = feature.install(this.featureCtx);
|
|
2726
|
+
if (teardown) this.teardowns.add(teardown);
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
warnOrphanFeatureOptions() {
|
|
2730
|
+
const names = new Set(this.featureList.map((f) => f.name));
|
|
2731
|
+
if ((this.closeOnBack || this.routedTo !== void 0 || this.closeOnRouteChange) && !names.has("route")) {
|
|
2732
|
+
devWarn(
|
|
2733
|
+
"[BottomSheet] closeOnBack/routedTo/closeOnRouteChange need routeFeature() \u2014 option ignored"
|
|
2734
|
+
);
|
|
2735
|
+
}
|
|
2736
|
+
if (this.persistKey && !names.has("persist")) {
|
|
2737
|
+
devWarn(
|
|
2738
|
+
"[BottomSheet] persistKey needs persistFeature() \u2014 snaps will not be saved"
|
|
2739
|
+
);
|
|
2945
2740
|
}
|
|
2946
2741
|
}
|
|
2947
2742
|
get state() {
|
|
@@ -3043,6 +2838,8 @@ var BottomSheetEngine = class {
|
|
|
3043
2838
|
const vt = document.startViewTransition(() => {
|
|
3044
2839
|
this.applySize(target.size);
|
|
3045
2840
|
});
|
|
2841
|
+
vt.ready?.catch(() => {
|
|
2842
|
+
});
|
|
3046
2843
|
this.currentViewTransition = vt;
|
|
3047
2844
|
try {
|
|
3048
2845
|
await vt.finished;
|
|
@@ -3294,11 +3091,16 @@ var BottomSheetEngine = class {
|
|
|
3294
3091
|
this.maxHeight.clampTo();
|
|
3295
3092
|
this.scrim.invalidateOpacityCache();
|
|
3296
3093
|
if (this.gesture?.isDragging) return;
|
|
3094
|
+
this.healActiveSnap();
|
|
3095
|
+
}
|
|
3096
|
+
healActiveSnap() {
|
|
3297
3097
|
const current = this.snaps.findById(this.activeId);
|
|
3298
|
-
if (current)
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3098
|
+
if (!current) return;
|
|
3099
|
+
this.size = current.size;
|
|
3100
|
+
this.applySize(this.size);
|
|
3101
|
+
this.updateAriaSlider();
|
|
3102
|
+
if (this.size > 0 && !this.lifecycle.isInstalled && !this.opening && !this.animation.isAnimating) {
|
|
3103
|
+
this.emitOpenSequence(this.activeId);
|
|
3302
3104
|
}
|
|
3303
3105
|
}
|
|
3304
3106
|
destroy() {
|
|
@@ -3477,18 +3279,7 @@ var BottomSheetEngine = class {
|
|
|
3477
3279
|
}
|
|
3478
3280
|
}
|
|
3479
3281
|
attachFeatures() {
|
|
3480
|
-
|
|
3481
|
-
this.teardowns.add(installContentSwipe({
|
|
3482
|
-
container: this.scrollContainer,
|
|
3483
|
-
isDragging: () => this.gesture?.isDragging ?? false,
|
|
3484
|
-
isAnimating: () => this.animation.isAnimating,
|
|
3485
|
-
getAllowedIds: () => this.allowedIdsBySize(),
|
|
3486
|
-
getActiveId: () => this.activeId,
|
|
3487
|
-
snapTo: (id) => {
|
|
3488
|
-
void this.snapTo(id);
|
|
3489
|
-
}
|
|
3490
|
-
}));
|
|
3491
|
-
}
|
|
3282
|
+
this.runFeatureStage("attach");
|
|
3492
3283
|
if (typeof window !== "undefined") {
|
|
3493
3284
|
this.teardowns.add(installResizeObserver({
|
|
3494
3285
|
element: this.element,
|
|
@@ -3528,31 +3319,6 @@ var BottomSheetEngine = class {
|
|
|
3528
3319
|
() => document.removeEventListener("keydown", onKey)
|
|
3529
3320
|
);
|
|
3530
3321
|
}
|
|
3531
|
-
this.teardowns.add(installVisualViewport({
|
|
3532
|
-
element: this.element,
|
|
3533
|
-
isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
|
|
3534
|
-
isDestroyed: () => this.destroyed,
|
|
3535
|
-
isDragging: () => this.gesture?.isDragging ?? false,
|
|
3536
|
-
recomputeSnaps: () => this.recomputeSnaps(),
|
|
3537
|
-
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
3538
|
-
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
3539
|
-
getSize: () => this.size,
|
|
3540
|
-
setMaxAxisSize: (size) => {
|
|
3541
|
-
this.snaps.setMaxAxisSize(size);
|
|
3542
|
-
},
|
|
3543
|
-
setSize: (size) => {
|
|
3544
|
-
this.size = size;
|
|
3545
|
-
},
|
|
3546
|
-
applySize: (size) => this.applySize(size),
|
|
3547
|
-
cancelInFlight: () => {
|
|
3548
|
-
this.animation.cancel();
|
|
3549
|
-
},
|
|
3550
|
-
newCycle: () => {
|
|
3551
|
-
this.newCycle();
|
|
3552
|
-
},
|
|
3553
|
-
isAnimating: () => this.animation.isAnimating,
|
|
3554
|
-
resyncAfterCancel: () => this.resyncAfterResize()
|
|
3555
|
-
}));
|
|
3556
3322
|
}
|
|
3557
3323
|
this.teardowns.add(installSliderKeyboard({
|
|
3558
3324
|
handle: this.handle,
|
|
@@ -3629,13 +3395,13 @@ var BottomSheetEngine = class {
|
|
|
3629
3395
|
}
|
|
3630
3396
|
}
|
|
3631
3397
|
}
|
|
3632
|
-
applySize(size) {
|
|
3398
|
+
applySize(size, skipTransform = false) {
|
|
3633
3399
|
const cap = this.snaps.getMaxAxisSize();
|
|
3634
3400
|
const clamped = cap > 0 && size > cap && !this.gesture?.isDragging && !this.allowOvershoot ? cap : size;
|
|
3635
3401
|
this.size = clamped;
|
|
3636
3402
|
const offset = cap - clamped;
|
|
3637
3403
|
const style = this.element.style;
|
|
3638
|
-
style.transform = this.transformTemplate(offset);
|
|
3404
|
+
if (!skipTransform) style.transform = this.transformTemplate(offset);
|
|
3639
3405
|
if (this.sizeWriteSentinel.shouldWrite(clamped, SIZE_WRITE_EPSILON)) {
|
|
3640
3406
|
style.setProperty("--bs-size", `${clamped}px`);
|
|
3641
3407
|
if (this.scrimParent) {
|
|
@@ -3712,6 +3478,514 @@ var BottomSheetEngine = class {
|
|
|
3712
3478
|
sheetStack.update();
|
|
3713
3479
|
}
|
|
3714
3480
|
};
|
|
3481
|
+
|
|
3482
|
+
// src/core/features/history-coordinator.ts
|
|
3483
|
+
var entries = [];
|
|
3484
|
+
var subscribers = /* @__PURE__ */ new Set();
|
|
3485
|
+
var suppress = 0;
|
|
3486
|
+
var internalDepth = 0;
|
|
3487
|
+
var pendingRebrands = [];
|
|
3488
|
+
var listenerInstalled = false;
|
|
3489
|
+
var patchInstalled = false;
|
|
3490
|
+
var origPushState = null;
|
|
3491
|
+
var origReplaceState = null;
|
|
3492
|
+
var patchedPushState = null;
|
|
3493
|
+
var patchedReplaceState = null;
|
|
3494
|
+
var hasWindow = () => typeof window !== "undefined";
|
|
3495
|
+
var hasHistory = () => typeof history !== "undefined";
|
|
3496
|
+
var brandMarker = (surface) => ({
|
|
3497
|
+
...surface.markerState(),
|
|
3498
|
+
__bs: true
|
|
3499
|
+
});
|
|
3500
|
+
var runInternal = (fn) => {
|
|
3501
|
+
internalDepth += 1;
|
|
3502
|
+
try {
|
|
3503
|
+
fn();
|
|
3504
|
+
} finally {
|
|
3505
|
+
internalDepth -= 1;
|
|
3506
|
+
}
|
|
3507
|
+
};
|
|
3508
|
+
var notifyRouteChange = () => {
|
|
3509
|
+
const snapshot = Array.from(subscribers);
|
|
3510
|
+
for (const fn of snapshot) fn();
|
|
3511
|
+
};
|
|
3512
|
+
var ensureListener = () => {
|
|
3513
|
+
if (listenerInstalled || !hasWindow()) return;
|
|
3514
|
+
window.addEventListener("popstate", onPopState);
|
|
3515
|
+
listenerInstalled = true;
|
|
3516
|
+
};
|
|
3517
|
+
var maybeTeardownListener = () => {
|
|
3518
|
+
if (!listenerInstalled) return;
|
|
3519
|
+
if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
|
|
3520
|
+
if (hasWindow()) window.removeEventListener("popstate", onPopState);
|
|
3521
|
+
listenerInstalled = false;
|
|
3522
|
+
};
|
|
3523
|
+
var installPatch = () => {
|
|
3524
|
+
if (patchInstalled || !hasHistory()) return;
|
|
3525
|
+
origPushState = history.pushState;
|
|
3526
|
+
origReplaceState = history.replaceState;
|
|
3527
|
+
patchedPushState = function(...args) {
|
|
3528
|
+
origPushState.apply(this, args);
|
|
3529
|
+
if (internalDepth === 0) notifyRouteChange();
|
|
3530
|
+
};
|
|
3531
|
+
patchedReplaceState = function(...args) {
|
|
3532
|
+
origReplaceState.apply(this, args);
|
|
3533
|
+
if (internalDepth === 0) notifyRouteChange();
|
|
3534
|
+
};
|
|
3535
|
+
history.pushState = patchedPushState;
|
|
3536
|
+
history.replaceState = patchedReplaceState;
|
|
3537
|
+
patchInstalled = true;
|
|
3538
|
+
};
|
|
3539
|
+
var removePatch = () => {
|
|
3540
|
+
if (!patchInstalled) return;
|
|
3541
|
+
if (history.pushState === patchedPushState && origPushState) {
|
|
3542
|
+
history.pushState = origPushState;
|
|
3543
|
+
}
|
|
3544
|
+
if (history.replaceState === patchedReplaceState && origReplaceState) {
|
|
3545
|
+
history.replaceState = origReplaceState;
|
|
3546
|
+
}
|
|
3547
|
+
origPushState = null;
|
|
3548
|
+
origReplaceState = null;
|
|
3549
|
+
patchedPushState = null;
|
|
3550
|
+
patchedReplaceState = null;
|
|
3551
|
+
patchInstalled = false;
|
|
3552
|
+
};
|
|
3553
|
+
function onPopState() {
|
|
3554
|
+
if (suppress > 0) {
|
|
3555
|
+
suppress -= 1;
|
|
3556
|
+
const rebrand = pendingRebrands.shift();
|
|
3557
|
+
if (rebrand) rebrand();
|
|
3558
|
+
maybeTeardownListener();
|
|
3559
|
+
return;
|
|
3560
|
+
}
|
|
3561
|
+
if (entries.length === 0) {
|
|
3562
|
+
notifyRouteChange();
|
|
3563
|
+
maybeTeardownListener();
|
|
3564
|
+
return;
|
|
3565
|
+
}
|
|
3566
|
+
let target = null;
|
|
3567
|
+
let targetIdx = -1;
|
|
3568
|
+
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
3569
|
+
const entry = entries[i];
|
|
3570
|
+
if (!entry.surface.isOpen()) continue;
|
|
3571
|
+
if (!target) {
|
|
3572
|
+
target = entry;
|
|
3573
|
+
targetIdx = i;
|
|
3574
|
+
}
|
|
3575
|
+
if (entry.surface.isTop()) {
|
|
3576
|
+
target = entry;
|
|
3577
|
+
targetIdx = i;
|
|
3578
|
+
break;
|
|
3579
|
+
}
|
|
3580
|
+
}
|
|
3581
|
+
if (!target) {
|
|
3582
|
+
const removed = entries.pop();
|
|
3583
|
+
if (removed) removed.live = false;
|
|
3584
|
+
maybeTeardownListener();
|
|
3585
|
+
return;
|
|
3586
|
+
}
|
|
3587
|
+
target.live = false;
|
|
3588
|
+
entries.splice(targetIdx, 1);
|
|
3589
|
+
const settled = target;
|
|
3590
|
+
void Promise.resolve(settled.surface.close()).then(() => {
|
|
3591
|
+
if (settled.surface.isOpen()) restore(settled);
|
|
3592
|
+
});
|
|
3593
|
+
maybeTeardownListener();
|
|
3594
|
+
}
|
|
3595
|
+
function restore(entry) {
|
|
3596
|
+
if (!hasWindow() || !hasHistory()) return;
|
|
3597
|
+
entry.live = true;
|
|
3598
|
+
runInternal(() => {
|
|
3599
|
+
try {
|
|
3600
|
+
history.pushState(brandMarker(entry.surface), "", entry.surface.url);
|
|
3601
|
+
} catch {
|
|
3602
|
+
entry.live = false;
|
|
3603
|
+
}
|
|
3604
|
+
});
|
|
3605
|
+
if (entry.live) {
|
|
3606
|
+
entries.push(entry);
|
|
3607
|
+
ensureListener();
|
|
3608
|
+
}
|
|
3609
|
+
}
|
|
3610
|
+
function pushBackMarker(surface) {
|
|
3611
|
+
const entry = { surface, priorUrl: void 0, live: false };
|
|
3612
|
+
if (!hasWindow() || !hasHistory()) {
|
|
3613
|
+
return entry;
|
|
3614
|
+
}
|
|
3615
|
+
entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
|
|
3616
|
+
runInternal(() => {
|
|
3617
|
+
try {
|
|
3618
|
+
history.pushState(brandMarker(surface), "", surface.url);
|
|
3619
|
+
entry.live = true;
|
|
3620
|
+
} catch {
|
|
3621
|
+
entry.live = false;
|
|
3622
|
+
}
|
|
3623
|
+
});
|
|
3624
|
+
if (entry.live) {
|
|
3625
|
+
entries.push(entry);
|
|
3626
|
+
ensureListener();
|
|
3627
|
+
}
|
|
3628
|
+
return entry;
|
|
3629
|
+
}
|
|
3630
|
+
function popBackMarker(handle) {
|
|
3631
|
+
if (!hasWindow() || !hasHistory()) return;
|
|
3632
|
+
const entry = handle;
|
|
3633
|
+
const idx = entries.indexOf(entry);
|
|
3634
|
+
if (idx === -1 || !entry.live) return;
|
|
3635
|
+
const last = entries.length - 1;
|
|
3636
|
+
entry.live = false;
|
|
3637
|
+
entries.splice(idx, 1);
|
|
3638
|
+
let rebrand = null;
|
|
3639
|
+
if (idx !== last) {
|
|
3640
|
+
const rebrandSurface = entries[entries.length - 1].surface;
|
|
3641
|
+
const rebrandUrl = entry.priorUrl;
|
|
3642
|
+
rebrand = () => {
|
|
3643
|
+
runInternal(() => {
|
|
3644
|
+
history.replaceState(
|
|
3645
|
+
brandMarker(rebrandSurface),
|
|
3646
|
+
"",
|
|
3647
|
+
rebrandUrl !== void 0 ? rebrandUrl : location.href
|
|
3648
|
+
);
|
|
3649
|
+
});
|
|
3650
|
+
};
|
|
3651
|
+
}
|
|
3652
|
+
pendingRebrands.push(rebrand);
|
|
3653
|
+
suppress += 1;
|
|
3654
|
+
runInternal(() => {
|
|
3655
|
+
try {
|
|
3656
|
+
history.back();
|
|
3657
|
+
} catch {
|
|
3658
|
+
suppress = Math.max(0, suppress - 1);
|
|
3659
|
+
pendingRebrands.pop();
|
|
3660
|
+
}
|
|
3661
|
+
});
|
|
3662
|
+
maybeTeardownListener();
|
|
3663
|
+
}
|
|
3664
|
+
function subscribeRouteChange(fn) {
|
|
3665
|
+
if (!hasWindow() || !hasHistory()) return () => {
|
|
3666
|
+
};
|
|
3667
|
+
subscribers.add(fn);
|
|
3668
|
+
if (subscribers.size === 1) installPatch();
|
|
3669
|
+
ensureListener();
|
|
3670
|
+
return () => {
|
|
3671
|
+
if (!subscribers.has(fn)) return;
|
|
3672
|
+
subscribers.delete(fn);
|
|
3673
|
+
if (subscribers.size === 0) removePatch();
|
|
3674
|
+
maybeTeardownListener();
|
|
3675
|
+
};
|
|
3676
|
+
}
|
|
3677
|
+
|
|
3678
|
+
// src/core/features/route.ts
|
|
3679
|
+
function installRoute(deps) {
|
|
3680
|
+
if (typeof window === "undefined") {
|
|
3681
|
+
return () => {
|
|
3682
|
+
};
|
|
3683
|
+
}
|
|
3684
|
+
if (!deps.routedTo && !deps.closeOnBack) {
|
|
3685
|
+
return () => {
|
|
3686
|
+
};
|
|
3687
|
+
}
|
|
3688
|
+
let handle = null;
|
|
3689
|
+
const onOpen = () => {
|
|
3690
|
+
if (handle) return;
|
|
3691
|
+
handle = pushBackMarker({
|
|
3692
|
+
isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
|
|
3693
|
+
isTop: deps.isTopSheet,
|
|
3694
|
+
close: deps.close,
|
|
3695
|
+
markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
|
|
3696
|
+
url: deps.routedTo
|
|
3697
|
+
});
|
|
3698
|
+
};
|
|
3699
|
+
const onClose = () => {
|
|
3700
|
+
if (!handle) return;
|
|
3701
|
+
popBackMarker(handle);
|
|
3702
|
+
handle = null;
|
|
3703
|
+
};
|
|
3704
|
+
const unsubscribeOpen = deps.on("open", onOpen);
|
|
3705
|
+
const unsubscribeClose = deps.on("close", onClose);
|
|
3706
|
+
if (deps.getSize() > 0) onOpen();
|
|
3707
|
+
return () => {
|
|
3708
|
+
unsubscribeOpen();
|
|
3709
|
+
unsubscribeClose();
|
|
3710
|
+
if (handle) {
|
|
3711
|
+
popBackMarker(handle);
|
|
3712
|
+
handle = null;
|
|
3713
|
+
}
|
|
3714
|
+
};
|
|
3715
|
+
}
|
|
3716
|
+
function installRouteChange(deps) {
|
|
3717
|
+
return subscribeRouteChange(() => {
|
|
3718
|
+
if (deps.isDestroyed() || deps.getSize() <= 0) return;
|
|
3719
|
+
void deps.close();
|
|
3720
|
+
});
|
|
3721
|
+
}
|
|
3722
|
+
|
|
3723
|
+
// src/core/features/persist.ts
|
|
3724
|
+
function installPersist(engine, key) {
|
|
3725
|
+
const unsubscribe = engine.on("snap", ({ id }) => {
|
|
3726
|
+
if (typeof window === "undefined") return;
|
|
3727
|
+
if (typeof localStorage === "undefined") return;
|
|
3728
|
+
try {
|
|
3729
|
+
localStorage.setItem(key, id);
|
|
3730
|
+
} catch {
|
|
3731
|
+
}
|
|
3732
|
+
});
|
|
3733
|
+
return unsubscribe;
|
|
3734
|
+
}
|
|
3735
|
+
|
|
3736
|
+
// src/core/features/auto-collapse.ts
|
|
3737
|
+
function installAutoCollapse(deps) {
|
|
3738
|
+
const { ms } = deps;
|
|
3739
|
+
if (ms === void 0 || ms <= 0) {
|
|
3740
|
+
return () => {
|
|
3741
|
+
};
|
|
3742
|
+
}
|
|
3743
|
+
let timer = null;
|
|
3744
|
+
const clearTimer = () => {
|
|
3745
|
+
if (timer !== null) {
|
|
3746
|
+
clearTimeout(timer);
|
|
3747
|
+
timer = null;
|
|
3748
|
+
}
|
|
3749
|
+
};
|
|
3750
|
+
const fire = () => {
|
|
3751
|
+
if (deps.isDestroyed()) return;
|
|
3752
|
+
if (deps.isDragging()) return;
|
|
3753
|
+
const active = deps.resolveSnap(deps.getActiveId());
|
|
3754
|
+
if (!active || active.size === 0) return;
|
|
3755
|
+
let target = null;
|
|
3756
|
+
for (const id of deps.getAllowedIds()) {
|
|
3757
|
+
const snap = deps.resolveSnap(id);
|
|
3758
|
+
if (!snap || snap.size <= 0) continue;
|
|
3759
|
+
if (!target || snap.size < target.size) target = snap;
|
|
3760
|
+
}
|
|
3761
|
+
if (!target) return;
|
|
3762
|
+
if (target.id === active.id || target.size >= active.size) return;
|
|
3763
|
+
deps.snapTo(target.id);
|
|
3764
|
+
};
|
|
3765
|
+
const reset = () => {
|
|
3766
|
+
clearTimer();
|
|
3767
|
+
if (deps.isDestroyed()) return;
|
|
3768
|
+
timer = setTimeout(() => {
|
|
3769
|
+
timer = null;
|
|
3770
|
+
fire();
|
|
3771
|
+
}, ms);
|
|
3772
|
+
};
|
|
3773
|
+
const unsubscribe = deps.on("snap", () => reset());
|
|
3774
|
+
if ((deps.resolveSnap(deps.getActiveId())?.size ?? 0) > 0) reset();
|
|
3775
|
+
return () => {
|
|
3776
|
+
clearTimer();
|
|
3777
|
+
unsubscribe();
|
|
3778
|
+
};
|
|
3779
|
+
}
|
|
3780
|
+
|
|
3781
|
+
// src/core/features/content-swipe.ts
|
|
3782
|
+
var CONTENT_PULL_THRESHOLD = 60;
|
|
3783
|
+
function installContentSwipe(deps) {
|
|
3784
|
+
const { container } = deps;
|
|
3785
|
+
let startY = 0;
|
|
3786
|
+
let startScrollTop = 0;
|
|
3787
|
+
let moved = false;
|
|
3788
|
+
const onTouchStart = (e) => {
|
|
3789
|
+
const t = e.touches[0];
|
|
3790
|
+
if (!t) return;
|
|
3791
|
+
startY = t.clientY;
|
|
3792
|
+
startScrollTop = container.scrollTop;
|
|
3793
|
+
moved = false;
|
|
3794
|
+
};
|
|
3795
|
+
const onTouchMove = (e) => {
|
|
3796
|
+
const t = e.touches[0];
|
|
3797
|
+
if (!t) return;
|
|
3798
|
+
if (Math.abs(t.clientY - startY) > CONTENT_PULL_THRESHOLD) moved = true;
|
|
3799
|
+
};
|
|
3800
|
+
const onTouchEnd = (e) => {
|
|
3801
|
+
if (!moved) return;
|
|
3802
|
+
if (deps.isDragging() || deps.isAnimating()) return;
|
|
3803
|
+
if (container.scrollTop !== startScrollTop) return;
|
|
3804
|
+
const t = e.changedTouches[0];
|
|
3805
|
+
if (!t) return;
|
|
3806
|
+
const deltaY = t.clientY - startY;
|
|
3807
|
+
const atTop = container.scrollTop <= 0;
|
|
3808
|
+
const allowed = deps.getAllowedIds();
|
|
3809
|
+
const idx = allowed.indexOf(deps.getActiveId());
|
|
3810
|
+
if (idx === -1) return;
|
|
3811
|
+
if (atTop && deltaY > CONTENT_PULL_THRESHOLD && idx > 0) {
|
|
3812
|
+
deps.snapTo(allowed[idx - 1]);
|
|
3813
|
+
} else if (deltaY < -CONTENT_PULL_THRESHOLD && idx < allowed.length - 1) {
|
|
3814
|
+
deps.snapTo(allowed[idx + 1]);
|
|
3815
|
+
}
|
|
3816
|
+
};
|
|
3817
|
+
container.addEventListener("touchstart", onTouchStart, { passive: true });
|
|
3818
|
+
container.addEventListener("touchmove", onTouchMove, { passive: true });
|
|
3819
|
+
container.addEventListener("touchend", onTouchEnd, { passive: true });
|
|
3820
|
+
return () => {
|
|
3821
|
+
container.removeEventListener("touchstart", onTouchStart);
|
|
3822
|
+
container.removeEventListener("touchmove", onTouchMove);
|
|
3823
|
+
container.removeEventListener("touchend", onTouchEnd);
|
|
3824
|
+
};
|
|
3825
|
+
}
|
|
3826
|
+
|
|
3827
|
+
// src/core/features/visual-viewport.ts
|
|
3828
|
+
var SAFETY_PAD = 8;
|
|
3829
|
+
function installVisualViewport(deps) {
|
|
3830
|
+
if (typeof window === "undefined" || !window.visualViewport) {
|
|
3831
|
+
return () => {
|
|
3832
|
+
};
|
|
3833
|
+
}
|
|
3834
|
+
const vv = window.visualViewport;
|
|
3835
|
+
let rafId = null;
|
|
3836
|
+
const onResize = () => {
|
|
3837
|
+
if (rafId !== null) return;
|
|
3838
|
+
rafId = requestAnimationFrame(() => {
|
|
3839
|
+
rafId = null;
|
|
3840
|
+
if (deps.isDestroyed()) return;
|
|
3841
|
+
deps.recomputeSnaps();
|
|
3842
|
+
const isVertical = deps.isVerticalAxis();
|
|
3843
|
+
const visible = isVertical ? vv.height : vv.width;
|
|
3844
|
+
const windowSize = isVertical ? window.innerHeight : window.innerWidth;
|
|
3845
|
+
const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
|
|
3846
|
+
if (clamp < deps.getMaxAxisSize()) {
|
|
3847
|
+
deps.setMaxAxisSize(clamp);
|
|
3848
|
+
}
|
|
3849
|
+
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
3850
|
+
deps.cancelInFlight();
|
|
3851
|
+
deps.newCycle();
|
|
3852
|
+
const max = deps.getMaxAxisSize();
|
|
3853
|
+
deps.setSize(Math.min(deps.getSize(), max));
|
|
3854
|
+
const current = deps.resolveActiveSnap();
|
|
3855
|
+
if (current && !deps.isDragging()) {
|
|
3856
|
+
deps.applySize(Math.min(current.size, max));
|
|
3857
|
+
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
3858
|
+
} else {
|
|
3859
|
+
deps.applySize(deps.getSize());
|
|
3860
|
+
}
|
|
3861
|
+
});
|
|
3862
|
+
};
|
|
3863
|
+
vv.addEventListener("resize", onResize);
|
|
3864
|
+
return () => {
|
|
3865
|
+
vv.removeEventListener("resize", onResize);
|
|
3866
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
3867
|
+
};
|
|
3868
|
+
}
|
|
3869
|
+
|
|
3870
|
+
// src/core/features/engine-features.ts
|
|
3871
|
+
function routeFeature() {
|
|
3872
|
+
return {
|
|
3873
|
+
name: "route",
|
|
3874
|
+
install: (ctx) => {
|
|
3875
|
+
const teardowns = new TeardownStack();
|
|
3876
|
+
if (ctx.options.closeOnRouteChange) {
|
|
3877
|
+
teardowns.add(
|
|
3878
|
+
installRouteChange({
|
|
3879
|
+
isDestroyed: ctx.isDestroyed,
|
|
3880
|
+
getSize: ctx.getSize,
|
|
3881
|
+
close: () => ctx.close()
|
|
3882
|
+
})
|
|
3883
|
+
);
|
|
3884
|
+
}
|
|
3885
|
+
teardowns.add(
|
|
3886
|
+
installRoute({
|
|
3887
|
+
routedTo: ctx.options.routedTo,
|
|
3888
|
+
closeOnBack: ctx.options.closeOnBack,
|
|
3889
|
+
isTopSheet: ctx.isTopSheet,
|
|
3890
|
+
getSize: ctx.getSize,
|
|
3891
|
+
isDestroyed: ctx.isDestroyed,
|
|
3892
|
+
close: () => ctx.close("back"),
|
|
3893
|
+
on: ctx.on,
|
|
3894
|
+
sheetId: ctx.sheetId
|
|
3895
|
+
})
|
|
3896
|
+
);
|
|
3897
|
+
return () => teardowns.drain();
|
|
3898
|
+
}
|
|
3899
|
+
};
|
|
3900
|
+
}
|
|
3901
|
+
function persistFeature() {
|
|
3902
|
+
return {
|
|
3903
|
+
name: "persist",
|
|
3904
|
+
install: (ctx) => {
|
|
3905
|
+
const key = ctx.options.persistKey;
|
|
3906
|
+
if (!key) return;
|
|
3907
|
+
return installPersist({ on: ctx.on }, key);
|
|
3908
|
+
}
|
|
3909
|
+
};
|
|
3910
|
+
}
|
|
3911
|
+
function autoCollapseFeature() {
|
|
3912
|
+
return {
|
|
3913
|
+
name: "auto-collapse",
|
|
3914
|
+
install: (ctx) => installAutoCollapse({
|
|
3915
|
+
ms: ctx.options.autoCollapseAfter,
|
|
3916
|
+
isDestroyed: ctx.isDestroyed,
|
|
3917
|
+
isDragging: ctx.isDragging,
|
|
3918
|
+
getAllowedIds: ctx.getAllowedIds,
|
|
3919
|
+
getActiveId: ctx.getActiveId,
|
|
3920
|
+
resolveSnap: ctx.resolveSnap,
|
|
3921
|
+
snapTo: ctx.snapTo,
|
|
3922
|
+
on: ctx.on
|
|
3923
|
+
})
|
|
3924
|
+
};
|
|
3925
|
+
}
|
|
3926
|
+
function contentSwipeFeature() {
|
|
3927
|
+
return {
|
|
3928
|
+
name: "content-swipe",
|
|
3929
|
+
stage: "attach",
|
|
3930
|
+
install: (ctx) => {
|
|
3931
|
+
if (!ctx.scrollContainer) return;
|
|
3932
|
+
return installContentSwipe({
|
|
3933
|
+
container: ctx.scrollContainer,
|
|
3934
|
+
isDragging: ctx.isDragging,
|
|
3935
|
+
isAnimating: ctx.isAnimating,
|
|
3936
|
+
getAllowedIds: ctx.allowedIdsBySize,
|
|
3937
|
+
getActiveId: ctx.getActiveId,
|
|
3938
|
+
snapTo: ctx.snapTo
|
|
3939
|
+
});
|
|
3940
|
+
}
|
|
3941
|
+
};
|
|
3942
|
+
}
|
|
3943
|
+
function visualViewportFeature() {
|
|
3944
|
+
return {
|
|
3945
|
+
name: "visual-viewport",
|
|
3946
|
+
install: (ctx) => {
|
|
3947
|
+
if (typeof window === "undefined") return;
|
|
3948
|
+
return installVisualViewport({
|
|
3949
|
+
element: ctx.element,
|
|
3950
|
+
isVerticalAxis: ctx.isVerticalAxis,
|
|
3951
|
+
isDestroyed: ctx.isDestroyed,
|
|
3952
|
+
isDragging: ctx.isDragging,
|
|
3953
|
+
recomputeSnaps: ctx.recomputeSnaps,
|
|
3954
|
+
resolveActiveSnap: ctx.resolveActiveSnap,
|
|
3955
|
+
getMaxAxisSize: ctx.getMaxAxisSize,
|
|
3956
|
+
getSize: ctx.getSize,
|
|
3957
|
+
setMaxAxisSize: ctx.setMaxAxisSize,
|
|
3958
|
+
setSize: ctx.setSize,
|
|
3959
|
+
applySize: ctx.applySize,
|
|
3960
|
+
cancelInFlight: ctx.cancelInFlight,
|
|
3961
|
+
newCycle: ctx.newCycle,
|
|
3962
|
+
isAnimating: ctx.isAnimating,
|
|
3963
|
+
resyncAfterCancel: ctx.resyncAfterResize
|
|
3964
|
+
});
|
|
3965
|
+
}
|
|
3966
|
+
};
|
|
3967
|
+
}
|
|
3968
|
+
|
|
3969
|
+
// src/core/default-features.ts
|
|
3970
|
+
function defaultEngineFeatures() {
|
|
3971
|
+
return [
|
|
3972
|
+
contentSwipeFeature(),
|
|
3973
|
+
visualViewportFeature(),
|
|
3974
|
+
persistFeature(),
|
|
3975
|
+
autoCollapseFeature(),
|
|
3976
|
+
routeFeature()
|
|
3977
|
+
];
|
|
3978
|
+
}
|
|
3979
|
+
|
|
3980
|
+
// src/core/BottomSheetEngine.ts
|
|
3981
|
+
var BottomSheetEngine = class extends BottomSheetCore {
|
|
3982
|
+
constructor(opts) {
|
|
3983
|
+
super({
|
|
3984
|
+
...opts,
|
|
3985
|
+
features: [...defaultEngineFeatures(), ...opts.features ?? []]
|
|
3986
|
+
});
|
|
3987
|
+
}
|
|
3988
|
+
};
|
|
3715
3989
|
function useEnginePropSync(engineRef, opts) {
|
|
3716
3990
|
const optsRef = useRef(opts);
|
|
3717
3991
|
optsRef.current = opts;
|