@surdeddd/bottom-sheet 0.23.4 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +513 -527
  2. package/README.ru.md +533 -545
  3. package/dist/{BottomSheetCore-C5tJYVMY.d.cts → BottomSheetCore-B_r4KCQL.d.cts} +48 -13
  4. package/dist/{BottomSheetCore-DxSrC4QC.d.ts → BottomSheetCore-B_r4KCQL.d.ts} +48 -13
  5. package/dist/{BottomSheetEngine-B3F9qukX.d.cts → BottomSheetEngine-0F7mjyvF.d.cts} +1 -1
  6. package/dist/{BottomSheetEngine-BchzgqGG.d.ts → BottomSheetEngine-CJV_DDrM.d.ts} +1 -1
  7. package/dist/core.cjs +810 -436
  8. package/dist/core.d.cts +2 -3
  9. package/dist/core.d.ts +2 -3
  10. package/dist/core.js +810 -436
  11. package/dist/debug.d.cts +0 -1
  12. package/dist/debug.d.ts +0 -1
  13. package/dist/{default-features-DwVTzDwP.d.ts → default-features-4Xwv6aVt.d.ts} +4 -2
  14. package/dist/{default-features-BGiCSmV1.d.cts → default-features-DX2NOxP6.d.cts} +4 -2
  15. package/dist/element.cjs +1421 -697
  16. package/dist/element.d.cts +11 -3
  17. package/dist/element.d.ts +11 -3
  18. package/dist/element.iife.global.js +2 -2
  19. package/dist/element.js +1421 -697
  20. package/dist/features.cjs +334 -190
  21. package/dist/features.d.cts +3 -4
  22. package/dist/features.d.ts +3 -4
  23. package/dist/features.js +334 -191
  24. package/dist/{index-C7TSQkVK.d.cts → index-2shlxhcG.d.cts} +1 -1
  25. package/dist/{index-CdM1tke5.d.ts → index-CNCRQnpc.d.ts} +1 -1
  26. package/dist/index.cjs +1129 -631
  27. package/dist/index.d.cts +11 -6
  28. package/dist/index.d.ts +11 -6
  29. package/dist/index.js +1129 -632
  30. package/dist/integrations/formik.cjs +21 -10
  31. package/dist/integrations/formik.d.cts +0 -1
  32. package/dist/integrations/formik.d.ts +0 -1
  33. package/dist/integrations/formik.js +22 -11
  34. package/dist/integrations/react-hook-form.cjs +21 -12
  35. package/dist/integrations/react-hook-form.d.cts +0 -1
  36. package/dist/integrations/react-hook-form.d.ts +0 -1
  37. package/dist/integrations/react-hook-form.js +21 -12
  38. package/dist/option-keys-DItuAjUw.d.cts +6 -0
  39. package/dist/option-keys-a5DYNwwO.d.ts +6 -0
  40. package/dist/overlay.cjs +386 -189
  41. package/dist/overlay.d.cts +1 -3
  42. package/dist/overlay.d.ts +1 -3
  43. package/dist/overlay.js +386 -189
  44. package/dist/preact.d.cts +3 -4
  45. package/dist/preact.d.ts +3 -4
  46. package/dist/qwik-lib/index.qwik.cjs +1306 -671
  47. package/dist/qwik-lib/index.qwik.mjs +1306 -671
  48. package/dist/qwik.cjs +1326 -701
  49. package/dist/qwik.d.cts +12 -30
  50. package/dist/qwik.d.ts +12 -30
  51. package/dist/qwik.js +1326 -701
  52. package/dist/react.cjs +1373 -750
  53. package/dist/react.d.cts +26 -12
  54. package/dist/react.d.ts +26 -12
  55. package/dist/react.js +1375 -752
  56. package/dist/solid.cjs +1332 -727
  57. package/dist/solid.d.cts +13 -438
  58. package/dist/solid.d.ts +13 -438
  59. package/dist/solid.js +1334 -729
  60. package/dist/solid.source.jsx +1374 -751
  61. package/dist/styles.css +20 -6
  62. package/dist/svelte-core.cjs +1209 -676
  63. package/dist/svelte-core.js +1207 -677
  64. package/dist/svelte-src/BottomSheet.svelte +101 -58
  65. package/dist/svelte.cjs +1323 -705
  66. package/dist/svelte.d.cts +45 -25
  67. package/dist/svelte.d.ts +45 -25
  68. package/dist/svelte.js +1323 -705
  69. package/dist/vue.cjs +1354 -773
  70. package/dist/vue.d.cts +20 -3
  71. package/dist/vue.d.ts +20 -3
  72. package/dist/vue.js +1354 -773
  73. package/dist/webgl.cjs +38 -7
  74. package/dist/webgl.d.cts +0 -1
  75. package/dist/webgl.d.ts +0 -1
  76. package/dist/webgl.js +38 -7
  77. package/llms.txt +330 -0
  78. package/package.json +41 -19
  79. package/dist/transform-jVfAikE9.d.cts +0 -3
  80. package/dist/transform-jVfAikE9.d.ts +0 -3
package/dist/element.cjs CHANGED
@@ -17,10 +17,25 @@ var __export = (target, all) => {
17
17
  };
18
18
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
19
19
 
20
+ // src/core/primitives/shared.ts
21
+ function shared(name, init) {
22
+ const host = globalThis;
23
+ const store = host[STORE_KEY] ?? (host[STORE_KEY] = {});
24
+ if (!(name in store)) store[name] = init();
25
+ return store[name];
26
+ }
27
+ var STORE_KEY;
28
+ var init_shared = __esm({
29
+ "src/core/primitives/shared.ts"() {
30
+ STORE_KEY = /* @__PURE__ */ Symbol.for("@surdeddd/bottom-sheet/shared/1");
31
+ }
32
+ });
33
+
20
34
  // src/core/lifecycle/sheet-stack.ts
21
35
  var BASE_Z, STEP, SheetStack, sheetStack;
22
36
  var init_sheet_stack = __esm({
23
37
  "src/core/lifecycle/sheet-stack.ts"() {
38
+ init_shared();
24
39
  BASE_Z = 100;
25
40
  STEP = 10;
26
41
  SheetStack = class {
@@ -87,7 +102,7 @@ var init_sheet_stack = __esm({
87
102
  });
88
103
  }
89
104
  };
90
- sheetStack = new SheetStack();
105
+ sheetStack = shared("stack", () => new SheetStack());
91
106
  }
92
107
  });
93
108
 
@@ -123,7 +138,8 @@ function nextInstanceId(prefix) {
123
138
  var counters;
124
139
  var init_instance_id = __esm({
125
140
  "src/core/primitives/instance-id.ts"() {
126
- counters = {};
141
+ init_shared();
142
+ counters = shared("instanceIds", () => ({}));
127
143
  }
128
144
  });
129
145
 
@@ -146,7 +162,13 @@ function createEventBus() {
146
162
  const set = listeners.get(event);
147
163
  if (!set) return;
148
164
  for (const fn of [...set]) {
149
- fn(payload);
165
+ try {
166
+ fn(payload);
167
+ } catch (err) {
168
+ queueMicrotask(() => {
169
+ throw err;
170
+ });
171
+ }
150
172
  }
151
173
  },
152
174
  listenerCount(event) {
@@ -162,11 +184,31 @@ var init_event_bus = __esm({
162
184
  }
163
185
  });
164
186
 
187
+ // src/core/primitives/dev-warn.ts
188
+ function devWarn(...args) {
189
+ if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
190
+ console.warn(...args);
191
+ }
192
+ }
193
+ var init_dev_warn = __esm({
194
+ "src/core/primitives/dev-warn.ts"() {
195
+ }
196
+ });
197
+
165
198
  // src/core/primitives/css-length.ts
