@surdeddd/bottom-sheet 0.9.1 → 0.11.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 (50) hide show
  1. package/README.md +126 -83
  2. package/dist/{BottomSheetEngine-CBRcBwV-.d.ts → BottomSheetEngine-DRjCU73e.d.ts} +6 -5
  3. package/dist/{BottomSheetEngine-BcyruNP1.d.cts → BottomSheetEngine-DzsIwD28.d.cts} +6 -5
  4. package/dist/element.cjs +388 -222
  5. package/dist/element.d.cts +1 -1
  6. package/dist/element.d.ts +1 -1
  7. package/dist/element.iife.global.js +2 -2
  8. package/dist/element.js +388 -222
  9. package/dist/index.cjs +389 -266
  10. package/dist/index.d.cts +2 -2
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.js +389 -266
  13. package/dist/integrations/formik.d.cts +1 -1
  14. package/dist/integrations/formik.d.ts +1 -1
  15. package/dist/integrations/react-hook-form.d.cts +1 -1
  16. package/dist/integrations/react-hook-form.d.ts +1 -1
  17. package/dist/overlay.cjs +191 -58
  18. package/dist/overlay.d.cts +4 -3
  19. package/dist/overlay.d.ts +4 -3
  20. package/dist/overlay.js +191 -58
  21. package/dist/preact.d.cts +2 -1
  22. package/dist/preact.d.ts +2 -1
  23. package/dist/qwik.cjs +396 -211
  24. package/dist/qwik.d.cts +11 -2
  25. package/dist/qwik.d.ts +11 -2
  26. package/dist/qwik.js +396 -211
  27. package/dist/react.cjs +500 -332
  28. package/dist/react.d.cts +26 -4
  29. package/dist/react.d.ts +26 -4
  30. package/dist/react.js +500 -332
  31. package/dist/solid.cjs +362 -210
  32. package/dist/solid.d.cts +14 -4
  33. package/dist/solid.d.ts +14 -4
  34. package/dist/solid.js +362 -210
  35. package/dist/solid.source.jsx +362 -210
  36. package/dist/styles.css +17 -1
  37. package/dist/svelte-core.cjs +345 -208
  38. package/dist/svelte-core.js +345 -208
  39. package/dist/svelte-src/BottomSheet.svelte +6 -0
  40. package/dist/svelte.cjs +359 -220
  41. package/dist/svelte.d.cts +2 -0
  42. package/dist/svelte.d.ts +2 -0
  43. package/dist/svelte.js +359 -220
  44. package/dist/teleport-7uYNiEAT.d.cts +3 -0
  45. package/dist/teleport-7uYNiEAT.d.ts +3 -0
  46. package/dist/vue.cjs +353 -209
  47. package/dist/vue.d.cts +3 -1
  48. package/dist/vue.d.ts +3 -1
  49. package/dist/vue.js +353 -209
  50. package/package.json +11 -9
package/dist/svelte.cjs CHANGED
@@ -207,11 +207,18 @@ var resolveSnap = (point, mode, measureFit) => {
207
207
  return Math.max(0, el.getBoundingClientRect().width);
208
208
  };
209
209
 
210
+ // src/core/primitives/devWarn.ts
211
+ function devWarn(...args) {
212
+ if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
213
+ console.warn(...args);
214
+ }
215
+ }
216
+
210
217
  // src/core/primitives/snap-points.ts
