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