@surdeddd/bottom-sheet 0.2.0 → 0.3.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 (49) hide show
  1. package/README.md +51 -21
  2. package/dist/{BottomSheetEngine-CIT9Htti.d.cts → BottomSheetEngine-CAymrH-P.d.cts} +67 -1
  3. package/dist/{BottomSheetEngine-Df9MwBbm.d.ts → BottomSheetEngine-DcqcuudN.d.ts} +67 -1
  4. package/dist/element.cjs +699 -116
  5. package/dist/element.d.cts +7 -2
  6. package/dist/element.d.ts +7 -2
  7. package/dist/element.iife.global.js +2 -2
  8. package/dist/element.js +699 -116
  9. package/dist/index.cjs +715 -145
  10. package/dist/index.d.cts +17 -3
  11. package/dist/index.d.ts +17 -3
  12. package/dist/index.js +713 -146
  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 +168 -35
  18. package/dist/overlay.d.cts +13 -0
  19. package/dist/overlay.d.ts +13 -0
  20. package/dist/overlay.js +168 -35
  21. package/dist/preact.d.cts +1 -1
  22. package/dist/preact.d.ts +1 -1
  23. package/dist/qwik.cjs +619 -119
  24. package/dist/qwik.d.cts +2 -2
  25. package/dist/qwik.d.ts +2 -2
  26. package/dist/qwik.js +620 -120
  27. package/dist/react.cjs +821 -191
  28. package/dist/react.d.cts +20 -3
  29. package/dist/react.d.ts +20 -3
  30. package/dist/react.js +821 -191
  31. package/dist/solid.cjs +656 -161
  32. package/dist/solid.d.cts +263 -4
  33. package/dist/solid.d.ts +263 -4
  34. package/dist/solid.js +657 -162
  35. package/dist/solid.source.jsx +3215 -0
  36. package/dist/styles.css +10 -10
  37. package/dist/svelte-core.cjs +3149 -0
  38. package/dist/svelte-core.js +3147 -0
  39. package/dist/svelte-src/BottomSheet.svelte +210 -0
  40. package/dist/svelte-src/index.js +2 -0
  41. package/dist/svelte.cjs +618 -124
  42. package/dist/svelte.d.cts +100 -0
  43. package/dist/svelte.d.ts +7 -3
  44. package/dist/svelte.js +619 -125
  45. package/dist/vue.cjs +612 -119
  46. package/dist/vue.d.cts +78 -0
  47. package/dist/vue.d.ts +6 -2
  48. package/dist/vue.js +612 -119
  49. package/package.json +103 -43
package/dist/vue.js CHANGED
@@ -22,6 +22,18 @@ var SheetStack = class {
22
22
  this.entries.splice(idx, 1);
23
23
  this.recompute();
24
24
  }
25
+ promote(id) {
26
+ const idx = this.entries.findIndex((e) => e.id === id);
27
+ if (idx === -1) return;
28
+ if (idx !== this.entries.length - 1) {
29
+ const [entry] = this.entries.splice(idx, 1);
30
+ this.entries.push(entry);
31
+ }
32
+ this.recompute();
33
+ }
34
+ update() {
35
+ this.recompute();
36
+ }
25
37
  size() {
26
38
  return this.entries.length;
27
39
  }
@@ -29,9 +41,24 @@ var SheetStack = class {
29
41
  this.entries = [];
30
42
  }
31
43
  recompute() {
44
+ let top = null;
45
+ const open = [];
46
+ for (const entry of this.entries) {
47
+ if (!entry.isOpen || entry.isOpen()) {
48
+ top = entry;
49
+ open.push(entry);
50
+ }
51
+ }
52
+ if (!top && this.entries.length > 0) {
53
+ top = this.entries[this.entries.length - 1];
54
+ }
32
55
  this.entries.forEach((entry, i) => {
33
56
  entry.setZIndex(BASE_Z + i * STEP);
34
- entry.setIsTop(i === this.entries.length - 1);
57
+ entry.setIsTop(entry === top);
58
+ if (entry.setDepth) {
59
+ const openIdx = open.indexOf(entry);
60
+ entry.setDepth(openIdx === -1 ? 0 : open.length - 1 - openIdx);
61
+ }
35
62
  });
36
63
  }
37
64
  };
@@ -316,14 +343,17 @@ function installAutoCollapse(deps) {
316
343
  const fire = () => {
317
344
  if (deps.isDestroyed()) return;
318
345
  if (deps.isDragging()) return;
319
- const allowed = deps.getAllowedIds();
320
- const target = allowed.find((id) => {
346
+ const active = deps.resolveSnap(deps.getActiveId());
347
+ if (!active || active.size === 0) return;
348
+ let target = null;
349
+ for (const id of deps.getAllowedIds()) {
321
350
  const snap = deps.resolveSnap(id);
322
- return snap !== null && snap.size > 0;
323
- });
351
+ if (!snap || snap.size <= 0) continue;
352
+ if (!target || snap.size < target.size) target = snap;
353
+ }
324
354
  if (!target) return;
325
- if (target === deps.getActiveId()) return;
326
- deps.snapTo(target);
355
+ if (target.id === active.id || target.size >= active.size) return;
356
+ deps.snapTo(target.id);
327
357
  };
328
358
  const reset = () => {
329
359
  clearTimer();
@@ -334,6 +364,7 @@ function installAutoCollapse(deps) {
334
364
  }, ms);
335
365
  };
336
366
  const unsubscribe = deps.on("snap", () => reset());