211
218
  var resolveSnapList = (points, mode, measureFit) => points.map((p) => {
212
219
  const raw = resolveSnap(p.size, mode, measureFit);
213
220
  if (!Number.isFinite(raw) || raw < 0) {
214
- console.warn(
221
+ devWarn(
215
222
  `[BottomSheet] snap "${p.id}" resolved to invalid size (${String(p.size)} \u2192 ${raw}); clamped to 0.`
216
223
  );
217
224
  return { id: p.id, size: 0 };
@@ -223,7 +230,7 @@ var auditVhUsage = (points) => {
223
230
  for (const p of points) {
224
231
  if (typeof p.size !== "string") continue;
225
232
  if (!VH_NOT_DVH.test(p.size)) continue;
226
- console.warn(
233
+ devWarn(
227
234
  `[BottomSheet] snap "${p.id}" uses "vh" \u2014 prefer "dvh" on mobile (iOS Safari URL bar makes vh unstable). See https://web.dev/blog/viewport-units`
228
235
  );
229
236
  }
@@ -277,6 +284,26 @@ var findDragSettleTarget = (input) => {
277
284
  );
278
285
  };
279
286
 
287
+ // src/core/primitives/cancelable-emit.ts
288
+ function emitCancelable(emit, base, warnLabel) {
289
+ let cancelled = false;
290
+ let frozen = false;
291
+ emit({
292
+ ...base,
293
+ cancel: () => {
294
+ if (frozen) {
295
+ devWarn(
296
+ `[BottomSheet] ${warnLabel}.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener.`
297
+ );
298
+ return;
299
+ }
300
+ cancelled = true;
301
+ }
302
+ });
303
+ frozen = true;
304
+ return cancelled;
305
+ }
306
+
280
307
  // src/core/primitives/snap-resolver.ts
281
308
  var SnapResolver = class {
282
309
  constructor(raw, allowed, mode, measureFit, onMaxAxisSizeChange) {
@@ -421,7 +448,9 @@ function notifyLinkedSheets(sheets, self) {
421
448
  try {
422
449
  if (linked.state.size === 0) continue;
423
450
  const ids = linked.getAllowedIds();
424
- const target = ids.find((id) => id !== "closed");
451
+ const resolved = linked.getResolvedSnaps();
452
+ const sizeOf = (id) => resolved.find((s) => s.id === id)?.size ?? 0;
453
+ const target = ids.find((id) => sizeOf(id) > 0);
425
454
  if (target && target !== linked.state.activeId) {
426
455
  void linked.snapTo(target);
427
456
  }
@@ -433,46 +462,198 @@ function notifyLinkedSheets(sheets, self) {
433
462
  }
434
463
  }
435
464
 
436
- // src/core/features/route.ts
437
- var closers = [];
438
- var handlerInstalled = false;
465
+ // src/core/features/history-coordinator.ts
466
+ var entries = [];
467
+ var subscribers = /* @__PURE__ */ new Set();
439
468
  var suppress = 0;
440
- var ensureHandler = () => {
441
- if (handlerInstalled || typeof window === "undefined") return;
442
- handlerInstalled = true;
443
- window.addEventListener("popstate", () => {
444
- if (suppress > 0) {
445
- suppress -= 1;
446
- return;
469
+ var internalDepth = 0;
470
+ var pendingRebrand = null;
471
+ var listenerInstalled = false;
472
+ var patchInstalled = false;
473
+ var origPushState = null;
474
+ var origReplaceState = null;
475
+ var patchedPushState = null;
476
+ var patchedReplaceState = null;
477
+ var hasWindow = () => typeof window !== "undefined";
478
+ var hasHistory = () => typeof history !== "undefined";
479
+ var runInternal = (fn) => {
480
+ internalDepth += 1;
481
+ try {
482
+ fn();
483
+ } finally {
484
+ internalDepth -= 1;
485
+ }
486
+ };
487
+ var notifyRouteChange = () => {
488
+ const snapshot = Array.from(subscribers);
489
+ for (const fn of snapshot) fn();
490
+ };
491
+ var ensureListener = () => {
492
+ if (listenerInstalled || !hasWindow()) return;
493
+ window.addEventListener("popstate", onPopState);
494
+ listenerInstalled = true;
495
+ };
496
+ var maybeTeardownListener = () => {
497
+ if (!listenerInstalled) return;
498
+ if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
499
+ if (hasWindow()) window.removeEventListener("popstate", onPopState);
500
+ listenerInstalled = false;
501
+ };
502
+ var installPatch = () => {
503
+ if (patchInstalled || !hasHistory()) return;
504
+ origPushState = history.pushState;
505
+ origReplaceState = history.replaceState;
506
+ patchedPushState = function(...args) {
507
+ origPushState.apply(this, args);
508
+ if (internalDepth === 0) notifyRouteChange();
509
+ };
510
+ patchedReplaceState = function(...args) {
511
+ origReplaceState.apply(this, args);
512
+ if (internalDepth === 0) notifyRouteChange();
513
+ };
514
+ history.pushState = patchedPushState;
515
+ history.replaceState = patchedReplaceState;
516
+ patchInstalled = true;
517
+ };
518
+ var removePatch = () => {
519
+ if (!patchInstalled) return;
520
+ if (history.pushState === patchedPushState && origPushState) {
521
+ history.pushState = origPushState;
522
+ }
523
+ if (history.replaceState === patchedReplaceState && origReplaceState) {
524
+ history.replaceState = origReplaceState;
525
+ }
526
+ origPushState = null;
527
+ origReplaceState = null;
528
+ patchedPushState = null;
529
+ patchedReplaceState = null;
530
+ patchInstalled = false;
531
+ };
532
+ function onPopState() {
533
+ if (suppress > 0) {
534
+ suppress -= 1;
535
+ const rebrand = pendingRebrand;
536
+ pendingRebrand = null;
537
+ if (rebrand) rebrand();
538
+ maybeTeardownListener();
539
+ return;
540
+ }
541
+ if (entries.length === 0) {
542
+ notifyRouteChange();
543
+ maybeTeardownListener();
544
+ return;
545
+ }
546
+ let target = null;
547
+ let targetIdx = -1;
548
+ for (let i = entries.length - 1; i >= 0; i -= 1) {
549
+ const entry = entries[i];
550
+ if (!entry.surface.isOpen()) continue;
551
+ if (!target) {
552
+ target = entry;
553
+ targetIdx = i;
447
554
  }
448
- let target = null;
449
- for (let i = closers.length - 1; i >= 0; i -= 1) {
450
- const c = closers[i];
451
- if (!c.isOpen()) continue;
452
- if (!target) target = c;
453
- if (c.isTop()) {
454
- target = c;
455
- break;
456
- }
555
+ if (entry.surface.isTop()) {
556
+ target = entry;
557
+ targetIdx = i;
558
+ break;
457
559
  }
458
- if (!target) return;
459
- target.consumed = true;
460
- const idx = closers.indexOf(target);
461
- if (idx !== -1) closers.splice(idx, 1);
462
- const settled = target;
463
- void Promise.resolve(settled.close()).then(() => {
464
- if (settled.isOpen()) settled.restore();
465
- });
560
+ }
561
+ if (!target) {
562
+ const removed = entries.pop();
563
+ if (removed) removed.live = false;
564
+ maybeTeardownListener();
565
+ return;
566
+ }
567
+ target.live = false;
568
+ entries.splice(targetIdx, 1);
569
+ const settled = target;
570
+ void Promise.resolve(settled.surface.close()).then(() => {
571
+ if (settled.surface.isOpen()) restore(settled);
466
572
  });
467
- };
468
- var programmaticBack = () => {
469
- suppress += 1;
470
- try {
471
- history.back();
472
- } catch {
473
- suppress = Math.max(0, suppress - 1);
573
+ maybeTeardownListener();
574
+ }
575
+ function restore(entry) {
576
+ if (!hasWindow() || !hasHistory()) return;
577
+ entry.live = true;
578
+ runInternal(() => {
579
+ try {
580
+ history.pushState(entry.surface.markerState(), "", entry.surface.url);
581
+ } catch {
582
+ entry.live = false;
583
+ }
584
+ });
585
+ if (entry.live) {
586
+ entries.push(entry);
587
+ ensureListener();
474
588
  }
475
- };
589
+ }
590
+ function pushBackMarker(surface) {
591
+ const entry = { surface, priorUrl: void 0, live: false };
592
+ if (!hasWindow() || !hasHistory()) {
593
+ return entry;
594
+ }
595
+ entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
596
+ runInternal(() => {
597
+ try {
598
+ history.pushState(surface.markerState(), "", surface.url);
599
+ entry.live = true;
600
+ } catch {
601
+ entry.live = false;
602
+ }
603
+ });
604
+ if (entry.live) {
605
+ entries.push(entry);
606
+ ensureListener();
607
+ }
608
+ return entry;
609
+ }
610
+ function popBackMarker(handle) {
611
+ if (!hasWindow() || !hasHistory()) return;
612
+ const entry = handle;
613
+ const idx = entries.indexOf(entry);
614
+ if (idx === -1 || !entry.live) return;
615
+ const last = entries.length - 1;
616
+ entry.live = false;
617
+ entries.splice(idx, 1);
618
+ if (idx !== last) {
619
+ const rebrandSurface = entries[entries.length - 1].surface;
620
+ const rebrandUrl = entry.priorUrl;
621
+ pendingRebrand = () => {
622
+ runInternal(() => {
623
+ history.replaceState(
624
+ rebrandSurface.markerState(),
625
+ "",
626
+ rebrandUrl !== void 0 ? rebrandUrl : location.href
627
+ );
628
+ });
629
+ };
630
+ }
631
+ suppress += 1;
632
+ runInternal(() => {
633
+ try {
634
+ history.back();
635
+ } catch {
636
+ suppress = Math.max(0, suppress - 1);
637
+ pendingRebrand = null;
638
+ }
639
+ });
640
+ maybeTeardownListener();
641
+ }
642
+ function subscribeRouteChange(fn) {
643
+ if (!hasWindow() || !hasHistory()) return () => {
644
+ };
645
+ subscribers.add(fn);
646
+ if (subscribers.size === 1) installPatch();
647
+ ensureListener();
648
+ return () => {
649
+ if (!subscribers.has(fn)) return;
650
+ subscribers.delete(fn);
651
+ if (subscribers.size === 0) removePatch();
652
+ maybeTeardownListener();
653
+ };
654
+ }
655
+
656
+ // src/core/features/route.ts
476
657
  function installRoute(deps) {
477
658
  if (typeof window === "undefined") {
478
659
  return () => {
@@ -482,92 +663,39 @@ function installRoute(deps) {
482
663
  return () => {
483
664
  };
484
665
  }
485
- let pushed = false;
486
- let closer = null;
487
- const teardownEntry = () => {
488
- if (closer) {
489
- const idx = closers.indexOf(closer);
490
- if (idx !== -1) closers.splice(idx, 1);
491
- }
492
- const wasConsumed = closer?.consumed ?? false;
493
- closer = null;
494
- if (pushed && !wasConsumed) {
495
- pushed = false;
496
- programmaticBack();
497
- } else {
498
- pushed = false;
499
- }
500
- };
501
- const pushEntry = () => {
502
- try {
503
- if (deps.routedTo !== void 0) {
504
- history.pushState({ __bsRouted: deps.sheetId }, "", deps.routedTo);
505
- } else {
506
- history.pushState({ __bsSheet: deps.sheetId }, "");
507
- }
508
- pushed = true;
509
- } catch {
510
- pushed = false;
511
- }
512
- };
666
+ let handle = null;
513
667
  const onOpen = () => {
514
- if (closer) return;
515
- const self = {
668
+ if (handle) return;
669
+ handle = pushBackMarker({
516
670
  isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
517
- isTop: () => deps.isTopSheet(),
518
- close: () => deps.close(),
519
- restore: () => {
520
- if (deps.isDestroyed() || closer !== self) return;
521
- self.consumed = false;
522
- if (!closers.includes(self)) closers.push(self);
523
- pushEntry();
524
- },
525
- consumed: false
526
- };
527
- closer = self;
528
- ensureHandler();
529
- closers.push(self);
530
- pushEntry();
671
+ isTop: deps.isTopSheet,
672
+ close: deps.close,
673
+ markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
674
+ url: deps.routedTo
675
+ });
676
+ };
677
+ const onClose = () => {
678
+ if (!handle) return;
679
+ popBackMarker(handle);
680
+ handle = null;
531
681
  };
532
682
  const unsubscribeOpen = deps.on("open", onOpen);
533
- const unsubscribeClose = deps.on("close", teardownEntry);
683
+ const unsubscribeClose = deps.on("close", onClose);
534
684
  if (deps.getSize() > 0) onOpen();
535
685
  return () => {
536
686
  unsubscribeOpen();
537
687
  unsubscribeClose();
538
- teardownEntry();
688
+ if (handle) {
689
+ popBackMarker(handle);
690
+ handle = null;
691
+ }
539
692
  };
540
693
  }
541
694
  function installRouteChange(deps) {
542
- if (typeof window === "undefined" || typeof history === "undefined") {
543
- return () => {
544
- };
545
- }
546
- const onChange = () => {
695
+ return subscribeRouteChange(() => {
547
696
  if (deps.isDestroyed() || deps.getSize() <= 0) return;
548
697
  void deps.close();
549
- };
550
- const wrap = (key) => {
551
- const original = history[key];
552
- const patched = function(...args) {
553
- original.apply(this, args);
554
- onChange();
555
- };
556
- history[key] = patched;
557
- return () => {
558
- if (history[key] === patched) {
559
- history[key] = original;
560
- }
561
- };
562
- };
563
- window.addEventListener("popstate", onChange);
564
- const restorePush = wrap("pushState");
565
- const restoreReplace = wrap("replaceState");
566
- return () => {
567
- window.removeEventListener("popstate", onChange);
568
- restorePush();
569
- restoreReplace();
570
- };
698
+ });
571
699
  }
572
700
 
573
701
  // src/core/features/content-swipe.ts
@@ -638,11 +766,15 @@ function installVisualViewport(deps) {
638
766
  if (clamp < deps.getMaxAxisSize()) {
639
767
  deps.setMaxAxisSize(clamp);
640
768
  }
769
+ const wasAnimating = deps.isAnimating?.() ?? false;
770
+ deps.cancelInFlight();
771
+ deps.newCycle();
641
772
  const max = deps.getMaxAxisSize();
642
773
  deps.setSize(Math.min(deps.getSize(), max));
643
774
  const current = deps.resolveActiveSnap();
644
775
  if (current && !deps.isDragging()) {
645
776
  deps.applySize(Math.min(current.size, max));
777
+ if (wasAnimating) deps.resyncAfterCancel?.();
646
778
  } else {
647
779
  deps.applySize(deps.getSize());
648
780
  }
@@ -783,6 +915,54 @@ function installFitObserver(deps) {
783
915
  };
784
916
  }
785
917
 
918
+ // src/core/features/max-height-controller.ts
919
+ function createMaxHeightController(deps) {
920
+ let maxHeightCap;
921
+ let maxHeightRaw;
922
+ const resolveCap = () => {
923
+ const raw = maxHeightRaw;
924
+ if (raw === void 0) {
925
+ maxHeightCap = void 0;
926
+ return;
927
+ }
928
+ if (typeof raw === "number") {
929
+ maxHeightCap = raw;
930
+ return;
931
+ }
932
+ if (typeof window === "undefined") return;
933
+ const measured = resolveSnap(raw, deps.mode);
934
+ maxHeightCap = measured > 0 ? measured : void 0;
935
+ };
936
+ const clampTo = () => {
937
+ if (maxHeightCap === void 0) return;
938
+ if (deps.getMaxAxisSize() > maxHeightCap) {
939
+ deps.setMaxAxisSize(maxHeightCap);
940
+ }
941
+ };
942
+ return {
943
+ setRadius(r) {
944
+ deps.element.style.setProperty(
945
+ "--bs-radius",
946
+ typeof r === "number" ? `${r}px` : r
947
+ );
948
+ },
949
+ setMaxHeight(h) {
950
+ const value = typeof h === "number" ? `${h}px` : h;
951
+ const axis = layoutAxis(deps.mode);
952
+ deps.element.style.setProperty(
953
+ axis === "height" ? "max-height" : "max-width",
954
+ value
955
+ );
956
+ maxHeightRaw = h;
957
+ resolveCap();
958
+ deps.recompute();
959
+ },
960
+ resolveCap,
961
+ clampTo,
962
+ getCap: () => maxHeightCap
963
+ };
964
+ }
965
+
786
966
  // src/core/features/fit-measurement.ts
787
967
  var measureSheetNatural = (element, content, vertical) => {
788
968
  if (!content) {
@@ -914,13 +1094,6 @@ var WriteSentinel = class {
914
1094
  }
915
1095
  };
916
1096
 
917
- // src/core/primitives/devWarn.ts
918
- function devWarn(...args) {
919
- if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
920
- console.warn(...args);
921
- }
922
- }
923
-
924
1097
  // src/core/primitives/overlay-position.ts
925
1098
  function resolveSheetAnchoredStyle(mode, position, inset) {
926
1099
  const sizeOffset = `calc(var(--bs-size, 0px) + ${inset})`;
@@ -2375,7 +2548,7 @@ var matchesRange = (def, progress) => {
2375
2548
  };
2376
2549
  function installScrimStages(deps, opts) {
2377
2550
  const doc = deps.host.ownerDocument;
2378
- const entries = opts.stages.map((def) => {
2551
+ const entries2 = opts.stages.map((def) => {
2379
2552
  const wrapper = doc.createElement("div");
2380
2553
  wrapper.className = "bs-scrim-stage";
2381
2554
  const ws = wrapper.style;
@@ -2396,9 +2569,9 @@ function installScrimStages(deps, opts) {
2396
2569
  const resolveActive = () => {
2397
2570
  const state2 = deps.getState();
2398
2571
  if (state2.size === 0) {
2399
- return entries.find((e) => matchesId(e.def, state2.activeId)) ?? null;
2572
+ return entries2.find((e) => matchesId(e.def, state2.activeId)) ?? null;
2400
2573
  }
2401
- return entries.find((e) => matchesId(e.def, state2.activeId)) ?? entries.find((e) => matchesRange(e.def, state2.progress)) ?? null;
2574
+ return entries2.find((e) => matchesId(e.def, state2.activeId)) ?? entries2.find((e) => matchesRange(e.def, state2.progress)) ?? null;
2402
2575
  };
2403
2576
  const hide = (entry, animate) => {
2404
2577
  entry.inFlight?.cancel();
@@ -2447,13 +2620,13 @@ function installScrimStages(deps, opts) {
2447
2620
  deps.on("open", () => update(true)),
2448
2621
  deps.on("close", () => update(true))
2449
2622
  ];
2450
- if (entries.some((e) => e.def.forRange)) {
2623
+ if (entries2.some((e) => e.def.forRange)) {
2451
2624
  offs.push(deps.on("progress", () => update(true)));
2452
2625
  }
2453
2626
  update(false);
2454
2627
  return () => {
2455
2628
  offs.forEach((off) => off());
2456
- for (const entry of entries) {
2629
+ for (const entry of entries2) {
2457
2630
  entry.inFlight?.cancel();
2458
2631
  entry.inFlight = null;
2459
2632
  if (entry.wrapper.parentNode) {
@@ -2566,8 +2739,7 @@ var BottomSheetEngine = class {
2566
2739
  __publicField(this, "disableCloseFlag");
2567
2740
  __publicField(this, "disableDragFlag");
2568
2741
  __publicField(this, "closeOnRouteChange");
2569
- __publicField(this, "maxHeightCap");
2570
- __publicField(this, "maxHeightRaw");
2742
+ __publicField(this, "maxHeight");
2571
2743
  __publicField(this, "snapPointsRaw");
2572
2744
  __publicField(this, "snaps");
2573
2745
  __publicField(this, "activeId");
@@ -2678,11 +2850,20 @@ var BottomSheetEngine = class {
2678
2850
  auditVhUsage(this.snapPointsRaw);
2679
2851
  this.auditDuplicateSnapIds(this.snapPointsRaw);
2680
2852
  this.rootEl = this.element.closest(".bs-root");
2853
+ this.maxHeight = createMaxHeightController({
2854
+ element: this.element,
2855
+ mode: this.mode,
2856
+ getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
2857
+ setMaxAxisSize: (size) => {
2858
+ this.snaps.setMaxAxisSize(size);
2859
+ },
2860
+ recompute: () => this.recompute()
2861
+ });
2681
2862
  this.fitDeps = {
2682
2863
  element: this.element,
2683
2864
  scrollContainer: this.scrollContainer,
2684
2865
  mode: this.mode,
2685
- getMaxHeightCap: () => this.maxHeightCap
2866
+ getMaxHeightCap: () => this.maxHeight.getCap()
2686
2867
  };
2687
2868
  this.snaps = new SnapResolver(
2688
2869
  this.snapPointsRaw,
@@ -2704,8 +2885,8 @@ var BottomSheetEngine = class {
2704
2885
  this.attach();
2705
2886
  this.registerInStack();
2706
2887
  if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
2707
- const io = new IntersectionObserver((entries) => {
2708
- for (const entry of entries) {
2888
+ const io = new IntersectionObserver((entries2) => {
2889
+ for (const entry of entries2) {
2709
2890
  if (!entry.isIntersecting) continue;
2710
2891
  if (this.destroyed) return;
2711
2892
  this.snaps.recompute();
@@ -2793,7 +2974,7 @@ var BottomSheetEngine = class {
2793
2974
  }
2794
2975
  use(plugin) {
2795
2976
  if (this.destroyed) {
2796
- console.warn(
2977
+ devWarn(
2797
2978
  `[BottomSheet] use("${plugin.name}") called on destroyed engine \u2014 ignored.`
2798
2979
  );
2799
2980
  return this;
@@ -2835,6 +3016,9 @@ var BottomSheetEngine = class {
2835
3016
  getAllowedIds() {
2836
3017
  return this.snaps.getAllowedIds().slice();
2837
3018
  }
3019
+ getResolvedSnaps() {
3020
+ return this.snaps.getResolvedSnaps();
3021
+ }
2838
3022
  async snapTo(id, velocityOrOpts = 0, _skipBeforeSnap = false) {
2839
3023
  if (this.destroyed) return;
2840
3024
  const opts = typeof velocityOrOpts === "object" ? velocityOrOpts : { velocity: velocityOrOpts };
@@ -2843,11 +3027,11 @@ var BottomSheetEngine = class {
2843
3027
  if (externalSignal?.aborted) return;
2844
3028
  const target = this.snaps.findById(id);
2845
3029
  if (!target) {
2846
- console.warn(`[BottomSheet] unknown snap id: ${id}`);
3030
+ devWarn(`[BottomSheet] unknown snap id: ${id}`);
2847
3031
  return;
2848
3032
  }
2849
3033
  if (!this.snaps.getAllowedIds().includes(id)) {
2850
- console.warn(`[BottomSheet] snap "${id}" is not in allowed list`);
3034
+ devWarn(`[BottomSheet] snap "${id}" is not in allowed list`);
2851
3035
  return;
2852
3036
  }
2853
3037
  if (!_skipBeforeSnap && this.emitBeforeSnap(target, this.activeId)) {
@@ -2979,42 +3163,11 @@ var BottomSheetEngine = class {
2979
3163
  }
2980
3164
  setRadius(r) {
2981
3165
  if (this.destroyed) return;
2982
- this.element.style.setProperty(
2983
- "--bs-radius",
2984
- typeof r === "number" ? `${r}px` : r
2985
- );
3166
+ this.maxHeight.setRadius(r);
2986
3167
  }
2987
3168
  setMaxHeight(h) {
2988
3169
  if (this.destroyed) return;
2989
- const value = typeof h === "number" ? `${h}px` : h;
2990
- const axis = layoutAxis(this.mode);
2991
- this.element.style.setProperty(
2992
- axis === "height" ? "max-height" : "max-width",
2993
- value
2994
- );
2995
- this.maxHeightRaw = h;
2996
- this.resolveMaxHeightCap();
2997
- this.recompute();
2998
- }
2999
- resolveMaxHeightCap() {
3000
- const raw = this.maxHeightRaw;
3001
- if (raw === void 0) {
3002
- this.maxHeightCap = void 0;
3003
- return;
3004
- }
3005
- if (typeof raw === "number") {
3006
- this.maxHeightCap = raw;
3007
- return;
3008
- }
3009
- if (typeof window === "undefined") return;
3010
- const measured = resolveSnap(raw, this.mode);
3011
- this.maxHeightCap = measured > 0 ? measured : void 0;
3012
- }
3013
- clampToMaxHeight() {
3014
- if (this.maxHeightCap === void 0) return;
3015
- if (this.snaps.getMaxAxisSize() > this.maxHeightCap) {
3016
- this.snaps.setMaxAxisSize(this.maxHeightCap);
3017
- }
3170
+ this.maxHeight.setMaxHeight(h);
3018
3171
  }
3019
3172
  setAllowed(ids, snap) {
3020
3173
  if (this.destroyed) return;
@@ -3102,7 +3255,7 @@ var BottomSheetEngine = class {
3102
3255
  };
3103
3256
  const host = this.screenComponent?.parentElement;
3104
3257
  if (!host) {
3105
- console.warn(
3258
+ devWarn(
3106
3259
  "[BottomSheet] setScrimStages: no scrim element mounted \u2014 pass `scrim` to the engine first."
3107
3260
  );
3108
3261
  return () => {
@@ -3152,9 +3305,9 @@ var BottomSheetEngine = class {
3152
3305
  }
3153
3306
  recompute() {
3154
3307
  if (this.destroyed) return;
3155
- this.resolveMaxHeightCap();
3308
+ this.maxHeight.resolveCap();
3156
3309
  this.snaps.recompute();
3157
- this.clampToMaxHeight();
3310
+ this.maxHeight.clampTo();
3158
3311
  this.scrim.invalidateOpacityCache();
3159
3312
  if (this.gesture?.isDragging) return;
3160
3313
  const current = this.snaps.findById(this.activeId);
@@ -3204,42 +3357,18 @@ var BottomSheetEngine = class {
3204
3357
  return this.currentAbort.signal;
3205
3358
  }
3206
3359
  emitBeforeSnap(target, previousId) {
3207
- let cancelled = false;
3208
- let frozen = false;
3209
- this.emit("before-snap", {
3210
- id: target.id,
3211
- size: target.size,
3212
- previousId,
3213
- cancel: () => {
3214
- if (frozen) {
3215
- console.warn(
3216
- "[BottomSheet] before-snap.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener."
3217
- );
3218
- return;
3219
- }
3220
- cancelled = true;
3221
- }
3222
- });
3223
- frozen = true;
3224
- return cancelled;
3360
+ return emitCancelable(
3361
+ (payload) => this.emit("before-snap", payload),
3362
+ { id: target.id, size: target.size, previousId },
3363
+ "before-snap"
3364
+ );
3225
3365
  }
3226
3366
  emitBeforeClose(reason) {
3227
- let cancelled = false;
3228
- let frozen = false;
3229
- this.emit("before-close", {
3230
- reason,
3231
- cancel: () => {
3232
- if (frozen) {
3233
- console.warn(
3234
- "[BottomSheet] before-close.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener."
3235
- );
3236
- return;
3237
- }
3238
- cancelled = true;
3239
- }
3240
- });
3241
- frozen = true;
3242
- return cancelled;
3367
+ return emitCancelable(
3368
+ (payload) => this.emit("before-close", payload),
3369
+ { reason },
3370
+ "before-close"
3371
+ );
3243
3372
  }
3244
3373
  applyAutoAriaLabelledBy() {
3245
3374
  if (typeof document === "undefined") return;
@@ -3254,16 +3383,16 @@ var BottomSheetEngine = class {
3254
3383
  this.element.setAttribute("aria-labelledby", titled.id);
3255
3384
  }
3256
3385
  recomputeSnaps() {
3257
- this.resolveMaxHeightCap();
3386
+ this.maxHeight.resolveCap();
3258
3387
  this.snaps.setRaw(this.snapPointsRaw);
3259
- this.clampToMaxHeight();
3388
+ this.maxHeight.clampTo();
3260
3389
  this.scrim.invalidateOpacityCache();
3261
3390
  }
3262
3391
  auditDuplicateSnapIds(points) {
3263
3392
  const seen = /* @__PURE__ */ new Set();
3264
3393
  for (const p of points) {
3265
3394
  if (seen.has(p.id)) {
3266
- console.warn(
3395
+ devWarn(
3267
3396
  `[BottomSheet] duplicate snap id "${p.id}" \u2014 only the first occurrence is reachable.`
3268
3397
  );
3269
3398
  }
@@ -3430,7 +3559,15 @@ var BottomSheetEngine = class {
3430
3559
  setSize: (size) => {
3431
3560
  this.size = size;
3432
3561
  },
3433
- applySize: (size) => this.applySize(size)
3562
+ applySize: (size) => this.applySize(size),
3563
+ cancelInFlight: () => {
3564
+ this.animation.cancel();
3565
+ },
3566
+ newCycle: () => {
3567
+ this.newCycle();
3568
+ },
3569
+ isAnimating: () => this.animation.isAnimating,
3570
+ resyncAfterCancel: () => this.resyncAfterResize()
3434
3571
  }));
3435
3572
  }
3436
3573
  this.teardowns.add(installSliderKeyboard({
@@ -3466,9 +3603,9 @@ var BottomSheetEngine = class {
3466
3603
  return;
3467
3604
  }
3468
3605
  if (this.emitBeforeSnap(target, previousId)) {
3469
- const restore = this.snaps.findById(previousId);
3470
- if (restore) {
3471
- void this.animation.animateTo(restore.size, 0);
3606
+ const restore2 = this.snaps.findById(previousId);
3607
+ if (restore2) {
3608
+ void this.animation.animateTo(restore2.size, 0);
3472
3609
  }
3473
3610
  return;
3474
3611
  }
@@ -3706,12 +3843,12 @@ function createBottomSheet(opts) {
3706
3843
  getEngine: () => engine
3707
3844
  };
3708
3845
  }
3709
- var root_1 = $2__namespace.from_html(`<div class="bs-backdrop" aria-hidden="true"></div>`);
3710
- var root_3 = $2__namespace.from_html(`<div class="bs-header"><!></div>`);
3711
- var root_5 = $2__namespace.from_html(`<div class="bs-footer"><!></div>`);
3712
- var root_6 = $2__namespace.from_html(`<div class="bs-button-slot" data-side="left"><!></div>`);
3713
- var root_7 = $2__namespace.from_html(`<div class="bs-button-slot" data-side="right"><!></div>`);
3714
- var root = $2__namespace.from_html(`<div class="bs-root"><!> <div class="bs-screen"><!></div> <section class="bs-sheet" role="dialog"><div class="bs-handle" role="slider" tabindex="0" aria-label="Resize sheet" aria-valuemin="0" aria-valuemax="0" aria-valuenow="0"></div> <!> <div class="bs-content" tabindex="0" role="region" aria-label="Sheet content"><!></div> <!> <span class="bs-sr-only" role="status" aria-live="polite"> </span></section> <!> <!></div>`);
3846
+ var root = $2__namespace.from_html(`<div class="bs-backdrop" aria-hidden="true"></div>`);
3847
+ var root_1 = $2__namespace.from_html(`<div class="bs-header"><!></div>`);
3848
+ var root_2 = $2__namespace.from_html(`<div class="bs-footer"><!></div>`);
3849
+ var root_3 = $2__namespace.from_html(`<div class="bs-button-slot" data-side="left"><!></div>`);
3850
+ var root_4 = $2__namespace.from_html(`<div class="bs-button-slot" data-side="right"><!></div>`);
3851
+ var root_5 = $2__namespace.from_html(`<div class="bs-root"><!> <div class="bs-screen"><!></div> <section class="bs-sheet" role="dialog"><div class="bs-handle" role="slider" tabindex="0" aria-label="Resize sheet" aria-valuemin="0" aria-valuemax="0" aria-valuenow="0"></div> <!> <div class="bs-content" tabindex="0" role="region" aria-label="Sheet content"><!></div> <!> <span class="bs-sr-only" role="status" aria-live="polite"> </span></section> <!> <!></div>`);
3715
3852
  function BottomSheet($$anchor, $$props) {
3716
3853
  $2__namespace.push($$props, true);
3717
3854
  let mode = $2__namespace.prop($$props, "mode", 3, "bottom"), animation = $2__namespace.prop($$props, "animation", 3, "spring"), focusTrap = $2__namespace.prop($$props, "focusTrap", 3, false), closeOnEscape = $2__namespace.prop($$props, "closeOnEscape", 3, true), closeOnBack = $2__namespace.prop($$props, "closeOnBack", 3, false), lockBodyScroll2 = $2__namespace.prop($$props, "lockBodyScroll", 3, true), rubberBand2 = $2__namespace.prop($$props, "rubberBand", 3, true), backdrop = $2__namespace.prop($$props, "backdrop", 3, true), closeOnBackdrop = $2__namespace.prop($$props, "closeOnBackdrop", 3, true), persistent = $2__namespace.prop($$props, "persistent", 3, false), disableClose = $2__namespace.prop($$props, "disableClose", 3, false), disableDrag = $2__namespace.prop($$props, "disableDrag", 3, false), closeOnRouteChange = $2__namespace.prop($$props, "closeOnRouteChange", 3, false), stackEffect = $2__namespace.prop($$props, "stackEffect", 3, false), teleport = $2__namespace.prop($$props, "teleport", 3, false), openProp = $2__namespace.prop($$props, "open", 15), snap = $2__namespace.prop($$props, "snap", 15), ariaLabel = $2__namespace.prop($$props, "ariaLabel", 3, "Bottom sheet");
@@ -3795,6 +3932,8 @@ function BottomSheet($$anchor, $$props) {
3795
3932
  sync();
3796
3933
  $$props.ondragend?.();
3797
3934
  });
3935
+ if ($$props.ondrag) engine.on("drag", (payload) => $$props.ondrag(payload));
3936
+ if ($$props.onprogress) engine.on("progress", (payload) => $$props.onprogress(payload));
3798
3937
  });
3799
3938
  svelte.onDestroy(() => {
3800
3939
  restoreTeleport?.();
@@ -3891,11 +4030,11 @@ function BottomSheet($$anchor, $$props) {
3891
4030
  getState,
3892
4031
  getEngine
3893
4032
  };
3894
- var div = root();
4033
+ var div = root_5();
3895
4034
  var node = $2__namespace.child(div);
3896
4035
  {
3897
4036
  var consequent = ($$anchor2) => {
3898
- var div_1 = root_1();
4037
+ var div_1 = root();
3899
4038
  $2__namespace.bind_this(div_1, ($$value) => $2__namespace.set(backdropEl, $$value), () => $2__namespace.get(backdropEl));
3900
4039
  $2__namespace.delegated("click", div_1, function(...$$args) {
3901
4040
  (closeOnBackdrop() ? () => {
@@ -3929,7 +4068,7 @@ function BottomSheet($$anchor, $$props) {
3929
4068
  var node_3 = $2__namespace.sibling(div_3, 2);
3930
4069
  {
3931
4070
  var consequent_2 = ($$anchor2) => {
3932
- var div_4 = root_3();
4071
+ var div_4 = root_1();
3933
4072
  var node_4 = $2__namespace.child(div_4);
3934
4073
  $2__namespace.snippet(node_4, () => $$props.header, () => $2__namespace.get(viewState));
3935
4074
  $2__namespace.reset(div_4);
@@ -3957,7 +4096,7 @@ function BottomSheet($$anchor, $$props) {
3957
4096
  var node_7 = $2__namespace.sibling(div_5, 2);
3958
4097
  {
3959
4098
  var consequent_4 = ($$anchor2) => {
3960
- var div_6 = root_5();
4099
+ var div_6 = root_2();
3961
4100
  var node_8 = $2__namespace.child(div_6);
3962
4101
  $2__namespace.snippet(node_8, () => $$props.footer, () => $2__namespace.get(viewState));
3963
4102
  $2__namespace.reset(div_6);
@@ -3975,7 +4114,7 @@ function BottomSheet($$anchor, $$props) {
3975
4114
  var node_9 = $2__namespace.sibling(section, 2);
3976
4115
  {
3977
4116
  var consequent_5 = ($$anchor2) => {
3978
- var div_7 = root_6();
4117
+ var div_7 = root_3();
3979
4118
  var node_10 = $2__namespace.child(div_7);
3980
4119
  $2__namespace.snippet(node_10, () => $$props.leftButton);
3981
4120
  $2__namespace.reset(div_7);
@@ -3989,7 +4128,7 @@ function BottomSheet($$anchor, $$props) {
3989
4128
  var node_11 = $2__namespace.sibling(node_9, 2);
3990
4129
  {
3991
4130
  var consequent_6 = ($$anchor2) => {
3992
- var div_8 = root_7();
4131
+ var div_8 = root_4();
3993
4132
  var node_12 = $2__namespace.child(div_8);
3994
4133
  $2__namespace.snippet(node_12, () => $$props.rightButton);
3995
4134
  $2__namespace.reset(div_8);