@surdeddd/bottom-sheet 0.12.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 +52 -1
  2. package/dist/{BottomSheetEngine-D6oiEfZ4.d.cts → BottomSheetCore-CsIjyq7C.d.cts} +60 -5
  3. package/dist/{BottomSheetEngine-Dhy0X_e9.d.ts → BottomSheetCore-D16lsa6g.d.ts} +60 -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 +972 -685
  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 +972 -685
  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 +805 -534
  26. package/dist/index.d.cts +6 -15
  27. package/dist/index.d.ts +6 -15
  28. package/dist/index.js +799 -535
  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 +6 -5
  34. package/dist/overlay.js +6 -5
  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 +798 -534
  40. package/dist/qwik.d.cts +2 -2
  41. package/dist/qwik.d.ts +2 -2
  42. package/dist/qwik.js +798 -534
  43. package/dist/react.cjs +798 -534
  44. package/dist/react.d.cts +3 -2
  45. package/dist/react.d.ts +3 -2
  46. package/dist/react.js +798 -534
  47. package/dist/solid.cjs +798 -534
  48. package/dist/solid.d.cts +63 -4
  49. package/dist/solid.d.ts +63 -4
  50. package/dist/solid.js +798 -534
  51. package/dist/solid.source.jsx +798 -534
  52. package/dist/svelte-core.cjs +798 -534
  53. package/dist/svelte-core.js +798 -534
  54. package/dist/svelte.cjs +798 -534
  55. package/dist/svelte.js +798 -534
  56. package/dist/vue.cjs +909 -637
  57. package/dist/vue.js +909 -637
  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,543 +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(brandMarker(entry.surface), "", 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(brandMarker(surface), "", 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
- brandMarker(rebrandSurface),
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, brandMarker, 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
- brandMarker = (surface) => ({
646
- ...surface.markerState(),
647
- __bs: true
648
- });
649
- runInternal = (fn) => {
650
- internalDepth += 1;
651
- try {
652
- fn();
653
- } finally {
654
- internalDepth -= 1;
655
- }
656
- };
657
- notifyRouteChange = () => {
658
- const snapshot = Array.from(subscribers);
659
- for (const fn of snapshot) fn();
660
- };
661
- ensureListener = () => {
662
- if (listenerInstalled || !hasWindow()) return;
663
- window.addEventListener("popstate", onPopState);
664
- listenerInstalled = true;
665
- };
666
- maybeTeardownListener = () => {
667
- if (!listenerInstalled) return;
668
- if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
669
- if (hasWindow()) window.removeEventListener("popstate", onPopState);
670
- listenerInstalled = false;
671
- };
672
- installPatch = () => {
673
- if (patchInstalled || !hasHistory()) return;
674
- origPushState = history.pushState;
675
- origReplaceState = history.replaceState;
676
- patchedPushState = function(...args) {
677
- origPushState.apply(this, args);
678
- if (internalDepth === 0) notifyRouteChange();
679
- };
680
- patchedReplaceState = function(...args) {
681
- origReplaceState.apply(this, args);
682
- if (internalDepth === 0) notifyRouteChange();
683
- };
684
- history.pushState = patchedPushState;
685
- history.replaceState = patchedReplaceState;
686
- patchInstalled = true;
687
- };
688
- removePatch = () => {
689
- if (!patchInstalled) return;
690
- if (history.pushState === patchedPushState && origPushState) {
691
- history.pushState = origPushState;
692
- }
693
- if (history.replaceState === patchedReplaceState && origReplaceState) {
694
- 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
+ }
695
560
  }
696
- origPushState = null;
697
- origReplaceState = null;
698
- patchedPushState = null;
699
- patchedReplaceState = null;
700
- patchInstalled = false;
561
+ return out;
701
562
  };
702
563
  }
703
564
  });
704
565
 