367
+ if ((deps.resolveSnap(deps.getActiveId())?.size ?? 0) > 0) reset();
337
368
  return () => {
338
369
  clearTimer();
339
370
  unsubscribe();
@@ -346,6 +377,7 @@ function notifyLinkedSheets(sheets, self) {
346
377
  for (const linked of sheets) {
347
378
  if (linked === self) continue;
348
379
  try {
380
+ if (linked.state.size === 0) continue;
349
381
  const ids = linked.getAllowedIds();
350
382
  const target = ids.find((id) => id !== "closed");
351
383
  if (target && target !== linked.state.activeId) {
@@ -392,7 +424,7 @@ function installRoute(deps) {
392
424
  const onPop = (event) => {
393
425
  if (deps.isDestroyed()) return;
394
426
  const state = event.state;
395
- if (state && state.__bsRouted === target && deps.getSize() > 0) {
427
+ if ((!state || state.__bsRouted !== target) && deps.getSize() > 0) {
396
428
  routePushed = false;
397
429
  void deps.close();
398
430
  }
@@ -546,13 +578,17 @@ function installResizeObserver(deps) {
546
578
  if (viewportSize2 > 0 && viewportSize2 < max) {
547
579
  deps.setMaxAxisSize(viewportSize2);
548
580
  }
581
+ const wasAnimating = deps.isAnimating?.() ?? false;
549
582
  deps.cancelInFlight();
550
583
  deps.newCycle();
551
584
  const current = deps.resolveActiveSnap();
552
585
  const newMax = deps.getMaxAxisSize();
553
586
  const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
554
587
  deps.setSize(targetSize);
555
- if (current && !deps.isDragging()) deps.applySize(targetSize);
588
+ if (current && !deps.isDragging()) {
589
+ deps.applySize(targetSize);
590
+ if (wasAnimating) deps.resyncAfterCancel?.();
591
+ }
556
592
  };
557
593
  let resizeObserver = null;
558
594
  if (typeof ResizeObserver !== "undefined") {
@@ -667,6 +703,85 @@ function devWarn(...args) {
667
703
  }
668
704
  }
669
705
 
706
+ // src/core/primitives/overlay-position.ts
707
+ function resolveSheetAnchoredStyle(mode, position, inset) {
708
+ const sizeOffset = `calc(var(--bs-size, 0px) + ${inset})`;
709
+ switch (mode) {
710
+ case "bottom":
711
+ if (position === "sheet-top-left") return { bottom: sizeOffset, left: inset };
712
+ if (position === "sheet-top-right") return { bottom: sizeOffset, right: inset };
713
+ return { bottom: sizeOffset, left: "50%", transform: "translateX(-50%)" };
714
+ case "top":
715
+ if (position === "sheet-top-left") return { top: sizeOffset, left: inset };
716
+ if (position === "sheet-top-right") return { top: sizeOffset, right: inset };
717
+ return { top: sizeOffset, left: "50%", transform: "translateX(-50%)" };
718
+ case "left":
719
+ if (position === "sheet-top-left") return { left: sizeOffset, top: inset };
720
+ if (position === "sheet-top-right") return { left: sizeOffset, bottom: inset };
721
+ return { left: sizeOffset, top: "50%", transform: "translateY(-50%)" };
722
+ case "right":
723
+ if (position === "sheet-top-left") return { right: sizeOffset, top: inset };
724
+ if (position === "sheet-top-right") return { right: sizeOffset, bottom: inset };
725
+ return { right: sizeOffset, top: "50%", transform: "translateY(-50%)" };
726
+ }
727
+ }
728
+ function applyOverlayPosition(ws, mode, position, inset) {
729
+ switch (position) {
730
+ case "top-left":
731
+ ws.top = inset;
732
+ ws.left = inset;
733
+ break;
734
+ case "top-center":
735
+ ws.top = inset;
736
+ ws.left = "50%";
737
+ ws.transform = "translateX(-50%)";
738
+ break;
739
+ case "top-right":
740
+ ws.top = inset;
741
+ ws.right = inset;
742
+ break;
743
+ case "center-left":
744
+ ws.top = "50%";
745
+ ws.left = inset;
746
+ ws.transform = "translateY(-50%)";
747
+ break;
748
+ case "center":
749
+ ws.top = "50%";
750
+ ws.left = "50%";
751
+ ws.transform = "translate(-50%, -50%)";
752
+ break;
753
+ case "center-right":
754
+ ws.top = "50%";
755
+ ws.right = inset;
756
+ ws.transform = "translateY(-50%)";
757
+ break;
758
+ case "bottom-left":
759
+ ws.bottom = inset;
760
+ ws.left = inset;
761
+ break;
762
+ case "bottom-center":
763
+ ws.bottom = inset;
764
+ ws.left = "50%";
765
+ ws.transform = "translateX(-50%)";
766
+ break;
767
+ case "bottom-right":
768
+ ws.bottom = inset;
769
+ ws.right = inset;
770
+ break;
771
+ case "sheet-top-left":
772
+ case "sheet-top-center":
773
+ case "sheet-top-right": {
774
+ const style = resolveSheetAnchoredStyle(mode, position, inset);
775
+ if (style.top !== void 0) ws.top = style.top;
776
+ if (style.bottom !== void 0) ws.bottom = style.bottom;
777
+ if (style.left !== void 0) ws.left = style.left;
778
+ if (style.right !== void 0) ws.right = style.right;
779
+ if (style.transform !== void 0) ws.transform = style.transform;
780
+ break;
781
+ }
782
+ }
783
+ }
784
+
670
785
  // src/core/controllers/scrim-controller.ts
671
786
  var VALID_CSS_LENGTH = /^-?\d+(?:\.\d+)?(?:px|em|rem|%)$/;
672
787
  var ScrimController = class {
@@ -679,6 +794,8 @@ var ScrimController = class {
679
794
  __publicField(this, "getAllowedIds");
680
795
  __publicField(this, "getResolvedSnaps");
681
796
  __publicField(this, "snapToFn");
797
+ __publicField(this, "closeFn");
798
+ __publicField(this, "scrimInteractive", false);
682
799
  __publicField(this, "scrimMode");
683
800
  __publicField(this, "backdropRange");
684
801
  __publicField(this, "screenRange");
@@ -699,6 +816,7 @@ var ScrimController = class {
699
816
  this.getAllowedIds = deps.getAllowedIds;
700
817
  this.getResolvedSnaps = deps.getResolvedSnaps;
701
818
  this.snapToFn = deps.snapTo;
819
+ this.closeFn = deps.close;
702
820
  this.scrimMode = opts.scrimMode ?? "full";
703
821
  const preset = opts.scrimPreset ? SCRIM_PRESETS[opts.scrimPreset] : null;
704
822
  this.backdropRange = opts.backdropRange ?? preset?.range ?? [0, 1];
@@ -840,11 +958,15 @@ var ScrimController = class {
840
958
  }
841
959
  const onClick = () => {
842
960
  if (this.isDestroyed()) return;
961
+ if (this.closeFn) {
962
+ this.closeFn();
963
+ return;
964
+ }
843
965
  const allowed = this.getAllowedIds();
844
966
  const snaps = this.getResolvedSnaps();
845
967
  const fallback = allowed.find((id) => {
846
968
  const snap = findById(id, snaps);
847
- return snap !== null && snap.size > 0;
969
+ return snap !== null && snap.size === 0;
848
970
  });
849
971
  if (fallback) this.snapToFn(fallback);
850
972
  };
@@ -861,6 +983,7 @@ var ScrimController = class {
861
983
  if (this.isDestroyed()) return;
862
984
  if (enabled === this.scrimEnabled) return;
863
985
  this.scrimEnabled = enabled;
986
+ this.invalidateOpacityCache();
864
987
  if (!enabled) {
865
988
  this.savedScrimRanges = {
866
989
  screen: this.screenRange,
@@ -884,7 +1007,12 @@ var ScrimController = class {
884
1007
  blur: cfg.blur ?? null,
885
1008
  interactive: cfg.interactive
886
1009
  });
887
- this.screenRange = cfg.range;
1010
+ if (!this.scrimEnabled && this.savedScrimRanges) {
1011
+ this.savedScrimRanges = { screen: cfg.range, backdrop: cfg.range };
1012
+ } else {
1013
+ this.screenRange = cfg.range;
1014
+ this.backdropRange = cfg.range;
1015
+ }
888
1016
  }
889
1017
  const noop = () => {
890
1018
  };
@@ -934,59 +1062,7 @@ var ScrimController = class {
934
1062
  wrapper.className = "bs-scrim-overlay";
935
1063
  const ws = wrapper.style;
936
1064
  ws.position = "absolute";
937
- switch (position) {
938
- case "top-left":
939
- ws.top = inset;
940
- ws.left = inset;
941
- break;
942
- case "top-center":
943
- ws.top = inset;
944
- ws.left = "50%";
945
- ws.transform = "translateX(-50%)";
946
- break;
947
- case "top-right":
948
- ws.top = inset;
949
- ws.right = inset;
950
- break;
951
- case "center-left":
952
- ws.top = "50%";
953
- ws.left = inset;
954
- ws.transform = "translateY(-50%)";
955
- break;
956
- case "center":
957
- ws.top = "50%";
958
- ws.left = "50%";
959
- ws.transform = "translate(-50%, -50%)";
960
- break;
961
- case "center-right":
962
- ws.top = "50%";
963
- ws.right = inset;
964
- ws.transform = "translateY(-50%)";
965
- break;
966
- case "bottom-left":
967
- ws.bottom = inset;
968
- ws.left = inset;
969
- break;
970
- case "bottom-center":
971
- ws.bottom = inset;
972
- ws.left = "50%";
973
- ws.transform = "translateX(-50%)";
974
- break;
975
- case "bottom-right":
976
- ws.bottom = inset;
977
- ws.right = inset;
978
- break;
979
- case "sheet-top-left":
980
- case "sheet-top-center":
981
- case "sheet-top-right":
982
- applySheetAnchoredPosition(
983
- ws,
984
- this.mode,
985
- position,
986
- inset
987
- );
988
- break;
989
- }
1065
+ applyOverlayPosition(ws, this.mode, position, inset);
990
1066
  if (interactive) {
991
1067
  ws.pointerEvents = "auto";
992
1068
  }
@@ -1045,6 +1121,7 @@ var ScrimController = class {
1045
1121
  }
1046
1122
  }
1047
1123
  if (opts.interactive !== void 0) {
1124
+ this.scrimInteractive = opts.interactive;
1048
1125
  s.pointerEvents = opts.interactive ? "auto" : "none";
1049
1126
  }
1050
1127
  }
@@ -1059,38 +1136,9 @@ var ScrimController = class {
1059
1136
  const s = this.screenComponent.style;
1060
1137
  s.position = "fixed";
1061
1138
  s.inset = insetByMode[this.mode];
1062
- s.pointerEvents = "none";
1139
+ s.pointerEvents = this.scrimInteractive || this.scrimTapToCloseEnabled ? "auto" : "none";
1063
1140
  }
1064
1141
  };
1065
- function resolveSheetAnchoredStyle(mode, position, inset) {
1066
- const sizeOffset = `calc(var(--bs-size, 0px) + ${inset})`;
1067
- switch (mode) {
1068
- case "bottom":
1069
- if (position === "sheet-top-left") return { bottom: sizeOffset, left: inset };
1070
- if (position === "sheet-top-right") return { bottom: sizeOffset, right: inset };
1071
- return { bottom: sizeOffset, left: "50%", transform: "translateX(-50%)" };
1072
- case "top":
1073
- if (position === "sheet-top-left") return { top: sizeOffset, left: inset };
1074
- if (position === "sheet-top-right") return { top: sizeOffset, right: inset };
1075
- return { top: sizeOffset, left: "50%", transform: "translateX(-50%)" };
1076
- case "left":
1077
- if (position === "sheet-top-left") return { left: sizeOffset, top: inset };
1078
- if (position === "sheet-top-right") return { left: sizeOffset, bottom: inset };
1079
- return { left: sizeOffset, top: "50%", transform: "translateY(-50%)" };
1080
- case "right":
1081
- if (position === "sheet-top-left") return { right: sizeOffset, top: inset };
1082
- if (position === "sheet-top-right") return { right: sizeOffset, bottom: inset };
1083
- return { right: sizeOffset, top: "50%", transform: "translateY(-50%)" };
1084
- }
1085
- }
1086
- function applySheetAnchoredPosition(ws, mode, position, inset) {
1087
- const style = resolveSheetAnchoredStyle(mode, position, inset);
1088
- if (style.top !== void 0) ws.top = style.top;
1089
- if (style.bottom !== void 0) ws.bottom = style.bottom;
1090
- if (style.left !== void 0) ws.left = style.left;
1091
- if (style.right !== void 0) ws.right = style.right;
1092
- if (style.transform !== void 0) ws.transform = style.transform;
1093
- }
1094
1142
 
1095
1143
  // src/core/animation/animation.ts
1096
1144
  var easeOutBack = (t) => {
@@ -1142,6 +1190,10 @@ var tween = ({
1142
1190
  promise
1143
1191
  };
1144
1192
  };
1193
+ var prefersReducedMotion = () => {
1194
+ if (typeof window === "undefined" || !window.matchMedia) return false;
1195
+ return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
1196
+ };
1145
1197
 
1146
1198
  // src/core/animation/spring.ts
1147
1199
  var DEFAULT_SPRING = {
@@ -1172,14 +1224,20 @@ var runSpring = ({
1172
1224
  if (cancelled) return;
1173
1225
  const dt = Math.min((now - lastTime) / 1e3, MAX_DT);
1174
1226
  lastTime = now;
1175
- const subDt = Math.min(dt, 1 / 240);
1176
- let stepsLeft = Math.max(1, Math.ceil(dt / subDt));
1227
+ const steps = Math.max(1, Math.ceil(dt * 240));
1228
+ const subDt = dt / steps;
1229
+ let stepsLeft = steps;
1177
1230
  while (stepsLeft-- > 0) {
1178
1231
  const force = -cfg.stiffness * (x - to) - cfg.damping * v;
1179
1232
  const accel = force / cfg.mass;
1180
1233
  v += accel * subDt;
1181
1234
  x += v * subDt;
1182
1235
  }
1236
+ if (!Number.isFinite(x) || !Number.isFinite(v)) {
1237
+ onUpdate(to, 0);
1238
+ resolve();
1239
+ return;
1240
+ }
1183
1241
  onUpdate(x, v);
1184
1242
  const isAtRest = Math.abs(to - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
1185
1243
  if (isAtRest) {
@@ -1354,9 +1412,13 @@ var isVisible = (el) => {
1354
1412
  var focusables = (root) => Array.from(root.querySelectorAll(FOCUSABLE)).filter(
1355
1413
  (el) => !el.hasAttribute("inert") && isVisible(el) && !el.matches("[aria-hidden='true']")
1356
1414
  );
1415
+ var trapStack = [];
1357
1416
  var installFocusTrap = (container, options = {}) => {
1358
1417
  if (typeof document === "undefined") return () => {
1359
1418
  };
1419
+ const token = {};
1420
+ trapStack.push(token);
1421
+ const isActive = () => trapStack[trapStack.length - 1] === token;
1360
1422
  const previouslyFocused = document.activeElement;
1361
1423
  const focusInitial = () => {
1362
1424
  const initial = typeof options.initialFocus === "string" ? container.querySelector(options.initialFocus) : options.initialFocus ?? focusables(container)[0] ?? container;
@@ -1364,6 +1426,7 @@ var installFocusTrap = (container, options = {}) => {
1364
1426
  };
1365
1427
  focusInitial();
1366
1428
  const handleKey = (e) => {
1429
+ if (!isActive()) return;
1367
1430
  if (e.key === "Escape" && options.onEscape) {
1368
1431
  options.onEscape();
1369
1432
  return;
@@ -1386,6 +1449,7 @@ var installFocusTrap = (container, options = {}) => {
1386
1449
  }
1387
1450
  };
1388
1451
  const handleFocusIn = (e) => {
1452
+ if (!isActive()) return;
1389
1453
  const target = e.target;
1390
1454
  if (target && !container.contains(target)) {
1391
1455
  const list = focusables(container);
@@ -1398,6 +1462,8 @@ var installFocusTrap = (container, options = {}) => {
1398
1462
  return () => {
1399
1463
  if (released) return;
1400
1464
  released = true;
1465
+ const idx = trapStack.indexOf(token);
1466
+ if (idx !== -1) trapStack.splice(idx, 1);
1401
1467
  document.removeEventListener("keydown", handleKey, true);
1402
1468
  document.removeEventListener("focusin", handleFocusIn, true);
1403
1469
  if (previouslyFocused && document.contains(previouslyFocused)) {
@@ -1453,11 +1519,17 @@ function createInertSiblings(rootProvider) {
1453
1519
  return {
1454
1520
  apply() {
1455
1521
  if (typeof document === "undefined") return;
1456
- const root = rootProvider();
1457
- const parent = root.parentElement ?? document.body;
1522
+ let top = rootProvider();
1523
+ while (top.parentElement && top.parentElement !== document.body) {
1524
+ top = top.parentElement;
1525
+ }
1526
+ const parent = top.parentElement ?? document.body;
1458
1527
  for (const child of Array.from(parent.children)) {
1459
- if (child === root) continue;
1528
+ if (child === top) continue;
1460
1529
  if (child.hasAttribute("inert")) continue;
1530
+ if (child.classList.contains("bs-backdrop") || child.classList.contains("bs-screen") || child.classList.contains("bs-root")) {
1531
+ continue;
1532
+ }
1461
1533
  child.setAttribute("inert", "");
1462
1534
  tracked.push(child);
1463
1535
  }
@@ -1473,7 +1545,6 @@ function createInertSiblings(rootProvider) {
1473
1545
  var LifecycleController = class {
1474
1546
  constructor(deps, opts) {
1475
1547
  __publicField(this, "element");
1476
- __publicField(this, "closeFn");
1477
1548
  __publicField(this, "focusTrapEnabled");
1478
1549
  __publicField(this, "initialFocus");
1479
1550
  __publicField(this, "closeOnEscape");
@@ -1487,7 +1558,6 @@ var LifecycleController = class {
1487
1558
  __publicField(this, "installed", false);
1488
1559
  __publicField(this, "destroyed", false);
1489
1560
  this.element = deps.element;
1490
- this.closeFn = deps.close;
1491
1561
  this.focusTrapEnabled = opts.focusTrap ?? false;
1492
1562
  this.initialFocus = opts.initialFocus;
1493
1563
  this.closeOnEscape = opts.closeOnEscape ?? true;
@@ -1497,6 +1567,9 @@ var LifecycleController = class {
1497
1567
  this.returnFocus = opts.returnFocus;
1498
1568
  this.inertSiblings = createInertSiblings(() => this.element);
1499
1569
  }
1570
+ get isInstalled() {
1571
+ return this.installed;
1572
+ }
1500
1573
  install() {
1501
1574
  if (this.destroyed) return;
1502
1575
  this.installed = true;
@@ -1505,8 +1578,7 @@ var LifecycleController = class {
1505
1578
  }
1506
1579
  if (this.focusTrapEnabled && !this.releaseFocusTrap) {
1507
1580
  this.releaseFocusTrap = installFocusTrap(this.element, {
1508
- initialFocus: this.initialFocus,
1509
- onEscape: this.closeOnEscape ? () => void this.closeFn() : void 0
1581
+ initialFocus: this.initialFocus
1510
1582
  });
1511
1583
  }
1512
1584
  if (this.inertSiblingsEnabled && this.shouldApplyInertSiblings()) {
@@ -1660,10 +1732,11 @@ var installGestures = (handle, mode, callbacks) => {
1660
1732
  };
1661
1733
 
1662
1734
  // src/core/primitives/rubber-band.ts
1663
- var RUBBER_BAND_FACTOR = 0.55;
1664
1735
  function rubberBand(overshoot, maxAxisSize) {
1665
1736
  const cap = Math.min(maxAxisSize * 0.15, 80);
1666
- return Math.sign(overshoot) * Math.pow(Math.abs(overshoot), RUBBER_BAND_FACTOR) * Math.min(6, cap / Math.max(Math.abs(overshoot), 1));
1737
+ if (cap <= 0) return 0;
1738
+ const abs = Math.abs(overshoot);
1739
+ return Math.sign(overshoot) * (cap * abs / (abs + cap));
1667
1740
  }
1668
1741
 
1669
1742
  // src/core/features/soft-keyboard.ts
@@ -1748,6 +1821,10 @@ var GestureController = class {
1748
1821
  this.isDragging_ = false;
1749
1822
  this.keyboardDismissed = false;
1750
1823
  this.deps.getRoot()?.removeAttribute("data-dragging");
1824
+ this.deps.emit("dragend", {
1825
+ size: this.deps.getDragContext().size,
1826
+ velocity: 0
1827
+ });
1751
1828
  const restoreTo = this.dragStartSize;
1752
1829
  void this.deps.animateTo(restoreTo, 0);
1753
1830
  }
@@ -1821,6 +1898,287 @@ function createScrollCache(deps) {
1821
1898
  };
1822
1899
  }
1823
1900
 
1901
+ // src/core/primitives/anchor-animations.ts
1902
+ var DEFAULT_DURATION3 = 200;
1903
+ var DEFAULT_EASING = "cubic-bezier(0.22, 1, 0.36, 1)";
1904
+ var PRESET_FRAMES = {
1905
+ fade: {
1906
+ enter: [{ opacity: 0 }, { opacity: 1 }],
1907
+ exit: [{ opacity: 1 }, { opacity: 0 }]
1908
+ },
1909
+ scale: {
1910
+ enter: [
1911
+ { opacity: 0, transform: "scale(0.85)" },
1912
+ { opacity: 1, transform: "scale(1)" }
1913
+ ],
1914
+ exit: [
1915
+ { opacity: 1, transform: "scale(1)" },
1916
+ { opacity: 0, transform: "scale(0.85)" }
1917
+ ]
1918
+ },
1919
+ slide: {
1920
+ enter: [
1921
+ { opacity: 0, transform: "translateY(10px)" },
1922
+ { opacity: 1, transform: "translateY(0)" }
1923
+ ],
1924
+ exit: [
1925
+ { opacity: 1, transform: "translateY(0)" },
1926
+ { opacity: 0, transform: "translateY(10px)" }
1927
+ ]
1928
+ },
1929
+ pop: {
1930
+ enter: [
1931
+ { opacity: 0, transform: "scale(0.6)", offset: 0 },
1932
+ { opacity: 1, transform: "scale(1.06)", offset: 0.7 },
1933
+ { opacity: 1, transform: "scale(1)", offset: 1 }
1934
+ ],
1935
+ exit: [
1936
+ { opacity: 1, transform: "scale(1)" },
1937
+ { opacity: 0, transform: "scale(0.6)" }
1938
+ ]
1939
+ }
1940
+ };
1941
+ var INSTANT = {
1942
+ finished: Promise.resolve(),
1943
+ cancel: () => {
1944
+ }
1945
+ };
1946
+ function resolveTransitionFrames(spec, phase) {
1947
+ const fallback = { frames: null, duration: 0, easing: DEFAULT_EASING };
1948
+ if (spec === "none") return fallback;
1949
+ if (spec === void 0 || typeof spec === "string") {
1950
+ const preset2 = PRESET_FRAMES[spec ?? "fade"];
1951
+ return {
1952
+ frames: preset2[phase],
1953
+ duration: DEFAULT_DURATION3,
1954
+ easing: DEFAULT_EASING
1955
+ };
1956
+ }
1957
+ const custom = phase === "enter" ? spec.enter : spec.exit;
1958
+ if (custom) {
1959
+ return {
1960
+ frames: custom,
1961
+ duration: spec.duration ?? DEFAULT_DURATION3,
1962
+ easing: spec.easing ?? DEFAULT_EASING
1963
+ };
1964
+ }
1965
+ if (spec.preset === "none") return fallback;
1966
+ const preset = PRESET_FRAMES[spec.preset ?? "fade"];
1967
+ return {
1968
+ frames: preset[phase],
1969
+ duration: spec.duration ?? DEFAULT_DURATION3,
1970
+ easing: spec.easing ?? DEFAULT_EASING
1971
+ };
1972
+ }
1973
+ function runAnchorTransition(el, spec, phase) {
1974
+ const respectReduced = typeof spec === "object" ? spec.respectReducedMotion !== false : true;
1975
+ if (respectReduced && prefersReducedMotion()) return INSTANT;
1976
+ const { frames, duration, easing } = resolveTransitionFrames(spec, phase);
1977
+ if (!frames || duration <= 0) return INSTANT;
1978
+ if (typeof el.animate !== "function") return INSTANT;
1979
+ const animation = el.animate(frames, {
1980
+ duration,
1981
+ easing,
1982
+ fill: "both"
1983
+ });
1984
+ const finished = animation.finished.then(() => void 0).catch(() => void 0);
1985
+ return {
1986
+ finished,
1987
+ cancel: () => {
1988
+ try {
1989
+ animation.cancel();
1990
+ } catch {
1991
+ return;
1992
+ }
1993
+ }
1994
+ };
1995
+ }
1996
+
1997
+ // src/core/features/sheet-anchors.ts
1998
+ function attachAnchor(deps, opts) {
1999
+ const doc = deps.host.ownerDocument;
2000
+ const wrapper = doc.createElement("div");
2001
+ wrapper.className = "bs-anchor";
2002
+ const interactive = opts.interactive ?? true;
2003
+ const position = opts.position ?? "sheet-top-right";
2004
+ const isDock = position === "dock-bottom" || position === "dock-top";
2005
+ const ws = wrapper.style;
2006
+ ws.position = "fixed";
2007
+ if (isDock) {
2008
+ ws.left = "0";
2009
+ ws.right = "0";
2010
+ if (position === "dock-bottom") {
2011
+ ws.bottom = "0";
2012
+ } else {
2013
+ ws.top = "0";
2014
+ }
2015
+ } else {
2016
+ applyOverlayPosition(ws, deps.mode, position, opts.inset ?? "16px");
2017
+ }
2018
+ if (opts.fadeRange) {
2019
+ const [r0, r1] = opts.fadeRange;
2020
+ const span = Math.max(r1 - r0, 1e-4);
2021
+ ws.opacity = `clamp(0, calc((var(--bs-progress, 0) - ${r0}) / ${span}), 1)`;
2022
+ }
2023
+ wrapper.appendChild(opts.element);
2024
+ deps.host.appendChild(wrapper);
2025
+ let visible = null;
2026
+ let inFlight = null;
2027
+ const shouldShow = (state) => {
2028
+ if (typeof opts.showOn === "function") return opts.showOn(state);
2029
+ if (Array.isArray(opts.showOn)) return opts.showOn.includes(state.activeId);
2030
+ return isDock || state.size > 0;
2031
+ };
2032
+ const applyVisibility = (next, animate) => {
2033
+ if (next === visible) return;
2034
+ visible = next;
2035
+ inFlight?.cancel();
2036
+ inFlight = null;
2037
+ wrapper.style.pointerEvents = next && interactive ? "auto" : "none";
2038
+ if (next) {
2039
+ wrapper.style.visibility = "";
2040
+ if (animate) {
2041
+ inFlight = runAnchorTransition(opts.element, opts.animation, "enter");
2042
+ }
2043
+ return;
2044
+ }
2045
+ if (!animate) {
2046
+ wrapper.style.visibility = "hidden";
2047
+ return;
2048
+ }
2049
+ const handle = runAnchorTransition(opts.element, opts.animation, "exit");
2050
+ inFlight = handle;
2051
+ void handle.finished.then(() => {
2052
+ if (inFlight === handle && visible === false) {
2053
+ wrapper.style.visibility = "hidden";
2054
+ }
2055
+ });
2056
+ };
2057
+ const evaluate = (animate) => {
2058
+ if (deps.isDestroyed()) return;
2059
+ applyVisibility(shouldShow(deps.getState()), animate);
2060
+ };
2061
+ const offs = [
2062
+ deps.on("snap", () => evaluate(true)),
2063
+ deps.on("open", () => evaluate(true)),
2064
+ deps.on("close", () => evaluate(true))
2065
+ ];
2066
+ evaluate(false);
2067
+ return {
2068
+ wrapper,
2069
+ detach: () => {
2070
+ offs.forEach((off) => off());
2071
+ inFlight?.cancel();
2072
+ inFlight = null;
2073
+ if (wrapper.parentNode) wrapper.parentNode.removeChild(wrapper);
2074
+ },
2075
+ syncZ: (z) => {
2076
+ wrapper.style.zIndex = String(z);
2077
+ }
2078
+ };
2079
+ }
2080
+
2081
+ // src/core/features/scrim-stages.ts
2082
+ var matchesId = (def, activeId) => {
2083
+ if (def.for === void 0) return false;
2084
+ return Array.isArray(def.for) ? def.for.includes(activeId) : def.for === activeId;
2085
+ };
2086
+ var matchesRange = (def, progress) => {
2087
+ if (!def.forRange) return false;
2088
+ const [from, to] = def.forRange;
2089
+ return progress >= from && progress <= to;
2090
+ };
2091
+ function installScrimStages(deps, opts) {
2092
+ const doc = deps.host.ownerDocument;
2093
+ const entries = opts.stages.map((def) => {
2094
+ const wrapper = doc.createElement("div");
2095
+ wrapper.className = "bs-scrim-stage";
2096
+ const ws = wrapper.style;
2097
+ ws.position = "absolute";
2098
+ applyOverlayPosition(
2099
+ ws,
2100
+ deps.mode,
2101
+ def.position ?? opts.position ?? "center",
2102
+ def.inset ?? opts.inset ?? "16px"
2103
+ );
2104
+ ws.visibility = "hidden";
2105
+ ws.pointerEvents = "none";
2106
+ wrapper.appendChild(def.element);
2107
+ deps.host.appendChild(wrapper);
2108
+ return { def, wrapper, inFlight: null };
2109
+ });
2110
+ let active = null;
2111
+ const resolveActive = () => {
2112
+ const state = deps.getState();
2113
+ if (state.size === 0) {
2114
+ return entries.find((e) => matchesId(e.def, state.activeId)) ?? null;
2115
+ }
2116
+ return entries.find((e) => matchesId(e.def, state.activeId)) ?? entries.find((e) => matchesRange(e.def, state.progress)) ?? null;
2117
+ };
2118
+ const hide = (entry, animate) => {
2119
+ entry.inFlight?.cancel();
2120
+ entry.wrapper.style.pointerEvents = "none";
2121
+ if (!animate) {
2122
+ entry.inFlight = null;
2123
+ entry.wrapper.style.visibility = "hidden";
2124
+ return;
2125
+ }
2126
+ const handle = runAnchorTransition(
2127
+ entry.def.element,
2128
+ entry.def.animation ?? opts.animation,
2129
+ "exit"
2130
+ );
2131
+ entry.inFlight = handle;
2132
+ void handle.finished.then(() => {
2133
+ if (entry.inFlight === handle && active !== entry) {
2134
+ entry.wrapper.style.visibility = "hidden";
2135
+ }
2136
+ });
2137
+ };
2138
+ const show = (entry, animate) => {
2139
+ entry.inFlight?.cancel();
2140
+ entry.inFlight = null;
2141
+ entry.wrapper.style.visibility = "";
2142
+ entry.wrapper.style.pointerEvents = entry.def.interactive ?? opts.interactive ?? false ? "auto" : "none";
2143
+ if (animate) {
2144
+ entry.inFlight = runAnchorTransition(
2145
+ entry.def.element,
2146
+ entry.def.animation ?? opts.animation,
2147
+ "enter"
2148
+ );
2149
+ }
2150
+ };
2151
+ const update = (animate) => {
2152
+ if (deps.isDestroyed()) return;
2153
+ const next = resolveActive();
2154
+ if (next === active) return;
2155
+ const prev = active;
2156
+ active = next;
2157
+ if (prev) hide(prev, animate);
2158
+ if (next) show(next, animate);
2159
+ };
2160
+ const offs = [
2161
+ deps.on("snap", () => update(true)),
2162
+ deps.on("open", () => update(true)),
2163
+ deps.on("close", () => update(true))
2164
+ ];
2165
+ if (entries.some((e) => e.def.forRange)) {
2166
+ offs.push(deps.on("progress", () => update(true)));
2167
+ }
2168
+ update(false);
2169
+ return () => {
2170
+ offs.forEach((off) => off());
2171
+ for (const entry of entries) {
2172
+ entry.inFlight?.cancel();
2173
+ entry.inFlight = null;
2174
+ if (entry.wrapper.parentNode) {
2175
+ entry.wrapper.parentNode.removeChild(entry.wrapper);
2176
+ }
2177
+ }
2178
+ active = null;
2179
+ };
2180
+ }
2181
+
1824
2182
  // src/core/primitives/engine-options.ts
1825
2183
  var DEFAULT_FLICK_VELOCITY = 0.65;
1826
2184
  var DEFAULT_DRAG_THRESHOLD = 18;
@@ -1937,6 +2295,12 @@ var BottomSheetEngine = class {
1937
2295
  __publicField(this, "linkedSheets", []);
1938
2296
  __publicField(this, "scrollCache");
1939
2297
  __publicField(this, "teardowns", new TeardownStack());
2298
+ __publicField(this, "anchors", []);
2299
+ __publicField(this, "anchorHost", null);
2300
+ __publicField(this, "stackZ", 100);
2301
+ __publicField(this, "detachScrimStages", null);
2302
+ __publicField(this, "stackEffectEnabled", false);
2303
+ __publicField(this, "stackEffectPrimed", false);
1940
2304
  __publicField(this, "transformTemplate");
1941
2305
  const resolved = resolveEngineOptions(opts, {
1942
2306
  shouldApplyInertSiblings: () => {
@@ -1970,6 +2334,9 @@ var BottomSheetEngine = class {
1970
2334
  getResolvedSnaps: () => this.snaps.getResolvedSnaps().slice(),
1971
2335
  snapTo: (id) => {
1972
2336
  void this.snapTo(id);
2337
+ },
2338
+ close: () => {
2339
+ void this.close();
1973
2340
  }
1974
2341
  },
1975
2342
  resolved.scrim
@@ -1993,6 +2360,7 @@ var BottomSheetEngine = class {
1993
2360
  );
1994
2361
  this.closeOnBack = resolved.closeOnBack;
1995
2362
  this.routedTo = opts.routedTo;
2363
+ this.stackEffectEnabled = opts.stackEffect ?? false;
1996
2364
  this.snapPointsRaw = opts.snapPoints;
1997
2365
  this.persistKey = opts.persistKey;
1998
2366
  if (opts.linkedSheets) {
@@ -2005,7 +2373,7 @@ var BottomSheetEngine = class {
2005
2373
  this.snapPointsRaw,
2006
2374
  resolved.initialAllowed,
2007
2375
  this.mode,
2008
- () => this.handle.offsetHeight,
2376
+ () => layoutAxis(this.mode) === "width" ? this.handle.offsetWidth : this.handle.offsetHeight,
2009
2377
  (maxAxisSize) => {
2010
2378
  this.element.style[layoutAxis(this.mode)] = `${maxAxisSize}px`;
2011
2379
  }
@@ -2215,11 +2583,6 @@ var BottomSheetEngine = class {
2215
2583
  }
2216
2584
  setAllowed(ids, snap) {
2217
2585
  if (this.destroyed) return;
2218
- const willSnap = snap !== void 0 && ids.includes(snap) || !ids.includes(this.activeId) && ids.length > 0;
2219
- if (!willSnap) {
2220
- this.animation.cancel();
2221
- this.newCycle();
2222
- }
2223
2586
  this.snaps.setAllowedIds(ids);
2224
2587
  this.updateAriaSlider();
2225
2588
  if (snap && ids.includes(snap)) {
@@ -2259,6 +2622,79 @@ var BottomSheetEngine = class {
2259
2622
  setScrimOverlay(opts) {
2260
2623
  return this.scrim.setScrimOverlay(opts);
2261
2624
  }
2625
+ addAnchor(opts) {
2626
+ if (this.destroyed || typeof document === "undefined") return () => {
2627
+ };
2628
+ if (!this.anchorHost) {
2629
+ this.anchorHost = this.rootEl ?? this.element.parentElement ?? document.body;
2630
+ this.anchorHost.style.setProperty("--bs-size", `${this.size}px`);
2631
+ this.anchorHost.style.setProperty(
2632
+ "--bs-progress",
2633
+ String(this.computeProgress(this.size))
2634
+ );
2635
+ }
2636
+ const handle = attachAnchor(
2637
+ {
2638
+ mode: this.mode,
2639
+ host: this.anchorHost,
2640
+ getState: () => ({
2641
+ activeId: this.activeId,
2642
+ size: this.size,
2643
+ progress: this.computeProgress(this.size)
2644
+ }),
2645
+ on: (event, fn) => this.on(event, fn),
2646
+ isDestroyed: () => this.destroyed
2647
+ },
2648
+ opts
2649
+ );
2650
+ handle.syncZ(this.stackZ + 1);
2651
+ this.anchors.push(handle);
2652
+ const detach = () => {
2653
+ const idx = this.anchors.indexOf(handle);
2654
+ if (idx === -1) return;
2655
+ this.anchors.splice(idx, 1);
2656
+ handle.detach();
2657
+ };
2658
+ this.teardowns.add(detach);
2659
+ return detach;
2660
+ }
2661
+ setScrimStages(opts) {
2662
+ if (this.destroyed || typeof document === "undefined") return () => {
2663
+ };
2664
+ this.detachScrimStages?.();
2665
+ this.detachScrimStages = null;
2666
+ if (!opts) return () => {
2667
+ };
2668
+ const host = this.screenComponent?.parentElement;
2669
+ if (!host) {
2670
+ console.warn(
2671
+ "[BottomSheet] setScrimStages: no scrim element mounted \u2014 pass `scrim` to the engine first."
2672
+ );
2673
+ return () => {
2674
+ };
2675
+ }
2676
+ const detachInstalled = installScrimStages(
2677
+ {
2678
+ mode: this.mode,
2679
+ host,
2680
+ getState: () => ({
2681
+ activeId: this.activeId,
2682
+ size: this.size,
2683
+ progress: this.computeProgress(this.size)
2684
+ }),
2685
+ on: (event, fn) => this.on(event, fn),
2686
+ isDestroyed: () => this.destroyed
2687
+ },
2688
+ opts
2689
+ );
2690
+ const detach = () => {
2691
+ if (this.detachScrimStages === detach) this.detachScrimStages = null;
2692
+ detachInstalled();
2693
+ };
2694
+ this.detachScrimStages = detach;
2695
+ this.teardowns.add(() => this.detachScrimStages?.());
2696
+ return detach;
2697
+ }
2262
2698
  getScrimState() {
2263
2699
  return { mode: this.scrim.scrimMode, enabled: this.scrim.scrimEnabled };
2264
2700
  }
@@ -2345,24 +2781,45 @@ var BottomSheetEngine = class {
2345
2781
  getAllowedRange() {
2346
2782
  return this.snaps.getAllowedRange();
2347
2783
  }
2784
+ allowedIdsBySize() {
2785
+ return this.snaps.getAllowedIds().slice().sort(
2786
+ (a, b) => (this.snaps.findById(a)?.size ?? 0) - (this.snaps.findById(b)?.size ?? 0)
2787
+ );
2788
+ }
2348
2789
  updateAriaSlider() {
2349
- this.aria.setValue(this.snaps.getAllowedIds(), this.activeId);
2790
+ this.aria.setValue(this.allowedIdsBySize(), this.activeId);
2350
2791
  }
2351
2792
  registerInStack() {
2352
2793
  this.teardowns.add(sheetStack.push({
2353
2794
  id: this.id,
2354
2795
  setZIndex: (z) => {
2796
+ this.stackZ = z;
2355
2797
  this.element.style.zIndex = String(z);
2356
2798
  if (this.backdrop) this.backdrop.style.zIndex = String(z - 1);
2799
+ for (const anchor of this.anchors) anchor.syncZ(z + 1);
2357
2800
  },
2358
2801
  setIsTop: (isTop) => {
2359
2802
  this.isTopSheet = isTop;
2360
2803
  if (this.backdrop) {
2361
2804
  this.backdrop.style.display = isTop ? "" : "none";
2362
2805
  }
2363
- }
2806
+ },
2807
+ isOpen: () => this.size > 0,
2808
+ setDepth: (depth) => this.applyStackDepth(depth)
2364
2809
  }));
2365
2810
  }
2811
+ applyStackDepth(depth) {
2812
+ if (!this.stackEffectEnabled) return;
2813
+ this.element.setAttribute("data-stack-depth", String(depth));
2814
+ if (!this.stackEffectPrimed) {
2815
+ this.stackEffectPrimed = true;
2816
+ const isVertical = this.mode === "bottom" || this.mode === "top";
2817
+ this.element.style.transformOrigin = isVertical ? "50% 100%" : "0% 50%";
2818
+ this.element.style.transition = "scale 320ms cubic-bezier(0.29, 1.04, 0.84, 0.99)";
2819
+ }
2820
+ const scale = Math.max(1 - depth * 0.04, 0.86);
2821
+ this.element.style.scale = scale === 1 ? "" : String(scale);
2822
+ }
2366
2823
  attach() {
2367
2824
  this.gesture = new GestureController({
2368
2825
  handle: this.handle,
@@ -2422,7 +2879,7 @@ var BottomSheetEngine = class {
2422
2879
  container: this.scrollContainer,
2423
2880
  isDragging: () => this.gesture?.isDragging ?? false,
2424
2881
  isAnimating: () => this.animation.isAnimating,
2425
- getAllowedIds: () => this.snaps.getAllowedIds(),
2882
+ getAllowedIds: () => this.allowedIdsBySize(),
2426
2883
  getActiveId: () => this.activeId,
2427
2884
  snapTo: (id) => {
2428
2885
  void this.snapTo(id);
@@ -2451,11 +2908,13 @@ var BottomSheetEngine = class {
2451
2908
  },
2452
2909
  newCycle: () => {
2453
2910
  this.newCycle();
2454
- }
2911
+ },
2912
+ isAnimating: () => this.animation.isAnimating,
2913
+ resyncAfterCancel: () => this.resyncAfterResize()
2455
2914
  }));
2456
2915
  if (this.lifecycle.closeOnEscape) {
2457
2916
  const onKey = (e) => {
2458
- if (this.destroyed) return;
2917
+ if (this.destroyed || e.defaultPrevented) return;
2459
2918
  if (e.key === "Escape" && this.isTopSheet && this.size > 0) {
2460
2919
  void this.close();
2461
2920
  }
@@ -2487,7 +2946,7 @@ var BottomSheetEngine = class {
2487
2946
  handle: this.handle,
2488
2947
  mode: this.mode,
2489
2948
  isDestroyed: () => this.destroyed,
2490
- getAllowedIds: () => this.snaps.getAllowedIds(),
2949
+ getAllowedIds: () => this.allowedIdsBySize(),
2491
2950
  getActiveId: () => this.activeId,
2492
2951
  snapTo: (id) => {
2493
2952
  void this.snapTo(id);
@@ -2508,6 +2967,7 @@ var BottomSheetEngine = class {
2508
2967
  });
2509
2968
  if (!target) return;
2510
2969
  const previousId = this.activeId;
2970
+ if (target.id === previousId && target.size === this.size) return;
2511
2971
  if (this.emitBeforeSnap(target, previousId)) {
2512
2972
  const restore = this.snaps.findById(previousId);
2513
2973
  if (restore) {
@@ -2516,6 +2976,7 @@ var BottomSheetEngine = class {
2516
2976
  return;
2517
2977
  }
2518
2978
  const previousSize = this.size;
2979
+ const previousSnapSize = this.snaps.findById(previousId)?.size;
2519
2980
  this.scrollCache.cache(previousId, previousSize, target.size);
2520
2981
  this.activeId = target.id;
2521
2982
  void this.animation.animateTo(target.size, velocity).then(() => {
@@ -2524,9 +2985,10 @@ var BottomSheetEngine = class {
2524
2985
  this.updateAriaSlider();
2525
2986
  this.emit("snap", { id: target.id, size: target.size });
2526
2987
  this.haptic();
2527
- if (previousId === "closed" && target.size > 0) {
2988
+ if (previousSnapSize === 0 && target.size > 0) {
2528
2989
  this.emit("open", { id: target.id });
2529
2990
  this.handleOpen();
2991
+ notifyLinkedSheets(this.linkedSheets, this);
2530
2992
  }
2531
2993
  if (target.size === 0) {
2532
2994
  this.emit("close", void 0);
@@ -2552,6 +3014,9 @@ var BottomSheetEngine = class {
2552
3014
  if (this.scrimParent) {
2553
3015
  this.scrimParent.style.setProperty("--bs-size", `${size}px`);
2554
3016
  }
3017
+ if (this.anchorHost && this.anchorHost !== this.scrimParent) {
3018
+ this.anchorHost.style.setProperty("--bs-size", `${size}px`);
3019
+ }
2555
3020
  }
2556
3021
  const progress = this.computeProgress(size);
2557
3022
  const progressChanged = this.progressWriteSentinel.shouldWrite(
@@ -2560,6 +3025,9 @@ var BottomSheetEngine = class {
2560
3025
  );
2561
3026
  if (progressChanged) {
2562
3027
  style.setProperty("--bs-progress", String(progress));
3028
+ if (this.anchorHost) {
3029
+ this.anchorHost.style.setProperty("--bs-progress", String(progress));
3030
+ }
2563
3031
  }
2564
3032
  this.scrim.applyOpacity(progress, progressChanged);
2565
3033
  if (progressChanged && this.bus.listenerCount("progress") > 0) {
@@ -2574,6 +3042,7 @@ var BottomSheetEngine = class {
2574
3042
  return Math.min(Math.max((size - min) / (max - min), 0), 1);
2575
3043
  }
2576
3044
  handleOpen() {
3045
+ sheetStack.promote(this.id);
2577
3046
  try {
2578
3047
  this.lifecycle.install();
2579
3048
  } catch (err) {
@@ -2587,8 +3056,24 @@ var BottomSheetEngine = class {
2587
3056
  });
2588
3057
  }
2589
3058
  }
3059
+ resyncAfterResize() {
3060
+ if (this.destroyed) return;
3061
+ const target = this.snaps.findById(this.activeId);
3062
+ if (!target) return;
3063
+ this.updateAriaSlider();
3064
+ this.emit("snap", { id: target.id, size: target.size });
3065
+ if (target.size > 0 && !this.lifecycle.isInstalled) {
3066
+ this.emit("open", { id: target.id });
3067
+ this.handleOpen();
3068
+ notifyLinkedSheets(this.linkedSheets, this);
3069
+ } else if (target.size === 0 && this.lifecycle.isInstalled) {
3070
+ this.emit("close", void 0);
3071
+ this.handleClose();
3072
+ }
3073
+ }
2590
3074
  handleClose() {
2591
3075
  this.lifecycle.release();
3076
+ sheetStack.update();
2592
3077
  }
2593
3078
  };
2594
3079
 
@@ -2657,6 +3142,10 @@ function useBottomSheet(opts) {
2657
3142
  setScrim: (opts2) => engine?.setScrim(opts2),
2658
3143
  setScrimOverlay: (opts2) => engine?.setScrimOverlay(opts2) ?? (() => {
2659
3144
  }),
3145
+ addAnchor: (opts2) => engine?.addAnchor(opts2) ?? (() => {
3146
+ }),
3147
+ setScrimStages: (opts2) => engine?.setScrimStages(opts2) ?? (() => {
3148
+ }),
2660
3149
  on: (event, fn) => {
2661
3150
  if (engine) return engine.on(event, fn);
2662
3151
  const entry = {
@@ -2808,6 +3297,10 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
2808
3297
  type: Boolean,
2809
3298
  required: false
2810
3299
  },
3300
+ stackEffect: {
3301
+ type: Boolean,
3302
+ required: false
3303
+ },
2811
3304
  snapPoints: {
2812
3305
  type: Array,
2813
3306
  required: true
@@ -3009,7 +3502,7 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
3009
3502
  ], 8, _hoisted_3)
3010
3503
  ]);
3011
3504
  }
3012
- var BottomSheet_default = /* @__PURE__ */ export_helper_default(_sfc_main, [["render", _sfc_render], ["__file", "/Users/maksimkravcov/Desktop/\u043F\u0440\u043E\u0435\u043A\u0442\u044B/BottomSheet/src/vue/BottomSheet.vue"]]);
3505
+ var BottomSheet_default = /* @__PURE__ */ export_helper_default(_sfc_main, [["render", _sfc_render], ["__file", "/home/runner/work/BottomSheet/BottomSheet/src/vue/BottomSheet.vue"]]);
3013
3506
 
3014
3507
  export { BottomSheet_default as BottomSheet, useBottomSheet };
3015
3508
  //# sourceMappingURL=vue.js.map