@surdeddd/bottom-sheet 0.23.4 → 0.24.0

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