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