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