@surdeddd/bottom-sheet 0.23.4 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +38 -7
  74. package/dist/webgl.d.cts +0 -1
  75. package/dist/webgl.d.ts +0 -1
  76. package/dist/webgl.js +38 -7
  77. package/llms.txt +330 -0
  78. package/package.json +41 -19
  79. package/dist/transform-jVfAikE9.d.cts +0 -3
  80. package/dist/transform-jVfAikE9.d.ts +0 -3
package/dist/svelte.js CHANGED
@@ -6,6 +6,15 @@ var __defProp = Object.defineProperty;
6
6
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
7
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
8
8
 
9
+ // src/core/primitives/shared.ts
10
+ var STORE_KEY = /* @__PURE__ */ Symbol.for("@surdeddd/bottom-sheet/shared/1");
11
+ function shared(name, init) {
12
+ const host = globalThis;
13
+ const store = host[STORE_KEY] ?? (host[STORE_KEY] = {});
14
+ if (!(name in store)) store[name] = init();
15
+ return store[name];
16
+ }
17
+
9
18
  // src/core/lifecycle/sheet-stack.ts
10
19
  var BASE_Z = 100;
11
20
  var STEP = 10;
@@ -73,7 +82,7 @@ var SheetStack = class {
73
82
  });
74
83
  }
75
84
  };
76
- var sheetStack = new SheetStack();
85
+ var sheetStack = shared("stack", () => new SheetStack());
77
86
 
78
87
  // src/core/primitives/transform.ts
