@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.
Files changed (58) hide show
  1. package/README.md +68 -1
  2. package/dist/{BottomSheetEngine-DzsIwD28.d.cts → BottomSheetCore-CsIjyq7C.d.cts} +61 -5
  3. package/dist/{BottomSheetEngine-DRjCU73e.d.ts → BottomSheetCore-D16lsa6g.d.ts} +61 -5
  4. package/dist/BottomSheetEngine-BYjAVrmd.d.cts +7 -0
  5. package/dist/BottomSheetEngine-YuCNugZn.d.ts +7 -0
  6. package/dist/core.cjs +3476 -0
  7. package/dist/core.d.cts +3 -0
  8. package/dist/core.d.ts +3 -0
  9. package/dist/core.js +3474 -0
  10. package/dist/debug.cjs +109 -0
  11. package/dist/debug.d.cts +22 -0
  12. package/dist/debug.d.ts +22 -0
  13. package/dist/debug.js +107 -0
  14. package/dist/element.cjs +994 -697
  15. package/dist/element.d.cts +2 -1
  16. package/dist/element.d.ts +2 -1
  17. package/dist/element.iife.global.js +2 -2
  18. package/dist/element.js +994 -697
  19. package/dist/features.cjs +533 -0
  20. package/dist/features.d.cts +13 -0
  21. package/dist/features.d.ts +13 -0
  22. package/dist/features.js +526 -0
  23. package/dist/index-DdYLOIIT.d.ts +15 -0
  24. package/dist/index-dfrzw-lI.d.cts +15 -0
  25. package/dist/index.cjs +823 -542
  26. package/dist/index.d.cts +6 -15
  27. package/dist/index.d.ts +6 -15
  28. package/dist/index.js +817 -543
  29. package/dist/integrations/formik.d.cts +1 -1
  30. package/dist/integrations/formik.d.ts +1 -1
  31. package/dist/integrations/react-hook-form.d.cts +1 -1
  32. package/dist/integrations/react-hook-form.d.ts +1 -1
  33. package/dist/overlay.cjs +13 -8
  34. package/dist/overlay.js +13 -8
  35. package/dist/preact.d.cts +2 -1
  36. package/dist/preact.d.ts +2 -1
  37. package/dist/qwik-lib/index.qwik.cjs +4267 -0
  38. package/dist/qwik-lib/index.qwik.mjs +4267 -0
  39. package/dist/qwik.cjs +816 -542
  40. package/dist/qwik.d.cts +2 -2
  41. package/dist/qwik.d.ts +2 -2
  42. package/dist/qwik.js +816 -542
  43. package/dist/react.cjs +816 -542
  44. package/dist/react.d.cts +3 -2
  45. package/dist/react.d.ts +3 -2
  46. package/dist/react.js +816 -542
  47. package/dist/solid.cjs +816 -542
  48. package/dist/solid.d.cts +64 -4
  49. package/dist/solid.d.ts +64 -4
  50. package/dist/solid.js +816 -542
  51. package/dist/solid.source.jsx +816 -542
  52. package/dist/svelte-core.cjs +816 -542
  53. package/dist/svelte-core.js +816 -542
  54. package/dist/svelte.cjs +816 -542
  55. package/dist/svelte.js +816 -542
  56. package/dist/vue.cjs +927 -645
  57. package/dist/vue.js +927 -645
  58. package/package.json +63 -11
package/dist/element.cjs CHANGED
@@ -402,82 +402,6 @@ var init_snap_resolver = __esm({
402
402
  }
403
403
  });
404
404
 
405
- // src/core/features/persist.ts
406
- function readPersistedId(key) {
407
- if (!key) return null;
408
- if (typeof window === "undefined") return null;
409
- if (typeof localStorage === "undefined") return null;
410
- try {
411
- return localStorage.getItem(key);
412
- } catch {
413
- return null;
414
- }
415
- }
416
- function installPersist(engine, key) {
417
- const unsubscribe = engine.on("snap", ({ id }) => {
418
- if (typeof window === "undefined") return;
419
- if (typeof localStorage === "undefined") return;
420
- try {
421
- localStorage.setItem(key, id);
422
- } catch {
423
- }
424
- });
425
- return unsubscribe;
426
- }
427
- var init_persist = __esm({
428
- "src/core/features/persist.ts"() {
429
- }
430
- });
431
-
432
- // src/core/features/auto-collapse.ts
433
- function installAutoCollapse(deps) {
434
- const { ms } = deps;
435
- if (ms === void 0 || ms <= 0) {
436
- return () => {
437
- };
438
- }
439
- let timer = null;
440
- const clearTimer = () => {
441
- if (timer !== null) {
442
- clearTimeout(timer);
443
- timer = null;
444
- }
445
- };
446
- const fire = () => {
447
- if (deps.isDestroyed()) return;
448
- if (deps.isDragging()) return;
449
- const active = deps.resolveSnap(deps.getActiveId());
450
- if (!active || active.size === 0) return;
451
- let target = null;
452
- for (const id of deps.getAllowedIds()) {
453
- const snap = deps.resolveSnap(id);
454
- if (!snap || snap.size <= 0) continue;
455
- if (!target || snap.size < target.size) target = snap;
456
- }
457
- if (!target) return;
458
- if (target.id === active.id || target.size >= active.size) return;
459
- deps.snapTo(target.id);
460
- };
461
- const reset = () => {
462
- clearTimer();
463
- if (deps.isDestroyed()) return;
464
- timer = setTimeout(() => {
465
- timer = null;
466
- fire();
467
- }, ms);
468
- };
469
- const unsubscribe = deps.on("snap", () => reset());
470
- if ((deps.resolveSnap(deps.getActiveId())?.size ?? 0) > 0) reset();
471
- return () => {
472
- clearTimer();
473
- unsubscribe();
474
- };
475
- }
476
- var init_auto_collapse = __esm({
477
- "src/core/features/auto-collapse.ts"() {
478
- }
479
- });
480
-
481
405
  // src/core/features/linked-sheets.ts
482
406
  function notifyLinkedSheets(sheets, self) {
483
407
  if (sheets.length === 0) return;
@@ -504,539 +428,194 @@ var init_linked_sheets = __esm({
504
428
  }
505
429
  });
506
430
 
