@surdeddd/bottom-sheet 0.23.4 → 0.24.1

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 (80) hide show
  1. package/README.md +513 -527
  2. package/README.ru.md +533 -545
  3. package/dist/{BottomSheetCore-C5tJYVMY.d.cts → BottomSheetCore-B_r4KCQL.d.cts} +48 -13
  4. package/dist/{BottomSheetCore-DxSrC4QC.d.ts → BottomSheetCore-B_r4KCQL.d.ts} +48 -13
  5. package/dist/{BottomSheetEngine-B3F9qukX.d.cts → BottomSheetEngine-0F7mjyvF.d.cts} +1 -1
  6. package/dist/{BottomSheetEngine-BchzgqGG.d.ts → BottomSheetEngine-CJV_DDrM.d.ts} +1 -1
  7. package/dist/core.cjs +810 -436
  8. package/dist/core.d.cts +2 -3
  9. package/dist/core.d.ts +2 -3
  10. package/dist/core.js +810 -436
  11. package/dist/debug.d.cts +0 -1
  12. package/dist/debug.d.ts +0 -1
  13. package/dist/{default-features-DwVTzDwP.d.ts → default-features-4Xwv6aVt.d.ts} +4 -2
  14. package/dist/{default-features-BGiCSmV1.d.cts → default-features-DX2NOxP6.d.cts} +4 -2
  15. package/dist/element.cjs +1421 -697
  16. package/dist/element.d.cts +11 -3
  17. package/dist/element.d.ts +11 -3
  18. package/dist/element.iife.global.js +2 -2
  19. package/dist/element.js +1421 -697
  20. package/dist/features.cjs +334 -190
  21. package/dist/features.d.cts +3 -4
  22. package/dist/features.d.ts +3 -4
  23. package/dist/features.js +334 -191
  24. package/dist/{index-C7TSQkVK.d.cts → index-2shlxhcG.d.cts} +1 -1
  25. package/dist/{index-CdM1tke5.d.ts → index-CNCRQnpc.d.ts} +1 -1
  26. package/dist/index.cjs +1129 -631
  27. package/dist/index.d.cts +11 -6
  28. package/dist/index.d.ts +11 -6
  29. package/dist/index.js +1129 -632
  30. package/dist/integrations/formik.cjs +21 -10
  31. package/dist/integrations/formik.d.cts +0 -1
  32. package/dist/integrations/formik.d.ts +0 -1
  33. package/dist/integrations/formik.js +22 -11
  34. package/dist/integrations/react-hook-form.cjs +21 -12
  35. package/dist/integrations/react-hook-form.d.cts +0 -1
  36. package/dist/integrations/react-hook-form.d.ts +0 -1
  37. package/dist/integrations/react-hook-form.js +21 -12
  38. package/dist/option-keys-DItuAjUw.d.cts +6 -0
  39. package/dist/option-keys-a5DYNwwO.d.ts +6 -0
  40. package/dist/overlay.cjs +386 -189
  41. package/dist/overlay.d.cts +1 -3
  42. package/dist/overlay.d.ts +1 -3
  43. package/dist/overlay.js +386 -189
  44. package/dist/preact.d.cts +3 -4
  45. package/dist/preact.d.ts +3 -4
  46. package/dist/qwik-lib/index.qwik.cjs +1306 -671
  47. package/dist/qwik-lib/index.qwik.mjs +1306 -671
  48. package/dist/qwik.cjs +1326 -701
  49. package/dist/qwik.d.cts +12 -30
  50. package/dist/qwik.d.ts +12 -30
  51. package/dist/qwik.js +1326 -701
  52. package/dist/react.cjs +1373 -750
  53. package/dist/react.d.cts +26 -12
  54. package/dist/react.d.ts +26 -12
  55. package/dist/react.js +1375 -752
  56. package/dist/solid.cjs +1332 -727
  57. package/dist/solid.d.cts +13 -438
  58. package/dist/solid.d.ts +13 -438
  59. package/dist/solid.js +1334 -729
  60. package/dist/solid.source.jsx +1374 -751
  61. package/dist/styles.css +20 -6
  62. package/dist/svelte-core.cjs +1209 -676
  63. package/dist/svelte-core.js +1207 -677
  64. package/dist/svelte-src/BottomSheet.svelte +101 -58
  65. package/dist/svelte.cjs +1323 -705
  66. package/dist/svelte.d.cts +45 -25
  67. package/dist/svelte.d.ts +45 -25
  68. package/dist/svelte.js +1323 -705
  69. package/dist/vue.cjs +1354 -773
  70. package/dist/vue.d.cts +20 -3
  71. package/dist/vue.d.ts +20 -3
  72. package/dist/vue.js +1354 -773
  73. package/dist/webgl.cjs +159 -53
  74. package/dist/webgl.d.cts +2 -2
  75. package/dist/webgl.d.ts +2 -2
  76. package/dist/webgl.js +159 -53
  77. package/llms.txt +330 -0
  78. package/package.json +42 -20
  79. package/dist/transform-jVfAikE9.d.cts +0 -3
  80. package/dist/transform-jVfAikE9.d.ts +0 -3
package/dist/svelte.cjs CHANGED
@@ -28,6 +28,15 @@ var __defProp = Object.defineProperty;
28
28
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
29
29
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
30
30
 
31
+ // src/core/primitives/shared.ts
32
+ var STORE_KEY = /* @__PURE__ */ Symbol.for("@surdeddd/bottom-sheet/shared/1");
33
+ function shared(name, init) {
34
+ const host = globalThis;
35
+ const store = host[STORE_KEY] ?? (host[STORE_KEY] = {});
36
+ if (!(name in store)) store[name] = init();
37
+ return store[name];
38
+ }
39
+
31
40
  // src/core/lifecycle/sheet-stack.ts
32
41
  var BASE_Z = 100;
33
42
  var STEP = 10;
@@ -95,7 +104,7 @@ var SheetStack = class {
95
104
  });
96
105
  }
97
106
  };
98
- var sheetStack = new SheetStack();
107
+ var sheetStack = shared("stack", () => new SheetStack());
99
108
 
100
109
  // src/core/primitives/transform.ts
