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