507
- // src/core/features/history-coordinator.ts
508
- function onPopState() {
509
- if (suppress > 0) {
510
- suppress -= 1;
511
- const rebrand = pendingRebrand;
512
- pendingRebrand = null;
513
- if (rebrand) rebrand();
514
- maybeTeardownListener();
515
- return;
516
- }
517
- if (entries.length === 0) {
518
- notifyRouteChange();
519
- maybeTeardownListener();
520
- return;
431
+ // src/core/features/resize-observer.ts
432
+ function installResizeObserver(deps) {
433
+ if (typeof window === "undefined") {
434
+ return () => {
435
+ };
521
436
  }
522
- let target = null;
523
- let targetIdx = -1;
524
- for (let i = entries.length - 1; i >= 0; i -= 1) {
525
- const entry = entries[i];
526
- if (!entry.surface.isOpen()) continue;
527
- if (!target) {
528
- target = entry;
529
- targetIdx = i;
530
- }
531
- if (entry.surface.isTop()) {
532
- target = entry;
533
- targetIdx = i;
534
- break;
437
+ const onResize = () => {
438
+ if (deps.isDestroyed()) return;
439
+ deps.recomputeSnaps();
440
+ const mode = deps.getMode();
441
+ const isVerticalAxis = mode === "bottom" || mode === "top";
442
+ const viewportSize2 = isVerticalAxis ? window.innerHeight : window.innerWidth;
443
+ const max = deps.getMaxAxisSize();
444
+ if (viewportSize2 > 0 && viewportSize2 < max) {
445
+ deps.setMaxAxisSize(viewportSize2);
535
446
  }
536
- }
537
- if (!target) {
538
- const removed = entries.pop();
539
- if (removed) removed.live = false;
540
- maybeTeardownListener();
541
- return;
542
- }
543
- target.live = false;
544
- entries.splice(targetIdx, 1);
545
- const settled = target;
546
- void Promise.resolve(settled.surface.close()).then(() => {
547
- if (settled.surface.isOpen()) restore(settled);
548
- });
549
- maybeTeardownListener();
550
- }
551
- function restore(entry) {
552
- if (!hasWindow() || !hasHistory()) return;
553
- entry.live = true;
554
- runInternal(() => {
555
- try {
556
- history.pushState(entry.surface.markerState(), "", entry.surface.url);
557
- } catch {
558
- entry.live = false;
447
+ const wasAnimating = deps.isAnimating?.() ?? false;
448
+ deps.cancelInFlight();
449
+ deps.newCycle();
450
+ const current = deps.resolveActiveSnap();
451
+ const newMax = deps.getMaxAxisSize();
452
+ const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
453
+ deps.setSize(targetSize);
454
+ if (current && !deps.isDragging()) {
455
+ deps.applySize(targetSize);
456
+ if (wasAnimating) deps.resyncAfterCancel?.();
559
457
  }
560
- });
561
- if (entry.live) {
562
- entries.push(entry);
563
- ensureListener();
458
+ };
459
+ let resizeObserver = null;
460
+ if (typeof ResizeObserver !== "undefined") {
461
+ resizeObserver = new ResizeObserver(onResize);
462
+ resizeObserver.observe(document.documentElement);
463
+ } else {
464
+ window.addEventListener("resize", onResize);
564
465
  }
466
+ window.addEventListener("orientationchange", onResize);
467
+ const onVisibility = () => {
468
+ if (deps.isDestroyed()) return;
469
+ if (document.hidden) deps.cancelInFlight();
470
+ };
471
+ document.addEventListener("visibilitychange", onVisibility);
472
+ return () => {
473
+ resizeObserver?.disconnect();
474
+ window.removeEventListener("resize", onResize);
475
+ window.removeEventListener("orientationchange", onResize);
476
+ document.removeEventListener("visibilitychange", onVisibility);
477
+ };
565
478
  }
566
- function pushBackMarker(surface) {
567
- const entry = { surface, priorUrl: void 0, live: false };
568
- if (!hasWindow() || !hasHistory()) {
569
- return entry;
479
+ var init_resize_observer = __esm({
480
+ "src/core/features/resize-observer.ts"() {
570
481
  }
571
- entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
572
- runInternal(() => {
573
- try {
574
- history.pushState(surface.markerState(), "", surface.url);
575
- entry.live = true;
576
- } catch {
577
- entry.live = false;
482
+ });
483
+
484
+ // src/core/features/fit-observer.ts
485
+ function installFitObserver(deps) {
486
+ if (typeof ResizeObserver === "undefined") return () => {
487
+ };
488
+ if (!deps.hasFitSnap()) return () => {
489
+ };
490
+ let raf = 0;
491
+ const schedule = () => {
492
+ if (raf) return;
493
+ raf = requestAnimationFrame(() => {
494
+ raf = 0;
495
+ if (deps.isDestroyed() || deps.isDragging()) return;
496
+ deps.recompute();
497
+ });
498
+ };
499
+ const ro = new ResizeObserver(schedule);
500
+ ro.observe(deps.handle);
501
+ const scroller = deps.scrollContainer;
502
+ const observed = /* @__PURE__ */ new Set();
503
+ const slots = /* @__PURE__ */ new Set();
504
+ const hasSlot = typeof HTMLSlotElement !== "undefined";
505
+ const onSlotChange = () => resync();
506
+ const trackSlots = () => {
507
+ if (!scroller || !hasSlot) return;
508
+ for (const child of Array.from(scroller.children)) {
509
+ if (child instanceof HTMLSlotElement && !slots.has(child)) {
510
+ child.addEventListener("slotchange", onSlotChange);
511
+ slots.add(child);
512
+ }
513
+ }
514
+ };
515
+ const resync = () => {
516
+ trackSlots();
517
+ const targets = contentTargets(scroller);
518
+ for (const el of observed) {
519
+ if (!targets.includes(el)) {
520
+ ro.unobserve(el);
521
+ observed.delete(el);
522
+ }
523
+ }
524
+ for (const el of targets) {
525
+ if (!observed.has(el)) {
526
+ ro.observe(el);
527
+ observed.add(el);
528
+ }
529
+ }
530
+ schedule();
531
+ };
532
+ let mo;
533
+ if (scroller) {
534
+ resync();
535
+ if (typeof MutationObserver !== "undefined") {
536
+ mo = new MutationObserver(resync);
537
+ mo.observe(scroller, { childList: true });
578
538
  }
579
- });
580
- if (entry.live) {
581
- entries.push(entry);
582
- ensureListener();
583
539
  }
584
- return entry;
540
+ return () => {
541
+ ro.disconnect();
542
+ mo?.disconnect();
543
+ for (const slot of slots) {
544
+ slot.removeEventListener("slotchange", onSlotChange);
545
+ }
546
+ if (raf) cancelAnimationFrame(raf);
547
+ };
585
548
  }
586
- function popBackMarker(handle) {
587
- if (!hasWindow() || !hasHistory()) return;
588
- const entry = handle;
589
- const idx = entries.indexOf(entry);
590
- if (idx === -1 || !entry.live) return;
591
- const last = entries.length - 1;
592
- entry.live = false;
593
- entries.splice(idx, 1);
594
- if (idx !== last) {
595
- const rebrandSurface = entries[entries.length - 1].surface;
596
- const rebrandUrl = entry.priorUrl;
597
- pendingRebrand = () => {
598
- runInternal(() => {
599
- history.replaceState(
600
- rebrandSurface.markerState(),
601
- "",
602
- rebrandUrl !== void 0 ? rebrandUrl : location.href
603
- );
604
- });
605
- };
606
- }
607
- suppress += 1;
608
- runInternal(() => {
609
- try {
610
- history.back();
611
- } catch {
612
- suppress = Math.max(0, suppress - 1);
613
- pendingRebrand = null;
614
- }
615
- });
616
- maybeTeardownListener();
617
- }
618
- function subscribeRouteChange(fn) {
619
- if (!hasWindow() || !hasHistory()) return () => {
620
- };
621
- subscribers.add(fn);
622
- if (subscribers.size === 1) installPatch();
623
- ensureListener();
624
- return () => {
625
- if (!subscribers.has(fn)) return;
626
- subscribers.delete(fn);
627
- if (subscribers.size === 0) removePatch();
628
- maybeTeardownListener();
629
- };
630
- }
631
- var entries, subscribers, suppress, internalDepth, pendingRebrand, listenerInstalled, patchInstalled, origPushState, origReplaceState, patchedPushState, patchedReplaceState, hasWindow, hasHistory, runInternal, notifyRouteChange, ensureListener, maybeTeardownListener, installPatch, removePatch;
632
- var init_history_coordinator = __esm({
633
- "src/core/features/history-coordinator.ts"() {
634
- entries = [];
635
- subscribers = /* @__PURE__ */ new Set();
636
- suppress = 0;
637
- internalDepth = 0;
638
- pendingRebrand = null;
639
- listenerInstalled = false;
640
- patchInstalled = false;
641
- origPushState = null;
642
- origReplaceState = null;
643
- patchedPushState = null;
644
- patchedReplaceState = null;
645
- hasWindow = () => typeof window !== "undefined";
646
- hasHistory = () => typeof history !== "undefined";
647
- runInternal = (fn) => {
648
- internalDepth += 1;
649
- try {
650
- fn();
651
- } finally {
652
- internalDepth -= 1;
653
- }
654
- };
655
- notifyRouteChange = () => {
656
- const snapshot = Array.from(subscribers);
657
- for (const fn of snapshot) fn();
658
- };
659
- ensureListener = () => {
660
- if (listenerInstalled || !hasWindow()) return;
661
- window.addEventListener("popstate", onPopState);
662
- listenerInstalled = true;
663
- };
664
- maybeTeardownListener = () => {
665
- if (!listenerInstalled) return;
666
- if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
667
- if (hasWindow()) window.removeEventListener("popstate", onPopState);
668
- listenerInstalled = false;
669
- };
670
- installPatch = () => {
671
- if (patchInstalled || !hasHistory()) return;
672
- origPushState = history.pushState;
673
- origReplaceState = history.replaceState;
674
- patchedPushState = function(...args) {
675
- origPushState.apply(this, args);
676
- if (internalDepth === 0) notifyRouteChange();
677
- };
678
- patchedReplaceState = function(...args) {
679
- origReplaceState.apply(this, args);
680
- if (internalDepth === 0) notifyRouteChange();
681
- };
682
- history.pushState = patchedPushState;
683
- history.replaceState = patchedReplaceState;
684
- patchInstalled = true;
685
- };
686
- removePatch = () => {
687
- if (!patchInstalled) return;
688
- if (history.pushState === patchedPushState && origPushState) {
689
- history.pushState = origPushState;
690
- }
691
- if (history.replaceState === patchedReplaceState && origReplaceState) {
692
- history.replaceState = origReplaceState;
549
+ var contentTargets;
550
+ var init_fit_observer = __esm({
551
+ "src/core/features/fit-observer.ts"() {
552
+ contentTargets = (scroller) => {
553
+ if (!scroller) return [];
554
+ const hasSlot = typeof HTMLSlotElement !== "undefined";
555
+ const out = [];
556
+ for (const child of Array.from(scroller.children)) {
557
+ if (hasSlot && child instanceof HTMLSlotElement) {
558
+ for (const el of child.assignedElements()) out.push(el);
559
+ } else {
560
+ out.push(child);
561
+ }
693
562
  }
694
- origPushState = null;
695
- origReplaceState = null;
696
- patchedPushState = null;
697
- patchedReplaceState = null;
698
- patchInstalled = false;
563
+ return out;
699
564
  };
700
565
  }
701
566
  });
702
567
 
703
- // src/core/features/route.ts
704
- function installRoute(deps) {
705
- if (typeof window === "undefined") {
706
- return () => {
707
- };
708
- }
709
- if (!deps.routedTo && !deps.closeOnBack) {
710
- return () => {
711
- };
712
- }
713
- let handle = null;
714
- const onOpen = () => {
715
- if (handle) return;
716
- handle = pushBackMarker({
717
- isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
718
- isTop: deps.isTopSheet,
719
- close: deps.close,
720
- markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
721
- url: deps.routedTo
722
- });
723
- };
724
- const onClose = () => {
725
- if (!handle) return;
726
- popBackMarker(handle);
727
- handle = null;
728
- };
729
- const unsubscribeOpen = deps.on("open", onOpen);
730
- const unsubscribeClose = deps.on("close", onClose);
731
- if (deps.getSize() > 0) onOpen();
732
- return () => {
733
- unsubscribeOpen();
734
- unsubscribeClose();
735
- if (handle) {
736
- popBackMarker(handle);
737
- handle = null;
568
+ // src/core/features/max-height-controller.ts
569
+ function createMaxHeightController(deps) {
570
+ let maxHeightCap;
571
+ let maxHeightRaw;
572
+ const resolveCap = () => {
573
+ const raw = maxHeightRaw;
574
+ if (raw === void 0) {
575
+ maxHeightCap = void 0;
576
+ return;
738
577
  }
578
+ if (typeof raw === "number") {
579
+ maxHeightCap = raw;
580
+ return;
581
+ }
582
+ if (typeof window === "undefined") return;
583
+ const measured = resolveSnap(raw, deps.mode);
584
+ maxHeightCap = measured > 0 ? measured : void 0;
739
585
  };
740
- }
741
- function installRouteChange(deps) {
742
- return subscribeRouteChange(() => {
743
- if (deps.isDestroyed() || deps.getSize() <= 0) return;
744
- void deps.close();
745
- });
746
- }
747
- var init_route = __esm({
748
- "src/core/features/route.ts"() {
749
- init_history_coordinator();
750
- }
751
- });
752
-
753
- // src/core/features/content-swipe.ts
754
- function installContentSwipe(deps) {
755
- const { container } = deps;
756
- let startY = 0;
757
- let startScrollTop = 0;
758
- let moved = false;
759
- const onTouchStart = (e) => {
760
- const t = e.touches[0];
761
- if (!t) return;
762
- startY = t.clientY;
763
- startScrollTop = container.scrollTop;
764
- moved = false;
765
- };
766
- const onTouchMove = (e) => {
767
- const t = e.touches[0];
768
- if (!t) return;
769
- if (Math.abs(t.clientY - startY) > CONTENT_PULL_THRESHOLD) moved = true;
770
- };
771
- const onTouchEnd = (e) => {
772
- if (!moved) return;
773
- if (deps.isDragging() || deps.isAnimating()) return;
774
- if (container.scrollTop !== startScrollTop) return;
775
- const t = e.changedTouches[0];
776
- if (!t) return;
777
- const deltaY = t.clientY - startY;
778
- const atTop = container.scrollTop <= 0;
779
- const allowed = deps.getAllowedIds();
780
- const idx = allowed.indexOf(deps.getActiveId());
781
- if (idx === -1) return;
782
- if (atTop && deltaY > CONTENT_PULL_THRESHOLD && idx > 0) {
783
- deps.snapTo(allowed[idx - 1]);
784
- } else if (deltaY < -CONTENT_PULL_THRESHOLD && idx < allowed.length - 1) {
785
- deps.snapTo(allowed[idx + 1]);
586
+ const clampTo = () => {
587
+ if (maxHeightCap === void 0) return;
588
+ if (deps.getMaxAxisSize() > maxHeightCap) {
589
+ deps.setMaxAxisSize(maxHeightCap);
786
590
  }
787
591
  };
788
- container.addEventListener("touchstart", onTouchStart, { passive: true });
789
- container.addEventListener("touchmove", onTouchMove, { passive: true });
790
- container.addEventListener("touchend", onTouchEnd, { passive: true });
791
- return () => {
792
- container.removeEventListener("touchstart", onTouchStart);
793
- container.removeEventListener("touchmove", onTouchMove);
794
- container.removeEventListener("touchend", onTouchEnd);
592
+ return {
593
+ setRadius(r) {
594
+ deps.element.style.setProperty(
595
+ "--bs-radius",
596
+ typeof r === "number" ? `${r}px` : r
597
+ );
598
+ },
599
+ setMaxHeight(h) {
600
+ const value = typeof h === "number" ? `${h}px` : h;
601
+ const axis = layoutAxis(deps.mode);
602
+ deps.element.style.setProperty(
603
+ axis === "height" ? "max-height" : "max-width",
604
+ value
605
+ );
606
+ maxHeightRaw = h;
607
+ resolveCap();
608
+ deps.recompute();
609
+ },
610
+ resolveCap,
611
+ clampTo,
612
+ getCap: () => maxHeightCap
795
613
  };
796
614
  }
797
- var CONTENT_PULL_THRESHOLD;
798
- var init_content_swipe = __esm({
799
- "src/core/features/content-swipe.ts"() {
800
- CONTENT_PULL_THRESHOLD = 60;
801
- }
802
- });
803
-
804
- // src/core/features/visual-viewport.ts
805
- function installVisualViewport(deps) {
806
- if (typeof window === "undefined" || !window.visualViewport) {
807
- return () => {
808
- };
809
- }
810
- const vv = window.visualViewport;
811
- let rafId = null;
812
- const onResize = () => {
813
- if (rafId !== null) return;
814
- rafId = requestAnimationFrame(() => {
815
- rafId = null;
816
- if (deps.isDestroyed()) return;
817
- deps.recomputeSnaps();
818
- const isVertical = deps.isVerticalAxis();
819
- const visible = isVertical ? vv.height : vv.width;
820
- const windowSize = isVertical ? window.innerHeight : window.innerWidth;
821
- const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
822
- if (clamp < deps.getMaxAxisSize()) {
823
- deps.setMaxAxisSize(clamp);
824
- }
825
- const wasAnimating = deps.isAnimating?.() ?? false;
826
- deps.cancelInFlight();
827
- deps.newCycle();
828
- const max = deps.getMaxAxisSize();
829
- deps.setSize(Math.min(deps.getSize(), max));
830
- const current = deps.resolveActiveSnap();
831
- if (current && !deps.isDragging()) {
832
- deps.applySize(Math.min(current.size, max));
833
- if (wasAnimating) deps.resyncAfterCancel?.();
834
- } else {
835
- deps.applySize(deps.getSize());
836
- }
837
- });
838
- };
839
- vv.addEventListener("resize", onResize);
840
- return () => {
841
- vv.removeEventListener("resize", onResize);
842
- if (rafId !== null) cancelAnimationFrame(rafId);
843
- };
844
- }
845
- var SAFETY_PAD;
846
- var init_visual_viewport = __esm({
847
- "src/core/features/visual-viewport.ts"() {
848
- SAFETY_PAD = 8;
849
- }
850
- });
851
-
852
- // src/core/features/resize-observer.ts
853
- function installResizeObserver(deps) {
854
- if (typeof window === "undefined") {
855
- return () => {
856
- };
857
- }
858
- const onResize = () => {
859
- if (deps.isDestroyed()) return;
860
- deps.recomputeSnaps();
861
- const mode = deps.getMode();
862
- const isVerticalAxis = mode === "bottom" || mode === "top";
863
- const viewportSize2 = isVerticalAxis ? window.innerHeight : window.innerWidth;
864
- const max = deps.getMaxAxisSize();
865
- if (viewportSize2 > 0 && viewportSize2 < max) {
866
- deps.setMaxAxisSize(viewportSize2);
867
- }
868
- const wasAnimating = deps.isAnimating?.() ?? false;
869
- deps.cancelInFlight();
870
- deps.newCycle();
871
- const current = deps.resolveActiveSnap();
872
- const newMax = deps.getMaxAxisSize();
873
- const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
874
- deps.setSize(targetSize);
875
- if (current && !deps.isDragging()) {
876
- deps.applySize(targetSize);
877
- if (wasAnimating) deps.resyncAfterCancel?.();
878
- }
879
- };
880
- let resizeObserver = null;
881
- if (typeof ResizeObserver !== "undefined") {
882
- resizeObserver = new ResizeObserver(onResize);
883
- resizeObserver.observe(document.documentElement);
884
- } else {
885
- window.addEventListener("resize", onResize);
886
- }
887
- window.addEventListener("orientationchange", onResize);
888
- const onVisibility = () => {
889
- if (deps.isDestroyed()) return;
890
- if (document.hidden) deps.cancelInFlight();
891
- };
892
- document.addEventListener("visibilitychange", onVisibility);
893
- return () => {
894
- resizeObserver?.disconnect();
895
- window.removeEventListener("resize", onResize);
896
- window.removeEventListener("orientationchange", onResize);
897
- document.removeEventListener("visibilitychange", onVisibility);
898
- };
899
- }
900
- var init_resize_observer = __esm({
901
- "src/core/features/resize-observer.ts"() {
902
- }
903
- });
904
-
905
- // src/core/features/fit-observer.ts
906
- function installFitObserver(deps) {
907
- if (typeof ResizeObserver === "undefined") return () => {
908
- };
909
- if (!deps.hasFitSnap()) return () => {
910
- };
911
- let raf = 0;
912
- const schedule = () => {
913
- if (raf) return;
914
- raf = requestAnimationFrame(() => {
915
- raf = 0;
916
- if (deps.isDestroyed() || deps.isDragging()) return;
917
- deps.recompute();
918
- });
919
- };
920
- const ro = new ResizeObserver(schedule);
921
- ro.observe(deps.handle);
922
- const scroller = deps.scrollContainer;
923
- const observed = /* @__PURE__ */ new Set();
924
- const slots = /* @__PURE__ */ new Set();
925
- const hasSlot = typeof HTMLSlotElement !== "undefined";
926
- const onSlotChange = () => resync();
927
- const trackSlots = () => {
928
- if (!scroller || !hasSlot) return;
929
- for (const child of Array.from(scroller.children)) {
930
- if (child instanceof HTMLSlotElement && !slots.has(child)) {
931
- child.addEventListener("slotchange", onSlotChange);
932
- slots.add(child);
933
- }
934
- }
935
- };
936
- const resync = () => {
937
- trackSlots();
938
- const targets = contentTargets(scroller);
939
- for (const el of observed) {
940
- if (!targets.includes(el)) {
941
- ro.unobserve(el);
942
- observed.delete(el);
943
- }
944
- }
945
- for (const el of targets) {
946
- if (!observed.has(el)) {
947
- ro.observe(el);
948
- observed.add(el);
949
- }
950
- }
951
- schedule();
952
- };
953
- let mo;
954
- if (scroller) {
955
- resync();
956
- if (typeof MutationObserver !== "undefined") {
957
- mo = new MutationObserver(resync);
958
- mo.observe(scroller, { childList: true });
959
- }
960
- }
961
- return () => {
962
- ro.disconnect();
963
- mo?.disconnect();
964
- for (const slot of slots) {
965
- slot.removeEventListener("slotchange", onSlotChange);
966
- }
967
- if (raf) cancelAnimationFrame(raf);
968
- };
969
- }
970
- var contentTargets;
971
- var init_fit_observer = __esm({
972
- "src/core/features/fit-observer.ts"() {
973
- contentTargets = (scroller) => {
974
- if (!scroller) return [];
975
- const hasSlot = typeof HTMLSlotElement !== "undefined";
976
- const out = [];
977
- for (const child of Array.from(scroller.children)) {
978
- if (hasSlot && child instanceof HTMLSlotElement) {
979
- for (const el of child.assignedElements()) out.push(el);
980
- } else {
981
- out.push(child);
982
- }
983
- }
984
- return out;
985
- };
986
- }
987
- });
988
-
989
- // src/core/features/max-height-controller.ts
990
- function createMaxHeightController(deps) {
991
- let maxHeightCap;
992
- let maxHeightRaw;
993
- const resolveCap = () => {
994
- const raw = maxHeightRaw;
995
- if (raw === void 0) {
996
- maxHeightCap = void 0;
997
- return;
998
- }
999
- if (typeof raw === "number") {
1000
- maxHeightCap = raw;
1001
- return;
1002
- }
1003
- if (typeof window === "undefined") return;
1004
- const measured = resolveSnap(raw, deps.mode);
1005
- maxHeightCap = measured > 0 ? measured : void 0;
1006
- };
1007
- const clampTo = () => {
1008
- if (maxHeightCap === void 0) return;
1009
- if (deps.getMaxAxisSize() > maxHeightCap) {
1010
- deps.setMaxAxisSize(maxHeightCap);
1011
- }
1012
- };
1013
- return {
1014
- setRadius(r) {
1015
- deps.element.style.setProperty(
1016
- "--bs-radius",
1017
- typeof r === "number" ? `${r}px` : r
1018
- );
1019
- },
1020
- setMaxHeight(h) {
1021
- const value = typeof h === "number" ? `${h}px` : h;
1022
- const axis = layoutAxis(deps.mode);
1023
- deps.element.style.setProperty(
1024
- axis === "height" ? "max-height" : "max-width",
1025
- value
1026
- );
1027
- maxHeightRaw = h;
1028
- resolveCap();
1029
- deps.recompute();
1030
- },
1031
- resolveCap,
1032
- clampTo,
1033
- getCap: () => maxHeightCap
1034
- };
1035
- }
1036
- var init_max_height_controller = __esm({
1037
- "src/core/features/max-height-controller.ts"() {
1038
- init_snap_points();
1039
- init_transform();
615
+ var init_max_height_controller = __esm({
616
+ "src/core/features/max-height-controller.ts"() {
617
+ init_snap_points();
618
+ init_transform();
1040
619
  }
1041
620
  });
1042
621
 
@@ -1046,11 +625,15 @@ var init_fit_measurement = __esm({
1046
625
  "src/core/features/fit-measurement.ts"() {
1047
626
  init_transform();
1048
627
  measureSheetNatural = (element, content, vertical) => {
1049
- if (!content) {
1050
- return vertical ? element.offsetHeight : element.offsetWidth;
1051
- }
1052
628
  const axis = vertical ? "height" : "width";
1053
629
  const sheetStyle = element.style;
630
+ if (!content) {
631
+ const prev = sheetStyle[axis];
632
+ sheetStyle[axis] = "auto";
633
+ const poked2 = vertical ? element.offsetHeight : element.offsetWidth;
634
+ sheetStyle[axis] = prev;
635
+ return poked2;
636
+ }
1054
637
  const cs = content.style;
1055
638
  const prevSheet = sheetStyle[axis];
1056
639
  const prevFlex = cs.flex;
@@ -1816,6 +1399,58 @@ var init_animation_presets = __esm({
1816
1399
  }
1817
1400
  });
1818
1401
 
1402
+ // src/core/animation/waapi-settle.ts
1403
+ function sampleSpringSettle(from, to, velocityPxPerS, config) {
1404
+ const cfg = { ...DEFAULT_SPRING, ...config };
1405
+ const subDt = 1 / SIM_HZ;
1406
+ const stepMs = SAMPLE_STRIDE / SIM_HZ * 1e3;
1407
+ const maxSteps = Math.ceil(MAX_SIM_MS / 1e3 * SIM_HZ);
1408
+ const values = [from];
1409
+ let x = from;
1410
+ let v = velocityPxPerS;
1411
+ for (let i = 1; i <= maxSteps; i += 1) {
1412
+ const force = -cfg.stiffness * (x - to) - cfg.damping * v;
1413
+ v += force / cfg.mass * subDt;
1414
+ x += v * subDt;
1415
+ if (!Number.isFinite(x) || !Number.isFinite(v)) {
1416
+ values.push(to);
1417
+ break;
1418
+ }
1419
+ if (i % SAMPLE_STRIDE === 0) values.push(x);
1420
+ const atRest = Math.abs(to - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
1421
+ if (atRest) break;
1422
+ }
1423
+ if (values[values.length - 1] !== to) values.push(to);
1424
+ return {
1425
+ values,
1426
+ stepMs,
1427
+ durationMs: (values.length - 1) * stepMs
1428
+ };
1429
+ }
1430
+ function sampleTweenSettle(from, to, durationMs, easing) {
1431
+ const count = Math.max(2, Math.min(60, Math.round(durationMs / 16)));
1432
+ const values = [];
1433
+ for (let i = 0; i <= count; i += 1) {
1434
+ const t = i / count;
1435
+ values.push(from + (to - from) * easing(t));
1436
+ }
1437
+ values[values.length - 1] = to;
1438
+ return {
1439
+ values,
1440
+ stepMs: durationMs / count,
1441
+ durationMs
1442
+ };
1443
+ }
1444
+ var SIM_HZ, SAMPLE_STRIDE, MAX_SIM_MS;
1445
+ var init_waapi_settle = __esm({
1446
+ "src/core/animation/waapi-settle.ts"() {
1447
+ init_spring();
1448
+ SIM_HZ = 240;
1449
+ SAMPLE_STRIDE = 4;
1450
+ MAX_SIM_MS = 3e3;
1451
+ }
1452
+ });
1453
+
1819
1454
  // src/core/controllers/animation-runner.ts
1820
1455
  var DEFAULT_DURATION2, VELOCITY_PX_PER_S, AnimationRunner;
1821
1456
  var init_animation_runner = __esm({
@@ -1823,6 +1458,7 @@ var init_animation_runner = __esm({
1823
1458
  init_animation();
1824
1459
  init_spring();
1825
1460
  init_animation_presets();
1461
+ init_waapi_settle();
1826
1462
  DEFAULT_DURATION2 = 220;
1827
1463
  VELOCITY_PX_PER_S = 1e3;
1828
1464
  AnimationRunner = class {
@@ -1832,6 +1468,10 @@ var init_animation_runner = __esm({
1832
1468
  __publicField(this, "applySizeFn");
1833
1469
  __publicField(this, "getSize");
1834
1470
  __publicField(this, "isDragging");
1471
+ __publicField(this, "applyAux");
1472
+ __publicField(this, "getTransformFor");
1473
+ __publicField(this, "settleWaapi");
1474
+ __publicField(this, "currentWaapi", null);
1835
1475
  __publicField(this, "animationKind");
1836
1476
  __publicField(this, "springConfig");
1837
1477
  __publicField(this, "duration");
@@ -1847,6 +1487,9 @@ var init_animation_runner = __esm({
1847
1487
  this.applySizeFn = deps.applySize;
1848
1488
  this.getSize = deps.getSize;
1849
1489
  this.isDragging = deps.isDragging;
1490
+ this.applyAux = deps.applyAux;
1491
+ this.getTransformFor = deps.getTransformFor;
1492
+ this.settleWaapi = opts.settleAnimation === "waapi";
1850
1493
  const preset = resolveAnimationPreset(opts.animation);
1851
1494
  this.animationKind = preset.kind;
1852
1495
  this.duration = opts.duration ?? preset.duration ?? DEFAULT_DURATION2;
@@ -1871,11 +1514,20 @@ var init_animation_runner = __esm({
1871
1514
  }
1872
1515
  }
1873
1516
  get isAnimating() {
1874
- return this.currentTween !== null || this.currentSpring !== null;
1517
+ return this.currentTween !== null || this.currentSpring !== null || this.currentWaapi !== null;
1875
1518
  }
1876
1519
  cancel() {
1877
1520
  this.currentTween?.cancel();
1878
1521
  this.currentSpring?.cancel();
1522
+ if (this.currentWaapi) {
1523
+ const entry = this.currentWaapi;
1524
+ this.currentWaapi = null;
1525
+ entry.stop();
1526
+ try {
1527
+ entry.anim.cancel();
1528
+ } catch {
1529
+ }
1530
+ }
1879
1531
  }
1880
1532
  async animateTo(target, velocityPxPerMs) {
1881
1533
  if (target === this.getSize()) {
@@ -1894,10 +1546,31 @@ var init_animation_runner = __esm({
1894
1546
  if (!this.isDragging()) this.element.style.willChange = "";
1895
1547
  return;
1896
1548
  }
1897
- if (this.animationKind === "spring") {
1898
- const spring = runSpring({
1899
- from: this.getSize(),
1900
- to: target,
1549
+ if (this.settleWaapi && this.applyAux && this.getTransformFor && typeof this.element.animate === "function") {
1550
+ const samples = this.animationKind === "spring" ? sampleSpringSettle(
1551
+ this.getSize(),
1552
+ target,
1553
+ velocityPxPerMs * VELOCITY_PX_PER_S,
1554
+ this.springConfig
1555
+ ) : sampleTweenSettle(
1556
+ this.getSize(),
1557
+ target,
1558
+ this.duration,
1559
+ this.easing
1560
+ );
1561
+ if (samples.values.length >= 2 && samples.durationMs > 0) {
1562
+ await this.runWaapiSettle(samples, target);
1563
+ if (!this.isAnimating) {
1564
+ this.getRootEl()?.removeAttribute("data-animating");
1565
+ if (!this.isDragging()) this.element.style.willChange = "";
1566
+ }
1567
+ return;
1568
+ }
1569
+ }
1570
+ if (this.animationKind === "spring") {
1571
+ const spring = runSpring({
1572
+ from: this.getSize(),
1573
+ to: target,
1901
1574
  velocity: velocityPxPerMs * VELOCITY_PX_PER_S,
1902
1575
  config: this.springConfig,
1903
1576
  onUpdate: (v) => this.applySizeFn(v)
@@ -1922,11 +1595,66 @@ var init_animation_runner = __esm({
1922
1595
  if (!this.isDragging()) this.element.style.willChange = "";
1923
1596
  }
1924
1597
  }
1598
+ async runWaapiSettle(samples, target) {
1599
+ const applyAux = this.applyAux;
1600
+ const getTransformFor = this.getTransformFor;
1601
+ const frames = samples.values.map((v) => ({
1602
+ transform: getTransformFor(v)
1603
+ }));
1604
+ const anim = this.element.animate(frames, {
1605
+ duration: samples.durationMs,
1606
+ easing: "linear",
1607
+ fill: "forwards"
1608
+ });
1609
+ let stopped = false;
1610
+ let auxRaf = 0;
1611
+ const start = performance.now();
1612
+ const lastIdx = samples.values.length - 1;
1613
+ const auxTick = () => {
1614
+ if (stopped) return;
1615
+ const elapsed = performance.now() - start;
1616
+ const idx = Math.min(Math.floor(elapsed / samples.stepMs), lastIdx);
1617
+ applyAux(samples.values[idx]);
1618
+ auxRaf = requestAnimationFrame(auxTick);
1619
+ };
1620
+ auxRaf = requestAnimationFrame(auxTick);
1621
+ const entry = {
1622
+ anim,
1623
+ stop: () => {
1624
+ stopped = true;
1625
+ cancelAnimationFrame(auxRaf);
1626
+ }
1627
+ };
1628
+ this.currentWaapi = entry;
1629
+ try {
1630
+ await anim.finished;
1631
+ } catch {
1632
+ }
1633
+ entry.stop();
1634
+ const wasCurrent = this.currentWaapi === entry;
1635
+ if (wasCurrent) this.currentWaapi = null;
1636
+ if (wasCurrent && anim.playState === "finished") {
1637
+ this.applySizeFn(target);
1638
+ try {
1639
+ anim.cancel();
1640
+ } catch {
1641
+ }
1642
+ }
1643
+ }
1925
1644
  destroy() {
1926
1645
  this.detachReducedMotion?.();
1927
1646
  this.detachReducedMotion = null;
1928
1647
  this.currentTween = null;
1929
1648
  this.currentSpring = null;
1649
+ if (this.currentWaapi) {
1650
+ const entry = this.currentWaapi;
1651
+ this.currentWaapi = null;
1652
+ entry.stop();
1653
+ try {
1654
+ entry.anim.cancel();
1655
+ } catch {
1656
+ }
1657
+ }
1930
1658
  }
1931
1659
  };
1932
1660
  }
@@ -2854,7 +2582,7 @@ function resolveEngineOptions(opts, extras) {
2854
2582
  const initialAllowed = opts.allowed ?? opts.snapPoints.map((p) => p.id);
2855
2583
  let initialId = opts.initial ?? initialAllowed[0] ?? opts.snapPoints[0]?.id ?? "default";
2856
2584
  if (opts.persistKey) {
2857
- const restored = readPersistedId(opts.persistKey);
2585
+ const restored = readPersistedIdSafe(opts.persistKey);
2858
2586
  if (restored && initialAllowed.includes(restored)) {
2859
2587
  initialId = restored;
2860
2588
  }
@@ -2885,6 +2613,7 @@ function resolveEngineOptions(opts, extras) {
2885
2613
  },
2886
2614
  animation: {
2887
2615
  animation: opts.animation,
2616
+ settleAnimation: opts.settleAnimation,
2888
2617
  duration: opts.duration,
2889
2618
  easing: opts.easing,
2890
2619
  spring: opts.spring,
@@ -2902,12 +2631,20 @@ function resolveEngineOptions(opts, extras) {
2902
2631
  }
2903
2632
  };
2904
2633
  }
2905
- var DEFAULT_FLICK_VELOCITY, DEFAULT_DRAG_THRESHOLD;
2634
+ var DEFAULT_FLICK_VELOCITY, DEFAULT_DRAG_THRESHOLD, readPersistedIdSafe;
2906
2635
  var init_engine_options = __esm({
2907
2636
  "src/core/primitives/engine-options.ts"() {
2908
- init_persist();
2909
2637
  DEFAULT_FLICK_VELOCITY = 0.65;
2910
2638
  DEFAULT_DRAG_THRESHOLD = 18;
2639
+ readPersistedIdSafe = (key) => {
2640
+ if (typeof window === "undefined") return null;
2641
+ if (typeof localStorage === "undefined") return null;
2642
+ try {
2643
+ return localStorage.getItem(key);
2644
+ } catch {
2645
+ return null;
2646
+ }
2647
+ };
2911
2648
  }
2912
2649
  });
2913
2650
 
@@ -2937,10 +2674,10 @@ var init_teardown_stack = __esm({
2937
2674
  }
2938
2675
  });
2939
2676
 
2940
- // src/core/BottomSheetEngine.ts
2941
- var HAPTIC_DURATION_MS, BottomSheetEngine;
2942
- var init_BottomSheetEngine = __esm({
2943
- "src/core/BottomSheetEngine.ts"() {
2677
+ // src/core/BottomSheetCore.ts
2678
+ var HAPTIC_DURATION_MS, BottomSheetCore;
2679
+ var init_BottomSheetCore = __esm({
2680
+ "src/core/BottomSheetCore.ts"() {
2944
2681
  init_sheetStack();
2945
2682
  init_transform();
2946
2683
  init_instance_id();
@@ -2949,12 +2686,7 @@ var init_BottomSheetEngine = __esm({
2949
2686
  init_cancelable_emit();
2950
2687
  init_devWarn();
2951
2688
  init_snap_resolver();
2952
- init_persist();
2953
- init_auto_collapse();
2954
2689
  init_linked_sheets();
2955
- init_route();
2956
- init_content_swipe();
2957
- init_visual_viewport();
2958
2690
  init_resize_observer();
2959
2691
  init_fit_observer();
2960
2692
  init_max_height_controller();
@@ -2973,7 +2705,7 @@ var init_BottomSheetEngine = __esm({
2973
2705
  init_teardown_stack();
2974
2706
  init_opacity_dedup();
2975
2707
  HAPTIC_DURATION_MS = 8;
2976
- BottomSheetEngine = class {
2708
+ BottomSheetCore = class {
2977
2709
  constructor(opts) {
2978
2710
  __publicField(this, "id", nextInstanceId("bs"));
2979
2711
  __publicField(this, "element");
@@ -3034,6 +2766,8 @@ var init_BottomSheetEngine = __esm({
3034
2766
  __publicField(this, "stackEffectPrimed", false);
3035
2767
  __publicField(this, "fitDeps");
3036
2768
  __publicField(this, "transformTemplate");
2769
+ __publicField(this, "featureList", []);
2770
+ __publicField(this, "featureCtx");
3037
2771
  const resolved = resolveEngineOptions(opts, {
3038
2772
  shouldApplyInertSiblings: () => {
3039
2773
  if (typeof document === "undefined") return false;
@@ -3080,7 +2814,9 @@ var init_BottomSheetEngine = __esm({
3080
2814
  getRootEl: () => this.rootEl,
3081
2815
  applySize: (size) => this.applySize(size),
3082
2816
  getSize: () => this.size,
3083
- isDragging: () => this.gesture?.isDragging ?? false
2817
+ isDragging: () => this.gesture?.isDragging ?? false,
2818
+ applyAux: (size) => this.applySize(size, true),
2819
+ getTransformFor: (size) => this.transformTemplate(this.snaps.getMaxAxisSize() - size)
3084
2820
  },
3085
2821
  resolved.animation
3086
2822
  );
@@ -3103,6 +2839,11 @@ var init_BottomSheetEngine = __esm({
3103
2839
  if (opts.linkedSheets) {
3104
2840
  this.linkedSheets = opts.linkedSheets;
3105
2841
  }
2842
+ const byName = /* @__PURE__ */ new Map();
2843
+ for (const feature of opts.features ?? []) {
2844
+ byName.set(feature.name, feature);
2845
+ }
2846
+ this.featureList = Array.from(byName.values());
3106
2847
  this.activeId = resolved.initialId;
3107
2848
  auditVhUsage(this.snapPointsRaw);
3108
2849
  this.auditDuplicateSnapIds(this.snapPointsRaw);
@@ -3139,6 +2880,7 @@ var init_BottomSheetEngine = __esm({
3139
2880
  scrollContainer: this.scrollContainer,
3140
2881
  getMaxAxisSize: () => this.snaps.getMaxAxisSize()
3141
2882
  });
2883
+ this.featureCtx = this.buildFeatureContext(opts.autoCollapseAfter);
3142
2884
  this.attach();
3143
2885
  this.registerInStack();
3144
2886
  if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
@@ -3147,12 +2889,7 @@ var init_BottomSheetEngine = __esm({
3147
2889
  if (!entry.isIntersecting) continue;
3148
2890
  if (this.destroyed) return;
3149
2891
  this.snaps.recompute();
3150
- const current = this.snaps.findById(this.activeId);
3151
- if (current) {
3152
- this.size = current.size;
3153
- this.applySize(this.size);
3154
- this.updateAriaSlider();
3155
- }
2892
+ this.healActiveSnap();
3156
2893
  io.disconnect();
3157
2894
  return;
3158
2895
  }
@@ -3175,46 +2912,77 @@ var init_BottomSheetEngine = __esm({
3175
2912
  if (resolved.radius !== void 0) this.setRadius(resolved.radius);
3176
2913
  if (resolved.maxHeight !== void 0) this.setMaxHeight(resolved.maxHeight);
3177
2914
  this.applyAutoAriaLabelledBy();
3178
- if (this.closeOnRouteChange) {
3179
- this.teardowns.add(
3180
- installRouteChange({
3181
- isDestroyed: () => this.destroyed,
3182
- getSize: () => this.size,
3183
- close: () => this.close()
3184
- })
3185
- );
3186
- }
3187
- if (this.persistKey) {
3188
- this.teardowns.add(installPersist(this, this.persistKey));
2915
+ this.runFeatureStage("post");
2916
+ this.warnOrphanFeatureOptions();
2917
+ if (this.size > 0) {
2918
+ this.handleOpen();
3189
2919
  }
3190
- this.teardowns.add(
3191
- installAutoCollapse({
3192
- ms: opts.autoCollapseAfter,
3193
- isDestroyed: () => this.destroyed,
3194
- isDragging: () => this.gesture?.isDragging ?? false,
3195
- getAllowedIds: () => this.snaps.getAllowedIds().slice(),
3196
- getActiveId: () => this.activeId,
3197
- resolveSnap: (id) => this.snaps.findById(id),
3198
- snapTo: (id) => {
3199
- void this.snapTo(id);
3200
- },
3201
- on: (event, fn) => this.on(event, fn)
3202
- })
3203
- );
3204
- this.teardowns.add(
3205
- installRoute({
2920
+ }
2921
+ buildFeatureContext(autoCollapseAfter) {
2922
+ return {
2923
+ element: this.element,
2924
+ scrollContainer: this.scrollContainer,
2925
+ sheetId: this.id,
2926
+ options: {
3206
2927
  routedTo: this.routedTo,
3207
2928
  closeOnBack: this.closeOnBack,
3208
- isTopSheet: () => this.isTopSheet,
3209
- getSize: () => this.size,
3210
- isDestroyed: () => this.destroyed,
3211
- close: () => this.close("back"),
3212
- on: (event, fn) => this.on(event, fn),
3213
- sheetId: this.id
3214
- })
3215
- );
3216
- if (this.size > 0) {
3217
- this.handleOpen();
2929
+ closeOnRouteChange: this.closeOnRouteChange,
2930
+ persistKey: this.persistKey,
2931
+ autoCollapseAfter
2932
+ },
2933
+ isDestroyed: () => this.destroyed,
2934
+ isDragging: () => this.gesture?.isDragging ?? false,
2935
+ isAnimating: () => this.animation.isAnimating,
2936
+ isTopSheet: () => this.isTopSheet,
2937
+ isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
2938
+ getSize: () => this.size,
2939
+ getActiveId: () => this.activeId,
2940
+ getAllowedIds: () => this.snaps.getAllowedIds().slice(),
2941
+ allowedIdsBySize: () => this.allowedIdsBySize(),
2942
+ getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
2943
+ resolveSnap: (id) => this.snaps.findById(id),
2944
+ resolveActiveSnap: () => this.snaps.findById(this.activeId),
2945
+ setSize: (size) => {
2946
+ this.size = size;
2947
+ },
2948
+ setMaxAxisSize: (size) => {
2949
+ this.snaps.setMaxAxisSize(size);
2950
+ },
2951
+ applySize: (size) => this.applySize(size),
2952
+ recomputeSnaps: () => this.recomputeSnaps(),
2953
+ newCycle: () => {
2954
+ this.newCycle();
2955
+ },
2956
+ cancelInFlight: () => {
2957
+ this.animation.cancel();
2958
+ },
2959
+ resyncAfterResize: () => this.resyncAfterResize(),
2960
+ snapTo: (id) => {
2961
+ void this.snapTo(id);
2962
+ },
2963
+ close: (reason) => this.close(reason),
2964
+ on: (event, fn) => this.on(event, fn),
2965
+ addTeardown: (fn) => this.teardowns.add(fn)
2966
+ };
2967
+ }
2968
+ runFeatureStage(stage) {
2969
+ for (const feature of this.featureList) {
2970
+ if ((feature.stage ?? "post") !== stage) continue;
2971
+ const teardown = feature.install(this.featureCtx);
2972
+ if (teardown) this.teardowns.add(teardown);
2973
+ }
2974
+ }
2975
+ warnOrphanFeatureOptions() {
2976
+ const names = new Set(this.featureList.map((f) => f.name));
2977
+ if ((this.closeOnBack || this.routedTo !== void 0 || this.closeOnRouteChange) && !names.has("route")) {
2978
+ devWarn(
2979
+ "[BottomSheet] closeOnBack/routedTo/closeOnRouteChange need routeFeature() \u2014 option ignored"
2980
+ );
2981
+ }
2982
+ if (this.persistKey && !names.has("persist")) {
2983
+ devWarn(
2984
+ "[BottomSheet] persistKey needs persistFeature() \u2014 snaps will not be saved"
2985
+ );
3218
2986
  }
3219
2987
  }
3220
2988
  get state() {
@@ -3316,6 +3084,8 @@ var init_BottomSheetEngine = __esm({
3316
3084
  const vt = document.startViewTransition(() => {
3317
3085
  this.applySize(target.size);
3318
3086
  });
3087
+ vt.ready?.catch(() => {
3088
+ });
3319
3089
  this.currentViewTransition = vt;
3320
3090
  try {
3321
3091
  await vt.finished;
@@ -3567,11 +3337,16 @@ var init_BottomSheetEngine = __esm({
3567
3337
  this.maxHeight.clampTo();
3568
3338
  this.scrim.invalidateOpacityCache();
3569
3339
  if (this.gesture?.isDragging) return;
3340
+ this.healActiveSnap();
3341
+ }
3342
+ healActiveSnap() {
3570
3343
  const current = this.snaps.findById(this.activeId);
3571
- if (current) {
3572
- this.size = current.size;
3573
- this.applySize(this.size);
3574
- this.updateAriaSlider();
3344
+ if (!current) return;
3345
+ this.size = current.size;
3346
+ this.applySize(this.size);
3347
+ this.updateAriaSlider();
3348
+ if (this.size > 0 && !this.lifecycle.isInstalled && !this.opening && !this.animation.isAnimating) {
3349
+ this.emitOpenSequence(this.activeId);
3575
3350
  }
3576
3351
  }
3577
3352
  destroy() {
@@ -3750,18 +3525,7 @@ var init_BottomSheetEngine = __esm({
3750
3525
  }
3751
3526
  }
3752
3527
  attachFeatures() {
3753
- if (this.scrollContainer) {
3754
- this.teardowns.add(installContentSwipe({
3755
- container: this.scrollContainer,
3756
- isDragging: () => this.gesture?.isDragging ?? false,
3757
- isAnimating: () => this.animation.isAnimating,
3758
- getAllowedIds: () => this.allowedIdsBySize(),
3759
- getActiveId: () => this.activeId,
3760
- snapTo: (id) => {
3761
- void this.snapTo(id);
3762
- }
3763
- }));
3764
- }
3528
+ this.runFeatureStage("attach");
3765
3529
  if (typeof window !== "undefined") {
3766
3530
  this.teardowns.add(installResizeObserver({
3767
3531
  element: this.element,
@@ -3801,31 +3565,6 @@ var init_BottomSheetEngine = __esm({
3801
3565
  () => document.removeEventListener("keydown", onKey)
3802
3566
  );
3803
3567
  }
3804
- this.teardowns.add(installVisualViewport({
3805
- element: this.element,
3806
- isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
3807
- isDestroyed: () => this.destroyed,
3808
- isDragging: () => this.gesture?.isDragging ?? false,
3809
- recomputeSnaps: () => this.recomputeSnaps(),
3810
- resolveActiveSnap: () => this.snaps.findById(this.activeId),
3811
- getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
3812
- getSize: () => this.size,
3813
- setMaxAxisSize: (size) => {
3814
- this.snaps.setMaxAxisSize(size);
3815
- },
3816
- setSize: (size) => {
3817
- this.size = size;
3818
- },
3819
- applySize: (size) => this.applySize(size),
3820
- cancelInFlight: () => {
3821
- this.animation.cancel();
3822
- },
3823
- newCycle: () => {
3824
- this.newCycle();
3825
- },
3826
- isAnimating: () => this.animation.isAnimating,
3827
- resyncAfterCancel: () => this.resyncAfterResize()
3828
- }));
3829
3568
  }
3830
3569
  this.teardowns.add(installSliderKeyboard({
3831
3570
  handle: this.handle,
@@ -3902,13 +3641,13 @@ var init_BottomSheetEngine = __esm({
3902
3641
  }
3903
3642
  }
3904
3643
  }
3905
- applySize(size) {
3644
+ applySize(size, skipTransform = false) {
3906
3645
  const cap = this.snaps.getMaxAxisSize();
3907
3646
  const clamped = cap > 0 && size > cap && !this.gesture?.isDragging && !this.allowOvershoot ? cap : size;
3908
3647
  this.size = clamped;
3909
3648
  const offset = cap - clamped;
3910
3649
  const style = this.element.style;
3911
- style.transform = this.transformTemplate(offset);
3650
+ if (!skipTransform) style.transform = this.transformTemplate(offset);
3912
3651
  if (this.sizeWriteSentinel.shouldWrite(clamped, SIZE_WRITE_EPSILON)) {
3913
3652
  style.setProperty("--bs-size", `${clamped}px`);
3914
3653
  if (this.scrimParent) {
@@ -3988,6 +3727,564 @@ var init_BottomSheetEngine = __esm({
3988
3727
  }
3989
3728
  });
3990
3729
 
3730
+ // src/core/features/history-coordinator.ts
3731
+ function onPopState() {
3732
+ if (suppress > 0) {
3733
+ suppress -= 1;
3734
+ const rebrand = pendingRebrands.shift();
3735
+ if (rebrand) rebrand();
3736
+ maybeTeardownListener();
3737
+ return;
3738
+ }
3739
+ if (entries.length === 0) {
3740
+ notifyRouteChange();
3741
+ maybeTeardownListener();
3742
+ return;
3743
+ }
3744
+ let target = null;
3745
+ let targetIdx = -1;
3746
+ for (let i = entries.length - 1; i >= 0; i -= 1) {
3747
+ const entry = entries[i];
3748
+ if (!entry.surface.isOpen()) continue;
3749
+ if (!target) {
3750
+ target = entry;
3751
+ targetIdx = i;
3752
+ }
3753
+ if (entry.surface.isTop()) {
3754
+ target = entry;
3755
+ targetIdx = i;
3756
+ break;
3757
+ }
3758
+ }
3759
+ if (!target) {
3760
+ const removed = entries.pop();
3761
+ if (removed) removed.live = false;
3762
+ maybeTeardownListener();
3763
+ return;
3764
+ }
3765
+ target.live = false;
3766
+ entries.splice(targetIdx, 1);
3767
+ const settled = target;
3768
+ void Promise.resolve(settled.surface.close()).then(() => {
3769
+ if (settled.surface.isOpen()) restore(settled);
3770
+ });
3771
+ maybeTeardownListener();
3772
+ }
3773
+ function restore(entry) {
3774
+ if (!hasWindow() || !hasHistory()) return;
3775
+ entry.live = true;
3776
+ runInternal(() => {
3777
+ try {
3778
+ history.pushState(brandMarker(entry.surface), "", entry.surface.url);
3779
+ } catch {
3780
+ entry.live = false;
3781
+ }
3782
+ });
3783
+ if (entry.live) {
3784
+ entries.push(entry);
3785
+ ensureListener();
3786
+ }
3787
+ }
3788
+ function pushBackMarker(surface) {
3789
+ const entry = { surface, priorUrl: void 0, live: false };
3790
+ if (!hasWindow() || !hasHistory()) {
3791
+ return entry;
3792
+ }
3793
+ entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
3794
+ runInternal(() => {
3795
+ try {
3796
+ history.pushState(brandMarker(surface), "", surface.url);
3797
+ entry.live = true;
3798
+ } catch {
3799
+ entry.live = false;
3800
+ }
3801
+ });
3802
+ if (entry.live) {
3803
+ entries.push(entry);
3804
+ ensureListener();
3805
+ }
3806
+ return entry;
3807
+ }
3808
+ function popBackMarker(handle) {
3809
+ if (!hasWindow() || !hasHistory()) return;
3810
+ const entry = handle;
3811
+ const idx = entries.indexOf(entry);
3812
+ if (idx === -1 || !entry.live) return;
3813
+ const last = entries.length - 1;
3814
+ entry.live = false;
3815
+ entries.splice(idx, 1);
3816
+ let rebrand = null;
3817
+ if (idx !== last) {
3818
+ const rebrandSurface = entries[entries.length - 1].surface;
3819
+ const rebrandUrl = entry.priorUrl;
3820
+ rebrand = () => {
3821
+ runInternal(() => {
3822
+ history.replaceState(
3823
+ brandMarker(rebrandSurface),
3824
+ "",
3825
+ rebrandUrl !== void 0 ? rebrandUrl : location.href
3826
+ );
3827
+ });
3828
+ };
3829
+ }
3830
+ pendingRebrands.push(rebrand);
3831
+ suppress += 1;
3832
+ runInternal(() => {
3833
+ try {
3834
+ history.back();
3835
+ } catch {
3836
+ suppress = Math.max(0, suppress - 1);
3837
+ pendingRebrands.pop();
3838
+ }
3839
+ });
3840
+ maybeTeardownListener();
3841
+ }
3842
+ function subscribeRouteChange(fn) {
3843
+ if (!hasWindow() || !hasHistory()) return () => {
3844
+ };
3845
+ subscribers.add(fn);
3846
+ if (subscribers.size === 1) installPatch();
3847
+ ensureListener();
3848
+ return () => {
3849
+ if (!subscribers.has(fn)) return;
3850
+ subscribers.delete(fn);
3851
+ if (subscribers.size === 0) removePatch();
3852
+ maybeTeardownListener();
3853
+ };
3854
+ }
3855
+ var entries, subscribers, suppress, internalDepth, pendingRebrands, listenerInstalled, patchInstalled, origPushState, origReplaceState, patchedPushState, patchedReplaceState, hasWindow, hasHistory, brandMarker, runInternal, notifyRouteChange, ensureListener, maybeTeardownListener, installPatch, removePatch;
3856
+ var init_history_coordinator = __esm({
3857
+ "src/core/features/history-coordinator.ts"() {
3858
+ entries = [];
3859
+ subscribers = /* @__PURE__ */ new Set();
3860
+ suppress = 0;
3861
+ internalDepth = 0;
3862
+ pendingRebrands = [];
3863
+ listenerInstalled = false;
3864
+ patchInstalled = false;
3865
+ origPushState = null;
3866
+ origReplaceState = null;
3867
+ patchedPushState = null;
3868
+ patchedReplaceState = null;
3869
+ hasWindow = () => typeof window !== "undefined";
3870
+ hasHistory = () => typeof history !== "undefined";
3871
+ brandMarker = (surface) => ({
3872
+ ...surface.markerState(),
3873
+ __bs: true
3874
+ });
3875
+ runInternal = (fn) => {
3876
+ internalDepth += 1;
3877
+ try {
3878
+ fn();
3879
+ } finally {
3880
+ internalDepth -= 1;
3881
+ }
3882
+ };
3883
+ notifyRouteChange = () => {
3884
+ const snapshot = Array.from(subscribers);
3885
+ for (const fn of snapshot) fn();
3886
+ };
3887
+ ensureListener = () => {
3888
+ if (listenerInstalled || !hasWindow()) return;
3889
+ window.addEventListener("popstate", onPopState);
3890
+ listenerInstalled = true;
3891
+ };
3892
+ maybeTeardownListener = () => {
3893
+ if (!listenerInstalled) return;
3894
+ if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
3895
+ if (hasWindow()) window.removeEventListener("popstate", onPopState);
3896
+ listenerInstalled = false;
3897
+ };
3898
+ installPatch = () => {
3899
+ if (patchInstalled || !hasHistory()) return;
3900
+ origPushState = history.pushState;
3901
+ origReplaceState = history.replaceState;
3902
+ patchedPushState = function(...args) {
3903
+ origPushState.apply(this, args);
3904
+ if (internalDepth === 0) notifyRouteChange();
3905
+ };
3906
+ patchedReplaceState = function(...args) {
3907
+ origReplaceState.apply(this, args);
3908
+ if (internalDepth === 0) notifyRouteChange();
3909
+ };
3910
+ history.pushState = patchedPushState;
3911
+ history.replaceState = patchedReplaceState;
3912
+ patchInstalled = true;
3913
+ };
3914
+ removePatch = () => {
3915
+ if (!patchInstalled) return;
3916
+ if (history.pushState === patchedPushState && origPushState) {
3917
+ history.pushState = origPushState;
3918
+ }
3919
+ if (history.replaceState === patchedReplaceState && origReplaceState) {
3920
+ history.replaceState = origReplaceState;
3921
+ }
3922
+ origPushState = null;
3923
+ origReplaceState = null;
3924
+ patchedPushState = null;
3925
+ patchedReplaceState = null;
3926
+ patchInstalled = false;
3927
+ };
3928
+ }
3929
+ });
3930
+
3931
+ // src/core/features/route.ts
3932
+ function installRoute(deps) {
3933
+ if (typeof window === "undefined") {
3934
+ return () => {
3935
+ };
3936
+ }
3937
+ if (!deps.routedTo && !deps.closeOnBack) {
3938
+ return () => {
3939
+ };
3940
+ }
3941
+ let handle = null;
3942
+ const onOpen = () => {
3943
+ if (handle) return;
3944
+ handle = pushBackMarker({
3945
+ isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
3946
+ isTop: deps.isTopSheet,
3947
+ close: deps.close,
3948
+ markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
3949
+ url: deps.routedTo
3950
+ });
3951
+ };
3952
+ const onClose = () => {
3953
+ if (!handle) return;
3954
+ popBackMarker(handle);
3955
+ handle = null;
3956
+ };
3957
+ const unsubscribeOpen = deps.on("open", onOpen);
3958
+ const unsubscribeClose = deps.on("close", onClose);
3959
+ if (deps.getSize() > 0) onOpen();
3960
+ return () => {
3961
+ unsubscribeOpen();
3962
+ unsubscribeClose();
3963
+ if (handle) {
3964
+ popBackMarker(handle);
3965
+ handle = null;
3966
+ }
3967
+ };
3968
+ }
3969
+ function installRouteChange(deps) {
3970
+ return subscribeRouteChange(() => {
3971
+ if (deps.isDestroyed() || deps.getSize() <= 0) return;
3972
+ void deps.close();
3973
+ });
3974
+ }
3975
+ var init_route = __esm({
3976
+ "src/core/features/route.ts"() {
3977
+ init_history_coordinator();
3978
+ }
3979
+ });
3980
+
3981
+ // src/core/features/persist.ts
3982
+ function installPersist(engine, key) {
3983
+ const unsubscribe = engine.on("snap", ({ id }) => {
3984
+ if (typeof window === "undefined") return;
3985
+ if (typeof localStorage === "undefined") return;
3986
+ try {
3987
+ localStorage.setItem(key, id);
3988
+ } catch {
3989
+ }
3990
+ });
3991
+ return unsubscribe;
3992
+ }
3993
+ var init_persist = __esm({
3994
+ "src/core/features/persist.ts"() {
3995
+ }
3996
+ });
3997
+
3998
+ // src/core/features/auto-collapse.ts
3999
+ function installAutoCollapse(deps) {
4000
+ const { ms } = deps;
4001
+ if (ms === void 0 || ms <= 0) {
4002
+ return () => {
4003
+ };
4004
+ }
4005
+ let timer = null;
4006
+ const clearTimer = () => {
4007
+ if (timer !== null) {
4008
+ clearTimeout(timer);
4009
+ timer = null;
4010
+ }
4011
+ };
4012
+ const fire = () => {
4013
+ if (deps.isDestroyed()) return;
4014
+ if (deps.isDragging()) return;
4015
+ const active = deps.resolveSnap(deps.getActiveId());
4016
+ if (!active || active.size === 0) return;
4017
+ let target = null;
4018
+ for (const id of deps.getAllowedIds()) {
4019
+ const snap = deps.resolveSnap(id);
4020
+ if (!snap || snap.size <= 0) continue;
4021
+ if (!target || snap.size < target.size) target = snap;
4022
+ }
4023
+ if (!target) return;
4024
+ if (target.id === active.id || target.size >= active.size) return;
4025
+ deps.snapTo(target.id);
4026
+ };
4027
+ const reset = () => {
4028
+ clearTimer();
4029
+ if (deps.isDestroyed()) return;
4030
+ timer = setTimeout(() => {
4031
+ timer = null;
4032
+ fire();
4033
+ }, ms);
4034
+ };
4035
+ const unsubscribe = deps.on("snap", () => reset());
4036
+ if ((deps.resolveSnap(deps.getActiveId())?.size ?? 0) > 0) reset();
4037
+ return () => {
4038
+ clearTimer();
4039
+ unsubscribe();
4040
+ };
4041
+ }
4042
+ var init_auto_collapse = __esm({
4043
+ "src/core/features/auto-collapse.ts"() {
4044
+ }
4045
+ });
4046
+
4047
+ // src/core/features/content-swipe.ts
4048
+ function installContentSwipe(deps) {
4049
+ const { container } = deps;
4050
+ let startY = 0;
4051
+ let startScrollTop = 0;
4052
+ let moved = false;
4053
+ const onTouchStart = (e) => {
4054
+ const t = e.touches[0];
4055
+ if (!t) return;
4056
+ startY = t.clientY;
4057
+ startScrollTop = container.scrollTop;
4058
+ moved = false;
4059
+ };
4060
+ const onTouchMove = (e) => {
4061
+ const t = e.touches[0];
4062
+ if (!t) return;
4063
+ if (Math.abs(t.clientY - startY) > CONTENT_PULL_THRESHOLD) moved = true;
4064
+ };
4065
+ const onTouchEnd = (e) => {
4066
+ if (!moved) return;
4067
+ if (deps.isDragging() || deps.isAnimating()) return;
4068
+ if (container.scrollTop !== startScrollTop) return;
4069
+ const t = e.changedTouches[0];
4070
+ if (!t) return;
4071
+ const deltaY = t.clientY - startY;
4072
+ const atTop = container.scrollTop <= 0;
4073
+ const allowed = deps.getAllowedIds();
4074
+ const idx = allowed.indexOf(deps.getActiveId());
4075
+ if (idx === -1) return;
4076
+ if (atTop && deltaY > CONTENT_PULL_THRESHOLD && idx > 0) {
4077
+ deps.snapTo(allowed[idx - 1]);
4078
+ } else if (deltaY < -CONTENT_PULL_THRESHOLD && idx < allowed.length - 1) {
4079
+ deps.snapTo(allowed[idx + 1]);
4080
+ }
4081
+ };
4082
+ container.addEventListener("touchstart", onTouchStart, { passive: true });
4083
+ container.addEventListener("touchmove", onTouchMove, { passive: true });
4084
+ container.addEventListener("touchend", onTouchEnd, { passive: true });
4085
+ return () => {
4086
+ container.removeEventListener("touchstart", onTouchStart);
4087
+ container.removeEventListener("touchmove", onTouchMove);
4088
+ container.removeEventListener("touchend", onTouchEnd);
4089
+ };
4090
+ }
4091
+ var CONTENT_PULL_THRESHOLD;
4092
+ var init_content_swipe = __esm({
4093
+ "src/core/features/content-swipe.ts"() {
4094
+ CONTENT_PULL_THRESHOLD = 60;
4095
+ }
4096
+ });
4097
+
4098
+ // src/core/features/visual-viewport.ts
4099
+ function installVisualViewport(deps) {
4100
+ if (typeof window === "undefined" || !window.visualViewport) {
4101
+ return () => {
4102
+ };
4103
+ }
4104
+ const vv = window.visualViewport;
4105
+ let rafId = null;
4106
+ const onResize = () => {
4107
+ if (rafId !== null) return;
4108
+ rafId = requestAnimationFrame(() => {
4109
+ rafId = null;
4110
+ if (deps.isDestroyed()) return;
4111
+ deps.recomputeSnaps();
4112
+ const isVertical = deps.isVerticalAxis();
4113
+ const visible = isVertical ? vv.height : vv.width;
4114
+ const windowSize = isVertical ? window.innerHeight : window.innerWidth;
4115
+ const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
4116
+ if (clamp < deps.getMaxAxisSize()) {
4117
+ deps.setMaxAxisSize(clamp);
4118
+ }
4119
+ const wasAnimating = deps.isAnimating?.() ?? false;
4120
+ deps.cancelInFlight();
4121
+ deps.newCycle();
4122
+ const max = deps.getMaxAxisSize();
4123
+ deps.setSize(Math.min(deps.getSize(), max));
4124
+ const current = deps.resolveActiveSnap();
4125
+ if (current && !deps.isDragging()) {
4126
+ deps.applySize(Math.min(current.size, max));
4127
+ if (wasAnimating) deps.resyncAfterCancel?.();
4128
+ } else {
4129
+ deps.applySize(deps.getSize());
4130
+ }
4131
+ });
4132
+ };
4133
+ vv.addEventListener("resize", onResize);
4134
+ return () => {
4135
+ vv.removeEventListener("resize", onResize);
4136
+ if (rafId !== null) cancelAnimationFrame(rafId);
4137
+ };
4138
+ }
4139
+ var SAFETY_PAD;
4140
+ var init_visual_viewport = __esm({
4141
+ "src/core/features/visual-viewport.ts"() {
4142
+ SAFETY_PAD = 8;
4143
+ }
4144
+ });
4145
+
4146
+ // src/core/features/engine-features.ts
4147
+ function routeFeature() {
4148
+ return {
4149
+ name: "route",
4150
+ install: (ctx) => {
4151
+ const teardowns = new TeardownStack();
4152
+ if (ctx.options.closeOnRouteChange) {
4153
+ teardowns.add(
4154
+ installRouteChange({
4155
+ isDestroyed: ctx.isDestroyed,
4156
+ getSize: ctx.getSize,
4157
+ close: () => ctx.close()
4158
+ })
4159
+ );
4160
+ }
4161
+ teardowns.add(
4162
+ installRoute({
4163
+ routedTo: ctx.options.routedTo,
4164
+ closeOnBack: ctx.options.closeOnBack,
4165
+ isTopSheet: ctx.isTopSheet,
4166
+ getSize: ctx.getSize,
4167
+ isDestroyed: ctx.isDestroyed,
4168
+ close: () => ctx.close("back"),
4169
+ on: ctx.on,
4170
+ sheetId: ctx.sheetId
4171
+ })
4172
+ );
4173
+ return () => teardowns.drain();
4174
+ }
4175
+ };
4176
+ }
4177
+ function persistFeature() {
4178
+ return {
4179
+ name: "persist",
4180
+ install: (ctx) => {
4181
+ const key = ctx.options.persistKey;
4182
+ if (!key) return;
4183
+ return installPersist({ on: ctx.on }, key);
4184
+ }
4185
+ };
4186
+ }
4187
+ function autoCollapseFeature() {
4188
+ return {
4189
+ name: "auto-collapse",
4190
+ install: (ctx) => installAutoCollapse({
4191
+ ms: ctx.options.autoCollapseAfter,
4192
+ isDestroyed: ctx.isDestroyed,
4193
+ isDragging: ctx.isDragging,
4194
+ getAllowedIds: ctx.getAllowedIds,
4195
+ getActiveId: ctx.getActiveId,
4196
+ resolveSnap: ctx.resolveSnap,
4197
+ snapTo: ctx.snapTo,
4198
+ on: ctx.on
4199
+ })
4200
+ };
4201
+ }
4202
+ function contentSwipeFeature() {
4203
+ return {
4204
+ name: "content-swipe",
4205
+ stage: "attach",
4206
+ install: (ctx) => {
4207
+ if (!ctx.scrollContainer) return;
4208
+ return installContentSwipe({
4209
+ container: ctx.scrollContainer,
4210
+ isDragging: ctx.isDragging,
4211
+ isAnimating: ctx.isAnimating,
4212
+ getAllowedIds: ctx.allowedIdsBySize,
4213
+ getActiveId: ctx.getActiveId,
4214
+ snapTo: ctx.snapTo
4215
+ });
4216
+ }
4217
+ };
4218
+ }
4219
+ function visualViewportFeature() {
4220
+ return {
4221
+ name: "visual-viewport",
4222
+ install: (ctx) => {
4223
+ if (typeof window === "undefined") return;
4224
+ return installVisualViewport({
4225
+ element: ctx.element,
4226
+ isVerticalAxis: ctx.isVerticalAxis,
4227
+ isDestroyed: ctx.isDestroyed,
4228
+ isDragging: ctx.isDragging,
4229
+ recomputeSnaps: ctx.recomputeSnaps,
4230
+ resolveActiveSnap: ctx.resolveActiveSnap,
4231
+ getMaxAxisSize: ctx.getMaxAxisSize,
4232
+ getSize: ctx.getSize,
4233
+ setMaxAxisSize: ctx.setMaxAxisSize,
4234
+ setSize: ctx.setSize,
4235
+ applySize: ctx.applySize,
4236
+ cancelInFlight: ctx.cancelInFlight,
4237
+ newCycle: ctx.newCycle,
4238
+ isAnimating: ctx.isAnimating,
4239
+ resyncAfterCancel: ctx.resyncAfterResize
4240
+ });
4241
+ }
4242
+ };
4243
+ }
4244
+ var init_engine_features = __esm({
4245
+ "src/core/features/engine-features.ts"() {
4246
+ init_route();
4247
+ init_persist();
4248
+ init_auto_collapse();
4249
+ init_content_swipe();
4250
+ init_visual_viewport();
4251
+ init_teardown_stack();
4252
+ }
4253
+ });
4254
+
4255
+ // src/core/default-features.ts
4256
+ function defaultEngineFeatures() {
4257
+ return [
4258
+ contentSwipeFeature(),
4259
+ visualViewportFeature(),
4260
+ persistFeature(),
4261
+ autoCollapseFeature(),
4262
+ routeFeature()
4263
+ ];
4264
+ }
4265
+ var init_default_features = __esm({
4266
+ "src/core/default-features.ts"() {
4267
+ init_engine_features();
4268
+ }
4269
+ });
4270
+
4271
+ // src/core/BottomSheetEngine.ts
4272
+ var BottomSheetEngine;
4273
+ var init_BottomSheetEngine = __esm({
4274
+ "src/core/BottomSheetEngine.ts"() {
4275
+ init_BottomSheetCore();
4276
+ init_default_features();
4277
+ BottomSheetEngine = class extends BottomSheetCore {
4278
+ constructor(opts) {
4279
+ super({
4280
+ ...opts,
4281
+ features: [...defaultEngineFeatures(), ...opts.features ?? []]
4282
+ });
4283
+ }
4284
+ };
4285
+ }
4286
+ });
4287
+
3991
4288
  // src/web-component/baseStyles.ts
3992
4289
  var baseStyles;
3993
4290
  var init_baseStyles = __esm({