79
88
  function buildTransformTemplate(axis) {
@@ -92,7 +101,7 @@ var offsetFromMatrix = (axis, m) => axis === "bottom" ? m.m42 : axis === "top" ?
92
101
  var layoutAxis = (axis) => axis === "left" || axis === "right" ? "width" : "height";
93
102
 
94
103
  // src/core/primitives/instance-id.ts
95
- var counters = {};
104
+ var counters = shared("instanceIds", () => ({}));
96
105
  function nextInstanceId(prefix) {
97
106
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
98
107
  return `${prefix}-${crypto.randomUUID()}`;
@@ -120,7 +129,13 @@ function createEventBus() {
120
129
  const set2 = listeners.get(event);
121
130
  if (!set2) return;
122
131
  for (const fn of [...set2]) {
123
- fn(payload);
132
+ try {
133
+ fn(payload);
134
+ } catch (err) {
135
+ queueMicrotask(() => {
136
+ throw err;
137
+ });
138
+ }
124
139
  }
125
140
  },
126
141
  listenerCount(event) {
@@ -132,8 +147,23 @@ function createEventBus() {
132
147
  };
133
148
  }
134
149
 
150
+ // src/core/primitives/dev-warn.ts
151
+ function devWarn(...args) {
152
+ if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
153
+ console.warn(...args);
154
+ }
155
+ }
156
+
135
157
  // src/core/primitives/css-length.ts
136
158
  var probe = null;
159
+ var rejected = /* @__PURE__ */ new Set();
160
+ var warnRejected = (value) => {
161
+ if (rejected.has(value)) return;
162
+ rejected.add(value);
163
+ devWarn(
164
+ `[BottomSheet] snap size "${value}" is not a CSS length the browser accepts \u2014 it resolves to 0.`
165
+ );
166
+ };
137
167
  var PROBE_ATTR = "data-bs-probe";
138
168
  var ensureProbe = (axis) => {
139
169
  if (typeof document === "undefined") return null;
@@ -180,19 +210,14 @@ var resolveSnap = (point, mode, measureFit) => {
180
210
  if (!el) return 0;
181
211
  if (axis === "vertical") {
182
212
  el.style.height = point;
213
+ if (el.style.height === "") warnRejected(point);
183
214
  return Math.max(0, el.getBoundingClientRect().height);
184
215
  }
185
216
  el.style.width = point;
217
+ if (el.style.width === "") warnRejected(point);
186
218
  return Math.max(0, el.getBoundingClientRect().width);
187
219
  };
188
220
 
189
- // src/core/primitives/dev-warn.ts
190
- function devWarn(...args) {
191
- if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
192
- console.warn(...args);
193
- }
194
- }
195
-
196
221
  // src/core/primitives/snap-points.ts
197
222
  var resolveSnapList = (points, mode, measureFit) => points.map((p) => {
198
223
  const raw = resolveSnap(p.size, mode, measureFit);
@@ -204,6 +229,10 @@ var resolveSnapList = (points, mode, measureFit) => points.map((p) => {
204
229
  }
205
230
  return { id: p.id, size: raw };
206
231
  }).sort((a, b) => a.size - b.size);
232
+ var startsClosed = (points, initial, allowed) => {
233
+ const id = initial ?? allowed?.[0] ?? points[0]?.id;
234
+ return points.find((p) => p.id === id)?.size === 0;
235
+ };
207
236
  var VH_NOT_DVH = /(^|[^a-z])vh\b/i;
208
237
  var auditVhUsage = (points) => {
209
238
  for (const p of points) {
@@ -321,6 +350,7 @@ var SnapResolver = class {
321
350
  setMode(mode) {
322
351
  if (mode === this.mode) return;
323
352
  this.mode = mode;
353
+ this.notified = false;
324
354
  this.recompute();
325
355
  }
326
356
  setAllowedIds(ids) {
@@ -330,14 +360,20 @@ var SnapResolver = class {
330
360
  findById(id) {
331
361
  return findById(id, this.resolved);
332
362
  }
333
- findDragSettleTarget(args) {
363
+ findDragSettleTarget(args, openOnly = false) {
334
364
  return findDragSettleTarget({
335
365
  ...args,
336
366
  resolved: this.resolved,
337
- allowed: this.allowedIds,
367
+ allowed: this.pool(openOnly),
338
368
  maxAxisSize: this.maxAxisSize
339
369
  });
340
370
  }
371
+ nearest(size, openOnly) {
372
+ return findNearest(size, this.resolved, this.pool(openOnly));
373
+ }
374
+ pool(openOnly) {
375
+ return openOnly ? this.allowedIds.filter((id) => (this.findById(id)?.size ?? 0) > 0) : this.allowedIds;
376
+ }
341
377
  getAllowedRange() {
342
378
  return this.rangeCache ?? (this.rangeCache = allowedRange(this.resolved, this.allowedIds));
343
379
  }
@@ -385,19 +421,20 @@ var POINTER_EVENTS_OPACITY_THRESHOLD = 0.05;
385
421
  var RANGE_DIVISION_EPSILON = 1e-4;
386
422
 
387
423
  // src/core/features/resize-observer.ts
424
+ var seatOf = (deps) => {
425
+ const snap = deps.resolveActiveSnap();
426
+ const max = deps.getMaxAxisSize();
427
+ return { target: snap ? Math.min(snap.size, max) : null, max };
428
+ };
429
+ 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;
388
430
  function installResizeObserver(deps) {
389
431
  if (typeof window === "undefined") {
390
432
  return () => {
391
433
  };
392
434
  }
393
- const seatFor = () => {
394
- const snap = deps.resolveActiveSnap();
395
- const max = deps.getMaxAxisSize();
396
- return { target: snap ? Math.min(snap.size, max) : null, max };
397
- };
398
435
  const onResize = () => {
399
436
  if (deps.isDestroyed()) return;
400
- const before = seatFor();
437
+ const before = seatOf(deps);
401
438
  deps.recomputeSnaps();
402
439
  const mode = deps.getMode();
403
440
  const isVerticalAxis = mode === "bottom" || mode === "top";
@@ -406,21 +443,8 @@ function installResizeObserver(deps) {
406
443
  if (viewportSize2 > 0 && viewportSize2 < max) {
407
444
  deps.setMaxAxisSize(viewportSize2);
408
445
  }
409
- const after = seatFor();
410
- 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) {
411
- return;
412
- }
413
- const wasAnimating = deps.isAnimating?.() ?? false;
414
- deps.cancelInFlight();
415
- deps.newCycle();
416
- const current = deps.resolveActiveSnap();
417
- const newMax = deps.getMaxAxisSize();
418
- const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
419
- deps.setSize(targetSize);
420
- if (current && !deps.isDragging()) {
421
- deps.applySize(targetSize);
422
- if (wasAnimating) deps.resyncAfterCancel?.();
423
- }
446
+ if (sameSeat(before, seatOf(deps))) return;
447
+ deps.reseat();
424
448
  };
425
449
  let resizeObserver = null;
426
450
  if (typeof ResizeObserver !== "undefined") {
@@ -432,7 +456,7 @@ function installResizeObserver(deps) {
432
456
  window.addEventListener("orientationchange", onResize);
433
457
  const onVisibility = () => {
434
458
  if (deps.isDestroyed()) return;
435
- if (document.hidden) deps.cancelInFlight();
459
+ if (document.hidden) deps.landNow();
436
460
  };
437
461
  document.addEventListener("visibilitychange", onVisibility);
438
462
  return () => {
@@ -457,6 +481,16 @@ var contentTargets = (scroller) => {
457
481
  }
458
482
  return out;
459
483
  };
484
+ var chromeTargets = (deps) => {
485
+ const out = [];
486
+ for (const child2 of Array.from(deps.element.children)) {
487
+ if (child2 !== deps.scrollContainer) out.push(child2);
488
+ }
489
+ if (deps.handle !== deps.element && !out.includes(deps.handle)) {
490
+ out.push(deps.handle);
491
+ }
492
+ return out;
493
+ };
460
494
  function installFitObserver(deps) {
461
495
  if (typeof ResizeObserver === "undefined") return () => {
462
496
  };
@@ -472,7 +506,6 @@ function installFitObserver(deps) {
472
506
  });
473
507
  };
474
508
  const ro = new ResizeObserver(schedule);
475
- ro.observe(deps.handle);
476
509
  const scroller = deps.scrollContainer;
477
510
  const observed = /* @__PURE__ */ new Set();
478
511
  const slots = /* @__PURE__ */ new Set();
@@ -489,7 +522,7 @@ function installFitObserver(deps) {
489
522
  };
490
523
  const resync = () => {
491
524
  trackSlots();
492
- const targets = contentTargets(scroller);
525
+ const targets = [...chromeTargets(deps), ...contentTargets(scroller)];
493
526
  for (const el of observed) {
494
527
  if (!targets.includes(el)) {
495
528
  ro.unobserve(el);
@@ -504,13 +537,12 @@ function installFitObserver(deps) {
504
537
  }
505
538
  schedule();
506
539
  };
540
+ resync();
507
541
  let mo;
508
- if (scroller) {
509
- resync();
510
- if (typeof MutationObserver !== "undefined") {
511
- mo = new MutationObserver(resync);
512
- mo.observe(scroller, { childList: true });
513
- }
542
+ if (typeof MutationObserver !== "undefined") {
543
+ mo = new MutationObserver(resync);
544
+ mo.observe(deps.element, { childList: true });
545
+ if (scroller) mo.observe(scroller, { childList: true });
514
546
  }
515
547
  return () => {
516
548
  ro.disconnect();
@@ -522,6 +554,72 @@ function installFitObserver(deps) {
522
554
  };
523
555
  }
524
556
 
557
+ // src/core/features/teleport.ts
558
+ var resolveTeleportTarget = (target) => {
559
+ if (!target) return null;
560
+ if (typeof target !== "string") return target;
561
+ if (typeof document === "undefined") return null;
562
+ if (target === "body") return document.body;
563
+ return document.querySelector(target);
564
+ };
565
+ var ROOT_CLASS = "bs-root";
566
+ var homes = /* @__PURE__ */ new WeakMap();
567
+ var homeRootOf = (root2) => (root2 && homes.get(root2)) ?? null;
568
+ var mirrorClasses = (home, wrapper) => {
569
+ wrapper.className = home?.className ?? "";
570
+ wrapper.classList.add(ROOT_CLASS);
571
+ };
572
+ var teleportElements = (els, target) => {
573
+ const nodes = els.filter(
574
+ (el) => !!el && el.parentNode !== target
575
+ );
576
+ if (nodes.length === 0) return () => {
577
+ };
578
+ const home = nodes[0].closest(`.${ROOT_CLASS}`);
579
+ if (home && home.parentNode === target) return () => {
580
+ };
581
+ const wrapper = target.ownerDocument.createElement("div");
582
+ wrapper.setAttribute("data-bs-teleported", "");
583
+ mirrorClasses(home, wrapper);
584
+ let watcher = null;
585
+ if (home) {
586
+ for (const name of Array.from(home.style)) {
587
+ if (name.startsWith("--")) {
588
+ wrapper.style.setProperty(name, home.style.getPropertyValue(name));
589
+ }
590
+ }
591
+ homes.set(wrapper, home);
592
+ if (typeof MutationObserver !== "undefined") {
593
+ watcher = new MutationObserver(() => mirrorClasses(home, wrapper));
594
+ watcher.observe(home, { attributes: true, attributeFilter: ["class"] });
595
+ }
596
+ }
597
+ target.appendChild(wrapper);
598
+ const records = [];
599
+ for (const el of nodes) {
600
+ records.push({ el, parent: el.parentNode, next: el.nextSibling });
601
+ wrapper.appendChild(el);
602
+ }
603
+ return () => {
604
+ watcher?.disconnect();
605
+ for (let i = records.length - 1; i >= 0; i--) {
606
+ const { el, parent, next } = records[i];
607
+ if (parent && parent.isConnected) {
608
+ const before = next && next.parentNode === parent ? next : null;
609
+ try {
610
+ parent.insertBefore(el, before);
611
+ } catch {
612
+ el.parentNode?.removeChild(el);
613
+ }
614
+ } else {
615
+ el.parentNode?.removeChild(el);
616
+ }
617
+ }
618
+ homes.delete(wrapper);
619
+ wrapper.parentNode?.removeChild(wrapper);
620
+ };
621
+ };
622
+
525
623
  // src/core/features/max-height-controller.ts
526
624
  function createMaxHeightController(deps) {
527
625
  let maxHeightCap;
@@ -625,8 +723,9 @@ function installSliderKeyboard(deps) {
625
723
  const isVerticalAxis = deps.mode === "bottom" || deps.mode === "top";
626
724
  const stepUp = isVerticalAxis ? "ArrowUp" : "ArrowRight";
627
725
  const stepDown = isVerticalAxis ? "ArrowDown" : "ArrowLeft";
628
- const sheetExpandsKey = deps.mode === "top" ? stepDown : stepUp;
629
- const sheetCollapsesKey = deps.mode === "top" ? stepUp : stepDown;
726
+ const flipped = deps.mode === "top" || deps.mode === "right";
727
+ const sheetExpandsKey = flipped ? stepDown : stepUp;
728
+ const sheetCollapsesKey = flipped ? stepUp : stepDown;
630
729
  const onHandleKey = (e) => {
631
730
  if (deps.isDestroyed()) return;
632
731
  const allowed = deps.getAllowedIds();
@@ -702,11 +801,12 @@ var WriteSentinel = class {
702
801
  // src/core/primitives/overlay-position.ts
703
802
  function resolveSheetAnchoredStyle(mode, position, inset) {
704
803
  const sizeOffset = `calc(var(--bs-size, 0px) + ${inset})`;
804
+ const lifted = `calc(var(--bs-size, 0px) + var(--bs-keyboard-inset, 0px) + ${inset})`;
705
805
  switch (mode) {
706
806
  case "bottom":
707
- if (position === "sheet-top-left") return { bottom: sizeOffset, left: inset };
708
- if (position === "sheet-top-right") return { bottom: sizeOffset, right: inset };
709
- return { bottom: sizeOffset, left: "50%", transform: "translateX(-50%)" };
807
+ if (position === "sheet-top-left") return { bottom: lifted, left: inset };
808
+ if (position === "sheet-top-right") return { bottom: lifted, right: inset };
809
+ return { bottom: lifted, left: "50%", transform: "translateX(-50%)" };
710
810
  case "top":
711
811
  if (position === "sheet-top-left") return { top: sizeOffset, left: inset };
712
812
  if (position === "sheet-top-right") return { top: sizeOffset, right: inset };
@@ -721,6 +821,13 @@ function resolveSheetAnchoredStyle(mode, position, inset) {
721
821
  return { right: sizeOffset, top: "50%", transform: "translateY(-50%)" };
722
822
  }
723
823
  }
824
+ function resetOverlayPosition(ws) {
825
+ ws.top = "";
826
+ ws.bottom = "";
827
+ ws.left = "";
828
+ ws.right = "";
829
+ ws.transform = "";
830
+ }
724
831
  function applyOverlayPosition(ws, mode, position, inset) {
725
832
  switch (position) {
726
833
  case "top-left":
@@ -781,6 +888,8 @@ function applyOverlayPosition(ws, mode, position, inset) {
781
888
  // src/core/controllers/scrim-controller.ts
782
889
  var VALID_CSS_LENGTH = /^-?\d+(?:\.\d+)?(?:px|em|rem|%)$/;
783
890
  var DEFAULT_SCRIM_DIM = "rgba(0, 0, 0, 0.4)";
891
+ var BACKDROP_COLOR_VAR = "--bs-backdrop-color";
892
+ var unit = (value) => Number.isFinite(value) ? Math.min(Math.max(value, 0), 1) : 1;
784
893
  var ScrimController = class {
785
894
  constructor(deps, opts) {
786
895
  __publicField(this, "screenComponent");
@@ -795,11 +904,13 @@ var ScrimController = class {
795
904
  __publicField(this, "scrimMode");
796
905
  __publicField(this, "backdropRange");
797
906
  __publicField(this, "screenRange");
907
+ __publicField(this, "backdropPeak");
798
908
  __publicField(this, "scrimEnabled", true);
799
909
  __publicField(this, "savedScrimRanges", null);
800
910
  __publicField(this, "scrimTapToCloseEnabled", false);
801
911
  __publicField(this, "detachScrimTap", null);
802
912
  __publicField(this, "scrimOverlayTeardown", null);
913
+ __publicField(this, "placeOverlay", null);
803
914
  __publicField(this, "backdropOpacitySentinel", new WriteSentinel());
804
915
  __publicField(this, "screenOpacitySentinel", new WriteSentinel());
805
916
  __publicField(this, "lastBackdropPointer", "");
@@ -816,6 +927,8 @@ var ScrimController = class {
816
927
  const preset = opts.scrimPreset ? SCRIM_PRESETS[opts.scrimPreset] : null;
817
928
  this.backdropRange = opts.backdropRange ?? preset?.range ?? [0, 1];
818
929
  this.screenRange = opts.screenRange ?? preset?.range ?? [0, 1];
930
+ this.backdropPeak = unit(opts.backdropOpacity ?? 1);
931
+ this.setBackdropColor(opts.backdropColor);
819
932
  this.scrimTapToCloseEnabled = opts.scrimTapToClose ?? false;
820
933
  const explicitColor = opts.scrimColor ?? preset?.color;
821
934
  const effectiveColor = explicitColor ?? (this.scrimMode !== "off" && !this.backdrop ? DEFAULT_SCRIM_DIM : void 0);
@@ -845,24 +958,19 @@ var ScrimController = class {
845
958
  this.setScrimTapToClose(true);
846
959
  }
847
960
  }
848
- applyOpacity(progress, progressChanged) {
849
- if (!progressChanged && this.backdropOpacitySentinel.value !== -1 && this.screenOpacitySentinel.value !== -1) {
961
+ applyOpacity(progress, progressChanged, epsilon = OPACITY_WRITE_EPSILON) {
962
+ if (epsilon > 0 && !progressChanged && this.backdropOpacitySentinel.value !== -1 && this.screenOpacitySentinel.value !== -1) {
850
963
  return;
851
964
  }
852
965
  if (this.backdrop) {
853
966
  const [s, e] = this.backdropRange;
854
967
  const range = Math.max(e - s, RANGE_DIVISION_EPSILON);
855
- const backdropOpacity = Math.min(
856
- Math.max((progress - s) / range, 0),
857
- 1
858
- );
859
- if (this.backdropOpacitySentinel.shouldWrite(
860
- backdropOpacity,
861
- OPACITY_WRITE_EPSILON
862
- )) {
968
+ const along = Math.min(Math.max((progress - s) / range, 0), 1);
969
+ const backdropOpacity = along * this.backdropPeak;
970
+ if (this.backdropOpacitySentinel.shouldWrite(backdropOpacity, epsilon)) {
863
971
  this.backdrop.style.opacity = String(backdropOpacity);
864
972
  }
865
- const nextPointer = backdropOpacity > POINTER_EVENTS_OPACITY_THRESHOLD ? "auto" : "none";
973
+ const nextPointer = along > POINTER_EVENTS_OPACITY_THRESHOLD ? "auto" : "none";
866
974
  if (nextPointer !== this.lastBackdropPointer) {
867
975
  this.backdrop.style.pointerEvents = nextPointer;
868
976
  this.lastBackdropPointer = nextPointer;
@@ -877,10 +985,7 @@ var ScrimController = class {
877
985
  (progress - ss) / Math.max(RANGE_DIVISION_EPSILON, se - ss)
878
986
  )
879
987
  );
880
- if (this.screenOpacitySentinel.shouldWrite(
881
- screenOpacity,
882
- OPACITY_WRITE_EPSILON
883
- )) {
988
+ if (this.screenOpacitySentinel.shouldWrite(screenOpacity, epsilon)) {
884
989
  this.screenComponent.style.opacity = String(screenOpacity);
885
990
  }
886
991
  const nextDisplay = screenOpacity > 0 ? "" : "none";
@@ -896,6 +1001,17 @@ var ScrimController = class {
896
1001
  this.invalidateOpacityCache();
897
1002
  applySize();
898
1003
  }
1004
+ setBackdropColor(color) {
1005
+ if (this.isDestroyed() || !this.backdrop) return;
1006
+ if (color) this.backdrop.style.setProperty(BACKDROP_COLOR_VAR, color);
1007
+ else this.backdrop.style.removeProperty(BACKDROP_COLOR_VAR);
1008
+ }
1009
+ setBackdropOpacity(value, applySize) {
1010
+ if (this.isDestroyed()) return;
1011
+ this.backdropPeak = unit(value);
1012
+ this.invalidateOpacityCache();
1013
+ applySize();
1014
+ }
899
1015
  setScreenRange(range, applySize) {
900
1016
  if (this.isDestroyed()) return;
901
1017
  this.screenRange = range;
@@ -918,6 +1034,8 @@ var ScrimController = class {
918
1034
  if (this.isDestroyed() || mode === this.mode) return;
919
1035
  this.mode = mode;
920
1036
  this.invalidateOpacityCache();
1037
+ if (this.scrimMode === "above-sheet") this.applyAboveSheetInset();
1038
+ this.placeOverlay?.();
921
1039
  }
922
1040
  setScrimMode(mode, applySize) {
923
1041
  if (this.isDestroyed()) return;
@@ -930,7 +1048,7 @@ var ScrimController = class {
930
1048
  if (previous === "above-sheet" && mode !== "above-sheet") {
931
1049
  s.position = "";
932
1050
  s.inset = "";
933
- s.pointerEvents = "";
1051
+ this.syncPointer();
934
1052
  }
935
1053
  if (mode === "above-sheet") {
936
1054
  this.applyAboveSheetInset();
@@ -955,9 +1073,6 @@ var ScrimController = class {
955
1073
  if (enabled === installed) return;
956
1074
  if (enabled) {
957
1075
  const target = this.screenComponent;
958
- if (target.style.pointerEvents === "none") {
959
- target.style.pointerEvents = "auto";
960
- }
961
1076
  const onClick = () => {
962
1077
  if (this.isDestroyed()) return;
963
1078
  if (this.closeFn) {
@@ -980,6 +1095,11 @@ var ScrimController = class {
980
1095
  this.detachScrimTap = null;
981
1096
  this.scrimTapToCloseEnabled = false;
982
1097
  }
1098
+ this.syncPointer();
1099
+ }
1100
+ syncPointer() {
1101
+ if (!this.screenComponent) return;
1102
+ this.screenComponent.style.pointerEvents = this.scrimInteractive || this.detachScrimTap ? "auto" : "none";
983
1103
  }
984
1104
  setScrimEnabled(enabled, applySize) {
985
1105
  if (this.isDestroyed()) return;
@@ -1063,8 +1183,12 @@ var ScrimController = class {
1063
1183
  const wrapper = screen.ownerDocument.createElement("div");
1064
1184
  wrapper.className = "bs-scrim-overlay";
1065
1185
  const ws = wrapper.style;
1066
- ws.position = "absolute";
1067
- applyOverlayPosition(ws, this.mode, position, inset);
1186
+ ws.position = "fixed";
1187
+ const place = () => {
1188
+ resetOverlayPosition(ws);
1189
+ applyOverlayPosition(ws, this.mode, position, inset);
1190
+ };
1191
+ place();
1068
1192
  if (interactive) {
1069
1193
  ws.pointerEvents = "auto";
1070
1194
  }
@@ -1078,8 +1202,10 @@ var ScrimController = class {
1078
1202
  };
1079
1203
  }
1080
1204
  host.appendChild(wrapper);
1205
+ this.placeOverlay = place;
1081
1206
  const teardown = () => {
1082
1207
  if (wrapper.parentNode) wrapper.parentNode.removeChild(wrapper);
1208
+ if (this.placeOverlay === place) this.placeOverlay = null;
1083
1209
  if (this.scrimOverlayTeardown === teardown) {
1084
1210
  this.scrimOverlayTeardown = null;
1085
1211
  }
@@ -1103,6 +1229,7 @@ var ScrimController = class {
1103
1229
  if (this.backdrop) {
1104
1230
  this.backdrop.style.opacity = "";
1105
1231
  this.backdrop.style.pointerEvents = "";
1232
+ this.backdrop.style.removeProperty(BACKDROP_COLOR_VAR);
1106
1233
  }
1107
1234
  this.invalidateOpacityCache();
1108
1235
  this.lastBackdropPointer = "";
@@ -1127,13 +1254,13 @@ var ScrimController = class {
1127
1254
  }
1128
1255
  if (opts.interactive !== void 0) {
1129
1256
  this.scrimInteractive = opts.interactive;
1130
- s.pointerEvents = opts.interactive ? "auto" : "none";
1257
+ this.syncPointer();
1131
1258
  }
1132
1259
  }
1133
1260
  applyAboveSheetInset() {
1134
1261
  if (!this.screenComponent) return;
1135
1262
  const insetByMode = {
1136
- bottom: "0 0 var(--bs-size) 0",
1263
+ bottom: "0 0 calc(var(--bs-size) + var(--bs-keyboard-inset, 0px)) 0",
1137
1264
  top: "var(--bs-size) 0 0 0",
1138
1265
  left: "0 0 0 var(--bs-size)",
1139
1266
  right: "0 var(--bs-size) 0 0"
@@ -1141,7 +1268,7 @@ var ScrimController = class {
1141
1268
  const s = this.screenComponent.style;
1142
1269
  s.position = "fixed";
1143
1270
  s.inset = insetByMode[this.mode];
1144
- s.pointerEvents = this.scrimInteractive || this.scrimTapToCloseEnabled ? "auto" : "none";
1271
+ this.syncPointer();
1145
1272
  }
1146
1273
  };
1147
1274
 
@@ -1154,6 +1281,7 @@ var easeOutBack = (t) => {
1154
1281
  var easeOutCubic = (t) => 1 - Math.pow(1 - t, 3);
1155
1282
  var easeLinear = (t) => t;
1156
1283
  var easeOutQuint = (t) => 1 - Math.pow(1 - t, 5);
1284
+ var MIN_RETARGET_MS = 120;
1157
1285
  var tween = ({
1158
1286
  from,
1159
1287
  to,
@@ -1162,12 +1290,18 @@ var tween = ({
1162
1290
  onUpdate
1163
1291
  }) => {
1164
1292
  let cancelled = false;
1293
+ let finished = false;
1165
1294
  let rafId = 0;
1166
1295
  let resolveFn = null;
1167
- const start = performance.now();
1296
+ let start = performance.now();
1297
+ let origin = from;
1298
+ let target = to;
1299
+ let span = duration;
1300
+ let last = from;
1168
1301
  const promise = new Promise((resolve) => {
1169
1302
  resolveFn = resolve;
1170
1303
  if (duration <= 0) {
1304
+ finished = true;
1171
1305
  onUpdate(to);
1172
1306
  resolve();
1173
1307
  return;
@@ -1175,12 +1309,13 @@ var tween = ({
1175
1309
  const step = (now) => {
1176
1310
  if (cancelled) return;
1177
1311
  const elapsed = Math.max(0, now - start);
1178
- const t = Math.min(elapsed / duration, 1);
1179
- const value = from + (to - from) * easing(t);
1180
- onUpdate(value);
1312
+ const t = Math.min(elapsed / span, 1);
1313
+ last = origin + (target - origin) * easing(t);
1314
+ onUpdate(last);
1181
1315
  if (t < 1) {
1182
1316
  rafId = requestAnimationFrame(step);
1183
1317
  } else {
1318
+ finished = true;
1184
1319
  resolve();
1185
1320
  }
1186
1321
  };
@@ -1192,6 +1327,15 @@ var tween = ({
1192
1327
  cancelAnimationFrame(rafId);
1193
1328
  resolveFn?.();
1194
1329
  },
1330
+ retarget: (next) => {
1331
+ if (cancelled || finished || next === target) return;
1332
+ const now = performance.now();
1333
+ const remaining = span - Math.max(0, now - start);
1334
+ origin = last;
1335
+ target = next;
1336
+ start = now;
1337
+ span = Math.max(remaining, MIN_RETARGET_MS);
1338
+ },
1195
1339
  promise
1196
1340
  };
1197
1341
  };
@@ -1209,22 +1353,32 @@ var DEFAULT_SPRING = {
1209
1353
  restSpeed: 0.5
1210
1354
  };
1211
1355
  var MAX_DT = 1 / 30;
1356
+ var MAX_DURATION_MS = 3e3;
1212
1357
  var runSpring = ({
1213
1358
  from,
1214
1359
  to,
1215
1360
  velocity = 0,
1216
1361
  config,
1362
+ maxDuration = MAX_DURATION_MS,
1217
1363
  onUpdate
1218
1364
  }) => {
1219
1365
  const cfg = { ...DEFAULT_SPRING, ...config };
1220
1366
  let cancelled = false;
1367
+ let finished = false;
1221
1368
  let rafId = 0;
1222
1369
  let resolveFn = null;
1223
1370
  let x = from;
1224
1371
  let v = velocity;
1372
+ let target = to;
1225
1373
  let lastTime = performance.now();
1374
+ let deadline = lastTime + maxDuration;
1226
1375
  const promise = new Promise((resolve) => {
1227
1376
  resolveFn = resolve;
1377
+ const land = () => {
1378
+ finished = true;
1379
+ onUpdate(target, 0);
1380
+ resolve();
1381
+ };
1228
1382
  const step = (now) => {
1229
1383
  if (cancelled) return;
1230
1384
  const dt = Math.min(Math.max(0, now - lastTime) / 1e3, MAX_DT);
@@ -1233,21 +1387,19 @@ var runSpring = ({
1233
1387
  const subDt = dt / steps;
1234
1388
  let stepsLeft = steps;
1235
1389
  while (stepsLeft-- > 0) {
1236
- const force = -cfg.stiffness * (x - to) - cfg.damping * v;
1390
+ const force = -cfg.stiffness * (x - target) - cfg.damping * v;
1237
1391
  const accel = force / cfg.mass;
1238
1392
  v += accel * subDt;
1239
1393
  x += v * subDt;
1240
1394
  }
1241
- if (!Number.isFinite(x) || !Number.isFinite(v)) {
1242
- onUpdate(to, 0);
1243
- resolve();
1395
+ if (!Number.isFinite(x) || !Number.isFinite(v) || lastTime >= deadline) {
1396
+ land();
1244
1397
  return;
1245
1398
  }
1246
1399
  onUpdate(x, v);
1247
- const isAtRest = Math.abs(to - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
1400
+ const isAtRest = Math.abs(target - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
1248
1401
  if (isAtRest) {
1249
- onUpdate(to, 0);
1250
- resolve();
1402
+ land();
1251
1403
  } else {
1252
1404
  rafId = requestAnimationFrame(step);
1253
1405
  }
@@ -1260,6 +1412,11 @@ var runSpring = ({
1260
1412
  cancelAnimationFrame(rafId);
1261
1413
  resolveFn?.();
1262
1414
  },
1415
+ retarget: (next) => {
1416
+ if (cancelled || finished) return;
1417
+ target = next;
1418
+ deadline = performance.now() + maxDuration;
1419
+ },
1263
1420
  promise
1264
1421
  };
1265
1422
  };
@@ -1411,21 +1568,40 @@ var AnimationRunner = class {
1411
1568
  this.applySizeFn(size);
1412
1569
  }
1413
1570
  cancel() {
1414
- this.currentTween?.cancel();
1415
- this.currentSpring?.cancel();
1571
+ const tween2 = this.currentTween;
1572
+ const spring = this.currentSpring;
1573
+ this.currentTween = null;
1574
+ this.currentSpring = null;
1575
+ tween2?.cancel();
1576
+ spring?.cancel();
1416
1577
  this.cancelWaapi();
1417
1578
  }
1579
+ retarget(target) {
1580
+ if (this.currentSpring) {
1581
+ this.currentSpring.retarget(target);
1582
+ return true;
1583
+ }
1584
+ if (this.currentTween) {
1585
+ this.currentTween.retarget(target);
1586
+ return true;
1587
+ }
1588
+ if (this.currentWaapi) {
1589
+ this.currentWaapi.retarget(target);
1590
+ return true;
1591
+ }
1592
+ return false;
1593
+ }
1418
1594
  async animateTo(target, velocityPxPerMs) {
1419
1595
  if (target === this.getSize()) {
1420
- if (!this.isAnimating && !this.isDragging()) {
1596
+ if (this.isAnimating) this.cancel();
1597
+ if (!this.isDragging()) {
1421
1598
  this.applySizeFn(target);
1599
+ this.getRootEl()?.removeAttribute("data-animating");
1422
1600
  this.element.style.willChange = "";
1423
1601
  }
1424
1602
  return;
1425
1603
  }
1426
- this.currentTween?.cancel();
1427
- this.currentSpring?.cancel();
1428
- this.cancelWaapi();
1604
+ this.cancel();
1429
1605
  this.getRootEl()?.setAttribute("data-animating", "true");
1430
1606
  this.element.style.willChange = "transform";
1431
1607
  if (this.reducedMotion) {
@@ -1435,19 +1611,13 @@ var AnimationRunner = class {
1435
1611
  return;
1436
1612
  }
1437
1613
  if (this.settleWaapi && this.applyAux && this.getTransformFor && typeof this.element.animate === "function") {
1438
- const samples = this.animationKind === "spring" ? sampleSpringSettle(
1439
- this.getSize(),
1440
- target,
1441
- velocityPxPerMs * VELOCITY_PX_PER_S,
1442
- this.springConfig
1443
- ) : sampleTweenSettle(
1614
+ const samples = this.sampleSettle(
1444
1615
  this.getSize(),
1445
1616
  target,
1446
- this.duration,
1447
- this.easing
1617
+ velocityPxPerMs * VELOCITY_PX_PER_S
1448
1618
  );
1449
1619
  if (samples.values.length >= 2 && samples.durationMs > 0) {
1450
- await this.runWaapiSettle(samples, target);
1620
+ await this.runWaapiSettle({ samples, target });
1451
1621
  if (!this.isAnimating) {
1452
1622
  this.getRootEl()?.removeAttribute("data-animating");
1453
1623
  if (!this.isDragging()) this.element.style.willChange = "";
@@ -1489,7 +1659,10 @@ var AnimationRunner = class {
1489
1659
  }
1490
1660
  }
1491
1661
  }
1492
- async runWaapiSettle(samples, target) {
1662
+ sampleSettle(from, to, velocityPxPerS) {
1663
+ return this.animationKind === "spring" ? sampleSpringSettle(from, to, velocityPxPerS, this.springConfig) : sampleTweenSettle(from, to, this.duration, this.easing);
1664
+ }
1665
+ startWaapiLeg(samples, onRetarget) {
1493
1666
  const applyAux = this.applyAux;
1494
1667
  const getTransformFor = this.getTransformFor;
1495
1668
  const frames = samples.values.map((v) => ({
@@ -1504,16 +1677,20 @@ var AnimationRunner = class {
1504
1677
  let stopped = false;
1505
1678
  let auxRaf = 0;
1506
1679
  const lastIdx = samples.values.length - 1;
1680
+ const cursor = () => Math.min((Number(anim.currentTime) || 0) / samples.stepMs, lastIdx);
1507
1681
  const sizeNow = () => {
1508
- const at = Math.min(
1509
- (Number(anim.currentTime) || 0) / samples.stepMs,
1510
- lastIdx
1511
- );
1682
+ const at = cursor();
1512
1683
  const idx = Math.floor(at);
1513
1684
  const from = samples.values[idx];
1514
1685
  const to = samples.values[Math.min(idx + 1, lastIdx)];
1515
1686
  return from + (to - from) * (at - idx);
1516
1687
  };
1688
+ const velocityNow = () => {
1689
+ const idx = Math.min(Math.floor(cursor()), Math.max(lastIdx - 1, 0));
1690
+ const from = samples.values[idx];
1691
+ const to = samples.values[Math.min(idx + 1, lastIdx)];
1692
+ return (to - from) / samples.stepMs * 1e3;
1693
+ };
1517
1694
  const auxTick = () => {
1518
1695
  if (stopped) return;
1519
1696
  applyAux(sizeNow());
@@ -1526,22 +1703,55 @@ var AnimationRunner = class {
1526
1703
  stopped = true;
1527
1704
  cancelAnimationFrame(auxRaf);
1528
1705
  },
1529
- sizeNow
1706
+ sizeNow,
1707
+ velocityNow,
1708
+ retarget: (to) => onRetarget(entry, to)
1530
1709
  };
1531
- this.currentWaapi = entry;
1532
- try {
1533
- await anim.finished;
1534
- } catch {
1535
- }
1536
- entry.stop();
1537
- const wasCurrent = this.currentWaapi === entry;
1538
- if (wasCurrent) this.currentWaapi = null;
1539
- if (wasCurrent && anim.playState === "finished") {
1540
- this.applySizeFn(target);
1710
+ return entry;
1711
+ }
1712
+ async runWaapiSettle(first) {
1713
+ let leg = first;
1714
+ for (; ; ) {
1715
+ let queued = null;
1716
+ const entry = this.startWaapiLeg(leg.samples, (running, to) => {
1717
+ const size = this.readShownSize?.() ?? running.sizeNow();
1718
+ queued = {
1719
+ samples: this.sampleSettle(size, to, running.velocityNow()),
1720
+ target: to
1721
+ };
1722
+ running.stop();
1723
+ try {
1724
+ running.anim.cancel();
1725
+ } catch {
1726
+ }
1727
+ this.applySizeFn(size);
1728
+ });
1729
+ this.currentWaapi = entry;
1541
1730
  try {
1542
- anim.cancel();
1731
+ await entry.anim.finished;
1543
1732
  } catch {
1544
1733
  }
1734
+ entry.stop();
1735
+ const wasCurrent = this.currentWaapi === entry;
1736
+ const next = queued;
1737
+ if (wasCurrent && next) {
1738
+ if (next.samples.values.length >= 2 && next.samples.durationMs > 0) {
1739
+ leg = next;
1740
+ continue;
1741
+ }
1742
+ this.currentWaapi = null;
1743
+ this.applySizeFn(next.target);
1744
+ return;
1745
+ }
1746
+ if (wasCurrent) this.currentWaapi = null;
1747
+ if (wasCurrent && entry.anim.playState === "finished") {
1748
+ this.applySizeFn(leg.target);
1749
+ try {
1750
+ entry.anim.cancel();
1751
+ } catch {
1752
+ }
1753
+ }
1754
+ return;
1545
1755
  }
1546
1756
  }
1547
1757
  destroy() {
@@ -1596,27 +1806,51 @@ var collectFocusables = (root2) => {
1596
1806
  var focusables = (root2) => collectFocusables(root2).filter(
1597
1807
  (el) => !el.hasAttribute("inert") && isVisible(el) && !el.matches("[aria-hidden='true']")
1598
1808
  );
1809
+ var findDeep = (root2, selector) => {
1810
+ const direct = root2.querySelector(selector);
1811
+ if (direct || typeof HTMLSlotElement === "undefined") return direct;
1812
+ for (const slot of Array.from(root2.querySelectorAll("slot"))) {
1813
+ for (const assigned of slot.assignedElements()) {
1814
+ if (assigned.matches(selector)) return assigned;
1815
+ const inner = findDeep(assigned, selector);
1816
+ if (inner) return inner;
1817
+ }
1818
+ }
1819
+ return null;
1820
+ };
1821
+ var FOCUS_ALLOW_ATTR = "data-bs-focus-allow";
1822
+ var composedParent = (node) => {
1823
+ const slot = node.assignedSlot;
1824
+ if (slot) return slot;
1825
+ const parent = node.parentNode;
1826
+ return parent instanceof ShadowRoot ? parent.host : parent;
1827
+ };
1599
1828
  var containsComposed = (container, node) => {
1600
- let n = node;
1601
- while (n) {
1829
+ for (let n = node; n; n = composedParent(n)) {
1602
1830
  if (n === container) return true;
1603
- const slot = n.assignedSlot;
1604
- if (slot) {
1605
- n = slot;
1606
- continue;
1607
- }
1608
- const parent = n.parentNode;
1609
- n = parent instanceof ShadowRoot ? parent.host : parent;
1610
1831
  }
1611
1832
  return false;
1612
1833
  };
1613
- var trapStack = [];
1834
+ var isAllowedOutside = (node) => {
1835
+ for (let n = node; n; n = composedParent(n)) {
1836
+ if (n instanceof Element && n.hasAttribute(FOCUS_ALLOW_ATTR)) return true;
1837
+ }
1838
+ return false;
1839
+ };
1840
+ var deepActiveElement = () => {
1841
+ let active = document.activeElement;
1842
+ while (active?.shadowRoot?.activeElement) {
1843
+ active = active.shadowRoot.activeElement;
1844
+ }
1845
+ return active;
1846
+ };
1847
+ var trapStack = shared("focusTraps", () => []);
1614
1848
  var installFocusTrap = (container, options = {}) => {
1615
1849
  if (typeof document === "undefined") return () => {
1616
1850
  };
1617
1851
  const token = {};
1618
- trapStack.push(token);
1619
- const isActive = () => trapStack[trapStack.length - 1] === token;
1852
+ if (!options.isActive) trapStack.push(token);
1853
+ const isActive = options.isActive ?? (() => trapStack[trapStack.length - 1] === token);
1620
1854
  const previouslyFocused = document.activeElement;
1621
1855
  const focusInitial = () => {
1622
1856
  const spec = options.initialFocus;
@@ -1625,10 +1859,11 @@ var installFocusTrap = (container, options = {}) => {
1625
1859
  container.focus({ preventScroll: true });
1626
1860
  return;
1627
1861
  }
1628
- const initial = typeof spec === "string" ? container.querySelector(spec) : spec ?? focusables(container)[0] ?? container;
1862
+ const initial = typeof spec === "string" ? findDeep(container, spec) : spec ?? focusables(container)[0] ?? container;
1629
1863
  initial?.focus({ preventScroll: true });
1630
1864
  };
1631
- focusInitial();
1865
+ if (!containsComposed(container, deepActiveElement())) focusInitial();
1866
+ let backwards = false;
1632
1867
  const handleKey = (e) => {
1633
1868
  if (!isActive()) return;
1634
1869
  if (e.key === "Escape" && options.onEscape) {
@@ -1636,6 +1871,10 @@ var installFocusTrap = (container, options = {}) => {
1636
1871
  return;
1637
1872
  }
1638
1873
  if (e.key !== "Tab") return;
1874
+ backwards = e.shiftKey;
1875
+ setTimeout(() => {
1876
+ backwards = false;
1877
+ }, 0);
1639
1878
  const list = focusables(container);
1640
1879
  if (list.length === 0) {
1641
1880
  e.preventDefault();
@@ -1643,7 +1882,7 @@ var installFocusTrap = (container, options = {}) => {
1643
1882
  }
1644
1883
  const first = list[0];
1645
1884
  const last = list[list.length - 1];
1646
- const active = document.activeElement;
1885
+ const active = deepActiveElement();
1647
1886
  if (e.shiftKey && active === first) {
1648
1887
  e.preventDefault();
1649
1888
  last.focus();
@@ -1654,11 +1893,11 @@ var installFocusTrap = (container, options = {}) => {
1654
1893
  };
1655
1894
  const handleFocusIn = (e) => {
1656
1895
  if (!isActive()) return;
1657
- const target = e.target;
1658
- if (target && !containsComposed(container, target)) {
1659
- const list = focusables(container);
1660
- list[0]?.focus({ preventScroll: true });
1661
- }
1896
+ const target = e.composedPath()[0] ?? e.target;
1897
+ if (!target || containsComposed(container, target)) return;
1898
+ if (isAllowedOutside(target)) return;
1899
+ const list = focusables(container);
1900
+ list[backwards ? list.length - 1 : 0]?.focus({ preventScroll: true });
1662
1901
  };
1663
1902
  document.addEventListener("keydown", handleKey, true);
1664
1903
  document.addEventListener("focusin", handleFocusIn, true);
@@ -1680,21 +1919,25 @@ var installFocusTrap = (container, options = {}) => {
1680
1919
  };
1681
1920
 
1682
1921
  // src/core/lifecycle/scroll-lock.ts
1683
- var lockCount = 0;
1684
- var savedStyles = null;
1922
+ var state = shared("scrollLock", () => ({
1923
+ count: 0,
1924
+ saved: null
1925
+ }));
1685
1926
  var lockBodyScroll = () => {
1686
1927
  if (typeof document === "undefined") return () => {
1687
1928
  };
1688
- if (lockCount === 0) {
1929
+ if (state.count === 0) {
1689
1930
  const body = document.body;
1690
- savedStyles = {
1931
+ const saved = {
1691
1932
  overflow: body.style.overflow,
1692
1933
  position: body.style.position,
1693
1934
  top: body.style.top,
1694
1935
  width: body.style.width,
1695
1936
  paddingRight: body.style.paddingRight,
1937
+ scrollX: window.scrollX,
1696
1938
  scrollY: window.scrollY
1697
1939
  };
1940
+ state.saved = saved;
1698
1941
  const scrollbarGap = window.innerWidth - document.documentElement.clientWidth;
1699
1942
  if (scrollbarGap > 0) {
1700
1943
  const current = parseFloat(getComputedStyle(body).paddingRight) || 0;
@@ -1702,53 +1945,72 @@ var lockBodyScroll = () => {
1702
1945
  }
1703
1946
  body.style.overflow = "hidden";
1704
1947
  body.style.position = "fixed";
1705
- body.style.top = `-${savedStyles.scrollY}px`;
1948
+ body.style.top = `-${saved.scrollY}px`;
1706
1949
  body.style.width = "100%";
1707
1950
  }
1708
- lockCount++;
1951
+ state.count++;
1709
1952
  let released = false;
1710
1953
  return () => {
1711
1954
  if (released) return;
1712
1955
  released = true;
1713
- lockCount = Math.max(0, lockCount - 1);
1714
- if (lockCount === 0 && savedStyles) {
1956
+ state.count = Math.max(0, state.count - 1);
1957
+ if (state.count === 0 && state.saved) {
1715
1958
  const body = document.body;
1716
- body.style.overflow = savedStyles.overflow;
1717
- body.style.position = savedStyles.position;
1718
- body.style.top = savedStyles.top;
1719
- body.style.width = savedStyles.width;
1720
- body.style.paddingRight = savedStyles.paddingRight;
1721
- window.scrollTo(0, savedStyles.scrollY);
1722
- savedStyles = null;
1959
+ const saved = state.saved;
1960
+ body.style.overflow = saved.overflow;
1961
+ body.style.position = saved.position;
1962
+ body.style.top = saved.top;
1963
+ body.style.width = saved.width;
1964
+ body.style.paddingRight = saved.paddingRight;
1965
+ window.scrollTo({
1966
+ top: saved.scrollY,
1967
+ left: saved.scrollX,
1968
+ behavior: "instant"
1969
+ });
1970
+ state.saved = null;
1723
1971
  }
1724
1972
  };
1725
1973
  };
1726
1974
 
1727
1975
  // src/core/features/inert-siblings.ts
1976
+ var OWN_ROOTS = ".bs-root, .ovl-root";
1977
+ var LAYER_CLASSES = [
1978
+ "bs-backdrop",
1979
+ "bs-screen",
1980
+ "bs-root",
1981
+ "ovl-backdrop",
1982
+ "ovl-root"
1983
+ ];
1984
+ var isLayer = (el) => LAYER_CLASSES.some((name) => el.classList.contains(name));
1728
1985
  function createInertSiblings(rootProvider) {
1729
1986
  const tracked = [];
1987
+ const remove = () => {
1988
+ for (const el of tracked) el.removeAttribute("inert");
1989
+ tracked.length = 0;
1990
+ };
1730
1991
  return {
1731
1992
  apply() {
1732
1993
  if (typeof document === "undefined") return;
1733
- let top = rootProvider();
1734
- while (top.parentElement && top.parentElement !== document.body) {
1735
- top = top.parentElement;
1736
- }
1737
- const parent = top.parentElement ?? document.body;
1738
- for (const child2 of Array.from(parent.children)) {
1739
- if (child2 === top) continue;
1740
- if (child2.hasAttribute("inert")) continue;
1741
- if (child2.classList.contains("bs-backdrop") || child2.classList.contains("bs-screen") || child2.classList.contains("bs-root")) {
1994
+ remove();
1995
+ const surface = rootProvider();
1996
+ let node = surface.closest(OWN_ROOTS) ?? surface;
1997
+ while (node && node !== document.body) {
1998
+ const parent = node.parentElement;
1999
+ if (!parent) {
2000
+ const root2 = node.getRootNode();
2001
+ node = typeof ShadowRoot !== "undefined" && root2 instanceof ShadowRoot ? root2.host : null;
1742
2002
  continue;
1743
2003
  }
1744
- child2.setAttribute("inert", "");
1745
- tracked.push(child2);
2004
+ for (const sibling2 of Array.from(parent.children)) {
2005
+ if (sibling2 === node) continue;
2006
+ if (sibling2.hasAttribute("inert") || isLayer(sibling2)) continue;
2007
+ sibling2.setAttribute("inert", "");
2008
+ tracked.push(sibling2);
2009
+ }
2010
+ node = parent;
1746
2011
  }
1747
2012
  },
1748
- remove() {
1749
- for (const el of tracked) el.removeAttribute("inert");
1750
- tracked.length = 0;
1751
- }
2013
+ remove
1752
2014
  };
1753
2015
  }
1754
2016
 
@@ -1756,6 +2018,7 @@ function createInertSiblings(rootProvider) {
1756
2018
  var LifecycleController = class {
1757
2019
  constructor(deps, opts) {
1758
2020
  __publicField(this, "element");
2021
+ __publicField(this, "isTop");
1759
2022
  __publicField(this, "focusTrapEnabled");
1760
2023
  __publicField(this, "initialFocus");
1761
2024
  __publicField(this, "closeOnEscape");
@@ -1769,6 +2032,7 @@ var LifecycleController = class {
1769
2032
  __publicField(this, "installed", false);
1770
2033
  __publicField(this, "destroyed", false);
1771
2034
  this.element = deps.element;
2035
+ this.isTop = deps.isTop;
1772
2036
  this.focusTrapEnabled = opts.focusTrap ?? false;
1773
2037
  this.initialFocus = opts.initialFocus;
1774
2038
  this.closeOnEscape = opts.closeOnEscape ?? true;
@@ -1789,12 +2053,17 @@ var LifecycleController = class {
1789
2053
  }
1790
2054
  if (this.focusTrapEnabled && !this.releaseFocusTrap) {
1791
2055
  this.releaseFocusTrap = installFocusTrap(this.element, {
1792
- initialFocus: this.initialFocus
2056
+ initialFocus: this.initialFocus,
2057
+ isActive: this.isTop
1793
2058
  });
1794
2059
  }
1795
- if (this.inertSiblingsEnabled && this.shouldApplyInertSiblings()) {
1796
- this.inertSiblings.apply();
1797
- }
2060
+ this.syncTop();
2061
+ }
2062
+ syncTop() {
2063
+ if (!this.installed || !this.inertSiblingsEnabled) return;
2064
+ if (!this.shouldApplyInertSiblings()) return;
2065
+ if (this.isTop?.() ?? true) this.inertSiblings.apply();
2066
+ else this.inertSiblings.remove();
1798
2067
  }
1799
2068
  setReturnFocus(target) {
1800
2069
  if (this.destroyed) return;
@@ -1964,10 +2233,14 @@ var installGestures = (handle, mode, callbacks, options = {}) => {
1964
2233
  if (wasPending) return;
1965
2234
  callbacks.onCancel?.();
1966
2235
  };
2236
+ const onLostCapture = (e) => {
2237
+ if (e.target === handle) onPointerCancel(e);
2238
+ };
1967
2239
  handle.addEventListener("pointerdown", onPointerDown);
1968
2240
  handle.addEventListener("pointermove", onPointerMove);
1969
2241
  handle.addEventListener("pointerup", finishGesture);
1970
2242
  handle.addEventListener("pointercancel", onPointerCancel);
2243
+ handle.addEventListener("lostpointercapture", onLostCapture);
1971
2244
  const managesTouchAction = options.manageTouchAction !== false;
1972
2245
  const prevTouchAction = handle.style.touchAction;
1973
2246
  if (managesTouchAction) {
@@ -1978,6 +2251,7 @@ var installGestures = (handle, mode, callbacks, options = {}) => {
1978
2251
  handle.removeEventListener("pointermove", onPointerMove);
1979
2252
  handle.removeEventListener("pointerup", finishGesture);
1980
2253
  handle.removeEventListener("pointercancel", onPointerCancel);
2254
+ handle.removeEventListener("lostpointercapture", onLostCapture);
1981
2255
  if (managesTouchAction) handle.style.touchAction = prevTouchAction;
1982
2256
  if (activePointerId !== null && handle.hasPointerCapture(activePointerId)) {
1983
2257
  handle.releasePointerCapture(activePointerId);
@@ -2094,8 +2368,7 @@ var GestureController = class {
2094
2368
  size: this.deps.getDragContext().size,
2095
2369
  velocity: 0
2096
2370
  });
2097
- const restoreTo = this.dragStartSize;
2098
- void this.deps.animateTo(restoreTo, 0);
2371
+ this.deps.restoreAfterDrag();
2099
2372
  }
2100
2373
  }, this.deps.gestureOptions);
2101
2374
  return this.detach;
@@ -2160,6 +2433,11 @@ var readDirection = (el) => {
2160
2433
  }
2161
2434
  return "ltr";
2162
2435
  };
2436
+ var guessPhysicalMode = (mode) => {
2437
+ if (mode === "start") return "left";
2438
+ if (mode === "end") return "right";
2439
+ return mode ?? "bottom";
2440
+ };
2163
2441
  var resolveMode = (mode, el) => {
2164
2442
  if (!isLogicalMode(mode)) return mode;
2165
2443
  const rtl = readDirection(el) === "rtl";
@@ -2212,22 +2490,24 @@ function createScrollCache(deps) {
2212
2490
  return size < max / 2;
2213
2491
  };
2214
2492
  return {
2215
- cache(fromId, prevSize, nextSize) {
2493
+ leave(fromId, prevSize, nextSize) {
2216
2494
  const container = deps.scrollContainer;
2217
2495
  if (!container) return;
2218
- if (isSmallSize(prevSize)) return;
2219
- if (!isSmallSize(nextSize)) return;
2496
+ if (nextSize <= 0) {
2497
+ positions.clear();
2498
+ return;
2499
+ }
2500
+ if (isSmallSize(prevSize) || !isSmallSize(nextSize)) return;
2220
2501
  positions.set(fromId, container.scrollTop);
2221
2502
  },
2222
- restore(toId, prevSize, nextSize) {
2503
+ enter(toId, prevSize, nextSize) {
2223
2504
  const container = deps.scrollContainer;
2224
2505
  if (!container) return;
2225
- if (isSmallSize(nextSize)) return;
2226
- if (!isSmallSize(prevSize)) return;
2506
+ if (isSmallSize(nextSize) || !isSmallSize(prevSize)) return;
2227
2507
  const cached = positions.get(toId);
2228
2508
  if (cached === void 0) return;
2229
- container.scrollTop = cached;
2230
2509
  positions.delete(toId);
2510
+ container.scrollTop = cached;
2231
2511
  },
2232
2512
  clear() {
2233
2513
  positions.clear();
@@ -2341,17 +2621,18 @@ function attachAnchor(deps, opts) {
2341
2621
  const isDock = position === "dock-bottom" || position === "dock-top";
2342
2622
  const ws = wrapper.style;
2343
2623
  ws.position = "fixed";
2344
- if (isDock) {
2624
+ const place = () => {
2625
+ resetOverlayPosition(ws);
2626
+ if (!isDock) {
2627
+ applyOverlayPosition(ws, deps.getMode(), position, opts.inset ?? "16px");
2628
+ return;
2629
+ }
2345
2630
  ws.left = "0";
2346
2631
  ws.right = "0";
2347
- if (position === "dock-bottom") {
2348
- ws.bottom = "0";
2349
- } else {
2350
- ws.top = "0";
2351
- }
2352
- } else {
2353
- applyOverlayPosition(ws, deps.mode, position, opts.inset ?? "16px");
2354
- }
2632
+ if (position === "dock-bottom") ws.bottom = "0";
2633
+ else ws.top = "0";
2634
+ };
2635
+ place();
2355
2636
  if (opts.fadeRange) {
2356
2637
  const [r0, r1] = opts.fadeRange;
2357
2638
  const span = Math.max(r1 - r0, 1e-4);
@@ -2361,10 +2642,10 @@ function attachAnchor(deps, opts) {
2361
2642
  deps.host.appendChild(wrapper);
2362
2643
  let visible = null;
2363
2644
  let inFlight = null;
2364
- const shouldShow = (state2) => {
2365
- if (typeof opts.showOn === "function") return opts.showOn(state2);
2366
- if (Array.isArray(opts.showOn)) return opts.showOn.includes(state2.activeId);
2367
- return isDock || state2.size > 0;
2645
+ const shouldShow = (state4) => {
2646
+ if (typeof opts.showOn === "function") return opts.showOn(state4);
2647
+ if (Array.isArray(opts.showOn)) return opts.showOn.includes(state4.activeId);
2648
+ return isDock || state4.size > 0;
2368
2649
  };
2369
2650
  const applyVisibility = (next, animate) => {
2370
2651
  if (next === visible) return;
@@ -2411,7 +2692,8 @@ function attachAnchor(deps, opts) {
2411
2692
  },
2412
2693
  syncZ: (z) => {
2413
2694
  wrapper.style.zIndex = String(z);
2414
- }
2695
+ },
2696
+ reposition: place
2415
2697
  };
2416
2698
  }
2417
2699
 
@@ -2427,30 +2709,37 @@ var matchesRange = (def, progress) => {
2427
2709
  };
2428
2710
  function installScrimStages(deps, opts) {
2429
2711
  const doc = deps.host.ownerDocument;
2430
- const entries2 = opts.stages.map((def) => {
2712
+ const entries = opts.stages.map((def) => {
2431
2713
  const wrapper = doc.createElement("div");
2432
2714
  wrapper.className = "bs-scrim-stage";
2433
2715
  const ws = wrapper.style;
2434
- ws.position = "absolute";
2435
- applyOverlayPosition(
2436
- ws,
2437
- deps.mode,
2438
- def.position ?? opts.position ?? "center",
2439
- def.inset ?? opts.inset ?? "16px"
2440
- );
2716
+ ws.position = "fixed";
2441
2717
  ws.visibility = "hidden";
2442
2718
  ws.pointerEvents = "none";
2443
2719
  wrapper.appendChild(def.element);
2444
2720
  deps.host.appendChild(wrapper);
2445
2721
  return { def, wrapper, inFlight: null };
2446
2722
  });
2723
+ const place = () => {
2724
+ for (const entry of entries) {
2725
+ const ws = entry.wrapper.style;
2726
+ resetOverlayPosition(ws);
2727
+ applyOverlayPosition(
2728
+ ws,
2729
+ deps.getMode(),
2730
+ entry.def.position ?? opts.position ?? "center",
2731
+ entry.def.inset ?? opts.inset ?? "16px"
2732
+ );
2733
+ }
2734
+ };
2735
+ place();
2447
2736
  let active = null;
2448
2737
  const resolveActive = () => {
2449
- const state2 = deps.getState();
2450
- if (state2.size === 0) {
2451
- return entries2.find((e) => matchesId(e.def, state2.activeId)) ?? null;
2738
+ const state4 = deps.getState();
2739
+ if (state4.size === 0) {
2740
+ return entries.find((e) => matchesId(e.def, state4.activeId)) ?? null;
2452
2741
  }
2453
- return entries2.find((e) => matchesId(e.def, state2.activeId)) ?? entries2.find((e) => matchesRange(e.def, state2.progress)) ?? null;
2742
+ return entries.find((e) => matchesId(e.def, state4.activeId)) ?? entries.find((e) => matchesRange(e.def, state4.progress)) ?? null;
2454
2743
  };
2455
2744
  const hide = (entry, animate) => {
2456
2745
  entry.inFlight?.cancel();
@@ -2499,20 +2788,23 @@ function installScrimStages(deps, opts) {
2499
2788
  deps.on("open", () => update(true)),
2500
2789
  deps.on("close", () => update(true))
2501
2790
  ];
2502
- if (entries2.some((e) => e.def.forRange)) {
2791
+ if (entries.some((e) => e.def.forRange)) {
2503
2792
  offs.push(deps.on("progress", () => update(true)));
2504
2793
  }
2505
2794
  update(false);
2506
- return () => {
2507
- offs.forEach((off) => off());
2508
- for (const entry of entries2) {
2509
- entry.inFlight?.cancel();
2510
- entry.inFlight = null;
2511
- if (entry.wrapper.parentNode) {
2512
- entry.wrapper.parentNode.removeChild(entry.wrapper);
2795
+ return {
2796
+ reposition: place,
2797
+ detach: () => {
2798
+ offs.forEach((off) => off());
2799
+ for (const entry of entries) {
2800
+ entry.inFlight?.cancel();
2801
+ entry.inFlight = null;
2802
+ if (entry.wrapper.parentNode) {
2803
+ entry.wrapper.parentNode.removeChild(entry.wrapper);
2804
+ }
2513
2805
  }
2806
+ active = null;
2514
2807
  }
2515
- active = null;
2516
2808
  };
2517
2809
  }
2518
2810
 
@@ -2548,11 +2840,13 @@ function resolveEngineOptions(opts, extras) {
2548
2840
  scrimMode: opts.scrimMode,
2549
2841
  scrimColor: opts.scrimColor,
2550
2842
  scrimBlur: opts.scrimBlur,
2551
- scrimInteractive: opts.scrimInteractive ?? (opts.scrimTapToClose ? true : void 0),
2843
+ scrimInteractive: opts.scrimInteractive,
2552
2844
  scrimTapToClose: opts.scrimTapToClose,
2553
2845
  scrimPreset: opts.scrimPreset,
2554
2846
  screenRange: opts.screenRange,
2555
- backdropRange: opts.backdropRange
2847
+ backdropRange: opts.backdropRange,
2848
+ backdropOpacity: opts.backdropOpacity,
2849
+ backdropColor: opts.backdropColor
2556
2850
  },
2557
2851
  animation: {
2558
2852
  animation: opts.animation,
@@ -2631,6 +2925,7 @@ var BottomSheetCore = class {
2631
2925
  __publicField(this, "fitContentToSnap");
2632
2926
  __publicField(this, "settleAnimation");
2633
2927
  __publicField(this, "persistent");
2928
+ __publicField(this, "keyboardInset", 0);
2634
2929
  __publicField(this, "disableCloseFlag");
2635
2930
  __publicField(this, "disableDragFlag");
2636
2931
  __publicField(this, "closeOnRouteChange");
@@ -2645,6 +2940,7 @@ var BottomSheetCore = class {
2645
2940
  __publicField(this, "detachSheetGesture", null);
2646
2941
  __publicField(this, "detachSliderKeyboard", null);
2647
2942
  __publicField(this, "rootEl", null);
2943
+ __publicField(this, "homeRoot", null);
2648
2944
  __publicField(this, "destroyed", false);
2649
2945
  __publicField(this, "restClosed", false);
2650
2946
  __publicField(this, "currentViewTransition", null);
@@ -2652,8 +2948,13 @@ var BottomSheetCore = class {
2652
2948
  __publicField(this, "sizeWriteSentinel", new WriteSentinel());
2653
2949
  __publicField(this, "progressWriteSentinel", new WriteSentinel());
2654
2950
  __publicField(this, "isTopSheet", true);
2655
- __publicField(this, "opening", false);
2656
- __publicField(this, "promotedForOpen", false);
2951
+ __publicField(this, "phase", "closed");
2952
+ __publicField(this, "transition", null);
2953
+ __publicField(this, "inFlight", null);
2954
+ __publicField(this, "outbox", []);
2955
+ __publicField(this, "flushing", false);
2956
+ __publicField(this, "openPending", false);
2957
+ __publicField(this, "settleHolds", []);
2657
2958
  __publicField(this, "allowOvershoot", false);
2658
2959
  __publicField(this, "progressPayload", {
2659
2960
  value: 0,
@@ -2674,6 +2975,7 @@ var BottomSheetCore = class {
2674
2975
  __publicField(this, "anchorHost", null);
2675
2976
  __publicField(this, "stackZ", 100);
2676
2977
  __publicField(this, "detachScrimStages", null);
2978
+ __publicField(this, "placeScrimStages", null);
2677
2979
  __publicField(this, "stackEffectEnabled", false);
2678
2980
  __publicField(this, "stackEffectPrimed", false);
2679
2981
  __publicField(this, "fitDeps");
@@ -2681,13 +2983,7 @@ var BottomSheetCore = class {
2681
2983
  __publicField(this, "featureList", []);
2682
2984
  __publicField(this, "featureCtx");
2683
2985
  const resolved = resolveEngineOptions(opts, {
2684
- shouldApplyInertSiblings: () => {
2685
- if (typeof document === "undefined") return false;
2686
- const bodyChildren = Array.from(document.body.children);
2687
- return bodyChildren.some(
2688
- (c) => c === opts.element || c.contains(opts.element)
2689
- );
2690
- }
2986
+ shouldApplyInertSiblings: () => opts.element.isConnected
2691
2987
  });
2692
2988
  this.element = opts.element;
2693
2989
  this.handle = opts.handle ?? opts.element;
@@ -2716,7 +3012,6 @@ var BottomSheetCore = class {
2716
3012
  void this.snapTo(id);
2717
3013
  },
2718
3014
  close: () => {
2719
- if (!this.canDismiss()) return;
2720
3015
  void this.close("backdrop");
2721
3016
  }
2722
3017
  },
@@ -2746,7 +3041,8 @@ var BottomSheetCore = class {
2746
3041
  this.lifecycle = new LifecycleController(
2747
3042
  {
2748
3043
  element: this.element,
2749
- close: () => this.close()
3044
+ close: () => this.close(),
3045
+ isTop: () => this.isTopSheet
2750
3046
  },
2751
3047
  resolved.lifecycle
2752
3048
  );
@@ -2773,6 +3069,7 @@ var BottomSheetCore = class {
2773
3069
  auditVhUsage(this.snapPointsRaw);
2774
3070
  this.auditDuplicateSnapIds(this.snapPointsRaw);
2775
3071
  this.rootEl = this.element.closest(".bs-root");
3072
+ this.homeRoot = homeRootOf(this.rootEl);
2776
3073
  this.maxHeightDeps = {
2777
3074
  element: this.element,
2778
3075
  mode: this.mode,
@@ -2800,7 +3097,9 @@ var BottomSheetCore = class {
2800
3097
  );
2801
3098
  const initial = this.snaps.findById(this.activeId);
2802
3099
  if (initial) this.size = initial.size;
3100
+ this.phase = this.size > 0 ? "open" : "closed";
2803
3101
  this.applySize(this.size);
3102
+ this.restClosed = this.element.getAttribute("data-bs-rest") === "closed";
2804
3103
  this.setRestClosed(this.size === 0);
2805
3104
  this.updateAriaSlider();
2806
3105
  this.scrollCache = createScrollCache({
@@ -2811,12 +3110,11 @@ var BottomSheetCore = class {
2811
3110
  this.attach();
2812
3111
  this.registerInStack();
2813
3112
  if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
2814
- const io = new IntersectionObserver((entries2) => {
2815
- for (const entry of entries2) {
3113
+ const io = new IntersectionObserver((entries) => {
3114
+ for (const entry of entries) {
2816
3115
  if (!entry.isIntersecting) continue;
2817
3116
  if (this.destroyed) return;
2818
- this.snaps.recompute();
2819
- this.healActiveSnap();
3117
+ this.recompute();
2820
3118
  io.disconnect();
2821
3119
  return;
2822
3120
  }
@@ -2826,6 +3124,7 @@ var BottomSheetCore = class {
2826
3124
  }
2827
3125
  this.teardowns.add(
2828
3126
  installFitObserver({
3127
+ element: this.element,
2829
3128
  handle: this.handle,
2830
3129
  scrollContainer: this.scrollContainer,
2831
3130
  hasFitSnap: () => this.snapPointsRaw.some(
@@ -2841,9 +3140,7 @@ var BottomSheetCore = class {
2841
3140
  this.applyAutoAriaLabelledBy();
2842
3141
  this.runFeatureStage("post");
2843
3142
  this.warnOrphanFeatureOptions();
2844
- if (this.size > 0) {
2845
- this.handleOpen();
2846
- }
3143
+ if (this.phase === "open") this.installLifecycle(true);
2847
3144
  }
2848
3145
  buildFeatureContext(autoCollapseAfter) {
2849
3146
  return {
@@ -2871,21 +3168,27 @@ var BottomSheetCore = class {
2871
3168
  getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
2872
3169
  resolveSnap: (id) => this.snaps.findById(id),
2873
3170
  resolveActiveSnap: () => this.snaps.findById(this.activeId),
3171
+ getPhase: () => this.phase,
2874
3172
  setSize: (size) => {
2875
3173
  this.size = size;
2876
3174
  },
2877
3175
  setMaxAxisSize: (size) => {
2878
3176
  this.snaps.setMaxAxisSize(size);
2879
3177
  },
3178
+ setKeyboardInset: (px) => this.setKeyboardInset(px),
2880
3179
  applySize: (size) => this.applySize(size),
2881
3180
  recomputeSnaps: () => this.recomputeSnaps(),
3181
+ reseat: () => this.reseat(),
3182
+ holdSettle: (settled) => {
3183
+ this.settleHolds.push(settled);
3184
+ },
2882
3185
  newCycle: () => {
2883
3186
  this.newCycle();
2884
3187
  },
2885
- cancelInFlight: () => {
2886
- this.animation.cancel();
3188
+ cancelInFlight: () => this.suspend(),
3189
+ resyncAfterResize: () => {
3190
+ if (!this.destroyed) this.land(false);
2887
3191
  },
2888
- resyncAfterResize: () => this.resyncAfterResize(),
2889
3192
  snapTo: (id) => {
2890
3193
  void this.snapTo(id);
2891
3194
  },
@@ -2924,8 +3227,9 @@ var BottomSheetCore = class {
2924
3227
  return {
2925
3228
  size: this.size,
2926
3229
  activeId: this.activeId,
3230
+ phase: this.phase,
2927
3231
  isDragging: this.isDraggingAny(),
2928
- isAnimating: this.animation.isAnimating,
3232
+ isAnimating: this.animation.isAnimating || this.currentViewTransition !== null,
2929
3233
  progress: this.computeProgress(this.size)
2930
3234
  };
2931
3235
  }
@@ -2979,49 +3283,53 @@ var BottomSheetCore = class {
2979
3283
  getResolvedSnaps() {
2980
3284
  return this.snaps.getResolvedSnaps();
2981
3285
  }
2982
- async snapTo(id, velocityOrOpts = 0, _skipBeforeSnap = false) {
2983
- if (this.destroyed) return;
3286
+ snapTo(id, velocityOrOpts = 0, _skipBeforeSnap = false) {
2984
3287
  const opts = typeof velocityOrOpts === "object" ? velocityOrOpts : { velocity: velocityOrOpts };
2985
- const velocityPxPerMs = opts.velocity ?? 0;
2986
- const externalSignal = opts.signal;
2987
- if (externalSignal?.aborted) return;
3288
+ return this.transitionTo(
3289
+ id,
3290
+ opts.velocity ?? 0,
3291
+ _skipBeforeSnap,
3292
+ opts.signal
3293
+ );
3294
+ }
3295
+ transitionTo(id, velocityPxPerMs = 0, skipBeforeSnap = false, externalSignal) {
3296
+ if (this.destroyed || externalSignal?.aborted) return Promise.resolve();
2988
3297
  const target = this.snaps.findById(id);
2989
3298
  if (!target) {
2990
3299
  devWarn(`[BottomSheet] unknown snap id: ${id}`);
2991
- return;
3300
+ return Promise.resolve();
2992
3301
  }
2993
3302
  if (!this.snaps.getAllowedIds().includes(id)) {
2994
3303
  devWarn(`[BottomSheet] snap "${id}" is not in allowed list`);
2995
- return;
2996
- }
2997
- if (!_skipBeforeSnap && this.emitBeforeSnap(target, this.activeId)) {
2998
- return;
2999
- }
3000
- const resumingOpen = this.opening;
3001
- const signal = this.newCycle();
3002
- const onExternalAbort = () => {
3003
- this.animation.cancel();
3004
- this.newCycle();
3005
- };
3304
+ return Promise.resolve();
3305
+ }
3306
+ if (target.size === 0 && this.closingBlocked()) return Promise.resolve();
3307
+ if (!externalSignal && this.inFlight?.id === id) return this.inFlight.done;
3308
+ if (!skipBeforeSnap && this.emitBeforeSnap(target, this.activeId)) {
3309
+ return Promise.resolve();
3310
+ }
3311
+ const flight = { id, done: Promise.resolve() };
3312
+ flight.done = this.runTransition(
3313
+ target,
3314
+ velocityPxPerMs,
3315
+ false,
3316
+ externalSignal,
3317
+ flight
3318
+ );
3319
+ return flight.done;
3320
+ }
3321
+ async runTransition(target, velocityPxPerMs, fromDrag, externalSignal, flight = null) {
3322
+ const signal = this.beginTransition(target);
3323
+ const transition = this.transition;
3324
+ if (signal.aborted || !transition) return;
3325
+ this.inFlight = flight;
3326
+ const onExternalAbort = () => this.suspend();
3006
3327
  externalSignal?.addEventListener("abort", onExternalAbort, { once: true });
3007
- const wasClosed = this.size === 0 || resumingOpen;
3008
- const previousId = this.activeId;
3009
- const previousSize = this.size;
3010
- this.scrollCache.cache(previousId, previousSize, target.size);
3011
- this.activeId = id;
3012
- const rawTargetSize = this.snapPointsRaw.find((p) => p.id === id)?.size;
3013
- const opensToRest = id === "closed" || rawTargetSize === 0;
3014
- if (wasClosed && !opensToRest) {
3015
- this.opening = true;
3016
- if (!resumingOpen) {
3017
- this.promotedForOpen = true;
3018
- sheetStack.promote(this.id);
3019
- }
3020
- }
3021
- if (this.animation.viewTransitionsAvailable) {
3328
+ this.allowOvershoot = fromDrag;
3329
+ if (!fromDrag && this.animation.viewTransitionsAvailable) {
3022
3330
  this.currentViewTransition?.skipTransition?.();
3023
3331
  const vt = document.startViewTransition(() => {
3024
- this.applySize(target.size);
3332
+ if (!signal.aborted) this.applySize(transition.size);
3025
3333
  });
3026
3334
  vt.ready?.catch(() => {
3027
3335
  });
@@ -3032,25 +3340,202 @@ var BottomSheetCore = class {
3032
3340
  }
3033
3341
  if (this.currentViewTransition === vt) this.currentViewTransition = null;
3034
3342
  } else {
3035
- await this.animation.animateTo(target.size, velocityPxPerMs);
3343
+ await this.animation.animateTo(transition.size, velocityPxPerMs);
3036
3344
  }
3037
3345
  externalSignal?.removeEventListener("abort", onExternalAbort);
3038
3346
  if (signal.aborted) return;
3039
- this.opening = false;
3040
- this.completeSnap(id, target.size, previousSize, wasClosed, false);
3347
+ if (this.size !== transition.size) this.applySize(transition.size);
3348
+ this.land(fromDrag);
3349
+ if (this.settleHolds.length > 0) {
3350
+ await Promise.allSettled(this.settleHolds.splice(0));
3351
+ }
3352
+ }
3353
+ beginTransition(target) {
3354
+ const signal = this.newCycle();
3355
+ const cap = this.snaps.getMaxAxisSize();
3356
+ const fromId = this.activeId;
3357
+ const fromSize = this.snaps.findById(fromId)?.size ?? this.size;
3358
+ this.scrollCache.leave(fromId, fromSize, target.size);
3359
+ this.scrollCache.enter(target.id, fromSize, target.size);
3360
+ this.activeId = target.id;
3361
+ this.transition = {
3362
+ size: cap > 0 ? Math.min(target.size, cap) : target.size,
3363
+ cap
3364
+ };
3365
+ if (target.size > 0) {
3366
+ this.enterOpening(target.id);
3367
+ } else {
3368
+ if (this.phase === "closed" && !this.isClosedSnap(target.id)) {
3369
+ sheetStack.promote(this.id);
3370
+ }
3371
+ this.enterClosing();
3372
+ }
3373
+ this.flush();
3374
+ return signal;
3375
+ }
3376
+ enterOpening(id) {
3377
+ if (this.phase === "open" || this.phase === "opening") return;
3378
+ const fresh = this.phase === "closed";
3379
+ this.phase = "opening";
3380
+ this.setRestClosed(false);
3381
+ if (!this.installLifecycle(fresh)) return;
3382
+ this.post("open", { id });
3383
+ this.outbox.push(() => {
3384
+ if (this.phase !== "closed") {
3385
+ notifyLinkedSheets(this.linkedSheets, this);
3386
+ }
3387
+ });
3041
3388
  }
3042
- completeSnap(id, targetSize, previousSize, wasClosed, withHaptic) {
3043
- this.scrollCache.restore(id, previousSize, targetSize);
3389
+ enterClosing() {
3390
+ if (this.phase === "closed" || this.phase === "closing") return;
3391
+ this.phase = "closing";
3392
+ this.post("close", void 0);
3393
+ }
3394
+ settlePhase(heal) {
3395
+ if (this.size > 0) {
3396
+ this.enterOpening(this.activeId);
3397
+ if (this.phase === "opening") {
3398
+ this.phase = "open";
3399
+ this.post("opened", { id: this.activeId });
3400
+ }
3401
+ return;
3402
+ }
3403
+ if (heal && this.phase !== "closing") return;
3404
+ this.enterClosing();
3405
+ if (this.phase === "closing") {
3406
+ this.phase = "closed";
3407
+ this.setRestClosed(true);
3408
+ this.lifecycle.release();
3409
+ sheetStack.update();
3410
+ this.post("closed", void 0);
3411
+ }
3412
+ }
3413
+ land(haptic) {
3414
+ this.transition = null;
3415
+ this.inFlight = null;
3416
+ this.allowOvershoot = false;
3417
+ this.openPending = this.size === 0 && !this.isClosedSnap(this.activeId);
3044
3418
  this.updateAriaSlider();
3045
- this.emit("snap", {
3046
- id,
3419
+ this.setRestClosed(this.size === 0);
3420
+ this.post("snap", {
3421
+ id: this.activeId,
3047
3422
  size: this.size,
3048
3423
  progress: this.computeProgress(this.size)
3049
3424
  });
3050
- if (withHaptic) this.haptic();
3051
- this.setRestClosed(targetSize === 0);
3052
- if (wasClosed && targetSize > 0) this.emitOpenSequence(id);
3053
- if (targetSize === 0) this.emitCloseSequence();
3425
+ this.settlePhase(false);
3426
+ if (haptic) this.haptic();
3427
+ this.flush();
3428
+ }
3429
+ suspend() {
3430
+ this.animation.cancel();
3431
+ this.currentViewTransition?.skipTransition?.();
3432
+ this.newCycle();
3433
+ }
3434
+ landNow() {
3435
+ const transition = this.transition;
3436
+ if (this.destroyed || !transition || this.isDraggingAny()) return;
3437
+ this.animation.cancel();
3438
+ this.currentViewTransition?.skipTransition?.();
3439
+ this.newCycle();
3440
+ this.applySize(transition.size);
3441
+ this.land(false);
3442
+ }
3443
+ reseat() {
3444
+ if (this.destroyed || this.isDraggingAny()) return;
3445
+ const active = this.snaps.findById(this.activeId);
3446
+ if (!active) return;
3447
+ const cap = this.snaps.getMaxAxisSize();
3448
+ const target = cap > 0 ? Math.min(active.size, cap) : active.size;
3449
+ this.updateAriaSlider();
3450
+ const transition = this.transition;
3451
+ if (transition) {
3452
+ if (Math.abs(target - transition.size) < SIZE_WRITE_EPSILON && Math.abs(cap - transition.cap) < SIZE_WRITE_EPSILON) {
3453
+ return;
3454
+ }
3455
+ transition.size = target;
3456
+ transition.cap = cap;
3457
+ this.applySize(this.animation.retarget(target) ? this.size : target);
3458
+ return;
3459
+ }
3460
+ if (this.openPending && target > 0 && this.phase === "closed") {
3461
+ void this.runTransition(active, 0, false);
3462
+ return;
3463
+ }
3464
+ this.applySize(target);
3465
+ this.settlePhase(true);
3466
+ this.flush();
3467
+ }
3468
+ installLifecycle(promote) {
3469
+ if (promote) sheetStack.promote(this.id);
3470
+ if (this.lifecycle.isInstalled) return true;
3471
+ try {
3472
+ this.lifecycle.install();
3473
+ return true;
3474
+ } catch (err) {
3475
+ this.abortOpen();
3476
+ queueMicrotask(() => {
3477
+ throw err;
3478
+ });
3479
+ return false;
3480
+ }
3481
+ }
3482
+ abortOpen() {
3483
+ this.animation.cancel();
3484
+ if (!this.destroyed) this.newCycle();
3485
+ this.phase = "closed";
3486
+ this.openPending = false;
3487
+ this.lifecycle.release();
3488
+ sheetStack.update();
3489
+ this.activeId = this.zeroSnapId() ?? this.activeId;
3490
+ this.applySize(0);
3491
+ this.setRestClosed(true);
3492
+ this.updateAriaSlider();
3493
+ }
3494
+ zeroSnapId() {
3495
+ return this.snapPointsRaw.find((p) => p.id === "closed")?.id ?? this.snaps.getAllowedIds().find((a) => this.snaps.findById(a)?.size === 0);
3496
+ }
3497
+ isClosedSnap(id) {
3498
+ if (id === "closed") return true;
3499
+ return this.snapPointsRaw.find((p) => p.id === id)?.size === 0;
3500
+ }
3501
+ closingBlocked() {
3502
+ return this.disableCloseFlag && this.phase !== "closed";
3503
+ }
3504
+ setKeyboardInset(px) {
3505
+ if (px === this.keyboardInset) return;
3506
+ this.keyboardInset = px;
3507
+ for (const host of this.varHosts()) {
3508
+ host.style.setProperty("--bs-keyboard-inset", `${px}px`);
3509
+ }
3510
+ }
3511
+ varHosts() {
3512
+ const hosts = /* @__PURE__ */ new Set([this.element]);
3513
+ for (const host of [
3514
+ this.anchorHost,
3515
+ this.scrimParent,
3516
+ this.rootEl,
3517
+ this.homeRoot
3518
+ ]) {
3519
+ if (host) hosts.add(host);
3520
+ }
3521
+ return hosts;
3522
+ }
3523
+ dismissBlocked() {
3524
+ return (this.disableCloseFlag || this.persistent) && this.phase !== "closed";
3525
+ }
3526
+ post(event, payload) {
3527
+ this.outbox.push(() => this.bus.emit(event, payload));
3528
+ }
3529
+ flush() {
3530
+ if (this.flushing) return;
3531
+ this.flushing = true;
3532
+ try {
3533
+ for (let next = this.outbox.shift(); next; next = this.outbox.shift()) {
3534
+ next();
3535
+ }
3536
+ } finally {
3537
+ this.flushing = false;
3538
+ }
3054
3539
  }
3055
3540
  setRestClosed(closed) {
3056
3541
  if (closed === this.restClosed) return;
@@ -3058,17 +3543,6 @@ var BottomSheetCore = class {
3058
3543
  if (closed) this.element.setAttribute("data-bs-rest", "closed");
3059
3544
  else this.element.removeAttribute("data-bs-rest");
3060
3545
  }
3061
- emitOpenSequence(id) {
3062
- this.emit("open", { id });
3063
- this.handleOpen();
3064
- notifyLinkedSheets(this.linkedSheets, this);
3065
- this.emit("opened", { id });
3066
- }
3067
- emitCloseSequence() {
3068
- this.emit("close", void 0);
3069
- this.handleClose();
3070
- this.emit("closed", void 0);
3071
- }
3072
3546
  async dragTo(targetSize, velocityOrOpts = 0) {
3073
3547
  if (this.destroyed) return;
3074
3548
  const opts = typeof velocityOrOpts === "object" ? velocityOrOpts : { velocity: velocityOrOpts };
@@ -3076,27 +3550,31 @@ var BottomSheetCore = class {
3076
3550
  const externalSignal = opts.signal;
3077
3551
  if (externalSignal?.aborted) return;
3078
3552
  this.newCycle();
3079
- const onExternalAbort = () => {
3080
- this.animation.cancel();
3081
- this.newCycle();
3082
- };
3553
+ const onExternalAbort = () => this.suspend();
3083
3554
  externalSignal?.addEventListener("abort", onExternalAbort, { once: true });
3084
3555
  const clamped = Math.max(0, Math.min(targetSize, this.snaps.getMaxAxisSize()));
3085
3556
  await this.animation.animateTo(clamped, velocityPxPerMs);
3086
3557
  externalSignal?.removeEventListener("abort", onExternalAbort);
3087
- if (this.destroyed || externalSignal?.aborted) return;
3088
3558
  }
3089
3559
  open(id) {
3090
3560
  if (this.destroyed) return Promise.resolve();
3561
+ if (!id && (this.phase === "open" || this.phase === "opening")) {
3562
+ return Promise.resolve();
3563
+ }
3091
3564
  const target = id ?? this.snaps.getAllowedIds().find((a) => (this.snaps.findById(a)?.size ?? 0) > 0) ?? this.activeId;
3092
3565
  return this.snapTo(target);
3093
3566
  }
3094
3567
  close(reason = "programmatic") {
3095
- if (this.destroyed) return Promise.resolve();
3096
- if (this.disableCloseFlag) return Promise.resolve();
3097
- if (this.size > 0 && this.emitBeforeClose(reason)) return Promise.resolve();
3098
- 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];
3099
- return this.snapTo(closedId ?? this.activeId);
3568
+ if (this.destroyed || this.disableCloseFlag) return Promise.resolve();
3569
+ if (this.persistent && reason !== "programmatic") return Promise.resolve();
3570
+ const target = this.zeroSnapId() ?? this.allowedIdsBySize()[0];
3571
+ if (target === void 0) return Promise.resolve();
3572
+ if (this.phase === "closed" && this.activeId === target) {
3573
+ return Promise.resolve();
3574
+ }
3575
+ const visible = this.phase === "open" || this.phase === "opening";
3576
+ if (visible && this.emitBeforeClose(reason)) return Promise.resolve();
3577
+ return this.snapTo(target);
3100
3578
  }
3101
3579
  canDismiss() {
3102
3580
  return !this.persistent && !this.disableCloseFlag && !this.destroyed;
@@ -3119,10 +3597,12 @@ var BottomSheetCore = class {
3119
3597
  }
3120
3598
  setDragFrom(mode) {
3121
3599
  if (this.destroyed || mode === this.dragFromMode) return;
3600
+ const wasDragging = this.gesture?.isDragging ?? false;
3122
3601
  this.gesture?.forceClearDragState();
3123
3602
  this.detachSheetGesture?.();
3124
3603
  this.dragFromMode = mode;
3125
3604
  this.mountSheetGesture();
3605
+ if (wasDragging) this.restoreAfterDrag();
3126
3606
  }
3127
3607
  getDragFrom() {
3128
3608
  return this.dragFromMode;
@@ -3135,6 +3615,7 @@ var BottomSheetCore = class {
3135
3615
  const nowVertical = next === "bottom" || next === "top";
3136
3616
  this.gesture?.forceClearDragState();
3137
3617
  this.detachSheetGesture?.();
3618
+ this.landNow();
3138
3619
  this.animation.cancel();
3139
3620
  this.element.style.removeProperty(layoutAxis(this.mode));
3140
3621
  this.mode = next;
@@ -3150,9 +3631,12 @@ var BottomSheetCore = class {
3150
3631
  this.detachSliderKeyboard?.();
3151
3632
  this.mountSliderKeyboard();
3152
3633
  this.mountSheetGesture();
3634
+ for (const anchor of this.anchors) anchor.reposition();
3635
+ this.placeScrimStages?.();
3636
+ if (this.stackEffectPrimed) {
3637
+ this.element.style.transformOrigin = nowVertical ? "50% 100%" : "0% 50%";
3638
+ }
3153
3639
  this.recompute();
3154
- const active = this.snaps.findById(this.activeId);
3155
- if (active) this.applySize(active.size);
3156
3640
  this.updateAriaSlider();
3157
3641
  }
3158
3642
  getMode() {
@@ -3194,13 +3678,24 @@ var BottomSheetCore = class {
3194
3678
  if (snap && ids.includes(snap)) {
3195
3679
  void this.snapTo(snap, 0, true);
3196
3680
  } else if (!ids.includes(this.activeId)) {
3197
- const fallback = ids[0];
3198
- if (fallback) void this.snapTo(fallback, 0, true);
3681
+ const fallback = this.fallbackSnap(
3682
+ this.snaps.findById(this.activeId)?.size ?? this.size
3683
+ );
3684
+ if (fallback) void this.snapTo(fallback.id, 0, true);
3199
3685
  }
3200
3686
  }
3687
+ fallbackSnap(from) {
3688
+ return (from > 0 ? this.snaps.nearest(from, true) : null) ?? this.snaps.nearest(from, false);
3689
+ }
3201
3690
  setBackdropRange(range) {
3202
3691
  this.scrim.setBackdropRange(range, () => this.applySize(this.size));
3203
3692
  }
3693
+ setBackdropOpacity(value) {
3694
+ this.scrim.setBackdropOpacity(value, () => this.applySize(this.size));
3695
+ }
3696
+ setBackdropColor(color) {
3697
+ this.scrim.setBackdropColor(color);
3698
+ }
3204
3699
  setScreenRange(range) {
3205
3700
  this.scrim.setScreenRange(range, () => this.applySize(this.size));
3206
3701
  }
@@ -3241,7 +3736,7 @@ var BottomSheetCore = class {
3241
3736
  }
3242
3737
  const handle = attachAnchor(
3243
3738
  {
3244
- mode: this.mode,
3739
+ getMode: () => this.mode,
3245
3740
  host: this.anchorHost,
3246
3741
  getState: () => ({
3247
3742
  activeId: this.activeId,
@@ -3279,9 +3774,9 @@ var BottomSheetCore = class {
3279
3774
  return () => {
3280
3775
  };
3281
3776
  }
3282
- const detachInstalled = installScrimStages(
3777
+ const stages = installScrimStages(
3283
3778
  {
3284
- mode: this.mode,
3779
+ getMode: () => this.mode,
3285
3780
  host,
3286
3781
  getState: () => ({
3287
3782
  activeId: this.activeId,
@@ -3294,10 +3789,14 @@ var BottomSheetCore = class {
3294
3789
  opts
3295
3790
  );
3296
3791
  const detach = () => {
3297
- if (this.detachScrimStages === detach) this.detachScrimStages = null;
3298
- detachInstalled();
3792
+ if (this.detachScrimStages === detach) {
3793
+ this.detachScrimStages = null;
3794
+ this.placeScrimStages = null;
3795
+ }
3796
+ stages.detach();
3299
3797
  };
3300
3798
  this.detachScrimStages = detach;
3799
+ this.placeScrimStages = stages.reposition;
3301
3800
  this.teardowns.add(() => this.detachScrimStages?.());
3302
3801
  return detach;
3303
3802
  }
@@ -3306,32 +3805,29 @@ var BottomSheetCore = class {
3306
3805
  }
3307
3806
  setSnapPoints(points, allowed) {
3308
3807
  if (this.destroyed) return;
3309
- this.animation.cancel();
3310
- this.newCycle();
3808
+ const from = this.snaps.findById(this.activeId)?.size ?? this.size;
3809
+ const restricted = this.snaps.getResolvedSnaps().some((s) => !this.snaps.getAllowedIds().includes(s.id));
3311
3810
  this.snapPointsRaw = points;
3312
3811
  auditVhUsage(points);
3313
3812
  this.auditDuplicateSnapIds(points);
3813
+ this.maxHeight.resolveCap();
3314
3814
  this.snaps.setRaw(points);
3815
+ this.maxHeight.clampTo();
3315
3816
  if (allowed) {
3316
3817
  this.snaps.setAllowedIds(allowed);
3317
3818
  } else {
3318
3819
  const present = this.snaps.getResolvedSnaps().map((s) => s.id);
3319
- const kept = this.snaps.getAllowedIds().filter((id) => present.includes(id));
3820
+ const kept = restricted ? this.snaps.getAllowedIds().filter((id) => present.includes(id)) : [];
3320
3821
  this.snaps.setAllowedIds(kept.length ? kept : present);
3321
3822
  }
3322
3823
  this.scrollCache.clear();
3323
3824
  this.scrim.invalidateOpacityCache();
3324
- const current = this.snaps.findById(this.activeId);
3325
- if (current) {
3326
- this.applySize(current.size);
3327
- } else {
3328
- const fallback = this.snaps.getResolvedSnaps().find((s) => this.snaps.getAllowedIds().includes(s.id)) ?? this.snaps.getResolvedSnaps()[0];
3329
- if (fallback) {
3330
- this.activeId = fallback.id;
3331
- this.applySize(fallback.size);
3332
- }
3825
+ if (this.snaps.findById(this.activeId)) {
3826
+ this.reseat();
3827
+ return;
3333
3828
  }
3334
- this.updateAriaSlider();
3829
+ const fallback = this.fallbackSnap(from) ?? this.snaps.getResolvedSnaps()[0];
3830
+ if (fallback) void this.transitionTo(fallback.id, 0, true);
3335
3831
  }
3336
3832
  recompute() {
3337
3833
  if (this.destroyed) return;
@@ -3339,22 +3835,11 @@ var BottomSheetCore = class {
3339
3835
  this.snaps.recompute();
3340
3836
  this.maxHeight.clampTo();
3341
3837
  this.scrim.invalidateOpacityCache();
3342
- if (this.isDraggingAny()) return;
3343
- this.healActiveSnap();
3344
- }
3345
- healActiveSnap() {
3346
- const current = this.snaps.findById(this.activeId);
3347
- if (!current) return;
3348
- this.size = current.size;
3349
- this.applySize(this.size);
3350
- this.updateAriaSlider();
3351
- if (this.size > 0 && !this.lifecycle.isInstalled && !this.opening && !this.animation.isAnimating) {
3352
- this.emitOpenSequence(this.activeId);
3353
- }
3838
+ this.reseat();
3354
3839
  }
3355
3840
  destroy() {
3356
3841
  this.destroyed = true;
3357
- this.opening = false;
3842
+ this.outbox.length = 0;
3358
3843
  this.currentAbort.abort();
3359
3844
  this.currentViewTransition?.skipTransition?.();
3360
3845
  this.currentViewTransition = null;
@@ -3371,11 +3856,19 @@ var BottomSheetCore = class {
3371
3856
  this.backdrop.style.opacity = "";
3372
3857
  this.backdrop.style.pointerEvents = "";
3373
3858
  }
3374
- for (const host of [this.anchorHost, this.scrimParent, this.rootEl]) {
3859
+ for (const host of [
3860
+ this.anchorHost,
3861
+ this.scrimParent,
3862
+ this.rootEl,
3863
+ this.homeRoot
3864
+ ]) {
3375
3865
  if (!host) continue;
3376
3866
  host.style.removeProperty("--bs-size");
3377
3867
  host.style.removeProperty("--bs-progress");
3868
+ host.style.removeProperty("--bs-z-sheet");
3869
+ host.style.removeProperty("--bs-keyboard-inset");
3378
3870
  }
3871
+ this.element.style.removeProperty("--bs-keyboard-inset");
3379
3872
  if (this.screenComponent) {
3380
3873
  this.screenComponent.style.opacity = "";
3381
3874
  this.screenComponent.style.display = "";
@@ -3388,7 +3881,8 @@ var BottomSheetCore = class {
3388
3881
  }
3389
3882
  newCycle() {
3390
3883
  this.allowOvershoot = false;
3391
- this.opening = false;
3884
+ this.transition = null;
3885
+ this.inFlight = null;
3392
3886
  this.currentAbort.abort();
3393
3887
  this.currentAbort = new AbortController();
3394
3888
  return this.currentAbort.signal;
@@ -3411,8 +3905,9 @@ var BottomSheetCore = class {
3411
3905
  if (typeof document === "undefined") return;
3412
3906
  if (!this.lifecycle.focusTrapEnabled) return;
3413
3907
  if (this.element.getAttribute("aria-labelledby")) return;
3414
- const scope = this.handle ?? this.element;
3415
- const titled = scope.querySelector("[data-bs-title]") ?? scope.querySelector("h1,h2,h3,h4,h5,h6");
3908
+ const HEADING = "h1,h2,h3,h4,h5,h6";
3909
+ const header = this.element.querySelector(".bs-header");
3910
+ const titled = this.element.querySelector("[data-bs-title]") ?? this.handle.querySelector(HEADING) ?? header?.querySelector(HEADING);
3416
3911
  if (!titled) return;
3417
3912
  if (!titled.id) {
3418
3913
  titled.id = nextInstanceId("bs-title");
@@ -3454,12 +3949,16 @@ var BottomSheetCore = class {
3454
3949
  this.stackZ = z;
3455
3950
  this.element.style.zIndex = String(z);
3456
3951
  if (this.backdrop) this.backdrop.style.zIndex = String(z - 1);
3952
+ this.rootEl?.style.setProperty("--bs-z-sheet", String(z));
3953
+ this.homeRoot?.style.setProperty("--bs-z-sheet", String(z));
3457
3954
  for (const anchor of this.anchors) anchor.syncZ(z + 1);
3458
3955
  },
3459
3956
  setIsTop: (isTop) => {
3957
+ if (isTop === this.isTopSheet) return;
3460
3958
  this.isTopSheet = isTop;
3959
+ this.lifecycle.syncTop();
3461
3960
  },
3462
- isOpen: () => this.size > 0 || this.opening,
3961
+ isOpen: () => this.phase !== "closed",
3463
3962
  setDepth: (depth) => this.applyStackDepth(depth)
3464
3963
  }));
3465
3964
  }
@@ -3487,15 +3986,15 @@ var BottomSheetCore = class {
3487
3986
  const r = this.getAllowedRange();
3488
3987
  buf.size = this.size;
3489
3988
  buf.maxAxisSize = this.snaps.getMaxAxisSize();
3490
- buf.range.min = r.min;
3989
+ buf.range.min = this.dismissBlocked() ? Math.max(r.min, this.smallestOpenSize()) : r.min;
3491
3990
  buf.range.max = r.max;
3492
3991
  buf.rubberBandEnabled = this.rubberBandEnabled;
3493
3992
  return buf;
3494
3993
  },
3495
3994
  getDisableDrag: () => this.disableDragFlag,
3496
- cancelAnimation: () => this.animation.cancel(),
3995
+ cancelAnimation: () => this.suspend(),
3497
3996
  applySize: (size) => this.applySize(size),
3498
- animateTo: (size, velocity) => this.animation.animateTo(size, velocity),
3997
+ restoreAfterDrag: () => this.restoreAfterDrag(),
3499
3998
  settleAfterDrag: (delta, velocity, kind) => this.settleAfterDrag(delta, velocity, kind),
3500
3999
  emit: (event, payload) => this.emit(event, payload),
3501
4000
  listenerCount: (event) => this.bus.listenerCount(event)
@@ -3619,32 +4118,19 @@ var BottomSheetCore = class {
3619
4118
  element: this.element,
3620
4119
  getMode: () => this.mode,
3621
4120
  isDestroyed: () => this.destroyed,
3622
- isDragging: () => this.isDraggingAny(),
3623
4121
  resolveActiveSnap: () => this.snaps.findById(this.activeId),
3624
4122
  getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
3625
- getSize: () => this.size,
3626
4123
  setMaxAxisSize: (size) => {
3627
4124
  this.snaps.setMaxAxisSize(size);
3628
4125
  },
3629
- setSize: (size) => {
3630
- this.size = size;
3631
- },
3632
4126
  recomputeSnaps: () => this.recomputeSnaps(),
3633
- applySize: (size) => this.applySize(size),
3634
- cancelInFlight: () => {
3635
- this.animation.cancel();
3636
- },
3637
- newCycle: () => {
3638
- this.newCycle();
3639
- },
3640
- isAnimating: () => this.animation.isAnimating,
3641
- resyncAfterCancel: () => this.resyncAfterResize()
4127
+ reseat: () => this.reseat(),
4128
+ landNow: () => this.landNow()
3642
4129
  }));
3643
4130
  if (this.lifecycle.closeOnEscape) {
3644
4131
  const onKey = (e) => {
3645
4132
  if (this.destroyed || e.defaultPrevented) return;
3646
- if (!this.canDismiss()) return;
3647
- if (e.key === "Escape" && this.isTopSheet && this.size > 0) {
4133
+ if (e.key === "Escape" && this.isTopSheet) {
3648
4134
  void this.close("escape");
3649
4135
  }
3650
4136
  };
@@ -3662,7 +4148,10 @@ var BottomSheetCore = class {
3662
4148
  handle: this.handle,
3663
4149
  mode: this.mode,
3664
4150
  isDestroyed: () => this.destroyed,
3665
- getAllowedIds: () => this.allowedIdsBySize(),
4151
+ getAllowedIds: () => {
4152
+ const ids = this.allowedIdsBySize();
4153
+ return this.dismissBlocked() ? ids.filter((id) => (this.snaps.findById(id)?.size ?? 0) > 0) : ids;
4154
+ },
3666
4155
  getActiveId: () => this.activeId,
3667
4156
  snapTo: (id) => {
3668
4157
  void this.snapTo(id);
@@ -3675,56 +4164,46 @@ var BottomSheetCore = class {
3675
4164
  });
3676
4165
  }
3677
4166
  settleAfterDrag(delta, velocity, kind = "touch") {
3678
- const signal = this.newCycle();
3679
- const target = this.snaps.findDragSettleTarget({
3680
- delta,
3681
- velocity,
3682
- pointerKind: kind,
3683
- size: this.size,
3684
- activeId: this.activeId,
3685
- flickVelocity: this.flickVelocity,
3686
- dragThreshold: this.dragThreshold
3687
- });
4167
+ const target = this.snaps.findDragSettleTarget(
4168
+ {
4169
+ delta,
4170
+ velocity,
4171
+ pointerKind: kind,
4172
+ size: this.size,
4173
+ activeId: this.activeId,
4174
+ flickVelocity: this.flickVelocity,
4175
+ dragThreshold: this.dragThreshold
4176
+ },
4177
+ this.dismissBlocked()
4178
+ );
3688
4179
  if (!target) {
3689
4180
  this.clearWillChangeIfIdle();
3690
4181
  return;
3691
4182
  }
3692
4183
  const previousId = this.activeId;
3693
4184
  if (target.id === previousId && target.size === this.size) {
4185
+ if (this.phase === "opening" || this.phase === "closing") {
4186
+ this.land(false);
4187
+ }
3694
4188
  this.clearWillChangeIfIdle();
3695
4189
  return;
3696
4190
  }
3697
4191
  if (this.emitBeforeSnap(target, previousId)) {
3698
- const restore2 = this.snaps.findById(previousId);
3699
- if (restore2) {
3700
- void this.animation.animateTo(restore2.size, 0);
3701
- }
4192
+ this.restoreAfterDrag();
3702
4193
  return;
3703
4194
  }
3704
- const previousSize = this.size;
3705
- const previousSnapSize = this.snaps.findById(previousId)?.size;
3706
- this.scrollCache.cache(previousId, previousSize, target.size);
3707
- this.activeId = target.id;
3708
- if (previousSnapSize === 0 && target.size > 0) {
3709
- this.opening = true;
3710
- this.promotedForOpen = true;
3711
- sheetStack.promote(this.id);
3712
- }
3713
- const settleCap = this.snaps.getMaxAxisSize();
3714
- const settleSize = settleCap > 0 ? Math.min(target.size, settleCap) : target.size;
3715
- this.allowOvershoot = true;
3716
- void this.animation.animateTo(settleSize, velocity).then(() => {
3717
- if (signal.aborted) return;
3718
- this.allowOvershoot = false;
3719
- this.opening = false;
3720
- this.completeSnap(
3721
- target.id,
3722
- target.size,
3723
- previousSize,
3724
- previousSnapSize === 0,
3725
- true
3726
- );
3727
- });
4195
+ void this.runTransition(target, velocity, true);
4196
+ }
4197
+ restoreAfterDrag() {
4198
+ const active = this.snaps.findById(this.activeId);
4199
+ if (active) void this.runTransition(active, 0, false);
4200
+ }
4201
+ smallestOpenSize() {
4202
+ const allowed = this.snaps.getAllowedIds();
4203
+ for (const snap of this.snaps.getResolvedSnaps()) {
4204
+ if (snap.size > 0 && allowed.includes(snap.id)) return snap.size;
4205
+ }
4206
+ return 0;
3728
4207
  }
3729
4208
  isDraggingAny() {
3730
4209
  return (this.gesture?.isDragging ?? false) || (this.contentGesture?.isDragging ?? false);
@@ -3749,9 +4228,10 @@ var BottomSheetCore = class {
3749
4228
  const offset = cap - clamped;
3750
4229
  const style = this.element.style;
3751
4230
  if (!skipTransform) style.transform = this.transformTemplate(offset);
4231
+ const moving = this.animation.isAnimating || this.isDraggingAny();
3752
4232
  const sizeChanged = this.sizeWriteSentinel.shouldWrite(
3753
4233
  clamped,
3754
- this.animation.isAnimating || this.isDraggingAny() ? SIZE_WRITE_EPSILON : 0
4234
+ moving ? SIZE_WRITE_EPSILON : 0
3755
4235
  );
3756
4236
  if (sizeChanged) {
3757
4237
  style.setProperty("--bs-size", `${clamped}px`);
@@ -3764,11 +4244,13 @@ var BottomSheetCore = class {
3764
4244
  if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
3765
4245
  this.rootEl.style.setProperty("--bs-size", `${clamped}px`);
3766
4246
  }
4247
+ this.homeRoot?.style.setProperty("--bs-size", `${clamped}px`);
3767
4248
  }
3768
4249
  const progress = this.computeProgress(clamped);
4250
+ const opacityEpsilon = moving ? OPACITY_WRITE_EPSILON : 0;
3769
4251
  const progressChanged = this.progressWriteSentinel.shouldWrite(
3770
4252
  progress,
3771
- OPACITY_WRITE_EPSILON
4253
+ opacityEpsilon
3772
4254
  );
3773
4255
  if (progressChanged) {
3774
4256
  style.setProperty("--bs-progress", String(progress));
@@ -3778,8 +4260,9 @@ var BottomSheetCore = class {
3778
4260
  if (this.rootEl && this.rootEl !== this.anchorHost) {
3779
4261
  this.rootEl.style.setProperty("--bs-progress", String(progress));
3780
4262
  }
4263
+ this.homeRoot?.style.setProperty("--bs-progress", String(progress));
3781
4264
  }
3782
- this.scrim.applyOpacity(progress, progressChanged);
4265
+ this.scrim.applyOpacity(progress, progressChanged, opacityEpsilon);
3783
4266
  if ((progressChanged || sizeChanged) && this.bus.listenerCount("progress") > 0) {
3784
4267
  this.progressPayload.value = progress;
3785
4268
  this.progressPayload.size = clamped;
@@ -3792,238 +4275,322 @@ var BottomSheetCore = class {
3792
4275
  if (reachableMax <= min) return 0;
3793
4276
  return Math.min(Math.max((size - min) / (reachableMax - min), 0), 1);
3794
4277
  }
3795
- handleOpen() {
3796
- if (this.promotedForOpen) this.promotedForOpen = false;
3797
- else sheetStack.promote(this.id);
3798
- try {
3799
- this.lifecycle.install();
3800
- } catch (err) {
3801
- if (!this.destroyed) this.newCycle();
3802
- this.handleClose();
3803
- this.applySize(0);
3804
- this.activeId = this.snapPointsRaw.find((p) => p.id === "closed")?.id ?? this.activeId;
3805
- this.size = 0;
3806
- queueMicrotask(() => {
3807
- throw err;
3808
- });
3809
- }
3810
- }
3811
- resyncAfterResize() {
3812
- if (this.destroyed) return;
3813
- const target = this.snaps.findById(this.activeId);
3814
- if (!target) return;
3815
- this.updateAriaSlider();
3816
- this.emit("snap", {
3817
- id: target.id,
3818
- size: this.size,
3819
- progress: this.computeProgress(this.size)
3820
- });
3821
- if (target.size > 0 && !this.lifecycle.isInstalled) {
3822
- this.emitOpenSequence(target.id);
3823
- } else if (target.size === 0 && this.lifecycle.isInstalled) {
3824
- this.emitCloseSequence();
3825
- }
3826
- }
3827
- handleClose() {
3828
- this.opening = false;
3829
- this.promotedForOpen = false;
3830
- this.lifecycle.release();
3831
- sheetStack.update();
3832
- }
3833
4278
  };
3834
4279
 
3835
4280
  // src/core/features/history-coordinator.ts
3836
- var entries = [];
3837
- var subscribers = /* @__PURE__ */ new Set();
3838
- var suppress = 0;
3839
- var internalDepth = 0;
3840
- var pendingRebrands = [];
3841
- var listenerInstalled = false;
3842
- var patchInstalled = false;
3843
- var origPushState = null;
3844
- var origReplaceState = null;
3845
- var patchedPushState = null;
3846
- var patchedReplaceState = null;
3847
- var hasWindow = () => typeof window !== "undefined";
3848
- var hasHistory = () => typeof history !== "undefined";
3849
- var brandMarker = (surface) => ({
4281
+ var MARKER = "__bs";
4282
+ var STACK = "__bsStack";
4283
+ var DEPTH = "__bsDepth";
4284
+ var ROUTED = "__bsRouted";
4285
+ var SETTLE_TIMEOUT_MS = 1e3;
4286
+ var state2 = shared(
4287
+ "history",
4288
+ () => ({
4289
+ live: [],
4290
+ stackId: void 0,
4291
+ baseUrl: void 0,
4292
+ position: null,
4293
+ knownLength: 0,
4294
+ href: "",
4295
+ subscribers: /* @__PURE__ */ new Set(),
4296
+ internal: 0,
4297
+ pending: [],
4298
+ deferred: [],
4299
+ waiters: [],
4300
+ timer: null,
4301
+ listening: false,
4302
+ leftovers: false,
4303
+ orphanChecked: false,
4304
+ push: null,
4305
+ replace: null
4306
+ })
4307
+ );
4308
+ var hasHistory = () => typeof window !== "undefined" && typeof history !== "undefined";
4309
+ var plain = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
4310
+ var depthOf = (value) => {
4311
+ const depth = value?.[DEPTH];
4312
+ return typeof depth === "number" ? depth : null;
4313
+ };
4314
+ var isMarker = (value) => value?.[MARKER] === true;
4315
+ var inStack = (value) => value !== null && state2.stackId !== void 0 && value[STACK] === state2.stackId && depthOf(value) !== null;
4316
+ var foreignKeys = (value) => {
4317
+ const out = {};
4318
+ const source = plain(value);
4319
+ if (!source) return out;
4320
+ for (const key of Object.keys(source)) {
4321
+ if (!key.startsWith(MARKER)) out[key] = source[key];
4322
+ }
4323
+ return out;
4324
+ };
4325
+ var markerFor = (surface, depth) => ({
4326
+ ...foreignKeys(history.state),
3850
4327
  ...surface.markerState(),
3851
- __bs: true
4328
+ [MARKER]: true,
4329
+ [STACK]: state2.stackId,
4330
+ [DEPTH]: depth
3852
4331
  });
4332
+ var urlForDepth = (depth) => {
4333
+ for (let i = depth - 1; i >= 0; i -= 1) {
4334
+ const url = state2.live[i]?.surface.url;
4335
+ if (url !== void 0) return url;
4336
+ }
4337
+ return state2.baseUrl;
4338
+ };
3853
4339
  var runInternal = (fn) => {
3854
- internalDepth += 1;
4340
+ state2.internal += 1;
3855
4341
  try {
3856
4342
  fn();
4343
+ return true;
4344
+ } catch {
4345
+ return false;
3857
4346
  } finally {
3858
- internalDepth -= 1;
4347
+ state2.internal -= 1;
3859
4348
  }
3860
4349
  };
3861
4350
  var notifyRouteChange = () => {
3862
- const snapshot = Array.from(subscribers);
3863
- for (const fn of snapshot) fn();
4351
+ for (const fn of Array.from(state2.subscribers)) {
4352
+ try {
4353
+ fn();
4354
+ } catch (err) {
4355
+ queueMicrotask(() => {
4356
+ throw err;
4357
+ });
4358
+ }
4359
+ }
3864
4360
  };
3865
4361
  var ensureListener = () => {
3866
- if (listenerInstalled || !hasWindow()) return;
4362
+ if (state2.listening || !hasHistory()) return;
3867
4363
  window.addEventListener("popstate", onPopState);
3868
- listenerInstalled = true;
4364
+ state2.listening = true;
3869
4365
  };
3870
4366
  var maybeTeardownListener = () => {
3871
- if (!listenerInstalled) return;
3872
- if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
3873
- if (hasWindow()) window.removeEventListener("popstate", onPopState);
3874
- listenerInstalled = false;
3875
- };
3876
- var installPatch = () => {
3877
- if (patchInstalled || !hasHistory()) return;
3878
- origPushState = history.pushState;
3879
- origReplaceState = history.replaceState;
3880
- patchedPushState = function(...args) {
3881
- origPushState.apply(this, args);
3882
- if (internalDepth === 0) notifyRouteChange();
3883
- };
3884
- patchedReplaceState = function(...args) {
3885
- origReplaceState.apply(this, args);
3886
- if (internalDepth === 0) notifyRouteChange();
3887
- };
3888
- history.pushState = patchedPushState;
3889
- history.replaceState = patchedReplaceState;
3890
- patchInstalled = true;
3891
- };
3892
- var removePatch = () => {
3893
- if (!patchInstalled) return;
3894
- if (history.pushState === patchedPushState && origPushState) {
3895
- history.pushState = origPushState;
3896
- }
3897
- if (history.replaceState === patchedReplaceState && origReplaceState) {
3898
- history.replaceState = origReplaceState;
3899
- }
3900
- origPushState = null;
3901
- origReplaceState = null;
3902
- patchedPushState = null;
3903
- patchedReplaceState = null;
3904
- patchInstalled = false;
3905
- };
3906
- function onPopState() {
3907
- if (suppress > 0) {
3908
- suppress -= 1;
3909
- const rebrand = pendingRebrands.shift();
3910
- if (rebrand) rebrand();
3911
- maybeTeardownListener();
4367
+ if (!state2.listening) return;
4368
+ if (state2.live.length > 0 || state2.subscribers.size > 0 || state2.pending.length > 0 || state2.leftovers) {
3912
4369
  return;
3913
4370
  }
3914
- if (entries.length === 0) {
3915
- notifyRouteChange();
3916
- maybeTeardownListener();
3917
- return;
3918
- }
3919
- let target = null;
3920
- let targetIdx = -1;
3921
- for (let i = entries.length - 1; i >= 0; i -= 1) {
3922
- const entry = entries[i];
3923
- if (!entry.surface.isOpen()) continue;
3924
- if (!target) {
3925
- target = entry;
3926
- targetIdx = i;
3927
- }
3928
- if (entry.surface.isTop()) {
3929
- target = entry;
3930
- targetIdx = i;
3931
- break;
3932
- }
3933
- }
3934
- if (!target) {
3935
- const removed = entries.pop();
3936
- if (removed) removed.live = false;
4371
+ if (hasHistory()) window.removeEventListener("popstate", onPopState);
4372
+ state2.listening = false;
4373
+ };
4374
+ var settleIfIdle = () => {
4375
+ if (state2.pending.length > 0) return;
4376
+ if (state2.timer !== null) {
4377
+ clearTimeout(state2.timer);
4378
+ state2.timer = null;
4379
+ }
4380
+ for (const entry of state2.deferred.splice(0)) pushEntry(entry);
4381
+ for (const resolve of state2.waiters.splice(0)) resolve();
4382
+ };
4383
+ var traverse = (delta, kind) => {
4384
+ state2.pending.push(kind);
4385
+ if (state2.timer !== null) clearTimeout(state2.timer);
4386
+ state2.timer = setTimeout(() => {
4387
+ state2.timer = null;
4388
+ state2.pending.length = 0;
4389
+ settleIfIdle();
3937
4390
  maybeTeardownListener();
3938
- return;
3939
- }
3940
- target.live = false;
3941
- entries.splice(targetIdx, 1);
3942
- const settled = target;
3943
- void Promise.resolve(settled.surface.close()).then(() => {
3944
- if (settled.surface.isOpen()) restore(settled);
4391
+ }, SETTLE_TIMEOUT_MS);
4392
+ ensureListener();
4393
+ const moved = runInternal(() => {
4394
+ if (delta < 0) history.back();
4395
+ else history.forward();
3945
4396
  });
3946
- maybeTeardownListener();
3947
- }
3948
- function restore(entry) {
3949
- if (!hasWindow() || !hasHistory()) return;
3950
- entry.live = true;
4397
+ if (!moved) {
4398
+ state2.pending.pop();
4399
+ settleIfIdle();
4400
+ }
4401
+ };
4402
+ var newStackId = () => `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
4403
+ var startStack = () => {
4404
+ state2.stackId = newStackId();
4405
+ const current = history.state;
4406
+ const leftover = plain(current);
4407
+ state2.baseUrl = isMarker(leftover) && leftover?.[ROUTED] !== void 0 ? void 0 : location.href;
4408
+ if (isMarker(leftover)) return;
4409
+ if (current !== null && current !== void 0 && !leftover) return;
3951
4410
  runInternal(() => {
3952
- try {
3953
- history.pushState(brandMarker(entry.surface), "", entry.surface.url);
3954
- } catch {
3955
- entry.live = false;
3956
- }
4411
+ history.replaceState(
4412
+ { ...foreignKeys(current), [STACK]: state2.stackId, [DEPTH]: 0 },
4413
+ "",
4414
+ location.href
4415
+ );
3957
4416
  });
3958
- if (entry.live) {
3959
- entries.push(entry);
3960
- ensureListener();
3961
- }
4417
+ };
4418
+ function pushEntry(entry) {
4419
+ const depth = state2.live.length + 1;
4420
+ if (state2.live.length === 0) startStack();
4421
+ const written = runInternal(() => {
4422
+ history.pushState(markerFor(entry.surface, depth), "", entry.surface.url);
4423
+ });
4424
+ if (!written) return false;
4425
+ state2.live.push(entry);
4426
+ state2.position = depth;
4427
+ state2.knownLength = history.length;
4428
+ state2.href = location.href;
4429
+ ensureListener();
4430
+ return true;
3962
4431
  }
3963
- function pushBackMarker(surface) {
3964
- const entry = { surface, priorUrl: void 0, live: false };
3965
- if (!hasWindow() || !hasHistory()) {
3966
- return entry;
4432
+ var enlist = (entry) => {
4433
+ if (state2.pending.length > 0) state2.deferred.push(entry);
4434
+ else pushEntry(entry);
4435
+ };
4436
+ var sameBrand = (a, b) => {
4437
+ for (const key of /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)])) {
4438
+ if (key.startsWith(MARKER) && a[key] !== b[key]) return false;
3967
4439
  }
3968
- entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
4440
+ return true;
4441
+ };
4442
+ var rebrand = (depth) => {
4443
+ const entry = state2.live[depth - 1];
4444
+ if (!entry) return;
4445
+ const url = urlForDepth(depth);
4446
+ const marker = markerFor(entry.surface, depth);
4447
+ const atUrl = url === void 0 || new URL(url, location.href).href === location.href;
4448
+ if (atUrl && sameBrand(plain(history.state) ?? {}, marker)) return;
3969
4449
  runInternal(() => {
4450
+ history.replaceState(marker, "", url);
4451
+ });
4452
+ state2.href = location.href;
4453
+ };
4454
+ var closeAbove = (depth) => {
4455
+ const dropped = state2.live.splice(depth);
4456
+ for (let i = dropped.length - 1; i >= 0; i -= 1) {
4457
+ const entry = dropped[i];
4458
+ let closing = void 0;
3970
4459
  try {
3971
- history.pushState(brandMarker(surface), "", surface.url);
3972
- entry.live = true;
3973
- } catch {
3974
- entry.live = false;
4460
+ closing = entry.surface.close();
4461
+ } catch (err) {
4462
+ queueMicrotask(() => {
4463
+ throw err;
4464
+ });
3975
4465
  }
3976
- });
3977
- if (entry.live) {
3978
- entries.push(entry);
3979
- ensureListener();
4466
+ void Promise.resolve(closing).then(() => {
4467
+ if (!entry.surface.isOpen()) return;
4468
+ const known = (e) => e.surface === entry.surface;
4469
+ if (state2.live.some(known) || state2.deferred.some(known)) return;
4470
+ enlist(entry);
4471
+ });
4472
+ }
4473
+ };
4474
+ function onPopState(event) {
4475
+ const kind = state2.pending.shift();
4476
+ const byUser = kind !== "pop";
4477
+ const landed = plain(event.state);
4478
+ const depth = depthOf(landed);
4479
+ const from = state2.position;
4480
+ const liveBefore = state2.live.length;
4481
+ const grew = history.length > state2.knownLength;
4482
+ state2.knownLength = history.length;
4483
+ const within = inStack(landed);
4484
+ if (within && depth !== null) {
4485
+ state2.position = depth;
4486
+ if (depth > state2.live.length) {
4487
+ const forward = from !== null && from < depth;
4488
+ traverse(forward ? 1 : -1, byUser ? "skip" : "pop");
4489
+ } else if (depth < state2.live.length) {
4490
+ if (byUser) closeAbove(depth);
4491
+ } else {
4492
+ rebrand(depth);
4493
+ }
4494
+ } else if (isMarker(landed)) {
4495
+ state2.position = null;
4496
+ traverse(-1, byUser ? "skip" : "pop");
4497
+ } else {
4498
+ state2.position = null;
4499
+ if (byUser && !grew && state2.live.length > 0) {
4500
+ closeAbove(state2.live.length - 1);
4501
+ }
4502
+ }
4503
+ const moved = location.href !== state2.href;
4504
+ state2.href = location.href;
4505
+ if (kind === void 0 && moved && (liveBefore === 0 || !within)) {
4506
+ notifyRouteChange();
3980
4507
  }
4508
+ settleIfIdle();
4509
+ maybeTeardownListener();
4510
+ }
4511
+ function pushBackMarker(surface) {
4512
+ const entry = { surface };
4513
+ if (hasHistory()) enlist(entry);
3981
4514
  return entry;
3982
4515
  }
3983
4516
  function popBackMarker(handle) {
3984
- if (!hasWindow() || !hasHistory()) return;
4517
+ if (!hasHistory()) return Promise.resolve();
3985
4518
  const entry = handle;
3986
- const idx = entries.indexOf(entry);
3987
- if (idx === -1 || !entry.live) return;
3988
- const last = entries.length - 1;
3989
- entry.live = false;
3990
- entries.splice(idx, 1);
3991
- let rebrand = null;
3992
- if (idx !== last) {
3993
- const rebrandSurface = entries[entries.length - 1].surface;
3994
- const rebrandUrl = entry.priorUrl;
3995
- rebrand = () => {
3996
- runInternal(() => {
3997
- history.replaceState(
3998
- brandMarker(rebrandSurface),
3999
- "",
4000
- rebrandUrl !== void 0 ? rebrandUrl : location.href
4001
- );
4002
- });
4003
- };
4519
+ const waiting = state2.deferred.indexOf(entry);
4520
+ if (waiting !== -1) state2.deferred.splice(waiting, 1);
4521
+ const idx = state2.live.indexOf(entry);
4522
+ if (idx === -1) return historySettled();
4523
+ const top = state2.live.length;
4524
+ state2.live.splice(idx, 1);
4525
+ const current = plain(history.state);
4526
+ const onTop = isMarker(current) && inStack(current) && depthOf(current) === top;
4527
+ if (onTop && state2.pending.length === 0) {
4528
+ traverse(-1, "pop");
4529
+ } else {
4530
+ state2.leftovers = true;
4531
+ ensureListener();
4004
4532
  }
4005
- pendingRebrands.push(rebrand);
4006
- suppress += 1;
4007
- runInternal(() => {
4008
- try {
4009
- history.back();
4010
- } catch {
4011
- suppress = Math.max(0, suppress - 1);
4012
- pendingRebrands.pop();
4013
- }
4014
- });
4015
4533
  maybeTeardownListener();
4534
+ return historySettled();
4016
4535
  }
4536
+ function releaseOrphanMarker() {
4537
+ if (!hasHistory() || state2.orphanChecked) return;
4538
+ state2.orphanChecked = true;
4539
+ if (state2.live.length > 0 || state2.pending.length > 0) return;
4540
+ if (!isMarker(plain(history.state))) return;
4541
+ state2.leftovers = true;
4542
+ traverse(-1, "pop");
4543
+ }
4544
+ function historySettled() {
4545
+ if (state2.pending.length === 0) return Promise.resolve();
4546
+ return new Promise((resolve) => {
4547
+ state2.waiters.push(resolve);
4548
+ });
4549
+ }
4550
+ var wrap = (original) => function(...args) {
4551
+ original.apply(this, args);
4552
+ state2.knownLength = history.length;
4553
+ if (location.href === state2.href) return;
4554
+ state2.href = location.href;
4555
+ if (state2.internal === 0 && state2.subscribers.size > 0) {
4556
+ notifyRouteChange();
4557
+ }
4558
+ };
4559
+ var installPatch = () => {
4560
+ if (!state2.push || history.pushState === state2.push.original) {
4561
+ const original = history.pushState;
4562
+ const wrapper = wrap(original);
4563
+ history.pushState = wrapper;
4564
+ state2.push = { wrapper, original };
4565
+ }
4566
+ if (!state2.replace || history.replaceState === state2.replace.original) {
4567
+ const original = history.replaceState;
4568
+ const wrapper = wrap(original);
4569
+ history.replaceState = wrapper;
4570
+ state2.replace = { wrapper, original };
4571
+ }
4572
+ };
4573
+ var removePatch = () => {
4574
+ if (state2.push && history.pushState === state2.push.wrapper) {
4575
+ history.pushState = state2.push.original;
4576
+ state2.push = null;
4577
+ }
4578
+ if (state2.replace && history.replaceState === state2.replace.wrapper) {
4579
+ history.replaceState = state2.replace.original;
4580
+ state2.replace = null;
4581
+ }
4582
+ };
4017
4583
  function subscribeRouteChange(fn) {
4018
- if (!hasWindow() || !hasHistory()) return () => {
4584
+ if (!hasHistory()) return () => {
4019
4585
  };
4020
- subscribers.add(fn);
4021
- if (subscribers.size === 1) installPatch();
4586
+ state2.subscribers.add(fn);
4587
+ state2.href = location.href;
4588
+ state2.knownLength = history.length;
4589
+ installPatch();
4022
4590
  ensureListener();
4023
4591
  return () => {
4024
- if (!subscribers.has(fn)) return;
4025
- subscribers.delete(fn);
4026
- if (subscribers.size === 0) removePatch();
4592
+ if (!state2.subscribers.delete(fn)) return;
4593
+ if (state2.subscribers.size === 0) removePatch();
4027
4594
  maybeTeardownListener();
4028
4595
  };
4029
4596
  }
@@ -4039,36 +4606,37 @@ function installRoute(deps) {
4039
4606
  };
4040
4607
  }
4041
4608
  let handle = null;
4609
+ const surface = {
4610
+ isOpen: () => !deps.isDestroyed() && deps.isOpen(),
4611
+ close: deps.close,
4612
+ markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
4613
+ url: deps.routedTo
4614
+ };
4042
4615
  const onOpen = () => {
4043
4616
  if (handle) return;
4044
- handle = pushBackMarker({
4045
- isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
4046
- isTop: deps.isTopSheet,
4047
- close: deps.close,
4048
- markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
4049
- url: deps.routedTo
4050
- });
4617
+ handle = pushBackMarker(surface);
4051
4618
  };
4052
4619
  const onClose = () => {
4053
4620
  if (!handle) return;
4054
- popBackMarker(handle);
4621
+ deps.hold(popBackMarker(handle));
4055
4622
  handle = null;
4056
4623
  };
4057
4624
  const unsubscribeOpen = deps.on("open", onOpen);
4058
4625
  const unsubscribeClose = deps.on("close", onClose);
4059
- if (deps.getSize() > 0) onOpen();
4626
+ if (deps.isOpen()) onOpen();
4627
+ else releaseOrphanMarker();
4060
4628
  return () => {
4061
4629
  unsubscribeOpen();
4062
4630
  unsubscribeClose();
4063
4631
  if (handle) {
4064
- popBackMarker(handle);
4632
+ void popBackMarker(handle);
4065
4633
  handle = null;
4066
4634
  }
4067
4635
  };
4068
4636
  }
4069
4637
  function installRouteChange(deps) {
4070
4638
  return subscribeRouteChange(() => {
4071
- if (deps.isDestroyed() || deps.getSize() <= 0) return;
4639
+ if (deps.isDestroyed() || !deps.isOpen()) return;
4072
4640
  void deps.close();
4073
4641
  });
4074
4642
  }
@@ -4102,7 +4670,10 @@ function installAutoCollapse(deps) {
4102
4670
  };
4103
4671
  const fire = () => {
4104
4672
  if (deps.isDestroyed()) return;
4105
- if (deps.isDragging()) return;
4673
+ if (deps.isDragging() || deps.isAnimating()) {
4674
+ reset2();
4675
+ return;
4676
+ }
4106
4677
  const active = deps.resolveSnap(deps.getActiveId());
4107
4678
  if (!active || active.size === 0) return;
4108
4679
  let target = null;
@@ -4139,6 +4710,9 @@ function installContentDrag(deps) {
4139
4710
 
4140
4711
  // src/core/features/visual-viewport.ts
4141
4712
  var SAFETY_PAD = 8;
4713
+ var KEYBOARD_MIN_INSET = 1;
4714
+ var KEYBOARD_MIN_COVER = 60;
4715
+ var ZOOMED = 1.01;
4142
4716
  function installVisualViewport(deps) {
4143
4717
  if (typeof window === "undefined" || !window.visualViewport) {
4144
4718
  return () => {
@@ -4146,36 +4720,36 @@ function installVisualViewport(deps) {
4146
4720
  }
4147
4721
  const vv = window.visualViewport;
4148
4722
  let rafId = null;
4723
+ const coveredByKeyboard = () => {
4724
+ if ((vv.scale || 1) > ZOOMED) return 0;
4725
+ const covered = window.innerHeight - ((vv.offsetTop || 0) + vv.height);
4726
+ return covered >= KEYBOARD_MIN_COVER ? Math.round(covered) : 0;
4727
+ };
4149
4728
  const onResize = () => {
4150
4729
  if (rafId !== null) return;
4151
4730
  rafId = requestAnimationFrame(() => {
4152
4731
  rafId = null;
4153
4732
  if (deps.isDestroyed()) return;
4733
+ deps.setKeyboardInset(coveredByKeyboard());
4734
+ const before = seatOf(deps);
4154
4735
  deps.recomputeSnaps();
4155
4736
  const isVertical = deps.isVerticalAxis();
4156
4737
  const visible = isVertical ? vv.height : vv.width;
4157
4738
  const windowSize = isVertical ? window.innerHeight : window.innerWidth;
4158
- const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
4739
+ const pad = windowSize - visible > KEYBOARD_MIN_INSET ? SAFETY_PAD : 0;
4740
+ const clamp = Math.max(0, Math.min(windowSize, visible) - pad);
4159
4741
  if (clamp < deps.getMaxAxisSize()) {
4160
4742
  deps.setMaxAxisSize(clamp);
4161
4743
  }
4162
- const wasAnimating = deps.isAnimating?.() ?? false;
4163
- deps.cancelInFlight();
4164
- deps.newCycle();
4165
- const max = deps.getMaxAxisSize();
4166
- deps.setSize(Math.min(deps.getSize(), max));
4167
- const current = deps.resolveActiveSnap();
4168
- if (current && !deps.isDragging()) {
4169
- deps.applySize(Math.min(current.size, max));
4170
- if (wasAnimating) deps.resyncAfterCancel?.();
4171
- } else {
4172
- deps.applySize(deps.getSize());
4173
- }
4744
+ if (sameSeat(before, seatOf(deps))) return;
4745
+ deps.reseat();
4174
4746
  });
4175
4747
  };
4176
4748
  vv.addEventListener("resize", onResize);
4749
+ vv.addEventListener("scroll", onResize);
4177
4750
  return () => {
4178
4751
  vv.removeEventListener("resize", onResize);
4752
+ vv.removeEventListener("scroll", onResize);
4179
4753
  if (rafId !== null) cancelAnimationFrame(rafId);
4180
4754
  };
4181
4755
  }
@@ -4190,7 +4764,7 @@ function routeFeature() {
4190
4764
  teardowns.add(
4191
4765
  installRouteChange({
4192
4766
  isDestroyed: ctx.isDestroyed,
4193
- getSize: ctx.getSize,
4767
+ isOpen: () => ctx.getPhase() !== "closed",
4194
4768
  close: () => ctx.close()
4195
4769
  })
4196
4770
  );
@@ -4199,10 +4773,10 @@ function routeFeature() {
4199
4773
  installRoute({
4200
4774
  routedTo: ctx.options.routedTo,
4201
4775
  closeOnBack: ctx.options.closeOnBack,
4202
- isTopSheet: ctx.isTopSheet,
4203
- getSize: ctx.getSize,
4776
+ isOpen: () => ctx.getPhase() !== "closed",
4204
4777
  isDestroyed: ctx.isDestroyed,
4205
4778
  close: () => ctx.close("back"),
4779
+ hold: ctx.holdSettle,
4206
4780
  on: ctx.on,
4207
4781
  sheetId: ctx.sheetId
4208
4782
  })
@@ -4228,6 +4802,7 @@ function autoCollapseFeature() {
4228
4802
  ms: ctx.options.autoCollapseAfter,
4229
4803
  isDestroyed: ctx.isDestroyed,
4230
4804
  isDragging: ctx.isDragging,
4805
+ isAnimating: ctx.isAnimating,
4231
4806
  getAllowedIds: ctx.getAllowedIds,
4232
4807
  getActiveId: ctx.getActiveId,
4233
4808
  resolveSnap: ctx.resolveSnap,
@@ -4255,21 +4830,14 @@ function visualViewportFeature() {
4255
4830
  install: (ctx) => {
4256
4831
  if (typeof window === "undefined") return;
4257
4832
  return installVisualViewport({
4258
- element: ctx.element,
4259
4833
  isVerticalAxis: ctx.isVerticalAxis,
4260
4834
  isDestroyed: ctx.isDestroyed,
4261
- isDragging: ctx.isDragging,
4262
4835
  recomputeSnaps: ctx.recomputeSnaps,
4263
4836
  resolveActiveSnap: ctx.resolveActiveSnap,
4264
4837
  getMaxAxisSize: ctx.getMaxAxisSize,
4265
- getSize: ctx.getSize,
4266
4838
  setMaxAxisSize: ctx.setMaxAxisSize,
4267
- setSize: ctx.setSize,
4268
- applySize: ctx.applySize,
4269
- cancelInFlight: ctx.cancelInFlight,
4270
- newCycle: ctx.newCycle,
4271
- isAnimating: ctx.isAnimating,
4272
- resyncAfterCancel: ctx.resyncAfterResize
4839
+ setKeyboardInset: ctx.setKeyboardInset,
4840
+ reseat: ctx.reseat
4273
4841
  });
4274
4842
  }
4275
4843
  };
@@ -4433,42 +5001,14 @@ var BottomSheetEngine = class extends BottomSheetCore {
4433
5001
  }
4434
5002
  };
4435
5003
 
4436
- // src/core/features/teleport.ts
4437
- var resolveTeleportTarget = (target) => {
4438
- if (!target) return null;
4439
- if (typeof target !== "string") return target;
4440
- if (typeof document === "undefined") return null;
4441
- if (target === "body") return document.body;
4442
- return document.querySelector(target);
4443
- };
4444
- var teleportElements = (els, target) => {
4445
- const records = [];
4446
- for (const el of els) {
4447
- if (!el || el.parentNode === target) continue;
4448
- records.push({ el, parent: el.parentNode, next: el.nextSibling });
4449
- target.appendChild(el);
4450
- }
4451
- return () => {
4452
- for (let i = records.length - 1; i >= 0; i--) {
4453
- const { el, parent, next } = records[i];
4454
- if (parent && parent.isConnected) {
4455
- const before = next && next.parentNode === parent ? next : null;
4456
- try {
4457
- parent.insertBefore(el, before);
4458
- } catch {
4459
- el.parentNode?.removeChild(el);
4460
- }
4461
- } else {
4462
- el.parentNode?.removeChild(el);
4463
- }
4464
- }
4465
- };
4466
- };
5004
+ // src/core/primitives/open-state.ts
5005
+ var closedSnapId = (points) => points.find((point) => point.size === 0)?.id;
4467
5006
 
4468
5007
  // src/svelte/useBottomSheet.svelte.ts
4469
5008
  var SSR_STATE = Object.freeze({
4470
5009
  size: 0,
4471
5010
  activeId: "",
5011
+ phase: "closed",
4472
5012
  isDragging: false,
4473
5013
  isAnimating: false,
4474
5014
  progress: 0
@@ -4478,21 +5018,11 @@ function createBottomSheet(opts) {
4478
5018
  const pending = [];
4479
5019
  const attach = (refs) => {
4480
5020
  if (engine) engine.destroy();
4481
- const {
4482
- onSnap,
4483
- teleportTo,
4484
- backdropColor,
4485
- backdropOpacity,
4486
- ...engineOpts
4487
- } = opts;
4488
- const created = new BottomSheetEngine({ ...engineOpts, ...refs });
4489
- engine = created;
5021
+ const { onSnap, teleportTo, ...engineOpts } = opts;
4490
5022
  const target = resolveTeleportTarget(teleportTo);
4491
5023
  const restoreTeleport = target ? teleportElements([refs.backdrop, refs.scrim, refs.element], target) : null;
4492
- if (backdropColor !== void 0) created.setScrimColor(backdropColor);
4493
- if (backdropOpacity !== void 0) {
4494
- created.setBackdropRange([0, backdropOpacity]);
4495
- }
5024
+ const created = new BottomSheetEngine({ ...engineOpts, ...refs });
5025
+ engine = created;
4496
5026
  if (onSnap) {
4497
5027
  created.on("snap", (payload) => onSnap(payload.id));
4498
5028
  }
@@ -4525,7 +5055,7 @@ function createBottomSheet(opts) {
4525
5055
  },
4526
5056
  snapTo: (id) => engine?.snapTo(id) ?? Promise.resolve(),
4527
5057
  open: (id) => engine?.open(id) ?? Promise.resolve(),
4528
- close: () => engine?.close() ?? Promise.resolve(),
5058
+ close: (reason) => engine?.close(reason) ?? Promise.resolve(),
4529
5059
  expand: () => engine?.expand() ?? Promise.resolve(),
4530
5060
  collapse: () => engine?.collapse() ?? Promise.resolve(),
4531
5061
  isTop: () => engine?.isTop() ?? false,
@@ -4547,32 +5077,98 @@ function createBottomSheet(opts) {
4547
5077
  getEngine: () => engine
4548
5078
  };
4549
5079
  }
5080
+ var rest_excludes = /* @__PURE__ */ new Set([
5081
+ "$$slots",
5082
+ "$$events",
5083
+ "$$legacy",
5084
+ "snapPoints",
5085
+ "allowed",
5086
+ "initial",
5087
+ "mode",
5088
+ "animation",
5089
+ "spring",
5090
+ "focusTrap",
5091
+ "closeOnEscape",
5092
+ "closeOnBack",
5093
+ "lockBodyScroll",
5094
+ "rubberBand",
5095
+ "backdropRange",
5096
+ "backdrop",
5097
+ "closeOnBackdrop",
5098
+ "persistent",
5099
+ "disableClose",
5100
+ "disableDrag",
5101
+ "dragFrom",
5102
+ "dragFromContent",
5103
+ "fitContentToSnap",
5104
+ "closeOnRouteChange",
5105
+ "stackEffect",
5106
+ "teleport",
5107
+ "teleportTo",
5108
+ "radius",
5109
+ "maxHeight",
5110
+ "backdropColor",
5111
+ "backdropOpacity",
5112
+ "open",
5113
+ "snap",
5114
+ "returnFocusTo",
5115
+ "ariaLabel",
5116
+ "handleLabel",
5117
+ "contentLabel",
5118
+ "header",
5119
+ "footer",
5120
+ "leftButton",
5121
+ "rightButton",
5122
+ "screen",
5123
+ "children",
5124
+ "onsnap",
5125
+ "onbeforesnap",
5126
+ "onopen",
5127
+ "onclose",
5128
+ "onbeforeclose",
5129
+ "onopened",
5130
+ "onclosed",
5131
+ "ondragstart",
5132
+ "ondragend",
5133
+ "ondrag",
5134
+ "onprogress",
5135
+ "onchange"
5136
+ ]);
4550
5137
  var root = $2.from_html(`<div class="bs-backdrop" aria-hidden="true"></div>`);
4551
5138
  var root_1 = $2.from_html(`<div class="bs-header"><!></div>`);
4552
5139
  var root_2 = $2.from_html(`<div class="bs-footer"><!></div>`);
4553
5140
  var root_3 = $2.from_html(`<div class="bs-button-slot" data-side="left"><!></div>`);
4554
5141
  var root_4 = $2.from_html(`<div class="bs-button-slot" data-side="right"><!></div>`);
4555
- var root_5 = $2.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>`);
5142
+ var root_5 = $2.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>`);
4556
5143
  function BottomSheet($$anchor, $$props) {
4557
5144
  $2.push($$props, true);
4558
- let mode = $2.prop($$props, "mode", 3, "bottom"), animation = $2.prop($$props, "animation", 3, "spring"), focusTrap = $2.prop($$props, "focusTrap", 3, false), closeOnEscape = $2.prop($$props, "closeOnEscape", 3, true), closeOnBack = $2.prop($$props, "closeOnBack", 3, false), lockBodyScroll2 = $2.prop($$props, "lockBodyScroll", 3, true), rubberBand2 = $2.prop($$props, "rubberBand", 3, true), backdrop = $2.prop($$props, "backdrop", 3, true), closeOnBackdrop = $2.prop($$props, "closeOnBackdrop", 3, true), persistent = $2.prop($$props, "persistent", 3, false), disableClose = $2.prop($$props, "disableClose", 3, false), disableDrag = $2.prop($$props, "disableDrag", 3, false), closeOnRouteChange = $2.prop($$props, "closeOnRouteChange", 3, false), stackEffect = $2.prop($$props, "stackEffect", 3, false), teleport = $2.prop($$props, "teleport", 3, false), openProp = $2.prop($$props, "open", 15), snap = $2.prop($$props, "snap", 15), ariaLabel = $2.prop($$props, "ariaLabel", 3, "Bottom sheet");
5145
+ let mode = $2.prop($$props, "mode", 3, "bottom"), animation = $2.prop($$props, "animation", 3, "spring"), focusTrap = $2.prop($$props, "focusTrap", 3, false), closeOnEscape = $2.prop($$props, "closeOnEscape", 3, true), closeOnBack = $2.prop($$props, "closeOnBack", 3, false), lockBodyScroll2 = $2.prop($$props, "lockBodyScroll", 3, true), rubberBand2 = $2.prop($$props, "rubberBand", 3, true), backdrop = $2.prop($$props, "backdrop", 3, true), closeOnBackdrop = $2.prop($$props, "closeOnBackdrop", 3, true), persistent = $2.prop($$props, "persistent", 3, false), disableClose = $2.prop($$props, "disableClose", 3, false), disableDrag = $2.prop($$props, "disableDrag", 3, false), closeOnRouteChange = $2.prop($$props, "closeOnRouteChange", 3, false), stackEffect = $2.prop($$props, "stackEffect", 3, false), openProp = $2.prop($$props, "open", 15), snap = $2.prop($$props, "snap", 15), ariaLabel = $2.prop($$props, "ariaLabel", 3, "Bottom sheet"), handleLabel = $2.prop($$props, "handleLabel", 3, "Resize sheet"), contentLabel = $2.prop($$props, "contentLabel", 3, "Sheet content"), engineRest = $2.rest_props($$props, rest_excludes);
4559
5146
  let sheetEl = $2.state(void 0);
4560
5147
  let handleEl = $2.state(void 0);
4561
5148
  let contentEl = $2.state(void 0);
4562
5149
  let backdropEl = $2.state(void 0);
4563
5150
  let screenEl = $2.state(void 0);
5151
+ const startAt = untrack(() => $$props.initial ?? (openProp() === false ? closedSnapId($$props.snapPoints) : void 0) ?? snap());
4564
5152
  let viewState = $2.state($2.proxy({
4565
5153
  size: 0,
4566
- activeId: untrack(() => $$props.initial ?? $$props.snapPoints[0]?.id ?? "default"),
5154
+ activeId: untrack(() => startAt ?? $$props.snapPoints[0]?.id ?? "default"),
5155
+ phase: "closed",
4567
5156
  isDragging: false,
4568
5157
  isAnimating: false,
4569
5158
  progress: 0
4570
5159
  }));
4571
5160
  let engine = null;
4572
5161
  let restoreTeleport = null;
5162
+ let physicalMode = $2.state($2.proxy(untrack(() => guessPhysicalMode(mode()))));
5163
+ const restAtStart = untrack(() => startsClosed($$props.snapPoints, startAt, $$props.allowed) ? "closed" : void 0);
4573
5164
  onMount(() => {
4574
5165
  if (!$2.get(sheetEl)) return;
5166
+ const teleportTarget = $$props.teleport === false ? null : resolveTeleportTarget($$props.teleportTo);
5167
+ if (teleportTarget) {
5168
+ restoreTeleport = teleportElements([$2.get(backdropEl), $2.get(screenEl), $2.get(sheetEl)], teleportTarget);
5169
+ }
4575
5170
  engine = new BottomSheetEngine({
5171
+ ...engineRest,
4576
5172
  element: $2.get(sheetEl),
4577
5173
  handle: $2.get(handleEl),
4578
5174
  scrollContainer: $2.get(contentEl),
@@ -4581,7 +5177,7 @@ function BottomSheet($$anchor, $$props) {
4581
5177
  mode: mode(),
4582
5178
  snapPoints: $$props.snapPoints,
4583
5179
  allowed: $$props.allowed,
4584
- initial: $$props.initial,
5180
+ initial: startAt,
4585
5181
  animation: animation(),
4586
5182
  spring: $$props.spring,
4587
5183
  focusTrap: focusTrap(),
@@ -4600,44 +5196,52 @@ function BottomSheet($$anchor, $$props) {
4600
5196
  stackEffect: stackEffect(),
4601
5197
  radius: $$props.radius,
4602
5198
  maxHeight: $$props.maxHeight,
4603
- returnFocusTo: $$props.returnFocusTo
5199
+ returnFocusTo: $$props.returnFocusTo,
5200
+ backdropColor: $$props.backdropColor,
5201
+ backdropOpacity: $$props.backdropOpacity
4604
5202
  });
4605
- const teleportTarget = teleport() === false ? null : resolveTeleportTarget($$props.teleportTo);
4606
- if (teleportTarget) {
4607
- restoreTeleport = teleportElements([$2.get(backdropEl), $2.get(screenEl), $2.get(sheetEl)], teleportTarget);
4608
- }
4609
5203
  const sync = () => {
4610
5204
  if (!engine) return;
4611
5205
  $2.set(viewState, { ...engine.state }, true);
4612
5206
  $$props.onchange?.($2.get(viewState));
4613
5207
  };
5208
+ $2.set(physicalMode, engine.getMode(), true);
4614
5209
  sync();
4615
- if ($$props.backdropColor !== void 0) engine.setScrimColor($$props.backdropColor);
4616
- if ($$props.backdropOpacity !== void 0) engine.setBackdropRange([0, $$props.backdropOpacity]);
5210
+ if (snap() !== void 0 && snap() !== engine.state.activeId) {
5211
+ snap(engine.state.activeId);
5212
+ }
4617
5213
  engine.on("snap", (payload) => {
4618
5214
  sync();
4619
5215
  snap(payload.id);
4620
5216
  $$props.onsnap?.(payload.id);
4621
5217
  });
4622
5218
  engine.on("open", (payload) => {
5219
+ sync();
4623
5220
  openProp(true);
4624
5221
  $$props.onopen?.(payload.id);
4625
5222
  });
4626
5223
  engine.on("close", () => {
5224
+ sync();
4627
5225
  openProp(false);
4628
5226
  $$props.onclose?.();
4629
5227
  });
4630
5228
  engine.on("before-close", (payload) => $$props.onbeforeclose?.(payload));
4631
5229
  engine.on("before-snap", (payload) => $$props.onbeforesnap?.(payload));
4632
- engine.on("opened", (payload) => $$props.onopened?.(payload.id));
4633
- engine.on("closed", () => $$props.onclosed?.());
4634
- engine.on("dragstart", () => {
5230
+ engine.on("opened", (payload) => {
5231
+ sync();
5232
+ $$props.onopened?.(payload.id);
5233
+ });
5234
+ engine.on("closed", () => {
4635
5235
  sync();
4636
- $$props.ondragstart?.();
5236
+ $$props.onclosed?.();
4637
5237
  });
4638
- engine.on("dragend", () => {
5238
+ engine.on("dragstart", (payload) => {
4639
5239
  sync();
4640
- $$props.ondragend?.();
5240
+ $$props.ondragstart?.(payload);
5241
+ });
5242
+ engine.on("dragend", (payload) => {
5243
+ sync();
5244
+ $$props.ondragend?.(payload);
4641
5245
  });
4642
5246
  if ($$props.ondrag) engine.on("drag", (payload) => $$props.ondrag(payload));
4643
5247
  if ($$props.onprogress) engine.on("progress", (payload) => $$props.onprogress(payload));
@@ -4650,7 +5254,7 @@ function BottomSheet($$anchor, $$props) {
4650
5254
  });
4651
5255
  const snapTo = (id) => engine?.snapTo(id) ?? Promise.resolve();
4652
5256
  const open = (id) => engine?.open(id) ?? Promise.resolve();
4653
- const close = () => engine?.close() ?? Promise.resolve();
5257
+ const close = (reason) => engine?.close(reason) ?? Promise.resolve();
4654
5258
  const expand = () => engine?.expand() ?? Promise.resolve();
4655
5259
  const collapse = () => engine?.collapse() ?? Promise.resolve();
4656
5260
  const isTop = () => engine?.isTop() ?? false;
@@ -4660,6 +5264,11 @@ function BottomSheet($$anchor, $$props) {
4660
5264
  const setScrim = (opts) => engine?.setScrim(opts);
4661
5265
  const setScrimOverlay = (opts) => engine?.setScrimOverlay(opts) ?? (() => {
4662
5266
  });
5267
+ const addAnchor = (opts) => engine?.addAnchor(opts) ?? (() => {
5268
+ });
5269
+ const setScrimStages = (opts) => engine?.setScrimStages(opts) ?? (() => {
5270
+ });
5271
+ const recompute = () => engine?.recompute();
4663
5272
  const setRadius = (r) => engine?.setRadius(r);
4664
5273
  const setMaxHeight = (h) => engine?.setMaxHeight(h);
4665
5274
  const canDismiss = () => engine?.canDismiss() ?? false;
@@ -4701,7 +5310,9 @@ function BottomSheet($$anchor, $$props) {
4701
5310
  if ($$props.dragFrom !== void 0) engine?.setDragFrom($$props.dragFrom);
4702
5311
  });
4703
5312
  $2.user_effect(() => {
4704
- if (mode() !== void 0) engine?.setMode(mode());
5313
+ const next = mode();
5314
+ if (next !== void 0) engine?.setMode(next);
5315
+ $2.set(physicalMode, engine ? engine.getMode() : guessPhysicalMode(next), true);
4705
5316
  });
4706
5317
  $2.user_effect(() => {
4707
5318
  if ($$props.radius !== void 0) engine?.setRadius($$props.radius);
@@ -4710,26 +5321,27 @@ function BottomSheet($$anchor, $$props) {
4710
5321
  if ($$props.maxHeight !== void 0) engine?.setMaxHeight($$props.maxHeight);
4711
5322
  });
4712
5323
  $2.user_effect(() => {
4713
- if ($$props.backdropColor !== void 0) engine?.setScrimColor($$props.backdropColor);
5324
+ if ($$props.backdropColor !== void 0) engine?.setBackdropColor($$props.backdropColor);
4714
5325
  });
4715
5326
  $2.user_effect(() => {
4716
- if ($$props.backdropOpacity !== void 0) engine?.setBackdropRange([0, $$props.backdropOpacity]);
5327
+ if ($$props.backdropOpacity !== void 0) engine?.setBackdropOpacity($$props.backdropOpacity);
4717
5328
  });
4718
5329
  $2.user_effect(() => {
4719
5330
  if (snap() === void 0) return;
4720
5331
  const next = snap();
4721
- if (!engine || untrack(() => $2.get(viewState).activeId) === next) return;
5332
+ if (!engine || engine.state.activeId === next) return;
4722
5333
  void engine.snapTo(next);
4723
5334
  });
4724
5335
  $2.user_effect(() => {
4725
5336
  if (openProp() === void 0) return;
4726
5337
  const next = openProp();
4727
5338
  if (!engine) return;
4728
- const isOpen = untrack(() => $2.get(viewState).size) > 0;
4729
- if (next && !isOpen) void engine.open();
4730
- else if (!next && isOpen) void engine.close();
5339
+ const phase = engine.state.phase;
5340
+ const opening = phase === "open" || phase === "opening";
5341
+ if (next && !opening) void engine.open();
5342
+ else if (!next && opening) void engine.close();
4731
5343
  });
4732
- let isVerticalAxis = $2.derived(() => mode() === "bottom" || mode() === "top");
5344
+ let isVerticalAxis = $2.derived(() => $2.get(physicalMode) === "bottom" || $2.get(physicalMode) === "top");
4733
5345
  var $$exports = {
4734
5346
  snapTo,
4735
5347
  open,
@@ -4742,6 +5354,9 @@ function BottomSheet($$anchor, $$props) {
4742
5354
  setSnapPoints,
4743
5355
  setScrim,
4744
5356
  setScrimOverlay,
5357
+ addAnchor,
5358
+ setScrimStages,
5359
+ recompute,
4745
5360
  setRadius,
4746
5361
  setMaxHeight,
4747
5362
  canDismiss,
@@ -4835,7 +5450,7 @@ function BottomSheet($$anchor, $$props) {
4835
5450
  var node_10 = $2.child(div_7);
4836
5451
  $2.snippet(node_10, () => $$props.leftButton);
4837
5452
  $2.reset(div_7);
4838
- $2.template_effect(() => $2.set_attribute(div_7, "data-mode", mode()));
5453
+ $2.template_effect(() => $2.set_attribute(div_7, "data-mode", $2.get(physicalMode)));
4839
5454
  $2.append($$anchor2, div_7);
4840
5455
  };
4841
5456
  $2.if(node_9, ($$render) => {
@@ -4849,7 +5464,7 @@ function BottomSheet($$anchor, $$props) {
4849
5464
  var node_12 = $2.child(div_8);
4850
5465
  $2.snippet(node_12, () => $$props.rightButton);
4851
5466
  $2.reset(div_8);
4852
- $2.template_effect(() => $2.set_attribute(div_8, "data-mode", mode()));
5467
+ $2.template_effect(() => $2.set_attribute(div_8, "data-mode", $2.get(physicalMode)));
4853
5468
  $2.append($$anchor2, div_8);
4854
5469
  };
4855
5470
  $2.if(node_11, ($$render) => {
@@ -4858,11 +5473,14 @@ function BottomSheet($$anchor, $$props) {
4858
5473
  }
4859
5474
  $2.reset(div);
4860
5475
  $2.template_effect(() => {
4861
- $2.set_attribute(section, "data-mode", mode());
5476
+ $2.set_attribute(section, "data-mode", $2.get(physicalMode));
5477
+ $2.set_attribute(section, "data-bs-rest", restAtStart);
4862
5478
  $2.set_attribute(section, "data-active", $2.get(viewState).activeId);
4863
5479
  $2.set_attribute(section, "aria-modal", focusTrap() ? "true" : void 0);
4864
5480
  $2.set_attribute(section, "aria-label", ariaLabel());
5481
+ $2.set_attribute(div_3, "aria-label", handleLabel());
4865
5482
  $2.set_attribute(div_3, "aria-orientation", $2.get(isVerticalAxis) ? "vertical" : "horizontal");
5483
+ $2.set_attribute(div_5, "aria-label", contentLabel());
4866
5484
  $2.set_text(text, $2.get(viewState).activeId);
4867
5485
  });
4868
5486
  $2.append($$anchor, div);