166
- var probe, PROBE_ATTR, ensureProbe, isViewportAxisVertical, viewportSize, PERCENT, resolveSnap;
199
+ var probe, rejected, warnRejected, PROBE_ATTR, ensureProbe, isViewportAxisVertical, viewportSize, PERCENT, resolveSnap;
167
200
  var init_css_length = __esm({
168
201
  "src/core/primitives/css-length.ts"() {
202
+ init_dev_warn();
169
203
  probe = null;
204
+ rejected = /* @__PURE__ */ new Set();
205
+ warnRejected = (value) => {
206
+ if (rejected.has(value)) return;
207
+ rejected.add(value);
208
+ devWarn(
209
+ `[BottomSheet] snap size "${value}" is not a CSS length the browser accepts \u2014 it resolves to 0.`
210
+ );
211
+ };
170
212
  PROBE_ATTR = "data-bs-probe";
171
213
  ensureProbe = (axis) => {
172
214
  if (typeof document === "undefined") return null;
@@ -213,25 +255,16 @@ var init_css_length = __esm({
213
255
  if (!el) return 0;
214
256
  if (axis === "vertical") {
215
257
  el.style.height = point;
258
+ if (el.style.height === "") warnRejected(point);
216
259
  return Math.max(0, el.getBoundingClientRect().height);
217
260
  }
218
261
  el.style.width = point;
262
+ if (el.style.width === "") warnRejected(point);
219
263
  return Math.max(0, el.getBoundingClientRect().width);
220
264
  };
221
265
  }
222
266
  });
223
267
 
224
- // src/core/primitives/dev-warn.ts
225
- function devWarn(...args) {
226
- if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
227
- console.warn(...args);
228
- }
229
- }
230
- var init_dev_warn = __esm({
231
- "src/core/primitives/dev-warn.ts"() {
232
- }
233
- });
234
-
235
268
  // src/core/primitives/snap-points.ts
236
269
  var resolveSnapList, VH_NOT_DVH, auditVhUsage, findNearest, allowedRange, findById, MOUSE_FLICK_VELOCITY, MOUSE_DRAG_THRESHOLD, DIRECTIONAL_INTENT_VELOCITY, findDragSettleTarget;
237
270
  var init_snap_points = __esm({
@@ -376,6 +409,7 @@ var init_snap_resolver = __esm({
376
409
  setMode(mode) {
377
410
  if (mode === this.mode) return;
378
411
  this.mode = mode;
412
+ this.notified = false;
379
413
  this.recompute();
380
414
  }
381
415
  setAllowedIds(ids) {
@@ -385,14 +419,20 @@ var init_snap_resolver = __esm({
385
419
  findById(id) {
386
420
  return findById(id, this.resolved);
387
421
  }
388
- findDragSettleTarget(args) {
422
+ findDragSettleTarget(args, openOnly = false) {
389
423
  return findDragSettleTarget({
390
424
  ...args,
391
425
  resolved: this.resolved,
392
- allowed: this.allowedIds,
426
+ allowed: this.pool(openOnly),
393
427
  maxAxisSize: this.maxAxisSize
394
428
  });
395
429
  }
430
+ nearest(size, openOnly) {
431
+ return findNearest(size, this.resolved, this.pool(openOnly));
432
+ }
433
+ pool(openOnly) {
434
+ return openOnly ? this.allowedIds.filter((id) => (this.findById(id)?.size ?? 0) > 0) : this.allowedIds;
435
+ }
396
436
  getAllowedRange() {
397
437
  return this.rangeCache ?? (this.rangeCache = allowedRange(this.resolved, this.allowedIds));
398
438
  }
@@ -456,14 +496,9 @@ function installResizeObserver(deps) {
456
496
  return () => {
457
497
  };
458
498
  }
459
- const seatFor = () => {
460
- const snap = deps.resolveActiveSnap();
461
- const max = deps.getMaxAxisSize();
462
- return { target: snap ? Math.min(snap.size, max) : null, max };
463
- };
464
499
  const onResize = () => {
465
500
  if (deps.isDestroyed()) return;
466
- const before = seatFor();
501
+ const before = seatOf(deps);
467
502
  deps.recomputeSnaps();
468
503
  const mode = deps.getMode();
469
504
  const isVerticalAxis = mode === "bottom" || mode === "top";
@@ -472,21 +507,8 @@ function installResizeObserver(deps) {
472
507
  if (viewportSize2 > 0 && viewportSize2 < max) {
473
508
  deps.setMaxAxisSize(viewportSize2);
474
509
  }
475
- const after = seatFor();
476
- 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) {
477
- return;
478
- }
479
- const wasAnimating = deps.isAnimating?.() ?? false;
480
- deps.cancelInFlight();
481
- deps.newCycle();
482
- const current = deps.resolveActiveSnap();
483
- const newMax = deps.getMaxAxisSize();
484
- const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
485
- deps.setSize(targetSize);
486
- if (current && !deps.isDragging()) {
487
- deps.applySize(targetSize);
488
- if (wasAnimating) deps.resyncAfterCancel?.();
489
- }
510
+ if (sameSeat(before, seatOf(deps))) return;
511
+ deps.reseat();
490
512
  };
491
513
  let resizeObserver = null;
492
514
  if (typeof ResizeObserver !== "undefined") {
@@ -498,7 +520,7 @@ function installResizeObserver(deps) {
498
520
  window.addEventListener("orientationchange", onResize);
499
521
  const onVisibility = () => {
500
522
  if (deps.isDestroyed()) return;
501
- if (document.hidden) deps.cancelInFlight();
523
+ if (document.hidden) deps.landNow();
502
524
  };
503
525
  document.addEventListener("visibilitychange", onVisibility);
504
526
  return () => {
@@ -508,9 +530,16 @@ function installResizeObserver(deps) {
508
530
  document.removeEventListener("visibilitychange", onVisibility);
509
531
  };
510
532
  }
533
+ var seatOf, sameSeat;
511
534
  var init_resize_observer = __esm({
512
535
  "src/core/features/resize-observer.ts"() {
513
536
  init_hot_path_thresholds();
537
+ seatOf = (deps) => {
538
+ const snap = deps.resolveActiveSnap();
539
+ const max = deps.getMaxAxisSize();
540
+ return { target: snap ? Math.min(snap.size, max) : null, max };
541
+ };
542
+ 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;
514
543
  }
515
544
  });
516
545
 
@@ -530,7 +559,6 @@ function installFitObserver(deps) {
530
559
  });
531
560
  };
532
561
  const ro = new ResizeObserver(schedule);
533
- ro.observe(deps.handle);
534
562
  const scroller = deps.scrollContainer;
535
563
  const observed = /* @__PURE__ */ new Set();
536
564
  const slots = /* @__PURE__ */ new Set();
@@ -547,7 +575,7 @@ function installFitObserver(deps) {
547
575
  };
548
576
  const resync = () => {
549
577
  trackSlots();
550
- const targets = contentTargets(scroller);
578
+ const targets = [...chromeTargets(deps), ...contentTargets(scroller)];
551
579
  for (const el of observed) {
552
580
  if (!targets.includes(el)) {
553
581
  ro.unobserve(el);
@@ -562,13 +590,12 @@ function installFitObserver(deps) {
562
590
  }
563
591
  schedule();
564
592
  };
593
+ resync();
565
594
  let mo;
566
- if (scroller) {
567
- resync();
568
- if (typeof MutationObserver !== "undefined") {
569
- mo = new MutationObserver(resync);
570
- mo.observe(scroller, { childList: true });
571
- }
595
+ if (typeof MutationObserver !== "undefined") {
596
+ mo = new MutationObserver(resync);
597
+ mo.observe(deps.element, { childList: true });
598
+ if (scroller) mo.observe(scroller, { childList: true });
572
599
  }
573
600
  return () => {
574
601
  ro.disconnect();
@@ -579,7 +606,7 @@ function installFitObserver(deps) {
579
606
  if (raf) cancelAnimationFrame(raf);
580
607
  };
581
608
  }
582
- var contentTargets;
609
+ var contentTargets, chromeTargets;
583
610
  var init_fit_observer = __esm({
584
611
  "src/core/features/fit-observer.ts"() {
585
612
  contentTargets = (scroller) => {
@@ -595,6 +622,25 @@ var init_fit_observer = __esm({
595
622
  }
596
623
  return out;
597
624
  };
625
+ chromeTargets = (deps) => {
626
+ const out = [];
627
+ for (const child of Array.from(deps.element.children)) {
628
+ if (child !== deps.scrollContainer) out.push(child);
629
+ }
630
+ if (deps.handle !== deps.element && !out.includes(deps.handle)) {
631
+ out.push(deps.handle);
632
+ }
633
+ return out;
634
+ };
635
+ }
636
+ });
637
+
638
+ // src/core/features/teleport.ts
639
+ var homes, homeRootOf;
640
+ var init_teleport = __esm({
641
+ "src/core/features/teleport.ts"() {
642
+ homes = /* @__PURE__ */ new WeakMap();
643
+ homeRootOf = (root) => (root && homes.get(root)) ?? null;
598
644
  }
599
645
  });
600
646
 
@@ -713,8 +759,9 @@ function installSliderKeyboard(deps) {
713
759
  const isVerticalAxis = deps.mode === "bottom" || deps.mode === "top";
714
760
  const stepUp = isVerticalAxis ? "ArrowUp" : "ArrowRight";
715
761
  const stepDown = isVerticalAxis ? "ArrowDown" : "ArrowLeft";
716
- const sheetExpandsKey = deps.mode === "top" ? stepDown : stepUp;
717
- const sheetCollapsesKey = deps.mode === "top" ? stepUp : stepDown;
762
+ const flipped = deps.mode === "top" || deps.mode === "right";
763
+ const sheetExpandsKey = flipped ? stepDown : stepUp;
764
+ const sheetCollapsesKey = flipped ? stepUp : stepDown;
718
765
  const onHandleKey = (e) => {
719
766
  if (deps.isDestroyed()) return;
720
767
  const allowed = deps.getAllowedIds();
@@ -804,11 +851,12 @@ var init_opacity_dedup = __esm({
804
851
  // src/core/primitives/overlay-position.ts
805
852
  function resolveSheetAnchoredStyle(mode, position, inset) {
806
853
  const sizeOffset = `calc(var(--bs-size, 0px) + ${inset})`;
854
+ const lifted = `calc(var(--bs-size, 0px) + var(--bs-keyboard-inset, 0px) + ${inset})`;
807
855
  switch (mode) {
808
856
  case "bottom":
809
- if (position === "sheet-top-left") return { bottom: sizeOffset, left: inset };
810
- if (position === "sheet-top-right") return { bottom: sizeOffset, right: inset };
811
- return { bottom: sizeOffset, left: "50%", transform: "translateX(-50%)" };
857
+ if (position === "sheet-top-left") return { bottom: lifted, left: inset };
858
+ if (position === "sheet-top-right") return { bottom: lifted, right: inset };
859
+ return { bottom: lifted, left: "50%", transform: "translateX(-50%)" };
812
860
  case "top":
813
861
  if (position === "sheet-top-left") return { top: sizeOffset, left: inset };
814
862
  if (position === "sheet-top-right") return { top: sizeOffset, right: inset };
@@ -823,6 +871,13 @@ function resolveSheetAnchoredStyle(mode, position, inset) {
823
871
  return { right: sizeOffset, top: "50%", transform: "translateY(-50%)" };
824
872
  }
825
873
  }
874
+ function resetOverlayPosition(ws) {
875
+ ws.top = "";
876
+ ws.bottom = "";
877
+ ws.left = "";
878
+ ws.right = "";
879
+ ws.transform = "";
880
+ }
826
881
  function applyOverlayPosition(ws, mode, position, inset) {
827
882
  switch (position) {
828
883
  case "top-left":
@@ -885,7 +940,7 @@ var init_overlay_position = __esm({
885
940
  });
886
941
 
887
942
  // src/core/controllers/scrim-controller.ts
888
- var VALID_CSS_LENGTH, DEFAULT_SCRIM_DIM, ScrimController;
943
+ var VALID_CSS_LENGTH, DEFAULT_SCRIM_DIM, BACKDROP_COLOR_VAR, unit, ScrimController;
889
944
  var init_scrim_controller = __esm({
890
945
  "src/core/controllers/scrim-controller.ts"() {
891
946
  init_types();
@@ -896,6 +951,8 @@ var init_scrim_controller = __esm({
896
951
  init_overlay_position();
897
952
  VALID_CSS_LENGTH = /^-?\d+(?:\.\d+)?(?:px|em|rem|%)$/;
898
953
  DEFAULT_SCRIM_DIM = "rgba(0, 0, 0, 0.4)";
954
+ BACKDROP_COLOR_VAR = "--bs-backdrop-color";
955
+ unit = (value) => Number.isFinite(value) ? Math.min(Math.max(value, 0), 1) : 1;
899
956
  ScrimController = class {
900
957
  constructor(deps, opts) {
901
958
  __publicField(this, "screenComponent");
@@ -910,11 +967,13 @@ var init_scrim_controller = __esm({
910
967
  __publicField(this, "scrimMode");
911
968
  __publicField(this, "backdropRange");
912
969
  __publicField(this, "screenRange");
970
+ __publicField(this, "backdropPeak");
913
971
  __publicField(this, "scrimEnabled", true);
914
972
  __publicField(this, "savedScrimRanges", null);
915
973
  __publicField(this, "scrimTapToCloseEnabled", false);
916
974
  __publicField(this, "detachScrimTap", null);
917
975
  __publicField(this, "scrimOverlayTeardown", null);
976
+ __publicField(this, "placeOverlay", null);
918
977
  __publicField(this, "backdropOpacitySentinel", new WriteSentinel());
919
978
  __publicField(this, "screenOpacitySentinel", new WriteSentinel());
920
979
  __publicField(this, "lastBackdropPointer", "");
@@ -931,6 +990,8 @@ var init_scrim_controller = __esm({
931
990
  const preset = opts.scrimPreset ? SCRIM_PRESETS[opts.scrimPreset] : null;
932
991
  this.backdropRange = opts.backdropRange ?? preset?.range ?? [0, 1];
933
992
  this.screenRange = opts.screenRange ?? preset?.range ?? [0, 1];
993
+ this.backdropPeak = unit(opts.backdropOpacity ?? 1);
994
+ this.setBackdropColor(opts.backdropColor);
934
995
  this.scrimTapToCloseEnabled = opts.scrimTapToClose ?? false;
935
996
  const explicitColor = opts.scrimColor ?? preset?.color;
936
997
  const effectiveColor = explicitColor ?? (this.scrimMode !== "off" && !this.backdrop ? DEFAULT_SCRIM_DIM : void 0);
@@ -960,24 +1021,19 @@ var init_scrim_controller = __esm({
960
1021
  this.setScrimTapToClose(true);
961
1022
  }
962
1023
  }
963
- applyOpacity(progress, progressChanged) {
964
- if (!progressChanged && this.backdropOpacitySentinel.value !== -1 && this.screenOpacitySentinel.value !== -1) {
1024
+ applyOpacity(progress, progressChanged, epsilon = OPACITY_WRITE_EPSILON) {
1025
+ if (epsilon > 0 && !progressChanged && this.backdropOpacitySentinel.value !== -1 && this.screenOpacitySentinel.value !== -1) {
965
1026
  return;
966
1027
  }
967
1028
  if (this.backdrop) {
968
1029
  const [s, e] = this.backdropRange;
969
1030
  const range = Math.max(e - s, RANGE_DIVISION_EPSILON);
970
- const backdropOpacity = Math.min(
971
- Math.max((progress - s) / range, 0),
972
- 1
973
- );
974
- if (this.backdropOpacitySentinel.shouldWrite(
975
- backdropOpacity,
976
- OPACITY_WRITE_EPSILON
977
- )) {
1031
+ const along = Math.min(Math.max((progress - s) / range, 0), 1);
1032
+ const backdropOpacity = along * this.backdropPeak;
1033
+ if (this.backdropOpacitySentinel.shouldWrite(backdropOpacity, epsilon)) {
978
1034
  this.backdrop.style.opacity = String(backdropOpacity);
979
1035
  }
980
- const nextPointer = backdropOpacity > POINTER_EVENTS_OPACITY_THRESHOLD ? "auto" : "none";
1036
+ const nextPointer = along > POINTER_EVENTS_OPACITY_THRESHOLD ? "auto" : "none";
981
1037
  if (nextPointer !== this.lastBackdropPointer) {
982
1038
  this.backdrop.style.pointerEvents = nextPointer;
983
1039
  this.lastBackdropPointer = nextPointer;
@@ -992,10 +1048,7 @@ var init_scrim_controller = __esm({
992
1048
  (progress - ss) / Math.max(RANGE_DIVISION_EPSILON, se - ss)
993
1049
  )
994
1050
  );
995
- if (this.screenOpacitySentinel.shouldWrite(
996
- screenOpacity,
997
- OPACITY_WRITE_EPSILON
998
- )) {
1051
+ if (this.screenOpacitySentinel.shouldWrite(screenOpacity, epsilon)) {
999
1052
  this.screenComponent.style.opacity = String(screenOpacity);
1000
1053
  }
1001
1054
  const nextDisplay = screenOpacity > 0 ? "" : "none";
@@ -1011,6 +1064,17 @@ var init_scrim_controller = __esm({
1011
1064
  this.invalidateOpacityCache();
1012
1065
  applySize();
1013
1066
  }
1067
+ setBackdropColor(color) {
1068
+ if (this.isDestroyed() || !this.backdrop) return;
1069
+ if (color) this.backdrop.style.setProperty(BACKDROP_COLOR_VAR, color);
1070
+ else this.backdrop.style.removeProperty(BACKDROP_COLOR_VAR);
1071
+ }
1072
+ setBackdropOpacity(value, applySize) {
1073
+ if (this.isDestroyed()) return;
1074
+ this.backdropPeak = unit(value);
1075
+ this.invalidateOpacityCache();
1076
+ applySize();
1077
+ }
1014
1078
  setScreenRange(range, applySize) {
1015
1079
  if (this.isDestroyed()) return;
1016
1080
  this.screenRange = range;
@@ -1033,6 +1097,8 @@ var init_scrim_controller = __esm({
1033
1097
  if (this.isDestroyed() || mode === this.mode) return;
1034
1098
  this.mode = mode;
1035
1099
  this.invalidateOpacityCache();
1100
+ if (this.scrimMode === "above-sheet") this.applyAboveSheetInset();
1101
+ this.placeOverlay?.();
1036
1102
  }
1037
1103
  setScrimMode(mode, applySize) {
1038
1104
  if (this.isDestroyed()) return;
@@ -1045,7 +1111,7 @@ var init_scrim_controller = __esm({
1045
1111
  if (previous === "above-sheet" && mode !== "above-sheet") {
1046
1112
  s.position = "";
1047
1113
  s.inset = "";
1048
- s.pointerEvents = "";
1114
+ this.syncPointer();
1049
1115
  }
1050
1116
  if (mode === "above-sheet") {
1051
1117
  this.applyAboveSheetInset();
@@ -1070,9 +1136,6 @@ var init_scrim_controller = __esm({
1070
1136
  if (enabled === installed) return;
1071
1137
  if (enabled) {
1072
1138
  const target = this.screenComponent;
1073
- if (target.style.pointerEvents === "none") {
1074
- target.style.pointerEvents = "auto";
1075
- }
1076
1139
  const onClick = () => {
1077
1140
  if (this.isDestroyed()) return;
1078
1141
  if (this.closeFn) {
@@ -1095,6 +1158,11 @@ var init_scrim_controller = __esm({
1095
1158
  this.detachScrimTap = null;
1096
1159
  this.scrimTapToCloseEnabled = false;
1097
1160
  }
1161
+ this.syncPointer();
1162
+ }
1163
+ syncPointer() {
1164
+ if (!this.screenComponent) return;
1165
+ this.screenComponent.style.pointerEvents = this.scrimInteractive || this.detachScrimTap ? "auto" : "none";
1098
1166
  }
1099
1167
  setScrimEnabled(enabled, applySize) {
1100
1168
  if (this.isDestroyed()) return;
@@ -1178,8 +1246,12 @@ var init_scrim_controller = __esm({
1178
1246
  const wrapper = screen.ownerDocument.createElement("div");
1179
1247
  wrapper.className = "bs-scrim-overlay";
1180
1248
  const ws = wrapper.style;
1181
- ws.position = "absolute";
1182
- applyOverlayPosition(ws, this.mode, position, inset);
1249
+ ws.position = "fixed";
1250
+ const place = () => {
1251
+ resetOverlayPosition(ws);
1252
+ applyOverlayPosition(ws, this.mode, position, inset);
1253
+ };
1254
+ place();
1183
1255
  if (interactive) {
1184
1256
  ws.pointerEvents = "auto";
1185
1257
  }
@@ -1193,8 +1265,10 @@ var init_scrim_controller = __esm({
1193
1265
  };
1194
1266
  }
1195
1267
  host.appendChild(wrapper);
1268
+ this.placeOverlay = place;
1196
1269
  const teardown = () => {
1197
1270
  if (wrapper.parentNode) wrapper.parentNode.removeChild(wrapper);
1271
+ if (this.placeOverlay === place) this.placeOverlay = null;
1198
1272
  if (this.scrimOverlayTeardown === teardown) {
1199
1273
  this.scrimOverlayTeardown = null;
1200
1274
  }
@@ -1218,6 +1292,7 @@ var init_scrim_controller = __esm({
1218
1292
  if (this.backdrop) {
1219
1293
  this.backdrop.style.opacity = "";
1220
1294
  this.backdrop.style.pointerEvents = "";
1295
+ this.backdrop.style.removeProperty(BACKDROP_COLOR_VAR);
1221
1296
  }
1222
1297
  this.invalidateOpacityCache();
1223
1298
  this.lastBackdropPointer = "";
@@ -1242,13 +1317,13 @@ var init_scrim_controller = __esm({
1242
1317
  }
1243
1318
  if (opts.interactive !== void 0) {
1244
1319
  this.scrimInteractive = opts.interactive;
1245
- s.pointerEvents = opts.interactive ? "auto" : "none";
1320
+ this.syncPointer();
1246
1321
  }
1247
1322
  }
1248
1323
  applyAboveSheetInset() {
1249
1324
  if (!this.screenComponent) return;
1250
1325
  const insetByMode = {
1251
- bottom: "0 0 var(--bs-size) 0",
1326
+ bottom: "0 0 calc(var(--bs-size) + var(--bs-keyboard-inset, 0px)) 0",
1252
1327
  top: "var(--bs-size) 0 0 0",
1253
1328
  left: "0 0 0 var(--bs-size)",
1254
1329
  right: "0 var(--bs-size) 0 0"
@@ -1256,14 +1331,14 @@ var init_scrim_controller = __esm({
1256
1331
  const s = this.screenComponent.style;
1257
1332
  s.position = "fixed";
1258
1333
  s.inset = insetByMode[this.mode];
1259
- s.pointerEvents = this.scrimInteractive || this.scrimTapToCloseEnabled ? "auto" : "none";
1334
+ this.syncPointer();
1260
1335
  }
1261
1336
  };
1262
1337
  }
1263
1338
  });
1264
1339
 
1265
1340
  // src/core/animation/animation.ts
1266
- var easeOutBack, easeOutCubic, easeLinear, easeOutQuint, tween, prefersReducedMotion;
1341
+ var easeOutBack, easeOutCubic, easeLinear, easeOutQuint, MIN_RETARGET_MS, tween, prefersReducedMotion;
1267
1342
  var init_animation = __esm({
1268
1343
  "src/core/animation/animation.ts"() {
1269
1344
  easeOutBack = (t) => {
@@ -1274,6 +1349,7 @@ var init_animation = __esm({
1274
1349
  easeOutCubic = (t) => 1 - Math.pow(1 - t, 3);
1275
1350
  easeLinear = (t) => t;
1276
1351
  easeOutQuint = (t) => 1 - Math.pow(1 - t, 5);
1352
+ MIN_RETARGET_MS = 120;
1277
1353
  tween = ({
1278
1354
  from,
1279
1355
  to,
@@ -1282,12 +1358,18 @@ var init_animation = __esm({
1282
1358
  onUpdate
1283
1359
  }) => {
1284
1360
  let cancelled = false;
1361
+ let finished = false;
1285
1362
  let rafId = 0;
1286
1363
  let resolveFn = null;
1287
- const start = performance.now();
1364
+ let start = performance.now();
1365
+ let origin = from;
1366
+ let target = to;
1367
+ let span = duration;
1368
+ let last = from;
1288
1369
  const promise = new Promise((resolve) => {
1289
1370
  resolveFn = resolve;
1290
1371
  if (duration <= 0) {
1372
+ finished = true;
1291
1373
  onUpdate(to);
1292
1374
  resolve();
1293
1375
  return;
@@ -1295,12 +1377,13 @@ var init_animation = __esm({
1295
1377
  const step = (now) => {
1296
1378
  if (cancelled) return;
1297
1379
  const elapsed = Math.max(0, now - start);
1298
- const t = Math.min(elapsed / duration, 1);
1299
- const value = from + (to - from) * easing(t);
1300
- onUpdate(value);
1380
+ const t = Math.min(elapsed / span, 1);
1381
+ last = origin + (target - origin) * easing(t);
1382
+ onUpdate(last);
1301
1383
  if (t < 1) {
1302
1384
  rafId = requestAnimationFrame(step);
1303
1385
  } else {
1386
+ finished = true;
1304
1387
  resolve();
1305
1388
  }
1306
1389
  };
@@ -1312,6 +1395,15 @@ var init_animation = __esm({
1312
1395
  cancelAnimationFrame(rafId);
1313
1396
  resolveFn?.();
1314
1397
  },
1398
+ retarget: (next) => {
1399
+ if (cancelled || finished || next === target) return;
1400
+ const now = performance.now();
1401
+ const remaining = span - Math.max(0, now - start);
1402
+ origin = last;
1403
+ target = next;
1404
+ start = now;
1405
+ span = Math.max(remaining, MIN_RETARGET_MS);
1406
+ },
1315
1407
  promise
1316
1408
  };
1317
1409
  };
@@ -1323,7 +1415,7 @@ var init_animation = __esm({
1323
1415
  });
1324
1416
 
1325
1417
  // src/core/animation/spring.ts
1326
- var DEFAULT_SPRING, MAX_DT, runSpring;
1418
+ var DEFAULT_SPRING, MAX_DT, MAX_DURATION_MS, runSpring;
1327
1419
  var init_spring = __esm({
1328
1420
  "src/core/animation/spring.ts"() {
1329
1421
  DEFAULT_SPRING = {
@@ -1334,22 +1426,32 @@ var init_spring = __esm({
1334
1426
  restSpeed: 0.5
1335
1427
  };
1336
1428
  MAX_DT = 1 / 30;
1429
+ MAX_DURATION_MS = 3e3;
1337
1430
  runSpring = ({
1338
1431
  from,
1339
1432
  to,
1340
1433
  velocity = 0,
1341
1434
  config,
1435
+ maxDuration = MAX_DURATION_MS,
1342
1436
  onUpdate
1343
1437
  }) => {
1344
1438
  const cfg = { ...DEFAULT_SPRING, ...config };
1345
1439
  let cancelled = false;
1440
+ let finished = false;
1346
1441
  let rafId = 0;
1347
1442
  let resolveFn = null;
1348
1443
  let x = from;
1349
1444
  let v = velocity;
1445
+ let target = to;
1350
1446
  let lastTime = performance.now();
1447
+ let deadline = lastTime + maxDuration;
1351
1448
  const promise = new Promise((resolve) => {
1352
1449
  resolveFn = resolve;
1450
+ const land = () => {
1451
+ finished = true;
1452
+ onUpdate(target, 0);
1453
+ resolve();
1454
+ };
1353
1455
  const step = (now) => {
1354
1456
  if (cancelled) return;
1355
1457
  const dt = Math.min(Math.max(0, now - lastTime) / 1e3, MAX_DT);
@@ -1358,21 +1460,19 @@ var init_spring = __esm({
1358
1460
  const subDt = dt / steps;
1359
1461
  let stepsLeft = steps;
1360
1462
  while (stepsLeft-- > 0) {
1361
- const force = -cfg.stiffness * (x - to) - cfg.damping * v;
1463
+ const force = -cfg.stiffness * (x - target) - cfg.damping * v;
1362
1464
  const accel = force / cfg.mass;
1363
1465
  v += accel * subDt;
1364
1466
  x += v * subDt;
1365
1467
  }
1366
- if (!Number.isFinite(x) || !Number.isFinite(v)) {
1367
- onUpdate(to, 0);
1368
- resolve();
1468
+ if (!Number.isFinite(x) || !Number.isFinite(v) || lastTime >= deadline) {
1469
+ land();
1369
1470
  return;
1370
1471
  }
1371
1472
  onUpdate(x, v);
1372
- const isAtRest = Math.abs(to - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
1473
+ const isAtRest = Math.abs(target - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
1373
1474
  if (isAtRest) {
1374
- onUpdate(to, 0);
1375
- resolve();
1475
+ land();
1376
1476
  } else {
1377
1477
  rafId = requestAnimationFrame(step);
1378
1478
  }
@@ -1385,6 +1485,11 @@ var init_spring = __esm({
1385
1485
  cancelAnimationFrame(rafId);
1386
1486
  resolveFn?.();
1387
1487
  },
1488
+ retarget: (next) => {
1489
+ if (cancelled || finished) return;
1490
+ target = next;
1491
+ deadline = performance.now() + maxDuration;
1492
+ },
1388
1493
  promise
1389
1494
  };
1390
1495
  };
@@ -1557,21 +1662,40 @@ var init_animation_runner = __esm({
1557
1662
  this.applySizeFn(size);
1558
1663
  }
1559
1664
  cancel() {
1560
- this.currentTween?.cancel();
1561
- this.currentSpring?.cancel();
1665
+ const tween2 = this.currentTween;
1666
+ const spring = this.currentSpring;
1667
+ this.currentTween = null;
1668
+ this.currentSpring = null;
1669
+ tween2?.cancel();
1670
+ spring?.cancel();
1562
1671
  this.cancelWaapi();
1563
1672
  }
1673
+ retarget(target) {
1674
+ if (this.currentSpring) {
1675
+ this.currentSpring.retarget(target);
1676
+ return true;
1677
+ }
1678
+ if (this.currentTween) {
1679
+ this.currentTween.retarget(target);
1680
+ return true;
1681
+ }
1682
+ if (this.currentWaapi) {
1683
+ this.currentWaapi.retarget(target);
1684
+ return true;
1685
+ }
1686
+ return false;
1687
+ }
1564
1688
  async animateTo(target, velocityPxPerMs) {
1565
1689
  if (target === this.getSize()) {
1566
- if (!this.isAnimating && !this.isDragging()) {
1690
+ if (this.isAnimating) this.cancel();
1691
+ if (!this.isDragging()) {
1567
1692
  this.applySizeFn(target);
1693
+ this.getRootEl()?.removeAttribute("data-animating");
1568
1694
  this.element.style.willChange = "";
1569
1695
  }
1570
1696
  return;
1571
1697
  }
1572
- this.currentTween?.cancel();
1573
- this.currentSpring?.cancel();
1574
- this.cancelWaapi();
1698
+ this.cancel();
1575
1699
  this.getRootEl()?.setAttribute("data-animating", "true");
1576
1700
  this.element.style.willChange = "transform";
1577
1701
  if (this.reducedMotion) {
@@ -1581,19 +1705,13 @@ var init_animation_runner = __esm({
1581
1705
  return;
1582
1706
  }
1583
1707
  if (this.settleWaapi && this.applyAux && this.getTransformFor && typeof this.element.animate === "function") {
1584
- const samples = this.animationKind === "spring" ? sampleSpringSettle(
1708
+ const samples = this.sampleSettle(
1585
1709
  this.getSize(),
1586
1710
  target,
1587
- velocityPxPerMs * VELOCITY_PX_PER_S,
1588
- this.springConfig
1589
- ) : sampleTweenSettle(
1590
- this.getSize(),
1591
- target,
1592
- this.duration,
1593
- this.easing
1711
+ velocityPxPerMs * VELOCITY_PX_PER_S
1594
1712
  );
1595
1713
  if (samples.values.length >= 2 && samples.durationMs > 0) {
1596
- await this.runWaapiSettle(samples, target);
1714
+ await this.runWaapiSettle({ samples, target });
1597
1715
  if (!this.isAnimating) {
1598
1716
  this.getRootEl()?.removeAttribute("data-animating");
1599
1717
  if (!this.isDragging()) this.element.style.willChange = "";
@@ -1635,7 +1753,10 @@ var init_animation_runner = __esm({
1635
1753
  }
1636
1754
  }
1637
1755
  }
1638
- async runWaapiSettle(samples, target) {
1756
+ sampleSettle(from, to, velocityPxPerS) {
1757
+ return this.animationKind === "spring" ? sampleSpringSettle(from, to, velocityPxPerS, this.springConfig) : sampleTweenSettle(from, to, this.duration, this.easing);
1758
+ }
1759
+ startWaapiLeg(samples, onRetarget) {
1639
1760
  const applyAux = this.applyAux;
1640
1761
  const getTransformFor = this.getTransformFor;
1641
1762
  const frames = samples.values.map((v) => ({
@@ -1650,16 +1771,20 @@ var init_animation_runner = __esm({
1650
1771
  let stopped = false;
1651
1772
  let auxRaf = 0;
1652
1773
  const lastIdx = samples.values.length - 1;
1774
+ const cursor = () => Math.min((Number(anim.currentTime) || 0) / samples.stepMs, lastIdx);
1653
1775
  const sizeNow = () => {
1654
- const at = Math.min(
1655
- (Number(anim.currentTime) || 0) / samples.stepMs,
1656
- lastIdx
1657
- );
1776
+ const at = cursor();
1658
1777
  const idx = Math.floor(at);
1659
1778
  const from = samples.values[idx];
1660
1779
  const to = samples.values[Math.min(idx + 1, lastIdx)];
1661
1780
  return from + (to - from) * (at - idx);
1662
1781
  };
1782
+ const velocityNow = () => {
1783
+ const idx = Math.min(Math.floor(cursor()), Math.max(lastIdx - 1, 0));
1784
+ const from = samples.values[idx];
1785
+ const to = samples.values[Math.min(idx + 1, lastIdx)];
1786
+ return (to - from) / samples.stepMs * 1e3;
1787
+ };
1663
1788
  const auxTick = () => {
1664
1789
  if (stopped) return;
1665
1790
  applyAux(sizeNow());
@@ -1672,22 +1797,55 @@ var init_animation_runner = __esm({
1672
1797
  stopped = true;
1673
1798
  cancelAnimationFrame(auxRaf);
1674
1799
  },
1675
- sizeNow
1800
+ sizeNow,
1801
+ velocityNow,
1802
+ retarget: (to) => onRetarget(entry, to)
1676
1803
  };
1677
- this.currentWaapi = entry;
1678
- try {
1679
- await anim.finished;
1680
- } catch {
1681
- }
1682
- entry.stop();
1683
- const wasCurrent = this.currentWaapi === entry;
1684
- if (wasCurrent) this.currentWaapi = null;
1685
- if (wasCurrent && anim.playState === "finished") {
1686
- this.applySizeFn(target);
1804
+ return entry;
1805
+ }
1806
+ async runWaapiSettle(first) {
1807
+ let leg = first;
1808
+ for (; ; ) {
1809
+ let queued = null;
1810
+ const entry = this.startWaapiLeg(leg.samples, (running, to) => {
1811
+ const size = this.readShownSize?.() ?? running.sizeNow();
1812
+ queued = {
1813
+ samples: this.sampleSettle(size, to, running.velocityNow()),
1814
+ target: to
1815
+ };
1816
+ running.stop();
1817
+ try {
1818
+ running.anim.cancel();
1819
+ } catch {
1820
+ }
1821
+ this.applySizeFn(size);
1822
+ });
1823
+ this.currentWaapi = entry;
1687
1824
  try {
1688
- anim.cancel();
1825
+ await entry.anim.finished;
1689
1826
  } catch {
1690
1827
  }
1828
+ entry.stop();
1829
+ const wasCurrent = this.currentWaapi === entry;
1830
+ const next = queued;
1831
+ if (wasCurrent && next) {
1832
+ if (next.samples.values.length >= 2 && next.samples.durationMs > 0) {
1833
+ leg = next;
1834
+ continue;
1835
+ }
1836
+ this.currentWaapi = null;
1837
+ this.applySizeFn(next.target);
1838
+ return;
1839
+ }
1840
+ if (wasCurrent) this.currentWaapi = null;
1841
+ if (wasCurrent && entry.anim.playState === "finished") {
1842
+ this.applySizeFn(leg.target);
1843
+ try {
1844
+ entry.anim.cancel();
1845
+ } catch {
1846
+ }
1847
+ }
1848
+ return;
1691
1849
  }
1692
1850
  }
1693
1851
  destroy() {
@@ -1710,9 +1868,10 @@ var init_animation_runner = __esm({
1710
1868
  });
1711
1869
 
1712
1870
  // src/core/lifecycle/focus-trap.ts
1713
- var FOCUSABLE, isVisible, collectFocusables, focusables, containsComposed, trapStack, installFocusTrap;
1871
+ var FOCUSABLE, isVisible, collectFocusables, focusables, findDeep, FOCUS_ALLOW_ATTR, composedParent, containsComposed, isAllowedOutside, deepActiveElement, trapStack, installFocusTrap;
1714
1872
  var init_focus_trap = __esm({
1715
1873
  "src/core/lifecycle/focus-trap.ts"() {
1874
+ init_shared();
1716
1875
  FOCUSABLE = [
1717
1876
  "a[href]",
1718
1877
  "area[href]",
@@ -1747,27 +1906,51 @@ var init_focus_trap = __esm({
1747
1906
  focusables = (root) => collectFocusables(root).filter(
1748
1907
  (el) => !el.hasAttribute("inert") && isVisible(el) && !el.matches("[aria-hidden='true']")
1749
1908
  );
1909
+ findDeep = (root, selector) => {
1910
+ const direct = root.querySelector(selector);
1911
+ if (direct || typeof HTMLSlotElement === "undefined") return direct;
1912
+ for (const slot of Array.from(root.querySelectorAll("slot"))) {
1913
+ for (const assigned of slot.assignedElements()) {
1914
+ if (assigned.matches(selector)) return assigned;
1915
+ const inner = findDeep(assigned, selector);
1916
+ if (inner) return inner;
1917
+ }
1918
+ }
1919
+ return null;
1920
+ };
1921
+ FOCUS_ALLOW_ATTR = "data-bs-focus-allow";
1922
+ composedParent = (node) => {
1923
+ const slot = node.assignedSlot;
1924
+ if (slot) return slot;
1925
+ const parent = node.parentNode;
1926
+ return parent instanceof ShadowRoot ? parent.host : parent;
1927
+ };
1750
1928
  containsComposed = (container, node) => {
1751
- let n = node;
1752
- while (n) {
1929
+ for (let n = node; n; n = composedParent(n)) {
1753
1930
  if (n === container) return true;
1754
- const slot = n.assignedSlot;
1755
- if (slot) {
1756
- n = slot;
1757
- continue;
1758
- }
1759
- const parent = n.parentNode;
1760
- n = parent instanceof ShadowRoot ? parent.host : parent;
1761
1931
  }
1762
1932
  return false;
1763
1933
  };
1764
- trapStack = [];
1934
+ isAllowedOutside = (node) => {
1935
+ for (let n = node; n; n = composedParent(n)) {
1936
+ if (n instanceof Element && n.hasAttribute(FOCUS_ALLOW_ATTR)) return true;
1937
+ }
1938
+ return false;
1939
+ };
1940
+ deepActiveElement = () => {
1941
+ let active = document.activeElement;
1942
+ while (active?.shadowRoot?.activeElement) {
1943
+ active = active.shadowRoot.activeElement;
1944
+ }
1945
+ return active;
1946
+ };
1947
+ trapStack = shared("focusTraps", () => []);
1765
1948
  installFocusTrap = (container, options = {}) => {
1766
1949
  if (typeof document === "undefined") return () => {
1767
1950
  };
1768
1951
  const token = {};
1769
- trapStack.push(token);
1770
- const isActive = () => trapStack[trapStack.length - 1] === token;
1952
+ if (!options.isActive) trapStack.push(token);
1953
+ const isActive = options.isActive ?? (() => trapStack[trapStack.length - 1] === token);
1771
1954
  const previouslyFocused = document.activeElement;
1772
1955
  const focusInitial = () => {
1773
1956
  const spec = options.initialFocus;
@@ -1776,10 +1959,11 @@ var init_focus_trap = __esm({
1776
1959
  container.focus({ preventScroll: true });
1777
1960
  return;
1778
1961
  }
1779
- const initial = typeof spec === "string" ? container.querySelector(spec) : spec ?? focusables(container)[0] ?? container;
1962
+ const initial = typeof spec === "string" ? findDeep(container, spec) : spec ?? focusables(container)[0] ?? container;
1780
1963
  initial?.focus({ preventScroll: true });
1781
1964
  };
1782
- focusInitial();
1965
+ if (!containsComposed(container, deepActiveElement())) focusInitial();
1966
+ let backwards = false;
1783
1967
  const handleKey = (e) => {
1784
1968
  if (!isActive()) return;
1785
1969
  if (e.key === "Escape" && options.onEscape) {
@@ -1787,6 +1971,10 @@ var init_focus_trap = __esm({
1787
1971
  return;
1788
1972
  }
1789
1973
  if (e.key !== "Tab") return;
1974
+ backwards = e.shiftKey;
1975
+ setTimeout(() => {
1976
+ backwards = false;
1977
+ }, 0);
1790
1978
  const list = focusables(container);
1791
1979
  if (list.length === 0) {
1792
1980
  e.preventDefault();
@@ -1794,7 +1982,7 @@ var init_focus_trap = __esm({
1794
1982
  }
1795
1983
  const first = list[0];
1796
1984
  const last = list[list.length - 1];
1797
- const active = document.activeElement;
1985
+ const active = deepActiveElement();
1798
1986
  if (e.shiftKey && active === first) {
1799
1987
  e.preventDefault();
1800
1988
  last.focus();
@@ -1805,11 +1993,11 @@ var init_focus_trap = __esm({
1805
1993
  };
1806
1994
  const handleFocusIn = (e) => {
1807
1995
  if (!isActive()) return;
1808
- const target = e.target;
1809
- if (target && !containsComposed(container, target)) {
1810
- const list = focusables(container);
1811
- list[0]?.focus({ preventScroll: true });
1812
- }
1996
+ const target = e.composedPath()[0] ?? e.target;
1997
+ if (!target || containsComposed(container, target)) return;
1998
+ if (isAllowedOutside(target)) return;
1999
+ const list = focusables(container);
2000
+ list[backwards ? list.length - 1 : 0]?.focus({ preventScroll: true });
1813
2001
  };
1814
2002
  document.addEventListener("keydown", handleKey, true);
1815
2003
  document.addEventListener("focusin", handleFocusIn, true);
@@ -1833,24 +2021,29 @@ var init_focus_trap = __esm({
1833
2021
  });
1834
2022
 
1835
2023
  // src/core/lifecycle/scroll-lock.ts
1836
- var lockCount, savedStyles, lockBodyScroll;
2024
+ var state, lockBodyScroll;
1837
2025
  var init_scroll_lock = __esm({
1838
2026
  "src/core/lifecycle/scroll-lock.ts"() {
1839
- lockCount = 0;
1840
- savedStyles = null;
2027
+ init_shared();
2028
+ state = shared("scrollLock", () => ({
2029
+ count: 0,
2030
+ saved: null
2031
+ }));
1841
2032
  lockBodyScroll = () => {
1842
2033
  if (typeof document === "undefined") return () => {
1843
2034
  };
1844
- if (lockCount === 0) {
2035
+ if (state.count === 0) {
1845
2036
  const body = document.body;
1846
- savedStyles = {
2037
+ const saved = {
1847
2038
  overflow: body.style.overflow,
1848
2039
  position: body.style.position,
1849
2040
  top: body.style.top,
1850
2041
  width: body.style.width,
1851
2042
  paddingRight: body.style.paddingRight,
2043
+ scrollX: window.scrollX,
1852
2044
  scrollY: window.scrollY
1853
2045
  };
2046
+ state.saved = saved;
1854
2047
  const scrollbarGap = window.innerWidth - document.documentElement.clientWidth;
1855
2048
  if (scrollbarGap > 0) {
1856
2049
  const current = parseFloat(getComputedStyle(body).paddingRight) || 0;
@@ -1858,24 +2051,29 @@ var init_scroll_lock = __esm({
1858
2051
  }
1859
2052
  body.style.overflow = "hidden";
1860
2053
  body.style.position = "fixed";
1861
- body.style.top = `-${savedStyles.scrollY}px`;
2054
+ body.style.top = `-${saved.scrollY}px`;
1862
2055
  body.style.width = "100%";
1863
2056
  }
1864
- lockCount++;
2057
+ state.count++;
1865
2058
  let released = false;
1866
2059
  return () => {
1867
2060
  if (released) return;
1868
2061
  released = true;
1869
- lockCount = Math.max(0, lockCount - 1);
1870
- if (lockCount === 0 && savedStyles) {
2062
+ state.count = Math.max(0, state.count - 1);
2063
+ if (state.count === 0 && state.saved) {
1871
2064
  const body = document.body;
1872
- body.style.overflow = savedStyles.overflow;
1873
- body.style.position = savedStyles.position;
1874
- body.style.top = savedStyles.top;
1875
- body.style.width = savedStyles.width;
1876
- body.style.paddingRight = savedStyles.paddingRight;
1877
- window.scrollTo(0, savedStyles.scrollY);
1878
- savedStyles = null;
2065
+ const saved = state.saved;
2066
+ body.style.overflow = saved.overflow;
2067
+ body.style.position = saved.position;
2068
+ body.style.top = saved.top;
2069
+ body.style.width = saved.width;
2070
+ body.style.paddingRight = saved.paddingRight;
2071
+ window.scrollTo({
2072
+ top: saved.scrollY,
2073
+ left: saved.scrollX,
2074
+ behavior: "instant"
2075
+ });
2076
+ state.saved = null;
1879
2077
  }
1880
2078
  };
1881
2079
  };
@@ -1885,32 +2083,47 @@ var init_scroll_lock = __esm({
1885
2083
  // src/core/features/inert-siblings.ts
1886
2084
  function createInertSiblings(rootProvider) {
1887
2085
  const tracked = [];
2086
+ const remove = () => {
2087
+ for (const el of tracked) el.removeAttribute("inert");
2088
+ tracked.length = 0;
2089
+ };
1888
2090
  return {
1889
2091
  apply() {
1890
2092
  if (typeof document === "undefined") return;
1891
- let top = rootProvider();
1892
- while (top.parentElement && top.parentElement !== document.body) {
1893
- top = top.parentElement;
1894
- }
1895
- const parent = top.parentElement ?? document.body;
1896
- for (const child of Array.from(parent.children)) {
1897
- if (child === top) continue;
1898
- if (child.hasAttribute("inert")) continue;
1899
- if (child.classList.contains("bs-backdrop") || child.classList.contains("bs-screen") || child.classList.contains("bs-root")) {
2093
+ remove();
2094
+ const surface = rootProvider();
2095
+ let node = surface.closest(OWN_ROOTS) ?? surface;
2096
+ while (node && node !== document.body) {
2097
+ const parent = node.parentElement;
2098
+ if (!parent) {
2099
+ const root = node.getRootNode();
2100
+ node = typeof ShadowRoot !== "undefined" && root instanceof ShadowRoot ? root.host : null;
1900
2101
  continue;
1901
2102
  }
1902
- child.setAttribute("inert", "");
1903
- tracked.push(child);
2103
+ for (const sibling of Array.from(parent.children)) {
2104
+ if (sibling === node) continue;
2105
+ if (sibling.hasAttribute("inert") || isLayer(sibling)) continue;
2106
+ sibling.setAttribute("inert", "");
2107
+ tracked.push(sibling);
2108
+ }
2109
+ node = parent;
1904
2110
  }
1905
2111
  },
1906
- remove() {
1907
- for (const el of tracked) el.removeAttribute("inert");
1908
- tracked.length = 0;
1909
- }
2112
+ remove
1910
2113
  };
1911
2114
  }
2115
+ var OWN_ROOTS, LAYER_CLASSES, isLayer;
1912
2116
  var init_inert_siblings = __esm({
1913
2117
  "src/core/features/inert-siblings.ts"() {
2118
+ OWN_ROOTS = ".bs-root, .ovl-root";
2119
+ LAYER_CLASSES = [
2120
+ "bs-backdrop",
2121
+ "bs-screen",
2122
+ "bs-root",
2123
+ "ovl-backdrop",
2124
+ "ovl-root"
2125
+ ];
2126
+ isLayer = (el) => LAYER_CLASSES.some((name) => el.classList.contains(name));
1914
2127
  }
1915
2128
  });
1916
2129
 
@@ -1924,6 +2137,7 @@ var init_lifecycle_controller = __esm({
1924
2137
  LifecycleController = class {
1925
2138
  constructor(deps, opts) {
1926
2139
  __publicField(this, "element");
2140
+ __publicField(this, "isTop");
1927
2141
  __publicField(this, "focusTrapEnabled");
1928
2142
  __publicField(this, "initialFocus");
1929
2143
  __publicField(this, "closeOnEscape");
@@ -1937,6 +2151,7 @@ var init_lifecycle_controller = __esm({
1937
2151
  __publicField(this, "installed", false);
1938
2152
  __publicField(this, "destroyed", false);
1939
2153
  this.element = deps.element;
2154
+ this.isTop = deps.isTop;
1940
2155
  this.focusTrapEnabled = opts.focusTrap ?? false;
1941
2156
  this.initialFocus = opts.initialFocus;
1942
2157
  this.closeOnEscape = opts.closeOnEscape ?? true;
@@ -1957,12 +2172,17 @@ var init_lifecycle_controller = __esm({
1957
2172
  }
1958
2173
  if (this.focusTrapEnabled && !this.releaseFocusTrap) {
1959
2174
  this.releaseFocusTrap = installFocusTrap(this.element, {
1960
- initialFocus: this.initialFocus
2175
+ initialFocus: this.initialFocus,
2176
+ isActive: this.isTop
1961
2177
  });
1962
2178
  }
1963
- if (this.inertSiblingsEnabled && this.shouldApplyInertSiblings()) {
1964
- this.inertSiblings.apply();
1965
- }
2179
+ this.syncTop();
2180
+ }
2181
+ syncTop() {
2182
+ if (!this.installed || !this.inertSiblingsEnabled) return;
2183
+ if (!this.shouldApplyInertSiblings()) return;
2184
+ if (this.isTop?.() ?? true) this.inertSiblings.apply();
2185
+ else this.inertSiblings.remove();
1966
2186
  }
1967
2187
  setReturnFocus(target) {
1968
2188
  if (this.destroyed) return;
@@ -2137,10 +2357,14 @@ var init_gestures = __esm({
2137
2357
  if (wasPending) return;
2138
2358
  callbacks.onCancel?.();
2139
2359
  };
2360
+ const onLostCapture = (e) => {
2361
+ if (e.target === handle) onPointerCancel(e);
2362
+ };
2140
2363
  handle.addEventListener("pointerdown", onPointerDown);
2141
2364
  handle.addEventListener("pointermove", onPointerMove);
2142
2365
  handle.addEventListener("pointerup", finishGesture);
2143
2366
  handle.addEventListener("pointercancel", onPointerCancel);
2367
+ handle.addEventListener("lostpointercapture", onLostCapture);
2144
2368
  const managesTouchAction = options.manageTouchAction !== false;
2145
2369
  const prevTouchAction = handle.style.touchAction;
2146
2370
  if (managesTouchAction) {
@@ -2151,6 +2375,7 @@ var init_gestures = __esm({
2151
2375
  handle.removeEventListener("pointermove", onPointerMove);
2152
2376
  handle.removeEventListener("pointerup", finishGesture);
2153
2377
  handle.removeEventListener("pointercancel", onPointerCancel);
2378
+ handle.removeEventListener("lostpointercapture", onLostCapture);
2154
2379
  if (managesTouchAction) handle.style.touchAction = prevTouchAction;
2155
2380
  if (activePointerId !== null && handle.hasPointerCapture(activePointerId)) {
2156
2381
  handle.releasePointerCapture(activePointerId);
@@ -2283,8 +2508,7 @@ var init_gesture_controller = __esm({
2283
2508
  size: this.deps.getDragContext().size,
2284
2509
  velocity: 0
2285
2510
  });
2286
- const restoreTo = this.dragStartSize;
2287
- void this.deps.animateTo(restoreTo, 0);
2511
+ this.deps.restoreAfterDrag();
2288
2512
  }
2289
2513
  }, this.deps.gestureOptions);
2290
2514
  return this.detach;
@@ -2343,7 +2567,7 @@ var init_content_gesture = __esm({
2343
2567
  });
2344
2568
 
2345
2569
  // src/core/primitives/logical-mode.ts
2346
- var isLogicalMode, readDirection, resolveMode;
2570
+ var isLogicalMode, readDirection, guessPhysicalMode, resolveMode;
2347
2571
  var init_logical_mode = __esm({
2348
2572
  "src/core/primitives/logical-mode.ts"() {
2349
2573
  isLogicalMode = (mode) => mode === "start" || mode === "end";
@@ -2364,6 +2588,11 @@ var init_logical_mode = __esm({
2364
2588
  }
2365
2589
  return "ltr";
2366
2590
  };
2591
+ guessPhysicalMode = (mode) => {
2592
+ if (mode === "start") return "left";
2593
+ if (mode === "end") return "right";
2594
+ return mode ?? "bottom";
2595
+ };
2367
2596
  resolveMode = (mode, el) => {
2368
2597
  if (!isLogicalMode(mode)) return mode;
2369
2598
  const rtl = readDirection(el) === "rtl";
@@ -2427,22 +2656,24 @@ function createScrollCache(deps) {
2427
2656
  return size < max / 2;
2428
2657
  };
2429
2658
  return {
2430
- cache(fromId, prevSize, nextSize) {
2659
+ leave(fromId, prevSize, nextSize) {
2431
2660
  const container = deps.scrollContainer;
2432
2661
  if (!container) return;
2433
- if (isSmallSize(prevSize)) return;
2434
- if (!isSmallSize(nextSize)) return;
2662
+ if (nextSize <= 0) {
2663
+ positions.clear();
2664
+ return;
2665
+ }
2666
+ if (isSmallSize(prevSize) || !isSmallSize(nextSize)) return;
2435
2667
  positions.set(fromId, container.scrollTop);
2436
2668
  },
2437
- restore(toId, prevSize, nextSize) {
2669
+ enter(toId, prevSize, nextSize) {
2438
2670
  const container = deps.scrollContainer;
2439
2671
  if (!container) return;
2440
- if (isSmallSize(nextSize)) return;
2441
- if (!isSmallSize(prevSize)) return;
2672
+ if (isSmallSize(nextSize) || !isSmallSize(prevSize)) return;
2442
2673
  const cached = positions.get(toId);
2443
2674
  if (cached === void 0) return;
2444
- container.scrollTop = cached;
2445
2675
  positions.delete(toId);
2676
+ container.scrollTop = cached;
2446
2677
  },
2447
2678
  clear() {
2448
2679
  positions.clear();
@@ -2566,17 +2797,18 @@ function attachAnchor(deps, opts) {
2566
2797
  const isDock = position === "dock-bottom" || position === "dock-top";
2567
2798
  const ws = wrapper.style;
2568
2799
  ws.position = "fixed";
2569
- if (isDock) {
2800
+ const place = () => {
2801
+ resetOverlayPosition(ws);
2802
+ if (!isDock) {
2803
+ applyOverlayPosition(ws, deps.getMode(), position, opts.inset ?? "16px");
2804
+ return;
2805
+ }
2570
2806
  ws.left = "0";
2571
2807
  ws.right = "0";
2572
- if (position === "dock-bottom") {
2573
- ws.bottom = "0";
2574
- } else {
2575
- ws.top = "0";
2576
- }
2577
- } else {
2578
- applyOverlayPosition(ws, deps.mode, position, opts.inset ?? "16px");
2579
- }
2808
+ if (position === "dock-bottom") ws.bottom = "0";
2809
+ else ws.top = "0";
2810
+ };
2811
+ place();
2580
2812
  if (opts.fadeRange) {
2581
2813
  const [r0, r1] = opts.fadeRange;
2582
2814
  const span = Math.max(r1 - r0, 1e-4);
@@ -2586,10 +2818,10 @@ function attachAnchor(deps, opts) {
2586
2818
  deps.host.appendChild(wrapper);
2587
2819
  let visible = null;
2588
2820
  let inFlight = null;
2589
- const shouldShow = (state) => {
2590
- if (typeof opts.showOn === "function") return opts.showOn(state);
2591
- if (Array.isArray(opts.showOn)) return opts.showOn.includes(state.activeId);
2592
- return isDock || state.size > 0;
2821
+ const shouldShow = (state3) => {
2822
+ if (typeof opts.showOn === "function") return opts.showOn(state3);
2823
+ if (Array.isArray(opts.showOn)) return opts.showOn.includes(state3.activeId);
2824
+ return isDock || state3.size > 0;
2593
2825
  };
2594
2826
  const applyVisibility = (next, animate) => {
2595
2827
  if (next === visible) return;
@@ -2636,7 +2868,8 @@ function attachAnchor(deps, opts) {
2636
2868
  },
2637
2869
  syncZ: (z) => {
2638
2870
  wrapper.style.zIndex = String(z);
2639
- }
2871
+ },
2872
+ reposition: place
2640
2873
  };
2641
2874
  }
2642
2875
  var init_sheet_anchors = __esm({
@@ -2649,30 +2882,37 @@ var init_sheet_anchors = __esm({
2649
2882
  // src/core/features/scrim-stages.ts
2650
2883
  function installScrimStages(deps, opts) {
2651
2884
  const doc = deps.host.ownerDocument;
2652
- const entries2 = opts.stages.map((def) => {
2885
+ const entries = opts.stages.map((def) => {
2653
2886
  const wrapper = doc.createElement("div");
2654
2887
  wrapper.className = "bs-scrim-stage";
2655
2888
  const ws = wrapper.style;
2656
- ws.position = "absolute";
2657
- applyOverlayPosition(
2658
- ws,
2659
- deps.mode,
2660
- def.position ?? opts.position ?? "center",
2661
- def.inset ?? opts.inset ?? "16px"
2662
- );
2889
+ ws.position = "fixed";
2663
2890
  ws.visibility = "hidden";
2664
2891
  ws.pointerEvents = "none";
2665
2892
  wrapper.appendChild(def.element);
2666
2893
  deps.host.appendChild(wrapper);
2667
2894
  return { def, wrapper, inFlight: null };
2668
2895
  });
2896
+ const place = () => {
2897
+ for (const entry of entries) {
2898
+ const ws = entry.wrapper.style;
2899
+ resetOverlayPosition(ws);
2900
+ applyOverlayPosition(
2901
+ ws,
2902
+ deps.getMode(),
2903
+ entry.def.position ?? opts.position ?? "center",
2904
+ entry.def.inset ?? opts.inset ?? "16px"
2905
+ );
2906
+ }
2907
+ };
2908
+ place();
2669
2909
  let active = null;
2670
2910
  const resolveActive = () => {
2671
- const state = deps.getState();
2672
- if (state.size === 0) {
2673
- return entries2.find((e) => matchesId(e.def, state.activeId)) ?? null;
2911
+ const state3 = deps.getState();
2912
+ if (state3.size === 0) {
2913
+ return entries.find((e) => matchesId(e.def, state3.activeId)) ?? null;
2674
2914
  }
2675
- return entries2.find((e) => matchesId(e.def, state.activeId)) ?? entries2.find((e) => matchesRange(e.def, state.progress)) ?? null;
2915
+ return entries.find((e) => matchesId(e.def, state3.activeId)) ?? entries.find((e) => matchesRange(e.def, state3.progress)) ?? null;
2676
2916
  };
2677
2917
  const hide = (entry, animate) => {
2678
2918
  entry.inFlight?.cancel();
@@ -2721,20 +2961,23 @@ function installScrimStages(deps, opts) {
2721
2961
  deps.on("open", () => update(true)),
2722
2962
  deps.on("close", () => update(true))
2723
2963
  ];
2724
- if (entries2.some((e) => e.def.forRange)) {
2964
+ if (entries.some((e) => e.def.forRange)) {
2725
2965
  offs.push(deps.on("progress", () => update(true)));
2726
2966
  }
2727
2967
  update(false);
2728
- return () => {
2729
- offs.forEach((off) => off());
2730
- for (const entry of entries2) {
2731
- entry.inFlight?.cancel();
2732
- entry.inFlight = null;
2733
- if (entry.wrapper.parentNode) {
2734
- entry.wrapper.parentNode.removeChild(entry.wrapper);
2968
+ return {
2969
+ reposition: place,
2970
+ detach: () => {
2971
+ offs.forEach((off) => off());
2972
+ for (const entry of entries) {
2973
+ entry.inFlight?.cancel();
2974
+ entry.inFlight = null;
2975
+ if (entry.wrapper.parentNode) {
2976
+ entry.wrapper.parentNode.removeChild(entry.wrapper);
2977
+ }
2735
2978
  }
2979
+ active = null;
2736
2980
  }
2737
- active = null;
2738
2981
  };
2739
2982
  }
2740
2983
  var matchesId, matchesRange;
@@ -2784,11 +3027,13 @@ function resolveEngineOptions(opts, extras) {
2784
3027
  scrimMode: opts.scrimMode,
2785
3028
  scrimColor: opts.scrimColor,
2786
3029
  scrimBlur: opts.scrimBlur,
2787
- scrimInteractive: opts.scrimInteractive ?? (opts.scrimTapToClose ? true : void 0),
3030
+ scrimInteractive: opts.scrimInteractive,
2788
3031
  scrimTapToClose: opts.scrimTapToClose,
2789
3032
  scrimPreset: opts.scrimPreset,
2790
3033
  screenRange: opts.screenRange,
2791
- backdropRange: opts.backdropRange
3034
+ backdropRange: opts.backdropRange,
3035
+ backdropOpacity: opts.backdropOpacity,
3036
+ backdropColor: opts.backdropColor
2792
3037
  },
2793
3038
  animation: {
2794
3039
  animation: opts.animation,
@@ -2869,6 +3114,7 @@ var init_BottomSheetCore = __esm({
2869
3114
  init_linked_sheets();
2870
3115
  init_resize_observer();
2871
3116
  init_fit_observer();
3117
+ init_teleport();
2872
3118
  init_max_height_controller();
2873
3119
  init_fit_measurement();
2874
3120
  init_slider_keyboard();
@@ -2913,6 +3159,7 @@ var init_BottomSheetCore = __esm({
2913
3159
  __publicField(this, "fitContentToSnap");
2914
3160
  __publicField(this, "settleAnimation");
2915
3161
  __publicField(this, "persistent");
3162
+ __publicField(this, "keyboardInset", 0);
2916
3163
  __publicField(this, "disableCloseFlag");
2917
3164
  __publicField(this, "disableDragFlag");
2918
3165
  __publicField(this, "closeOnRouteChange");
@@ -2927,6 +3174,7 @@ var init_BottomSheetCore = __esm({
2927
3174
  __publicField(this, "detachSheetGesture", null);
2928
3175
  __publicField(this, "detachSliderKeyboard", null);
2929
3176
  __publicField(this, "rootEl", null);
3177
+ __publicField(this, "homeRoot", null);
2930
3178
  __publicField(this, "destroyed", false);
2931
3179
  __publicField(this, "restClosed", false);
2932
3180
  __publicField(this, "currentViewTransition", null);
@@ -2934,8 +3182,13 @@ var init_BottomSheetCore = __esm({
2934
3182
  __publicField(this, "sizeWriteSentinel", new WriteSentinel());
2935
3183
  __publicField(this, "progressWriteSentinel", new WriteSentinel());
2936
3184
  __publicField(this, "isTopSheet", true);
2937
- __publicField(this, "opening", false);
2938
- __publicField(this, "promotedForOpen", false);
3185
+ __publicField(this, "phase", "closed");
3186
+ __publicField(this, "transition", null);
3187
+ __publicField(this, "inFlight", null);
3188
+ __publicField(this, "outbox", []);
3189
+ __publicField(this, "flushing", false);
3190
+ __publicField(this, "openPending", false);
3191
+ __publicField(this, "settleHolds", []);
2939
3192
  __publicField(this, "allowOvershoot", false);
2940
3193
  __publicField(this, "progressPayload", {
2941
3194
  value: 0,
@@ -2956,6 +3209,7 @@ var init_BottomSheetCore = __esm({
2956
3209
  __publicField(this, "anchorHost", null);
2957
3210
  __publicField(this, "stackZ", 100);
2958
3211
  __publicField(this, "detachScrimStages", null);
3212
+ __publicField(this, "placeScrimStages", null);
2959
3213
  __publicField(this, "stackEffectEnabled", false);
2960
3214
  __publicField(this, "stackEffectPrimed", false);
2961
3215
  __publicField(this, "fitDeps");
@@ -2963,13 +3217,7 @@ var init_BottomSheetCore = __esm({
2963
3217
  __publicField(this, "featureList", []);
2964
3218
  __publicField(this, "featureCtx");
2965
3219
  const resolved = resolveEngineOptions(opts, {
2966
- shouldApplyInertSiblings: () => {
2967
- if (typeof document === "undefined") return false;
2968
- const bodyChildren = Array.from(document.body.children);
2969
- return bodyChildren.some(
2970
- (c) => c === opts.element || c.contains(opts.element)
2971
- );
2972
- }
3220
+ shouldApplyInertSiblings: () => opts.element.isConnected
2973
3221
  });
2974
3222
  this.element = opts.element;
2975
3223
  this.handle = opts.handle ?? opts.element;
@@ -2998,7 +3246,6 @@ var init_BottomSheetCore = __esm({
2998
3246
  void this.snapTo(id);
2999
3247
  },
3000
3248
  close: () => {
3001
- if (!this.canDismiss()) return;
3002
3249
  void this.close("backdrop");
3003
3250
  }
3004
3251
  },
@@ -3028,7 +3275,8 @@ var init_BottomSheetCore = __esm({
3028
3275
  this.lifecycle = new LifecycleController(
3029
3276
  {
3030
3277
  element: this.element,
3031
- close: () => this.close()
3278
+ close: () => this.close(),
3279
+ isTop: () => this.isTopSheet
3032
3280
  },
3033
3281
  resolved.lifecycle
3034
3282
  );
@@ -3055,6 +3303,7 @@ var init_BottomSheetCore = __esm({
3055
3303
  auditVhUsage(this.snapPointsRaw);
3056
3304
  this.auditDuplicateSnapIds(this.snapPointsRaw);
3057
3305
  this.rootEl = this.element.closest(".bs-root");
3306
+ this.homeRoot = homeRootOf(this.rootEl);
3058
3307
  this.maxHeightDeps = {
3059
3308
  element: this.element,
3060
3309
  mode: this.mode,
@@ -3082,7 +3331,9 @@ var init_BottomSheetCore = __esm({
3082
3331
  );
3083
3332
  const initial = this.snaps.findById(this.activeId);
3084
3333
  if (initial) this.size = initial.size;
3334
+ this.phase = this.size > 0 ? "open" : "closed";
3085
3335
  this.applySize(this.size);
3336
+ this.restClosed = this.element.getAttribute("data-bs-rest") === "closed";
3086
3337
  this.setRestClosed(this.size === 0);
3087
3338
  this.updateAriaSlider();
3088
3339
  this.scrollCache = createScrollCache({
@@ -3093,12 +3344,11 @@ var init_BottomSheetCore = __esm({
3093
3344
  this.attach();
3094
3345
  this.registerInStack();
3095
3346
  if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
3096
- const io = new IntersectionObserver((entries2) => {
3097
- for (const entry of entries2) {
3347
+ const io = new IntersectionObserver((entries) => {
3348
+ for (const entry of entries) {
3098
3349
  if (!entry.isIntersecting) continue;
3099
3350
  if (this.destroyed) return;
3100
- this.snaps.recompute();
3101
- this.healActiveSnap();
3351
+ this.recompute();
3102
3352
  io.disconnect();
3103
3353
  return;
3104
3354
  }
@@ -3108,6 +3358,7 @@ var init_BottomSheetCore = __esm({
3108
3358
  }
3109
3359
  this.teardowns.add(
3110
3360
  installFitObserver({
3361
+ element: this.element,
3111
3362
  handle: this.handle,
3112
3363
  scrollContainer: this.scrollContainer,
3113
3364
  hasFitSnap: () => this.snapPointsRaw.some(
@@ -3123,9 +3374,7 @@ var init_BottomSheetCore = __esm({
3123
3374
  this.applyAutoAriaLabelledBy();
3124
3375
  this.runFeatureStage("post");
3125
3376
  this.warnOrphanFeatureOptions();
3126
- if (this.size > 0) {
3127
- this.handleOpen();
3128
- }
3377
+ if (this.phase === "open") this.installLifecycle(true);
3129
3378
  }
3130
3379
  buildFeatureContext(autoCollapseAfter) {
3131
3380
  return {
@@ -3153,21 +3402,27 @@ var init_BottomSheetCore = __esm({
3153
3402
  getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
3154
3403
  resolveSnap: (id) => this.snaps.findById(id),
3155
3404
  resolveActiveSnap: () => this.snaps.findById(this.activeId),
3405
+ getPhase: () => this.phase,
3156
3406
  setSize: (size) => {
3157
3407
  this.size = size;
3158
3408
  },
3159
3409
  setMaxAxisSize: (size) => {
3160
3410
  this.snaps.setMaxAxisSize(size);
3161
3411
  },
3412
+ setKeyboardInset: (px) => this.setKeyboardInset(px),
3162
3413
  applySize: (size) => this.applySize(size),
3163
3414
  recomputeSnaps: () => this.recomputeSnaps(),
3415
+ reseat: () => this.reseat(),
3416
+ holdSettle: (settled) => {
3417
+ this.settleHolds.push(settled);
3418
+ },
3164
3419
  newCycle: () => {
3165
3420
  this.newCycle();
3166
3421
  },
3167
- cancelInFlight: () => {
3168
- this.animation.cancel();
3422
+ cancelInFlight: () => this.suspend(),
3423
+ resyncAfterResize: () => {
3424
+ if (!this.destroyed) this.land(false);
3169
3425
  },
3170
- resyncAfterResize: () => this.resyncAfterResize(),
3171
3426
  snapTo: (id) => {
3172
3427
  void this.snapTo(id);
3173
3428
  },
@@ -3206,8 +3461,9 @@ var init_BottomSheetCore = __esm({
3206
3461
  return {
3207
3462
  size: this.size,
3208
3463
  activeId: this.activeId,
3464
+ phase: this.phase,
3209
3465
  isDragging: this.isDraggingAny(),
3210
- isAnimating: this.animation.isAnimating,
3466
+ isAnimating: this.animation.isAnimating || this.currentViewTransition !== null,
3211
3467
  progress: this.computeProgress(this.size)
3212
3468
  };
3213
3469
  }
@@ -3261,49 +3517,53 @@ var init_BottomSheetCore = __esm({
3261
3517
  getResolvedSnaps() {
3262
3518
  return this.snaps.getResolvedSnaps();
3263
3519
  }
3264
- async snapTo(id, velocityOrOpts = 0, _skipBeforeSnap = false) {
3265
- if (this.destroyed) return;
3520
+ snapTo(id, velocityOrOpts = 0, _skipBeforeSnap = false) {
3266
3521
  const opts = typeof velocityOrOpts === "object" ? velocityOrOpts : { velocity: velocityOrOpts };
3267
- const velocityPxPerMs = opts.velocity ?? 0;
3268
- const externalSignal = opts.signal;
3269
- if (externalSignal?.aborted) return;
3522
+ return this.transitionTo(
3523
+ id,
3524
+ opts.velocity ?? 0,
3525
+ _skipBeforeSnap,
3526
+ opts.signal
3527
+ );
3528
+ }
3529
+ transitionTo(id, velocityPxPerMs = 0, skipBeforeSnap = false, externalSignal) {
3530
+ if (this.destroyed || externalSignal?.aborted) return Promise.resolve();
3270
3531
  const target = this.snaps.findById(id);
3271
3532
  if (!target) {
3272
3533
  devWarn(`[BottomSheet] unknown snap id: ${id}`);
3273
- return;
3534
+ return Promise.resolve();
3274
3535
  }
3275
3536
  if (!this.snaps.getAllowedIds().includes(id)) {
3276
3537
  devWarn(`[BottomSheet] snap "${id}" is not in allowed list`);
3277
- return;
3538
+ return Promise.resolve();
3278
3539
  }
3279
- if (!_skipBeforeSnap && this.emitBeforeSnap(target, this.activeId)) {
3280
- return;
3540
+ if (target.size === 0 && this.closingBlocked()) return Promise.resolve();
3541
+ if (!externalSignal && this.inFlight?.id === id) return this.inFlight.done;
3542
+ if (!skipBeforeSnap && this.emitBeforeSnap(target, this.activeId)) {
3543
+ return Promise.resolve();
3281
3544
  }
3282
- const resumingOpen = this.opening;
3283
- const signal = this.newCycle();
3284
- const onExternalAbort = () => {
3285
- this.animation.cancel();
3286
- this.newCycle();
3287
- };
3545
+ const flight = { id, done: Promise.resolve() };
3546
+ flight.done = this.runTransition(
3547
+ target,
3548
+ velocityPxPerMs,
3549
+ false,
3550
+ externalSignal,
3551
+ flight
3552
+ );
3553
+ return flight.done;
3554
+ }
3555
+ async runTransition(target, velocityPxPerMs, fromDrag, externalSignal, flight = null) {
3556
+ const signal = this.beginTransition(target);
3557
+ const transition = this.transition;
3558
+ if (signal.aborted || !transition) return;
3559
+ this.inFlight = flight;
3560
+ const onExternalAbort = () => this.suspend();
3288
3561
  externalSignal?.addEventListener("abort", onExternalAbort, { once: true });
3289
- const wasClosed = this.size === 0 || resumingOpen;
3290
- const previousId = this.activeId;
3291
- const previousSize = this.size;
3292
- this.scrollCache.cache(previousId, previousSize, target.size);
3293
- this.activeId = id;
3294
- const rawTargetSize = this.snapPointsRaw.find((p) => p.id === id)?.size;
3295
- const opensToRest = id === "closed" || rawTargetSize === 0;
3296
- if (wasClosed && !opensToRest) {
3297
- this.opening = true;
3298
- if (!resumingOpen) {
3299
- this.promotedForOpen = true;
3300
- sheetStack.promote(this.id);
3301
- }
3302
- }
3303
- if (this.animation.viewTransitionsAvailable) {
3562
+ this.allowOvershoot = fromDrag;
3563
+ if (!fromDrag && this.animation.viewTransitionsAvailable) {
3304
3564
  this.currentViewTransition?.skipTransition?.();
3305
3565
  const vt = document.startViewTransition(() => {
3306
- this.applySize(target.size);
3566
+ if (!signal.aborted) this.applySize(transition.size);
3307
3567
  });
3308
3568
  vt.ready?.catch(() => {
3309
3569
  });
@@ -3314,25 +3574,202 @@ var init_BottomSheetCore = __esm({
3314
3574
  }
3315
3575
  if (this.currentViewTransition === vt) this.currentViewTransition = null;
3316
3576
  } else {
3317
- await this.animation.animateTo(target.size, velocityPxPerMs);
3577
+ await this.animation.animateTo(transition.size, velocityPxPerMs);
3318
3578
  }
3319
3579
  externalSignal?.removeEventListener("abort", onExternalAbort);
3320
3580
  if (signal.aborted) return;
3321
- this.opening = false;
3322
- this.completeSnap(id, target.size, previousSize, wasClosed, false);
3581
+ if (this.size !== transition.size) this.applySize(transition.size);
3582
+ this.land(fromDrag);
3583
+ if (this.settleHolds.length > 0) {
3584
+ await Promise.allSettled(this.settleHolds.splice(0));
3585
+ }
3586
+ }
3587
+ beginTransition(target) {
3588
+ const signal = this.newCycle();
3589
+ const cap = this.snaps.getMaxAxisSize();
3590
+ const fromId = this.activeId;
3591
+ const fromSize = this.snaps.findById(fromId)?.size ?? this.size;
3592
+ this.scrollCache.leave(fromId, fromSize, target.size);
3593
+ this.scrollCache.enter(target.id, fromSize, target.size);
3594
+ this.activeId = target.id;
3595
+ this.transition = {
3596
+ size: cap > 0 ? Math.min(target.size, cap) : target.size,
3597
+ cap
3598
+ };
3599
+ if (target.size > 0) {
3600
+ this.enterOpening(target.id);
3601
+ } else {
3602
+ if (this.phase === "closed" && !this.isClosedSnap(target.id)) {
3603
+ sheetStack.promote(this.id);
3604
+ }
3605
+ this.enterClosing();
3606
+ }
3607
+ this.flush();
3608
+ return signal;
3323
3609
  }
3324
- completeSnap(id, targetSize, previousSize, wasClosed, withHaptic) {
3325
- this.scrollCache.restore(id, previousSize, targetSize);
3610
+ enterOpening(id) {
3611
+ if (this.phase === "open" || this.phase === "opening") return;
3612
+ const fresh = this.phase === "closed";
3613
+ this.phase = "opening";
3614
+ this.setRestClosed(false);
3615
+ if (!this.installLifecycle(fresh)) return;
3616
+ this.post("open", { id });
3617
+ this.outbox.push(() => {
3618
+ if (this.phase !== "closed") {
3619
+ notifyLinkedSheets(this.linkedSheets, this);
3620
+ }
3621
+ });
3622
+ }
3623
+ enterClosing() {
3624
+ if (this.phase === "closed" || this.phase === "closing") return;
3625
+ this.phase = "closing";
3626
+ this.post("close", void 0);
3627
+ }
3628
+ settlePhase(heal) {
3629
+ if (this.size > 0) {
3630
+ this.enterOpening(this.activeId);
3631
+ if (this.phase === "opening") {
3632
+ this.phase = "open";
3633
+ this.post("opened", { id: this.activeId });
3634
+ }
3635
+ return;
3636
+ }
3637
+ if (heal && this.phase !== "closing") return;
3638
+ this.enterClosing();
3639
+ if (this.phase === "closing") {
3640
+ this.phase = "closed";
3641
+ this.setRestClosed(true);
3642
+ this.lifecycle.release();
3643
+ sheetStack.update();
3644
+ this.post("closed", void 0);
3645
+ }
3646
+ }
3647
+ land(haptic) {
3648
+ this.transition = null;
3649
+ this.inFlight = null;
3650
+ this.allowOvershoot = false;
3651
+ this.openPending = this.size === 0 && !this.isClosedSnap(this.activeId);
3326
3652
  this.updateAriaSlider();
3327
- this.emit("snap", {
3328
- id,
3653
+ this.setRestClosed(this.size === 0);
3654
+ this.post("snap", {
3655
+ id: this.activeId,
3329
3656
  size: this.size,
3330
3657
  progress: this.computeProgress(this.size)
3331
3658
  });
3332
- if (withHaptic) this.haptic();
3333
- this.setRestClosed(targetSize === 0);
3334
- if (wasClosed && targetSize > 0) this.emitOpenSequence(id);
3335
- if (targetSize === 0) this.emitCloseSequence();
3659
+ this.settlePhase(false);
3660
+ if (haptic) this.haptic();
3661
+ this.flush();
3662
+ }
3663
+ suspend() {
3664
+ this.animation.cancel();
3665
+ this.currentViewTransition?.skipTransition?.();
3666
+ this.newCycle();
3667
+ }
3668
+ landNow() {
3669
+ const transition = this.transition;
3670
+ if (this.destroyed || !transition || this.isDraggingAny()) return;
3671
+ this.animation.cancel();
3672
+ this.currentViewTransition?.skipTransition?.();
3673
+ this.newCycle();
3674
+ this.applySize(transition.size);
3675
+ this.land(false);
3676
+ }
3677
+ reseat() {
3678
+ if (this.destroyed || this.isDraggingAny()) return;
3679
+ const active = this.snaps.findById(this.activeId);
3680
+ if (!active) return;
3681
+ const cap = this.snaps.getMaxAxisSize();
3682
+ const target = cap > 0 ? Math.min(active.size, cap) : active.size;
3683
+ this.updateAriaSlider();
3684
+ const transition = this.transition;
3685
+ if (transition) {
3686
+ if (Math.abs(target - transition.size) < SIZE_WRITE_EPSILON && Math.abs(cap - transition.cap) < SIZE_WRITE_EPSILON) {
3687
+ return;
3688
+ }
3689
+ transition.size = target;
3690
+ transition.cap = cap;
3691
+ this.applySize(this.animation.retarget(target) ? this.size : target);
3692
+ return;
3693
+ }
3694
+ if (this.openPending && target > 0 && this.phase === "closed") {
3695
+ void this.runTransition(active, 0, false);
3696
+ return;
3697
+ }
3698
+ this.applySize(target);
3699
+ this.settlePhase(true);
3700
+ this.flush();
3701
+ }
3702
+ installLifecycle(promote) {
3703
+ if (promote) sheetStack.promote(this.id);
3704
+ if (this.lifecycle.isInstalled) return true;
3705
+ try {
3706
+ this.lifecycle.install();
3707
+ return true;
3708
+ } catch (err) {
3709
+ this.abortOpen();
3710
+ queueMicrotask(() => {
3711
+ throw err;
3712
+ });
3713
+ return false;
3714
+ }
3715
+ }
3716
+ abortOpen() {
3717
+ this.animation.cancel();
3718
+ if (!this.destroyed) this.newCycle();
3719
+ this.phase = "closed";
3720
+ this.openPending = false;
3721
+ this.lifecycle.release();
3722
+ sheetStack.update();
3723
+ this.activeId = this.zeroSnapId() ?? this.activeId;
3724
+ this.applySize(0);
3725
+ this.setRestClosed(true);
3726
+ this.updateAriaSlider();
3727
+ }
3728
+ zeroSnapId() {
3729
+ return this.snapPointsRaw.find((p) => p.id === "closed")?.id ?? this.snaps.getAllowedIds().find((a) => this.snaps.findById(a)?.size === 0);
3730
+ }
3731
+ isClosedSnap(id) {
3732
+ if (id === "closed") return true;
3733
+ return this.snapPointsRaw.find((p) => p.id === id)?.size === 0;
3734
+ }
3735
+ closingBlocked() {
3736
+ return this.disableCloseFlag && this.phase !== "closed";
3737
+ }
3738
+ setKeyboardInset(px) {
3739
+ if (px === this.keyboardInset) return;
3740
+ this.keyboardInset = px;
3741
+ for (const host of this.varHosts()) {
3742
+ host.style.setProperty("--bs-keyboard-inset", `${px}px`);
3743
+ }
3744
+ }
3745
+ varHosts() {
3746
+ const hosts = /* @__PURE__ */ new Set([this.element]);
3747
+ for (const host of [
3748
+ this.anchorHost,
3749
+ this.scrimParent,
3750
+ this.rootEl,
3751
+ this.homeRoot
3752
+ ]) {
3753
+ if (host) hosts.add(host);
3754
+ }
3755
+ return hosts;
3756
+ }
3757
+ dismissBlocked() {
3758
+ return (this.disableCloseFlag || this.persistent) && this.phase !== "closed";
3759
+ }
3760
+ post(event, payload) {
3761
+ this.outbox.push(() => this.bus.emit(event, payload));
3762
+ }
3763
+ flush() {
3764
+ if (this.flushing) return;
3765
+ this.flushing = true;
3766
+ try {
3767
+ for (let next = this.outbox.shift(); next; next = this.outbox.shift()) {
3768
+ next();
3769
+ }
3770
+ } finally {
3771
+ this.flushing = false;
3772
+ }
3336
3773
  }
3337
3774
  setRestClosed(closed) {
3338
3775
  if (closed === this.restClosed) return;
@@ -3340,17 +3777,6 @@ var init_BottomSheetCore = __esm({
3340
3777
  if (closed) this.element.setAttribute("data-bs-rest", "closed");
3341
3778
  else this.element.removeAttribute("data-bs-rest");
3342
3779
  }
3343
- emitOpenSequence(id) {
3344
- this.emit("open", { id });
3345
- this.handleOpen();
3346
- notifyLinkedSheets(this.linkedSheets, this);
3347
- this.emit("opened", { id });
3348
- }
3349
- emitCloseSequence() {
3350
- this.emit("close", void 0);
3351
- this.handleClose();
3352
- this.emit("closed", void 0);
3353
- }
3354
3780
  async dragTo(targetSize, velocityOrOpts = 0) {
3355
3781
  if (this.destroyed) return;
3356
3782
  const opts = typeof velocityOrOpts === "object" ? velocityOrOpts : { velocity: velocityOrOpts };
@@ -3358,27 +3784,31 @@ var init_BottomSheetCore = __esm({
3358
3784
  const externalSignal = opts.signal;
3359
3785
  if (externalSignal?.aborted) return;
3360
3786
  this.newCycle();
3361
- const onExternalAbort = () => {
3362
- this.animation.cancel();
3363
- this.newCycle();
3364
- };
3787
+ const onExternalAbort = () => this.suspend();
3365
3788
  externalSignal?.addEventListener("abort", onExternalAbort, { once: true });
3366
3789
  const clamped = Math.max(0, Math.min(targetSize, this.snaps.getMaxAxisSize()));
3367
3790
  await this.animation.animateTo(clamped, velocityPxPerMs);
3368
3791
  externalSignal?.removeEventListener("abort", onExternalAbort);
3369
- if (this.destroyed || externalSignal?.aborted) return;
3370
3792
  }
3371
3793
  open(id) {
3372
3794
  if (this.destroyed) return Promise.resolve();
3795
+ if (!id && (this.phase === "open" || this.phase === "opening")) {
3796
+ return Promise.resolve();
3797
+ }
3373
3798
  const target = id ?? this.snaps.getAllowedIds().find((a) => (this.snaps.findById(a)?.size ?? 0) > 0) ?? this.activeId;
3374
3799
  return this.snapTo(target);
3375
3800
  }
3376
3801
  close(reason = "programmatic") {
3377
- if (this.destroyed) return Promise.resolve();
3378
- if (this.disableCloseFlag) return Promise.resolve();
3379
- if (this.size > 0 && this.emitBeforeClose(reason)) return Promise.resolve();
3380
- 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];
3381
- return this.snapTo(closedId ?? this.activeId);
3802
+ if (this.destroyed || this.disableCloseFlag) return Promise.resolve();
3803
+ if (this.persistent && reason !== "programmatic") return Promise.resolve();
3804
+ const target = this.zeroSnapId() ?? this.allowedIdsBySize()[0];
3805
+ if (target === void 0) return Promise.resolve();
3806
+ if (this.phase === "closed" && this.activeId === target) {
3807
+ return Promise.resolve();
3808
+ }
3809
+ const visible = this.phase === "open" || this.phase === "opening";
3810
+ if (visible && this.emitBeforeClose(reason)) return Promise.resolve();
3811
+ return this.snapTo(target);
3382
3812
  }
3383
3813
  canDismiss() {
3384
3814
  return !this.persistent && !this.disableCloseFlag && !this.destroyed;
@@ -3401,10 +3831,12 @@ var init_BottomSheetCore = __esm({
3401
3831
  }
3402
3832
  setDragFrom(mode) {
3403
3833
  if (this.destroyed || mode === this.dragFromMode) return;
3834
+ const wasDragging = this.gesture?.isDragging ?? false;
3404
3835
  this.gesture?.forceClearDragState();
3405
3836
  this.detachSheetGesture?.();
3406
3837
  this.dragFromMode = mode;
3407
3838
  this.mountSheetGesture();
3839
+ if (wasDragging) this.restoreAfterDrag();
3408
3840
  }
3409
3841
  getDragFrom() {
3410
3842
  return this.dragFromMode;
@@ -3417,6 +3849,7 @@ var init_BottomSheetCore = __esm({
3417
3849
  const nowVertical = next === "bottom" || next === "top";
3418
3850
  this.gesture?.forceClearDragState();
3419
3851
  this.detachSheetGesture?.();
3852
+ this.landNow();
3420
3853
  this.animation.cancel();
3421
3854
  this.element.style.removeProperty(layoutAxis(this.mode));
3422
3855
  this.mode = next;
@@ -3432,9 +3865,12 @@ var init_BottomSheetCore = __esm({
3432
3865
  this.detachSliderKeyboard?.();
3433
3866
  this.mountSliderKeyboard();
3434
3867
  this.mountSheetGesture();
3868
+ for (const anchor of this.anchors) anchor.reposition();
3869
+ this.placeScrimStages?.();
3870
+ if (this.stackEffectPrimed) {
3871
+ this.element.style.transformOrigin = nowVertical ? "50% 100%" : "0% 50%";
3872
+ }
3435
3873
  this.recompute();
3436
- const active = this.snaps.findById(this.activeId);
3437
- if (active) this.applySize(active.size);
3438
3874
  this.updateAriaSlider();
3439
3875
  }
3440
3876
  getMode() {
@@ -3476,13 +3912,24 @@ var init_BottomSheetCore = __esm({
3476
3912
  if (snap && ids.includes(snap)) {
3477
3913
  void this.snapTo(snap, 0, true);
3478
3914
  } else if (!ids.includes(this.activeId)) {
3479
- const fallback = ids[0];
3480
- if (fallback) void this.snapTo(fallback, 0, true);
3915
+ const fallback = this.fallbackSnap(
3916
+ this.snaps.findById(this.activeId)?.size ?? this.size
3917
+ );
3918
+ if (fallback) void this.snapTo(fallback.id, 0, true);
3481
3919
  }
3482
3920
  }
3921
+ fallbackSnap(from) {
3922
+ return (from > 0 ? this.snaps.nearest(from, true) : null) ?? this.snaps.nearest(from, false);
3923
+ }
3483
3924
  setBackdropRange(range) {
3484
3925
  this.scrim.setBackdropRange(range, () => this.applySize(this.size));
3485
3926
  }
3927
+ setBackdropOpacity(value) {
3928
+ this.scrim.setBackdropOpacity(value, () => this.applySize(this.size));
3929
+ }
3930
+ setBackdropColor(color) {
3931
+ this.scrim.setBackdropColor(color);
3932
+ }
3486
3933
  setScreenRange(range) {
3487
3934
  this.scrim.setScreenRange(range, () => this.applySize(this.size));
3488
3935
  }
@@ -3523,7 +3970,7 @@ var init_BottomSheetCore = __esm({
3523
3970
  }
3524
3971
  const handle = attachAnchor(
3525
3972
  {
3526
- mode: this.mode,
3973
+ getMode: () => this.mode,
3527
3974
  host: this.anchorHost,
3528
3975
  getState: () => ({
3529
3976
  activeId: this.activeId,
@@ -3561,9 +4008,9 @@ var init_BottomSheetCore = __esm({
3561
4008
  return () => {
3562
4009
  };
3563
4010
  }
3564
- const detachInstalled = installScrimStages(
4011
+ const stages = installScrimStages(
3565
4012
  {
3566
- mode: this.mode,
4013
+ getMode: () => this.mode,
3567
4014
  host,
3568
4015
  getState: () => ({
3569
4016
  activeId: this.activeId,
@@ -3576,10 +4023,14 @@ var init_BottomSheetCore = __esm({
3576
4023
  opts
3577
4024
  );
3578
4025
  const detach = () => {
3579
- if (this.detachScrimStages === detach) this.detachScrimStages = null;
3580
- detachInstalled();
4026
+ if (this.detachScrimStages === detach) {
4027
+ this.detachScrimStages = null;
4028
+ this.placeScrimStages = null;
4029
+ }
4030
+ stages.detach();
3581
4031
  };
3582
4032
  this.detachScrimStages = detach;
4033
+ this.placeScrimStages = stages.reposition;
3583
4034
  this.teardowns.add(() => this.detachScrimStages?.());
3584
4035
  return detach;
3585
4036
  }
@@ -3588,32 +4039,29 @@ var init_BottomSheetCore = __esm({
3588
4039
  }
3589
4040
  setSnapPoints(points, allowed) {
3590
4041
  if (this.destroyed) return;
3591
- this.animation.cancel();
3592
- this.newCycle();
4042
+ const from = this.snaps.findById(this.activeId)?.size ?? this.size;
4043
+ const restricted = this.snaps.getResolvedSnaps().some((s) => !this.snaps.getAllowedIds().includes(s.id));
3593
4044
  this.snapPointsRaw = points;
3594
4045
  auditVhUsage(points);
3595
4046
  this.auditDuplicateSnapIds(points);
4047
+ this.maxHeight.resolveCap();
3596
4048
  this.snaps.setRaw(points);
4049
+ this.maxHeight.clampTo();
3597
4050
  if (allowed) {
3598
4051
  this.snaps.setAllowedIds(allowed);
3599
4052
  } else {
3600
4053
  const present = this.snaps.getResolvedSnaps().map((s) => s.id);
3601
- const kept = this.snaps.getAllowedIds().filter((id) => present.includes(id));
4054
+ const kept = restricted ? this.snaps.getAllowedIds().filter((id) => present.includes(id)) : [];
3602
4055
  this.snaps.setAllowedIds(kept.length ? kept : present);
3603
4056
  }
3604
4057
  this.scrollCache.clear();
3605
4058
  this.scrim.invalidateOpacityCache();
3606
- const current = this.snaps.findById(this.activeId);
3607
- if (current) {
3608
- this.applySize(current.size);
3609
- } else {
3610
- const fallback = this.snaps.getResolvedSnaps().find((s) => this.snaps.getAllowedIds().includes(s.id)) ?? this.snaps.getResolvedSnaps()[0];
3611
- if (fallback) {
3612
- this.activeId = fallback.id;
3613
- this.applySize(fallback.size);
3614
- }
4059
+ if (this.snaps.findById(this.activeId)) {
4060
+ this.reseat();
4061
+ return;
3615
4062
  }
3616
- this.updateAriaSlider();
4063
+ const fallback = this.fallbackSnap(from) ?? this.snaps.getResolvedSnaps()[0];
4064
+ if (fallback) void this.transitionTo(fallback.id, 0, true);
3617
4065
  }
3618
4066
  recompute() {
3619
4067
  if (this.destroyed) return;
@@ -3621,22 +4069,11 @@ var init_BottomSheetCore = __esm({
3621
4069
  this.snaps.recompute();
3622
4070
  this.maxHeight.clampTo();
3623
4071
  this.scrim.invalidateOpacityCache();
3624
- if (this.isDraggingAny()) return;
3625
- this.healActiveSnap();
3626
- }
3627
- healActiveSnap() {
3628
- const current = this.snaps.findById(this.activeId);
3629
- if (!current) return;
3630
- this.size = current.size;
3631
- this.applySize(this.size);
3632
- this.updateAriaSlider();
3633
- if (this.size > 0 && !this.lifecycle.isInstalled && !this.opening && !this.animation.isAnimating) {
3634
- this.emitOpenSequence(this.activeId);
3635
- }
4072
+ this.reseat();
3636
4073
  }
3637
4074
  destroy() {
3638
4075
  this.destroyed = true;
3639
- this.opening = false;
4076
+ this.outbox.length = 0;
3640
4077
  this.currentAbort.abort();
3641
4078
  this.currentViewTransition?.skipTransition?.();
3642
4079
  this.currentViewTransition = null;
@@ -3653,11 +4090,19 @@ var init_BottomSheetCore = __esm({
3653
4090
  this.backdrop.style.opacity = "";
3654
4091
  this.backdrop.style.pointerEvents = "";
3655
4092
  }
3656
- for (const host of [this.anchorHost, this.scrimParent, this.rootEl]) {
4093
+ for (const host of [
4094
+ this.anchorHost,
4095
+ this.scrimParent,
4096
+ this.rootEl,
4097
+ this.homeRoot
4098
+ ]) {
3657
4099
  if (!host) continue;
3658
4100
  host.style.removeProperty("--bs-size");
3659
4101
  host.style.removeProperty("--bs-progress");
4102
+ host.style.removeProperty("--bs-z-sheet");
4103
+ host.style.removeProperty("--bs-keyboard-inset");
3660
4104
  }
4105
+ this.element.style.removeProperty("--bs-keyboard-inset");
3661
4106
  if (this.screenComponent) {
3662
4107
  this.screenComponent.style.opacity = "";
3663
4108
  this.screenComponent.style.display = "";
@@ -3670,7 +4115,8 @@ var init_BottomSheetCore = __esm({
3670
4115
  }
3671
4116
  newCycle() {
3672
4117
  this.allowOvershoot = false;
3673
- this.opening = false;
4118
+ this.transition = null;
4119
+ this.inFlight = null;
3674
4120
  this.currentAbort.abort();
3675
4121
  this.currentAbort = new AbortController();
3676
4122
  return this.currentAbort.signal;
@@ -3693,8 +4139,9 @@ var init_BottomSheetCore = __esm({
3693
4139
  if (typeof document === "undefined") return;
3694
4140
  if (!this.lifecycle.focusTrapEnabled) return;
3695
4141
  if (this.element.getAttribute("aria-labelledby")) return;
3696
- const scope = this.handle ?? this.element;
3697
- const titled = scope.querySelector("[data-bs-title]") ?? scope.querySelector("h1,h2,h3,h4,h5,h6");
4142
+ const HEADING = "h1,h2,h3,h4,h5,h6";
4143
+ const header = this.element.querySelector(".bs-header");
4144
+ const titled = this.element.querySelector("[data-bs-title]") ?? this.handle.querySelector(HEADING) ?? header?.querySelector(HEADING);
3698
4145
  if (!titled) return;
3699
4146
  if (!titled.id) {
3700
4147
  titled.id = nextInstanceId("bs-title");
@@ -3736,12 +4183,16 @@ var init_BottomSheetCore = __esm({
3736
4183
  this.stackZ = z;
3737
4184
  this.element.style.zIndex = String(z);
3738
4185
  if (this.backdrop) this.backdrop.style.zIndex = String(z - 1);
4186
+ this.rootEl?.style.setProperty("--bs-z-sheet", String(z));
4187
+ this.homeRoot?.style.setProperty("--bs-z-sheet", String(z));
3739
4188
  for (const anchor of this.anchors) anchor.syncZ(z + 1);
3740
4189
  },
3741
4190
  setIsTop: (isTop) => {
4191
+ if (isTop === this.isTopSheet) return;
3742
4192
  this.isTopSheet = isTop;
4193
+ this.lifecycle.syncTop();
3743
4194
  },
3744
- isOpen: () => this.size > 0 || this.opening,
4195
+ isOpen: () => this.phase !== "closed",
3745
4196
  setDepth: (depth) => this.applyStackDepth(depth)
3746
4197
  }));
3747
4198
  }
@@ -3769,15 +4220,15 @@ var init_BottomSheetCore = __esm({
3769
4220
  const r = this.getAllowedRange();
3770
4221
  buf.size = this.size;
3771
4222
  buf.maxAxisSize = this.snaps.getMaxAxisSize();
3772
- buf.range.min = r.min;
4223
+ buf.range.min = this.dismissBlocked() ? Math.max(r.min, this.smallestOpenSize()) : r.min;
3773
4224
  buf.range.max = r.max;
3774
4225
  buf.rubberBandEnabled = this.rubberBandEnabled;
3775
4226
  return buf;
3776
4227
  },
3777
4228
  getDisableDrag: () => this.disableDragFlag,
3778
- cancelAnimation: () => this.animation.cancel(),
4229
+ cancelAnimation: () => this.suspend(),
3779
4230
  applySize: (size) => this.applySize(size),
3780
- animateTo: (size, velocity) => this.animation.animateTo(size, velocity),
4231
+ restoreAfterDrag: () => this.restoreAfterDrag(),
3781
4232
  settleAfterDrag: (delta, velocity, kind) => this.settleAfterDrag(delta, velocity, kind),
3782
4233
  emit: (event, payload) => this.emit(event, payload),
3783
4234
  listenerCount: (event) => this.bus.listenerCount(event)
@@ -3901,32 +4352,19 @@ var init_BottomSheetCore = __esm({
3901
4352
  element: this.element,
3902
4353
  getMode: () => this.mode,
3903
4354
  isDestroyed: () => this.destroyed,
3904
- isDragging: () => this.isDraggingAny(),
3905
4355
  resolveActiveSnap: () => this.snaps.findById(this.activeId),
3906
4356
  getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
3907
- getSize: () => this.size,
3908
4357
  setMaxAxisSize: (size) => {
3909
4358
  this.snaps.setMaxAxisSize(size);
3910
4359
  },
3911
- setSize: (size) => {
3912
- this.size = size;
3913
- },
3914
4360
  recomputeSnaps: () => this.recomputeSnaps(),
3915
- applySize: (size) => this.applySize(size),
3916
- cancelInFlight: () => {
3917
- this.animation.cancel();
3918
- },
3919
- newCycle: () => {
3920
- this.newCycle();
3921
- },
3922
- isAnimating: () => this.animation.isAnimating,
3923
- resyncAfterCancel: () => this.resyncAfterResize()
4361
+ reseat: () => this.reseat(),
4362
+ landNow: () => this.landNow()
3924
4363
  }));
3925
4364
  if (this.lifecycle.closeOnEscape) {
3926
4365
  const onKey = (e) => {
3927
4366
  if (this.destroyed || e.defaultPrevented) return;
3928
- if (!this.canDismiss()) return;
3929
- if (e.key === "Escape" && this.isTopSheet && this.size > 0) {
4367
+ if (e.key === "Escape" && this.isTopSheet) {
3930
4368
  void this.close("escape");
3931
4369
  }
3932
4370
  };
@@ -3944,7 +4382,10 @@ var init_BottomSheetCore = __esm({
3944
4382
  handle: this.handle,
3945
4383
  mode: this.mode,
3946
4384
  isDestroyed: () => this.destroyed,
3947
- getAllowedIds: () => this.allowedIdsBySize(),
4385
+ getAllowedIds: () => {
4386
+ const ids = this.allowedIdsBySize();
4387
+ return this.dismissBlocked() ? ids.filter((id) => (this.snaps.findById(id)?.size ?? 0) > 0) : ids;
4388
+ },
3948
4389
  getActiveId: () => this.activeId,
3949
4390
  snapTo: (id) => {
3950
4391
  void this.snapTo(id);
@@ -3957,56 +4398,46 @@ var init_BottomSheetCore = __esm({
3957
4398
  });
3958
4399
  }
3959
4400
  settleAfterDrag(delta, velocity, kind = "touch") {
3960
- const signal = this.newCycle();
3961
- const target = this.snaps.findDragSettleTarget({
3962
- delta,
3963
- velocity,
3964
- pointerKind: kind,
3965
- size: this.size,
3966
- activeId: this.activeId,
3967
- flickVelocity: this.flickVelocity,
3968
- dragThreshold: this.dragThreshold
3969
- });
4401
+ const target = this.snaps.findDragSettleTarget(
4402
+ {
4403
+ delta,
4404
+ velocity,
4405
+ pointerKind: kind,
4406
+ size: this.size,
4407
+ activeId: this.activeId,
4408
+ flickVelocity: this.flickVelocity,
4409
+ dragThreshold: this.dragThreshold
4410
+ },
4411
+ this.dismissBlocked()
4412
+ );
3970
4413
  if (!target) {
3971
4414
  this.clearWillChangeIfIdle();
3972
4415
  return;
3973
4416
  }
3974
4417
  const previousId = this.activeId;
3975
4418
  if (target.id === previousId && target.size === this.size) {
4419
+ if (this.phase === "opening" || this.phase === "closing") {
4420
+ this.land(false);
4421
+ }
3976
4422
  this.clearWillChangeIfIdle();
3977
4423
  return;
3978
4424
  }
3979
4425
  if (this.emitBeforeSnap(target, previousId)) {
3980
- const restore2 = this.snaps.findById(previousId);
3981
- if (restore2) {
3982
- void this.animation.animateTo(restore2.size, 0);
3983
- }
4426
+ this.restoreAfterDrag();
3984
4427
  return;
3985
4428
  }
3986
- const previousSize = this.size;
3987
- const previousSnapSize = this.snaps.findById(previousId)?.size;
3988
- this.scrollCache.cache(previousId, previousSize, target.size);
3989
- this.activeId = target.id;
3990
- if (previousSnapSize === 0 && target.size > 0) {
3991
- this.opening = true;
3992
- this.promotedForOpen = true;
3993
- sheetStack.promote(this.id);
3994
- }
3995
- const settleCap = this.snaps.getMaxAxisSize();
3996
- const settleSize = settleCap > 0 ? Math.min(target.size, settleCap) : target.size;
3997
- this.allowOvershoot = true;
3998
- void this.animation.animateTo(settleSize, velocity).then(() => {
3999
- if (signal.aborted) return;
4000
- this.allowOvershoot = false;
4001
- this.opening = false;
4002
- this.completeSnap(
4003
- target.id,
4004
- target.size,
4005
- previousSize,
4006
- previousSnapSize === 0,
4007
- true
4008
- );
4009
- });
4429
+ void this.runTransition(target, velocity, true);
4430
+ }
4431
+ restoreAfterDrag() {
4432
+ const active = this.snaps.findById(this.activeId);
4433
+ if (active) void this.runTransition(active, 0, false);
4434
+ }
4435
+ smallestOpenSize() {
4436
+ const allowed = this.snaps.getAllowedIds();
4437
+ for (const snap of this.snaps.getResolvedSnaps()) {
4438
+ if (snap.size > 0 && allowed.includes(snap.id)) return snap.size;
4439
+ }
4440
+ return 0;
4010
4441
  }
4011
4442
  isDraggingAny() {
4012
4443
  return (this.gesture?.isDragging ?? false) || (this.contentGesture?.isDragging ?? false);
@@ -4031,9 +4462,10 @@ var init_BottomSheetCore = __esm({
4031
4462
  const offset = cap - clamped;
4032
4463
  const style = this.element.style;
4033
4464
  if (!skipTransform) style.transform = this.transformTemplate(offset);
4465
+ const moving = this.animation.isAnimating || this.isDraggingAny();
4034
4466
  const sizeChanged = this.sizeWriteSentinel.shouldWrite(
4035
4467
  clamped,
4036
- this.animation.isAnimating || this.isDraggingAny() ? SIZE_WRITE_EPSILON : 0
4468
+ moving ? SIZE_WRITE_EPSILON : 0
4037
4469
  );
4038
4470
  if (sizeChanged) {
4039
4471
  style.setProperty("--bs-size", `${clamped}px`);
@@ -4046,11 +4478,13 @@ var init_BottomSheetCore = __esm({
4046
4478
  if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
4047
4479
  this.rootEl.style.setProperty("--bs-size", `${clamped}px`);
4048
4480
  }
4481
+ this.homeRoot?.style.setProperty("--bs-size", `${clamped}px`);
4049
4482
  }
4050
4483
  const progress = this.computeProgress(clamped);
4484
+ const opacityEpsilon = moving ? OPACITY_WRITE_EPSILON : 0;
4051
4485
  const progressChanged = this.progressWriteSentinel.shouldWrite(
4052
4486
  progress,
4053
- OPACITY_WRITE_EPSILON
4487
+ opacityEpsilon
4054
4488
  );
4055
4489
  if (progressChanged) {
4056
4490
  style.setProperty("--bs-progress", String(progress));
@@ -4060,8 +4494,9 @@ var init_BottomSheetCore = __esm({
4060
4494
  if (this.rootEl && this.rootEl !== this.anchorHost) {
4061
4495
  this.rootEl.style.setProperty("--bs-progress", String(progress));
4062
4496
  }
4497
+ this.homeRoot?.style.setProperty("--bs-progress", String(progress));
4063
4498
  }
4064
- this.scrim.applyOpacity(progress, progressChanged);
4499
+ this.scrim.applyOpacity(progress, progressChanged, opacityEpsilon);
4065
4500
  if ((progressChanged || sizeChanged) && this.bus.listenerCount("progress") > 0) {
4066
4501
  this.progressPayload.value = progress;
4067
4502
  this.progressPayload.size = clamped;
@@ -4074,245 +4509,330 @@ var init_BottomSheetCore = __esm({
4074
4509
  if (reachableMax <= min) return 0;
4075
4510
  return Math.min(Math.max((size - min) / (reachableMax - min), 0), 1);
4076
4511
  }
4077
- handleOpen() {
4078
- if (this.promotedForOpen) this.promotedForOpen = false;
4079
- else sheetStack.promote(this.id);
4080
- try {
4081
- this.lifecycle.install();
4082
- } catch (err) {
4083
- if (!this.destroyed) this.newCycle();
4084
- this.handleClose();
4085
- this.applySize(0);
4086
- this.activeId = this.snapPointsRaw.find((p) => p.id === "closed")?.id ?? this.activeId;
4087
- this.size = 0;
4088
- queueMicrotask(() => {
4089
- throw err;
4090
- });
4091
- }
4092
- }
4093
- resyncAfterResize() {
4094
- if (this.destroyed) return;
4095
- const target = this.snaps.findById(this.activeId);
4096
- if (!target) return;
4097
- this.updateAriaSlider();
4098
- this.emit("snap", {
4099
- id: target.id,
4100
- size: this.size,
4101
- progress: this.computeProgress(this.size)
4102
- });
4103
- if (target.size > 0 && !this.lifecycle.isInstalled) {
4104
- this.emitOpenSequence(target.id);
4105
- } else if (target.size === 0 && this.lifecycle.isInstalled) {
4106
- this.emitCloseSequence();
4107
- }
4108
- }
4109
- handleClose() {
4110
- this.opening = false;
4111
- this.promotedForOpen = false;
4112
- this.lifecycle.release();
4113
- sheetStack.update();
4114
- }
4115
4512
  };
4116
4513
  }
4117
4514
  });
4118
4515
 
4119
4516
  // src/core/features/history-coordinator.ts
4120
- function onPopState() {
4121
- if (suppress > 0) {
4122
- suppress -= 1;
4123
- const rebrand = pendingRebrands.shift();
4124
- if (rebrand) rebrand();
4125
- maybeTeardownListener();
4126
- return;
4127
- }
4128
- if (entries.length === 0) {
4129
- notifyRouteChange();
4130
- maybeTeardownListener();
4131
- return;
4132
- }
4133
- let target = null;
4134
- let targetIdx = -1;
4135
- for (let i = entries.length - 1; i >= 0; i -= 1) {
4136
- const entry = entries[i];
4137
- if (!entry.surface.isOpen()) continue;
4138
- if (!target) {
4139
- target = entry;
4140
- targetIdx = i;
4517
+ function pushEntry(entry) {
4518
+ const depth = state2.live.length + 1;
4519
+ if (state2.live.length === 0) startStack();
4520
+ const written = runInternal(() => {
4521
+ history.pushState(markerFor(entry.surface, depth), "", entry.surface.url);
4522
+ });
4523
+ if (!written) return false;
4524
+ state2.live.push(entry);
4525
+ state2.position = depth;
4526
+ state2.knownLength = history.length;
4527
+ state2.href = location.href;
4528
+ ensureListener();
4529
+ return true;
4530
+ }
4531
+ function onPopState(event) {
4532
+ const kind = state2.pending.shift();
4533
+ const byUser = kind !== "pop";
4534
+ const landed = plain(event.state);
4535
+ const depth = depthOf(landed);
4536
+ const from = state2.position;
4537
+ const liveBefore = state2.live.length;
4538
+ const grew = history.length > state2.knownLength;
4539
+ state2.knownLength = history.length;
4540
+ const within = inStack(landed);
4541
+ if (within && depth !== null) {
4542
+ state2.position = depth;
4543
+ if (depth > state2.live.length) {
4544
+ const forward = from !== null && from < depth;
4545
+ traverse(forward ? 1 : -1, byUser ? "skip" : "pop");
4546
+ } else if (depth < state2.live.length) {
4547
+ if (byUser) closeAbove(depth);
4548
+ } else {
4549
+ rebrand(depth);
4141
4550
  }
4142
- if (entry.surface.isTop()) {
4143
- target = entry;
4144
- targetIdx = i;
4145
- break;
4551
+ } else if (isMarker(landed)) {
4552
+ state2.position = null;
4553
+ traverse(-1, byUser ? "skip" : "pop");
4554
+ } else {
4555
+ state2.position = null;
4556
+ if (byUser && !grew && state2.live.length > 0) {
4557
+ closeAbove(state2.live.length - 1);
4146
4558
  }
4147
4559
  }
4148
- if (!target) {
4149
- const removed = entries.pop();
4150
- if (removed) removed.live = false;
4151
- maybeTeardownListener();
4152
- return;
4560
+ const moved = location.href !== state2.href;
4561
+ state2.href = location.href;
4562
+ if (kind === void 0 && moved && (liveBefore === 0 || !within)) {
4563
+ notifyRouteChange();
4153
4564
  }
4154
- target.live = false;
4155
- entries.splice(targetIdx, 1);
4156
- const settled = target;
4157
- void Promise.resolve(settled.surface.close()).then(() => {
4158
- if (settled.surface.isOpen()) restore(settled);
4159
- });
4565
+ settleIfIdle();
4160
4566
  maybeTeardownListener();
4161
4567
  }
4162
- function restore(entry) {
4163
- if (!hasWindow() || !hasHistory()) return;
4164
- entry.live = true;
4165
- runInternal(() => {
4166
- try {
4167
- history.pushState(brandMarker(entry.surface), "", entry.surface.url);
4168
- } catch {
4169
- entry.live = false;
4170
- }
4171
- });
4172
- if (entry.live) {
4173
- entries.push(entry);
4174
- ensureListener();
4175
- }
4176
- }
4177
4568
  function pushBackMarker(surface) {
4178
- const entry = { surface, priorUrl: void 0, live: false };
4179
- if (!hasWindow() || !hasHistory()) {
4180
- return entry;
4181
- }
4182
- entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
4183
- runInternal(() => {
4184
- try {
4185
- history.pushState(brandMarker(surface), "", surface.url);
4186
- entry.live = true;
4187
- } catch {
4188
- entry.live = false;
4189
- }
4190
- });
4191
- if (entry.live) {
4192
- entries.push(entry);
4193
- ensureListener();
4194
- }
4569
+ const entry = { surface };
4570
+ if (hasHistory()) enlist(entry);
4195
4571
  return entry;
4196
4572
  }
4197
4573
  function popBackMarker(handle) {
4198
- if (!hasWindow() || !hasHistory()) return;
4574
+ if (!hasHistory()) return Promise.resolve();
4199
4575
  const entry = handle;
4200
- const idx = entries.indexOf(entry);
4201
- if (idx === -1 || !entry.live) return;
4202
- const last = entries.length - 1;
4203
- entry.live = false;
4204
- entries.splice(idx, 1);
4205
- let rebrand = null;
4206
- if (idx !== last) {
4207
- const rebrandSurface = entries[entries.length - 1].surface;
4208
- const rebrandUrl = entry.priorUrl;
4209
- rebrand = () => {
4210
- runInternal(() => {
4211
- history.replaceState(
4212
- brandMarker(rebrandSurface),
4213
- "",
4214
- rebrandUrl !== void 0 ? rebrandUrl : location.href
4215
- );
4216
- });
4217
- };
4576
+ const waiting = state2.deferred.indexOf(entry);
4577
+ if (waiting !== -1) state2.deferred.splice(waiting, 1);
4578
+ const idx = state2.live.indexOf(entry);
4579
+ if (idx === -1) return historySettled();
4580
+ const top = state2.live.length;
4581
+ state2.live.splice(idx, 1);
4582
+ const current = plain(history.state);
4583
+ const onTop = isMarker(current) && inStack(current) && depthOf(current) === top;
4584
+ if (onTop && state2.pending.length === 0) {
4585
+ traverse(-1, "pop");
4586
+ } else {
4587
+ state2.leftovers = true;
4588
+ ensureListener();
4218
4589
  }
4219
- pendingRebrands.push(rebrand);
4220
- suppress += 1;
4221
- runInternal(() => {
4222
- try {
4223
- history.back();
4224
- } catch {
4225
- suppress = Math.max(0, suppress - 1);
4226
- pendingRebrands.pop();
4227
- }
4228
- });
4229
4590
  maybeTeardownListener();
4591
+ return historySettled();
4592
+ }
4593
+ function releaseOrphanMarker() {
4594
+ if (!hasHistory() || state2.orphanChecked) return;
4595
+ state2.orphanChecked = true;
4596
+ if (state2.live.length > 0 || state2.pending.length > 0) return;
4597
+ if (!isMarker(plain(history.state))) return;
4598
+ state2.leftovers = true;
4599
+ traverse(-1, "pop");
4600
+ }
4601
+ function historySettled() {
4602
+ if (state2.pending.length === 0) return Promise.resolve();
4603
+ return new Promise((resolve) => {
4604
+ state2.waiters.push(resolve);
4605
+ });
4230
4606
  }
4231
4607
  function subscribeRouteChange(fn) {
4232
- if (!hasWindow() || !hasHistory()) return () => {
4608
+ if (!hasHistory()) return () => {
4233
4609
  };
4234
- subscribers.add(fn);
4235
- if (subscribers.size === 1) installPatch();
4610
+ state2.subscribers.add(fn);
4611
+ state2.href = location.href;
4612
+ state2.knownLength = history.length;
4613
+ installPatch();
4236
4614
  ensureListener();
4237
4615
  return () => {
4238
- if (!subscribers.has(fn)) return;
4239
- subscribers.delete(fn);
4240
- if (subscribers.size === 0) removePatch();
4616
+ if (!state2.subscribers.delete(fn)) return;
4617
+ if (state2.subscribers.size === 0) removePatch();
4241
4618
  maybeTeardownListener();
4242
4619
  };
4243
4620
  }
4244
- var entries, subscribers, suppress, internalDepth, pendingRebrands, listenerInstalled, patchInstalled, origPushState, origReplaceState, patchedPushState, patchedReplaceState, hasWindow, hasHistory, brandMarker, runInternal, notifyRouteChange, ensureListener, maybeTeardownListener, installPatch, removePatch;
4621
+ var MARKER, STACK, DEPTH, ROUTED, SETTLE_TIMEOUT_MS, state2, hasHistory, plain, depthOf, isMarker, inStack, foreignKeys, markerFor, urlForDepth, runInternal, notifyRouteChange, ensureListener, maybeTeardownListener, settleIfIdle, traverse, newStackId, startStack, enlist, sameBrand, rebrand, closeAbove, wrap, installPatch, removePatch;
4245
4622
  var init_history_coordinator = __esm({
4246
4623
  "src/core/features/history-coordinator.ts"() {
4247
- entries = [];
4248
- subscribers = /* @__PURE__ */ new Set();
4249
- suppress = 0;
4250
- internalDepth = 0;
4251
- pendingRebrands = [];
4252
- listenerInstalled = false;
4253
- patchInstalled = false;
4254
- origPushState = null;
4255
- origReplaceState = null;
4256
- patchedPushState = null;
4257
- patchedReplaceState = null;
4258
- hasWindow = () => typeof window !== "undefined";
4259
- hasHistory = () => typeof history !== "undefined";
4260
- brandMarker = (surface) => ({
4624
+ init_shared();
4625
+ MARKER = "__bs";
4626
+ STACK = "__bsStack";
4627
+ DEPTH = "__bsDepth";
4628
+ ROUTED = "__bsRouted";
4629
+ SETTLE_TIMEOUT_MS = 1e3;
4630
+ state2 = shared(
4631
+ "history",
4632
+ () => ({
4633
+ live: [],
4634
+ stackId: void 0,
4635
+ baseUrl: void 0,
4636
+ position: null,
4637
+ knownLength: 0,
4638
+ href: "",
4639
+ subscribers: /* @__PURE__ */ new Set(),
4640
+ internal: 0,
4641
+ pending: [],
4642
+ deferred: [],
4643
+ waiters: [],
4644
+ timer: null,
4645
+ listening: false,
4646
+ leftovers: false,
4647
+ orphanChecked: false,
4648
+ push: null,
4649
+ replace: null
4650
+ })
4651
+ );
4652
+ hasHistory = () => typeof window !== "undefined" && typeof history !== "undefined";
4653
+ plain = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
4654
+ depthOf = (value) => {
4655
+ const depth = value?.[DEPTH];
4656
+ return typeof depth === "number" ? depth : null;
4657
+ };
4658
+ isMarker = (value) => value?.[MARKER] === true;
4659
+ inStack = (value) => value !== null && state2.stackId !== void 0 && value[STACK] === state2.stackId && depthOf(value) !== null;
4660
+ foreignKeys = (value) => {
4661
+ const out = {};
4662
+ const source = plain(value);
4663
+ if (!source) return out;
4664
+ for (const key of Object.keys(source)) {
4665
+ if (!key.startsWith(MARKER)) out[key] = source[key];
4666
+ }
4667
+ return out;
4668
+ };
4669
+ markerFor = (surface, depth) => ({
4670
+ ...foreignKeys(history.state),
4261
4671
  ...surface.markerState(),
4262
- __bs: true
4672
+ [MARKER]: true,
4673
+ [STACK]: state2.stackId,
4674
+ [DEPTH]: depth
4263
4675
  });
4676
+ urlForDepth = (depth) => {
4677
+ for (let i = depth - 1; i >= 0; i -= 1) {
4678
+ const url = state2.live[i]?.surface.url;
4679
+ if (url !== void 0) return url;
4680
+ }
4681
+ return state2.baseUrl;
4682
+ };
4264
4683
  runInternal = (fn) => {
4265
- internalDepth += 1;
4684
+ state2.internal += 1;
4266
4685
  try {
4267
4686
  fn();
4687
+ return true;
4688
+ } catch {
4689
+ return false;
4268
4690
  } finally {
4269
- internalDepth -= 1;
4691
+ state2.internal -= 1;
4270
4692
  }
4271
4693
  };
4272
4694
  notifyRouteChange = () => {
4273
- const snapshot = Array.from(subscribers);
4274
- for (const fn of snapshot) fn();
4695
+ for (const fn of Array.from(state2.subscribers)) {
4696
+ try {
4697
+ fn();
4698
+ } catch (err) {
4699
+ queueMicrotask(() => {
4700
+ throw err;
4701
+ });
4702
+ }
4703
+ }
4275
4704
  };
4276
4705
  ensureListener = () => {
4277
- if (listenerInstalled || !hasWindow()) return;
4706
+ if (state2.listening || !hasHistory()) return;
4278
4707
  window.addEventListener("popstate", onPopState);
4279
- listenerInstalled = true;
4708
+ state2.listening = true;
4280
4709
  };
4281
4710
  maybeTeardownListener = () => {
4282
- if (!listenerInstalled) return;
4283
- if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
4284
- if (hasWindow()) window.removeEventListener("popstate", onPopState);
4285
- listenerInstalled = false;
4711
+ if (!state2.listening) return;
4712
+ if (state2.live.length > 0 || state2.subscribers.size > 0 || state2.pending.length > 0 || state2.leftovers) {
4713
+ return;
4714
+ }
4715
+ if (hasHistory()) window.removeEventListener("popstate", onPopState);
4716
+ state2.listening = false;
4717
+ };
4718
+ settleIfIdle = () => {
4719
+ if (state2.pending.length > 0) return;
4720
+ if (state2.timer !== null) {
4721
+ clearTimeout(state2.timer);
4722
+ state2.timer = null;
4723
+ }
4724
+ for (const entry of state2.deferred.splice(0)) pushEntry(entry);
4725
+ for (const resolve of state2.waiters.splice(0)) resolve();
4726
+ };
4727
+ traverse = (delta, kind) => {
4728
+ state2.pending.push(kind);
4729
+ if (state2.timer !== null) clearTimeout(state2.timer);
4730
+ state2.timer = setTimeout(() => {
4731
+ state2.timer = null;
4732
+ state2.pending.length = 0;
4733
+ settleIfIdle();
4734
+ maybeTeardownListener();
4735
+ }, SETTLE_TIMEOUT_MS);
4736
+ ensureListener();
4737
+ const moved = runInternal(() => {
4738
+ if (delta < 0) history.back();
4739
+ else history.forward();
4740
+ });
4741
+ if (!moved) {
4742
+ state2.pending.pop();
4743
+ settleIfIdle();
4744
+ }
4745
+ };
4746
+ newStackId = () => `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
4747
+ startStack = () => {
4748
+ state2.stackId = newStackId();
4749
+ const current = history.state;
4750
+ const leftover = plain(current);
4751
+ state2.baseUrl = isMarker(leftover) && leftover?.[ROUTED] !== void 0 ? void 0 : location.href;
4752
+ if (isMarker(leftover)) return;
4753
+ if (current !== null && current !== void 0 && !leftover) return;
4754
+ runInternal(() => {
4755
+ history.replaceState(
4756
+ { ...foreignKeys(current), [STACK]: state2.stackId, [DEPTH]: 0 },
4757
+ "",
4758
+ location.href
4759
+ );
4760
+ });
4761
+ };
4762
+ enlist = (entry) => {
4763
+ if (state2.pending.length > 0) state2.deferred.push(entry);
4764
+ else pushEntry(entry);
4765
+ };
4766
+ sameBrand = (a, b) => {
4767
+ for (const key of /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)])) {
4768
+ if (key.startsWith(MARKER) && a[key] !== b[key]) return false;
4769
+ }
4770
+ return true;
4771
+ };
4772
+ rebrand = (depth) => {
4773
+ const entry = state2.live[depth - 1];
4774
+ if (!entry) return;
4775
+ const url = urlForDepth(depth);
4776
+ const marker = markerFor(entry.surface, depth);
4777
+ const atUrl = url === void 0 || new URL(url, location.href).href === location.href;
4778
+ if (atUrl && sameBrand(plain(history.state) ?? {}, marker)) return;
4779
+ runInternal(() => {
4780
+ history.replaceState(marker, "", url);
4781
+ });
4782
+ state2.href = location.href;
4783
+ };
4784
+ closeAbove = (depth) => {
4785
+ const dropped = state2.live.splice(depth);
4786
+ for (let i = dropped.length - 1; i >= 0; i -= 1) {
4787
+ const entry = dropped[i];
4788
+ let closing = void 0;
4789
+ try {
4790
+ closing = entry.surface.close();
4791
+ } catch (err) {
4792
+ queueMicrotask(() => {
4793
+ throw err;
4794
+ });
4795
+ }
4796
+ void Promise.resolve(closing).then(() => {
4797
+ if (!entry.surface.isOpen()) return;
4798
+ const known = (e) => e.surface === entry.surface;
4799
+ if (state2.live.some(known) || state2.deferred.some(known)) return;
4800
+ enlist(entry);
4801
+ });
4802
+ }
4803
+ };
4804
+ wrap = (original) => function(...args) {
4805
+ original.apply(this, args);
4806
+ state2.knownLength = history.length;
4807
+ if (location.href === state2.href) return;
4808
+ state2.href = location.href;
4809
+ if (state2.internal === 0 && state2.subscribers.size > 0) {
4810
+ notifyRouteChange();
4811
+ }
4286
4812
  };
4287
4813
  installPatch = () => {
4288
- if (patchInstalled || !hasHistory()) return;
4289
- origPushState = history.pushState;
4290
- origReplaceState = history.replaceState;
4291
- patchedPushState = function(...args) {
4292
- origPushState.apply(this, args);
4293
- if (internalDepth === 0) notifyRouteChange();
4294
- };
4295
- patchedReplaceState = function(...args) {
4296
- origReplaceState.apply(this, args);
4297
- if (internalDepth === 0) notifyRouteChange();
4298
- };
4299
- history.pushState = patchedPushState;
4300
- history.replaceState = patchedReplaceState;
4301
- patchInstalled = true;
4814
+ if (!state2.push || history.pushState === state2.push.original) {
4815
+ const original = history.pushState;
4816
+ const wrapper = wrap(original);
4817
+ history.pushState = wrapper;
4818
+ state2.push = { wrapper, original };
4819
+ }
4820
+ if (!state2.replace || history.replaceState === state2.replace.original) {
4821
+ const original = history.replaceState;
4822
+ const wrapper = wrap(original);
4823
+ history.replaceState = wrapper;
4824
+ state2.replace = { wrapper, original };
4825
+ }
4302
4826
  };
4303
4827
  removePatch = () => {
4304
- if (!patchInstalled) return;
4305
- if (history.pushState === patchedPushState && origPushState) {
4306
- history.pushState = origPushState;
4307
- }
4308
- if (history.replaceState === patchedReplaceState && origReplaceState) {
4309
- history.replaceState = origReplaceState;
4310
- }
4311
- origPushState = null;
4312
- origReplaceState = null;
4313
- patchedPushState = null;
4314
- patchedReplaceState = null;
4315
- patchInstalled = false;
4828
+ if (state2.push && history.pushState === state2.push.wrapper) {
4829
+ history.pushState = state2.push.original;
4830
+ state2.push = null;
4831
+ }
4832
+ if (state2.replace && history.replaceState === state2.replace.wrapper) {
4833
+ history.replaceState = state2.replace.original;
4834
+ state2.replace = null;
4835
+ }
4316
4836
  };
4317
4837
  }
4318
4838
  });
@@ -4328,36 +4848,37 @@ function installRoute(deps) {
4328
4848
  };
4329
4849
  }
4330
4850
  let handle = null;
4851
+ const surface = {
4852
+ isOpen: () => !deps.isDestroyed() && deps.isOpen(),
4853
+ close: deps.close,
4854
+ markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
4855
+ url: deps.routedTo
4856
+ };
4331
4857
  const onOpen = () => {
4332
4858
  if (handle) return;
4333
- handle = pushBackMarker({
4334
- isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
4335
- isTop: deps.isTopSheet,
4336
- close: deps.close,
4337
- markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
4338
- url: deps.routedTo
4339
- });
4859
+ handle = pushBackMarker(surface);
4340
4860
  };
4341
4861
  const onClose = () => {
4342
4862
  if (!handle) return;
4343
- popBackMarker(handle);
4863
+ deps.hold(popBackMarker(handle));
4344
4864
  handle = null;
4345
4865
  };
4346
4866
  const unsubscribeOpen = deps.on("open", onOpen);
4347
4867
  const unsubscribeClose = deps.on("close", onClose);
4348
- if (deps.getSize() > 0) onOpen();
4868
+ if (deps.isOpen()) onOpen();
4869
+ else releaseOrphanMarker();
4349
4870
  return () => {
4350
4871
  unsubscribeOpen();
4351
4872
  unsubscribeClose();
4352
4873
  if (handle) {
4353
- popBackMarker(handle);
4874
+ void popBackMarker(handle);
4354
4875
  handle = null;
4355
4876
  }
4356
4877
  };
4357
4878
  }
4358
4879
  function installRouteChange(deps) {
4359
4880
  return subscribeRouteChange(() => {
4360
- if (deps.isDestroyed() || deps.getSize() <= 0) return;
4881
+ if (deps.isDestroyed() || !deps.isOpen()) return;
4361
4882
  void deps.close();
4362
4883
  });
4363
4884
  }
@@ -4400,7 +4921,10 @@ function installAutoCollapse(deps) {
4400
4921
  };
4401
4922
  const fire = () => {
4402
4923
  if (deps.isDestroyed()) return;
4403
- if (deps.isDragging()) return;
4924
+ if (deps.isDragging() || deps.isAnimating()) {
4925
+ reset();
4926
+ return;
4927
+ }
4404
4928
  const active = deps.resolveSnap(deps.getActiveId());
4405
4929
  if (!active || active.size === 0) return;
4406
4930
  let target = null;
@@ -4451,43 +4975,47 @@ function installVisualViewport(deps) {
4451
4975
  }
4452
4976
  const vv = window.visualViewport;
4453
4977
  let rafId = null;
4978
+ const coveredByKeyboard = () => {
4979
+ if ((vv.scale || 1) > ZOOMED) return 0;
4980
+ const covered = window.innerHeight - ((vv.offsetTop || 0) + vv.height);
4981
+ return covered >= KEYBOARD_MIN_COVER ? Math.round(covered) : 0;
4982
+ };
4454
4983
  const onResize = () => {
4455
4984
  if (rafId !== null) return;
4456
4985
  rafId = requestAnimationFrame(() => {
4457
4986
  rafId = null;
4458
4987
  if (deps.isDestroyed()) return;
4988
+ deps.setKeyboardInset(coveredByKeyboard());
4989
+ const before = seatOf(deps);
4459
4990
  deps.recomputeSnaps();
4460
4991
  const isVertical = deps.isVerticalAxis();
4461
4992
  const visible = isVertical ? vv.height : vv.width;
4462
4993
  const windowSize = isVertical ? window.innerHeight : window.innerWidth;
4463
- const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
4994
+ const pad = windowSize - visible > KEYBOARD_MIN_INSET ? SAFETY_PAD : 0;
4995
+ const clamp = Math.max(0, Math.min(windowSize, visible) - pad);
4464
4996
  if (clamp < deps.getMaxAxisSize()) {
4465
4997
  deps.setMaxAxisSize(clamp);
4466
4998
  }
4467
- const wasAnimating = deps.isAnimating?.() ?? false;
4468
- deps.cancelInFlight();
4469
- deps.newCycle();
4470
- const max = deps.getMaxAxisSize();
4471
- deps.setSize(Math.min(deps.getSize(), max));
4472
- const current = deps.resolveActiveSnap();
4473
- if (current && !deps.isDragging()) {
4474
- deps.applySize(Math.min(current.size, max));
4475
- if (wasAnimating) deps.resyncAfterCancel?.();
4476
- } else {
4477
- deps.applySize(deps.getSize());
4478
- }
4999
+ if (sameSeat(before, seatOf(deps))) return;
5000
+ deps.reseat();
4479
5001
  });
4480
5002
  };
4481
5003
  vv.addEventListener("resize", onResize);
5004
+ vv.addEventListener("scroll", onResize);
4482
5005
  return () => {
4483
5006
  vv.removeEventListener("resize", onResize);
5007
+ vv.removeEventListener("scroll", onResize);
4484
5008
  if (rafId !== null) cancelAnimationFrame(rafId);
4485
5009
  };
4486
5010
  }
4487
- var SAFETY_PAD;
5011
+ var SAFETY_PAD, KEYBOARD_MIN_INSET, KEYBOARD_MIN_COVER, ZOOMED;
4488
5012
  var init_visual_viewport = __esm({
4489
5013
  "src/core/features/visual-viewport.ts"() {
5014
+ init_resize_observer();
4490
5015
  SAFETY_PAD = 8;
5016
+ KEYBOARD_MIN_INSET = 1;
5017
+ KEYBOARD_MIN_COVER = 60;
5018
+ ZOOMED = 1.01;
4491
5019
  }
4492
5020
  });
4493
5021
 
@@ -4501,7 +5029,7 @@ function routeFeature() {
4501
5029
  teardowns.add(
4502
5030
  installRouteChange({
4503
5031
  isDestroyed: ctx.isDestroyed,
4504
- getSize: ctx.getSize,
5032
+ isOpen: () => ctx.getPhase() !== "closed",
4505
5033
  close: () => ctx.close()
4506
5034
  })
4507
5035
  );
@@ -4510,10 +5038,10 @@ function routeFeature() {
4510
5038
  installRoute({
4511
5039
  routedTo: ctx.options.routedTo,
4512
5040
  closeOnBack: ctx.options.closeOnBack,
4513
- isTopSheet: ctx.isTopSheet,
4514
- getSize: ctx.getSize,
5041
+ isOpen: () => ctx.getPhase() !== "closed",
4515
5042
  isDestroyed: ctx.isDestroyed,
4516
5043
  close: () => ctx.close("back"),
5044
+ hold: ctx.holdSettle,
4517
5045
  on: ctx.on,
4518
5046
  sheetId: ctx.sheetId
4519
5047
  })
@@ -4539,6 +5067,7 @@ function autoCollapseFeature() {
4539
5067
  ms: ctx.options.autoCollapseAfter,
4540
5068
  isDestroyed: ctx.isDestroyed,
4541
5069
  isDragging: ctx.isDragging,
5070
+ isAnimating: ctx.isAnimating,
4542
5071
  getAllowedIds: ctx.getAllowedIds,
4543
5072
  getActiveId: ctx.getActiveId,
4544
5073
  resolveSnap: ctx.resolveSnap,
@@ -4566,21 +5095,14 @@ function visualViewportFeature() {
4566
5095
  install: (ctx) => {
4567
5096
  if (typeof window === "undefined") return;
4568
5097
  return installVisualViewport({
4569
- element: ctx.element,
4570
5098
  isVerticalAxis: ctx.isVerticalAxis,
4571
5099
  isDestroyed: ctx.isDestroyed,
4572
- isDragging: ctx.isDragging,
4573
5100
  recomputeSnaps: ctx.recomputeSnaps,
4574
5101
  resolveActiveSnap: ctx.resolveActiveSnap,
4575
5102
  getMaxAxisSize: ctx.getMaxAxisSize,
4576
- getSize: ctx.getSize,
4577
5103
  setMaxAxisSize: ctx.setMaxAxisSize,
4578
- setSize: ctx.setSize,
4579
- applySize: ctx.applySize,
4580
- cancelInFlight: ctx.cancelInFlight,
4581
- newCycle: ctx.newCycle,
4582
- isAnimating: ctx.isAnimating,
4583
- resyncAfterCancel: ctx.resyncAfterResize
5104
+ setKeyboardInset: ctx.setKeyboardInset,
5105
+ reseat: ctx.reseat
4584
5106
  });
4585
5107
  }
4586
5108
  };
@@ -4773,11 +5295,88 @@ var init_BottomSheetEngine = __esm({
4773
5295
  }
4774
5296
  });
4775
5297
 
5298
+ // src/core/primitives/open-state.ts
5299
+ var closedSnapId, syncOpen;
5300
+ var init_open_state = __esm({
5301
+ "src/core/primitives/open-state.ts"() {
5302
+ closedSnapId = (points) => points.find((point) => point.size === 0)?.id;
5303
+ syncOpen = (engine, open) => {
5304
+ const phase = engine.state.phase;
5305
+ const showing = phase === "open" || phase === "opening";
5306
+ if (open && !showing) void engine.open();
5307
+ else if (!open && showing) void engine.close();
5308
+ };
5309
+ }
5310
+ });
5311
+
5312
+ // src/core/primitives/option-keys.ts
5313
+ var ENGINE_OPTION_KEYS, pickEngineOptions;
5314
+ var init_option_keys = __esm({
5315
+ "src/core/primitives/option-keys.ts"() {
5316
+ ENGINE_OPTION_KEYS = [
5317
+ "mode",
5318
+ "snapPoints",
5319
+ "allowed",
5320
+ "initial",
5321
+ "duration",
5322
+ "easing",
5323
+ "respectReducedMotion",
5324
+ "flickVelocity",
5325
+ "dragThreshold",
5326
+ "dragFrom",
5327
+ "dragFromContent",
5328
+ "fitContentToSnap",
5329
+ "rubberBand",
5330
+ "backdropRange",
5331
+ "backdropOpacity",
5332
+ "backdropColor",
5333
+ "screenRange",
5334
+ "scrimMode",
5335
+ "scrimColor",
5336
+ "scrimBlur",
5337
+ "scrimInteractive",
5338
+ "scrimTapToClose",
5339
+ "scrimPreset",
5340
+ "animation",
5341
+ "settleAnimation",
5342
+ "spring",
5343
+ "focusTrap",
5344
+ "initialFocus",
5345
+ "closeOnEscape",
5346
+ "lockBodyScroll",
5347
+ "closeOnBack",
5348
+ "routedTo",
5349
+ "inertSiblings",
5350
+ "persistent",
5351
+ "disableClose",
5352
+ "disableDrag",
5353
+ "closeOnRouteChange",
5354
+ "radius",
5355
+ "maxHeight",
5356
+ "returnFocusTo",
5357
+ "persistKey",
5358
+ "autoCollapseAfter",
5359
+ "linkedSheets",
5360
+ "viewTransitions",
5361
+ "stackEffect",
5362
+ "features"
5363
+ ];
5364
+ pickEngineOptions = (source) => {
5365
+ const out = {};
5366
+ for (const key of ENGINE_OPTION_KEYS) {
5367
+ const value = source[key];
5368
+ if (value !== void 0) out[key] = value;
5369
+ }
5370
+ return out;
5371
+ };
5372
+ }
5373
+ });
5374
+
4776
5375
  // src/web-component/baseStyles.ts
4777
5376
  var baseStyles;
4778
5377
  var init_baseStyles = __esm({
4779
5378
  "src/web-component/baseStyles.ts"() {
4780
- baseStyles = `:where(.bs-root){--bs-surface-d:#ffffff;--bs-surface-border-d:rgba(225,227,237,1);--bs-radius-d:20px;--bs-handle-color-d:rgba(26,22,20,0.3);--bs-handle-width:40px;--bs-handle-height:5px;--bs-z-backdrop:90;--bs-z-sheet:100;--bs-backdrop-color-d:rgba(0,0,0,0.5);--bs-scrim-color-d:transparent;--bs-scrim-blur:0px;--bs-z-scrim:calc(var(--bs-z-sheet) - 1);--bs-size:0px;--bs-progress:0}.bs-backdrop{position:fixed;inset:0;background:var(--bs-backdrop-color,var(--bs-backdrop-color-d));opacity:0;pointer-events:none;z-index:var(--bs-z-backdrop);transition:opacity 0.24s cubic-bezier(0.22,1,0.36,1);will-change:opacity}.bs-root[data-dragging="true"] .bs-backdrop,.bs-root[data-animating="true"] .bs-backdrop{transition:none}.bs-sheet{position:fixed;background:var(--bs-surface,var(--bs-surface-d));box-shadow:var(--bs-shadow,var(--bs-shadow-auto,none));--bs-shadow-fade:clamp(0,calc(var(--bs-progress,0) * 8),1);z-index:var(--bs-z-sheet);pointer-events:auto;overflow:hidden;display:flex;flex-direction:column;-webkit-tap-highlight-color:transparent;user-select:none;overscroll-behavior:contain}.bs-sheet[data-mode="bottom"]{left:0;right:0;bottom:0;width:100%;border-top-left-radius:var(--bs-radius,var(--bs-radius-d));border-top-right-radius:var(--bs-radius,var(--bs-radius-d));border-top:1px solid var(--bs-surface-border,var(--bs-surface-border-d));padding-bottom:env(safe-area-inset-bottom);--bs-shadow-auto:0 calc(var(--bs-progress,0) * -2px - 3px) calc(var(--bs-progress,0) * 18px + 12px) rgba( 0,0,0,calc(var(--bs-shadow-fade) * (var(--bs-progress,0) * 0.15 + 0.12)) )}.bs-sheet[data-mode="top"]{left:0;right:0;top:0;width:100%;border-bottom-left-radius:var(--bs-radius,var(--bs-radius-d));border-bottom-right-radius:var(--bs-radius,var(--bs-radius-d));border-bottom:1px solid var(--bs-surface-border,var(--bs-surface-border-d));flex-direction:column-reverse;--bs-shadow-auto:0 3px 12px rgba(0,0,0,calc(var(--bs-shadow-fade) * 0.12));padding-top:env(safe-area-inset-top)}.bs-sheet[data-mode="left"]{top:0;bottom:0;left:0;height:100%;border-top-right-radius:var(--bs-radius,var(--bs-radius-d));border-bottom-right-radius:var(--bs-radius,var(--bs-radius-d));border-right:1px solid var(--bs-surface-border,var(--bs-surface-border-d));--bs-shadow-auto:3px 0 12px rgba(0,0,0,calc(var(--bs-shadow-fade) * 0.12))}.bs-sheet[data-mode="right"]{top:0;bottom:0;right:0;height:100%;border-top-left-radius:var(--bs-radius,var(--bs-radius-d));border-bottom-left-radius:var(--bs-radius,var(--bs-radius-d));border-left:1px solid var(--bs-surface-border,var(--bs-surface-border-d));--bs-shadow-auto:-3px 0 12px rgba(0,0,0,calc(var(--bs-shadow-fade) * 0.12))}.bs-sheet[data-bs-rest="closed"]{box-shadow:none;visibility:hidden}.bs-sheet[data-bs-webgl="on"],.bs-sheet[data-bs-webgl="on"] .bs-handle,.bs-sheet[data-bs-webgl="on"] .bs-header,.bs-sheet[data-bs-webgl="on"] .bs-footer{background:transparent;box-shadow:none}.bs-sheet[data-mode="left"] .bs-content{padding-right:36px}.bs-sheet[data-mode="right"] .bs-content{padding-left:36px}.bs-handle{flex-shrink:0;min-height:44px;display:flex;flex-direction:column;justify-content:center;padding:var(--bs-handle-padding,8px 16px 4px);cursor:grab;touch-action:none;user-select:none;background:var(--bs-surface,var(--bs-surface-d));-webkit-tap-highlight-color:transparent;outline:none;position:relative}.bs-handle:active{cursor:grabbing}.bs-handle:focus-visible{outline:2px solid currentColor;outline-offset:-2px;border-radius:var(--bs-radius,var(--bs-radius-d))}.bs-handle::before{content:"";display:block;width:var(--bs-handle-width);height:var(--bs-handle-height);background:var(--bs-handle-color,var(--bs-handle-color-d));border-radius:calc(var(--bs-handle-height) / 2);margin:0 auto 8px;transition:width 0.15s ease,background 0.15s ease,transform 0.15s ease;pointer-events:none}.bs-sheet[data-mode="left"] .bs-handle,.bs-sheet[data-mode="right"] .bs-handle{position:absolute;top:0;bottom:0;width:28px;min-width:0;min-height:0;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:0;background:var(--bs-surface,var(--bs-surface-d));z-index:1;overflow:hidden}.bs-sheet[data-mode="left"] .bs-handle>*,.bs-sheet[data-mode="right"] .bs-handle>*{display:none}.bs-sheet[data-mode="left"] .bs-handle{right:0;border-left:1px solid var(--bs-surface-border,var(--bs-surface-border-d))}.bs-sheet[data-mode="right"] .bs-handle{left:0;border-right:1px solid var(--bs-surface-border,var(--bs-surface-border-d))}.bs-sheet[data-mode="left"] .bs-handle::before,.bs-sheet[data-mode="right"] .bs-handle::before{width:var(--bs-handle-height);height:var(--bs-handle-width);margin:0}.bs-sheet:hover .bs-handle::before{background:color-mix(in oklab,var(--bs-handle-color,var(--bs-handle-color-d)),#000 15%)}.bs-handle:active::before{background:color-mix(in oklab,var(--bs-handle-color,var(--bs-handle-color-d)),#000 35%);transform:scaleX(1.15)}.bs-handle.bs-handle--ticks::after{content:"";display:block;position:absolute;left:50%;bottom:6px;transform:translateX(-50%);width:calc(var(--bs-handle-width) * 2);height:3px;background-image:radial-gradient( circle,var(--bs-handle-color,var(--bs-handle-color-d)) 0 1.5px,transparent 1.6px );background-size:8px 3px;background-repeat:repeat-x;background-position:center;opacity:0;transition:opacity 0.18s ease-out;pointer-events:none}.bs-root[data-dragging="true"] .bs-handle.bs-handle--ticks::after{opacity:0.4}.bs-sheet[data-mode="top"] .bs-handle.bs-handle--ticks::after{bottom:auto;top:6px}.bs-sheet[data-mode="left"] .bs-handle.bs-handle--ticks::after,.bs-sheet[data-mode="right"] .bs-handle.bs-handle--ticks::after{left:50%;top:50%;bottom:auto;transform:translate(-50%,-50%);width:3px;height:calc(var(--bs-handle-width) * 2);background-size:3px 8px;background-repeat:repeat-y;margin-left:calc(var(--bs-handle-height) + 6px)}.bs-sheet[data-mode="right"] .bs-handle.bs-handle--ticks::after{margin-left:calc(-1 * (var(--bs-handle-height) + 6px))}.bs-header{flex:0 0 auto;min-height:var(--bs-header-min-height,0px);padding:var(--bs-header-padding,0 16px 8px);background:var(--bs-surface,var(--bs-surface-d))}.bs-content{flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;user-select:text;padding:var(--bs-content-padding,0 16px 16px)}.bs-sheet[data-bs-fit-content="moving"] .bs-content{scroll-padding-bottom:var(--bs-content-inset,0px)}.bs-sheet[data-bs-fit-content="moving"] .bs-content::after{content:"";display:block;flex:none;height:var(--bs-content-inset,0px)}.bs-sheet[data-bs-fit-content="rest"][data-mode="bottom"]::after{content:"";flex:0 1 max(0px,var(--bs-max-size,0px) - var(--bs-size,0px))}.bs-footer{flex:0 0 auto;padding:var(--bs-footer-padding,12px 16px calc(12px + env(safe-area-inset-bottom)));border-top:1px solid var(--bs-surface-border,var(--bs-surface-border-d));background:var(--bs-surface,var(--bs-surface-d))}.bs-sheet[data-bs-fit-content="moving"][data-mode="bottom"] .bs-footer{transform:translateY( clamp( calc(-1 * var(--bs-footer-lift-max,0px)),calc(var(--bs-size,0px) - var(--bs-max-size,0px)),0px ) )}.bs-sheet[data-bs-fit-content="moving"][data-mode="bottom"][data-bs-webgl="on"] .bs-footer{background:var(--bs-surface,var(--bs-surface-d))}.bs-sheet[data-mode="bottom"]:has(.bs-footer:not([hidden]):has(*)){padding-bottom:0}.bs-header:not(:has(*)),.bs-footer:not(:has(*)),.bs-header[hidden],.bs-footer[hidden]{display:none}.bs-screen{position:absolute;inset:0;pointer-events:none;z-index:var(--bs-z-scrim);background:var(--bs-scrim-color,var(--bs-scrim-color-d));backdrop-filter:blur(var(--bs-scrim-blur,0px));-webkit-backdrop-filter:blur(var(--bs-scrim-blur,0px));transition:opacity 0.24s cubic-bezier(0.22,1,0.36,1);will-change:opacity}.bs-root[data-dragging="true"] .bs-screen,.bs-root[data-animating="true"] .bs-screen{transition:none}.bs-scrim-overlay{z-index:calc(var(--bs-z-sheet) + 1);pointer-events:none}.bs-button-slot{position:fixed;z-index:calc(var(--bs-z-sheet) + 1);pointer-events:auto}.bs-button-slot[data-side="left"]{left:16px;bottom:calc(var(--bs-size,0px) + 12px)}.bs-button-slot[data-side="right"]{right:16px;bottom:calc(var(--bs-size,0px) + 12px)}.bs-button-slot[data-mode="top"]{bottom:auto;top:calc(var(--bs-size,0px) + 12px)}.bs-button-slot[data-mode="left"]{left:calc(var(--bs-size,0px) + 12px);right:auto;bottom:auto;top:16px}.bs-button-slot[data-mode="right"]{right:calc(var(--bs-size,0px) + 12px);left:auto;bottom:auto;top:16px}@media (prefers-reduced-motion:reduce){.bs-backdrop,.bs-handle::before,.bs-button-slot[data-side="left"],.bs-button-slot[data-side="right"]{transition:none !important}}@media (prefers-color-scheme:dark){:where(.bs-root){--bs-surface-d:#1a1a1d;--bs-surface-border-d:rgba(255,255,255,0.08);--bs-handle-color-d:rgba(255,255,255,0.45);--bs-shadow-auto:0 -3px 16px rgba(0,0,0,0.5)}}@media (forced-colors:active){.bs-sheet{border:1px solid CanvasText}.bs-handle::before{background:CanvasText;forced-color-adjust:none}.bs-backdrop,.bs-screen{forced-color-adjust:none}}.bs-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}:where(.ovl-root){--ovl-surface:var(--bs-surface,var(--bs-surface-d,#ffffff));--ovl-surface-border:var(--bs-surface-border,var(--bs-surface-border-d,rgba(0,0,0,0.08)));--ovl-shadow:0 -8px 40px rgba(0,0,0,0.35);--ovl-radius:var(--bs-radius,var(--bs-radius-d,20px));--ovl-backdrop-color:rgba(0,0,0,0.5);--ovl-z-backdrop:200;--ovl-z-panel:201}.ovl-backdrop{position:fixed;inset:0;background:var(--ovl-backdrop-color);opacity:0;pointer-events:none;z-index:var(--ovl-z-backdrop)}.ovl-panel{position:fixed;background:var(--ovl-surface);box-shadow:var(--ovl-shadow);z-index:var(--ovl-z-panel);-webkit-tap-highlight-color:transparent;outline:none;transition:transform 0.32s cubic-bezier(0.29,1.24,0.84,0.99),opacity 0.32s ease-out}.ovl-panel[data-state="open"]{transform:translate3d(0,0,0);opacity:1}@starting-style{.ovl-panel[data-edge="bottom"][data-state="open"]{transform:translate3d(0,100%,0);opacity:0}.ovl-panel[data-edge="top"][data-state="open"]{transform:translate3d(0,-100%,0);opacity:0}.ovl-panel[data-edge="left"][data-state="open"]{transform:translate3d(-100%,0,0);opacity:0}.ovl-panel[data-edge="right"][data-state="open"]{transform:translate3d(100%,0,0);opacity:0}}.ovl-panel[data-edge="bottom"]{left:0;right:0;bottom:0;width:100%;border-top-left-radius:var(--ovl-radius);border-top-right-radius:var(--ovl-radius);border-top:1px solid var(--ovl-surface-border);padding-bottom:env(safe-area-inset-bottom)}.ovl-panel[data-edge="top"]{left:0;right:0;top:0;width:100%;border-bottom-left-radius:var(--ovl-radius);border-bottom-right-radius:var(--ovl-radius);border-bottom:1px solid var(--ovl-surface-border);padding-top:env(safe-area-inset-top)}.ovl-panel[data-edge="left"]{top:0;bottom:0;left:0;height:100%;border-top-right-radius:var(--ovl-radius);border-bottom-right-radius:var(--ovl-radius);border-right:1px solid var(--ovl-surface-border)}.ovl-panel[data-edge="right"]{top:0;bottom:0;right:0;height:100%;border-top-left-radius:var(--ovl-radius);border-bottom-left-radius:var(--ovl-radius);border-left:1px solid var(--ovl-surface-border)}@media (prefers-reduced-motion:reduce){.ovl-panel,.ovl-backdrop{transition:none !important}}`;
5379
+ baseStyles = `:where(.bs-root){--bs-surface-d:#ffffff;--bs-surface-border-d:rgba(225,227,237,1);--bs-radius-d:20px;--bs-handle-color-d:rgba(26,22,20,0.3);--bs-handle-width:40px;--bs-handle-height:5px;--bs-z-backdrop:90;--bs-z-sheet:100;--bs-backdrop-color-d:rgba(0,0,0,0.5);--bs-scrim-color-d:transparent;--bs-scrim-blur:0px;--bs-z-scrim:calc(var(--bs-z-sheet) - 1);--bs-size:0px;--bs-progress:0}.bs-backdrop{position:fixed;inset:0;background:var(--bs-backdrop-color,var(--bs-backdrop-color-d));opacity:0;pointer-events:none;z-index:var(--bs-z-backdrop);transition:opacity 0.24s cubic-bezier(0.22,1,0.36,1);will-change:opacity}.bs-root[data-dragging="true"] .bs-backdrop,.bs-root[data-animating="true"] .bs-backdrop{transition:none}.bs-sheet,.bs-handle,.bs-header,.bs-content,.bs-footer{box-sizing:border-box}.bs-sheet{position:fixed;background:var(--bs-surface,var(--bs-surface-d));box-shadow:var(--bs-shadow,var(--bs-shadow-auto,none));--bs-shadow-fade:clamp(0,calc(var(--bs-progress,0) * 8),1);z-index:var(--bs-z-sheet);pointer-events:auto;overflow:hidden;display:flex;flex-direction:column;-webkit-tap-highlight-color:transparent;user-select:none;overscroll-behavior:contain}.bs-sheet[data-mode="bottom"]{left:0;right:0;bottom:var(--bs-keyboard-inset,0px);transition:bottom 0.2s cubic-bezier(0.22,1,0.36,1);width:100%;border-top-left-radius:var(--bs-radius,var(--bs-radius-d));border-top-right-radius:var(--bs-radius,var(--bs-radius-d));border-top:1px solid var(--bs-surface-border,var(--bs-surface-border-d));padding-bottom:env(safe-area-inset-bottom);--bs-shadow-auto:0 calc(var(--bs-progress,0) * -2px - 3px) calc(var(--bs-progress,0) * 18px + 12px) rgba( 0,0,0,calc(var(--bs-shadow-fade) * (var(--bs-progress,0) * 0.15 + 0.12)) )}.bs-sheet[data-mode="top"]{left:0;right:0;top:0;width:100%;border-bottom-left-radius:var(--bs-radius,var(--bs-radius-d));border-bottom-right-radius:var(--bs-radius,var(--bs-radius-d));border-bottom:1px solid var(--bs-surface-border,var(--bs-surface-border-d));flex-direction:column-reverse;--bs-shadow-auto:0 3px 12px rgba(0,0,0,calc(var(--bs-shadow-fade) * 0.12));padding-top:env(safe-area-inset-top)}.bs-sheet[data-mode="left"]{top:0;bottom:0;left:0;height:100%;border-top-right-radius:var(--bs-radius,var(--bs-radius-d));border-bottom-right-radius:var(--bs-radius,var(--bs-radius-d));border-right:1px solid var(--bs-surface-border,var(--bs-surface-border-d));--bs-shadow-auto:3px 0 12px rgba(0,0,0,calc(var(--bs-shadow-fade) * 0.12))}.bs-sheet[data-mode="right"]{top:0;bottom:0;right:0;height:100%;border-top-left-radius:var(--bs-radius,var(--bs-radius-d));border-bottom-left-radius:var(--bs-radius,var(--bs-radius-d));border-left:1px solid var(--bs-surface-border,var(--bs-surface-border-d));--bs-shadow-auto:-3px 0 12px rgba(0,0,0,calc(var(--bs-shadow-fade) * 0.12))}.bs-sheet[data-bs-rest="closed"]{box-shadow:none;visibility:hidden}.bs-sheet[data-bs-webgl="on"],.bs-sheet[data-bs-webgl="on"] .bs-handle,.bs-sheet[data-bs-webgl="on"] .bs-header,.bs-sheet[data-bs-webgl="on"] .bs-footer{background:transparent;box-shadow:none}.bs-sheet[data-mode="left"] .bs-content,.bs-sheet[data-mode="left"] .bs-header,.bs-sheet[data-mode="left"] .bs-footer{padding-right:36px}.bs-sheet[data-mode="right"] .bs-content,.bs-sheet[data-mode="right"] .bs-header,.bs-sheet[data-mode="right"] .bs-footer{padding-left:36px}.bs-handle{flex-shrink:0;min-height:44px;display:flex;flex-direction:column;justify-content:center;padding:var(--bs-handle-padding,8px 16px 4px);cursor:grab;touch-action:none;user-select:none;background:var(--bs-surface,var(--bs-surface-d));-webkit-tap-highlight-color:transparent;outline:none;position:relative}.bs-handle:active{cursor:grabbing}.bs-handle:focus-visible{outline:2px solid currentColor;outline-offset:-2px;border-radius:var(--bs-radius,var(--bs-radius-d))}.bs-handle::before{content:"";display:block;width:var(--bs-handle-width);height:var(--bs-handle-height);background:var(--bs-handle-color,var(--bs-handle-color-d));border-radius:calc(var(--bs-handle-height) / 2);margin:0 auto 8px;transition:width 0.15s ease,background 0.15s ease,transform 0.15s ease;pointer-events:none}.bs-sheet[data-mode="left"] .bs-handle,.bs-sheet[data-mode="right"] .bs-handle{position:absolute;top:0;bottom:0;width:28px;min-width:0;min-height:0;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:0;background:var(--bs-surface,var(--bs-surface-d));z-index:1;overflow:hidden}.bs-sheet[data-mode="left"] .bs-handle>*,.bs-sheet[data-mode="right"] .bs-handle>*{display:none}.bs-sheet[data-mode="left"] .bs-handle{right:0;border-left:1px solid var(--bs-surface-border,var(--bs-surface-border-d))}.bs-sheet[data-mode="right"] .bs-handle{left:0;border-right:1px solid var(--bs-surface-border,var(--bs-surface-border-d))}.bs-sheet[data-mode="left"] .bs-handle::before,.bs-sheet[data-mode="right"] .bs-handle::before{width:var(--bs-handle-height);height:var(--bs-handle-width);margin:0}.bs-sheet:hover .bs-handle::before{background:color-mix(in oklab,var(--bs-handle-color,var(--bs-handle-color-d)),#000 15%)}.bs-handle:active::before{background:color-mix(in oklab,var(--bs-handle-color,var(--bs-handle-color-d)),#000 35%);transform:scaleX(1.15)}.bs-handle.bs-handle--ticks::after{content:"";display:block;position:absolute;left:50%;bottom:6px;transform:translateX(-50%);width:calc(var(--bs-handle-width) * 2);height:3px;background-image:radial-gradient( circle,var(--bs-handle-color,var(--bs-handle-color-d)) 0 1.5px,transparent 1.6px );background-size:8px 3px;background-repeat:repeat-x;background-position:center;opacity:0;transition:opacity 0.18s ease-out;pointer-events:none}.bs-root[data-dragging="true"] .bs-handle.bs-handle--ticks::after{opacity:0.4}.bs-sheet[data-mode="top"] .bs-handle.bs-handle--ticks::after{bottom:auto;top:6px}.bs-sheet[data-mode="left"] .bs-handle.bs-handle--ticks::after,.bs-sheet[data-mode="right"] .bs-handle.bs-handle--ticks::after{left:50%;top:50%;bottom:auto;transform:translate(-50%,-50%);width:3px;height:calc(var(--bs-handle-width) * 2);background-size:3px 8px;background-repeat:repeat-y;margin-left:calc(var(--bs-handle-height) + 6px)}.bs-sheet[data-mode="right"] .bs-handle.bs-handle--ticks::after{margin-left:calc(-1 * (var(--bs-handle-height) + 6px))}.bs-header{flex:0 0 auto;min-height:var(--bs-header-min-height,0px);padding:var(--bs-header-padding,0 16px 8px);background:var(--bs-surface,var(--bs-surface-d))}.bs-content{flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;user-select:text;padding:var(--bs-content-padding,0 16px 16px)}.bs-sheet[data-bs-fit-content="moving"] .bs-content{scroll-padding-bottom:var(--bs-content-inset,0px)}.bs-sheet[data-bs-fit-content="moving"] .bs-content::after{content:"";display:block;flex:none;height:var(--bs-content-inset,0px)}.bs-sheet[data-bs-fit-content="rest"][data-mode="bottom"]::after{content:"";flex:0 1 max(0px,var(--bs-max-size,0px) - var(--bs-size,0px))}.bs-footer{flex:0 0 auto;padding:var(--bs-footer-padding,12px 16px calc(12px + env(safe-area-inset-bottom)));border-top:1px solid var(--bs-surface-border,var(--bs-surface-border-d));background:var(--bs-surface,var(--bs-surface-d))}.bs-sheet[data-bs-fit-content="moving"][data-mode="bottom"] .bs-footer{transform:translateY( clamp( calc(-1 * var(--bs-footer-lift-max,0px)),calc(var(--bs-size,0px) - var(--bs-max-size,0px)),0px ) )}.bs-sheet[data-bs-fit-content="moving"][data-mode="bottom"][data-bs-webgl="on"] .bs-footer{background:var(--bs-surface,var(--bs-surface-d))}.bs-sheet[data-mode="bottom"]:has(.bs-footer:not([hidden]):has(*)){padding-bottom:0}.bs-header:not(:has(*)),.bs-footer:not(:has(*)),.bs-header[hidden],.bs-footer[hidden]{display:none}.bs-screen{position:fixed;inset:0;pointer-events:none;z-index:var(--bs-z-scrim);background:var(--bs-scrim-color,var(--bs-scrim-color-d));backdrop-filter:blur(var(--bs-scrim-blur,0px));-webkit-backdrop-filter:blur(var(--bs-scrim-blur,0px));transition:opacity 0.24s cubic-bezier(0.22,1,0.36,1);will-change:opacity}.bs-root[data-dragging="true"] .bs-screen,.bs-root[data-animating="true"] .bs-screen{transition:none}.bs-scrim-overlay{z-index:calc(var(--bs-z-sheet) + 1);pointer-events:none}.bs-button-slot{position:fixed;z-index:calc(var(--bs-z-sheet) + 1);pointer-events:auto}.bs-button-slot[data-side="left"]{left:16px;bottom:calc(var(--bs-size,0px) + var(--bs-keyboard-inset,0px) + 12px)}.bs-button-slot[data-side="right"]{right:16px;bottom:calc(var(--bs-size,0px) + var(--bs-keyboard-inset,0px) + 12px)}.bs-button-slot[data-mode="top"]{bottom:auto;top:calc(var(--bs-size,0px) + 12px)}.bs-button-slot[data-mode="left"]{left:calc(var(--bs-size,0px) + 12px);right:auto;bottom:auto;top:16px}.bs-button-slot[data-mode="right"]{right:calc(var(--bs-size,0px) + 12px);left:auto;bottom:auto;top:16px}@media (prefers-reduced-motion:reduce){.bs-sheet,.bs-backdrop,.bs-handle::before,.bs-button-slot[data-side="left"],.bs-button-slot[data-side="right"]{transition:none !important}}@media (prefers-color-scheme:dark){:where(.bs-root){--bs-surface-d:#1a1a1d;--bs-surface-border-d:rgba(255,255,255,0.08);--bs-handle-color-d:rgba(255,255,255,0.45);--bs-shadow-auto:0 -3px 16px rgba(0,0,0,0.5)}}@media (forced-colors:active){.bs-sheet{border:1px solid CanvasText}.bs-handle::before{background:CanvasText;forced-color-adjust:none}.bs-backdrop,.bs-screen{forced-color-adjust:none}}.bs-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}:where(.ovl-root){--ovl-surface:var(--bs-surface,var(--bs-surface-d,#ffffff));--ovl-surface-border:var(--bs-surface-border,var(--bs-surface-border-d,rgba(0,0,0,0.08)));--ovl-shadow:0 -8px 40px rgba(0,0,0,0.35);--ovl-radius:var(--bs-radius,var(--bs-radius-d,20px));--ovl-backdrop-color:rgba(0,0,0,0.5);--ovl-z-backdrop:200;--ovl-z-panel:201}.ovl-backdrop{position:fixed;inset:0;background:var(--ovl-backdrop-color);opacity:0;pointer-events:none;z-index:var(--ovl-z-backdrop)}.ovl-panel{position:fixed;background:var(--ovl-surface);box-shadow:var(--ovl-shadow);z-index:var(--ovl-z-panel);-webkit-tap-highlight-color:transparent;outline:none;transition:transform 0.32s cubic-bezier(0.29,1.24,0.84,0.99),opacity 0.32s ease-out}.ovl-panel[data-state="open"]{transform:translate3d(0,0,0);opacity:1}@starting-style{.ovl-panel[data-edge="bottom"][data-state="open"]{transform:translate3d(0,100%,0);opacity:0}.ovl-panel[data-edge="top"][data-state="open"]{transform:translate3d(0,-100%,0);opacity:0}.ovl-panel[data-edge="left"][data-state="open"]{transform:translate3d(-100%,0,0);opacity:0}.ovl-panel[data-edge="right"][data-state="open"]{transform:translate3d(100%,0,0);opacity:0}}.ovl-panel[data-edge="bottom"]{left:0;right:0;bottom:0;width:100%;border-top-left-radius:var(--ovl-radius);border-top-right-radius:var(--ovl-radius);border-top:1px solid var(--ovl-surface-border);padding-bottom:env(safe-area-inset-bottom)}.ovl-panel[data-edge="top"]{left:0;right:0;top:0;width:100%;border-bottom-left-radius:var(--ovl-radius);border-bottom-right-radius:var(--ovl-radius);border-bottom:1px solid var(--ovl-surface-border);padding-top:env(safe-area-inset-top)}.ovl-panel[data-edge="left"]{top:0;bottom:0;left:0;height:100%;border-top-right-radius:var(--ovl-radius);border-bottom-right-radius:var(--ovl-radius);border-right:1px solid var(--ovl-surface-border)}.ovl-panel[data-edge="right"]{top:0;bottom:0;right:0;height:100%;border-top-left-radius:var(--ovl-radius);border-bottom-left-radius:var(--ovl-radius);border-left:1px solid var(--ovl-surface-border)}@media (prefers-reduced-motion:reduce){.ovl-panel,.ovl-backdrop{transition:none !important}}`;
4781
5380
  }
4782
5381
  });
4783
5382
 
@@ -4874,9 +5473,11 @@ var init_shadow_tree = __esm({
4874
5473
  });
4875
5474
 
4876
5475
  // src/web-component/attributes.ts
4877
- var ATTR_SNAP_POINTS, ATTR_ALLOWED, ATTR_INITIAL, ATTR_MODE, ATTR_BACKDROP, ATTR_STYLESHEET, ATTR_ANIMATION, ATTR_FOCUS_TRAP, ATTR_CLOSE_ON_ESCAPE, ATTR_LOCK_BODY_SCROLL, ATTR_SHEET_LABEL, ATTR_STACK_EFFECT, ATTR_PERSISTENT, ATTR_DISABLE_CLOSE, ATTR_DISABLE_DRAG, ATTR_DRAG_FROM, ATTR_DRAG_FROM_CONTENT, ATTR_FIT_CONTENT_TO_SNAP, ATTR_CLOSE_ON_ROUTE_CHANGE, ATTR_RADIUS, ATTR_MAX_HEIGHT, ATTR_RETURN_FOCUS_TO, ATTR_BACKDROP_COLOR, ATTR_SCRIM_COLOR, ATTR_SNAP, LIVE_ATTRS, OBSERVED_ATTRS, isValidSnapPoint, DEFAULT_SNAP_POINTS, parseSnapPoints, VALID_MODES, VALID_ANIMATIONS, parseMode, parseAnimation, VALID_DRAG_FROM, parseDragFrom, parseList, parseDimension, ANCHOR_POSITIONS, ANCHOR_ANIMATIONS, parseAnchorOptions;
5476
+ var ATTR_SNAP_POINTS, ATTR_ALLOWED, ATTR_INITIAL, ATTR_MODE, ATTR_BACKDROP, ATTR_STYLESHEET, ATTR_ANIMATION, ATTR_FOCUS_TRAP, ATTR_CLOSE_ON_ESCAPE, ATTR_LOCK_BODY_SCROLL, ATTR_SHEET_LABEL, ATTR_STACK_EFFECT, ATTR_PERSISTENT, ATTR_DISABLE_CLOSE, ATTR_DISABLE_DRAG, ATTR_DRAG_FROM, ATTR_DRAG_FROM_CONTENT, ATTR_FIT_CONTENT_TO_SNAP, ATTR_CLOSE_ON_ROUTE_CHANGE, ATTR_RADIUS, ATTR_MAX_HEIGHT, ATTR_RETURN_FOCUS_TO, ATTR_BACKDROP_COLOR, ATTR_SCRIM_COLOR, ATTR_SNAP, ATTR_OPEN, ATTR_OPTIONS, ATTR_HANDLE_LABEL, ATTR_CONTENT_LABEL, LIVE_ATTRS, OBSERVED_ATTRS, parseOptions, isValidSnapPoint, DEFAULT_SNAP_POINTS, parseSnapPoints, VALID_MODES, VALID_ANIMATIONS, parseMode, parseAnimation, VALID_DRAG_FROM, parseDragFrom, parseList, parseDimension, ANCHOR_POSITIONS, ANCHOR_ANIMATIONS, parseAnchorOptions;
4878
5477
  var init_attributes = __esm({
4879
5478
  "src/web-component/attributes.ts"() {
5479
+ init_dev_warn();
5480
+ init_option_keys();
4880
5481
  ATTR_SNAP_POINTS = "snap-points";
4881
5482
  ATTR_ALLOWED = "allowed";
4882
5483
  ATTR_INITIAL = "initial";
@@ -4902,6 +5503,10 @@ var init_attributes = __esm({
4902
5503
  ATTR_BACKDROP_COLOR = "backdrop-color";
4903
5504
  ATTR_SCRIM_COLOR = "scrim-color";
4904
5505
  ATTR_SNAP = "snap";
5506
+ ATTR_OPEN = "open";
5507
+ ATTR_OPTIONS = "options";
5508
+ ATTR_HANDLE_LABEL = "handle-label";
5509
+ ATTR_CONTENT_LABEL = "content-label";
4905
5510
  LIVE_ATTRS = /* @__PURE__ */ new Set([
4906
5511
  ATTR_MODE,
4907
5512
  ATTR_RADIUS,
@@ -4913,7 +5518,10 @@ var init_attributes = __esm({
4913
5518
  ATTR_DISABLE_CLOSE,
4914
5519
  ATTR_DISABLE_DRAG,
4915
5520
  ATTR_DRAG_FROM,
4916
- ATTR_DRAG_FROM_CONTENT
5521
+ ATTR_DRAG_FROM_CONTENT,
5522
+ ATTR_HANDLE_LABEL,
5523
+ ATTR_CONTENT_LABEL,
5524
+ ATTR_OPEN
4917
5525
  ]);
4918
5526
  OBSERVED_ATTRS = [
4919
5527
  ATTR_SNAP_POINTS,
@@ -4939,8 +5547,26 @@ var init_attributes = __esm({
4939
5547
  ATTR_RETURN_FOCUS_TO,
4940
5548
  ATTR_BACKDROP_COLOR,
4941
5549
  ATTR_SCRIM_COLOR,
4942
- ATTR_SNAP
5550
+ ATTR_SNAP,
5551
+ ATTR_OPTIONS,
5552
+ ATTR_HANDLE_LABEL,
5553
+ ATTR_CONTENT_LABEL,
5554
+ ATTR_OPEN
4943
5555
  ];
5556
+ parseOptions = (raw) => {
5557
+ if (!raw) return {};
5558
+ try {
5559
+ const parsed = JSON.parse(raw);
5560
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
5561
+ return pickEngineOptions(parsed);
5562
+ }
5563
+ } catch {
5564
+ }
5565
+ devWarn(
5566
+ `[BottomSheet] options="${raw}" is not a JSON object \u2014 ignored.`
5567
+ );
5568
+ return {};
5569
+ };
4944
5570
  isValidSnapPoint = (p) => !!p && typeof p === "object" && typeof p.id === "string" && (typeof p.size === "number" || typeof p.size === "string");
4945
5571
  DEFAULT_SNAP_POINTS = [{ id: "full", size: "full" }];
4946
5572
  parseSnapPoints = (raw) => {
@@ -4953,18 +5579,36 @@ var init_attributes = __esm({
4953
5579
  if (Array.isArray(parsed)) return DEFAULT_SNAP_POINTS;
4954
5580
  } catch {
4955
5581
  }
4956
- return raw.split(",").map((s) => s.trim()).filter(Boolean).map((part) => {
5582
+ const points = [];
5583
+ for (const part of raw.split(",")) {
4957
5584
  const [id, size] = part.split(":").map((s) => s.trim());
5585
+ if (!id || !size) {
5586
+ if (part.trim()) {
5587
+ devWarn(
5588
+ `[BottomSheet] snap-points entry "${part.trim()}" is not "id:size" \u2014 skipped.`
5589
+ );
5590
+ }
5591
+ continue;
5592
+ }
4958
5593
  const numeric = Number(size);
4959
- const resolvedSize = Number.isFinite(numeric) ? numeric : size;
4960
- return { id: id ?? "default", size: resolvedSize };
4961
- });
5594
+ points.push({
5595
+ id,
5596
+ size: Number.isFinite(numeric) ? numeric : size
5597
+ });
5598
+ }
5599
+ if (points.length > 0) return points;
5600
+ devWarn(
5601
+ `[BottomSheet] snap-points="${raw}" has no usable entry \u2014 falling back to a single full-height snap.`
5602
+ );
5603
+ return DEFAULT_SNAP_POINTS;
4962
5604
  };
4963
5605
  VALID_MODES = [
4964
5606
  "bottom",
4965
5607
  "top",
4966
5608
  "left",
4967
- "right"
5609
+ "right",
5610
+ "start",
5611
+ "end"
4968
5612
  ];
4969
5613
  VALID_ANIMATIONS = ["spring", "tween", "ios-spring", "material-bounce", "linear", "snappy"];
4970
5614
  parseMode = (raw) => raw && VALID_MODES.includes(raw) ? raw : "bottom";
@@ -5032,6 +5676,9 @@ var BaseHTMLElement; exports.BottomSheetElement = void 0; exports.defineBottomSh
5032
5676
  var init_BottomSheetElement = __esm({
5033
5677
  "src/web-component/BottomSheetElement.ts"() {
5034
5678
  init_BottomSheetEngine();
5679
+ init_logical_mode();
5680
+ init_open_state();
5681
+ init_option_keys();
5035
5682
  init_baseStyles();
5036
5683
  init_shadow_tree();
5037
5684
  init_attributes();
@@ -5048,6 +5695,7 @@ var init_BottomSheetElement = __esm({
5048
5695
  __publicField(this, "stylesheetLinked", false);
5049
5696
  __publicField(this, "declarativeAnchors", []);
5050
5697
  __publicField(this, "lastActiveId", null);
5698
+ __publicField(this, "extraOptions", {});
5051
5699
  this.root = this.attachShadow({ mode: "open" });
5052
5700
  const baseStyle = document.createElement("style");
5053
5701
  baseStyle.textContent = baseStyles;
@@ -5072,7 +5720,21 @@ var init_BottomSheetElement = __esm({
5072
5720
  static get observedAttributes() {
5073
5721
  return OBSERVED_ATTRS.slice();
5074
5722
  }
5723
+ get options() {
5724
+ return this.extraOptions;
5725
+ }
5726
+ set options(value) {
5727
+ this.extraOptions = value ? pickEngineOptions(value) : {};
5728
+ if (!this.engine) return;
5729
+ this.teardownEngine();
5730
+ this.initEngine();
5731
+ }
5075
5732
  connectedCallback() {
5733
+ if (Object.prototype.hasOwnProperty.call(this, "options")) {
5734
+ const early = this.options;
5735
+ delete this.options;
5736
+ this.options = early;
5737
+ }
5076
5738
  if (!this.stylesheetLinked) {
5077
5739
  this.stylesheetLinked = true;
5078
5740
  const stylesheet = this.getAttribute(ATTR_STYLESHEET);
@@ -5088,8 +5750,8 @@ var init_BottomSheetElement = __esm({
5088
5750
  disconnectedCallback() {
5089
5751
  this.teardownEngine();
5090
5752
  }
5091
- attributeChangedCallback(name, _old, value) {
5092
- if (!this.engine) return;
5753
+ attributeChangedCallback(name, old, value) {
5754
+ if (!this.engine || old === value) return;
5093
5755
  if (LIVE_ATTRS.has(name)) {
5094
5756
  this.applyLiveAttribute(name, value);
5095
5757
  return;
@@ -5111,6 +5773,8 @@ var init_BottomSheetElement = __esm({
5111
5773
  break;
5112
5774
  }
5113
5775
  case ATTR_BACKDROP_COLOR:
5776
+ this.engine.setBackdropColor(value);
5777
+ break;
5114
5778
  case ATTR_SCRIM_COLOR:
5115
5779
  this.engine.setScrimColor(value);
5116
5780
  break;
@@ -5133,12 +5797,20 @@ var init_BottomSheetElement = __esm({
5133
5797
  }
5134
5798
  case ATTR_MODE:
5135
5799
  this.engine.setMode(parseMode(value));
5800
+ this.writeMode(this.engine.getMode());
5136
5801
  break;
5137
5802
  case ATTR_SNAP:
5138
5803
  if (value && value !== this.engine.state.activeId) {
5139
5804
  void this.engine.snapTo(value);
5140
5805
  }
5141
5806
  break;
5807
+ case ATTR_HANDLE_LABEL:
5808
+ case ATTR_CONTENT_LABEL:
5809
+ this.writeLabels();
5810
+ break;
5811
+ case ATTR_OPEN:
5812
+ syncOpen(this.engine, value !== null && value !== "false");
5813
+ break;
5142
5814
  }
5143
5815
  }
5144
5816
  getEngine() {
@@ -5152,20 +5824,51 @@ var init_BottomSheetElement = __esm({
5152
5824
  this.refs.backdrop.removeEventListener("click", this.backdropClickHandler);
5153
5825
  this.backdropClickHandler = null;
5154
5826
  }
5155
- this.engine?.destroy();
5156
- this.engine = null;
5157
- for (const el of this.declarativeAnchors) {
5158
- this.appendChild(el);
5827
+ for (const anchor of this.declarativeAnchors) {
5828
+ anchor.detach();
5829
+ anchor.el.setAttribute("slot", "anchor");
5159
5830
  }
5160
5831
  this.declarativeAnchors = [];
5832
+ this.engine?.destroy();
5833
+ this.engine = null;
5161
5834
  }
5162
- initEngine() {
5163
- const { sheet, handle, content, backdrop, announcer } = this.refs;
5164
- const mode = parseMode(this.getAttribute(ATTR_MODE));
5165
- sheet.setAttribute("data-mode", mode);
5835
+ reflectOpen(open) {
5836
+ const raw = this.getAttribute(ATTR_OPEN);
5837
+ if (open === (raw !== null && raw !== "false")) return;
5838
+ if (open) this.setAttribute(ATTR_OPEN, "");
5839
+ else this.removeAttribute(ATTR_OPEN);
5840
+ }
5841
+ writeLabels() {
5842
+ this.refs.handle.setAttribute(
5843
+ "aria-label",
5844
+ this.getAttribute(ATTR_HANDLE_LABEL) ?? "Resize sheet"
5845
+ );
5846
+ this.refs.content.setAttribute(
5847
+ "aria-label",
5848
+ this.getAttribute(ATTR_CONTENT_LABEL) ?? "Sheet content"
5849
+ );
5850
+ }
5851
+ writeMode(mode) {
5852
+ this.refs.sheet.setAttribute("data-mode", mode);
5166
5853
  this.refs.leftButton.setAttribute("data-mode", mode);
5167
5854
  this.refs.rightButton.setAttribute("data-mode", mode);
5168
- const focusTrap = this.getAttribute(ATTR_FOCUS_TRAP) === "true";
5855
+ }
5856
+ initEngine() {
5857
+ const { sheet, handle, content, backdrop, announcer } = this.refs;
5858
+ const extra = {
5859
+ ...this.extraOptions,
5860
+ ...parseOptions(this.getAttribute(ATTR_OPTIONS))
5861
+ };
5862
+ const given = (name, read) => {
5863
+ const raw = this.getAttribute(name);
5864
+ return raw === null ? void 0 : read(raw);
5865
+ };
5866
+ const isTrue = (raw) => raw === "true";
5867
+ const notFalse = (raw) => raw !== "false";
5868
+ const mode = given(ATTR_MODE, parseMode) ?? extra.mode ?? parseMode(null);
5869
+ this.writeMode(guessPhysicalMode(mode));
5870
+ this.writeLabels();
5871
+ const focusTrap = given(ATTR_FOCUS_TRAP, isTrue) ?? extra.focusTrap ?? false;
5169
5872
  if (focusTrap) {
5170
5873
  sheet.setAttribute("aria-modal", "true");
5171
5874
  } else {
@@ -5183,10 +5886,12 @@ var init_BottomSheetElement = __esm({
5183
5886
  };
5184
5887
  backdrop.addEventListener("click", this.backdropClickHandler);
5185
5888
  }
5186
- const snapPoints = parseSnapPoints(this.getAttribute(ATTR_SNAP_POINTS));
5187
- const initialAttr = this.getAttribute(ATTR_INITIAL) ?? void 0;
5188
- const initial = this.lastActiveId && snapPoints.some((p) => p.id === this.lastActiveId) ? this.lastActiveId : initialAttr;
5889
+ const snapPoints = given(ATTR_SNAP_POINTS, parseSnapPoints) ?? extra.snapPoints ?? parseSnapPoints(null);
5890
+ const known = (id) => id !== null && snapPoints.some((p) => p.id === id);
5891
+ const snapAttr = this.getAttribute(ATTR_SNAP);
5892
+ const initial = known(this.lastActiveId) ? this.lastActiveId : known(snapAttr) ? snapAttr : this.getAttribute(ATTR_INITIAL) ?? extra.initial ?? (this.getAttribute(ATTR_OPEN) === "false" ? closedSnapId(snapPoints) : void 0);
5189
5893
  const opts = {
5894
+ ...extra,
5190
5895
  element: sheet,
5191
5896
  handle,
5192
5897
  scrollContainer: content,
@@ -5194,34 +5899,48 @@ var init_BottomSheetElement = __esm({
5194
5899
  scrim: this.refs.screen,
5195
5900
  mode,
5196
5901
  snapPoints,
5197
- allowed: parseList(this.getAttribute(ATTR_ALLOWED)),
5902
+ allowed: given(ATTR_ALLOWED, parseList) ?? extra.allowed,
5198
5903
  initial,
5199
- animation: parseAnimation(this.getAttribute(ATTR_ANIMATION)),
5904
+ animation: given(ATTR_ANIMATION, parseAnimation) ?? extra.animation,
5200
5905
  focusTrap,
5201
- closeOnEscape: this.getAttribute(ATTR_CLOSE_ON_ESCAPE) !== "false",
5202
- lockBodyScroll: this.getAttribute(ATTR_LOCK_BODY_SCROLL) !== "false",
5203
- stackEffect: this.getAttribute(ATTR_STACK_EFFECT) === "true",
5204
- persistent: this.getAttribute(ATTR_PERSISTENT) === "true",
5205
- disableClose: this.getAttribute(ATTR_DISABLE_CLOSE) === "true",
5206
- disableDrag: this.getAttribute(ATTR_DISABLE_DRAG) === "true",
5207
- dragFrom: parseDragFrom(this.getAttribute(ATTR_DRAG_FROM)),
5208
- dragFromContent: this.getAttribute(ATTR_DRAG_FROM_CONTENT) === null ? void 0 : this.getAttribute(ATTR_DRAG_FROM_CONTENT) !== "false",
5209
- fitContentToSnap: this.hasAttribute(ATTR_FIT_CONTENT_TO_SNAP) && this.getAttribute(ATTR_FIT_CONTENT_TO_SNAP) !== "false",
5210
- closeOnRouteChange: this.getAttribute(ATTR_CLOSE_ON_ROUTE_CHANGE) === "true",
5211
- radius: parseDimension(this.getAttribute(ATTR_RADIUS)),
5212
- maxHeight: parseDimension(this.getAttribute(ATTR_MAX_HEIGHT)),
5213
- returnFocusTo: this.getAttribute(ATTR_RETURN_FOCUS_TO) ?? void 0
5906
+ closeOnEscape: given(ATTR_CLOSE_ON_ESCAPE, notFalse) ?? extra.closeOnEscape,
5907
+ lockBodyScroll: given(ATTR_LOCK_BODY_SCROLL, notFalse) ?? extra.lockBodyScroll,
5908
+ stackEffect: given(ATTR_STACK_EFFECT, isTrue) ?? extra.stackEffect,
5909
+ persistent: given(ATTR_PERSISTENT, isTrue) ?? extra.persistent,
5910
+ disableClose: given(ATTR_DISABLE_CLOSE, isTrue) ?? extra.disableClose,
5911
+ disableDrag: given(ATTR_DISABLE_DRAG, isTrue) ?? extra.disableDrag,
5912
+ dragFrom: given(ATTR_DRAG_FROM, parseDragFrom) ?? extra.dragFrom,
5913
+ dragFromContent: given(ATTR_DRAG_FROM_CONTENT, notFalse) ?? extra.dragFromContent,
5914
+ fitContentToSnap: given(ATTR_FIT_CONTENT_TO_SNAP, notFalse) ?? extra.fitContentToSnap,
5915
+ closeOnRouteChange: given(ATTR_CLOSE_ON_ROUTE_CHANGE, isTrue) ?? extra.closeOnRouteChange,
5916
+ radius: given(ATTR_RADIUS, parseDimension) ?? extra.radius,
5917
+ maxHeight: given(ATTR_MAX_HEIGHT, parseDimension) ?? extra.maxHeight,
5918
+ returnFocusTo: this.getAttribute(ATTR_RETURN_FOCUS_TO) ?? extra.returnFocusTo,
5919
+ backdropColor: this.getAttribute(ATTR_BACKDROP_COLOR) ?? extra.backdropColor,
5920
+ scrimColor: this.getAttribute(ATTR_SCRIM_COLOR) ?? extra.scrimColor
5214
5921
  };
5215
5922
  this.engine = new BottomSheetEngine(opts);
5923
+ const wanted = this.getAttribute(ATTR_OPEN);
5924
+ if (wanted !== null) syncOpen(this.engine, wanted !== "false");
5925
+ this.reflectOpen(this.engine.state.phase !== "closed");
5926
+ this.writeMode(this.engine.getMode());
5216
5927
  sheet.setAttribute("data-active", this.engine.state.activeId);
5217
- const scrimColor = this.getAttribute(ATTR_SCRIM_COLOR) ?? this.getAttribute(ATTR_BACKDROP_COLOR);
5218
- if (scrimColor !== null) this.engine.setScrimColor(scrimColor);
5219
- for (const el of Array.from(
5220
- this.querySelectorAll('[slot="anchor"]')
5221
- )) {
5222
- this.declarativeAnchors.push(el);
5223
- this.engine.addAnchor({ ...parseAnchorOptions(el), element: el });
5224
- }
5928
+ const anchors = Array.from(this.children).filter(
5929
+ (child) => child.getAttribute("slot") === "anchor"
5930
+ );
5931
+ anchors.forEach((el, index) => {
5932
+ const name = `bs-anchor-${index}`;
5933
+ const host = document.createElement("div");
5934
+ const slot = document.createElement("slot");
5935
+ slot.name = name;
5936
+ host.appendChild(slot);
5937
+ el.setAttribute("slot", name);
5938
+ const detach = this.engine.addAnchor({
5939
+ ...parseAnchorOptions(el),
5940
+ element: host
5941
+ });
5942
+ this.declarativeAnchors.push({ el, detach });
5943
+ });
5225
5944
  this.offHandlers = [
5226
5945
  this.engine.on("snap", (payload) => {
5227
5946
  sheet.setAttribute("data-active", payload.id);
@@ -5237,14 +5956,14 @@ var init_BottomSheetElement = __esm({
5237
5956
  );
5238
5957
  if (!accepted) payload.cancel();
5239
5958
  }),
5240
- this.engine.on(
5241
- "open",
5242
- (payload) => this.dispatchEvent(new CustomEvent("open", { detail: payload }))
5243
- ),
5244
- this.engine.on(
5245
- "close",
5246
- () => this.dispatchEvent(new CustomEvent("close"))
5247
- ),
5959
+ this.engine.on("open", (payload) => {
5960
+ this.reflectOpen(true);
5961
+ this.dispatchEvent(new CustomEvent("open", { detail: payload }));
5962
+ }),
5963
+ this.engine.on("close", () => {
5964
+ this.reflectOpen(false);
5965
+ this.dispatchEvent(new CustomEvent("close"));
5966
+ }),
5248
5967
  this.engine.on(
5249
5968
  "progress",
5250
5969
  (payload) => this.dispatchEvent(new CustomEvent("progress", { detail: payload }))
@@ -5324,6 +6043,11 @@ var init_BottomSheetElement = __esm({
5324
6043
  recompute() {
5325
6044
  this.engine?.recompute();
5326
6045
  }
6046
+ setMode(mode) {
6047
+ if (!this.engine) return;
6048
+ this.engine.setMode(mode);
6049
+ this.writeMode(this.engine.getMode());
6050
+ }
5327
6051
  get sheetState() {
5328
6052
  return this.engine?.state ?? null;
5329
6053
  }