101
110
  function buildTransformTemplate(axis) {
@@ -114,7 +123,7 @@ var offsetFromMatrix = (axis, m) => axis === "bottom" ? m.m42 : axis === "top" ?
114
123
  var layoutAxis = (axis) => axis === "left" || axis === "right" ? "width" : "height";
115
124
 
116
125
  // src/core/primitives/instance-id.ts
117
- var counters = {};
126
+ var counters = shared("instanceIds", () => ({}));
118
127
  function nextInstanceId(prefix) {
119
128
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
120
129
  return `${prefix}-${crypto.randomUUID()}`;
@@ -142,7 +151,13 @@ function createEventBus() {
142
151
  const set2 = listeners.get(event);
143
152
  if (!set2) return;
144
153
  for (const fn of [...set2]) {
145
- fn(payload);
154
+ try {
155
+ fn(payload);
156
+ } catch (err) {
157
+ queueMicrotask(() => {
158
+ throw err;
159
+ });
160
+ }
146
161
  }
147
162
  },
148
163
  listenerCount(event) {
@@ -154,8 +169,23 @@ function createEventBus() {
154
169
  };
155
170
  }
156
171
 
172
+ // src/core/primitives/dev-warn.ts
173
+ function devWarn(...args) {
174
+ if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
175
+ console.warn(...args);
176
+ }
177
+ }
178
+
157
179
  // src/core/primitives/css-length.ts
158
180
  var probe = null;
181
+ var rejected = /* @__PURE__ */ new Set();
182
+ var warnRejected = (value) => {
183
+ if (rejected.has(value)) return;
184
+ rejected.add(value);
185
+ devWarn(
186
+ `[BottomSheet] snap size "${value}" is not a CSS length the browser accepts \u2014 it resolves to 0.`
187
+ );
188
+ };
159
189
  var PROBE_ATTR = "data-bs-probe";
160
190
  var ensureProbe = (axis) => {
161
191
  if (typeof document === "undefined") return null;
@@ -202,19 +232,14 @@ var resolveSnap = (point, mode, measureFit) => {
202
232
  if (!el) return 0;
203
233
  if (axis === "vertical") {
204
234
  el.style.height = point;
235
+ if (el.style.height === "") warnRejected(point);
205
236
  return Math.max(0, el.getBoundingClientRect().height);
206
237
  }
207
238
  el.style.width = point;
239
+ if (el.style.width === "") warnRejected(point);
208
240
  return Math.max(0, el.getBoundingClientRect().width);
209
241
  };
210
242
 
211
- // src/core/primitives/dev-warn.ts
212
- function devWarn(...args) {
213
- if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
214
- console.warn(...args);
215
- }
216
- }
217
-
218
243
  // src/core/primitives/snap-points.ts
219
244
  var resolveSnapList = (points, mode, measureFit) => points.map((p) => {
220
245
  const raw = resolveSnap(p.size, mode, measureFit);
@@ -226,6 +251,10 @@ var resolveSnapList = (points, mode, measureFit) => points.map((p) => {
226
251
  }
227
252
  return { id: p.id, size: raw };
228
253
  }).sort((a, b) => a.size - b.size);
254
+ var startsClosed = (points, initial, allowed) => {
255
+ const id = initial ?? allowed?.[0] ?? points[0]?.id;
256
+ return points.find((p) => p.id === id)?.size === 0;
257
+ };
229
258
  var VH_NOT_DVH = /(^|[^a-z])vh\b/i;
230
259
  var auditVhUsage = (points) => {
231
260
  for (const p of points) {
@@ -343,6 +372,7 @@ var SnapResolver = class {
343
372
  setMode(mode) {
344
373
  if (mode === this.mode) return;
345
374
  this.mode = mode;
375
+ this.notified = false;
346
376
  this.recompute();
347
377
  }
348
378
  setAllowedIds(ids) {
@@ -352,14 +382,20 @@ var SnapResolver = class {
352
382
  findById(id) {
353
383
  return findById(id, this.resolved);
354
384
  }
355
- findDragSettleTarget(args) {
385
+ findDragSettleTarget(args, openOnly = false) {
356
386
  return findDragSettleTarget({
357
387
  ...args,
358
388
  resolved: this.resolved,
359
- allowed: this.allowedIds,
389
+ allowed: this.pool(openOnly),
360
390
  maxAxisSize: this.maxAxisSize
361
391
  });
362
392
  }
393
+ nearest(size, openOnly) {
394
+ return findNearest(size, this.resolved, this.pool(openOnly));
395
+ }
396
+ pool(openOnly) {
397
+ return openOnly ? this.allowedIds.filter((id) => (this.findById(id)?.size ?? 0) > 0) : this.allowedIds;
398
+ }
363
399
  getAllowedRange() {
364
400
  return this.rangeCache ?? (this.rangeCache = allowedRange(this.resolved, this.allowedIds));
365
401
  }
@@ -407,19 +443,20 @@ var POINTER_EVENTS_OPACITY_THRESHOLD = 0.05;
407
443
  var RANGE_DIVISION_EPSILON = 1e-4;
408
444
 
409
445
  // src/core/features/resize-observer.ts
446
+ var seatOf = (deps) => {
447
+ const snap = deps.resolveActiveSnap();
448
+ const max = deps.getMaxAxisSize();
449
+ return { target: snap ? Math.min(snap.size, max) : null, max };
450
+ };
451
+ var sameSeat = (before, after) => before.target !== null && after.target !== null && Math.abs(after.target - before.target) < SIZE_WRITE_EPSILON && Math.abs(after.max - before.max) < SIZE_WRITE_EPSILON;
410
452
  function installResizeObserver(deps) {
411
453
  if (typeof window === "undefined") {
412
454
  return () => {
413
455
  };
414
456
  }
415
- const seatFor = () => {
416
- const snap = deps.resolveActiveSnap();
417
- const max = deps.getMaxAxisSize();
418
- return { target: snap ? Math.min(snap.size, max) : null, max };
419
- };
420
457
  const onResize = () => {
421
458
  if (deps.isDestroyed()) return;
422
- const before = seatFor();
459
+ const before = seatOf(deps);
423
460
  deps.recomputeSnaps();
424
461
  const mode = deps.getMode();
425
462
  const isVerticalAxis = mode === "bottom" || mode === "top";
@@ -428,21 +465,8 @@ function installResizeObserver(deps) {
428
465
  if (viewportSize2 > 0 && viewportSize2 < max) {
429
466
  deps.setMaxAxisSize(viewportSize2);
430
467
  }
431
- const after = seatFor();
432
- if (before.target !== null && after.target !== null && Math.abs(after.target - before.target) < SIZE_WRITE_EPSILON && Math.abs(after.max - before.max) < SIZE_WRITE_EPSILON) {
433
- return;
434
- }
435
- const wasAnimating = deps.isAnimating?.() ?? false;
436
- deps.cancelInFlight();
437
- deps.newCycle();
438
- const current = deps.resolveActiveSnap();
439
- const newMax = deps.getMaxAxisSize();
440
- const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
441
- deps.setSize(targetSize);
442
- if (current && !deps.isDragging()) {
443
- deps.applySize(targetSize);
444
- if (wasAnimating) deps.resyncAfterCancel?.();
445
- }
468
+ if (sameSeat(before, seatOf(deps))) return;
469
+ deps.reseat();
446
470
  };
447
471
  let resizeObserver = null;
448
472
  if (typeof ResizeObserver !== "undefined") {
@@ -454,7 +478,7 @@ function installResizeObserver(deps) {
454
478
  window.addEventListener("orientationchange", onResize);
455
479
  const onVisibility = () => {
456
480
  if (deps.isDestroyed()) return;
457
- if (document.hidden) deps.cancelInFlight();
481
+ if (document.hidden) deps.landNow();
458
482
  };
459
483
  document.addEventListener("visibilitychange", onVisibility);
460
484
  return () => {
@@ -479,6 +503,16 @@ var contentTargets = (scroller) => {
479
503
  }
480
504
  return out;
481
505
  };
506
+ var chromeTargets = (deps) => {
507
+ const out = [];
508
+ for (const child2 of Array.from(deps.element.children)) {
509
+ if (child2 !== deps.scrollContainer) out.push(child2);
510
+ }
511
+ if (deps.handle !== deps.element && !out.includes(deps.handle)) {
512
+ out.push(deps.handle);
513
+ }
514
+ return out;
515
+ };
482
516
  function installFitObserver(deps) {
483
517
  if (typeof ResizeObserver === "undefined") return () => {
484
518
  };
@@ -494,7 +528,6 @@ function installFitObserver(deps) {
494
528
  });
495
529
  };
496
530
  const ro = new ResizeObserver(schedule);
497
- ro.observe(deps.handle);
498
531
  const scroller = deps.scrollContainer;
499
532
  const observed = /* @__PURE__ */ new Set();
500
533
  const slots = /* @__PURE__ */ new Set();
@@ -511,7 +544,7 @@ function installFitObserver(deps) {
511
544
  };
512
545
  const resync = () => {
513
546
  trackSlots();
514
- const targets = contentTargets(scroller);
547
+ const targets = [...chromeTargets(deps), ...contentTargets(scroller)];
515
548
  for (const el of observed) {
516
549
  if (!targets.includes(el)) {
517
550
  ro.unobserve(el);
@@ -526,13 +559,12 @@ function installFitObserver(deps) {
526
559
  }
527
560
  schedule();
528
561
  };
562
+ resync();
529
563
  let mo;
530
- if (scroller) {
531
- resync();
532
- if (typeof MutationObserver !== "undefined") {
533
- mo = new MutationObserver(resync);
534
- mo.observe(scroller, { childList: true });
535
- }
564
+ if (typeof MutationObserver !== "undefined") {
565
+ mo = new MutationObserver(resync);
566
+ mo.observe(deps.element, { childList: true });
567
+ if (scroller) mo.observe(scroller, { childList: true });
536
568
  }
537
569
  return () => {
538
570
  ro.disconnect();
@@ -544,6 +576,72 @@ function installFitObserver(deps) {
544
576
  };
545
577
  }
546
578
 
579
+ // src/core/features/teleport.ts
580
+ var resolveTeleportTarget = (target) => {
581
+ if (!target) return null;
582
+ if (typeof target !== "string") return target;
583
+ if (typeof document === "undefined") return null;
584
+ if (target === "body") return document.body;
585
+ return document.querySelector(target);
586
+ };
587
+ var ROOT_CLASS = "bs-root";
588
+ var homes = /* @__PURE__ */ new WeakMap();
589
+ var homeRootOf = (root2) => (root2 && homes.get(root2)) ?? null;
590
+ var mirrorClasses = (home, wrapper) => {
591
+ wrapper.className = home?.className ?? "";
592
+ wrapper.classList.add(ROOT_CLASS);
593
+ };
594
+ var teleportElements = (els, target) => {
595
+ const nodes = els.filter(
596
+ (el) => !!el && el.parentNode !== target
597
+ );
598
+ if (nodes.length === 0) return () => {
599
+ };
600
+ const home = nodes[0].closest(`.${ROOT_CLASS}`);
601
+ if (home && home.parentNode === target) return () => {
602
+ };
603
+ const wrapper = target.ownerDocument.createElement("div");
604
+ wrapper.setAttribute("data-bs-teleported", "");
605
+ mirrorClasses(home, wrapper);
606
+ let watcher = null;
607
+ if (home) {
608
+ for (const name of Array.from(home.style)) {
609
+ if (name.startsWith("--")) {
610
+ wrapper.style.setProperty(name, home.style.getPropertyValue(name));
611
+ }
612
+ }
613
+ homes.set(wrapper, home);
614
+ if (typeof MutationObserver !== "undefined") {
615
+ watcher = new MutationObserver(() => mirrorClasses(home, wrapper));
616
+ watcher.observe(home, { attributes: true, attributeFilter: ["class"] });
617
+ }
618
+ }
619
+ target.appendChild(wrapper);
620
+ const records = [];
621
+ for (const el of nodes) {
622
+ records.push({ el, parent: el.parentNode, next: el.nextSibling });
623
+ wrapper.appendChild(el);
624
+ }
625
+ return () => {
626
+ watcher?.disconnect();
627
+ for (let i = records.length - 1; i >= 0; i--) {
628
+ const { el, parent, next } = records[i];
629
+ if (parent && parent.isConnected) {
630
+ const before = next && next.parentNode === parent ? next : null;
631
+ try {
632
+ parent.insertBefore(el, before);
633
+ } catch {
634
+ el.parentNode?.removeChild(el);
635
+ }
636
+ } else {
637
+ el.parentNode?.removeChild(el);
638
+ }
639
+ }
640
+ homes.delete(wrapper);
641
+ wrapper.parentNode?.removeChild(wrapper);
642
+ };
643
+ };
644
+
547
645
  // src/core/features/max-height-controller.ts
548
646
  function createMaxHeightController(deps) {
549
647
  let maxHeightCap;
@@ -647,8 +745,9 @@ function installSliderKeyboard(deps) {
647
745
  const isVerticalAxis = deps.mode === "bottom" || deps.mode === "top";
648
746
  const stepUp = isVerticalAxis ? "ArrowUp" : "ArrowRight";
649
747
  const stepDown = isVerticalAxis ? "ArrowDown" : "ArrowLeft";
650
- const sheetExpandsKey = deps.mode === "top" ? stepDown : stepUp;
651
- const sheetCollapsesKey = deps.mode === "top" ? stepUp : stepDown;
748
+ const flipped = deps.mode === "top" || deps.mode === "right";
749
+ const sheetExpandsKey = flipped ? stepDown : stepUp;
750
+ const sheetCollapsesKey = flipped ? stepUp : stepDown;
652
751
  const onHandleKey = (e) => {
653
752
  if (deps.isDestroyed()) return;
654
753
  const allowed = deps.getAllowedIds();
@@ -724,11 +823,12 @@ var WriteSentinel = class {
724
823
  // src/core/primitives/overlay-position.ts
725
824
  function resolveSheetAnchoredStyle(mode, position, inset) {
726
825
  const sizeOffset = `calc(var(--bs-size, 0px) + ${inset})`;
826
+ const lifted = `calc(var(--bs-size, 0px) + var(--bs-keyboard-inset, 0px) + ${inset})`;
727
827
  switch (mode) {
728
828
  case "bottom":
729
- if (position === "sheet-top-left") return { bottom: sizeOffset, left: inset };
730
- if (position === "sheet-top-right") return { bottom: sizeOffset, right: inset };
731
- return { bottom: sizeOffset, left: "50%", transform: "translateX(-50%)" };
829
+ if (position === "sheet-top-left") return { bottom: lifted, left: inset };
830
+ if (position === "sheet-top-right") return { bottom: lifted, right: inset };
831
+ return { bottom: lifted, left: "50%", transform: "translateX(-50%)" };
732
832
  case "top":
733
833
  if (position === "sheet-top-left") return { top: sizeOffset, left: inset };
734
834
  if (position === "sheet-top-right") return { top: sizeOffset, right: inset };
@@ -743,6 +843,13 @@ function resolveSheetAnchoredStyle(mode, position, inset) {
743
843
  return { right: sizeOffset, top: "50%", transform: "translateY(-50%)" };
744
844
  }
745
845
  }
846
+ function resetOverlayPosition(ws) {
847
+ ws.top = "";
848
+ ws.bottom = "";
849
+ ws.left = "";
850
+ ws.right = "";
851
+ ws.transform = "";
852
+ }
746
853
  function applyOverlayPosition(ws, mode, position, inset) {
747
854
  switch (position) {
748
855
  case "top-left":
@@ -803,6 +910,8 @@ function applyOverlayPosition(ws, mode, position, inset) {
803
910
  // src/core/controllers/scrim-controller.ts
804
911
  var VALID_CSS_LENGTH = /^-?\d+(?:\.\d+)?(?:px|em|rem|%)$/;
805
912
  var DEFAULT_SCRIM_DIM = "rgba(0, 0, 0, 0.4)";
913
+ var BACKDROP_COLOR_VAR = "--bs-backdrop-color";
914
+ var unit = (value) => Number.isFinite(value) ? Math.min(Math.max(value, 0), 1) : 1;
806
915
  var ScrimController = class {
807
916
  constructor(deps, opts) {
808
917
  __publicField(this, "screenComponent");
@@ -817,11 +926,13 @@ var ScrimController = class {
817
926
  __publicField(this, "scrimMode");
818
927
  __publicField(this, "backdropRange");
819
928
  __publicField(this, "screenRange");
929
+ __publicField(this, "backdropPeak");
820
930
  __publicField(this, "scrimEnabled", true);
821
931
  __publicField(this, "savedScrimRanges", null);
822
932
  __publicField(this, "scrimTapToCloseEnabled", false);
823
933
  __publicField(this, "detachScrimTap", null);
824
934
  __publicField(this, "scrimOverlayTeardown", null);
935
+ __publicField(this, "placeOverlay", null);
825
936
  __publicField(this, "backdropOpacitySentinel", new WriteSentinel());
826
937
  __publicField(this, "screenOpacitySentinel", new WriteSentinel());
827
938
  __publicField(this, "lastBackdropPointer", "");
@@ -838,6 +949,8 @@ var ScrimController = class {
838
949
  const preset = opts.scrimPreset ? SCRIM_PRESETS[opts.scrimPreset] : null;
839
950
  this.backdropRange = opts.backdropRange ?? preset?.range ?? [0, 1];
840
951
  this.screenRange = opts.screenRange ?? preset?.range ?? [0, 1];
952
+ this.backdropPeak = unit(opts.backdropOpacity ?? 1);
953
+ this.setBackdropColor(opts.backdropColor);
841
954
  this.scrimTapToCloseEnabled = opts.scrimTapToClose ?? false;
842
955
  const explicitColor = opts.scrimColor ?? preset?.color;
843
956
  const effectiveColor = explicitColor ?? (this.scrimMode !== "off" && !this.backdrop ? DEFAULT_SCRIM_DIM : void 0);
@@ -867,24 +980,19 @@ var ScrimController = class {
867
980
  this.setScrimTapToClose(true);
868
981
  }
869
982
  }
870
- applyOpacity(progress, progressChanged) {
871
- if (!progressChanged && this.backdropOpacitySentinel.value !== -1 && this.screenOpacitySentinel.value !== -1) {
983
+ applyOpacity(progress, progressChanged, epsilon = OPACITY_WRITE_EPSILON) {
984
+ if (epsilon > 0 && !progressChanged && this.backdropOpacitySentinel.value !== -1 && this.screenOpacitySentinel.value !== -1) {
872
985
  return;
873
986
  }
874
987
  if (this.backdrop) {
875
988
  const [s, e] = this.backdropRange;
876
989
  const range = Math.max(e - s, RANGE_DIVISION_EPSILON);
877
- const backdropOpacity = Math.min(
878
- Math.max((progress - s) / range, 0),
879
- 1
880
- );
881
- if (this.backdropOpacitySentinel.shouldWrite(
882
- backdropOpacity,
883
- OPACITY_WRITE_EPSILON
884
- )) {
990
+ const along = Math.min(Math.max((progress - s) / range, 0), 1);
991
+ const backdropOpacity = along * this.backdropPeak;
992
+ if (this.backdropOpacitySentinel.shouldWrite(backdropOpacity, epsilon)) {
885
993
  this.backdrop.style.opacity = String(backdropOpacity);
886
994
  }
887
- const nextPointer = backdropOpacity > POINTER_EVENTS_OPACITY_THRESHOLD ? "auto" : "none";
995
+ const nextPointer = along > POINTER_EVENTS_OPACITY_THRESHOLD ? "auto" : "none";
888
996
  if (nextPointer !== this.lastBackdropPointer) {
889
997
  this.backdrop.style.pointerEvents = nextPointer;
890
998
  this.lastBackdropPointer = nextPointer;
@@ -899,10 +1007,7 @@ var ScrimController = class {
899
1007
  (progress - ss) / Math.max(RANGE_DIVISION_EPSILON, se - ss)
900
1008
  )
901
1009
  );
902
- if (this.screenOpacitySentinel.shouldWrite(
903
- screenOpacity,
904
- OPACITY_WRITE_EPSILON
905
- )) {
1010
+ if (this.screenOpacitySentinel.shouldWrite(screenOpacity, epsilon)) {
906
1011
  this.screenComponent.style.opacity = String(screenOpacity);
907
1012
  }
908
1013
  const nextDisplay = screenOpacity > 0 ? "" : "none";
@@ -918,6 +1023,17 @@ var ScrimController = class {
918
1023
  this.invalidateOpacityCache();
919
1024
  applySize();
920
1025
  }
1026
+ setBackdropColor(color) {
1027
+ if (this.isDestroyed() || !this.backdrop) return;
1028
+ if (color) this.backdrop.style.setProperty(BACKDROP_COLOR_VAR, color);
1029
+ else this.backdrop.style.removeProperty(BACKDROP_COLOR_VAR);
1030
+ }
1031
+ setBackdropOpacity(value, applySize) {
1032
+ if (this.isDestroyed()) return;
1033
+ this.backdropPeak = unit(value);
1034
+ this.invalidateOpacityCache();
1035
+ applySize();
1036
+ }
921
1037
  setScreenRange(range, applySize) {
922
1038
  if (this.isDestroyed()) return;
923
1039
  this.screenRange = range;
@@ -940,6 +1056,8 @@ var ScrimController = class {
940
1056
  if (this.isDestroyed() || mode === this.mode) return;
941
1057
  this.mode = mode;
942
1058
  this.invalidateOpacityCache();
1059
+ if (this.scrimMode === "above-sheet") this.applyAboveSheetInset();
1060
+ this.placeOverlay?.();
943
1061
  }
944
1062
  setScrimMode(mode, applySize) {
945
1063
  if (this.isDestroyed()) return;
@@ -952,7 +1070,7 @@ var ScrimController = class {
952
1070
  if (previous === "above-sheet" && mode !== "above-sheet") {
953
1071
  s.position = "";
954
1072
  s.inset = "";
955
- s.pointerEvents = "";
1073
+ this.syncPointer();
956
1074
  }
957
1075
  if (mode === "above-sheet") {
958
1076
  this.applyAboveSheetInset();
@@ -977,9 +1095,6 @@ var ScrimController = class {
977
1095
  if (enabled === installed) return;
978
1096
  if (enabled) {
979
1097
  const target = this.screenComponent;
980
- if (target.style.pointerEvents === "none") {
981
- target.style.pointerEvents = "auto";
982
- }
983
1098
  const onClick = () => {
984
1099
  if (this.isDestroyed()) return;
985
1100
  if (this.closeFn) {
@@ -1002,6 +1117,11 @@ var ScrimController = class {
1002
1117
  this.detachScrimTap = null;
1003
1118
  this.scrimTapToCloseEnabled = false;
1004
1119
  }
1120
+ this.syncPointer();
1121
+ }
1122
+ syncPointer() {
1123
+ if (!this.screenComponent) return;
1124
+ this.screenComponent.style.pointerEvents = this.scrimInteractive || this.detachScrimTap ? "auto" : "none";
1005
1125
  }
1006
1126
  setScrimEnabled(enabled, applySize) {
1007
1127
  if (this.isDestroyed()) return;
@@ -1085,8 +1205,12 @@ var ScrimController = class {
1085
1205
  const wrapper = screen.ownerDocument.createElement("div");
1086
1206
  wrapper.className = "bs-scrim-overlay";
1087
1207
  const ws = wrapper.style;
1088
- ws.position = "absolute";
1089
- applyOverlayPosition(ws, this.mode, position, inset);
1208
+ ws.position = "fixed";
1209
+ const place = () => {
1210
+ resetOverlayPosition(ws);
1211
+ applyOverlayPosition(ws, this.mode, position, inset);
1212
+ };
1213
+ place();
1090
1214
  if (interactive) {
1091
1215
  ws.pointerEvents = "auto";
1092
1216
  }
@@ -1100,8 +1224,10 @@ var ScrimController = class {
1100
1224
  };
1101
1225
  }
1102
1226
  host.appendChild(wrapper);
1227
+ this.placeOverlay = place;
1103
1228
  const teardown = () => {
1104
1229
  if (wrapper.parentNode) wrapper.parentNode.removeChild(wrapper);
1230
+ if (this.placeOverlay === place) this.placeOverlay = null;
1105
1231
  if (this.scrimOverlayTeardown === teardown) {
1106
1232
  this.scrimOverlayTeardown = null;
1107
1233
  }
@@ -1125,6 +1251,7 @@ var ScrimController = class {
1125
1251
  if (this.backdrop) {
1126
1252
  this.backdrop.style.opacity = "";
1127
1253
  this.backdrop.style.pointerEvents = "";
1254
+ this.backdrop.style.removeProperty(BACKDROP_COLOR_VAR);
1128
1255
  }
1129
1256
  this.invalidateOpacityCache();
1130
1257
  this.lastBackdropPointer = "";
@@ -1149,13 +1276,13 @@ var ScrimController = class {
1149
1276
  }
1150
1277
  if (opts.interactive !== void 0) {
1151
1278
  this.scrimInteractive = opts.interactive;
1152
- s.pointerEvents = opts.interactive ? "auto" : "none";
1279
+ this.syncPointer();
1153
1280
  }
1154
1281
  }
1155
1282
  applyAboveSheetInset() {
1156
1283
  if (!this.screenComponent) return;
1157
1284
  const insetByMode = {
1158
- bottom: "0 0 var(--bs-size) 0",
1285
+ bottom: "0 0 calc(var(--bs-size) + var(--bs-keyboard-inset, 0px)) 0",
1159
1286
  top: "var(--bs-size) 0 0 0",
1160
1287
  left: "0 0 0 var(--bs-size)",
1161
1288
  right: "0 var(--bs-size) 0 0"
@@ -1163,7 +1290,7 @@ var ScrimController = class {
1163
1290
  const s = this.screenComponent.style;
1164
1291
  s.position = "fixed";
1165
1292
  s.inset = insetByMode[this.mode];
1166
- s.pointerEvents = this.scrimInteractive || this.scrimTapToCloseEnabled ? "auto" : "none";
1293
+ this.syncPointer();
1167
1294
  }
1168
1295
  };
1169
1296
 
@@ -1176,6 +1303,7 @@ var easeOutBack = (t) => {
1176
1303
  var easeOutCubic = (t) => 1 - Math.pow(1 - t, 3);
1177
1304
  var easeLinear = (t) => t;
1178
1305
  var easeOutQuint = (t) => 1 - Math.pow(1 - t, 5);
1306
+ var MIN_RETARGET_MS = 120;
1179
1307
  var tween = ({
1180
1308
  from,
1181
1309
  to,
@@ -1184,12 +1312,18 @@ var tween = ({
1184
1312
  onUpdate
1185
1313
  }) => {
1186
1314
  let cancelled = false;
1315
+ let finished = false;
1187
1316
  let rafId = 0;
1188
1317
  let resolveFn = null;
1189
- const start = performance.now();
1318
+ let start = performance.now();
1319
+ let origin = from;
1320
+ let target = to;
1321
+ let span = duration;
1322
+ let last = from;
1190
1323
  const promise = new Promise((resolve) => {
1191
1324
  resolveFn = resolve;
1192
1325
  if (duration <= 0) {
1326
+ finished = true;
1193
1327
  onUpdate(to);
1194
1328
  resolve();
1195
1329
  return;
@@ -1197,12 +1331,13 @@ var tween = ({
1197
1331
  const step = (now) => {
1198
1332
  if (cancelled) return;
1199
1333
  const elapsed = Math.max(0, now - start);
1200
- const t = Math.min(elapsed / duration, 1);
1201
- const value = from + (to - from) * easing(t);
1202
- onUpdate(value);
1334
+ const t = Math.min(elapsed / span, 1);
1335
+ last = origin + (target - origin) * easing(t);
1336
+ onUpdate(last);
1203
1337
  if (t < 1) {
1204
1338
  rafId = requestAnimationFrame(step);
1205
1339
  } else {
1340
+ finished = true;
1206
1341
  resolve();
1207
1342
  }
1208
1343
  };
@@ -1214,6 +1349,15 @@ var tween = ({
1214
1349
  cancelAnimationFrame(rafId);
1215
1350
  resolveFn?.();
1216
1351
  },
1352
+ retarget: (next) => {
1353
+ if (cancelled || finished || next === target) return;
1354
+ const now = performance.now();
1355
+ const remaining = span - Math.max(0, now - start);
1356
+ origin = last;
1357
+ target = next;
1358
+ start = now;
1359
+ span = Math.max(remaining, MIN_RETARGET_MS);
1360
+ },
1217
1361
  promise
1218
1362
  };
1219
1363
  };
@@ -1231,22 +1375,32 @@ var DEFAULT_SPRING = {
1231
1375
  restSpeed: 0.5
1232
1376
  };
1233
1377
  var MAX_DT = 1 / 30;
1378
+ var MAX_DURATION_MS = 3e3;
1234
1379
  var runSpring = ({
1235
1380
  from,
1236
1381
  to,
1237
1382
  velocity = 0,
1238
1383
  config,
1384
+ maxDuration = MAX_DURATION_MS,
1239
1385
  onUpdate
1240
1386
  }) => {
1241
1387
  const cfg = { ...DEFAULT_SPRING, ...config };
1242
1388
  let cancelled = false;
1389
+ let finished = false;
1243
1390
  let rafId = 0;
1244
1391
  let resolveFn = null;
1245
1392
  let x = from;
1246
1393
  let v = velocity;
1394
+ let target = to;
1247
1395
  let lastTime = performance.now();
1396
+ let deadline = lastTime + maxDuration;
1248
1397
  const promise = new Promise((resolve) => {
1249
1398
  resolveFn = resolve;
1399
+ const land = () => {
1400
+ finished = true;
1401
+ onUpdate(target, 0);
1402
+ resolve();
1403
+ };
1250
1404
  const step = (now) => {
1251
1405
  if (cancelled) return;
1252
1406
  const dt = Math.min(Math.max(0, now - lastTime) / 1e3, MAX_DT);
@@ -1255,21 +1409,19 @@ var runSpring = ({
1255
1409
  const subDt = dt / steps;
1256
1410
  let stepsLeft = steps;
1257
1411
  while (stepsLeft-- > 0) {
1258
- const force = -cfg.stiffness * (x - to) - cfg.damping * v;
1412
+ const force = -cfg.stiffness * (x - target) - cfg.damping * v;
1259
1413
  const accel = force / cfg.mass;
1260
1414
  v += accel * subDt;
1261
1415
  x += v * subDt;
1262
1416
  }
1263
- if (!Number.isFinite(x) || !Number.isFinite(v)) {
1264
- onUpdate(to, 0);
1265
- resolve();
1417
+ if (!Number.isFinite(x) || !Number.isFinite(v) || lastTime >= deadline) {
1418
+ land();
1266
1419
  return;
1267
1420
  }
1268
1421
  onUpdate(x, v);
1269
- const isAtRest = Math.abs(to - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
1422
+ const isAtRest = Math.abs(target - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
1270
1423
  if (isAtRest) {
1271
- onUpdate(to, 0);
1272
- resolve();
1424
+ land();
1273
1425
  } else {
1274
1426
  rafId = requestAnimationFrame(step);
1275
1427
  }
@@ -1282,6 +1434,11 @@ var runSpring = ({
1282
1434
  cancelAnimationFrame(rafId);
1283
1435
  resolveFn?.();
1284
1436
  },
1437
+ retarget: (next) => {
1438
+ if (cancelled || finished) return;
1439
+ target = next;
1440
+ deadline = performance.now() + maxDuration;
1441
+ },
1285
1442
  promise
1286
1443
  };
1287
1444
  };
@@ -1433,21 +1590,40 @@ var AnimationRunner = class {
1433
1590
  this.applySizeFn(size);
1434
1591
  }
1435
1592
  cancel() {
1436
- this.currentTween?.cancel();
1437
- this.currentSpring?.cancel();
1593
+ const tween2 = this.currentTween;
1594
+ const spring = this.currentSpring;
1595
+ this.currentTween = null;
1596
+ this.currentSpring = null;
1597
+ tween2?.cancel();
1598
+ spring?.cancel();
1438
1599
  this.cancelWaapi();
1439
1600
  }
1601
+ retarget(target) {
1602
+ if (this.currentSpring) {
1603
+ this.currentSpring.retarget(target);
1604
+ return true;
1605
+ }
1606
+ if (this.currentTween) {
1607
+ this.currentTween.retarget(target);
1608
+ return true;
1609
+ }
1610
+ if (this.currentWaapi) {
1611
+ this.currentWaapi.retarget(target);
1612
+ return true;
1613
+ }
1614
+ return false;
1615
+ }
1440
1616
  async animateTo(target, velocityPxPerMs) {
1441
1617
  if (target === this.getSize()) {
1442
- if (!this.isAnimating && !this.isDragging()) {
1618
+ if (this.isAnimating) this.cancel();
1619
+ if (!this.isDragging()) {
1443
1620
  this.applySizeFn(target);
1621
+ this.getRootEl()?.removeAttribute("data-animating");
1444
1622
  this.element.style.willChange = "";
1445
1623
  }
1446
1624
  return;
1447
1625
  }
1448
- this.currentTween?.cancel();
1449
- this.currentSpring?.cancel();
1450
- this.cancelWaapi();
1626
+ this.cancel();
1451
1627
  this.getRootEl()?.setAttribute("data-animating", "true");
1452
1628
  this.element.style.willChange = "transform";
1453
1629
  if (this.reducedMotion) {
@@ -1457,19 +1633,13 @@ var AnimationRunner = class {
1457
1633
  return;
1458
1634
  }
1459
1635
  if (this.settleWaapi && this.applyAux && this.getTransformFor && typeof this.element.animate === "function") {
1460
- const samples = this.animationKind === "spring" ? sampleSpringSettle(
1461
- this.getSize(),
1462
- target,
1463
- velocityPxPerMs * VELOCITY_PX_PER_S,
1464
- this.springConfig
1465
- ) : sampleTweenSettle(
1636
+ const samples = this.sampleSettle(
1466
1637
  this.getSize(),
1467
1638
  target,
1468
- this.duration,
1469
- this.easing
1639
+ velocityPxPerMs * VELOCITY_PX_PER_S
1470
1640
  );
1471
1641
  if (samples.values.length >= 2 && samples.durationMs > 0) {
1472
- await this.runWaapiSettle(samples, target);
1642
+ await this.runWaapiSettle({ samples, target });
1473
1643
  if (!this.isAnimating) {
1474
1644
  this.getRootEl()?.removeAttribute("data-animating");
1475
1645
  if (!this.isDragging()) this.element.style.willChange = "";
@@ -1511,7 +1681,10 @@ var AnimationRunner = class {
1511
1681
  }
1512
1682
  }
1513
1683
  }
1514
- async runWaapiSettle(samples, target) {
1684
+ sampleSettle(from, to, velocityPxPerS) {
1685
+ return this.animationKind === "spring" ? sampleSpringSettle(from, to, velocityPxPerS, this.springConfig) : sampleTweenSettle(from, to, this.duration, this.easing);
1686
+ }
1687
+ startWaapiLeg(samples, onRetarget) {
1515
1688
  const applyAux = this.applyAux;
1516
1689
  const getTransformFor = this.getTransformFor;
1517
1690
  const frames = samples.values.map((v) => ({
@@ -1526,16 +1699,20 @@ var AnimationRunner = class {
1526
1699
  let stopped = false;
1527
1700
  let auxRaf = 0;
1528
1701
  const lastIdx = samples.values.length - 1;
1702
+ const cursor = () => Math.min((Number(anim.currentTime) || 0) / samples.stepMs, lastIdx);
1529
1703
  const sizeNow = () => {
1530
- const at = Math.min(
1531
- (Number(anim.currentTime) || 0) / samples.stepMs,
1532
- lastIdx
1533
- );
1704
+ const at = cursor();
1534
1705
  const idx = Math.floor(at);
1535
1706
  const from = samples.values[idx];
1536
1707
  const to = samples.values[Math.min(idx + 1, lastIdx)];
1537
1708
  return from + (to - from) * (at - idx);
1538
1709
  };
1710
+ const velocityNow = () => {
1711
+ const idx = Math.min(Math.floor(cursor()), Math.max(lastIdx - 1, 0));
1712
+ const from = samples.values[idx];
1713
+ const to = samples.values[Math.min(idx + 1, lastIdx)];
1714
+ return (to - from) / samples.stepMs * 1e3;
1715
+ };
1539
1716
  const auxTick = () => {
1540
1717
  if (stopped) return;
1541
1718
  applyAux(sizeNow());
@@ -1548,22 +1725,55 @@ var AnimationRunner = class {
1548
1725
  stopped = true;
1549
1726
  cancelAnimationFrame(auxRaf);
1550
1727
  },
1551
- sizeNow
1728
+ sizeNow,
1729
+ velocityNow,
1730
+ retarget: (to) => onRetarget(entry, to)
1552
1731
  };
1553
- this.currentWaapi = entry;
1554
- try {
1555
- await anim.finished;
1556
- } catch {
1557
- }
1558
- entry.stop();
1559
- const wasCurrent = this.currentWaapi === entry;
1560
- if (wasCurrent) this.currentWaapi = null;
1561
- if (wasCurrent && anim.playState === "finished") {
1562
- this.applySizeFn(target);
1732
+ return entry;
1733
+ }
1734
+ async runWaapiSettle(first) {
1735
+ let leg = first;
1736
+ for (; ; ) {
1737
+ let queued = null;
1738
+ const entry = this.startWaapiLeg(leg.samples, (running, to) => {
1739
+ const size = this.readShownSize?.() ?? running.sizeNow();
1740
+ queued = {
1741
+ samples: this.sampleSettle(size, to, running.velocityNow()),
1742
+ target: to
1743
+ };
1744
+ running.stop();
1745
+ try {
1746
+ running.anim.cancel();
1747
+ } catch {
1748
+ }
1749
+ this.applySizeFn(size);
1750
+ });
1751
+ this.currentWaapi = entry;
1563
1752
  try {
1564
- anim.cancel();
1753
+ await entry.anim.finished;
1565
1754
  } catch {
1566
1755
  }
1756
+ entry.stop();
1757
+ const wasCurrent = this.currentWaapi === entry;
1758
+ const next = queued;
1759
+ if (wasCurrent && next) {
1760
+ if (next.samples.values.length >= 2 && next.samples.durationMs > 0) {
1761
+ leg = next;
1762
+ continue;
1763
+ }
1764
+ this.currentWaapi = null;
1765
+ this.applySizeFn(next.target);
1766
+ return;
1767
+ }
1768
+ if (wasCurrent) this.currentWaapi = null;
1769
+ if (wasCurrent && entry.anim.playState === "finished") {
1770
+ this.applySizeFn(leg.target);
1771
+ try {
1772
+ entry.anim.cancel();
1773
+ } catch {
1774
+ }
1775
+ }
1776
+ return;
1567
1777
  }
1568
1778
  }
1569
1779
  destroy() {
@@ -1618,27 +1828,51 @@ var collectFocusables = (root2) => {
1618
1828
  var focusables = (root2) => collectFocusables(root2).filter(
1619
1829
  (el) => !el.hasAttribute("inert") && isVisible(el) && !el.matches("[aria-hidden='true']")
1620
1830
  );
1831
+ var findDeep = (root2, selector) => {
1832
+ const direct = root2.querySelector(selector);
1833
+ if (direct || typeof HTMLSlotElement === "undefined") return direct;
1834
+ for (const slot of Array.from(root2.querySelectorAll("slot"))) {
1835
+ for (const assigned of slot.assignedElements()) {
1836
+ if (assigned.matches(selector)) return assigned;
1837
+ const inner = findDeep(assigned, selector);
1838
+ if (inner) return inner;
1839
+ }
1840
+ }
1841
+ return null;
1842
+ };
1843
+ var FOCUS_ALLOW_ATTR = "data-bs-focus-allow";
1844
+ var composedParent = (node) => {
1845
+ const slot = node.assignedSlot;
1846
+ if (slot) return slot;
1847
+ const parent = node.parentNode;
1848
+ return parent instanceof ShadowRoot ? parent.host : parent;
1849
+ };
1621
1850
  var containsComposed = (container, node) => {
1622
- let n = node;
1623
- while (n) {
1851
+ for (let n = node; n; n = composedParent(n)) {
1624
1852
  if (n === container) return true;
1625
- const slot = n.assignedSlot;
1626
- if (slot) {
1627
- n = slot;
1628
- continue;
1629
- }
1630
- const parent = n.parentNode;
1631
- n = parent instanceof ShadowRoot ? parent.host : parent;
1632
1853
  }
1633
1854
  return false;
1634
1855
  };
1635
- var trapStack = [];
1856
+ var isAllowedOutside = (node) => {
1857
+ for (let n = node; n; n = composedParent(n)) {
1858
+ if (n instanceof Element && n.hasAttribute(FOCUS_ALLOW_ATTR)) return true;
1859
+ }
1860
+ return false;
1861
+ };
1862
+ var deepActiveElement = () => {
1863
+ let active = document.activeElement;
1864
+ while (active?.shadowRoot?.activeElement) {
1865
+ active = active.shadowRoot.activeElement;
1866
+ }
1867
+ return active;
1868
+ };
1869
+ var trapStack = shared("focusTraps", () => []);
1636
1870
  var installFocusTrap = (container, options = {}) => {
1637
1871
  if (typeof document === "undefined") return () => {
1638
1872
  };
1639
1873
  const token = {};
1640
- trapStack.push(token);
1641
- const isActive = () => trapStack[trapStack.length - 1] === token;
1874
+ if (!options.isActive) trapStack.push(token);
1875
+ const isActive = options.isActive ?? (() => trapStack[trapStack.length - 1] === token);
1642
1876
  const previouslyFocused = document.activeElement;
1643
1877
  const focusInitial = () => {
1644
1878
  const spec = options.initialFocus;
@@ -1647,10 +1881,11 @@ var installFocusTrap = (container, options = {}) => {
1647
1881
  container.focus({ preventScroll: true });
1648
1882
  return;
1649
1883
  }
1650
- const initial = typeof spec === "string" ? container.querySelector(spec) : spec ?? focusables(container)[0] ?? container;
1884
+ const initial = typeof spec === "string" ? findDeep(container, spec) : spec ?? focusables(container)[0] ?? container;
1651
1885
  initial?.focus({ preventScroll: true });
1652
1886
  };
1653
- focusInitial();
1887
+ if (!containsComposed(container, deepActiveElement())) focusInitial();
1888
+ let backwards = false;
1654
1889
  const handleKey = (e) => {
1655
1890
  if (!isActive()) return;
1656
1891
  if (e.key === "Escape" && options.onEscape) {
@@ -1658,6 +1893,10 @@ var installFocusTrap = (container, options = {}) => {
1658
1893
  return;
1659
1894
  }
1660
1895
  if (e.key !== "Tab") return;
1896
+ backwards = e.shiftKey;
1897
+ setTimeout(() => {
1898
+ backwards = false;
1899
+ }, 0);
1661
1900
  const list = focusables(container);
1662
1901
  if (list.length === 0) {
1663
1902
  e.preventDefault();
@@ -1665,7 +1904,7 @@ var installFocusTrap = (container, options = {}) => {
1665
1904
  }
1666
1905
  const first = list[0];
1667
1906
  const last = list[list.length - 1];
1668
- const active = document.activeElement;
1907
+ const active = deepActiveElement();
1669
1908
  if (e.shiftKey && active === first) {
1670
1909
  e.preventDefault();
1671
1910
  last.focus();
@@ -1676,11 +1915,11 @@ var installFocusTrap = (container, options = {}) => {
1676
1915
  };
1677
1916
  const handleFocusIn = (e) => {
1678
1917
  if (!isActive()) return;
1679
- const target = e.target;
1680
- if (target && !containsComposed(container, target)) {
1681
- const list = focusables(container);
1682
- list[0]?.focus({ preventScroll: true });
1683
- }
1918
+ const target = e.composedPath()[0] ?? e.target;
1919
+ if (!target || containsComposed(container, target)) return;
1920
+ if (isAllowedOutside(target)) return;
1921
+ const list = focusables(container);
1922
+ list[backwards ? list.length - 1 : 0]?.focus({ preventScroll: true });
1684
1923
  };
1685
1924
  document.addEventListener("keydown", handleKey, true);
1686
1925
  document.addEventListener("focusin", handleFocusIn, true);
@@ -1702,21 +1941,25 @@ var installFocusTrap = (container, options = {}) => {
1702
1941
  };
1703
1942
 
1704
1943
  // src/core/lifecycle/scroll-lock.ts
1705
- var lockCount = 0;
1706
- var savedStyles = null;
1944
+ var state = shared("scrollLock", () => ({
1945
+ count: 0,
1946
+ saved: null
1947
+ }));
1707
1948
  var lockBodyScroll = () => {
1708
1949
  if (typeof document === "undefined") return () => {
1709
1950
  };
1710
- if (lockCount === 0) {
1951
+ if (state.count === 0) {
1711
1952
  const body = document.body;
1712
- savedStyles = {
1953
+ const saved = {
1713
1954
  overflow: body.style.overflow,
1714
1955
  position: body.style.position,
1715
1956
  top: body.style.top,
1716
1957
  width: body.style.width,
1717
1958
  paddingRight: body.style.paddingRight,
1959
+ scrollX: window.scrollX,
1718
1960
  scrollY: window.scrollY
1719
1961
  };
1962
+ state.saved = saved;
1720
1963
  const scrollbarGap = window.innerWidth - document.documentElement.clientWidth;
1721
1964
  if (scrollbarGap > 0) {
1722
1965
  const current = parseFloat(getComputedStyle(body).paddingRight) || 0;
@@ -1724,53 +1967,72 @@ var lockBodyScroll = () => {
1724
1967
  }
1725
1968
  body.style.overflow = "hidden";
1726
1969
  body.style.position = "fixed";
1727
- body.style.top = `-${savedStyles.scrollY}px`;
1970
+ body.style.top = `-${saved.scrollY}px`;
1728
1971
  body.style.width = "100%";
1729
1972
  }
1730
- lockCount++;
1973
+ state.count++;
1731
1974
  let released = false;
1732
1975
  return () => {
1733
1976
  if (released) return;
1734
1977
  released = true;
1735
- lockCount = Math.max(0, lockCount - 1);
1736
- if (lockCount === 0 && savedStyles) {
1978
+ state.count = Math.max(0, state.count - 1);
1979
+ if (state.count === 0 && state.saved) {
1737
1980
  const body = document.body;
1738
- body.style.overflow = savedStyles.overflow;
1739
- body.style.position = savedStyles.position;
1740
- body.style.top = savedStyles.top;
1741
- body.style.width = savedStyles.width;
1742
- body.style.paddingRight = savedStyles.paddingRight;
1743
- window.scrollTo(0, savedStyles.scrollY);
1744
- savedStyles = null;
1981
+ const saved = state.saved;
1982
+ body.style.overflow = saved.overflow;
1983
+ body.style.position = saved.position;
1984
+ body.style.top = saved.top;
1985
+ body.style.width = saved.width;
1986
+ body.style.paddingRight = saved.paddingRight;
1987
+ window.scrollTo({
1988
+ top: saved.scrollY,
1989
+ left: saved.scrollX,
1990
+ behavior: "instant"
1991
+ });
1992
+ state.saved = null;
1745
1993
  }
1746
1994
  };
1747
1995
  };
1748
1996
 
1749
1997
  // src/core/features/inert-siblings.ts
1998
+ var OWN_ROOTS = ".bs-root, .ovl-root";
1999
+ var LAYER_CLASSES = [
2000
+ "bs-backdrop",
2001
+ "bs-screen",
2002
+ "bs-root",
2003
+ "ovl-backdrop",
2004
+ "ovl-root"
2005
+ ];
2006
+ var isLayer = (el) => LAYER_CLASSES.some((name) => el.classList.contains(name));
1750
2007
  function createInertSiblings(rootProvider) {
1751
2008
  const tracked = [];
2009
+ const remove = () => {
2010
+ for (const el of tracked) el.removeAttribute("inert");
2011
+ tracked.length = 0;
2012
+ };
1752
2013
  return {
1753
2014
  apply() {
1754
2015
  if (typeof document === "undefined") return;
1755
- let top = rootProvider();
1756
- while (top.parentElement && top.parentElement !== document.body) {
1757
- top = top.parentElement;
1758
- }
1759
- const parent = top.parentElement ?? document.body;
1760
- for (const child2 of Array.from(parent.children)) {
1761
- if (child2 === top) continue;
1762
- if (child2.hasAttribute("inert")) continue;
1763
- if (child2.classList.contains("bs-backdrop") || child2.classList.contains("bs-screen") || child2.classList.contains("bs-root")) {
2016
+ remove();
2017
+ const surface = rootProvider();
2018
+ let node = surface.closest(OWN_ROOTS) ?? surface;
2019
+ while (node && node !== document.body) {
2020
+ const parent = node.parentElement;
2021
+ if (!parent) {
2022
+ const root2 = node.getRootNode();
2023
+ node = typeof ShadowRoot !== "undefined" && root2 instanceof ShadowRoot ? root2.host : null;
1764
2024
  continue;
1765
2025
  }
1766
- child2.setAttribute("inert", "");
1767
- tracked.push(child2);
2026
+ for (const sibling2 of Array.from(parent.children)) {
2027
+ if (sibling2 === node) continue;
2028
+ if (sibling2.hasAttribute("inert") || isLayer(sibling2)) continue;
2029
+ sibling2.setAttribute("inert", "");
2030
+ tracked.push(sibling2);
2031
+ }
2032
+ node = parent;
1768
2033
  }
1769
2034
  },
1770
- remove() {
1771
- for (const el of tracked) el.removeAttribute("inert");
1772
- tracked.length = 0;
1773
- }
2035
+ remove
1774
2036
  };
1775
2037
  }
1776
2038
 
@@ -1778,6 +2040,7 @@ function createInertSiblings(rootProvider) {
1778
2040
  var LifecycleController = class {
1779
2041
  constructor(deps, opts) {
1780
2042
  __publicField(this, "element");
2043
+ __publicField(this, "isTop");
1781
2044
  __publicField(this, "focusTrapEnabled");
1782
2045
  __publicField(this, "initialFocus");
1783
2046
  __publicField(this, "closeOnEscape");
@@ -1791,6 +2054,7 @@ var LifecycleController = class {
1791
2054
  __publicField(this, "installed", false);
1792
2055
  __publicField(this, "destroyed", false);
1793
2056
  this.element = deps.element;
2057
+ this.isTop = deps.isTop;
1794
2058
  this.focusTrapEnabled = opts.focusTrap ?? false;
1795
2059
  this.initialFocus = opts.initialFocus;
1796
2060
  this.closeOnEscape = opts.closeOnEscape ?? true;
@@ -1811,12 +2075,17 @@ var LifecycleController = class {
1811
2075
  }
1812
2076
  if (this.focusTrapEnabled && !this.releaseFocusTrap) {
1813
2077
  this.releaseFocusTrap = installFocusTrap(this.element, {
1814
- initialFocus: this.initialFocus
2078
+ initialFocus: this.initialFocus,
2079
+ isActive: this.isTop
1815
2080
  });
1816
2081
  }
1817
- if (this.inertSiblingsEnabled && this.shouldApplyInertSiblings()) {
1818
- this.inertSiblings.apply();
1819
- }
2082
+ this.syncTop();
2083
+ }
2084
+ syncTop() {
2085
+ if (!this.installed || !this.inertSiblingsEnabled) return;
2086
+ if (!this.shouldApplyInertSiblings()) return;
2087
+ if (this.isTop?.() ?? true) this.inertSiblings.apply();
2088
+ else this.inertSiblings.remove();
1820
2089
  }
1821
2090
  setReturnFocus(target) {
1822
2091
  if (this.destroyed) return;
@@ -1986,10 +2255,14 @@ var installGestures = (handle, mode, callbacks, options = {}) => {
1986
2255
  if (wasPending) return;
1987
2256
  callbacks.onCancel?.();
1988
2257
  };
2258
+ const onLostCapture = (e) => {
2259
+ if (e.target === handle) onPointerCancel(e);
2260
+ };
1989
2261
  handle.addEventListener("pointerdown", onPointerDown);
1990
2262
  handle.addEventListener("pointermove", onPointerMove);
1991
2263
  handle.addEventListener("pointerup", finishGesture);
1992
2264
  handle.addEventListener("pointercancel", onPointerCancel);
2265
+ handle.addEventListener("lostpointercapture", onLostCapture);
1993
2266
  const managesTouchAction = options.manageTouchAction !== false;
1994
2267
  const prevTouchAction = handle.style.touchAction;
1995
2268
  if (managesTouchAction) {
@@ -2000,6 +2273,7 @@ var installGestures = (handle, mode, callbacks, options = {}) => {
2000
2273
  handle.removeEventListener("pointermove", onPointerMove);
2001
2274
  handle.removeEventListener("pointerup", finishGesture);
2002
2275
  handle.removeEventListener("pointercancel", onPointerCancel);
2276
+ handle.removeEventListener("lostpointercapture", onLostCapture);
2003
2277
  if (managesTouchAction) handle.style.touchAction = prevTouchAction;
2004
2278
  if (activePointerId !== null && handle.hasPointerCapture(activePointerId)) {
2005
2279
  handle.releasePointerCapture(activePointerId);
@@ -2116,8 +2390,7 @@ var GestureController = class {
2116
2390
  size: this.deps.getDragContext().size,
2117
2391
  velocity: 0
2118
2392
  });
2119
- const restoreTo = this.dragStartSize;
2120
- void this.deps.animateTo(restoreTo, 0);
2393
+ this.deps.restoreAfterDrag();
2121
2394
  }
2122
2395
  }, this.deps.gestureOptions);
2123
2396
  return this.detach;
@@ -2182,6 +2455,11 @@ var readDirection = (el) => {
2182
2455
  }
2183
2456
  return "ltr";
2184
2457
  };
2458
+ var guessPhysicalMode = (mode) => {
2459
+ if (mode === "start") return "left";
2460
+ if (mode === "end") return "right";
2461
+ return mode ?? "bottom";
2462
+ };
2185
2463
  var resolveMode = (mode, el) => {
2186
2464
  if (!isLogicalMode(mode)) return mode;
2187
2465
  const rtl = readDirection(el) === "rtl";
@@ -2234,22 +2512,24 @@ function createScrollCache(deps) {
2234
2512
  return size < max / 2;
2235
2513
  };
2236
2514
  return {
2237
- cache(fromId, prevSize, nextSize) {
2515
+ leave(fromId, prevSize, nextSize) {
2238
2516
  const container = deps.scrollContainer;
2239
2517
  if (!container) return;
2240
- if (isSmallSize(prevSize)) return;
2241
- if (!isSmallSize(nextSize)) return;
2518
+ if (nextSize <= 0) {
2519
+ positions.clear();
2520
+ return;
2521
+ }
2522
+ if (isSmallSize(prevSize) || !isSmallSize(nextSize)) return;
2242
2523
  positions.set(fromId, container.scrollTop);
2243
2524
  },
2244
- restore(toId, prevSize, nextSize) {
2525
+ enter(toId, prevSize, nextSize) {
2245
2526
  const container = deps.scrollContainer;
2246
2527
  if (!container) return;
2247
- if (isSmallSize(nextSize)) return;
2248
- if (!isSmallSize(prevSize)) return;
2528
+ if (isSmallSize(nextSize) || !isSmallSize(prevSize)) return;
2249
2529
  const cached = positions.get(toId);
2250
2530
  if (cached === void 0) return;
2251
- container.scrollTop = cached;
2252
2531
  positions.delete(toId);
2532
+ container.scrollTop = cached;
2253
2533
  },
2254
2534
  clear() {
2255
2535
  positions.clear();
@@ -2363,17 +2643,18 @@ function attachAnchor(deps, opts) {
2363
2643
  const isDock = position === "dock-bottom" || position === "dock-top";
2364
2644
  const ws = wrapper.style;
2365
2645
  ws.position = "fixed";
2366
- if (isDock) {
2646
+ const place = () => {
2647
+ resetOverlayPosition(ws);
2648
+ if (!isDock) {
2649
+ applyOverlayPosition(ws, deps.getMode(), position, opts.inset ?? "16px");
2650
+ return;
2651
+ }
2367
2652
  ws.left = "0";
2368
2653
  ws.right = "0";
2369
- if (position === "dock-bottom") {
2370
- ws.bottom = "0";
2371
- } else {
2372
- ws.top = "0";
2373
- }
2374
- } else {
2375
- applyOverlayPosition(ws, deps.mode, position, opts.inset ?? "16px");
2376
- }
2654
+ if (position === "dock-bottom") ws.bottom = "0";
2655
+ else ws.top = "0";
2656
+ };
2657
+ place();
2377
2658
  if (opts.fadeRange) {
2378
2659
  const [r0, r1] = opts.fadeRange;
2379
2660
  const span = Math.max(r1 - r0, 1e-4);
@@ -2383,10 +2664,10 @@ function attachAnchor(deps, opts) {
2383
2664
  deps.host.appendChild(wrapper);
2384
2665
  let visible = null;
2385
2666
  let inFlight = null;
2386
- const shouldShow = (state2) => {
2387
- if (typeof opts.showOn === "function") return opts.showOn(state2);
2388
- if (Array.isArray(opts.showOn)) return opts.showOn.includes(state2.activeId);
2389
- return isDock || state2.size > 0;
2667
+ const shouldShow = (state4) => {
2668
+ if (typeof opts.showOn === "function") return opts.showOn(state4);
2669
+ if (Array.isArray(opts.showOn)) return opts.showOn.includes(state4.activeId);
2670
+ return isDock || state4.size > 0;
2390
2671
  };
2391
2672
  const applyVisibility = (next, animate) => {
2392
2673
  if (next === visible) return;
@@ -2433,7 +2714,8 @@ function attachAnchor(deps, opts) {
2433
2714
  },
2434
2715
  syncZ: (z) => {
2435
2716
  wrapper.style.zIndex = String(z);
2436
- }
2717
+ },
2718
+ reposition: place
2437
2719
  };
2438
2720
  }
2439
2721
 
@@ -2449,30 +2731,37 @@ var matchesRange = (def, progress) => {
2449
2731
  };
2450
2732
  function installScrimStages(deps, opts) {
2451
2733
  const doc = deps.host.ownerDocument;
2452
- const entries2 = opts.stages.map((def) => {
2734
+ const entries = opts.stages.map((def) => {
2453
2735
  const wrapper = doc.createElement("div");
2454
2736
  wrapper.className = "bs-scrim-stage";
2455
2737
  const ws = wrapper.style;
2456
- ws.position = "absolute";
2457
- applyOverlayPosition(
2458
- ws,
2459
- deps.mode,
2460
- def.position ?? opts.position ?? "center",
2461
- def.inset ?? opts.inset ?? "16px"
2462
- );
2738
+ ws.position = "fixed";
2463
2739
  ws.visibility = "hidden";
2464
2740
  ws.pointerEvents = "none";
2465
2741
  wrapper.appendChild(def.element);
2466
2742
  deps.host.appendChild(wrapper);
2467
2743
  return { def, wrapper, inFlight: null };
2468
2744
  });
2745
+ const place = () => {
2746
+ for (const entry of entries) {
2747
+ const ws = entry.wrapper.style;
2748
+ resetOverlayPosition(ws);
2749
+ applyOverlayPosition(
2750
+ ws,
2751
+ deps.getMode(),
2752
+ entry.def.position ?? opts.position ?? "center",
2753
+ entry.def.inset ?? opts.inset ?? "16px"
2754
+ );
2755
+ }
2756
+ };
2757
+ place();
2469
2758
  let active = null;
2470
2759
  const resolveActive = () => {
2471
- const state2 = deps.getState();
2472
- if (state2.size === 0) {
2473
- return entries2.find((e) => matchesId(e.def, state2.activeId)) ?? null;
2760
+ const state4 = deps.getState();
2761
+ if (state4.size === 0) {
2762
+ return entries.find((e) => matchesId(e.def, state4.activeId)) ?? null;
2474
2763
  }
2475
- return entries2.find((e) => matchesId(e.def, state2.activeId)) ?? entries2.find((e) => matchesRange(e.def, state2.progress)) ?? null;
2764
+ return entries.find((e) => matchesId(e.def, state4.activeId)) ?? entries.find((e) => matchesRange(e.def, state4.progress)) ?? null;
2476
2765
  };
2477
2766
  const hide = (entry, animate) => {
2478
2767
  entry.inFlight?.cancel();
@@ -2521,20 +2810,23 @@ function installScrimStages(deps, opts) {
2521
2810
  deps.on("open", () => update(true)),
2522
2811
  deps.on("close", () => update(true))
2523
2812
  ];
2524
- if (entries2.some((e) => e.def.forRange)) {
2813
+ if (entries.some((e) => e.def.forRange)) {
2525
2814
  offs.push(deps.on("progress", () => update(true)));
2526
2815
  }
2527
2816
  update(false);
2528
- return () => {
2529
- offs.forEach((off) => off());
2530
- for (const entry of entries2) {
2531
- entry.inFlight?.cancel();
2532
- entry.inFlight = null;
2533
- if (entry.wrapper.parentNode) {
2534
- entry.wrapper.parentNode.removeChild(entry.wrapper);
2817
+ return {
2818
+ reposition: place,
2819
+ detach: () => {
2820
+ offs.forEach((off) => off());
2821
+ for (const entry of entries) {
2822
+ entry.inFlight?.cancel();
2823
+ entry.inFlight = null;
2824
+ if (entry.wrapper.parentNode) {
2825
+ entry.wrapper.parentNode.removeChild(entry.wrapper);
2826
+ }
2535
2827
  }
2828
+ active = null;
2536
2829
  }
2537
- active = null;
2538
2830
  };
2539
2831
  }
2540
2832
 
@@ -2570,11 +2862,13 @@ function resolveEngineOptions(opts, extras) {
2570
2862
  scrimMode: opts.scrimMode,
2571
2863
  scrimColor: opts.scrimColor,
2572
2864
  scrimBlur: opts.scrimBlur,
2573
- scrimInteractive: opts.scrimInteractive ?? (opts.scrimTapToClose ? true : void 0),
2865
+ scrimInteractive: opts.scrimInteractive,
2574
2866
  scrimTapToClose: opts.scrimTapToClose,
2575
2867
  scrimPreset: opts.scrimPreset,
2576
2868
  screenRange: opts.screenRange,
2577
- backdropRange: opts.backdropRange
2869
+ backdropRange: opts.backdropRange,
2870
+ backdropOpacity: opts.backdropOpacity,
2871
+ backdropColor: opts.backdropColor
2578
2872
  },
2579
2873
  animation: {
2580
2874
  animation: opts.animation,
@@ -2653,6 +2947,7 @@ var BottomSheetCore = class {
2653
2947
  __publicField(this, "fitContentToSnap");
2654
2948
  __publicField(this, "settleAnimation");
2655
2949
  __publicField(this, "persistent");
2950
+ __publicField(this, "keyboardInset", 0);
2656
2951
  __publicField(this, "disableCloseFlag");
2657
2952
  __publicField(this, "disableDragFlag");
2658
2953
  __publicField(this, "closeOnRouteChange");
@@ -2667,6 +2962,7 @@ var BottomSheetCore = class {
2667
2962
  __publicField(this, "detachSheetGesture", null);
2668
2963
  __publicField(this, "detachSliderKeyboard", null);
2669
2964
  __publicField(this, "rootEl", null);
2965
+ __publicField(this, "homeRoot", null);
2670
2966
  __publicField(this, "destroyed", false);
2671
2967
  __publicField(this, "restClosed", false);
2672
2968
  __publicField(this, "currentViewTransition", null);
@@ -2674,8 +2970,13 @@ var BottomSheetCore = class {
2674
2970
  __publicField(this, "sizeWriteSentinel", new WriteSentinel());
2675
2971
  __publicField(this, "progressWriteSentinel", new WriteSentinel());
2676
2972
  __publicField(this, "isTopSheet", true);
2677
- __publicField(this, "opening", false);
2678
- __publicField(this, "promotedForOpen", false);
2973
+ __publicField(this, "phase", "closed");
2974
+ __publicField(this, "transition", null);
2975
+ __publicField(this, "inFlight", null);
2976
+ __publicField(this, "outbox", []);
2977
+ __publicField(this, "flushing", false);
2978
+ __publicField(this, "openPending", false);
2979
+ __publicField(this, "settleHolds", []);
2679
2980
  __publicField(this, "allowOvershoot", false);
2680
2981
  __publicField(this, "progressPayload", {
2681
2982
  value: 0,
@@ -2696,6 +2997,7 @@ var BottomSheetCore = class {
2696
2997
  __publicField(this, "anchorHost", null);
2697
2998
  __publicField(this, "stackZ", 100);
2698
2999
  __publicField(this, "detachScrimStages", null);
3000
+ __publicField(this, "placeScrimStages", null);
2699
3001
  __publicField(this, "stackEffectEnabled", false);
2700
3002
  __publicField(this, "stackEffectPrimed", false);
2701
3003
  __publicField(this, "fitDeps");
@@ -2703,13 +3005,7 @@ var BottomSheetCore = class {
2703
3005
  __publicField(this, "featureList", []);
2704
3006
  __publicField(this, "featureCtx");
2705
3007
  const resolved = resolveEngineOptions(opts, {
2706
- shouldApplyInertSiblings: () => {
2707
- if (typeof document === "undefined") return false;
2708
- const bodyChildren = Array.from(document.body.children);
2709
- return bodyChildren.some(
2710
- (c) => c === opts.element || c.contains(opts.element)
2711
- );
2712
- }
3008
+ shouldApplyInertSiblings: () => opts.element.isConnected
2713
3009
  });
2714
3010
  this.element = opts.element;
2715
3011
  this.handle = opts.handle ?? opts.element;
@@ -2738,7 +3034,6 @@ var BottomSheetCore = class {
2738
3034
  void this.snapTo(id);
2739
3035
  },
2740
3036
  close: () => {
2741
- if (!this.canDismiss()) return;
2742
3037
  void this.close("backdrop");
2743
3038
  }
2744
3039
  },
@@ -2768,7 +3063,8 @@ var BottomSheetCore = class {
2768
3063
  this.lifecycle = new LifecycleController(
2769
3064
  {
2770
3065
  element: this.element,
2771
- close: () => this.close()
3066
+ close: () => this.close(),
3067
+ isTop: () => this.isTopSheet
2772
3068
  },
2773
3069
  resolved.lifecycle
2774
3070
  );
@@ -2795,6 +3091,7 @@ var BottomSheetCore = class {
2795
3091
  auditVhUsage(this.snapPointsRaw);
2796
3092
  this.auditDuplicateSnapIds(this.snapPointsRaw);
2797
3093
  this.rootEl = this.element.closest(".bs-root");
3094
+ this.homeRoot = homeRootOf(this.rootEl);
2798
3095
  this.maxHeightDeps = {
2799
3096
  element: this.element,
2800
3097
  mode: this.mode,
@@ -2822,7 +3119,9 @@ var BottomSheetCore = class {
2822
3119
  );
2823
3120
  const initial = this.snaps.findById(this.activeId);
2824
3121
  if (initial) this.size = initial.size;
3122
+ this.phase = this.size > 0 ? "open" : "closed";
2825
3123
  this.applySize(this.size);
3124
+ this.restClosed = this.element.getAttribute("data-bs-rest") === "closed";
2826
3125
  this.setRestClosed(this.size === 0);
2827
3126
  this.updateAriaSlider();
2828
3127
  this.scrollCache = createScrollCache({
@@ -2833,12 +3132,11 @@ var BottomSheetCore = class {
2833
3132
  this.attach();
2834
3133
  this.registerInStack();
2835
3134
  if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
2836
- const io = new IntersectionObserver((entries2) => {
2837
- for (const entry of entries2) {
3135
+ const io = new IntersectionObserver((entries) => {
3136
+ for (const entry of entries) {
2838
3137
  if (!entry.isIntersecting) continue;
2839
3138
  if (this.destroyed) return;
2840
- this.snaps.recompute();
2841
- this.healActiveSnap();
3139
+ this.recompute();
2842
3140
  io.disconnect();
2843
3141
  return;
2844
3142
  }
@@ -2848,6 +3146,7 @@ var BottomSheetCore = class {
2848
3146
  }
2849
3147
  this.teardowns.add(
2850
3148
  installFitObserver({
3149
+ element: this.element,
2851
3150
  handle: this.handle,
2852
3151
  scrollContainer: this.scrollContainer,
2853
3152
  hasFitSnap: () => this.snapPointsRaw.some(
@@ -2863,9 +3162,7 @@ var BottomSheetCore = class {
2863
3162
  this.applyAutoAriaLabelledBy();
2864
3163
  this.runFeatureStage("post");
2865
3164
  this.warnOrphanFeatureOptions();
2866
- if (this.size > 0) {
2867
- this.handleOpen();
2868
- }
3165
+ if (this.phase === "open") this.installLifecycle(true);
2869
3166
  }
2870
3167
  buildFeatureContext(autoCollapseAfter) {
2871
3168
  return {
@@ -2893,21 +3190,27 @@ var BottomSheetCore = class {
2893
3190
  getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
2894
3191
  resolveSnap: (id) => this.snaps.findById(id),
2895
3192
  resolveActiveSnap: () => this.snaps.findById(this.activeId),
3193
+ getPhase: () => this.phase,
2896
3194
  setSize: (size) => {
2897
3195
  this.size = size;
2898
3196
  },
2899
3197
  setMaxAxisSize: (size) => {
2900
3198
  this.snaps.setMaxAxisSize(size);
2901
3199
  },
3200
+ setKeyboardInset: (px) => this.setKeyboardInset(px),
2902
3201
  applySize: (size) => this.applySize(size),
2903
3202
  recomputeSnaps: () => this.recomputeSnaps(),
3203
+ reseat: () => this.reseat(),
3204
+ holdSettle: (settled) => {
3205
+ this.settleHolds.push(settled);
3206
+ },
2904
3207
  newCycle: () => {
2905
3208
  this.newCycle();
2906
3209
  },
2907
- cancelInFlight: () => {
2908
- this.animation.cancel();
3210
+ cancelInFlight: () => this.suspend(),
3211
+ resyncAfterResize: () => {
3212
+ if (!this.destroyed) this.land(false);
2909
3213
  },
2910
- resyncAfterResize: () => this.resyncAfterResize(),
2911
3214
  snapTo: (id) => {
2912
3215
  void this.snapTo(id);
2913
3216
  },
@@ -2946,8 +3249,9 @@ var BottomSheetCore = class {
2946
3249
  return {
2947
3250
  size: this.size,
2948
3251
  activeId: this.activeId,
3252
+ phase: this.phase,
2949
3253
  isDragging: this.isDraggingAny(),
2950
- isAnimating: this.animation.isAnimating,
3254
+ isAnimating: this.animation.isAnimating || this.currentViewTransition !== null,
2951
3255
  progress: this.computeProgress(this.size)
2952
3256
  };
2953
3257
  }
@@ -3001,49 +3305,53 @@ var BottomSheetCore = class {
3001
3305
  getResolvedSnaps() {
3002
3306
  return this.snaps.getResolvedSnaps();
3003
3307
  }
3004
- async snapTo(id, velocityOrOpts = 0, _skipBeforeSnap = false) {
3005
- if (this.destroyed) return;
3308
+ snapTo(id, velocityOrOpts = 0, _skipBeforeSnap = false) {
3006
3309
  const opts = typeof velocityOrOpts === "object" ? velocityOrOpts : { velocity: velocityOrOpts };
3007
- const velocityPxPerMs = opts.velocity ?? 0;
3008
- const externalSignal = opts.signal;
3009
- if (externalSignal?.aborted) return;
3310
+ return this.transitionTo(
3311
+ id,
3312
+ opts.velocity ?? 0,
3313
+ _skipBeforeSnap,
3314
+ opts.signal
3315
+ );
3316
+ }
3317
+ transitionTo(id, velocityPxPerMs = 0, skipBeforeSnap = false, externalSignal) {
3318
+ if (this.destroyed || externalSignal?.aborted) return Promise.resolve();
3010
3319
  const target = this.snaps.findById(id);
3011
3320
  if (!target) {
3012
3321
  devWarn(`[BottomSheet] unknown snap id: ${id}`);
3013
- return;
3322
+ return Promise.resolve();
3014
3323
  }
3015
3324
  if (!this.snaps.getAllowedIds().includes(id)) {
3016
3325
  devWarn(`[BottomSheet] snap "${id}" is not in allowed list`);
3017
- return;
3018
- }
3019
- if (!_skipBeforeSnap && this.emitBeforeSnap(target, this.activeId)) {
3020
- return;
3021
- }
3022
- const resumingOpen = this.opening;
3023
- const signal = this.newCycle();
3024
- const onExternalAbort = () => {
3025
- this.animation.cancel();
3026
- this.newCycle();
3027
- };
3326
+ return Promise.resolve();
3327
+ }
3328
+ if (target.size === 0 && this.closingBlocked()) return Promise.resolve();
3329
+ if (!externalSignal && this.inFlight?.id === id) return this.inFlight.done;
3330
+ if (!skipBeforeSnap && this.emitBeforeSnap(target, this.activeId)) {
3331
+ return Promise.resolve();
3332
+ }
3333
+ const flight = { id, done: Promise.resolve() };
3334
+ flight.done = this.runTransition(
3335
+ target,
3336
+ velocityPxPerMs,
3337
+ false,
3338
+ externalSignal,
3339
+ flight
3340
+ );
3341
+ return flight.done;
3342
+ }
3343
+ async runTransition(target, velocityPxPerMs, fromDrag, externalSignal, flight = null) {
3344
+ const signal = this.beginTransition(target);
3345
+ const transition = this.transition;
3346
+ if (signal.aborted || !transition) return;
3347
+ this.inFlight = flight;
3348
+ const onExternalAbort = () => this.suspend();
3028
3349
  externalSignal?.addEventListener("abort", onExternalAbort, { once: true });
3029
- const wasClosed = this.size === 0 || resumingOpen;
3030
- const previousId = this.activeId;
3031
- const previousSize = this.size;
3032
- this.scrollCache.cache(previousId, previousSize, target.size);
3033
- this.activeId = id;
3034
- const rawTargetSize = this.snapPointsRaw.find((p) => p.id === id)?.size;
3035
- const opensToRest = id === "closed" || rawTargetSize === 0;
3036
- if (wasClosed && !opensToRest) {
3037
- this.opening = true;
3038
- if (!resumingOpen) {
3039
- this.promotedForOpen = true;
3040
- sheetStack.promote(this.id);
3041
- }
3042
- }
3043
- if (this.animation.viewTransitionsAvailable) {
3350
+ this.allowOvershoot = fromDrag;
3351
+ if (!fromDrag && this.animation.viewTransitionsAvailable) {
3044
3352
  this.currentViewTransition?.skipTransition?.();
3045
3353
  const vt = document.startViewTransition(() => {
3046
- this.applySize(target.size);
3354
+ if (!signal.aborted) this.applySize(transition.size);
3047
3355
  });
3048
3356
  vt.ready?.catch(() => {
3049
3357
  });
@@ -3054,25 +3362,202 @@ var BottomSheetCore = class {
3054
3362
  }
3055
3363
  if (this.currentViewTransition === vt) this.currentViewTransition = null;
3056
3364
  } else {
3057
- await this.animation.animateTo(target.size, velocityPxPerMs);
3365
+ await this.animation.animateTo(transition.size, velocityPxPerMs);
3058
3366
  }
3059
3367
  externalSignal?.removeEventListener("abort", onExternalAbort);
3060
3368
  if (signal.aborted) return;
3061
- this.opening = false;
3062
- this.completeSnap(id, target.size, previousSize, wasClosed, false);
3369
+ if (this.size !== transition.size) this.applySize(transition.size);
3370
+ this.land(fromDrag);
3371
+ if (this.settleHolds.length > 0) {
3372
+ await Promise.allSettled(this.settleHolds.splice(0));
3373
+ }
3374
+ }
3375
+ beginTransition(target) {
3376
+ const signal = this.newCycle();
3377
+ const cap = this.snaps.getMaxAxisSize();
3378
+ const fromId = this.activeId;
3379
+ const fromSize = this.snaps.findById(fromId)?.size ?? this.size;
3380
+ this.scrollCache.leave(fromId, fromSize, target.size);
3381
+ this.scrollCache.enter(target.id, fromSize, target.size);
3382
+ this.activeId = target.id;
3383
+ this.transition = {
3384
+ size: cap > 0 ? Math.min(target.size, cap) : target.size,
3385
+ cap
3386
+ };
3387
+ if (target.size > 0) {
3388
+ this.enterOpening(target.id);
3389
+ } else {
3390
+ if (this.phase === "closed" && !this.isClosedSnap(target.id)) {
3391
+ sheetStack.promote(this.id);
3392
+ }
3393
+ this.enterClosing();
3394
+ }
3395
+ this.flush();
3396
+ return signal;
3397
+ }
3398
+ enterOpening(id) {
3399
+ if (this.phase === "open" || this.phase === "opening") return;
3400
+ const fresh = this.phase === "closed";
3401
+ this.phase = "opening";
3402
+ this.setRestClosed(false);
3403
+ if (!this.installLifecycle(fresh)) return;
3404
+ this.post("open", { id });
3405
+ this.outbox.push(() => {
3406
+ if (this.phase !== "closed") {
3407
+ notifyLinkedSheets(this.linkedSheets, this);
3408
+ }
3409
+ });
3063
3410
  }
3064
- completeSnap(id, targetSize, previousSize, wasClosed, withHaptic) {
3065
- this.scrollCache.restore(id, previousSize, targetSize);
3411
+ enterClosing() {
3412
+ if (this.phase === "closed" || this.phase === "closing") return;
3413
+ this.phase = "closing";
3414
+ this.post("close", void 0);
3415
+ }
3416
+ settlePhase(heal) {
3417
+ if (this.size > 0) {
3418
+ this.enterOpening(this.activeId);
3419
+ if (this.phase === "opening") {
3420
+ this.phase = "open";
3421
+ this.post("opened", { id: this.activeId });
3422
+ }
3423
+ return;
3424
+ }
3425
+ if (heal && this.phase !== "closing") return;
3426
+ this.enterClosing();
3427
+ if (this.phase === "closing") {
3428
+ this.phase = "closed";
3429
+ this.setRestClosed(true);
3430
+ this.lifecycle.release();
3431
+ sheetStack.update();
3432
+ this.post("closed", void 0);
3433
+ }
3434
+ }
3435
+ land(haptic) {
3436
+ this.transition = null;
3437
+ this.inFlight = null;
3438
+ this.allowOvershoot = false;
3439
+ this.openPending = this.size === 0 && !this.isClosedSnap(this.activeId);
3066
3440
  this.updateAriaSlider();
3067
- this.emit("snap", {
3068
- id,
3441
+ this.setRestClosed(this.size === 0);
3442
+ this.post("snap", {
3443
+ id: this.activeId,
3069
3444
  size: this.size,
3070
3445
  progress: this.computeProgress(this.size)
3071
3446
  });
3072
- if (withHaptic) this.haptic();
3073
- this.setRestClosed(targetSize === 0);
3074
- if (wasClosed && targetSize > 0) this.emitOpenSequence(id);
3075
- if (targetSize === 0) this.emitCloseSequence();
3447
+ this.settlePhase(false);
3448
+ if (haptic) this.haptic();
3449
+ this.flush();
3450
+ }
3451
+ suspend() {
3452
+ this.animation.cancel();
3453
+ this.currentViewTransition?.skipTransition?.();
3454
+ this.newCycle();
3455
+ }
3456
+ landNow() {
3457
+ const transition = this.transition;
3458
+ if (this.destroyed || !transition || this.isDraggingAny()) return;
3459
+ this.animation.cancel();
3460
+ this.currentViewTransition?.skipTransition?.();
3461
+ this.newCycle();
3462
+ this.applySize(transition.size);
3463
+ this.land(false);
3464
+ }
3465
+ reseat() {
3466
+ if (this.destroyed || this.isDraggingAny()) return;
3467
+ const active = this.snaps.findById(this.activeId);
3468
+ if (!active) return;
3469
+ const cap = this.snaps.getMaxAxisSize();
3470
+ const target = cap > 0 ? Math.min(active.size, cap) : active.size;
3471
+ this.updateAriaSlider();
3472
+ const transition = this.transition;
3473
+ if (transition) {
3474
+ if (Math.abs(target - transition.size) < SIZE_WRITE_EPSILON && Math.abs(cap - transition.cap) < SIZE_WRITE_EPSILON) {
3475
+ return;
3476
+ }
3477
+ transition.size = target;
3478
+ transition.cap = cap;
3479
+ this.applySize(this.animation.retarget(target) ? this.size : target);
3480
+ return;
3481
+ }
3482
+ if (this.openPending && target > 0 && this.phase === "closed") {
3483
+ void this.runTransition(active, 0, false);
3484
+ return;
3485
+ }
3486
+ this.applySize(target);
3487
+ this.settlePhase(true);
3488
+ this.flush();
3489
+ }
3490
+ installLifecycle(promote) {
3491
+ if (promote) sheetStack.promote(this.id);
3492
+ if (this.lifecycle.isInstalled) return true;
3493
+ try {
3494
+ this.lifecycle.install();
3495
+ return true;
3496
+ } catch (err) {
3497
+ this.abortOpen();
3498
+ queueMicrotask(() => {
3499
+ throw err;
3500
+ });
3501
+ return false;
3502
+ }
3503
+ }
3504
+ abortOpen() {
3505
+ this.animation.cancel();
3506
+ if (!this.destroyed) this.newCycle();
3507
+ this.phase = "closed";
3508
+ this.openPending = false;
3509
+ this.lifecycle.release();
3510
+ sheetStack.update();
3511
+ this.activeId = this.zeroSnapId() ?? this.activeId;
3512
+ this.applySize(0);
3513
+ this.setRestClosed(true);
3514
+ this.updateAriaSlider();
3515
+ }
3516
+ zeroSnapId() {
3517
+ return this.snapPointsRaw.find((p) => p.id === "closed")?.id ?? this.snaps.getAllowedIds().find((a) => this.snaps.findById(a)?.size === 0);
3518
+ }
3519
+ isClosedSnap(id) {
3520
+ if (id === "closed") return true;
3521
+ return this.snapPointsRaw.find((p) => p.id === id)?.size === 0;
3522
+ }
3523
+ closingBlocked() {
3524
+ return this.disableCloseFlag && this.phase !== "closed";
3525
+ }
3526
+ setKeyboardInset(px) {
3527
+ if (px === this.keyboardInset) return;
3528
+ this.keyboardInset = px;
3529
+ for (const host of this.varHosts()) {
3530
+ host.style.setProperty("--bs-keyboard-inset", `${px}px`);
3531
+ }
3532
+ }
3533
+ varHosts() {
3534
+ const hosts = /* @__PURE__ */ new Set([this.element]);
3535
+ for (const host of [
3536
+ this.anchorHost,
3537
+ this.scrimParent,
3538
+ this.rootEl,
3539
+ this.homeRoot
3540
+ ]) {
3541
+ if (host) hosts.add(host);
3542
+ }
3543
+ return hosts;
3544
+ }
3545
+ dismissBlocked() {
3546
+ return (this.disableCloseFlag || this.persistent) && this.phase !== "closed";
3547
+ }
3548
+ post(event, payload) {
3549
+ this.outbox.push(() => this.bus.emit(event, payload));
3550
+ }
3551
+ flush() {
3552
+ if (this.flushing) return;
3553
+ this.flushing = true;
3554
+ try {
3555
+ for (let next = this.outbox.shift(); next; next = this.outbox.shift()) {
3556
+ next();
3557
+ }
3558
+ } finally {
3559
+ this.flushing = false;
3560
+ }
3076
3561
  }
3077
3562
  setRestClosed(closed) {
3078
3563
  if (closed === this.restClosed) return;
@@ -3080,17 +3565,6 @@ var BottomSheetCore = class {
3080
3565
  if (closed) this.element.setAttribute("data-bs-rest", "closed");
3081
3566
  else this.element.removeAttribute("data-bs-rest");
3082
3567
  }
3083
- emitOpenSequence(id) {
3084
- this.emit("open", { id });
3085
- this.handleOpen();
3086
- notifyLinkedSheets(this.linkedSheets, this);
3087
- this.emit("opened", { id });
3088
- }
3089
- emitCloseSequence() {
3090
- this.emit("close", void 0);
3091
- this.handleClose();
3092
- this.emit("closed", void 0);
3093
- }
3094
3568
  async dragTo(targetSize, velocityOrOpts = 0) {
3095
3569
  if (this.destroyed) return;
3096
3570
  const opts = typeof velocityOrOpts === "object" ? velocityOrOpts : { velocity: velocityOrOpts };
@@ -3098,27 +3572,31 @@ var BottomSheetCore = class {
3098
3572
  const externalSignal = opts.signal;
3099
3573
  if (externalSignal?.aborted) return;
3100
3574
  this.newCycle();
3101
- const onExternalAbort = () => {
3102
- this.animation.cancel();
3103
- this.newCycle();
3104
- };
3575
+ const onExternalAbort = () => this.suspend();
3105
3576
  externalSignal?.addEventListener("abort", onExternalAbort, { once: true });
3106
3577
  const clamped = Math.max(0, Math.min(targetSize, this.snaps.getMaxAxisSize()));
3107
3578
  await this.animation.animateTo(clamped, velocityPxPerMs);
3108
3579
  externalSignal?.removeEventListener("abort", onExternalAbort);
3109
- if (this.destroyed || externalSignal?.aborted) return;
3110
3580
  }
3111
3581
  open(id) {
3112
3582
  if (this.destroyed) return Promise.resolve();
3583
+ if (!id && (this.phase === "open" || this.phase === "opening")) {
3584
+ return Promise.resolve();
3585
+ }
3113
3586
  const target = id ?? this.snaps.getAllowedIds().find((a) => (this.snaps.findById(a)?.size ?? 0) > 0) ?? this.activeId;
3114
3587
  return this.snapTo(target);
3115
3588
  }
3116
3589
  close(reason = "programmatic") {
3117
- if (this.destroyed) return Promise.resolve();
3118
- if (this.disableCloseFlag) return Promise.resolve();
3119
- if (this.size > 0 && this.emitBeforeClose(reason)) return Promise.resolve();
3120
- const closedId = this.snapPointsRaw.find((p) => p.id === "closed")?.id ?? this.snaps.getAllowedIds().find((a) => this.snaps.findById(a)?.size === 0) ?? this.snaps.getAllowedIds()[0];
3121
- return this.snapTo(closedId ?? this.activeId);
3590
+ if (this.destroyed || this.disableCloseFlag) return Promise.resolve();
3591
+ if (this.persistent && reason !== "programmatic") return Promise.resolve();
3592
+ const target = this.zeroSnapId() ?? this.allowedIdsBySize()[0];
3593
+ if (target === void 0) return Promise.resolve();
3594
+ if (this.phase === "closed" && this.activeId === target) {
3595
+ return Promise.resolve();
3596
+ }
3597
+ const visible = this.phase === "open" || this.phase === "opening";
3598
+ if (visible && this.emitBeforeClose(reason)) return Promise.resolve();
3599
+ return this.snapTo(target);
3122
3600
  }
3123
3601
  canDismiss() {
3124
3602
  return !this.persistent && !this.disableCloseFlag && !this.destroyed;
@@ -3141,10 +3619,12 @@ var BottomSheetCore = class {
3141
3619
  }
3142
3620
  setDragFrom(mode) {
3143
3621
  if (this.destroyed || mode === this.dragFromMode) return;
3622
+ const wasDragging = this.gesture?.isDragging ?? false;
3144
3623
  this.gesture?.forceClearDragState();
3145
3624
  this.detachSheetGesture?.();
3146
3625
  this.dragFromMode = mode;
3147
3626
  this.mountSheetGesture();
3627
+ if (wasDragging) this.restoreAfterDrag();
3148
3628
  }
3149
3629
  getDragFrom() {
3150
3630
  return this.dragFromMode;
@@ -3157,6 +3637,7 @@ var BottomSheetCore = class {
3157
3637
  const nowVertical = next === "bottom" || next === "top";
3158
3638
  this.gesture?.forceClearDragState();
3159
3639
  this.detachSheetGesture?.();
3640
+ this.landNow();
3160
3641
  this.animation.cancel();
3161
3642
  this.element.style.removeProperty(layoutAxis(this.mode));
3162
3643
  this.mode = next;
@@ -3172,9 +3653,12 @@ var BottomSheetCore = class {
3172
3653
  this.detachSliderKeyboard?.();
3173
3654
  this.mountSliderKeyboard();
3174
3655
  this.mountSheetGesture();
3656
+ for (const anchor of this.anchors) anchor.reposition();
3657
+ this.placeScrimStages?.();
3658
+ if (this.stackEffectPrimed) {
3659
+ this.element.style.transformOrigin = nowVertical ? "50% 100%" : "0% 50%";
3660
+ }
3175
3661
  this.recompute();
3176
- const active = this.snaps.findById(this.activeId);
3177
- if (active) this.applySize(active.size);
3178
3662
  this.updateAriaSlider();
3179
3663
  }
3180
3664
  getMode() {
@@ -3216,13 +3700,24 @@ var BottomSheetCore = class {
3216
3700
  if (snap && ids.includes(snap)) {
3217
3701
  void this.snapTo(snap, 0, true);
3218
3702
  } else if (!ids.includes(this.activeId)) {
3219
- const fallback = ids[0];
3220
- if (fallback) void this.snapTo(fallback, 0, true);
3703
+ const fallback = this.fallbackSnap(
3704
+ this.snaps.findById(this.activeId)?.size ?? this.size
3705
+ );
3706
+ if (fallback) void this.snapTo(fallback.id, 0, true);
3221
3707
  }
3222
3708
  }
3709
+ fallbackSnap(from) {
3710
+ return (from > 0 ? this.snaps.nearest(from, true) : null) ?? this.snaps.nearest(from, false);
3711
+ }
3223
3712
  setBackdropRange(range) {
3224
3713
  this.scrim.setBackdropRange(range, () => this.applySize(this.size));
3225
3714
  }
3715
+ setBackdropOpacity(value) {
3716
+ this.scrim.setBackdropOpacity(value, () => this.applySize(this.size));
3717
+ }
3718
+ setBackdropColor(color) {
3719
+ this.scrim.setBackdropColor(color);
3720
+ }
3226
3721
  setScreenRange(range) {
3227
3722
  this.scrim.setScreenRange(range, () => this.applySize(this.size));
3228
3723
  }
@@ -3263,7 +3758,7 @@ var BottomSheetCore = class {
3263
3758
  }
3264
3759
  const handle = attachAnchor(
3265
3760
  {
3266
- mode: this.mode,
3761
+ getMode: () => this.mode,
3267
3762
  host: this.anchorHost,
3268
3763
  getState: () => ({
3269
3764
  activeId: this.activeId,
@@ -3301,9 +3796,9 @@ var BottomSheetCore = class {
3301
3796
  return () => {
3302
3797
  };
3303
3798
  }
3304
- const detachInstalled = installScrimStages(
3799
+ const stages = installScrimStages(
3305
3800
  {
3306
- mode: this.mode,
3801
+ getMode: () => this.mode,
3307
3802
  host,
3308
3803
  getState: () => ({
3309
3804
  activeId: this.activeId,
@@ -3316,10 +3811,14 @@ var BottomSheetCore = class {
3316
3811
  opts
3317
3812
  );
3318
3813
  const detach = () => {
3319
- if (this.detachScrimStages === detach) this.detachScrimStages = null;
3320
- detachInstalled();
3814
+ if (this.detachScrimStages === detach) {
3815
+ this.detachScrimStages = null;
3816
+ this.placeScrimStages = null;
3817
+ }
3818
+ stages.detach();
3321
3819
  };
3322
3820
  this.detachScrimStages = detach;
3821
+ this.placeScrimStages = stages.reposition;
3323
3822
  this.teardowns.add(() => this.detachScrimStages?.());
3324
3823
  return detach;
3325
3824
  }
@@ -3328,32 +3827,29 @@ var BottomSheetCore = class {
3328
3827
  }
3329
3828
  setSnapPoints(points, allowed) {
3330
3829
  if (this.destroyed) return;
3331
- this.animation.cancel();
3332
- this.newCycle();
3830
+ const from = this.snaps.findById(this.activeId)?.size ?? this.size;
3831
+ const restricted = this.snaps.getResolvedSnaps().some((s) => !this.snaps.getAllowedIds().includes(s.id));
3333
3832
  this.snapPointsRaw = points;
3334
3833
  auditVhUsage(points);
3335
3834
  this.auditDuplicateSnapIds(points);
3835
+ this.maxHeight.resolveCap();
3336
3836
  this.snaps.setRaw(points);
3837
+ this.maxHeight.clampTo();
3337
3838
  if (allowed) {
3338
3839
  this.snaps.setAllowedIds(allowed);
3339
3840
  } else {
3340
3841
  const present = this.snaps.getResolvedSnaps().map((s) => s.id);
3341
- const kept = this.snaps.getAllowedIds().filter((id) => present.includes(id));
3842
+ const kept = restricted ? this.snaps.getAllowedIds().filter((id) => present.includes(id)) : [];
3342
3843
  this.snaps.setAllowedIds(kept.length ? kept : present);
3343
3844
  }
3344
3845
  this.scrollCache.clear();
3345
3846
  this.scrim.invalidateOpacityCache();
3346
- const current = this.snaps.findById(this.activeId);
3347
- if (current) {
3348
- this.applySize(current.size);
3349
- } else {
3350
- const fallback = this.snaps.getResolvedSnaps().find((s) => this.snaps.getAllowedIds().includes(s.id)) ?? this.snaps.getResolvedSnaps()[0];
3351
- if (fallback) {
3352
- this.activeId = fallback.id;
3353
- this.applySize(fallback.size);
3354
- }
3847
+ if (this.snaps.findById(this.activeId)) {
3848
+ this.reseat();
3849
+ return;
3355
3850
  }
3356
- this.updateAriaSlider();
3851
+ const fallback = this.fallbackSnap(from) ?? this.snaps.getResolvedSnaps()[0];
3852
+ if (fallback) void this.transitionTo(fallback.id, 0, true);
3357
3853
  }
3358
3854
  recompute() {
3359
3855
  if (this.destroyed) return;
@@ -3361,22 +3857,11 @@ var BottomSheetCore = class {
3361
3857
  this.snaps.recompute();
3362
3858
  this.maxHeight.clampTo();
3363
3859
  this.scrim.invalidateOpacityCache();
3364
- if (this.isDraggingAny()) return;
3365
- this.healActiveSnap();
3366
- }
3367
- healActiveSnap() {
3368
- const current = this.snaps.findById(this.activeId);
3369
- if (!current) return;
3370
- this.size = current.size;
3371
- this.applySize(this.size);
3372
- this.updateAriaSlider();
3373
- if (this.size > 0 && !this.lifecycle.isInstalled && !this.opening && !this.animation.isAnimating) {
3374
- this.emitOpenSequence(this.activeId);
3375
- }
3860
+ this.reseat();
3376
3861
  }
3377
3862
  destroy() {
3378
3863
  this.destroyed = true;
3379
- this.opening = false;
3864
+ this.outbox.length = 0;
3380
3865
  this.currentAbort.abort();
3381
3866
  this.currentViewTransition?.skipTransition?.();
3382
3867
  this.currentViewTransition = null;
@@ -3393,11 +3878,19 @@ var BottomSheetCore = class {
3393
3878
  this.backdrop.style.opacity = "";
3394
3879
  this.backdrop.style.pointerEvents = "";
3395
3880
  }
3396
- for (const host of [this.anchorHost, this.scrimParent, this.rootEl]) {
3881
+ for (const host of [
3882
+ this.anchorHost,
3883
+ this.scrimParent,
3884
+ this.rootEl,
3885
+ this.homeRoot
3886
+ ]) {
3397
3887
  if (!host) continue;
3398
3888
  host.style.removeProperty("--bs-size");
3399
3889
  host.style.removeProperty("--bs-progress");
3890
+ host.style.removeProperty("--bs-z-sheet");
3891
+ host.style.removeProperty("--bs-keyboard-inset");
3400
3892
  }
3893
+ this.element.style.removeProperty("--bs-keyboard-inset");
3401
3894
  if (this.screenComponent) {
3402
3895
  this.screenComponent.style.opacity = "";
3403
3896
  this.screenComponent.style.display = "";
@@ -3410,7 +3903,8 @@ var BottomSheetCore = class {
3410
3903
  }
3411
3904
  newCycle() {
3412
3905
  this.allowOvershoot = false;
3413
- this.opening = false;
3906
+ this.transition = null;
3907
+ this.inFlight = null;
3414
3908
  this.currentAbort.abort();
3415
3909
  this.currentAbort = new AbortController();
3416
3910
  return this.currentAbort.signal;
@@ -3433,8 +3927,9 @@ var BottomSheetCore = class {
3433
3927
  if (typeof document === "undefined") return;
3434
3928
  if (!this.lifecycle.focusTrapEnabled) return;
3435
3929
  if (this.element.getAttribute("aria-labelledby")) return;
3436
- const scope = this.handle ?? this.element;
3437
- const titled = scope.querySelector("[data-bs-title]") ?? scope.querySelector("h1,h2,h3,h4,h5,h6");
3930
+ const HEADING = "h1,h2,h3,h4,h5,h6";
3931
+ const header = this.element.querySelector(".bs-header");
3932
+ const titled = this.element.querySelector("[data-bs-title]") ?? this.handle.querySelector(HEADING) ?? header?.querySelector(HEADING);
3438
3933
  if (!titled) return;
3439
3934
  if (!titled.id) {
3440
3935
  titled.id = nextInstanceId("bs-title");
@@ -3476,12 +3971,16 @@ var BottomSheetCore = class {
3476
3971
  this.stackZ = z;
3477
3972
  this.element.style.zIndex = String(z);
3478
3973
  if (this.backdrop) this.backdrop.style.zIndex = String(z - 1);
3974
+ this.rootEl?.style.setProperty("--bs-z-sheet", String(z));
3975
+ this.homeRoot?.style.setProperty("--bs-z-sheet", String(z));
3479
3976
  for (const anchor of this.anchors) anchor.syncZ(z + 1);
3480
3977
  },
3481
3978
  setIsTop: (isTop) => {
3979
+ if (isTop === this.isTopSheet) return;
3482
3980
  this.isTopSheet = isTop;
3981
+ this.lifecycle.syncTop();
3483
3982
  },
3484
- isOpen: () => this.size > 0 || this.opening,
3983
+ isOpen: () => this.phase !== "closed",
3485
3984
  setDepth: (depth) => this.applyStackDepth(depth)
3486
3985
  }));
3487
3986
  }
@@ -3509,15 +4008,15 @@ var BottomSheetCore = class {
3509
4008
  const r = this.getAllowedRange();
3510
4009
  buf.size = this.size;
3511
4010
  buf.maxAxisSize = this.snaps.getMaxAxisSize();
3512
- buf.range.min = r.min;
4011
+ buf.range.min = this.dismissBlocked() ? Math.max(r.min, this.smallestOpenSize()) : r.min;
3513
4012
  buf.range.max = r.max;
3514
4013
  buf.rubberBandEnabled = this.rubberBandEnabled;
3515
4014
  return buf;
3516
4015
  },
3517
4016
  getDisableDrag: () => this.disableDragFlag,
3518
- cancelAnimation: () => this.animation.cancel(),
4017
+ cancelAnimation: () => this.suspend(),
3519
4018
  applySize: (size) => this.applySize(size),
3520
- animateTo: (size, velocity) => this.animation.animateTo(size, velocity),
4019
+ restoreAfterDrag: () => this.restoreAfterDrag(),
3521
4020
  settleAfterDrag: (delta, velocity, kind) => this.settleAfterDrag(delta, velocity, kind),
3522
4021
  emit: (event, payload) => this.emit(event, payload),
3523
4022
  listenerCount: (event) => this.bus.listenerCount(event)
@@ -3641,32 +4140,19 @@ var BottomSheetCore = class {
3641
4140
  element: this.element,
3642
4141
  getMode: () => this.mode,
3643
4142
  isDestroyed: () => this.destroyed,
3644
- isDragging: () => this.isDraggingAny(),
3645
4143
  resolveActiveSnap: () => this.snaps.findById(this.activeId),
3646
4144
  getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
3647
- getSize: () => this.size,
3648
4145
  setMaxAxisSize: (size) => {
3649
4146
  this.snaps.setMaxAxisSize(size);
3650
4147
  },
3651
- setSize: (size) => {
3652
- this.size = size;
3653
- },
3654
4148
  recomputeSnaps: () => this.recomputeSnaps(),
3655
- applySize: (size) => this.applySize(size),
3656
- cancelInFlight: () => {
3657
- this.animation.cancel();
3658
- },
3659
- newCycle: () => {
3660
- this.newCycle();
3661
- },
3662
- isAnimating: () => this.animation.isAnimating,
3663
- resyncAfterCancel: () => this.resyncAfterResize()
4149
+ reseat: () => this.reseat(),
4150
+ landNow: () => this.landNow()
3664
4151
  }));
3665
4152
  if (this.lifecycle.closeOnEscape) {
3666
4153
  const onKey = (e) => {
3667
4154
  if (this.destroyed || e.defaultPrevented) return;
3668
- if (!this.canDismiss()) return;
3669
- if (e.key === "Escape" && this.isTopSheet && this.size > 0) {
4155
+ if (e.key === "Escape" && this.isTopSheet) {
3670
4156
  void this.close("escape");
3671
4157
  }
3672
4158
  };
@@ -3684,7 +4170,10 @@ var BottomSheetCore = class {
3684
4170
  handle: this.handle,
3685
4171
  mode: this.mode,
3686
4172
  isDestroyed: () => this.destroyed,
3687
- getAllowedIds: () => this.allowedIdsBySize(),
4173
+ getAllowedIds: () => {
4174
+ const ids = this.allowedIdsBySize();
4175
+ return this.dismissBlocked() ? ids.filter((id) => (this.snaps.findById(id)?.size ?? 0) > 0) : ids;
4176
+ },
3688
4177
  getActiveId: () => this.activeId,
3689
4178
  snapTo: (id) => {
3690
4179
  void this.snapTo(id);
@@ -3697,56 +4186,46 @@ var BottomSheetCore = class {
3697
4186
  });
3698
4187
  }
3699
4188
  settleAfterDrag(delta, velocity, kind = "touch") {
3700
- const signal = this.newCycle();
3701
- const target = this.snaps.findDragSettleTarget({
3702
- delta,
3703
- velocity,
3704
- pointerKind: kind,
3705
- size: this.size,
3706
- activeId: this.activeId,
3707
- flickVelocity: this.flickVelocity,
3708
- dragThreshold: this.dragThreshold
3709
- });
4189
+ const target = this.snaps.findDragSettleTarget(
4190
+ {
4191
+ delta,
4192
+ velocity,
4193
+ pointerKind: kind,
4194
+ size: this.size,
4195
+ activeId: this.activeId,
4196
+ flickVelocity: this.flickVelocity,
4197
+ dragThreshold: this.dragThreshold
4198
+ },
4199
+ this.dismissBlocked()
4200
+ );
3710
4201
  if (!target) {
3711
4202
  this.clearWillChangeIfIdle();
3712
4203
  return;
3713
4204
  }
3714
4205
  const previousId = this.activeId;
3715
4206
  if (target.id === previousId && target.size === this.size) {
4207
+ if (this.phase === "opening" || this.phase === "closing") {
4208
+ this.land(false);
4209
+ }
3716
4210
  this.clearWillChangeIfIdle();
3717
4211
  return;
3718
4212
  }
3719
4213
  if (this.emitBeforeSnap(target, previousId)) {
3720
- const restore2 = this.snaps.findById(previousId);
3721
- if (restore2) {
3722
- void this.animation.animateTo(restore2.size, 0);
3723
- }
4214
+ this.restoreAfterDrag();
3724
4215
  return;
3725
4216
  }
3726
- const previousSize = this.size;
3727
- const previousSnapSize = this.snaps.findById(previousId)?.size;
3728
- this.scrollCache.cache(previousId, previousSize, target.size);
3729
- this.activeId = target.id;
3730
- if (previousSnapSize === 0 && target.size > 0) {
3731
- this.opening = true;
3732
- this.promotedForOpen = true;
3733
- sheetStack.promote(this.id);
3734
- }
3735
- const settleCap = this.snaps.getMaxAxisSize();
3736
- const settleSize = settleCap > 0 ? Math.min(target.size, settleCap) : target.size;
3737
- this.allowOvershoot = true;
3738
- void this.animation.animateTo(settleSize, velocity).then(() => {
3739
- if (signal.aborted) return;
3740
- this.allowOvershoot = false;
3741
- this.opening = false;
3742
- this.completeSnap(
3743
- target.id,
3744
- target.size,
3745
- previousSize,
3746
- previousSnapSize === 0,
3747
- true
3748
- );
3749
- });
4217
+ void this.runTransition(target, velocity, true);
4218
+ }
4219
+ restoreAfterDrag() {
4220
+ const active = this.snaps.findById(this.activeId);
4221
+ if (active) void this.runTransition(active, 0, false);
4222
+ }
4223
+ smallestOpenSize() {
4224
+ const allowed = this.snaps.getAllowedIds();
4225
+ for (const snap of this.snaps.getResolvedSnaps()) {
4226
+ if (snap.size > 0 && allowed.includes(snap.id)) return snap.size;
4227
+ }
4228
+ return 0;
3750
4229
  }
3751
4230
  isDraggingAny() {
3752
4231
  return (this.gesture?.isDragging ?? false) || (this.contentGesture?.isDragging ?? false);
@@ -3771,9 +4250,10 @@ var BottomSheetCore = class {
3771
4250
  const offset = cap - clamped;
3772
4251
  const style = this.element.style;
3773
4252
  if (!skipTransform) style.transform = this.transformTemplate(offset);
4253
+ const moving = this.animation.isAnimating || this.isDraggingAny();
3774
4254
  const sizeChanged = this.sizeWriteSentinel.shouldWrite(
3775
4255
  clamped,
3776
- this.animation.isAnimating || this.isDraggingAny() ? SIZE_WRITE_EPSILON : 0
4256
+ moving ? SIZE_WRITE_EPSILON : 0
3777
4257
  );
3778
4258
  if (sizeChanged) {
3779
4259
  style.setProperty("--bs-size", `${clamped}px`);
@@ -3786,11 +4266,13 @@ var BottomSheetCore = class {
3786
4266
  if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
3787
4267
  this.rootEl.style.setProperty("--bs-size", `${clamped}px`);
3788
4268
  }
4269
+ this.homeRoot?.style.setProperty("--bs-size", `${clamped}px`);
3789
4270
  }
3790
4271
  const progress = this.computeProgress(clamped);
4272
+ const opacityEpsilon = moving ? OPACITY_WRITE_EPSILON : 0;
3791
4273
  const progressChanged = this.progressWriteSentinel.shouldWrite(
3792
4274
  progress,
3793
- OPACITY_WRITE_EPSILON
4275
+ opacityEpsilon
3794
4276
  );
3795
4277
  if (progressChanged) {
3796
4278
  style.setProperty("--bs-progress", String(progress));
@@ -3800,8 +4282,9 @@ var BottomSheetCore = class {
3800
4282
  if (this.rootEl && this.rootEl !== this.anchorHost) {
3801
4283
  this.rootEl.style.setProperty("--bs-progress", String(progress));
3802
4284
  }
4285
+ this.homeRoot?.style.setProperty("--bs-progress", String(progress));
3803
4286
  }
3804
- this.scrim.applyOpacity(progress, progressChanged);
4287
+ this.scrim.applyOpacity(progress, progressChanged, opacityEpsilon);
3805
4288
  if ((progressChanged || sizeChanged) && this.bus.listenerCount("progress") > 0) {
3806
4289
  this.progressPayload.value = progress;
3807
4290
  this.progressPayload.size = clamped;
@@ -3814,238 +4297,322 @@ var BottomSheetCore = class {
3814
4297
  if (reachableMax <= min) return 0;
3815
4298
  return Math.min(Math.max((size - min) / (reachableMax - min), 0), 1);
3816
4299
  }
3817
- handleOpen() {
3818
- if (this.promotedForOpen) this.promotedForOpen = false;
3819
- else sheetStack.promote(this.id);
3820
- try {
3821
- this.lifecycle.install();
3822
- } catch (err) {
3823
- if (!this.destroyed) this.newCycle();
3824
- this.handleClose();
3825
- this.applySize(0);
3826
- this.activeId = this.snapPointsRaw.find((p) => p.id === "closed")?.id ?? this.activeId;
3827
- this.size = 0;
3828
- queueMicrotask(() => {
3829
- throw err;
3830
- });
3831
- }
3832
- }
3833
- resyncAfterResize() {
3834
- if (this.destroyed) return;
3835
- const target = this.snaps.findById(this.activeId);
3836
- if (!target) return;
3837
- this.updateAriaSlider();
3838
- this.emit("snap", {
3839
- id: target.id,
3840
- size: this.size,
3841
- progress: this.computeProgress(this.size)
3842
- });
3843
- if (target.size > 0 && !this.lifecycle.isInstalled) {
3844
- this.emitOpenSequence(target.id);
3845
- } else if (target.size === 0 && this.lifecycle.isInstalled) {
3846
- this.emitCloseSequence();
3847
- }
3848
- }
3849
- handleClose() {
3850
- this.opening = false;
3851
- this.promotedForOpen = false;
3852
- this.lifecycle.release();
3853
- sheetStack.update();
3854
- }
3855
4300
  };
3856
4301
 
3857
4302
  // src/core/features/history-coordinator.ts
3858
- var entries = [];
3859
- var subscribers = /* @__PURE__ */ new Set();
3860
- var suppress = 0;
3861
- var internalDepth = 0;
3862
- var pendingRebrands = [];
3863
- var listenerInstalled = false;
3864
- var patchInstalled = false;
3865
- var origPushState = null;
3866
- var origReplaceState = null;
3867
- var patchedPushState = null;
3868
- var patchedReplaceState = null;
3869
- var hasWindow = () => typeof window !== "undefined";
3870
- var hasHistory = () => typeof history !== "undefined";
3871
- var brandMarker = (surface) => ({
4303
+ var MARKER = "__bs";
4304
+ var STACK = "__bsStack";
4305
+ var DEPTH = "__bsDepth";
4306
+ var ROUTED = "__bsRouted";
4307
+ var SETTLE_TIMEOUT_MS = 1e3;
4308
+ var state2 = shared(
4309
+ "history",
4310
+ () => ({
4311
+ live: [],
4312
+ stackId: void 0,
4313
+ baseUrl: void 0,
4314
+ position: null,
4315
+ knownLength: 0,
4316
+ href: "",
4317
+ subscribers: /* @__PURE__ */ new Set(),
4318
+ internal: 0,
4319
+ pending: [],
4320
+ deferred: [],
4321
+ waiters: [],
4322
+ timer: null,
4323
+ listening: false,
4324
+ leftovers: false,
4325
+ orphanChecked: false,
4326
+ push: null,
4327
+ replace: null
4328
+ })
4329
+ );
4330
+ var hasHistory = () => typeof window !== "undefined" && typeof history !== "undefined";
4331
+ var plain = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
4332
+ var depthOf = (value) => {
4333
+ const depth = value?.[DEPTH];
4334
+ return typeof depth === "number" ? depth : null;
4335
+ };
4336
+ var isMarker = (value) => value?.[MARKER] === true;
4337
+ var inStack = (value) => value !== null && state2.stackId !== void 0 && value[STACK] === state2.stackId && depthOf(value) !== null;
4338
+ var foreignKeys = (value) => {
4339
+ const out = {};
4340
+ const source = plain(value);
4341
+ if (!source) return out;
4342
+ for (const key of Object.keys(source)) {
4343
+ if (!key.startsWith(MARKER)) out[key] = source[key];
4344
+ }
4345
+ return out;
4346
+ };
4347
+ var markerFor = (surface, depth) => ({
4348
+ ...foreignKeys(history.state),
3872
4349
  ...surface.markerState(),
3873
- __bs: true
4350
+ [MARKER]: true,
4351
+ [STACK]: state2.stackId,
4352
+ [DEPTH]: depth
3874
4353
  });
4354
+ var urlForDepth = (depth) => {
4355
+ for (let i = depth - 1; i >= 0; i -= 1) {
4356
+ const url = state2.live[i]?.surface.url;
4357
+ if (url !== void 0) return url;
4358
+ }
4359
+ return state2.baseUrl;
4360
+ };
3875
4361
  var runInternal = (fn) => {
3876
- internalDepth += 1;
4362
+ state2.internal += 1;
3877
4363
  try {
3878
4364
  fn();
4365
+ return true;
4366
+ } catch {
4367
+ return false;
3879
4368
  } finally {
3880
- internalDepth -= 1;
4369
+ state2.internal -= 1;
3881
4370
  }
3882
4371
  };
3883
4372
  var notifyRouteChange = () => {
3884
- const snapshot = Array.from(subscribers);
3885
- for (const fn of snapshot) fn();
4373
+ for (const fn of Array.from(state2.subscribers)) {
4374
+ try {
4375
+ fn();
4376
+ } catch (err) {
4377
+ queueMicrotask(() => {
4378
+ throw err;
4379
+ });
4380
+ }
4381
+ }
3886
4382
  };
3887
4383
  var ensureListener = () => {
3888
- if (listenerInstalled || !hasWindow()) return;
4384
+ if (state2.listening || !hasHistory()) return;
3889
4385
  window.addEventListener("popstate", onPopState);
3890
- listenerInstalled = true;
4386
+ state2.listening = true;
3891
4387
  };
3892
4388
  var maybeTeardownListener = () => {
3893
- if (!listenerInstalled) return;
3894
- if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
3895
- if (hasWindow()) window.removeEventListener("popstate", onPopState);
3896
- listenerInstalled = false;
3897
- };
3898
- var installPatch = () => {
3899
- if (patchInstalled || !hasHistory()) return;
3900
- origPushState = history.pushState;
3901
- origReplaceState = history.replaceState;
3902
- patchedPushState = function(...args) {
3903
- origPushState.apply(this, args);
3904
- if (internalDepth === 0) notifyRouteChange();
3905
- };
3906
- patchedReplaceState = function(...args) {
3907
- origReplaceState.apply(this, args);
3908
- if (internalDepth === 0) notifyRouteChange();
3909
- };
3910
- history.pushState = patchedPushState;
3911
- history.replaceState = patchedReplaceState;
3912
- patchInstalled = true;
3913
- };
3914
- var removePatch = () => {
3915
- if (!patchInstalled) return;
3916
- if (history.pushState === patchedPushState && origPushState) {
3917
- history.pushState = origPushState;
3918
- }
3919
- if (history.replaceState === patchedReplaceState && origReplaceState) {
3920
- history.replaceState = origReplaceState;
3921
- }
3922
- origPushState = null;
3923
- origReplaceState = null;
3924
- patchedPushState = null;
3925
- patchedReplaceState = null;
3926
- patchInstalled = false;
3927
- };
3928
- function onPopState() {
3929
- if (suppress > 0) {
3930
- suppress -= 1;
3931
- const rebrand = pendingRebrands.shift();
3932
- if (rebrand) rebrand();
3933
- maybeTeardownListener();
4389
+ if (!state2.listening) return;
4390
+ if (state2.live.length > 0 || state2.subscribers.size > 0 || state2.pending.length > 0 || state2.leftovers) {
3934
4391
  return;
3935
4392
  }
3936
- if (entries.length === 0) {
3937
- notifyRouteChange();
3938
- maybeTeardownListener();
3939
- return;
3940
- }
3941
- let target = null;
3942
- let targetIdx = -1;
3943
- for (let i = entries.length - 1; i >= 0; i -= 1) {
3944
- const entry = entries[i];
3945
- if (!entry.surface.isOpen()) continue;
3946
- if (!target) {
3947
- target = entry;
3948
- targetIdx = i;
3949
- }
3950
- if (entry.surface.isTop()) {
3951
- target = entry;
3952
- targetIdx = i;
3953
- break;
3954
- }
3955
- }
3956
- if (!target) {
3957
- const removed = entries.pop();
3958
- if (removed) removed.live = false;
4393
+ if (hasHistory()) window.removeEventListener("popstate", onPopState);
4394
+ state2.listening = false;
4395
+ };
4396
+ var settleIfIdle = () => {
4397
+ if (state2.pending.length > 0) return;
4398
+ if (state2.timer !== null) {
4399
+ clearTimeout(state2.timer);
4400
+ state2.timer = null;
4401
+ }
4402
+ for (const entry of state2.deferred.splice(0)) pushEntry(entry);
4403
+ for (const resolve of state2.waiters.splice(0)) resolve();
4404
+ };
4405
+ var traverse = (delta, kind) => {
4406
+ state2.pending.push(kind);
4407
+ if (state2.timer !== null) clearTimeout(state2.timer);
4408
+ state2.timer = setTimeout(() => {
4409
+ state2.timer = null;
4410
+ state2.pending.length = 0;
4411
+ settleIfIdle();
3959
4412
  maybeTeardownListener();
3960
- return;
3961
- }
3962
- target.live = false;
3963
- entries.splice(targetIdx, 1);
3964
- const settled = target;
3965
- void Promise.resolve(settled.surface.close()).then(() => {
3966
- if (settled.surface.isOpen()) restore(settled);
4413
+ }, SETTLE_TIMEOUT_MS);
4414
+ ensureListener();
4415
+ const moved = runInternal(() => {
4416
+ if (delta < 0) history.back();
4417
+ else history.forward();
3967
4418
  });
3968
- maybeTeardownListener();
3969
- }
3970
- function restore(entry) {
3971
- if (!hasWindow() || !hasHistory()) return;
3972
- entry.live = true;
4419
+ if (!moved) {
4420
+ state2.pending.pop();
4421
+ settleIfIdle();
4422
+ }
4423
+ };
4424
+ var newStackId = () => `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
4425
+ var startStack = () => {
4426
+ state2.stackId = newStackId();
4427
+ const current = history.state;
4428
+ const leftover = plain(current);
4429
+ state2.baseUrl = isMarker(leftover) && leftover?.[ROUTED] !== void 0 ? void 0 : location.href;
4430
+ if (isMarker(leftover)) return;
4431
+ if (current !== null && current !== void 0 && !leftover) return;
3973
4432
  runInternal(() => {
3974
- try {
3975
- history.pushState(brandMarker(entry.surface), "", entry.surface.url);
3976
- } catch {
3977
- entry.live = false;
3978
- }
4433
+ history.replaceState(
4434
+ { ...foreignKeys(current), [STACK]: state2.stackId, [DEPTH]: 0 },
4435
+ "",
4436
+ location.href
4437
+ );
3979
4438
  });
3980
- if (entry.live) {
3981
- entries.push(entry);
3982
- ensureListener();
3983
- }
4439
+ };
4440
+ function pushEntry(entry) {
4441
+ const depth = state2.live.length + 1;
4442
+ if (state2.live.length === 0) startStack();
4443
+ const written = runInternal(() => {
4444
+ history.pushState(markerFor(entry.surface, depth), "", entry.surface.url);
4445
+ });
4446
+ if (!written) return false;
4447
+ state2.live.push(entry);
4448
+ state2.position = depth;
4449
+ state2.knownLength = history.length;
4450
+ state2.href = location.href;
4451
+ ensureListener();
4452
+ return true;
3984
4453
  }
3985
- function pushBackMarker(surface) {
3986
- const entry = { surface, priorUrl: void 0, live: false };
3987
- if (!hasWindow() || !hasHistory()) {
3988
- return entry;
4454
+ var enlist = (entry) => {
4455
+ if (state2.pending.length > 0) state2.deferred.push(entry);
4456
+ else pushEntry(entry);
4457
+ };
4458
+ var sameBrand = (a, b) => {
4459
+ for (const key of /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)])) {
4460
+ if (key.startsWith(MARKER) && a[key] !== b[key]) return false;
3989
4461
  }
3990
- entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
4462
+ return true;
4463
+ };
4464
+ var rebrand = (depth) => {
4465
+ const entry = state2.live[depth - 1];
4466
+ if (!entry) return;
4467
+ const url = urlForDepth(depth);
4468
+ const marker = markerFor(entry.surface, depth);
4469
+ const atUrl = url === void 0 || new URL(url, location.href).href === location.href;
4470
+ if (atUrl && sameBrand(plain(history.state) ?? {}, marker)) return;
3991
4471
  runInternal(() => {
4472
+ history.replaceState(marker, "", url);
4473
+ });
4474
+ state2.href = location.href;
4475
+ };
4476
+ var closeAbove = (depth) => {
4477
+ const dropped = state2.live.splice(depth);
4478
+ for (let i = dropped.length - 1; i >= 0; i -= 1) {
4479
+ const entry = dropped[i];
4480
+ let closing = void 0;
3992
4481
  try {
3993
- history.pushState(brandMarker(surface), "", surface.url);
3994
- entry.live = true;
3995
- } catch {
3996
- entry.live = false;
4482
+ closing = entry.surface.close();
4483
+ } catch (err) {
4484
+ queueMicrotask(() => {
4485
+ throw err;
4486
+ });
3997
4487
  }
3998
- });
3999
- if (entry.live) {
4000
- entries.push(entry);
4001
- ensureListener();
4488
+ void Promise.resolve(closing).then(() => {
4489
+ if (!entry.surface.isOpen()) return;
4490
+ const known = (e) => e.surface === entry.surface;
4491
+ if (state2.live.some(known) || state2.deferred.some(known)) return;
4492
+ enlist(entry);
4493
+ });
4494
+ }
4495
+ };
4496
+ function onPopState(event) {
4497
+ const kind = state2.pending.shift();
4498
+ const byUser = kind !== "pop";
4499
+ const landed = plain(event.state);
4500
+ const depth = depthOf(landed);
4501
+ const from = state2.position;
4502
+ const liveBefore = state2.live.length;
4503
+ const grew = history.length > state2.knownLength;
4504
+ state2.knownLength = history.length;
4505
+ const within = inStack(landed);
4506
+ if (within && depth !== null) {
4507
+ state2.position = depth;
4508
+ if (depth > state2.live.length) {
4509
+ const forward = from !== null && from < depth;
4510
+ traverse(forward ? 1 : -1, byUser ? "skip" : "pop");
4511
+ } else if (depth < state2.live.length) {
4512
+ if (byUser) closeAbove(depth);
4513
+ } else {
4514
+ rebrand(depth);
4515
+ }
4516
+ } else if (isMarker(landed)) {
4517
+ state2.position = null;
4518
+ traverse(-1, byUser ? "skip" : "pop");
4519
+ } else {
4520
+ state2.position = null;
4521
+ if (byUser && !grew && state2.live.length > 0) {
4522
+ closeAbove(state2.live.length - 1);
4523
+ }
4524
+ }
4525
+ const moved = location.href !== state2.href;
4526
+ state2.href = location.href;
4527
+ if (kind === void 0 && moved && (liveBefore === 0 || !within)) {
4528
+ notifyRouteChange();
4002
4529
  }
4530
+ settleIfIdle();
4531
+ maybeTeardownListener();
4532
+ }
4533
+ function pushBackMarker(surface) {
4534
+ const entry = { surface };
4535
+ if (hasHistory()) enlist(entry);
4003
4536
  return entry;
4004
4537
  }
4005
4538
  function popBackMarker(handle) {
4006
- if (!hasWindow() || !hasHistory()) return;
4539
+ if (!hasHistory()) return Promise.resolve();
4007
4540
  const entry = handle;
4008
- const idx = entries.indexOf(entry);
4009
- if (idx === -1 || !entry.live) return;
4010
- const last = entries.length - 1;
4011
- entry.live = false;
4012
- entries.splice(idx, 1);
4013
- let rebrand = null;
4014
- if (idx !== last) {
4015
- const rebrandSurface = entries[entries.length - 1].surface;
4016
- const rebrandUrl = entry.priorUrl;
4017
- rebrand = () => {
4018
- runInternal(() => {
4019
- history.replaceState(
4020
- brandMarker(rebrandSurface),
4021
- "",
4022
- rebrandUrl !== void 0 ? rebrandUrl : location.href
4023
- );
4024
- });
4025
- };
4541
+ const waiting = state2.deferred.indexOf(entry);
4542
+ if (waiting !== -1) state2.deferred.splice(waiting, 1);
4543
+ const idx = state2.live.indexOf(entry);
4544
+ if (idx === -1) return historySettled();
4545
+ const top = state2.live.length;
4546
+ state2.live.splice(idx, 1);
4547
+ const current = plain(history.state);
4548
+ const onTop = isMarker(current) && inStack(current) && depthOf(current) === top;
4549
+ if (onTop && state2.pending.length === 0) {
4550
+ traverse(-1, "pop");
4551
+ } else {
4552
+ state2.leftovers = true;
4553
+ ensureListener();
4026
4554
  }
4027
- pendingRebrands.push(rebrand);
4028
- suppress += 1;
4029
- runInternal(() => {
4030
- try {
4031
- history.back();
4032
- } catch {
4033
- suppress = Math.max(0, suppress - 1);
4034
- pendingRebrands.pop();
4035
- }
4036
- });
4037
4555
  maybeTeardownListener();
4556
+ return historySettled();
4038
4557
  }
4558
+ function releaseOrphanMarker() {
4559
+ if (!hasHistory() || state2.orphanChecked) return;
4560
+ state2.orphanChecked = true;
4561
+ if (state2.live.length > 0 || state2.pending.length > 0) return;
4562
+ if (!isMarker(plain(history.state))) return;
4563
+ state2.leftovers = true;
4564
+ traverse(-1, "pop");
4565
+ }
4566
+ function historySettled() {
4567
+ if (state2.pending.length === 0) return Promise.resolve();
4568
+ return new Promise((resolve) => {
4569
+ state2.waiters.push(resolve);
4570
+ });
4571
+ }
4572
+ var wrap = (original) => function(...args) {
4573
+ original.apply(this, args);
4574
+ state2.knownLength = history.length;
4575
+ if (location.href === state2.href) return;
4576
+ state2.href = location.href;
4577
+ if (state2.internal === 0 && state2.subscribers.size > 0) {
4578
+ notifyRouteChange();
4579
+ }
4580
+ };
4581
+ var installPatch = () => {
4582
+ if (!state2.push || history.pushState === state2.push.original) {
4583
+ const original = history.pushState;
4584
+ const wrapper = wrap(original);
4585
+ history.pushState = wrapper;
4586
+ state2.push = { wrapper, original };
4587
+ }
4588
+ if (!state2.replace || history.replaceState === state2.replace.original) {
4589
+ const original = history.replaceState;
4590
+ const wrapper = wrap(original);
4591
+ history.replaceState = wrapper;
4592
+ state2.replace = { wrapper, original };
4593
+ }
4594
+ };
4595
+ var removePatch = () => {
4596
+ if (state2.push && history.pushState === state2.push.wrapper) {
4597
+ history.pushState = state2.push.original;
4598
+ state2.push = null;
4599
+ }
4600
+ if (state2.replace && history.replaceState === state2.replace.wrapper) {
4601
+ history.replaceState = state2.replace.original;
4602
+ state2.replace = null;
4603
+ }
4604
+ };
4039
4605
  function subscribeRouteChange(fn) {
4040
- if (!hasWindow() || !hasHistory()) return () => {
4606
+ if (!hasHistory()) return () => {
4041
4607
  };
4042
- subscribers.add(fn);
4043
- if (subscribers.size === 1) installPatch();
4608
+ state2.subscribers.add(fn);
4609
+ state2.href = location.href;
4610
+ state2.knownLength = history.length;
4611
+ installPatch();
4044
4612
  ensureListener();
4045
4613
  return () => {
4046
- if (!subscribers.has(fn)) return;
4047
- subscribers.delete(fn);
4048
- if (subscribers.size === 0) removePatch();
4614
+ if (!state2.subscribers.delete(fn)) return;
4615
+ if (state2.subscribers.size === 0) removePatch();
4049
4616
  maybeTeardownListener();
4050
4617
  };
4051
4618
  }
@@ -4061,36 +4628,37 @@ function installRoute(deps) {
4061
4628
  };
4062
4629
  }
4063
4630
  let handle = null;
4631
+ const surface = {
4632
+ isOpen: () => !deps.isDestroyed() && deps.isOpen(),
4633
+ close: deps.close,
4634
+ markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
4635
+ url: deps.routedTo
4636
+ };
4064
4637
  const onOpen = () => {
4065
4638
  if (handle) return;
4066
- handle = pushBackMarker({
4067
- isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
4068
- isTop: deps.isTopSheet,
4069
- close: deps.close,
4070
- markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
4071
- url: deps.routedTo
4072
- });
4639
+ handle = pushBackMarker(surface);
4073
4640
  };
4074
4641
  const onClose = () => {
4075
4642
  if (!handle) return;
4076
- popBackMarker(handle);
4643
+ deps.hold(popBackMarker(handle));
4077
4644
  handle = null;
4078
4645
  };
4079
4646
  const unsubscribeOpen = deps.on("open", onOpen);
4080
4647
  const unsubscribeClose = deps.on("close", onClose);
4081
- if (deps.getSize() > 0) onOpen();
4648
+ if (deps.isOpen()) onOpen();
4649
+ else releaseOrphanMarker();
4082
4650
  return () => {
4083
4651
  unsubscribeOpen();
4084
4652
  unsubscribeClose();
4085
4653
  if (handle) {
4086
- popBackMarker(handle);
4654
+ void popBackMarker(handle);
4087
4655
  handle = null;
4088
4656
  }
4089
4657
  };
4090
4658
  }
4091
4659
  function installRouteChange(deps) {
4092
4660
  return subscribeRouteChange(() => {
4093
- if (deps.isDestroyed() || deps.getSize() <= 0) return;
4661
+ if (deps.isDestroyed() || !deps.isOpen()) return;
4094
4662
  void deps.close();
4095
4663
  });
4096
4664
  }
@@ -4124,7 +4692,10 @@ function installAutoCollapse(deps) {
4124
4692
  };
4125
4693
  const fire = () => {
4126
4694
  if (deps.isDestroyed()) return;
4127
- if (deps.isDragging()) return;
4695
+ if (deps.isDragging() || deps.isAnimating()) {
4696
+ reset2();
4697
+ return;
4698
+ }
4128
4699
  const active = deps.resolveSnap(deps.getActiveId());
4129
4700
  if (!active || active.size === 0) return;
4130
4701
  let target = null;
@@ -4161,6 +4732,9 @@ function installContentDrag(deps) {
4161
4732
 
4162
4733
  // src/core/features/visual-viewport.ts
4163
4734
  var SAFETY_PAD = 8;
4735
+ var KEYBOARD_MIN_INSET = 1;
4736
+ var KEYBOARD_MIN_COVER = 60;
4737
+ var ZOOMED = 1.01;
4164
4738
  function installVisualViewport(deps) {
4165
4739
  if (typeof window === "undefined" || !window.visualViewport) {
4166
4740
  return () => {
@@ -4168,36 +4742,36 @@ function installVisualViewport(deps) {
4168
4742
  }
4169
4743
  const vv = window.visualViewport;
4170
4744
  let rafId = null;
4745
+ const coveredByKeyboard = () => {
4746
+ if ((vv.scale || 1) > ZOOMED) return 0;
4747
+ const covered = window.innerHeight - ((vv.offsetTop || 0) + vv.height);
4748
+ return covered >= KEYBOARD_MIN_COVER ? Math.round(covered) : 0;
4749
+ };
4171
4750
  const onResize = () => {
4172
4751
  if (rafId !== null) return;
4173
4752
  rafId = requestAnimationFrame(() => {
4174
4753
  rafId = null;
4175
4754
  if (deps.isDestroyed()) return;
4755
+ deps.setKeyboardInset(coveredByKeyboard());
4756
+ const before = seatOf(deps);
4176
4757
  deps.recomputeSnaps();
4177
4758
  const isVertical = deps.isVerticalAxis();
4178
4759
  const visible = isVertical ? vv.height : vv.width;
4179
4760
  const windowSize = isVertical ? window.innerHeight : window.innerWidth;
4180
- const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
4761
+ const pad = windowSize - visible > KEYBOARD_MIN_INSET ? SAFETY_PAD : 0;
4762
+ const clamp = Math.max(0, Math.min(windowSize, visible) - pad);
4181
4763
  if (clamp < deps.getMaxAxisSize()) {
4182
4764
  deps.setMaxAxisSize(clamp);
4183
4765
  }
4184
- const wasAnimating = deps.isAnimating?.() ?? false;
4185
- deps.cancelInFlight();
4186
- deps.newCycle();
4187
- const max = deps.getMaxAxisSize();
4188
- deps.setSize(Math.min(deps.getSize(), max));
4189
- const current = deps.resolveActiveSnap();
4190
- if (current && !deps.isDragging()) {
4191
- deps.applySize(Math.min(current.size, max));
4192
- if (wasAnimating) deps.resyncAfterCancel?.();
4193
- } else {
4194
- deps.applySize(deps.getSize());
4195
- }
4766
+ if (sameSeat(before, seatOf(deps))) return;
4767
+ deps.reseat();
4196
4768
  });
4197
4769
  };
4198
4770
  vv.addEventListener("resize", onResize);
4771
+ vv.addEventListener("scroll", onResize);
4199
4772
  return () => {
4200
4773
  vv.removeEventListener("resize", onResize);
4774
+ vv.removeEventListener("scroll", onResize);
4201
4775
  if (rafId !== null) cancelAnimationFrame(rafId);
4202
4776
  };
4203
4777
  }
@@ -4212,7 +4786,7 @@ function routeFeature() {
4212
4786
  teardowns.add(
4213
4787
  installRouteChange({
4214
4788
  isDestroyed: ctx.isDestroyed,
4215
- getSize: ctx.getSize,
4789
+ isOpen: () => ctx.getPhase() !== "closed",
4216
4790
  close: () => ctx.close()
4217
4791
  })
4218
4792
  );
@@ -4221,10 +4795,10 @@ function routeFeature() {
4221
4795
  installRoute({
4222
4796
  routedTo: ctx.options.routedTo,
4223
4797
  closeOnBack: ctx.options.closeOnBack,
4224
- isTopSheet: ctx.isTopSheet,
4225
- getSize: ctx.getSize,
4798
+ isOpen: () => ctx.getPhase() !== "closed",
4226
4799
  isDestroyed: ctx.isDestroyed,
4227
4800
  close: () => ctx.close("back"),
4801
+ hold: ctx.holdSettle,
4228
4802
  on: ctx.on,
4229
4803
  sheetId: ctx.sheetId
4230
4804
  })
@@ -4250,6 +4824,7 @@ function autoCollapseFeature() {
4250
4824
  ms: ctx.options.autoCollapseAfter,
4251
4825
  isDestroyed: ctx.isDestroyed,
4252
4826
  isDragging: ctx.isDragging,
4827
+ isAnimating: ctx.isAnimating,
4253
4828
  getAllowedIds: ctx.getAllowedIds,
4254
4829
  getActiveId: ctx.getActiveId,
4255
4830
  resolveSnap: ctx.resolveSnap,
@@ -4277,21 +4852,14 @@ function visualViewportFeature() {
4277
4852
  install: (ctx) => {
4278
4853
  if (typeof window === "undefined") return;
4279
4854
  return installVisualViewport({
4280
- element: ctx.element,
4281
4855
  isVerticalAxis: ctx.isVerticalAxis,
4282
4856
  isDestroyed: ctx.isDestroyed,
4283
- isDragging: ctx.isDragging,
4284
4857
  recomputeSnaps: ctx.recomputeSnaps,
4285
4858
  resolveActiveSnap: ctx.resolveActiveSnap,
4286
4859
  getMaxAxisSize: ctx.getMaxAxisSize,
4287
- getSize: ctx.getSize,
4288
4860
  setMaxAxisSize: ctx.setMaxAxisSize,
4289
- setSize: ctx.setSize,
4290
- applySize: ctx.applySize,
4291
- cancelInFlight: ctx.cancelInFlight,
4292
- newCycle: ctx.newCycle,
4293
- isAnimating: ctx.isAnimating,
4294
- resyncAfterCancel: ctx.resyncAfterResize
4861
+ setKeyboardInset: ctx.setKeyboardInset,
4862
+ reseat: ctx.reseat
4295
4863
  });
4296
4864
  }
4297
4865
  };
@@ -4455,42 +5023,14 @@ var BottomSheetEngine = class extends BottomSheetCore {
4455
5023
  }
4456
5024
  };
4457
5025
 
4458
- // src/core/features/teleport.ts
4459
- var resolveTeleportTarget = (target) => {
4460
- if (!target) return null;
4461
- if (typeof target !== "string") return target;
4462
- if (typeof document === "undefined") return null;
4463
- if (target === "body") return document.body;
4464
- return document.querySelector(target);
4465
- };
4466
- var teleportElements = (els, target) => {
4467
- const records = [];
4468
- for (const el of els) {
4469
- if (!el || el.parentNode === target) continue;
4470
- records.push({ el, parent: el.parentNode, next: el.nextSibling });
4471
- target.appendChild(el);
4472
- }
4473
- return () => {
4474
- for (let i = records.length - 1; i >= 0; i--) {
4475
- const { el, parent, next } = records[i];
4476
- if (parent && parent.isConnected) {
4477
- const before = next && next.parentNode === parent ? next : null;
4478
- try {
4479
- parent.insertBefore(el, before);
4480
- } catch {
4481
- el.parentNode?.removeChild(el);
4482
- }
4483
- } else {
4484
- el.parentNode?.removeChild(el);
4485
- }
4486
- }
4487
- };
4488
- };
5026
+ // src/core/primitives/open-state.ts
5027
+ var closedSnapId = (points) => points.find((point) => point.size === 0)?.id;
4489
5028
 
4490
5029
  // src/svelte/useBottomSheet.svelte.ts
4491
5030
  var SSR_STATE = Object.freeze({
4492
5031
  size: 0,
4493
5032
  activeId: "",
5033
+ phase: "closed",
4494
5034
  isDragging: false,
4495
5035
  isAnimating: false,
4496
5036
  progress: 0
@@ -4500,21 +5040,11 @@ function createBottomSheet(opts) {
4500
5040
  const pending = [];
4501
5041
  const attach = (refs) => {
4502
5042
  if (engine) engine.destroy();
4503
- const {
4504
- onSnap,
4505
- teleportTo,
4506
- backdropColor,
4507
- backdropOpacity,
4508
- ...engineOpts
4509
- } = opts;
4510
- const created = new BottomSheetEngine({ ...engineOpts, ...refs });
4511
- engine = created;
5043
+ const { onSnap, teleportTo, ...engineOpts } = opts;
4512
5044
  const target = resolveTeleportTarget(teleportTo);
4513
5045
  const restoreTeleport = target ? teleportElements([refs.backdrop, refs.scrim, refs.element], target) : null;
4514
- if (backdropColor !== void 0) created.setScrimColor(backdropColor);
4515
- if (backdropOpacity !== void 0) {
4516
- created.setBackdropRange([0, backdropOpacity]);
4517
- }
5046
+ const created = new BottomSheetEngine({ ...engineOpts, ...refs });
5047
+ engine = created;
4518
5048
  if (onSnap) {
4519
5049
  created.on("snap", (payload) => onSnap(payload.id));
4520
5050
  }
@@ -4547,7 +5077,7 @@ function createBottomSheet(opts) {
4547
5077
  },
4548
5078
  snapTo: (id) => engine?.snapTo(id) ?? Promise.resolve(),
4549
5079
  open: (id) => engine?.open(id) ?? Promise.resolve(),
4550
- close: () => engine?.close() ?? Promise.resolve(),
5080
+ close: (reason) => engine?.close(reason) ?? Promise.resolve(),
4551
5081
  expand: () => engine?.expand() ?? Promise.resolve(),
4552
5082
  collapse: () => engine?.collapse() ?? Promise.resolve(),
4553
5083
  isTop: () => engine?.isTop() ?? false,
@@ -4569,32 +5099,98 @@ function createBottomSheet(opts) {
4569
5099
  getEngine: () => engine
4570
5100
  };
4571
5101
  }
5102
+ var rest_excludes = /* @__PURE__ */ new Set([
5103
+ "$$slots",
5104
+ "$$events",
5105
+ "$$legacy",
5106
+ "snapPoints",
5107
+ "allowed",
5108
+ "initial",
5109
+ "mode",
5110
+ "animation",
5111
+ "spring",
5112
+ "focusTrap",
5113
+ "closeOnEscape",
5114
+ "closeOnBack",
5115
+ "lockBodyScroll",
5116
+ "rubberBand",
5117
+ "backdropRange",
5118
+ "backdrop",
5119
+ "closeOnBackdrop",
5120
+ "persistent",
5121
+ "disableClose",
5122
+ "disableDrag",
5123
+ "dragFrom",
5124
+ "dragFromContent",
5125
+ "fitContentToSnap",
5126
+ "closeOnRouteChange",
5127
+ "stackEffect",
5128
+ "teleport",
5129
+ "teleportTo",
5130
+ "radius",
5131
+ "maxHeight",
5132
+ "backdropColor",
5133
+ "backdropOpacity",
5134
+ "open",
5135
+ "snap",
5136
+ "returnFocusTo",
5137
+ "ariaLabel",
5138
+ "handleLabel",
5139
+ "contentLabel",
5140
+ "header",
5141
+ "footer",
5142
+ "leftButton",
5143
+ "rightButton",
5144
+ "screen",
5145
+ "children",
5146
+ "onsnap",
5147
+ "onbeforesnap",
5148
+ "onopen",
5149
+ "onclose",
5150
+ "onbeforeclose",
5151
+ "onopened",
5152
+ "onclosed",
5153
+ "ondragstart",
5154
+ "ondragend",
5155
+ "ondrag",
5156
+ "onprogress",
5157
+ "onchange"
5158
+ ]);
4572
5159
  var root = $2__namespace.from_html(`<div class="bs-backdrop" aria-hidden="true"></div>`);
4573
5160
  var root_1 = $2__namespace.from_html(`<div class="bs-header"><!></div>`);
4574
5161
  var root_2 = $2__namespace.from_html(`<div class="bs-footer"><!></div>`);
4575
5162
  var root_3 = $2__namespace.from_html(`<div class="bs-button-slot" data-side="left"><!></div>`);
4576
5163
  var root_4 = $2__namespace.from_html(`<div class="bs-button-slot" data-side="right"><!></div>`);
4577
- var root_5 = $2__namespace.from_html(`<div class="bs-root"><!> <div class="bs-screen"><!></div> <section class="bs-sheet" role="dialog"><div class="bs-handle" role="slider" tabindex="0" aria-label="Resize sheet" aria-valuemin="0" aria-valuemax="0" aria-valuenow="0"></div> <!> <div class="bs-content" tabindex="0" role="region" aria-label="Sheet content"><!></div> <!> <span class="bs-sr-only" role="status" aria-live="polite"> </span></section> <!> <!></div>`);
5164
+ var root_5 = $2__namespace.from_html(`<div class="bs-root"><!> <div class="bs-screen"><!></div> <section class="bs-sheet" role="dialog"><div class="bs-handle" role="slider" tabindex="0" aria-valuemin="0" aria-valuemax="0" aria-valuenow="0"></div> <!> <div class="bs-content" tabindex="0" role="region"><!></div> <!> <span class="bs-sr-only" role="status" aria-live="polite"> </span></section> <!> <!></div>`);
4578
5165
  function BottomSheet($$anchor, $$props) {
4579
5166
  $2__namespace.push($$props, true);
4580
- let mode = $2__namespace.prop($$props, "mode", 3, "bottom"), animation = $2__namespace.prop($$props, "animation", 3, "spring"), focusTrap = $2__namespace.prop($$props, "focusTrap", 3, false), closeOnEscape = $2__namespace.prop($$props, "closeOnEscape", 3, true), closeOnBack = $2__namespace.prop($$props, "closeOnBack", 3, false), lockBodyScroll2 = $2__namespace.prop($$props, "lockBodyScroll", 3, true), rubberBand2 = $2__namespace.prop($$props, "rubberBand", 3, true), backdrop = $2__namespace.prop($$props, "backdrop", 3, true), closeOnBackdrop = $2__namespace.prop($$props, "closeOnBackdrop", 3, true), persistent = $2__namespace.prop($$props, "persistent", 3, false), disableClose = $2__namespace.prop($$props, "disableClose", 3, false), disableDrag = $2__namespace.prop($$props, "disableDrag", 3, false), closeOnRouteChange = $2__namespace.prop($$props, "closeOnRouteChange", 3, false), stackEffect = $2__namespace.prop($$props, "stackEffect", 3, false), teleport = $2__namespace.prop($$props, "teleport", 3, false), openProp = $2__namespace.prop($$props, "open", 15), snap = $2__namespace.prop($$props, "snap", 15), ariaLabel = $2__namespace.prop($$props, "ariaLabel", 3, "Bottom sheet");
5167
+ let mode = $2__namespace.prop($$props, "mode", 3, "bottom"), animation = $2__namespace.prop($$props, "animation", 3, "spring"), focusTrap = $2__namespace.prop($$props, "focusTrap", 3, false), closeOnEscape = $2__namespace.prop($$props, "closeOnEscape", 3, true), closeOnBack = $2__namespace.prop($$props, "closeOnBack", 3, false), lockBodyScroll2 = $2__namespace.prop($$props, "lockBodyScroll", 3, true), rubberBand2 = $2__namespace.prop($$props, "rubberBand", 3, true), backdrop = $2__namespace.prop($$props, "backdrop", 3, true), closeOnBackdrop = $2__namespace.prop($$props, "closeOnBackdrop", 3, true), persistent = $2__namespace.prop($$props, "persistent", 3, false), disableClose = $2__namespace.prop($$props, "disableClose", 3, false), disableDrag = $2__namespace.prop($$props, "disableDrag", 3, false), closeOnRouteChange = $2__namespace.prop($$props, "closeOnRouteChange", 3, false), stackEffect = $2__namespace.prop($$props, "stackEffect", 3, false), openProp = $2__namespace.prop($$props, "open", 15), snap = $2__namespace.prop($$props, "snap", 15), ariaLabel = $2__namespace.prop($$props, "ariaLabel", 3, "Bottom sheet"), handleLabel = $2__namespace.prop($$props, "handleLabel", 3, "Resize sheet"), contentLabel = $2__namespace.prop($$props, "contentLabel", 3, "Sheet content"), engineRest = $2__namespace.rest_props($$props, rest_excludes);
4581
5168
  let sheetEl = $2__namespace.state(void 0);
4582
5169
  let handleEl = $2__namespace.state(void 0);
4583
5170
  let contentEl = $2__namespace.state(void 0);
4584
5171
  let backdropEl = $2__namespace.state(void 0);
4585
5172
  let screenEl = $2__namespace.state(void 0);
5173
+ const startAt = svelte.untrack(() => $$props.initial ?? (openProp() === false ? closedSnapId($$props.snapPoints) : void 0) ?? snap());
4586
5174
  let viewState = $2__namespace.state($2__namespace.proxy({
4587
5175
  size: 0,
4588
- activeId: svelte.untrack(() => $$props.initial ?? $$props.snapPoints[0]?.id ?? "default"),
5176
+ activeId: svelte.untrack(() => startAt ?? $$props.snapPoints[0]?.id ?? "default"),
5177
+ phase: "closed",
4589
5178
  isDragging: false,
4590
5179
  isAnimating: false,
4591
5180
  progress: 0
4592
5181
  }));
4593
5182
  let engine = null;
4594
5183
  let restoreTeleport = null;
5184
+ let physicalMode = $2__namespace.state($2__namespace.proxy(svelte.untrack(() => guessPhysicalMode(mode()))));
5185
+ const restAtStart = svelte.untrack(() => startsClosed($$props.snapPoints, startAt, $$props.allowed) ? "closed" : void 0);
4595
5186
  svelte.onMount(() => {
4596
5187
  if (!$2__namespace.get(sheetEl)) return;
5188
+ const teleportTarget = $$props.teleport === false ? null : resolveTeleportTarget($$props.teleportTo);
5189
+ if (teleportTarget) {
5190
+ restoreTeleport = teleportElements([$2__namespace.get(backdropEl), $2__namespace.get(screenEl), $2__namespace.get(sheetEl)], teleportTarget);
5191
+ }
4597
5192
  engine = new BottomSheetEngine({
5193
+ ...engineRest,
4598
5194
  element: $2__namespace.get(sheetEl),
4599
5195
  handle: $2__namespace.get(handleEl),
4600
5196
  scrollContainer: $2__namespace.get(contentEl),
@@ -4603,7 +5199,7 @@ function BottomSheet($$anchor, $$props) {
4603
5199
  mode: mode(),
4604
5200
  snapPoints: $$props.snapPoints,
4605
5201
  allowed: $$props.allowed,
4606
- initial: $$props.initial,
5202
+ initial: startAt,
4607
5203
  animation: animation(),
4608
5204
  spring: $$props.spring,
4609
5205
  focusTrap: focusTrap(),
@@ -4622,44 +5218,52 @@ function BottomSheet($$anchor, $$props) {
4622
5218
  stackEffect: stackEffect(),
4623
5219
  radius: $$props.radius,
4624
5220
  maxHeight: $$props.maxHeight,
4625
- returnFocusTo: $$props.returnFocusTo
5221
+ returnFocusTo: $$props.returnFocusTo,
5222
+ backdropColor: $$props.backdropColor,
5223
+ backdropOpacity: $$props.backdropOpacity
4626
5224
  });
4627
- const teleportTarget = teleport() === false ? null : resolveTeleportTarget($$props.teleportTo);
4628
- if (teleportTarget) {
4629
- restoreTeleport = teleportElements([$2__namespace.get(backdropEl), $2__namespace.get(screenEl), $2__namespace.get(sheetEl)], teleportTarget);
4630
- }
4631
5225
  const sync = () => {
4632
5226
  if (!engine) return;
4633
5227
  $2__namespace.set(viewState, { ...engine.state }, true);
4634
5228
  $$props.onchange?.($2__namespace.get(viewState));
4635
5229
  };
5230
+ $2__namespace.set(physicalMode, engine.getMode(), true);
4636
5231
  sync();
4637
- if ($$props.backdropColor !== void 0) engine.setScrimColor($$props.backdropColor);
4638
- if ($$props.backdropOpacity !== void 0) engine.setBackdropRange([0, $$props.backdropOpacity]);
5232
+ if (snap() !== void 0 && snap() !== engine.state.activeId) {
5233
+ snap(engine.state.activeId);
5234
+ }
4639
5235
  engine.on("snap", (payload) => {
4640
5236
  sync();
4641
5237
  snap(payload.id);
4642
5238
  $$props.onsnap?.(payload.id);
4643
5239
  });
4644
5240
  engine.on("open", (payload) => {
5241
+ sync();
4645
5242
  openProp(true);
4646
5243
  $$props.onopen?.(payload.id);
4647
5244
  });
4648
5245
  engine.on("close", () => {
5246
+ sync();
4649
5247
  openProp(false);
4650
5248
  $$props.onclose?.();
4651
5249
  });
4652
5250
  engine.on("before-close", (payload) => $$props.onbeforeclose?.(payload));
4653
5251
  engine.on("before-snap", (payload) => $$props.onbeforesnap?.(payload));
4654
- engine.on("opened", (payload) => $$props.onopened?.(payload.id));
4655
- engine.on("closed", () => $$props.onclosed?.());
4656
- engine.on("dragstart", () => {
5252
+ engine.on("opened", (payload) => {
5253
+ sync();
5254
+ $$props.onopened?.(payload.id);
5255
+ });
5256
+ engine.on("closed", () => {
4657
5257
  sync();
4658
- $$props.ondragstart?.();
5258
+ $$props.onclosed?.();
4659
5259
  });
4660
- engine.on("dragend", () => {
5260
+ engine.on("dragstart", (payload) => {
4661
5261
  sync();
4662
- $$props.ondragend?.();
5262
+ $$props.ondragstart?.(payload);
5263
+ });
5264
+ engine.on("dragend", (payload) => {
5265
+ sync();
5266
+ $$props.ondragend?.(payload);
4663
5267
  });
4664
5268
  if ($$props.ondrag) engine.on("drag", (payload) => $$props.ondrag(payload));
4665
5269
  if ($$props.onprogress) engine.on("progress", (payload) => $$props.onprogress(payload));
@@ -4672,7 +5276,7 @@ function BottomSheet($$anchor, $$props) {
4672
5276
  });
4673
5277
  const snapTo = (id) => engine?.snapTo(id) ?? Promise.resolve();
4674
5278
  const open = (id) => engine?.open(id) ?? Promise.resolve();
4675
- const close = () => engine?.close() ?? Promise.resolve();
5279
+ const close = (reason) => engine?.close(reason) ?? Promise.resolve();
4676
5280
  const expand = () => engine?.expand() ?? Promise.resolve();
4677
5281
  const collapse = () => engine?.collapse() ?? Promise.resolve();
4678
5282
  const isTop = () => engine?.isTop() ?? false;
@@ -4682,6 +5286,11 @@ function BottomSheet($$anchor, $$props) {
4682
5286
  const setScrim = (opts) => engine?.setScrim(opts);
4683
5287
  const setScrimOverlay = (opts) => engine?.setScrimOverlay(opts) ?? (() => {
4684
5288
  });
5289
+ const addAnchor = (opts) => engine?.addAnchor(opts) ?? (() => {
5290
+ });
5291
+ const setScrimStages = (opts) => engine?.setScrimStages(opts) ?? (() => {
5292
+ });
5293
+ const recompute = () => engine?.recompute();
4685
5294
  const setRadius = (r) => engine?.setRadius(r);
4686
5295
  const setMaxHeight = (h) => engine?.setMaxHeight(h);
4687
5296
  const canDismiss = () => engine?.canDismiss() ?? false;
@@ -4723,7 +5332,9 @@ function BottomSheet($$anchor, $$props) {
4723
5332
  if ($$props.dragFrom !== void 0) engine?.setDragFrom($$props.dragFrom);
4724
5333
  });
4725
5334
  $2__namespace.user_effect(() => {
4726
- if (mode() !== void 0) engine?.setMode(mode());
5335
+ const next = mode();
5336
+ if (next !== void 0) engine?.setMode(next);
5337
+ $2__namespace.set(physicalMode, engine ? engine.getMode() : guessPhysicalMode(next), true);
4727
5338
  });
4728
5339
  $2__namespace.user_effect(() => {
4729
5340
  if ($$props.radius !== void 0) engine?.setRadius($$props.radius);
@@ -4732,26 +5343,27 @@ function BottomSheet($$anchor, $$props) {
4732
5343
  if ($$props.maxHeight !== void 0) engine?.setMaxHeight($$props.maxHeight);
4733
5344
  });
4734
5345
  $2__namespace.user_effect(() => {
4735
- if ($$props.backdropColor !== void 0) engine?.setScrimColor($$props.backdropColor);
5346
+ if ($$props.backdropColor !== void 0) engine?.setBackdropColor($$props.backdropColor);
4736
5347
  });
4737
5348
  $2__namespace.user_effect(() => {
4738
- if ($$props.backdropOpacity !== void 0) engine?.setBackdropRange([0, $$props.backdropOpacity]);
5349
+ if ($$props.backdropOpacity !== void 0) engine?.setBackdropOpacity($$props.backdropOpacity);
4739
5350
  });
4740
5351
  $2__namespace.user_effect(() => {
4741
5352
  if (snap() === void 0) return;
4742
5353
  const next = snap();
4743
- if (!engine || svelte.untrack(() => $2__namespace.get(viewState).activeId) === next) return;
5354
+ if (!engine || engine.state.activeId === next) return;
4744
5355
  void engine.snapTo(next);
4745
5356
  });
4746
5357
  $2__namespace.user_effect(() => {
4747
5358
  if (openProp() === void 0) return;
4748
5359
  const next = openProp();
4749
5360
  if (!engine) return;
4750
- const isOpen = svelte.untrack(() => $2__namespace.get(viewState).size) > 0;
4751
- if (next && !isOpen) void engine.open();
4752
- else if (!next && isOpen) void engine.close();
5361
+ const phase = engine.state.phase;
5362
+ const opening = phase === "open" || phase === "opening";
5363
+ if (next && !opening) void engine.open();
5364
+ else if (!next && opening) void engine.close();
4753
5365
  });
4754
- let isVerticalAxis = $2__namespace.derived(() => mode() === "bottom" || mode() === "top");
5366
+ let isVerticalAxis = $2__namespace.derived(() => $2__namespace.get(physicalMode) === "bottom" || $2__namespace.get(physicalMode) === "top");
4755
5367
  var $$exports = {
4756
5368
  snapTo,
4757
5369
  open,
@@ -4764,6 +5376,9 @@ function BottomSheet($$anchor, $$props) {
4764
5376
  setSnapPoints,
4765
5377
  setScrim,
4766
5378
  setScrimOverlay,
5379
+ addAnchor,
5380
+ setScrimStages,
5381
+ recompute,
4767
5382
  setRadius,
4768
5383
  setMaxHeight,
4769
5384
  canDismiss,
@@ -4857,7 +5472,7 @@ function BottomSheet($$anchor, $$props) {
4857
5472
  var node_10 = $2__namespace.child(div_7);
4858
5473
  $2__namespace.snippet(node_10, () => $$props.leftButton);
4859
5474
  $2__namespace.reset(div_7);
4860
- $2__namespace.template_effect(() => $2__namespace.set_attribute(div_7, "data-mode", mode()));
5475
+ $2__namespace.template_effect(() => $2__namespace.set_attribute(div_7, "data-mode", $2__namespace.get(physicalMode)));
4861
5476
  $2__namespace.append($$anchor2, div_7);
4862
5477
  };
4863
5478
  $2__namespace.if(node_9, ($$render) => {
@@ -4871,7 +5486,7 @@ function BottomSheet($$anchor, $$props) {
4871
5486
  var node_12 = $2__namespace.child(div_8);
4872
5487
  $2__namespace.snippet(node_12, () => $$props.rightButton);
4873
5488
  $2__namespace.reset(div_8);
4874
- $2__namespace.template_effect(() => $2__namespace.set_attribute(div_8, "data-mode", mode()));
5489
+ $2__namespace.template_effect(() => $2__namespace.set_attribute(div_8, "data-mode", $2__namespace.get(physicalMode)));
4875
5490
  $2__namespace.append($$anchor2, div_8);
4876
5491
  };
4877
5492
  $2__namespace.if(node_11, ($$render) => {
@@ -4880,11 +5495,14 @@ function BottomSheet($$anchor, $$props) {
4880
5495
  }
4881
5496
  $2__namespace.reset(div);
4882
5497
  $2__namespace.template_effect(() => {
4883
- $2__namespace.set_attribute(section, "data-mode", mode());
5498
+ $2__namespace.set_attribute(section, "data-mode", $2__namespace.get(physicalMode));
5499
+ $2__namespace.set_attribute(section, "data-bs-rest", restAtStart);
4884
5500
  $2__namespace.set_attribute(section, "data-active", $2__namespace.get(viewState).activeId);
4885
5501
  $2__namespace.set_attribute(section, "aria-modal", focusTrap() ? "true" : void 0);
4886
5502
  $2__namespace.set_attribute(section, "aria-label", ariaLabel());
5503
+ $2__namespace.set_attribute(div_3, "aria-label", handleLabel());
4887
5504
  $2__namespace.set_attribute(div_3, "aria-orientation", $2__namespace.get(isVerticalAxis) ? "vertical" : "horizontal");
5505
+ $2__namespace.set_attribute(div_5, "aria-label", contentLabel());
4888
5506
  $2__namespace.set_text(text, $2__namespace.get(viewState).activeId);
4889
5507
  });
4890
5508
  $2__namespace.append($$anchor, div);