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