@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/vue.cjs CHANGED
@@ -185,11 +185,18 @@ var resolveSnap = (point, mode, measureFit) => {
185
185
  return Math.max(0, el.getBoundingClientRect().width);
186
186
  };
187
187
 
188
+ // src/core/primitives/devWarn.ts
189
+ function devWarn(...args) {
190
+ if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
191
+ console.warn(...args);
192
+ }
193
+ }
194
+
188
195
  // src/core/primitives/snap-points.ts
189
196
  var resolveSnapList = (points, mode, measureFit) => points.map((p) => {
190
197
  const raw = resolveSnap(p.size, mode, measureFit);
191
198
  if (!Number.isFinite(raw) || raw < 0) {
192
- console.warn(
199
+ devWarn(
193
200
  `[BottomSheet] snap "${p.id}" resolved to invalid size (${String(p.size)} \u2192 ${raw}); clamped to 0.`
194
201
  );
195
202
  return { id: p.id, size: 0 };
@@ -201,7 +208,7 @@ var auditVhUsage = (points) => {
201
208
  for (const p of points) {
202
209
  if (typeof p.size !== "string") continue;
203
210
  if (!VH_NOT_DVH.test(p.size)) continue;
204
- console.warn(
211
+ devWarn(
205
212
  `[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`
206
213
  );
207
214
  }
@@ -255,6 +262,26 @@ var findDragSettleTarget = (input) => {
255
262
  );
256
263
  };
257
264
 
265
+ // src/core/primitives/cancelable-emit.ts
266
+ function emitCancelable(emit, base, warnLabel) {
267
+ let cancelled = false;
268
+ let frozen = false;
269
+ emit({
270
+ ...base,
271
+ cancel: () => {
272
+ if (frozen) {
273
+ devWarn(
274
+ `[BottomSheet] ${warnLabel}.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener.`
275
+ );
276
+ return;
277
+ }
278
+ cancelled = true;
279
+ }
280
+ });
281
+ frozen = true;
282
+ return cancelled;
283
+ }
284
+
258
285
  // src/core/primitives/snap-resolver.ts
259
286
  var SnapResolver = class {
260
287
  constructor(raw, allowed, mode, measureFit, onMaxAxisSizeChange) {
@@ -399,7 +426,9 @@ function notifyLinkedSheets(sheets, self) {
399
426
  try {
400
427
  if (linked.state.size === 0) continue;
401
428
  const ids = linked.getAllowedIds();
402
- const target = ids.find((id) => id !== "closed");
429
+ const resolved = linked.getResolvedSnaps();
430
+ const sizeOf = (id) => resolved.find((s) => s.id === id)?.size ?? 0;
431
+ const target = ids.find((id) => sizeOf(id) > 0);
403
432
  if (target && target !== linked.state.activeId) {
404
433
  void linked.snapTo(target);
405
434
  }
@@ -411,46 +440,198 @@ function notifyLinkedSheets(sheets, self) {
411
440
  }
412
441
  }
413
442
 
414
- // src/core/features/route.ts
415
- var closers = [];
416
- var handlerInstalled = false;
443
+ // src/core/features/history-coordinator.ts
444
+ var entries = [];
445
+ var subscribers = /* @__PURE__ */ new Set();
417
446
  var suppress = 0;
418
- var ensureHandler = () => {
419
- if (handlerInstalled || typeof window === "undefined") return;
420
- handlerInstalled = true;
421
- window.addEventListener("popstate", () => {
422
- if (suppress > 0) {
423
- suppress -= 1;
424
- return;
447
+ var internalDepth = 0;
448
+ var pendingRebrand = null;
449
+ var listenerInstalled = false;
450
+ var patchInstalled = false;
451
+ var origPushState = null;
452
+ var origReplaceState = null;
453
+ var patchedPushState = null;
454
+ var patchedReplaceState = null;
455
+ var hasWindow = () => typeof window !== "undefined";
456
+ var hasHistory = () => typeof history !== "undefined";
457
+ var runInternal = (fn) => {
458
+ internalDepth += 1;
459
+ try {
460
+ fn();
461
+ } finally {
462
+ internalDepth -= 1;
463
+ }
464
+ };
465
+ var notifyRouteChange = () => {
466
+ const snapshot = Array.from(subscribers);
467
+ for (const fn of snapshot) fn();
468
+ };
469
+ var ensureListener = () => {
470
+ if (listenerInstalled || !hasWindow()) return;
471
+ window.addEventListener("popstate", onPopState);
472
+ listenerInstalled = true;
473
+ };
474
+ var maybeTeardownListener = () => {
475
+ if (!listenerInstalled) return;
476
+ if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
477
+ if (hasWindow()) window.removeEventListener("popstate", onPopState);
478
+ listenerInstalled = false;
479
+ };
480
+ var installPatch = () => {
481
+ if (patchInstalled || !hasHistory()) return;
482
+ origPushState = history.pushState;
483
+ origReplaceState = history.replaceState;
484
+ patchedPushState = function(...args) {
485
+ origPushState.apply(this, args);
486
+ if (internalDepth === 0) notifyRouteChange();
487
+ };
488
+ patchedReplaceState = function(...args) {
489
+ origReplaceState.apply(this, args);
490
+ if (internalDepth === 0) notifyRouteChange();
491
+ };
492
+ history.pushState = patchedPushState;
493
+ history.replaceState = patchedReplaceState;
494
+ patchInstalled = true;
495
+ };
496
+ var removePatch = () => {
497
+ if (!patchInstalled) return;
498
+ if (history.pushState === patchedPushState && origPushState) {
499
+ history.pushState = origPushState;
500
+ }
501
+ if (history.replaceState === patchedReplaceState && origReplaceState) {
502
+ history.replaceState = origReplaceState;
503
+ }
504
+ origPushState = null;
505
+ origReplaceState = null;
506
+ patchedPushState = null;
507
+ patchedReplaceState = null;
508
+ patchInstalled = false;
509
+ };
510
+ function onPopState() {
511
+ if (suppress > 0) {
512
+ suppress -= 1;
513
+ const rebrand = pendingRebrand;
514
+ pendingRebrand = null;
515
+ if (rebrand) rebrand();
516
+ maybeTeardownListener();
517
+ return;
518
+ }
519
+ if (entries.length === 0) {
520
+ notifyRouteChange();
521
+ maybeTeardownListener();
522
+ return;
523
+ }
524
+ let target = null;
525
+ let targetIdx = -1;
526
+ for (let i = entries.length - 1; i >= 0; i -= 1) {
527
+ const entry = entries[i];
528
+ if (!entry.surface.isOpen()) continue;
529
+ if (!target) {
530
+ target = entry;
531
+ targetIdx = i;
425
532
  }
426
- let target = null;
427
- for (let i = closers.length - 1; i >= 0; i -= 1) {
428
- const c = closers[i];
429
- if (!c.isOpen()) continue;
430
- if (!target) target = c;
431
- if (c.isTop()) {
432
- target = c;
433
- break;
434
- }
533
+ if (entry.surface.isTop()) {
534
+ target = entry;
535
+ targetIdx = i;
536
+ break;
435
537
  }
436
- if (!target) return;
437
- target.consumed = true;
438
- const idx = closers.indexOf(target);
439
- if (idx !== -1) closers.splice(idx, 1);
440
- const settled = target;
441
- void Promise.resolve(settled.close()).then(() => {
442
- if (settled.isOpen()) settled.restore();
443
- });
538
+ }
539
+ if (!target) {
540
+ const removed = entries.pop();
541
+ if (removed) removed.live = false;
542
+ maybeTeardownListener();
543
+ return;
544
+ }
545
+ target.live = false;
546
+ entries.splice(targetIdx, 1);
547
+ const settled = target;
548
+ void Promise.resolve(settled.surface.close()).then(() => {
549
+ if (settled.surface.isOpen()) restore(settled);
444
550
  });
445
- };
446
- var programmaticBack = () => {
447
- suppress += 1;
448
- try {
449
- history.back();
450
- } catch {
451
- suppress = Math.max(0, suppress - 1);
551
+ maybeTeardownListener();
552
+ }
553
+ function restore(entry) {
554
+ if (!hasWindow() || !hasHistory()) return;
555
+ entry.live = true;
556
+ runInternal(() => {
557
+ try {
558
+ history.pushState(entry.surface.markerState(), "", entry.surface.url);
559
+ } catch {
560
+ entry.live = false;
561
+ }
562
+ });
563
+ if (entry.live) {
564
+ entries.push(entry);
565
+ ensureListener();
452
566
  }
453
- };
567
+ }
568
+ function pushBackMarker(surface) {
569
+ const entry = { surface, priorUrl: void 0, live: false };
570
+ if (!hasWindow() || !hasHistory()) {
571
+ return entry;
572
+ }
573
+ entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
574
+ runInternal(() => {
575
+ try {
576
+ history.pushState(surface.markerState(), "", surface.url);
577
+ entry.live = true;
578
+ } catch {
579
+ entry.live = false;
580
+ }
581
+ });
582
+ if (entry.live) {
583
+ entries.push(entry);
584
+ ensureListener();
585
+ }
586
+ return entry;
587
+ }
588
+ function popBackMarker(handle) {
589
+ if (!hasWindow() || !hasHistory()) return;
590
+ const entry = handle;
591
+ const idx = entries.indexOf(entry);
592
+ if (idx === -1 || !entry.live) return;
593
+ const last = entries.length - 1;
594
+ entry.live = false;
595
+ entries.splice(idx, 1);
596
+ if (idx !== last) {
597
+ const rebrandSurface = entries[entries.length - 1].surface;
598
+ const rebrandUrl = entry.priorUrl;
599
+ pendingRebrand = () => {
600
+ runInternal(() => {
601
+ history.replaceState(
602
+ rebrandSurface.markerState(),
603
+ "",
604
+ rebrandUrl !== void 0 ? rebrandUrl : location.href
605
+ );
606
+ });
607
+ };
608
+ }
609
+ suppress += 1;
610
+ runInternal(() => {
611
+ try {
612
+ history.back();
613
+ } catch {
614
+ suppress = Math.max(0, suppress - 1);
615
+ pendingRebrand = null;
616
+ }
617
+ });
618
+ maybeTeardownListener();
619
+ }
620
+ function subscribeRouteChange(fn) {
621
+ if (!hasWindow() || !hasHistory()) return () => {
622
+ };
623
+ subscribers.add(fn);
624
+ if (subscribers.size === 1) installPatch();
625
+ ensureListener();
626
+ return () => {
627
+ if (!subscribers.has(fn)) return;
628
+ subscribers.delete(fn);
629
+ if (subscribers.size === 0) removePatch();
630
+ maybeTeardownListener();
631
+ };
632
+ }
633
+
634
+ // src/core/features/route.ts
454
635
  function installRoute(deps) {
455
636
  if (typeof window === "undefined") {
456
637
  return () => {
@@ -460,92 +641,39 @@ function installRoute(deps) {
460
641
  return () => {
461
642
  };
462
643
  }
463
- let pushed = false;
464
- let closer = null;
465
- const teardownEntry = () => {
466
- if (closer) {
467
- const idx = closers.indexOf(closer);
468
- if (idx !== -1) closers.splice(idx, 1);
469
- }
470
- const wasConsumed = closer?.consumed ?? false;
471
- closer = null;
472
- if (pushed && !wasConsumed) {
473
- pushed = false;
474
- programmaticBack();
475
- } else {
476
- pushed = false;
477
- }
478
- };
479
- const pushEntry = () => {
480
- try {
481
- if (deps.routedTo !== void 0) {
482
- history.pushState({ __bsRouted: deps.sheetId }, "", deps.routedTo);
483
- } else {
484
- history.pushState({ __bsSheet: deps.sheetId }, "");
485
- }
486
- pushed = true;
487
- } catch {
488
- pushed = false;
489
- }
490
- };
644
+ let handle = null;
491
645
  const onOpen = () => {
492
- if (closer) return;
493
- const self = {
646
+ if (handle) return;
647
+ handle = pushBackMarker({
494
648
  isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
495
- isTop: () => deps.isTopSheet(),
496
- close: () => deps.close(),
497
- restore: () => {
498
- if (deps.isDestroyed() || closer !== self) return;
499
- self.consumed = false;
500
- if (!closers.includes(self)) closers.push(self);
501
- pushEntry();
502
- },
503
- consumed: false
504
- };
505
- closer = self;
506
- ensureHandler();
507
- closers.push(self);
508
- pushEntry();
649
+ isTop: deps.isTopSheet,
650
+ close: deps.close,
651
+ markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
652
+ url: deps.routedTo
653
+ });
654
+ };
655
+ const onClose = () => {
656
+ if (!handle) return;
657
+ popBackMarker(handle);
658
+ handle = null;
509
659
  };
510
660
  const unsubscribeOpen = deps.on("open", onOpen);
511
- const unsubscribeClose = deps.on("close", teardownEntry);
661
+ const unsubscribeClose = deps.on("close", onClose);
512
662
  if (deps.getSize() > 0) onOpen();
513
663
  return () => {
514
664
  unsubscribeOpen();
515
665
  unsubscribeClose();
516
- teardownEntry();
666
+ if (handle) {
667
+ popBackMarker(handle);
668
+ handle = null;
669
+ }
517
670
  };
518
671
  }
519
672
  function installRouteChange(deps) {
520
- if (typeof window === "undefined" || typeof history === "undefined") {
521
- return () => {
522
- };
523
- }
524
- const onChange = () => {
673
+ return subscribeRouteChange(() => {
525
674
  if (deps.isDestroyed() || deps.getSize() <= 0) return;
526
675
  void deps.close();
527
- };
528
- const wrap = (key) => {
529
- const original = history[key];
530
- const patched = function(...args) {
531
- original.apply(this, args);
532
- onChange();
533
- };
534
- history[key] = patched;
535
- return () => {
536
- if (history[key] === patched) {
537
- history[key] = original;
538
- }
539
- };
540
- };
541
- window.addEventListener("popstate", onChange);
542
- const restorePush = wrap("pushState");
543
- const restoreReplace = wrap("replaceState");
544
- return () => {
545
- window.removeEventListener("popstate", onChange);
546
- restorePush();
547
- restoreReplace();
548
- };
676
+ });
549
677
  }
550
678
 
551
679
  // src/core/features/content-swipe.ts
@@ -616,11 +744,15 @@ function installVisualViewport(deps) {
616
744
  if (clamp < deps.getMaxAxisSize()) {
617
745
  deps.setMaxAxisSize(clamp);
618
746
  }
747
+ const wasAnimating = deps.isAnimating?.() ?? false;
748
+ deps.cancelInFlight();
749
+ deps.newCycle();
619
750
  const max = deps.getMaxAxisSize();
620
751
  deps.setSize(Math.min(deps.getSize(), max));
621
752
  const current = deps.resolveActiveSnap();
622
753
  if (current && !deps.isDragging()) {
623
754
  deps.applySize(Math.min(current.size, max));
755
+ if (wasAnimating) deps.resyncAfterCancel?.();
624
756
  } else {
625
757
  deps.applySize(deps.getSize());
626
758
  }
@@ -761,6 +893,54 @@ function installFitObserver(deps) {
761
893
  };
762
894
  }
763
895
 
896
+ // src/core/features/max-height-controller.ts
897
+ function createMaxHeightController(deps) {
898
+ let maxHeightCap;
899
+ let maxHeightRaw;
900
+ const resolveCap = () => {
901
+ const raw = maxHeightRaw;
902
+ if (raw === void 0) {
903
+ maxHeightCap = void 0;
904
+ return;
905
+ }
906
+ if (typeof raw === "number") {
907
+ maxHeightCap = raw;
908
+ return;
909
+ }
910
+ if (typeof window === "undefined") return;
911
+ const measured = resolveSnap(raw, deps.mode);
912
+ maxHeightCap = measured > 0 ? measured : void 0;
913
+ };
914
+ const clampTo = () => {
915
+ if (maxHeightCap === void 0) return;
916
+ if (deps.getMaxAxisSize() > maxHeightCap) {
917
+ deps.setMaxAxisSize(maxHeightCap);
918
+ }
919
+ };
920
+ return {
921
+ setRadius(r) {
922
+ deps.element.style.setProperty(
923
+ "--bs-radius",
924
+ typeof r === "number" ? `${r}px` : r
925
+ );
926
+ },
927
+ setMaxHeight(h) {
928
+ const value = typeof h === "number" ? `${h}px` : h;
929
+ const axis = layoutAxis(deps.mode);
930
+ deps.element.style.setProperty(
931
+ axis === "height" ? "max-height" : "max-width",
932
+ value
933
+ );
934
+ maxHeightRaw = h;
935
+ resolveCap();
936
+ deps.recompute();
937
+ },
938
+ resolveCap,
939
+ clampTo,
940
+ getCap: () => maxHeightCap
941
+ };
942
+ }
943
+
764
944
  // src/core/features/fit-measurement.ts
765
945
  var measureSheetNatural = (element, content, vertical) => {
766
946
  if (!content) {
@@ -892,13 +1072,6 @@ var WriteSentinel = class {
892
1072
  }
893
1073
  };
894
1074
 
895
- // src/core/primitives/devWarn.ts
896
- function devWarn(...args) {
897
- if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
898
- console.warn(...args);
899
- }
900
- }
901
-
902
1075
  // src/core/primitives/overlay-position.ts
903
1076
  function resolveSheetAnchoredStyle(mode, position, inset) {
904
1077
  const sizeOffset = `calc(var(--bs-size, 0px) + ${inset})`;
@@ -2353,7 +2526,7 @@ var matchesRange = (def, progress) => {
2353
2526
  };
2354
2527
  function installScrimStages(deps, opts) {
2355
2528
  const doc = deps.host.ownerDocument;
2356
- const entries = opts.stages.map((def) => {
2529
+ const entries2 = opts.stages.map((def) => {
2357
2530
  const wrapper = doc.createElement("div");
2358
2531
  wrapper.className = "bs-scrim-stage";
2359
2532
  const ws = wrapper.style;
@@ -2374,9 +2547,9 @@ function installScrimStages(deps, opts) {
2374
2547
  const resolveActive = () => {
2375
2548
  const state = deps.getState();
2376
2549
  if (state.size === 0) {
2377
- return entries.find((e) => matchesId(e.def, state.activeId)) ?? null;
2550
+ return entries2.find((e) => matchesId(e.def, state.activeId)) ?? null;
2378
2551
  }
2379
- return entries.find((e) => matchesId(e.def, state.activeId)) ?? entries.find((e) => matchesRange(e.def, state.progress)) ?? null;
2552
+ return entries2.find((e) => matchesId(e.def, state.activeId)) ?? entries2.find((e) => matchesRange(e.def, state.progress)) ?? null;
2380
2553
  };
2381
2554
  const hide = (entry, animate) => {
2382
2555
  entry.inFlight?.cancel();
@@ -2425,13 +2598,13 @@ function installScrimStages(deps, opts) {
2425
2598
  deps.on("open", () => update(true)),
2426
2599
  deps.on("close", () => update(true))
2427
2600
  ];
2428
- if (entries.some((e) => e.def.forRange)) {
2601
+ if (entries2.some((e) => e.def.forRange)) {
2429
2602
  offs.push(deps.on("progress", () => update(true)));
2430
2603
  }
2431
2604
  update(false);
2432
2605
  return () => {
2433
2606
  offs.forEach((off) => off());
2434
- for (const entry of entries) {
2607
+ for (const entry of entries2) {
2435
2608
  entry.inFlight?.cancel();
2436
2609
  entry.inFlight = null;
2437
2610
  if (entry.wrapper.parentNode) {
@@ -2544,8 +2717,7 @@ var BottomSheetEngine = class {
2544
2717
  __publicField(this, "disableCloseFlag");
2545
2718
  __publicField(this, "disableDragFlag");
2546
2719
  __publicField(this, "closeOnRouteChange");
2547
- __publicField(this, "maxHeightCap");
2548
- __publicField(this, "maxHeightRaw");
2720
+ __publicField(this, "maxHeight");
2549
2721
  __publicField(this, "snapPointsRaw");
2550
2722
  __publicField(this, "snaps");
2551
2723
  __publicField(this, "activeId");
@@ -2656,11 +2828,20 @@ var BottomSheetEngine = class {
2656
2828
  auditVhUsage(this.snapPointsRaw);
2657
2829
  this.auditDuplicateSnapIds(this.snapPointsRaw);
2658
2830
  this.rootEl = this.element.closest(".bs-root");
2831
+ this.maxHeight = createMaxHeightController({
2832
+ element: this.element,
2833
+ mode: this.mode,
2834
+ getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
2835
+ setMaxAxisSize: (size) => {
2836
+ this.snaps.setMaxAxisSize(size);
2837
+ },
2838
+ recompute: () => this.recompute()
2839
+ });
2659
2840
  this.fitDeps = {
2660
2841
  element: this.element,
2661
2842
  scrollContainer: this.scrollContainer,
2662
2843
  mode: this.mode,
2663
- getMaxHeightCap: () => this.maxHeightCap
2844
+ getMaxHeightCap: () => this.maxHeight.getCap()
2664
2845
  };
2665
2846
  this.snaps = new SnapResolver(
2666
2847
  this.snapPointsRaw,
@@ -2682,8 +2863,8 @@ var BottomSheetEngine = class {
2682
2863
  this.attach();
2683
2864
  this.registerInStack();
2684
2865
  if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
2685
- const io = new IntersectionObserver((entries) => {
2686
- for (const entry of entries) {
2866
+ const io = new IntersectionObserver((entries2) => {
2867
+ for (const entry of entries2) {
2687
2868
  if (!entry.isIntersecting) continue;
2688
2869
  if (this.destroyed) return;
2689
2870
  this.snaps.recompute();
@@ -2771,7 +2952,7 @@ var BottomSheetEngine = class {
2771
2952
  }
2772
2953
  use(plugin) {
2773
2954
  if (this.destroyed) {
2774
- console.warn(
2955
+ devWarn(
2775
2956
  `[BottomSheet] use("${plugin.name}") called on destroyed engine \u2014 ignored.`
2776
2957
  );
2777
2958
  return this;
@@ -2813,6 +2994,9 @@ var BottomSheetEngine = class {
2813
2994
  getAllowedIds() {
2814
2995
  return this.snaps.getAllowedIds().slice();
2815
2996
  }
2997
+ getResolvedSnaps() {
2998
+ return this.snaps.getResolvedSnaps();
2999
+ }
2816
3000
  async snapTo(id, velocityOrOpts = 0, _skipBeforeSnap = false) {
2817
3001
  if (this.destroyed) return;
2818
3002
  const opts = typeof velocityOrOpts === "object" ? velocityOrOpts : { velocity: velocityOrOpts };
@@ -2821,11 +3005,11 @@ var BottomSheetEngine = class {
2821
3005
  if (externalSignal?.aborted) return;
2822
3006
  const target = this.snaps.findById(id);
2823
3007
  if (!target) {
2824
- console.warn(`[BottomSheet] unknown snap id: ${id}`);
3008
+ devWarn(`[BottomSheet] unknown snap id: ${id}`);
2825
3009
  return;
2826
3010
  }
2827
3011
  if (!this.snaps.getAllowedIds().includes(id)) {
2828
- console.warn(`[BottomSheet] snap "${id}" is not in allowed list`);
3012
+ devWarn(`[BottomSheet] snap "${id}" is not in allowed list`);
2829
3013
  return;
2830
3014
  }
2831
3015
  if (!_skipBeforeSnap && this.emitBeforeSnap(target, this.activeId)) {
@@ -2957,42 +3141,11 @@ var BottomSheetEngine = class {
2957
3141
  }
2958
3142
  setRadius(r) {
2959
3143
  if (this.destroyed) return;
2960
- this.element.style.setProperty(
2961
- "--bs-radius",
2962
- typeof r === "number" ? `${r}px` : r
2963
- );
3144
+ this.maxHeight.setRadius(r);
2964
3145
  }
2965
3146
  setMaxHeight(h) {
2966
3147
  if (this.destroyed) return;
2967
- const value = typeof h === "number" ? `${h}px` : h;
2968
- const axis = layoutAxis(this.mode);
2969
- this.element.style.setProperty(
2970
- axis === "height" ? "max-height" : "max-width",
2971
- value
2972
- );
2973
- this.maxHeightRaw = h;
2974
- this.resolveMaxHeightCap();
2975
- this.recompute();
2976
- }
2977
- resolveMaxHeightCap() {
2978
- const raw = this.maxHeightRaw;
2979
- if (raw === void 0) {
2980
- this.maxHeightCap = void 0;
2981
- return;
2982
- }
2983
- if (typeof raw === "number") {
2984
- this.maxHeightCap = raw;
2985
- return;
2986
- }
2987
- if (typeof window === "undefined") return;
2988
- const measured = resolveSnap(raw, this.mode);
2989
- this.maxHeightCap = measured > 0 ? measured : void 0;
2990
- }
2991
- clampToMaxHeight() {
2992
- if (this.maxHeightCap === void 0) return;
2993
- if (this.snaps.getMaxAxisSize() > this.maxHeightCap) {
2994
- this.snaps.setMaxAxisSize(this.maxHeightCap);
2995
- }
3148
+ this.maxHeight.setMaxHeight(h);
2996
3149
  }
2997
3150
  setAllowed(ids, snap) {
2998
3151
  if (this.destroyed) return;
@@ -3080,7 +3233,7 @@ var BottomSheetEngine = class {
3080
3233
  };
3081
3234
  const host = this.screenComponent?.parentElement;
3082
3235
  if (!host) {
3083
- console.warn(
3236
+ devWarn(
3084
3237
  "[BottomSheet] setScrimStages: no scrim element mounted \u2014 pass `scrim` to the engine first."
3085
3238
  );
3086
3239
  return () => {
@@ -3130,9 +3283,9 @@ var BottomSheetEngine = class {
3130
3283
  }
3131
3284
  recompute() {
3132
3285
  if (this.destroyed) return;
3133
- this.resolveMaxHeightCap();
3286
+ this.maxHeight.resolveCap();
3134
3287
  this.snaps.recompute();
3135
- this.clampToMaxHeight();
3288
+ this.maxHeight.clampTo();
3136
3289
  this.scrim.invalidateOpacityCache();
3137
3290
  if (this.gesture?.isDragging) return;
3138
3291
  const current = this.snaps.findById(this.activeId);
@@ -3182,42 +3335,18 @@ var BottomSheetEngine = class {
3182
3335
  return this.currentAbort.signal;
3183
3336
  }
3184
3337
  emitBeforeSnap(target, previousId) {
3185
- let cancelled = false;
3186
- let frozen = false;
3187
- this.emit("before-snap", {
3188
- id: target.id,
3189
- size: target.size,
3190
- previousId,
3191
- cancel: () => {
3192
- if (frozen) {
3193
- console.warn(
3194
- "[BottomSheet] before-snap.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener."
3195
- );
3196
- return;
3197
- }
3198
- cancelled = true;
3199
- }
3200
- });
3201
- frozen = true;
3202
- return cancelled;
3338
+ return emitCancelable(
3339
+ (payload) => this.emit("before-snap", payload),
3340
+ { id: target.id, size: target.size, previousId },
3341
+ "before-snap"
3342
+ );
3203
3343
  }
3204
3344
  emitBeforeClose(reason) {
3205
- let cancelled = false;
3206
- let frozen = false;
3207
- this.emit("before-close", {
3208
- reason,
3209
- cancel: () => {
3210
- if (frozen) {
3211
- console.warn(
3212
- "[BottomSheet] before-close.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener."
3213
- );
3214
- return;
3215
- }
3216
- cancelled = true;
3217
- }
3218
- });
3219
- frozen = true;
3220
- return cancelled;
3345
+ return emitCancelable(
3346
+ (payload) => this.emit("before-close", payload),
3347
+ { reason },
3348
+ "before-close"
3349
+ );
3221
3350
  }
3222
3351
  applyAutoAriaLabelledBy() {
3223
3352
  if (typeof document === "undefined") return;
@@ -3232,16 +3361,16 @@ var BottomSheetEngine = class {
3232
3361
  this.element.setAttribute("aria-labelledby", titled.id);
3233
3362
  }
3234
3363
  recomputeSnaps() {
3235
- this.resolveMaxHeightCap();
3364
+ this.maxHeight.resolveCap();
3236
3365
  this.snaps.setRaw(this.snapPointsRaw);
3237
- this.clampToMaxHeight();
3366
+ this.maxHeight.clampTo();
3238
3367
  this.scrim.invalidateOpacityCache();
3239
3368
  }
3240
3369
  auditDuplicateSnapIds(points) {
3241
3370
  const seen = /* @__PURE__ */ new Set();
3242
3371
  for (const p of points) {
3243
3372
  if (seen.has(p.id)) {
3244
- console.warn(
3373
+ devWarn(
3245
3374
  `[BottomSheet] duplicate snap id "${p.id}" \u2014 only the first occurrence is reachable.`
3246
3375
  );
3247
3376
  }
@@ -3408,7 +3537,15 @@ var BottomSheetEngine = class {
3408
3537
  setSize: (size) => {
3409
3538
  this.size = size;
3410
3539
  },
3411
- applySize: (size) => this.applySize(size)
3540
+ applySize: (size) => this.applySize(size),
3541
+ cancelInFlight: () => {
3542
+ this.animation.cancel();
3543
+ },
3544
+ newCycle: () => {
3545
+ this.newCycle();
3546
+ },
3547
+ isAnimating: () => this.animation.isAnimating,
3548
+ resyncAfterCancel: () => this.resyncAfterResize()
3412
3549
  }));
3413
3550
  }
3414
3551
  this.teardowns.add(installSliderKeyboard({
@@ -3444,9 +3581,9 @@ var BottomSheetEngine = class {
3444
3581
  return;
3445
3582
  }
3446
3583
  if (this.emitBeforeSnap(target, previousId)) {
3447
- const restore = this.snaps.findById(previousId);
3448
- if (restore) {
3449
- void this.animation.animateTo(restore.size, 0);
3584
+ const restore2 = this.snaps.findById(previousId);
3585
+ if (restore2) {
3586
+ void this.animation.animateTo(restore2.size, 0);
3450
3587
  }
3451
3588
  return;
3452
3589
  }
@@ -3968,13 +4105,18 @@ var _sfc_main = /* @__PURE__ */ vue.defineComponent({
3968
4105
  "before-snap",
3969
4106
  "drag-start",
3970
4107
  "drag-end",
4108
+ "drag",
4109
+ "progress",
3971
4110
  "update:open",
3972
4111
  "update:snap"
3973
4112
  ],
3974
4113
  setup(__props, { expose: __expose, emit: __emit }) {
3975
4114
  const props = __props;
3976
4115
  const emit = __emit;
3977
- const { sheetRef, handleRef, contentRef, backdropRef, screenRef, state, snapTo, open, close, setAllowed, setSnapPoints, setScrim, setScrimOverlay, addAnchor, setScrimStages, recompute, setScrimColor, setBackdropRange, setRadius, setMaxHeight, expand, collapse, isTop, depth, canDismiss, on, getEngine } = useBottomSheet(props);
4116
+ const { sheetRef, handleRef, contentRef, backdropRef, screenRef, state, snapTo, open, close, setAllowed, setSnapPoints, setScrim, setScrimOverlay, addAnchor, setScrimStages, recompute, setScrimColor, setBackdropRange, setRadius, setMaxHeight, expand, collapse, isTop, depth, canDismiss, on, getEngine } = useBottomSheet({
4117
+ ...props,
4118
+ teleport: false
4119
+ });
3978
4120
  vue.watch(() => ({ ...state }), (next) => emit("change", next), { deep: false });
3979
4121
  on("snap", (payload) => {
3980
4122
  emit("snap", payload.id);
@@ -3999,6 +4141,8 @@ var _sfc_main = /* @__PURE__ */ vue.defineComponent({
3999
4141
  }));
4000
4142
  on("dragstart", (payload) => emit("drag-start", payload));
4001
4143
  on("dragend", (payload) => emit("drag-end", payload));
4144
+ on("drag", (payload) => emit("drag", payload));
4145
+ on("progress", (payload) => emit("progress", payload));
4002
4146
  vue.watch(() => props.open, (next) => {
4003
4147
  if (next === void 0) return;
4004
4148
  const isOpen = state.size > 0;