705
- // src/core/features/route.ts
706
- function installRoute(deps) {
707
- if (typeof window === "undefined") {
708
- return () => {
709
- };
710
- }
711
- if (!deps.routedTo && !deps.closeOnBack) {
712
- return () => {
713
- };
714
- }
715
- let handle = null;
716
- const onOpen = () => {
717
- if (handle) return;
718
- handle = pushBackMarker({
719
- isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
720
- isTop: deps.isTopSheet,
721
- close: deps.close,
722
- markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
723
- url: deps.routedTo
724
- });
725
- };
726
- const onClose = () => {
727
- if (!handle) return;
728
- popBackMarker(handle);
729
- handle = null;
730
- };
731
- const unsubscribeOpen = deps.on("open", onOpen);
732
- const unsubscribeClose = deps.on("close", onClose);
733
- if (deps.getSize() > 0) onOpen();
734
- return () => {
735
- unsubscribeOpen();
736
- unsubscribeClose();
737
- if (handle) {
738
- popBackMarker(handle);
739
- 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;
740
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;
741
583
  };
742
- }
743
- function installRouteChange(deps) {
744
- return subscribeRouteChange(() => {
745
- if (deps.isDestroyed() || deps.getSize() <= 0) return;
746
- void deps.close();
747
- });
748
- }
749
- var init_route = __esm({
750
- "src/core/features/route.ts"() {
751
- init_history_coordinator();
752
- }
753
- });
754
-
755
- // src/core/features/content-swipe.ts
756
- function installContentSwipe(deps) {
757
- const { container } = deps;
758
- let startY = 0;
759
- let startScrollTop = 0;
760
- let moved = false;
761
- const onTouchStart = (e) => {
762
- const t = e.touches[0];
763
- if (!t) return;
764
- startY = t.clientY;
765
- startScrollTop = container.scrollTop;
766
- moved = false;
767
- };
768
- const onTouchMove = (e) => {
769
- const t = e.touches[0];
770
- if (!t) return;
771
- if (Math.abs(t.clientY - startY) > CONTENT_PULL_THRESHOLD) moved = true;
772
- };
773
- const onTouchEnd = (e) => {
774
- if (!moved) return;
775
- if (deps.isDragging() || deps.isAnimating()) return;
776
- if (container.scrollTop !== startScrollTop) return;
777
- const t = e.changedTouches[0];
778
- if (!t) return;
779
- const deltaY = t.clientY - startY;
780
- const atTop = container.scrollTop <= 0;
781
- const allowed = deps.getAllowedIds();
782
- const idx = allowed.indexOf(deps.getActiveId());
783
- if (idx === -1) return;
784
- if (atTop && deltaY > CONTENT_PULL_THRESHOLD && idx > 0) {
785
- deps.snapTo(allowed[idx - 1]);
786
- } else if (deltaY < -CONTENT_PULL_THRESHOLD && idx < allowed.length - 1) {
787
- deps.snapTo(allowed[idx + 1]);
584
+ const clampTo = () => {
585
+ if (maxHeightCap === void 0) return;
586
+ if (deps.getMaxAxisSize() > maxHeightCap) {
587
+ deps.setMaxAxisSize(maxHeightCap);
788
588
  }
789
589
  };
790
- container.addEventListener("touchstart", onTouchStart, { passive: true });
791
- container.addEventListener("touchmove", onTouchMove, { passive: true });
792
- container.addEventListener("touchend", onTouchEnd, { passive: true });
793
- return () => {
794
- container.removeEventListener("touchstart", onTouchStart);
795
- container.removeEventListener("touchmove", onTouchMove);
796
- 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
797
611
  };
798
612
  }
799
- var CONTENT_PULL_THRESHOLD;
800
- var init_content_swipe = __esm({
801
- "src/core/features/content-swipe.ts"() {
802
- CONTENT_PULL_THRESHOLD = 60;
803
- }
804
- });
805
-
806
- // src/core/features/visual-viewport.ts
807
- function installVisualViewport(deps) {
808
- if (typeof window === "undefined" || !window.visualViewport) {
809
- return () => {
810
- };
811
- }
812
- const vv = window.visualViewport;
813
- let rafId = null;
814
- const onResize = () => {
815
- if (rafId !== null) return;
816
- rafId = requestAnimationFrame(() => {
817
- rafId = null;
818
- if (deps.isDestroyed()) return;
819
- deps.recomputeSnaps();
820
- const isVertical = deps.isVerticalAxis();
821
- const visible = isVertical ? vv.height : vv.width;
822
- const windowSize = isVertical ? window.innerHeight : window.innerWidth;
823
- const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
824
- if (clamp < deps.getMaxAxisSize()) {
825
- deps.setMaxAxisSize(clamp);
826
- }
827
- const wasAnimating = deps.isAnimating?.() ?? false;
828
- deps.cancelInFlight();
829
- deps.newCycle();
830
- const max = deps.getMaxAxisSize();
831
- deps.setSize(Math.min(deps.getSize(), max));
832
- const current = deps.resolveActiveSnap();
833
- if (current && !deps.isDragging()) {
834
- deps.applySize(Math.min(current.size, max));
835
- if (wasAnimating) deps.resyncAfterCancel?.();
836
- } else {
837
- deps.applySize(deps.getSize());
838
- }
839
- });
840
- };
841
- vv.addEventListener("resize", onResize);
842
- return () => {
843
- vv.removeEventListener("resize", onResize);
844
- if (rafId !== null) cancelAnimationFrame(rafId);
845
- };
846
- }
847
- var SAFETY_PAD;
848
- var init_visual_viewport = __esm({
849
- "src/core/features/visual-viewport.ts"() {
850
- SAFETY_PAD = 8;
851
- }
852
- });
853
-
854
- // src/core/features/resize-observer.ts
855
- function installResizeObserver(deps) {
856
- if (typeof window === "undefined") {
857
- return () => {
858
- };
859
- }
860
- const onResize = () => {
861
- if (deps.isDestroyed()) return;
862
- deps.recomputeSnaps();
863
- const mode = deps.getMode();
864
- const isVerticalAxis = mode === "bottom" || mode === "top";
865
- const viewportSize2 = isVerticalAxis ? window.innerHeight : window.innerWidth;
866
- const max = deps.getMaxAxisSize();
867
- if (viewportSize2 > 0 && viewportSize2 < max) {
868
- deps.setMaxAxisSize(viewportSize2);
869
- }
870
- const wasAnimating = deps.isAnimating?.() ?? false;
871
- deps.cancelInFlight();
872
- deps.newCycle();
873
- const current = deps.resolveActiveSnap();
874
- const newMax = deps.getMaxAxisSize();
875
- const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
876
- deps.setSize(targetSize);
877
- if (current && !deps.isDragging()) {
878
- deps.applySize(targetSize);
879
- if (wasAnimating) deps.resyncAfterCancel?.();
880
- }
881
- };
882
- let resizeObserver = null;
883
- if (typeof ResizeObserver !== "undefined") {
884
- resizeObserver = new ResizeObserver(onResize);
885
- resizeObserver.observe(document.documentElement);
886
- } else {
887
- window.addEventListener("resize", onResize);
888
- }
889
- window.addEventListener("orientationchange", onResize);
890
- const onVisibility = () => {
891
- if (deps.isDestroyed()) return;
892
- if (document.hidden) deps.cancelInFlight();
893
- };
894
- document.addEventListener("visibilitychange", onVisibility);
895
- return () => {
896
- resizeObserver?.disconnect();
897
- window.removeEventListener("resize", onResize);
898
- window.removeEventListener("orientationchange", onResize);
899
- document.removeEventListener("visibilitychange", onVisibility);
900
- };
901
- }
902
- var init_resize_observer = __esm({
903
- "src/core/features/resize-observer.ts"() {
904
- }
905
- });
906
-
907
- // src/core/features/fit-observer.ts
908
- function installFitObserver(deps) {
909
- if (typeof ResizeObserver === "undefined") return () => {
910
- };
911
- if (!deps.hasFitSnap()) return () => {
912
- };
913
- let raf = 0;
914
- const schedule = () => {
915
- if (raf) return;
916
- raf = requestAnimationFrame(() => {
917
- raf = 0;
918
- if (deps.isDestroyed() || deps.isDragging()) return;
919
- deps.recompute();
920
- });
921
- };
922
- const ro = new ResizeObserver(schedule);
923
- ro.observe(deps.handle);
924
- const scroller = deps.scrollContainer;
925
- const observed = /* @__PURE__ */ new Set();
926
- const slots = /* @__PURE__ */ new Set();
927
- const hasSlot = typeof HTMLSlotElement !== "undefined";
928
- const onSlotChange = () => resync();
929
- const trackSlots = () => {
930
- if (!scroller || !hasSlot) return;
931
- for (const child of Array.from(scroller.children)) {
932
- if (child instanceof HTMLSlotElement && !slots.has(child)) {
933
- child.addEventListener("slotchange", onSlotChange);
934
- slots.add(child);
935
- }
936
- }
937
- };
938
- const resync = () => {
939
- trackSlots();
940
- const targets = contentTargets(scroller);
941
- for (const el of observed) {
942
- if (!targets.includes(el)) {
943
- ro.unobserve(el);
944
- observed.delete(el);
945
- }
946
- }
947
- for (const el of targets) {
948
- if (!observed.has(el)) {
949
- ro.observe(el);
950
- observed.add(el);
951
- }
952
- }
953
- schedule();
954
- };
955
- let mo;
956
- if (scroller) {
957
- resync();
958
- if (typeof MutationObserver !== "undefined") {
959
- mo = new MutationObserver(resync);
960
- mo.observe(scroller, { childList: true });
961
- }
962
- }
963
- return () => {
964
- ro.disconnect();
965
- mo?.disconnect();
966
- for (const slot of slots) {
967
- slot.removeEventListener("slotchange", onSlotChange);
968
- }
969
- if (raf) cancelAnimationFrame(raf);
970
- };
971
- }
972
- var contentTargets;
973
- var init_fit_observer = __esm({
974
- "src/core/features/fit-observer.ts"() {
975
- contentTargets = (scroller) => {
976
- if (!scroller) return [];
977
- const hasSlot = typeof HTMLSlotElement !== "undefined";
978
- const out = [];
979
- for (const child of Array.from(scroller.children)) {
980
- if (hasSlot && child instanceof HTMLSlotElement) {
981
- for (const el of child.assignedElements()) out.push(el);
982
- } else {
983
- out.push(child);
984
- }
985
- }
986
- return out;
987
- };
988
- }
989
- });
990
-
991
- // src/core/features/max-height-controller.ts
992
- function createMaxHeightController(deps) {
993
- let maxHeightCap;
994
- let maxHeightRaw;
995
- const resolveCap = () => {
996
- const raw = maxHeightRaw;
997
- if (raw === void 0) {
998
- maxHeightCap = void 0;
999
- return;
1000
- }
1001
- if (typeof raw === "number") {
1002
- maxHeightCap = raw;
1003
- return;
1004
- }
1005
- if (typeof window === "undefined") return;
1006
- const measured = resolveSnap(raw, deps.mode);
1007
- maxHeightCap = measured > 0 ? measured : void 0;
1008
- };
1009
- const clampTo = () => {
1010
- if (maxHeightCap === void 0) return;
1011
- if (deps.getMaxAxisSize() > maxHeightCap) {
1012
- deps.setMaxAxisSize(maxHeightCap);
1013
- }
1014
- };
1015
- return {
1016
- setRadius(r) {
1017
- deps.element.style.setProperty(
1018
- "--bs-radius",
1019
- typeof r === "number" ? `${r}px` : r
1020
- );
1021
- },
1022
- setMaxHeight(h) {
1023
- const value = typeof h === "number" ? `${h}px` : h;
1024
- const axis = layoutAxis(deps.mode);
1025
- deps.element.style.setProperty(
1026
- axis === "height" ? "max-height" : "max-width",
1027
- value
1028
- );
1029
- maxHeightRaw = h;
1030
- resolveCap();
1031
- deps.recompute();
1032
- },
1033
- resolveCap,
1034
- clampTo,
1035
- getCap: () => maxHeightCap
1036
- };
1037
- }
1038
- var init_max_height_controller = __esm({
1039
- "src/core/features/max-height-controller.ts"() {
1040
- init_snap_points();
1041
- init_transform();
613
+ var init_max_height_controller = __esm({
614
+ "src/core/features/max-height-controller.ts"() {
615
+ init_snap_points();
616
+ init_transform();
1042
617
  }
1043
618
  });
1044
619
 
@@ -1822,6 +1397,58 @@ var init_animation_presets = __esm({
1822
1397
  }
1823
1398
  });
1824
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
+
1825
1452
  // src/core/controllers/animation-runner.ts
1826
1453
  var DEFAULT_DURATION2, VELOCITY_PX_PER_S, AnimationRunner;
1827
1454
  var init_animation_runner = __esm({
@@ -1829,6 +1456,7 @@ var init_animation_runner = __esm({
1829
1456
  init_animation();
1830
1457
  init_spring();
1831
1458
  init_animation_presets();
1459
+ init_waapi_settle();
1832
1460
  DEFAULT_DURATION2 = 220;
1833
1461
  VELOCITY_PX_PER_S = 1e3;
1834
1462
  AnimationRunner = class {
@@ -1838,6 +1466,10 @@ var init_animation_runner = __esm({
1838
1466
  __publicField(this, "applySizeFn");
1839
1467
  __publicField(this, "getSize");
1840
1468
  __publicField(this, "isDragging");
1469
+ __publicField(this, "applyAux");
1470
+ __publicField(this, "getTransformFor");
1471
+ __publicField(this, "settleWaapi");
1472
+ __publicField(this, "currentWaapi", null);
1841
1473
  __publicField(this, "animationKind");
1842
1474
  __publicField(this, "springConfig");
1843
1475
  __publicField(this, "duration");
@@ -1853,6 +1485,9 @@ var init_animation_runner = __esm({
1853
1485
  this.applySizeFn = deps.applySize;
1854
1486
  this.getSize = deps.getSize;
1855
1487
  this.isDragging = deps.isDragging;
1488
+ this.applyAux = deps.applyAux;
1489
+ this.getTransformFor = deps.getTransformFor;
1490
+ this.settleWaapi = opts.settleAnimation === "waapi";
1856
1491
  const preset = resolveAnimationPreset(opts.animation);
1857
1492
  this.animationKind = preset.kind;
1858
1493
  this.duration = opts.duration ?? preset.duration ?? DEFAULT_DURATION2;
@@ -1877,11 +1512,20 @@ var init_animation_runner = __esm({
1877
1512
  }
1878
1513
  }
1879
1514
  get isAnimating() {
1880
- return this.currentTween !== null || this.currentSpring !== null;
1515
+ return this.currentTween !== null || this.currentSpring !== null || this.currentWaapi !== null;
1881
1516
  }
1882
1517
  cancel() {
1883
1518
  this.currentTween?.cancel();
1884
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
+ }
1885
1529
  }
1886
1530
  async animateTo(target, velocityPxPerMs) {
1887
1531
  if (target === this.getSize()) {
@@ -1900,7 +1544,28 @@ var init_animation_runner = __esm({
1900
1544
  if (!this.isDragging()) this.element.style.willChange = "";
1901
1545
  return;
1902
1546
  }
1903
- if (this.animationKind === "spring") {
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") {
1904
1569
  const spring = runSpring({
1905
1570
  from: this.getSize(),
1906
1571
  to: target,
@@ -1928,11 +1593,66 @@ var init_animation_runner = __esm({
1928
1593
  if (!this.isDragging()) this.element.style.willChange = "";
1929
1594
  }
1930
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
+ }
1931
1642
  destroy() {
1932
1643
  this.detachReducedMotion?.();
1933
1644
  this.detachReducedMotion = null;
1934
1645
  this.currentTween = null;
1935
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
+ }
1936
1656
  }
1937
1657
  };
1938
1658
  }
@@ -2860,7 +2580,7 @@ function resolveEngineOptions(opts, extras) {
2860
2580
  const initialAllowed = opts.allowed ?? opts.snapPoints.map((p) => p.id);
2861
2581
  let initialId = opts.initial ?? initialAllowed[0] ?? opts.snapPoints[0]?.id ?? "default";
2862
2582
  if (opts.persistKey) {
2863
- const restored = readPersistedId(opts.persistKey);
2583
+ const restored = readPersistedIdSafe(opts.persistKey);
2864
2584
  if (restored && initialAllowed.includes(restored)) {
2865
2585
  initialId = restored;
2866
2586
  }
@@ -2891,6 +2611,7 @@ function resolveEngineOptions(opts, extras) {
2891
2611
  },
2892
2612
  animation: {
2893
2613
  animation: opts.animation,
2614
+ settleAnimation: opts.settleAnimation,
2894
2615
  duration: opts.duration,
2895
2616
  easing: opts.easing,
2896
2617
  spring: opts.spring,
@@ -2908,12 +2629,20 @@ function resolveEngineOptions(opts, extras) {
2908
2629
  }
2909
2630
  };
2910
2631
  }
2911
- var DEFAULT_FLICK_VELOCITY, DEFAULT_DRAG_THRESHOLD;
2632
+ var DEFAULT_FLICK_VELOCITY, DEFAULT_DRAG_THRESHOLD, readPersistedIdSafe;
2912
2633
  var init_engine_options = __esm({
2913
2634
  "src/core/primitives/engine-options.ts"() {
2914
- init_persist();
2915
2635
  DEFAULT_FLICK_VELOCITY = 0.65;
2916
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
+ };
2917
2646
  }
2918
2647
  });
2919
2648
 
@@ -2943,10 +2672,10 @@ var init_teardown_stack = __esm({
2943
2672
  }
2944
2673
  });
2945
2674
 
2946
- // src/core/BottomSheetEngine.ts
2947
- var HAPTIC_DURATION_MS, BottomSheetEngine;
2948
- var init_BottomSheetEngine = __esm({
2949
- "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"() {
2950
2679
  init_sheetStack();
2951
2680
  init_transform();
2952
2681
  init_instance_id();
@@ -2955,12 +2684,7 @@ var init_BottomSheetEngine = __esm({
2955
2684
  init_cancelable_emit();
2956
2685
  init_devWarn();
2957
2686
  init_snap_resolver();
2958
- init_persist();
2959
- init_auto_collapse();
2960
2687
  init_linked_sheets();
2961
- init_route();
2962
- init_content_swipe();
2963
- init_visual_viewport();
2964
2688
  init_resize_observer();
2965
2689
  init_fit_observer();
2966
2690
  init_max_height_controller();
@@ -2979,7 +2703,7 @@ var init_BottomSheetEngine = __esm({
2979
2703
  init_teardown_stack();
2980
2704
  init_opacity_dedup();
2981
2705
  HAPTIC_DURATION_MS = 8;
2982
- BottomSheetEngine = class {
2706
+ BottomSheetCore = class {
2983
2707
  constructor(opts) {
2984
2708
  __publicField(this, "id", nextInstanceId("bs"));
2985
2709
  __publicField(this, "element");
@@ -3040,6 +2764,8 @@ var init_BottomSheetEngine = __esm({
3040
2764
  __publicField(this, "stackEffectPrimed", false);
3041
2765
  __publicField(this, "fitDeps");
3042
2766
  __publicField(this, "transformTemplate");
2767
+ __publicField(this, "featureList", []);
2768
+ __publicField(this, "featureCtx");
3043
2769
  const resolved = resolveEngineOptions(opts, {
3044
2770
  shouldApplyInertSiblings: () => {
3045
2771
  if (typeof document === "undefined") return false;
@@ -3086,7 +2812,9 @@ var init_BottomSheetEngine = __esm({
3086
2812
  getRootEl: () => this.rootEl,
3087
2813
  applySize: (size) => this.applySize(size),
3088
2814
  getSize: () => this.size,
3089
- 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)
3090
2818
  },
3091
2819
  resolved.animation
3092
2820
  );
@@ -3109,6 +2837,11 @@ var init_BottomSheetEngine = __esm({
3109
2837
  if (opts.linkedSheets) {
3110
2838
  this.linkedSheets = opts.linkedSheets;
3111
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());
3112
2845
  this.activeId = resolved.initialId;
3113
2846
  auditVhUsage(this.snapPointsRaw);
3114
2847
  this.auditDuplicateSnapIds(this.snapPointsRaw);
@@ -3145,6 +2878,7 @@ var init_BottomSheetEngine = __esm({
3145
2878
  scrollContainer: this.scrollContainer,
3146
2879
  getMaxAxisSize: () => this.snaps.getMaxAxisSize()
3147
2880
  });
2881
+ this.featureCtx = this.buildFeatureContext(opts.autoCollapseAfter);
3148
2882
  this.attach();
3149
2883
  this.registerInStack();
3150
2884
  if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
@@ -3176,46 +2910,77 @@ var init_BottomSheetEngine = __esm({
3176
2910
  if (resolved.radius !== void 0) this.setRadius(resolved.radius);
3177
2911
  if (resolved.maxHeight !== void 0) this.setMaxHeight(resolved.maxHeight);
3178
2912
  this.applyAutoAriaLabelledBy();
3179
- if (this.closeOnRouteChange) {
3180
- this.teardowns.add(
3181
- installRouteChange({
3182
- isDestroyed: () => this.destroyed,
3183
- getSize: () => this.size,
3184
- close: () => this.close()
3185
- })
3186
- );
3187
- }
3188
- if (this.persistKey) {
3189
- this.teardowns.add(installPersist(this, this.persistKey));
2913
+ this.runFeatureStage("post");
2914
+ this.warnOrphanFeatureOptions();
2915
+ if (this.size > 0) {
2916
+ this.handleOpen();
3190
2917
  }
3191
- this.teardowns.add(
3192
- installAutoCollapse({
3193
- ms: opts.autoCollapseAfter,
3194
- isDestroyed: () => this.destroyed,
3195
- isDragging: () => this.gesture?.isDragging ?? false,
3196
- getAllowedIds: () => this.snaps.getAllowedIds().slice(),
3197
- getActiveId: () => this.activeId,
3198
- resolveSnap: (id) => this.snaps.findById(id),
3199
- snapTo: (id) => {
3200
- void this.snapTo(id);
3201
- },
3202
- on: (event, fn) => this.on(event, fn)
3203
- })
3204
- );
3205
- this.teardowns.add(
3206
- installRoute({
2918
+ }
2919
+ buildFeatureContext(autoCollapseAfter) {
2920
+ return {
2921
+ element: this.element,
2922
+ scrollContainer: this.scrollContainer,
2923
+ sheetId: this.id,
2924
+ options: {
3207
2925
  routedTo: this.routedTo,
3208
2926
  closeOnBack: this.closeOnBack,
3209
- isTopSheet: () => this.isTopSheet,
3210
- getSize: () => this.size,
3211
- isDestroyed: () => this.destroyed,
3212
- close: () => this.close("back"),
3213
- on: (event, fn) => this.on(event, fn),
3214
- sheetId: this.id
3215
- })
3216
- );
3217
- if (this.size > 0) {
3218
- 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
+ );
3219
2984
  }
3220
2985
  }
3221
2986
  get state() {
@@ -3758,18 +3523,7 @@ var init_BottomSheetEngine = __esm({
3758
3523
  }
3759
3524
  }
3760
3525
  attachFeatures() {
3761
- if (this.scrollContainer) {
3762
- this.teardowns.add(installContentSwipe({
3763
- container: this.scrollContainer,
3764
- isDragging: () => this.gesture?.isDragging ?? false,
3765
- isAnimating: () => this.animation.isAnimating,
3766
- getAllowedIds: () => this.allowedIdsBySize(),
3767
- getActiveId: () => this.activeId,
3768
- snapTo: (id) => {
3769
- void this.snapTo(id);
3770
- }
3771
- }));
3772
- }
3526
+ this.runFeatureStage("attach");
3773
3527
  if (typeof window !== "undefined") {
3774
3528
  this.teardowns.add(installResizeObserver({
3775
3529
  element: this.element,
@@ -3809,31 +3563,6 @@ var init_BottomSheetEngine = __esm({
3809
3563
  () => document.removeEventListener("keydown", onKey)
3810
3564
  );
3811
3565
  }
3812
- this.teardowns.add(installVisualViewport({
3813
- element: this.element,
3814
- isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
3815
- isDestroyed: () => this.destroyed,
3816
- isDragging: () => this.gesture?.isDragging ?? false,
3817
- recomputeSnaps: () => this.recomputeSnaps(),
3818
- resolveActiveSnap: () => this.snaps.findById(this.activeId),
3819
- getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
3820
- getSize: () => this.size,
3821
- setMaxAxisSize: (size) => {
3822
- this.snaps.setMaxAxisSize(size);
3823
- },
3824
- setSize: (size) => {
3825
- this.size = size;
3826
- },
3827
- applySize: (size) => this.applySize(size),
3828
- cancelInFlight: () => {
3829
- this.animation.cancel();
3830
- },
3831
- newCycle: () => {
3832
- this.newCycle();
3833
- },
3834
- isAnimating: () => this.animation.isAnimating,
3835
- resyncAfterCancel: () => this.resyncAfterResize()
3836
- }));
3837
3566
  }
3838
3567
  this.teardowns.add(installSliderKeyboard({
3839
3568
  handle: this.handle,
@@ -3910,13 +3639,13 @@ var init_BottomSheetEngine = __esm({
3910
3639
  }
3911
3640
  }
3912
3641
  }
3913
- applySize(size) {
3642
+ applySize(size, skipTransform = false) {
3914
3643
  const cap = this.snaps.getMaxAxisSize();
3915
3644
  const clamped = cap > 0 && size > cap && !this.gesture?.isDragging && !this.allowOvershoot ? cap : size;
3916
3645
  this.size = clamped;
3917
3646
  const offset = cap - clamped;
3918
3647
  const style = this.element.style;
3919
- style.transform = this.transformTemplate(offset);
3648
+ if (!skipTransform) style.transform = this.transformTemplate(offset);
3920
3649
  if (this.sizeWriteSentinel.shouldWrite(clamped, SIZE_WRITE_EPSILON)) {
3921
3650
  style.setProperty("--bs-size", `${clamped}px`);
3922
3651
  if (this.scrimParent) {
@@ -3996,6 +3725,564 @@ var init_BottomSheetEngine = __esm({
3996
3725
  }
3997
3726
  });
3998
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
+
3999
4286
  // src/web-component/baseStyles.ts
4000
4287
  var baseStyles;
4001
4288
  var init_baseStyles = __esm({