@surdeddd/bottom-sheet 0.23.3 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +513 -525
  2. package/README.ru.md +685 -0
  3. package/dist/{BottomSheetCore-COvILxmR.d.ts → BottomSheetCore-B_r4KCQL.d.cts} +48 -12
  4. package/dist/{BottomSheetCore-CaJwHnxY.d.cts → BottomSheetCore-B_r4KCQL.d.ts} +48 -12
  5. package/dist/{BottomSheetEngine-C_1aPJsU.d.cts → BottomSheetEngine-0F7mjyvF.d.cts} +1 -1
  6. package/dist/{BottomSheetEngine-CsgCcCSO.d.ts → BottomSheetEngine-CJV_DDrM.d.ts} +1 -1
  7. package/dist/core.cjs +810 -436
  8. package/dist/core.d.cts +2 -3
  9. package/dist/core.d.ts +2 -3
  10. package/dist/core.js +810 -436
  11. package/dist/debug.d.cts +3 -3
  12. package/dist/debug.d.ts +3 -3
  13. package/dist/{default-features-BJx7J0NH.d.ts → default-features-4Xwv6aVt.d.ts} +4 -2
  14. package/dist/{default-features-CTJb8Wdk.d.cts → default-features-DX2NOxP6.d.cts} +4 -2
  15. package/dist/element.cjs +1428 -699
  16. package/dist/element.d.cts +15 -5
  17. package/dist/element.d.ts +15 -5
  18. package/dist/element.iife.global.js +2 -2
  19. package/dist/element.js +1428 -699
  20. package/dist/features.cjs +334 -190
  21. package/dist/features.d.cts +3 -4
  22. package/dist/features.d.ts +3 -4
  23. package/dist/features.js +334 -191
  24. package/dist/{index-CXN7t3rr.d.ts → index-2shlxhcG.d.cts} +3 -2
  25. package/dist/{index-BBrJJjy5.d.cts → index-CNCRQnpc.d.ts} +3 -2
  26. package/dist/index.cjs +1129 -631
  27. package/dist/index.d.cts +13 -7
  28. package/dist/index.d.ts +13 -7
  29. package/dist/index.js +1129 -632
  30. package/dist/integrations/formik.cjs +21 -10
  31. package/dist/integrations/formik.d.cts +3 -3
  32. package/dist/integrations/formik.d.ts +3 -3
  33. package/dist/integrations/formik.js +22 -11
  34. package/dist/integrations/react-hook-form.cjs +21 -12
  35. package/dist/integrations/react-hook-form.d.cts +3 -3
  36. package/dist/integrations/react-hook-form.d.ts +3 -3
  37. package/dist/integrations/react-hook-form.js +21 -12
  38. package/dist/option-keys-DItuAjUw.d.cts +6 -0
  39. package/dist/option-keys-a5DYNwwO.d.ts +6 -0
  40. package/dist/overlay.cjs +386 -189
  41. package/dist/overlay.d.cts +3 -4
  42. package/dist/overlay.d.ts +3 -4
  43. package/dist/overlay.js +386 -189
  44. package/dist/preact.d.cts +3 -4
  45. package/dist/preact.d.ts +3 -4
  46. package/dist/qwik-lib/index.qwik.cjs +1306 -671
  47. package/dist/qwik-lib/index.qwik.mjs +1306 -671
  48. package/dist/qwik.cjs +1326 -701
  49. package/dist/qwik.d.cts +14 -30
  50. package/dist/qwik.d.ts +14 -30
  51. package/dist/qwik.js +1326 -701
  52. package/dist/react.cjs +1373 -750
  53. package/dist/react.d.cts +31 -14
  54. package/dist/react.d.ts +31 -14
  55. package/dist/react.js +1375 -752
  56. package/dist/solid.cjs +1332 -727
  57. package/dist/solid.d.cts +13 -437
  58. package/dist/solid.d.ts +13 -437
  59. package/dist/solid.js +1334 -729
  60. package/dist/solid.source.jsx +1374 -751
  61. package/dist/styles.css +20 -6
  62. package/dist/svelte-core.cjs +1211 -676
  63. package/dist/svelte-core.js +1207 -677
  64. package/dist/svelte-src/BottomSheet.svelte +102 -59
  65. package/dist/svelte.cjs +1324 -707
  66. package/dist/svelte.d.cts +45 -25
  67. package/dist/svelte.d.ts +45 -25
  68. package/dist/svelte.js +1324 -707
  69. package/dist/vue.cjs +1354 -773
  70. package/dist/vue.d.cts +20 -3
  71. package/dist/vue.d.ts +20 -3
  72. package/dist/vue.js +1354 -773
  73. package/dist/webgl.cjs +38 -7
  74. package/dist/webgl.d.cts +3 -3
  75. package/dist/webgl.d.ts +3 -3
  76. package/dist/webgl.js +38 -7
  77. package/llms.txt +330 -0
  78. package/package.json +62 -42
  79. package/dist/transform-jVfAikE9.d.cts +0 -3
  80. package/dist/transform-jVfAikE9.d.ts +0 -3
package/dist/element.js CHANGED
@@ -1,8 +1,13 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __getOwnPropNames = Object.getOwnPropertyNames;
3
3
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
- var __esm = (fn, res) => function __init() {
5
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
+ var __esm = (fn, res, err) => function __init() {
5
+ if (err) throw err[0];
6
+ try {
7
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
+ } catch (e) {
9
+ throw err = [e], e;
10
+ }
6
11
  };
7
12
  var __export = (target, all) => {
8
13
  for (var name in all)
@@ -10,10 +15,25 @@ var __export = (target, all) => {
10
15
  };
11
16
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
12
17
 
18
+ // src/core/primitives/shared.ts
19
+ function shared(name, init) {
20
+ const host = globalThis;
21
+ const store = host[STORE_KEY] ?? (host[STORE_KEY] = {});
22
+ if (!(name in store)) store[name] = init();
23
+ return store[name];
24
+ }
25
+ var STORE_KEY;
26
+ var init_shared = __esm({
27
+ "src/core/primitives/shared.ts"() {
28
+ STORE_KEY = /* @__PURE__ */ Symbol.for("@surdeddd/bottom-sheet/shared/1");
29
+ }
30
+ });
31
+
13
32
  // src/core/lifecycle/sheet-stack.ts
14
33
  var BASE_Z, STEP, SheetStack, sheetStack;
15
34
  var init_sheet_stack = __esm({
16
35
  "src/core/lifecycle/sheet-stack.ts"() {
36
+ init_shared();
17
37
  BASE_Z = 100;
18
38
  STEP = 10;
19
39
  SheetStack = class {
@@ -80,7 +100,7 @@ var init_sheet_stack = __esm({
80
100
  });
81
101
  }
82
102
  };
83
- sheetStack = new SheetStack();
103
+ sheetStack = shared("stack", () => new SheetStack());
84
104
  }
85
105
  });
86
106
 
@@ -116,7 +136,8 @@ function nextInstanceId(prefix) {
116
136
  var counters;
117
137
  var init_instance_id = __esm({
118
138
  "src/core/primitives/instance-id.ts"() {
119
- counters = {};
139
+ init_shared();
140
+ counters = shared("instanceIds", () => ({}));
120
141
  }
121
142
  });
122
143
 
@@ -139,7 +160,13 @@ function createEventBus() {
139
160
  const set = listeners.get(event);
140
161
  if (!set) return;
141
162
  for (const fn of [...set]) {
142
- fn(payload);
163
+ try {
164
+ fn(payload);
165
+ } catch (err) {
166
+ queueMicrotask(() => {
167
+ throw err;
168
+ });
169
+ }
143
170
  }
144
171
  },
145
172
  listenerCount(event) {
@@ -155,11 +182,31 @@ var init_event_bus = __esm({
155
182
  }
156
183
  });
157
184
 
185
+ // src/core/primitives/dev-warn.ts
186
+ function devWarn(...args) {
187
+ if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
188
+ console.warn(...args);
189
+ }
190
+ }
191
+ var init_dev_warn = __esm({
192
+ "src/core/primitives/dev-warn.ts"() {
193
+ }
194
+ });
195
+
158
196
  // src/core/primitives/css-length.ts
159
- var probe, PROBE_ATTR, ensureProbe, isViewportAxisVertical, viewportSize, PERCENT, resolveSnap;
197
+ var probe, rejected, warnRejected, PROBE_ATTR, ensureProbe, isViewportAxisVertical, viewportSize, PERCENT, resolveSnap;
160
198
  var init_css_length = __esm({
161
199
  "src/core/primitives/css-length.ts"() {
200
+ init_dev_warn();
162
201
  probe = null;
202
+ rejected = /* @__PURE__ */ new Set();
203
+ warnRejected = (value) => {
204
+ if (rejected.has(value)) return;
205
+ rejected.add(value);
206
+ devWarn(
207
+ `[BottomSheet] snap size "${value}" is not a CSS length the browser accepts \u2014 it resolves to 0.`
208
+ );
209
+ };
163
210
  PROBE_ATTR = "data-bs-probe";
164
211
  ensureProbe = (axis) => {
165
212
  if (typeof document === "undefined") return null;
@@ -206,25 +253,16 @@ var init_css_length = __esm({
206
253
  if (!el) return 0;
207
254
  if (axis === "vertical") {
208
255
  el.style.height = point;
256
+ if (el.style.height === "") warnRejected(point);
209
257
  return Math.max(0, el.getBoundingClientRect().height);
210
258
  }
211
259
  el.style.width = point;
260
+ if (el.style.width === "") warnRejected(point);
212
261
  return Math.max(0, el.getBoundingClientRect().width);
213
262
  };
214
263
  }
215
264
  });
216
265
 
217
- // src/core/primitives/dev-warn.ts
218
- function devWarn(...args) {
219
- if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
220
- console.warn(...args);
221
- }
222
- }
223
- var init_dev_warn = __esm({
224
- "src/core/primitives/dev-warn.ts"() {
225
- }
226
- });
227
-
228
266
  // src/core/primitives/snap-points.ts
229
267
  var resolveSnapList, VH_NOT_DVH, auditVhUsage, findNearest, allowedRange, findById, MOUSE_FLICK_VELOCITY, MOUSE_DRAG_THRESHOLD, DIRECTIONAL_INTENT_VELOCITY, findDragSettleTarget;
230
268
  var init_snap_points = __esm({
@@ -369,6 +407,7 @@ var init_snap_resolver = __esm({
369
407
  setMode(mode) {
370
408
  if (mode === this.mode) return;
371
409
  this.mode = mode;
410
+ this.notified = false;
372
411
  this.recompute();
373
412
  }
374
413
  setAllowedIds(ids) {
@@ -378,14 +417,20 @@ var init_snap_resolver = __esm({
378
417
  findById(id) {
379
418
  return findById(id, this.resolved);
380
419
  }
381
- findDragSettleTarget(args) {
420
+ findDragSettleTarget(args, openOnly = false) {
382
421
  return findDragSettleTarget({
383
422
  ...args,
384
423
  resolved: this.resolved,
385
- allowed: this.allowedIds,
424
+ allowed: this.pool(openOnly),
386
425
  maxAxisSize: this.maxAxisSize
387
426
  });
388
427
  }
428
+ nearest(size, openOnly) {
429
+ return findNearest(size, this.resolved, this.pool(openOnly));
430
+ }
431
+ pool(openOnly) {
432
+ return openOnly ? this.allowedIds.filter((id) => (this.findById(id)?.size ?? 0) > 0) : this.allowedIds;
433
+ }
389
434
  getAllowedRange() {
390
435
  return this.rangeCache ?? (this.rangeCache = allowedRange(this.resolved, this.allowedIds));
391
436
  }
@@ -449,14 +494,9 @@ function installResizeObserver(deps) {
449
494
  return () => {
450
495
  };
451
496
  }
452
- const seatFor = () => {
453
- const snap = deps.resolveActiveSnap();
454
- const max = deps.getMaxAxisSize();
455
- return { target: snap ? Math.min(snap.size, max) : null, max };
456
- };
457
497
  const onResize = () => {
458
498
  if (deps.isDestroyed()) return;
459
- const before = seatFor();
499
+ const before = seatOf(deps);
460
500
  deps.recomputeSnaps();
461
501
  const mode = deps.getMode();
462
502
  const isVerticalAxis = mode === "bottom" || mode === "top";
@@ -465,21 +505,8 @@ function installResizeObserver(deps) {
465
505
  if (viewportSize2 > 0 && viewportSize2 < max) {
466
506
  deps.setMaxAxisSize(viewportSize2);
467
507
  }
468
- const after = seatFor();
469
- 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) {
470
- return;
471
- }
472
- const wasAnimating = deps.isAnimating?.() ?? false;
473
- deps.cancelInFlight();
474
- deps.newCycle();
475
- const current = deps.resolveActiveSnap();
476
- const newMax = deps.getMaxAxisSize();
477
- const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
478
- deps.setSize(targetSize);
479
- if (current && !deps.isDragging()) {
480
- deps.applySize(targetSize);
481
- if (wasAnimating) deps.resyncAfterCancel?.();
482
- }
508
+ if (sameSeat(before, seatOf(deps))) return;
509
+ deps.reseat();
483
510
  };
484
511
  let resizeObserver = null;
485
512
  if (typeof ResizeObserver !== "undefined") {
@@ -491,7 +518,7 @@ function installResizeObserver(deps) {
491
518
  window.addEventListener("orientationchange", onResize);
492
519
  const onVisibility = () => {
493
520
  if (deps.isDestroyed()) return;
494
- if (document.hidden) deps.cancelInFlight();
521
+ if (document.hidden) deps.landNow();
495
522
  };
496
523
  document.addEventListener("visibilitychange", onVisibility);
497
524
  return () => {
@@ -501,9 +528,16 @@ function installResizeObserver(deps) {
501
528
  document.removeEventListener("visibilitychange", onVisibility);
502
529
  };
503
530
  }
531
+ var seatOf, sameSeat;
504
532
  var init_resize_observer = __esm({
505
533
  "src/core/features/resize-observer.ts"() {
506
534
  init_hot_path_thresholds();
535
+ seatOf = (deps) => {
536
+ const snap = deps.resolveActiveSnap();
537
+ const max = deps.getMaxAxisSize();
538
+ return { target: snap ? Math.min(snap.size, max) : null, max };
539
+ };
540
+ 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;
507
541
  }
508
542
  });
509
543
 
@@ -523,7 +557,6 @@ function installFitObserver(deps) {
523
557
  });
524
558
  };
525
559
  const ro = new ResizeObserver(schedule);
526
- ro.observe(deps.handle);
527
560
  const scroller = deps.scrollContainer;
528
561
  const observed = /* @__PURE__ */ new Set();
529
562
  const slots = /* @__PURE__ */ new Set();
@@ -540,7 +573,7 @@ function installFitObserver(deps) {
540
573
  };
541
574
  const resync = () => {
542
575
  trackSlots();
543
- const targets = contentTargets(scroller);
576
+ const targets = [...chromeTargets(deps), ...contentTargets(scroller)];
544
577
  for (const el of observed) {
545
578
  if (!targets.includes(el)) {
546
579
  ro.unobserve(el);
@@ -555,13 +588,12 @@ function installFitObserver(deps) {
555
588
  }
556
589
  schedule();
557
590
  };
591
+ resync();
558
592
  let mo;
559
- if (scroller) {
560
- resync();
561
- if (typeof MutationObserver !== "undefined") {
562
- mo = new MutationObserver(resync);
563
- mo.observe(scroller, { childList: true });
564
- }
593
+ if (typeof MutationObserver !== "undefined") {
594
+ mo = new MutationObserver(resync);
595
+ mo.observe(deps.element, { childList: true });
596
+ if (scroller) mo.observe(scroller, { childList: true });
565
597
  }
566
598
  return () => {
567
599
  ro.disconnect();
@@ -572,7 +604,7 @@ function installFitObserver(deps) {
572
604
  if (raf) cancelAnimationFrame(raf);
573
605
  };
574
606
  }
575
- var contentTargets;
607
+ var contentTargets, chromeTargets;
576
608
  var init_fit_observer = __esm({
577
609
  "src/core/features/fit-observer.ts"() {
578
610
  contentTargets = (scroller) => {
@@ -588,6 +620,25 @@ var init_fit_observer = __esm({
588
620
  }
589
621
  return out;
590
622
  };
623
+ chromeTargets = (deps) => {
624
+ const out = [];
625
+ for (const child of Array.from(deps.element.children)) {
626
+ if (child !== deps.scrollContainer) out.push(child);
627
+ }
628
+ if (deps.handle !== deps.element && !out.includes(deps.handle)) {
629
+ out.push(deps.handle);
630
+ }
631
+ return out;
632
+ };
633
+ }
634
+ });
635
+
636
+ // src/core/features/teleport.ts
637
+ var homes, homeRootOf;
638
+ var init_teleport = __esm({
639
+ "src/core/features/teleport.ts"() {
640
+ homes = /* @__PURE__ */ new WeakMap();
641
+ homeRootOf = (root) => (root && homes.get(root)) ?? null;
591
642
  }
592
643
  });
593
644
 
@@ -706,8 +757,9 @@ function installSliderKeyboard(deps) {
706
757
  const isVerticalAxis = deps.mode === "bottom" || deps.mode === "top";
707
758
  const stepUp = isVerticalAxis ? "ArrowUp" : "ArrowRight";
708
759
  const stepDown = isVerticalAxis ? "ArrowDown" : "ArrowLeft";
709
- const sheetExpandsKey = deps.mode === "top" ? stepDown : stepUp;
710
- const sheetCollapsesKey = deps.mode === "top" ? stepUp : stepDown;
760
+ const flipped = deps.mode === "top" || deps.mode === "right";
761
+ const sheetExpandsKey = flipped ? stepDown : stepUp;
762
+ const sheetCollapsesKey = flipped ? stepUp : stepDown;
711
763
  const onHandleKey = (e) => {
712
764
  if (deps.isDestroyed()) return;
713
765
  const allowed = deps.getAllowedIds();
@@ -797,11 +849,12 @@ var init_opacity_dedup = __esm({
797
849
  // src/core/primitives/overlay-position.ts
798
850
  function resolveSheetAnchoredStyle(mode, position, inset) {
799
851
  const sizeOffset = `calc(var(--bs-size, 0px) + ${inset})`;
852
+ const lifted = `calc(var(--bs-size, 0px) + var(--bs-keyboard-inset, 0px) + ${inset})`;
800
853
  switch (mode) {
801
854
  case "bottom":
802
- if (position === "sheet-top-left") return { bottom: sizeOffset, left: inset };
803
- if (position === "sheet-top-right") return { bottom: sizeOffset, right: inset };
804
- return { bottom: sizeOffset, left: "50%", transform: "translateX(-50%)" };
855
+ if (position === "sheet-top-left") return { bottom: lifted, left: inset };
856
+ if (position === "sheet-top-right") return { bottom: lifted, right: inset };
857
+ return { bottom: lifted, left: "50%", transform: "translateX(-50%)" };
805
858
  case "top":
806
859
  if (position === "sheet-top-left") return { top: sizeOffset, left: inset };
807
860
  if (position === "sheet-top-right") return { top: sizeOffset, right: inset };
@@ -816,6 +869,13 @@ function resolveSheetAnchoredStyle(mode, position, inset) {
816
869
  return { right: sizeOffset, top: "50%", transform: "translateY(-50%)" };
817
870
  }
818
871
  }
872
+ function resetOverlayPosition(ws) {
873
+ ws.top = "";
874
+ ws.bottom = "";
875
+ ws.left = "";
876
+ ws.right = "";
877
+ ws.transform = "";
878
+ }
819
879
  function applyOverlayPosition(ws, mode, position, inset) {
820
880
  switch (position) {
821
881
  case "top-left":
@@ -878,7 +938,7 @@ var init_overlay_position = __esm({
878
938
  });
879
939
 
880
940
  // src/core/controllers/scrim-controller.ts
881
- var VALID_CSS_LENGTH, DEFAULT_SCRIM_DIM, ScrimController;
941
+ var VALID_CSS_LENGTH, DEFAULT_SCRIM_DIM, BACKDROP_COLOR_VAR, unit, ScrimController;
882
942
  var init_scrim_controller = __esm({
883
943
  "src/core/controllers/scrim-controller.ts"() {
884
944
  init_types();
@@ -889,6 +949,8 @@ var init_scrim_controller = __esm({
889
949
  init_overlay_position();
890
950
  VALID_CSS_LENGTH = /^-?\d+(?:\.\d+)?(?:px|em|rem|%)$/;
891
951
  DEFAULT_SCRIM_DIM = "rgba(0, 0, 0, 0.4)";
952
+ BACKDROP_COLOR_VAR = "--bs-backdrop-color";
953
+ unit = (value) => Number.isFinite(value) ? Math.min(Math.max(value, 0), 1) : 1;
892
954
  ScrimController = class {
893
955
  constructor(deps, opts) {
894
956
  __publicField(this, "screenComponent");
@@ -903,11 +965,13 @@ var init_scrim_controller = __esm({
903
965
  __publicField(this, "scrimMode");
904
966
  __publicField(this, "backdropRange");
905
967
  __publicField(this, "screenRange");
968
+ __publicField(this, "backdropPeak");
906
969
  __publicField(this, "scrimEnabled", true);
907
970
  __publicField(this, "savedScrimRanges", null);
908
971
  __publicField(this, "scrimTapToCloseEnabled", false);
909
972
  __publicField(this, "detachScrimTap", null);
910
973
  __publicField(this, "scrimOverlayTeardown", null);
974
+ __publicField(this, "placeOverlay", null);
911
975
  __publicField(this, "backdropOpacitySentinel", new WriteSentinel());
912
976
  __publicField(this, "screenOpacitySentinel", new WriteSentinel());
913
977
  __publicField(this, "lastBackdropPointer", "");
@@ -924,6 +988,8 @@ var init_scrim_controller = __esm({
924
988
  const preset = opts.scrimPreset ? SCRIM_PRESETS[opts.scrimPreset] : null;
925
989
  this.backdropRange = opts.backdropRange ?? preset?.range ?? [0, 1];
926
990
  this.screenRange = opts.screenRange ?? preset?.range ?? [0, 1];
991
+ this.backdropPeak = unit(opts.backdropOpacity ?? 1);
992
+ this.setBackdropColor(opts.backdropColor);
927
993
  this.scrimTapToCloseEnabled = opts.scrimTapToClose ?? false;
928
994
  const explicitColor = opts.scrimColor ?? preset?.color;
929
995
  const effectiveColor = explicitColor ?? (this.scrimMode !== "off" && !this.backdrop ? DEFAULT_SCRIM_DIM : void 0);
@@ -953,24 +1019,19 @@ var init_scrim_controller = __esm({
953
1019
  this.setScrimTapToClose(true);
954
1020
  }
955
1021
  }
956
- applyOpacity(progress, progressChanged) {
957
- if (!progressChanged && this.backdropOpacitySentinel.value !== -1 && this.screenOpacitySentinel.value !== -1) {
1022
+ applyOpacity(progress, progressChanged, epsilon = OPACITY_WRITE_EPSILON) {
1023
+ if (epsilon > 0 && !progressChanged && this.backdropOpacitySentinel.value !== -1 && this.screenOpacitySentinel.value !== -1) {
958
1024
  return;
959
1025
  }
960
1026
  if (this.backdrop) {
961
1027
  const [s, e] = this.backdropRange;
962
1028
  const range = Math.max(e - s, RANGE_DIVISION_EPSILON);
963
- const backdropOpacity = Math.min(
964
- Math.max((progress - s) / range, 0),
965
- 1
966
- );
967
- if (this.backdropOpacitySentinel.shouldWrite(
968
- backdropOpacity,
969
- OPACITY_WRITE_EPSILON
970
- )) {
1029
+ const along = Math.min(Math.max((progress - s) / range, 0), 1);
1030
+ const backdropOpacity = along * this.backdropPeak;
1031
+ if (this.backdropOpacitySentinel.shouldWrite(backdropOpacity, epsilon)) {
971
1032
  this.backdrop.style.opacity = String(backdropOpacity);
972
1033
  }
973
- const nextPointer = backdropOpacity > POINTER_EVENTS_OPACITY_THRESHOLD ? "auto" : "none";
1034
+ const nextPointer = along > POINTER_EVENTS_OPACITY_THRESHOLD ? "auto" : "none";
974
1035
  if (nextPointer !== this.lastBackdropPointer) {
975
1036
  this.backdrop.style.pointerEvents = nextPointer;
976
1037
  this.lastBackdropPointer = nextPointer;
@@ -985,10 +1046,7 @@ var init_scrim_controller = __esm({
985
1046
  (progress - ss) / Math.max(RANGE_DIVISION_EPSILON, se - ss)
986
1047
  )
987
1048
  );
988
- if (this.screenOpacitySentinel.shouldWrite(
989
- screenOpacity,
990
- OPACITY_WRITE_EPSILON
991
- )) {
1049
+ if (this.screenOpacitySentinel.shouldWrite(screenOpacity, epsilon)) {
992
1050
  this.screenComponent.style.opacity = String(screenOpacity);
993
1051
  }
994
1052
  const nextDisplay = screenOpacity > 0 ? "" : "none";
@@ -1004,6 +1062,17 @@ var init_scrim_controller = __esm({
1004
1062
  this.invalidateOpacityCache();
1005
1063
  applySize();
1006
1064
  }
1065
+ setBackdropColor(color) {
1066
+ if (this.isDestroyed() || !this.backdrop) return;
1067
+ if (color) this.backdrop.style.setProperty(BACKDROP_COLOR_VAR, color);
1068
+ else this.backdrop.style.removeProperty(BACKDROP_COLOR_VAR);
1069
+ }
1070
+ setBackdropOpacity(value, applySize) {
1071
+ if (this.isDestroyed()) return;
1072
+ this.backdropPeak = unit(value);
1073
+ this.invalidateOpacityCache();
1074
+ applySize();
1075
+ }
1007
1076
  setScreenRange(range, applySize) {
1008
1077
  if (this.isDestroyed()) return;
1009
1078
  this.screenRange = range;
@@ -1026,6 +1095,8 @@ var init_scrim_controller = __esm({
1026
1095
  if (this.isDestroyed() || mode === this.mode) return;
1027
1096
  this.mode = mode;
1028
1097
  this.invalidateOpacityCache();
1098
+ if (this.scrimMode === "above-sheet") this.applyAboveSheetInset();
1099
+ this.placeOverlay?.();
1029
1100
  }
1030
1101
  setScrimMode(mode, applySize) {
1031
1102
  if (this.isDestroyed()) return;
@@ -1038,7 +1109,7 @@ var init_scrim_controller = __esm({
1038
1109
  if (previous === "above-sheet" && mode !== "above-sheet") {
1039
1110
  s.position = "";
1040
1111
  s.inset = "";
1041
- s.pointerEvents = "";
1112
+ this.syncPointer();
1042
1113
  }
1043
1114
  if (mode === "above-sheet") {
1044
1115
  this.applyAboveSheetInset();
@@ -1063,9 +1134,6 @@ var init_scrim_controller = __esm({
1063
1134
  if (enabled === installed) return;
1064
1135
  if (enabled) {
1065
1136
  const target = this.screenComponent;
1066
- if (target.style.pointerEvents === "none") {
1067
- target.style.pointerEvents = "auto";
1068
- }
1069
1137
  const onClick = () => {
1070
1138
  if (this.isDestroyed()) return;
1071
1139
  if (this.closeFn) {
@@ -1088,6 +1156,11 @@ var init_scrim_controller = __esm({
1088
1156
  this.detachScrimTap = null;
1089
1157
  this.scrimTapToCloseEnabled = false;
1090
1158
  }
1159
+ this.syncPointer();
1160
+ }
1161
+ syncPointer() {
1162
+ if (!this.screenComponent) return;
1163
+ this.screenComponent.style.pointerEvents = this.scrimInteractive || this.detachScrimTap ? "auto" : "none";
1091
1164
  }
1092
1165
  setScrimEnabled(enabled, applySize) {
1093
1166
  if (this.isDestroyed()) return;
@@ -1171,8 +1244,12 @@ var init_scrim_controller = __esm({
1171
1244
  const wrapper = screen.ownerDocument.createElement("div");
1172
1245
  wrapper.className = "bs-scrim-overlay";
1173
1246
  const ws = wrapper.style;
1174
- ws.position = "absolute";
1175
- applyOverlayPosition(ws, this.mode, position, inset);
1247
+ ws.position = "fixed";
1248
+ const place = () => {
1249
+ resetOverlayPosition(ws);
1250
+ applyOverlayPosition(ws, this.mode, position, inset);
1251
+ };
1252
+ place();
1176
1253
  if (interactive) {
1177
1254
  ws.pointerEvents = "auto";
1178
1255
  }
@@ -1186,8 +1263,10 @@ var init_scrim_controller = __esm({
1186
1263
  };
1187
1264
  }
1188
1265
  host.appendChild(wrapper);
1266
+ this.placeOverlay = place;
1189
1267
  const teardown = () => {
1190
1268
  if (wrapper.parentNode) wrapper.parentNode.removeChild(wrapper);
1269
+ if (this.placeOverlay === place) this.placeOverlay = null;
1191
1270
  if (this.scrimOverlayTeardown === teardown) {
1192
1271
  this.scrimOverlayTeardown = null;
1193
1272
  }
@@ -1211,6 +1290,7 @@ var init_scrim_controller = __esm({
1211
1290
  if (this.backdrop) {
1212
1291
  this.backdrop.style.opacity = "";
1213
1292
  this.backdrop.style.pointerEvents = "";
1293
+ this.backdrop.style.removeProperty(BACKDROP_COLOR_VAR);
1214
1294
  }
1215
1295
  this.invalidateOpacityCache();
1216
1296
  this.lastBackdropPointer = "";
@@ -1235,13 +1315,13 @@ var init_scrim_controller = __esm({
1235
1315
  }
1236
1316
  if (opts.interactive !== void 0) {
1237
1317
  this.scrimInteractive = opts.interactive;
1238
- s.pointerEvents = opts.interactive ? "auto" : "none";
1318
+ this.syncPointer();
1239
1319
  }
1240
1320
  }
1241
1321
  applyAboveSheetInset() {
1242
1322
  if (!this.screenComponent) return;
1243
1323
  const insetByMode = {
1244
- bottom: "0 0 var(--bs-size) 0",
1324
+ bottom: "0 0 calc(var(--bs-size) + var(--bs-keyboard-inset, 0px)) 0",
1245
1325
  top: "var(--bs-size) 0 0 0",
1246
1326
  left: "0 0 0 var(--bs-size)",
1247
1327
  right: "0 var(--bs-size) 0 0"
@@ -1249,14 +1329,14 @@ var init_scrim_controller = __esm({
1249
1329
  const s = this.screenComponent.style;
1250
1330
  s.position = "fixed";
1251
1331
  s.inset = insetByMode[this.mode];
1252
- s.pointerEvents = this.scrimInteractive || this.scrimTapToCloseEnabled ? "auto" : "none";
1332
+ this.syncPointer();
1253
1333
  }
1254
1334
  };
1255
1335
  }
1256
1336
  });
1257
1337
 
1258
1338
  // src/core/animation/animation.ts
1259
- var easeOutBack, easeOutCubic, easeLinear, easeOutQuint, tween, prefersReducedMotion;
1339
+ var easeOutBack, easeOutCubic, easeLinear, easeOutQuint, MIN_RETARGET_MS, tween, prefersReducedMotion;
1260
1340
  var init_animation = __esm({
1261
1341
  "src/core/animation/animation.ts"() {
1262
1342
  easeOutBack = (t) => {
@@ -1267,6 +1347,7 @@ var init_animation = __esm({
1267
1347
  easeOutCubic = (t) => 1 - Math.pow(1 - t, 3);
1268
1348
  easeLinear = (t) => t;
1269
1349
  easeOutQuint = (t) => 1 - Math.pow(1 - t, 5);
1350
+ MIN_RETARGET_MS = 120;
1270
1351
  tween = ({
1271
1352
  from,
1272
1353
  to,
@@ -1275,12 +1356,18 @@ var init_animation = __esm({
1275
1356
  onUpdate
1276
1357
  }) => {
1277
1358
  let cancelled = false;
1359
+ let finished = false;
1278
1360
  let rafId = 0;
1279
1361
  let resolveFn = null;
1280
- const start = performance.now();
1362
+ let start = performance.now();
1363
+ let origin = from;
1364
+ let target = to;
1365
+ let span = duration;
1366
+ let last = from;
1281
1367
  const promise = new Promise((resolve) => {
1282
1368
  resolveFn = resolve;
1283
1369
  if (duration <= 0) {
1370
+ finished = true;
1284
1371
  onUpdate(to);
1285
1372
  resolve();
1286
1373
  return;
@@ -1288,12 +1375,13 @@ var init_animation = __esm({
1288
1375
  const step = (now) => {
1289
1376
  if (cancelled) return;
1290
1377
  const elapsed = Math.max(0, now - start);
1291
- const t = Math.min(elapsed / duration, 1);
1292
- const value = from + (to - from) * easing(t);
1293
- onUpdate(value);
1378
+ const t = Math.min(elapsed / span, 1);
1379
+ last = origin + (target - origin) * easing(t);
1380
+ onUpdate(last);
1294
1381
  if (t < 1) {
1295
1382
  rafId = requestAnimationFrame(step);
1296
1383
  } else {
1384
+ finished = true;
1297
1385
  resolve();
1298
1386
  }
1299
1387
  };
@@ -1305,6 +1393,15 @@ var init_animation = __esm({
1305
1393
  cancelAnimationFrame(rafId);
1306
1394
  resolveFn?.();
1307
1395
  },
1396
+ retarget: (next) => {
1397
+ if (cancelled || finished || next === target) return;
1398
+ const now = performance.now();
1399
+ const remaining = span - Math.max(0, now - start);
1400
+ origin = last;
1401
+ target = next;
1402
+ start = now;
1403
+ span = Math.max(remaining, MIN_RETARGET_MS);
1404
+ },
1308
1405
  promise
1309
1406
  };
1310
1407
  };
@@ -1316,7 +1413,7 @@ var init_animation = __esm({
1316
1413
  });
1317
1414
 
1318
1415
  // src/core/animation/spring.ts
1319
- var DEFAULT_SPRING, MAX_DT, runSpring;
1416
+ var DEFAULT_SPRING, MAX_DT, MAX_DURATION_MS, runSpring;
1320
1417
  var init_spring = __esm({
1321
1418
  "src/core/animation/spring.ts"() {
1322
1419
  DEFAULT_SPRING = {
@@ -1327,22 +1424,32 @@ var init_spring = __esm({
1327
1424
  restSpeed: 0.5
1328
1425
  };
1329
1426
  MAX_DT = 1 / 30;
1427
+ MAX_DURATION_MS = 3e3;
1330
1428
  runSpring = ({
1331
1429
  from,
1332
1430
  to,
1333
1431
  velocity = 0,
1334
1432
  config,
1433
+ maxDuration = MAX_DURATION_MS,
1335
1434
  onUpdate
1336
1435
  }) => {
1337
1436
  const cfg = { ...DEFAULT_SPRING, ...config };
1338
1437
  let cancelled = false;
1438
+ let finished = false;
1339
1439
  let rafId = 0;
1340
1440
  let resolveFn = null;
1341
1441
  let x = from;
1342
1442
  let v = velocity;
1443
+ let target = to;
1343
1444
  let lastTime = performance.now();
1445
+ let deadline = lastTime + maxDuration;
1344
1446
  const promise = new Promise((resolve) => {
1345
1447
  resolveFn = resolve;
1448
+ const land = () => {
1449
+ finished = true;
1450
+ onUpdate(target, 0);
1451
+ resolve();
1452
+ };
1346
1453
  const step = (now) => {
1347
1454
  if (cancelled) return;
1348
1455
  const dt = Math.min(Math.max(0, now - lastTime) / 1e3, MAX_DT);
@@ -1351,21 +1458,19 @@ var init_spring = __esm({
1351
1458
  const subDt = dt / steps;
1352
1459
  let stepsLeft = steps;
1353
1460
  while (stepsLeft-- > 0) {
1354
- const force = -cfg.stiffness * (x - to) - cfg.damping * v;
1461
+ const force = -cfg.stiffness * (x - target) - cfg.damping * v;
1355
1462
  const accel = force / cfg.mass;
1356
1463
  v += accel * subDt;
1357
1464
  x += v * subDt;
1358
1465
  }
1359
- if (!Number.isFinite(x) || !Number.isFinite(v)) {
1360
- onUpdate(to, 0);
1361
- resolve();
1466
+ if (!Number.isFinite(x) || !Number.isFinite(v) || lastTime >= deadline) {
1467
+ land();
1362
1468
  return;
1363
1469
  }
1364
1470
  onUpdate(x, v);
1365
- const isAtRest = Math.abs(to - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
1471
+ const isAtRest = Math.abs(target - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
1366
1472
  if (isAtRest) {
1367
- onUpdate(to, 0);
1368
- resolve();
1473
+ land();
1369
1474
  } else {
1370
1475
  rafId = requestAnimationFrame(step);
1371
1476
  }
@@ -1378,6 +1483,11 @@ var init_spring = __esm({
1378
1483
  cancelAnimationFrame(rafId);
1379
1484
  resolveFn?.();
1380
1485
  },
1486
+ retarget: (next) => {
1487
+ if (cancelled || finished) return;
1488
+ target = next;
1489
+ deadline = performance.now() + maxDuration;
1490
+ },
1381
1491
  promise
1382
1492
  };
1383
1493
  };
@@ -1550,21 +1660,40 @@ var init_animation_runner = __esm({
1550
1660
  this.applySizeFn(size);
1551
1661
  }
1552
1662
  cancel() {
1553
- this.currentTween?.cancel();
1554
- this.currentSpring?.cancel();
1663
+ const tween2 = this.currentTween;
1664
+ const spring = this.currentSpring;
1665
+ this.currentTween = null;
1666
+ this.currentSpring = null;
1667
+ tween2?.cancel();
1668
+ spring?.cancel();
1555
1669
  this.cancelWaapi();
1556
1670
  }
1671
+ retarget(target) {
1672
+ if (this.currentSpring) {
1673
+ this.currentSpring.retarget(target);
1674
+ return true;
1675
+ }
1676
+ if (this.currentTween) {
1677
+ this.currentTween.retarget(target);
1678
+ return true;
1679
+ }
1680
+ if (this.currentWaapi) {
1681
+ this.currentWaapi.retarget(target);
1682
+ return true;
1683
+ }
1684
+ return false;
1685
+ }
1557
1686
  async animateTo(target, velocityPxPerMs) {
1558
1687
  if (target === this.getSize()) {
1559
- if (!this.isAnimating && !this.isDragging()) {
1688
+ if (this.isAnimating) this.cancel();
1689
+ if (!this.isDragging()) {
1560
1690
  this.applySizeFn(target);
1691
+ this.getRootEl()?.removeAttribute("data-animating");
1561
1692
  this.element.style.willChange = "";
1562
1693
  }
1563
1694
  return;
1564
1695
  }
1565
- this.currentTween?.cancel();
1566
- this.currentSpring?.cancel();
1567
- this.cancelWaapi();
1696
+ this.cancel();
1568
1697
  this.getRootEl()?.setAttribute("data-animating", "true");
1569
1698
  this.element.style.willChange = "transform";
1570
1699
  if (this.reducedMotion) {
@@ -1574,19 +1703,13 @@ var init_animation_runner = __esm({
1574
1703
  return;
1575
1704
  }
1576
1705
  if (this.settleWaapi && this.applyAux && this.getTransformFor && typeof this.element.animate === "function") {
1577
- const samples = this.animationKind === "spring" ? sampleSpringSettle(
1578
- this.getSize(),
1579
- target,
1580
- velocityPxPerMs * VELOCITY_PX_PER_S,
1581
- this.springConfig
1582
- ) : sampleTweenSettle(
1706
+ const samples = this.sampleSettle(
1583
1707
  this.getSize(),
1584
1708
  target,
1585
- this.duration,
1586
- this.easing
1709
+ velocityPxPerMs * VELOCITY_PX_PER_S
1587
1710
  );
1588
1711
  if (samples.values.length >= 2 && samples.durationMs > 0) {
1589
- await this.runWaapiSettle(samples, target);
1712
+ await this.runWaapiSettle({ samples, target });
1590
1713
  if (!this.isAnimating) {
1591
1714
  this.getRootEl()?.removeAttribute("data-animating");
1592
1715
  if (!this.isDragging()) this.element.style.willChange = "";
@@ -1628,7 +1751,10 @@ var init_animation_runner = __esm({
1628
1751
  }
1629
1752
  }
1630
1753
  }
1631
- async runWaapiSettle(samples, target) {
1754
+ sampleSettle(from, to, velocityPxPerS) {
1755
+ return this.animationKind === "spring" ? sampleSpringSettle(from, to, velocityPxPerS, this.springConfig) : sampleTweenSettle(from, to, this.duration, this.easing);
1756
+ }
1757
+ startWaapiLeg(samples, onRetarget) {
1632
1758
  const applyAux = this.applyAux;
1633
1759
  const getTransformFor = this.getTransformFor;
1634
1760
  const frames = samples.values.map((v) => ({
@@ -1643,16 +1769,20 @@ var init_animation_runner = __esm({
1643
1769
  let stopped = false;
1644
1770
  let auxRaf = 0;
1645
1771
  const lastIdx = samples.values.length - 1;
1772
+ const cursor = () => Math.min((Number(anim.currentTime) || 0) / samples.stepMs, lastIdx);
1646
1773
  const sizeNow = () => {
1647
- const at = Math.min(
1648
- (Number(anim.currentTime) || 0) / samples.stepMs,
1649
- lastIdx
1650
- );
1774
+ const at = cursor();
1651
1775
  const idx = Math.floor(at);
1652
1776
  const from = samples.values[idx];
1653
1777
  const to = samples.values[Math.min(idx + 1, lastIdx)];
1654
1778
  return from + (to - from) * (at - idx);
1655
1779
  };
1780
+ const velocityNow = () => {
1781
+ const idx = Math.min(Math.floor(cursor()), Math.max(lastIdx - 1, 0));
1782
+ const from = samples.values[idx];
1783
+ const to = samples.values[Math.min(idx + 1, lastIdx)];
1784
+ return (to - from) / samples.stepMs * 1e3;
1785
+ };
1656
1786
  const auxTick = () => {
1657
1787
  if (stopped) return;
1658
1788
  applyAux(sizeNow());
@@ -1665,22 +1795,55 @@ var init_animation_runner = __esm({
1665
1795
  stopped = true;
1666
1796
  cancelAnimationFrame(auxRaf);
1667
1797
  },
1668
- sizeNow
1798
+ sizeNow,
1799
+ velocityNow,
1800
+ retarget: (to) => onRetarget(entry, to)
1669
1801
  };
1670
- this.currentWaapi = entry;
1671
- try {
1672
- await anim.finished;
1673
- } catch {
1674
- }
1675
- entry.stop();
1676
- const wasCurrent = this.currentWaapi === entry;
1677
- if (wasCurrent) this.currentWaapi = null;
1678
- if (wasCurrent && anim.playState === "finished") {
1679
- this.applySizeFn(target);
1802
+ return entry;
1803
+ }
1804
+ async runWaapiSettle(first) {
1805
+ let leg = first;
1806
+ for (; ; ) {
1807
+ let queued = null;
1808
+ const entry = this.startWaapiLeg(leg.samples, (running, to) => {
1809
+ const size = this.readShownSize?.() ?? running.sizeNow();
1810
+ queued = {
1811
+ samples: this.sampleSettle(size, to, running.velocityNow()),
1812
+ target: to
1813
+ };
1814
+ running.stop();
1815
+ try {
1816
+ running.anim.cancel();
1817
+ } catch {
1818
+ }
1819
+ this.applySizeFn(size);
1820
+ });
1821
+ this.currentWaapi = entry;
1680
1822
  try {
1681
- anim.cancel();
1823
+ await entry.anim.finished;
1682
1824
  } catch {
1683
1825
  }
1826
+ entry.stop();
1827
+ const wasCurrent = this.currentWaapi === entry;
1828
+ const next = queued;
1829
+ if (wasCurrent && next) {
1830
+ if (next.samples.values.length >= 2 && next.samples.durationMs > 0) {
1831
+ leg = next;
1832
+ continue;
1833
+ }
1834
+ this.currentWaapi = null;
1835
+ this.applySizeFn(next.target);
1836
+ return;
1837
+ }
1838
+ if (wasCurrent) this.currentWaapi = null;
1839
+ if (wasCurrent && entry.anim.playState === "finished") {
1840
+ this.applySizeFn(leg.target);
1841
+ try {
1842
+ entry.anim.cancel();
1843
+ } catch {
1844
+ }
1845
+ }
1846
+ return;
1684
1847
  }
1685
1848
  }
1686
1849
  destroy() {
@@ -1703,9 +1866,10 @@ var init_animation_runner = __esm({
1703
1866
  });
1704
1867
 
1705
1868
  // src/core/lifecycle/focus-trap.ts
1706
- var FOCUSABLE, isVisible, collectFocusables, focusables, containsComposed, trapStack, installFocusTrap;
1869
+ var FOCUSABLE, isVisible, collectFocusables, focusables, findDeep, FOCUS_ALLOW_ATTR, composedParent, containsComposed, isAllowedOutside, deepActiveElement, trapStack, installFocusTrap;
1707
1870
  var init_focus_trap = __esm({
1708
1871
  "src/core/lifecycle/focus-trap.ts"() {
1872
+ init_shared();
1709
1873
  FOCUSABLE = [
1710
1874
  "a[href]",
1711
1875
  "area[href]",
@@ -1740,27 +1904,51 @@ var init_focus_trap = __esm({
1740
1904
  focusables = (root) => collectFocusables(root).filter(
1741
1905
  (el) => !el.hasAttribute("inert") && isVisible(el) && !el.matches("[aria-hidden='true']")
1742
1906
  );
1907
+ findDeep = (root, selector) => {
1908
+ const direct = root.querySelector(selector);
1909
+ if (direct || typeof HTMLSlotElement === "undefined") return direct;
1910
+ for (const slot of Array.from(root.querySelectorAll("slot"))) {
1911
+ for (const assigned of slot.assignedElements()) {
1912
+ if (assigned.matches(selector)) return assigned;
1913
+ const inner = findDeep(assigned, selector);
1914
+ if (inner) return inner;
1915
+ }
1916
+ }
1917
+ return null;
1918
+ };
1919
+ FOCUS_ALLOW_ATTR = "data-bs-focus-allow";
1920
+ composedParent = (node) => {
1921
+ const slot = node.assignedSlot;
1922
+ if (slot) return slot;
1923
+ const parent = node.parentNode;
1924
+ return parent instanceof ShadowRoot ? parent.host : parent;
1925
+ };
1743
1926
  containsComposed = (container, node) => {
1744
- let n = node;
1745
- while (n) {
1927
+ for (let n = node; n; n = composedParent(n)) {
1746
1928
  if (n === container) return true;
1747
- const slot = n.assignedSlot;
1748
- if (slot) {
1749
- n = slot;
1750
- continue;
1751
- }
1752
- const parent = n.parentNode;
1753
- n = parent instanceof ShadowRoot ? parent.host : parent;
1754
1929
  }
1755
1930
  return false;
1756
1931
  };
1757
- trapStack = [];
1932
+ isAllowedOutside = (node) => {
1933
+ for (let n = node; n; n = composedParent(n)) {
1934
+ if (n instanceof Element && n.hasAttribute(FOCUS_ALLOW_ATTR)) return true;
1935
+ }
1936
+ return false;
1937
+ };
1938
+ deepActiveElement = () => {
1939
+ let active = document.activeElement;
1940
+ while (active?.shadowRoot?.activeElement) {
1941
+ active = active.shadowRoot.activeElement;
1942
+ }
1943
+ return active;
1944
+ };
1945
+ trapStack = shared("focusTraps", () => []);
1758
1946
  installFocusTrap = (container, options = {}) => {
1759
1947
  if (typeof document === "undefined") return () => {
1760
1948
  };
1761
1949
  const token = {};
1762
- trapStack.push(token);
1763
- const isActive = () => trapStack[trapStack.length - 1] === token;
1950
+ if (!options.isActive) trapStack.push(token);
1951
+ const isActive = options.isActive ?? (() => trapStack[trapStack.length - 1] === token);
1764
1952
  const previouslyFocused = document.activeElement;
1765
1953
  const focusInitial = () => {
1766
1954
  const spec = options.initialFocus;
@@ -1769,10 +1957,11 @@ var init_focus_trap = __esm({
1769
1957
  container.focus({ preventScroll: true });
1770
1958
  return;
1771
1959
  }
1772
- const initial = typeof spec === "string" ? container.querySelector(spec) : spec ?? focusables(container)[0] ?? container;
1960
+ const initial = typeof spec === "string" ? findDeep(container, spec) : spec ?? focusables(container)[0] ?? container;
1773
1961
  initial?.focus({ preventScroll: true });
1774
1962
  };
1775
- focusInitial();
1963
+ if (!containsComposed(container, deepActiveElement())) focusInitial();
1964
+ let backwards = false;
1776
1965
  const handleKey = (e) => {
1777
1966
  if (!isActive()) return;
1778
1967
  if (e.key === "Escape" && options.onEscape) {
@@ -1780,6 +1969,10 @@ var init_focus_trap = __esm({
1780
1969
  return;
1781
1970
  }
1782
1971
  if (e.key !== "Tab") return;
1972
+ backwards = e.shiftKey;
1973
+ setTimeout(() => {
1974
+ backwards = false;
1975
+ }, 0);
1783
1976
  const list = focusables(container);
1784
1977
  if (list.length === 0) {
1785
1978
  e.preventDefault();
@@ -1787,7 +1980,7 @@ var init_focus_trap = __esm({
1787
1980
  }
1788
1981
  const first = list[0];
1789
1982
  const last = list[list.length - 1];
1790
- const active = document.activeElement;
1983
+ const active = deepActiveElement();
1791
1984
  if (e.shiftKey && active === first) {
1792
1985
  e.preventDefault();
1793
1986
  last.focus();
@@ -1798,11 +1991,11 @@ var init_focus_trap = __esm({
1798
1991
  };
1799
1992
  const handleFocusIn = (e) => {
1800
1993
  if (!isActive()) return;
1801
- const target = e.target;
1802
- if (target && !containsComposed(container, target)) {
1803
- const list = focusables(container);
1804
- list[0]?.focus({ preventScroll: true });
1805
- }
1994
+ const target = e.composedPath()[0] ?? e.target;
1995
+ if (!target || containsComposed(container, target)) return;
1996
+ if (isAllowedOutside(target)) return;
1997
+ const list = focusables(container);
1998
+ list[backwards ? list.length - 1 : 0]?.focus({ preventScroll: true });
1806
1999
  };
1807
2000
  document.addEventListener("keydown", handleKey, true);
1808
2001
  document.addEventListener("focusin", handleFocusIn, true);
@@ -1826,24 +2019,29 @@ var init_focus_trap = __esm({
1826
2019
  });
1827
2020
 
1828
2021
  // src/core/lifecycle/scroll-lock.ts
1829
- var lockCount, savedStyles, lockBodyScroll;
2022
+ var state, lockBodyScroll;
1830
2023
  var init_scroll_lock = __esm({
1831
2024
  "src/core/lifecycle/scroll-lock.ts"() {
1832
- lockCount = 0;
1833
- savedStyles = null;
2025
+ init_shared();
2026
+ state = shared("scrollLock", () => ({
2027
+ count: 0,
2028
+ saved: null
2029
+ }));
1834
2030
  lockBodyScroll = () => {
1835
2031
  if (typeof document === "undefined") return () => {
1836
2032
  };
1837
- if (lockCount === 0) {
2033
+ if (state.count === 0) {
1838
2034
  const body = document.body;
1839
- savedStyles = {
2035
+ const saved = {
1840
2036
  overflow: body.style.overflow,
1841
2037
  position: body.style.position,
1842
2038
  top: body.style.top,
1843
2039
  width: body.style.width,
1844
2040
  paddingRight: body.style.paddingRight,
2041
+ scrollX: window.scrollX,
1845
2042
  scrollY: window.scrollY
1846
2043
  };
2044
+ state.saved = saved;
1847
2045
  const scrollbarGap = window.innerWidth - document.documentElement.clientWidth;
1848
2046
  if (scrollbarGap > 0) {
1849
2047
  const current = parseFloat(getComputedStyle(body).paddingRight) || 0;
@@ -1851,24 +2049,29 @@ var init_scroll_lock = __esm({
1851
2049
  }
1852
2050
  body.style.overflow = "hidden";
1853
2051
  body.style.position = "fixed";
1854
- body.style.top = `-${savedStyles.scrollY}px`;
2052
+ body.style.top = `-${saved.scrollY}px`;
1855
2053
  body.style.width = "100%";
1856
2054
  }
1857
- lockCount++;
2055
+ state.count++;
1858
2056
  let released = false;
1859
2057
  return () => {
1860
2058
  if (released) return;
1861
2059
  released = true;
1862
- lockCount = Math.max(0, lockCount - 1);
1863
- if (lockCount === 0 && savedStyles) {
2060
+ state.count = Math.max(0, state.count - 1);
2061
+ if (state.count === 0 && state.saved) {
1864
2062
  const body = document.body;
1865
- body.style.overflow = savedStyles.overflow;
1866
- body.style.position = savedStyles.position;
1867
- body.style.top = savedStyles.top;
1868
- body.style.width = savedStyles.width;
1869
- body.style.paddingRight = savedStyles.paddingRight;
1870
- window.scrollTo(0, savedStyles.scrollY);
1871
- savedStyles = null;
2063
+ const saved = state.saved;
2064
+ body.style.overflow = saved.overflow;
2065
+ body.style.position = saved.position;
2066
+ body.style.top = saved.top;
2067
+ body.style.width = saved.width;
2068
+ body.style.paddingRight = saved.paddingRight;
2069
+ window.scrollTo({
2070
+ top: saved.scrollY,
2071
+ left: saved.scrollX,
2072
+ behavior: "instant"
2073
+ });
2074
+ state.saved = null;
1872
2075
  }
1873
2076
  };
1874
2077
  };
@@ -1878,32 +2081,47 @@ var init_scroll_lock = __esm({
1878
2081
  // src/core/features/inert-siblings.ts
1879
2082
  function createInertSiblings(rootProvider) {
1880
2083
  const tracked = [];
2084
+ const remove = () => {
2085
+ for (const el of tracked) el.removeAttribute("inert");
2086
+ tracked.length = 0;
2087
+ };
1881
2088
  return {
1882
2089
  apply() {
1883
2090
  if (typeof document === "undefined") return;
1884
- let top = rootProvider();
1885
- while (top.parentElement && top.parentElement !== document.body) {
1886
- top = top.parentElement;
1887
- }
1888
- const parent = top.parentElement ?? document.body;
1889
- for (const child of Array.from(parent.children)) {
1890
- if (child === top) continue;
1891
- if (child.hasAttribute("inert")) continue;
1892
- if (child.classList.contains("bs-backdrop") || child.classList.contains("bs-screen") || child.classList.contains("bs-root")) {
2091
+ remove();
2092
+ const surface = rootProvider();
2093
+ let node = surface.closest(OWN_ROOTS) ?? surface;
2094
+ while (node && node !== document.body) {
2095
+ const parent = node.parentElement;
2096
+ if (!parent) {
2097
+ const root = node.getRootNode();
2098
+ node = typeof ShadowRoot !== "undefined" && root instanceof ShadowRoot ? root.host : null;
1893
2099
  continue;
1894
2100
  }
1895
- child.setAttribute("inert", "");
1896
- tracked.push(child);
2101
+ for (const sibling of Array.from(parent.children)) {
2102
+ if (sibling === node) continue;
2103
+ if (sibling.hasAttribute("inert") || isLayer(sibling)) continue;
2104
+ sibling.setAttribute("inert", "");
2105
+ tracked.push(sibling);
2106
+ }
2107
+ node = parent;
1897
2108
  }
1898
2109
  },
1899
- remove() {
1900
- for (const el of tracked) el.removeAttribute("inert");
1901
- tracked.length = 0;
1902
- }
2110
+ remove
1903
2111
  };
1904
2112
  }
2113
+ var OWN_ROOTS, LAYER_CLASSES, isLayer;
1905
2114
  var init_inert_siblings = __esm({
1906
2115
  "src/core/features/inert-siblings.ts"() {
2116
+ OWN_ROOTS = ".bs-root, .ovl-root";
2117
+ LAYER_CLASSES = [
2118
+ "bs-backdrop",
2119
+ "bs-screen",
2120
+ "bs-root",
2121
+ "ovl-backdrop",
2122
+ "ovl-root"
2123
+ ];
2124
+ isLayer = (el) => LAYER_CLASSES.some((name) => el.classList.contains(name));
1907
2125
  }
1908
2126
  });
1909
2127
 
@@ -1917,6 +2135,7 @@ var init_lifecycle_controller = __esm({
1917
2135
  LifecycleController = class {
1918
2136
  constructor(deps, opts) {
1919
2137
  __publicField(this, "element");
2138
+ __publicField(this, "isTop");
1920
2139
  __publicField(this, "focusTrapEnabled");
1921
2140
  __publicField(this, "initialFocus");
1922
2141
  __publicField(this, "closeOnEscape");
@@ -1930,6 +2149,7 @@ var init_lifecycle_controller = __esm({
1930
2149
  __publicField(this, "installed", false);
1931
2150
  __publicField(this, "destroyed", false);
1932
2151
  this.element = deps.element;
2152
+ this.isTop = deps.isTop;
1933
2153
  this.focusTrapEnabled = opts.focusTrap ?? false;
1934
2154
  this.initialFocus = opts.initialFocus;
1935
2155
  this.closeOnEscape = opts.closeOnEscape ?? true;
@@ -1950,12 +2170,17 @@ var init_lifecycle_controller = __esm({
1950
2170
  }
1951
2171
  if (this.focusTrapEnabled && !this.releaseFocusTrap) {
1952
2172
  this.releaseFocusTrap = installFocusTrap(this.element, {
1953
- initialFocus: this.initialFocus
2173
+ initialFocus: this.initialFocus,
2174
+ isActive: this.isTop
1954
2175
  });
1955
2176
  }
1956
- if (this.inertSiblingsEnabled && this.shouldApplyInertSiblings()) {
1957
- this.inertSiblings.apply();
1958
- }
2177
+ this.syncTop();
2178
+ }
2179
+ syncTop() {
2180
+ if (!this.installed || !this.inertSiblingsEnabled) return;
2181
+ if (!this.shouldApplyInertSiblings()) return;
2182
+ if (this.isTop?.() ?? true) this.inertSiblings.apply();
2183
+ else this.inertSiblings.remove();
1959
2184
  }
1960
2185
  setReturnFocus(target) {
1961
2186
  if (this.destroyed) return;
@@ -2130,10 +2355,14 @@ var init_gestures = __esm({
2130
2355
  if (wasPending) return;
2131
2356
  callbacks.onCancel?.();
2132
2357
  };
2358
+ const onLostCapture = (e) => {
2359
+ if (e.target === handle) onPointerCancel(e);
2360
+ };
2133
2361
  handle.addEventListener("pointerdown", onPointerDown);
2134
2362
  handle.addEventListener("pointermove", onPointerMove);
2135
2363
  handle.addEventListener("pointerup", finishGesture);
2136
2364
  handle.addEventListener("pointercancel", onPointerCancel);
2365
+ handle.addEventListener("lostpointercapture", onLostCapture);
2137
2366
  const managesTouchAction = options.manageTouchAction !== false;
2138
2367
  const prevTouchAction = handle.style.touchAction;
2139
2368
  if (managesTouchAction) {
@@ -2144,6 +2373,7 @@ var init_gestures = __esm({
2144
2373
  handle.removeEventListener("pointermove", onPointerMove);
2145
2374
  handle.removeEventListener("pointerup", finishGesture);
2146
2375
  handle.removeEventListener("pointercancel", onPointerCancel);
2376
+ handle.removeEventListener("lostpointercapture", onLostCapture);
2147
2377
  if (managesTouchAction) handle.style.touchAction = prevTouchAction;
2148
2378
  if (activePointerId !== null && handle.hasPointerCapture(activePointerId)) {
2149
2379
  handle.releasePointerCapture(activePointerId);
@@ -2276,8 +2506,7 @@ var init_gesture_controller = __esm({
2276
2506
  size: this.deps.getDragContext().size,
2277
2507
  velocity: 0
2278
2508
  });
2279
- const restoreTo = this.dragStartSize;
2280
- void this.deps.animateTo(restoreTo, 0);
2509
+ this.deps.restoreAfterDrag();
2281
2510
  }
2282
2511
  }, this.deps.gestureOptions);
2283
2512
  return this.detach;
@@ -2336,7 +2565,7 @@ var init_content_gesture = __esm({
2336
2565
  });
2337
2566
 
2338
2567
  // src/core/primitives/logical-mode.ts
2339
- var isLogicalMode, readDirection, resolveMode;
2568
+ var isLogicalMode, readDirection, guessPhysicalMode, resolveMode;
2340
2569
  var init_logical_mode = __esm({
2341
2570
  "src/core/primitives/logical-mode.ts"() {
2342
2571
  isLogicalMode = (mode) => mode === "start" || mode === "end";
@@ -2357,6 +2586,11 @@ var init_logical_mode = __esm({
2357
2586
  }
2358
2587
  return "ltr";
2359
2588
  };
2589
+ guessPhysicalMode = (mode) => {
2590
+ if (mode === "start") return "left";
2591
+ if (mode === "end") return "right";
2592
+ return mode ?? "bottom";
2593
+ };
2360
2594
  resolveMode = (mode, el) => {
2361
2595
  if (!isLogicalMode(mode)) return mode;
2362
2596
  const rtl = readDirection(el) === "rtl";
@@ -2420,22 +2654,24 @@ function createScrollCache(deps) {
2420
2654
  return size < max / 2;
2421
2655
  };
2422
2656
  return {
2423
- cache(fromId, prevSize, nextSize) {
2657
+ leave(fromId, prevSize, nextSize) {
2424
2658
  const container = deps.scrollContainer;
2425
2659
  if (!container) return;
2426
- if (isSmallSize(prevSize)) return;
2427
- if (!isSmallSize(nextSize)) return;
2660
+ if (nextSize <= 0) {
2661
+ positions.clear();
2662
+ return;
2663
+ }
2664
+ if (isSmallSize(prevSize) || !isSmallSize(nextSize)) return;
2428
2665
  positions.set(fromId, container.scrollTop);
2429
2666
  },
2430
- restore(toId, prevSize, nextSize) {
2667
+ enter(toId, prevSize, nextSize) {
2431
2668
  const container = deps.scrollContainer;
2432
2669
  if (!container) return;
2433
- if (isSmallSize(nextSize)) return;
2434
- if (!isSmallSize(prevSize)) return;
2670
+ if (isSmallSize(nextSize) || !isSmallSize(prevSize)) return;
2435
2671
  const cached = positions.get(toId);
2436
2672
  if (cached === void 0) return;
2437
- container.scrollTop = cached;
2438
2673
  positions.delete(toId);
2674
+ container.scrollTop = cached;
2439
2675
  },
2440
2676
  clear() {
2441
2677
  positions.clear();
@@ -2559,17 +2795,18 @@ function attachAnchor(deps, opts) {
2559
2795
  const isDock = position === "dock-bottom" || position === "dock-top";
2560
2796
  const ws = wrapper.style;
2561
2797
  ws.position = "fixed";
2562
- if (isDock) {
2798
+ const place = () => {
2799
+ resetOverlayPosition(ws);
2800
+ if (!isDock) {
2801
+ applyOverlayPosition(ws, deps.getMode(), position, opts.inset ?? "16px");
2802
+ return;
2803
+ }
2563
2804
  ws.left = "0";
2564
2805
  ws.right = "0";
2565
- if (position === "dock-bottom") {
2566
- ws.bottom = "0";
2567
- } else {
2568
- ws.top = "0";
2569
- }
2570
- } else {
2571
- applyOverlayPosition(ws, deps.mode, position, opts.inset ?? "16px");
2572
- }
2806
+ if (position === "dock-bottom") ws.bottom = "0";
2807
+ else ws.top = "0";
2808
+ };
2809
+ place();
2573
2810
  if (opts.fadeRange) {
2574
2811
  const [r0, r1] = opts.fadeRange;
2575
2812
  const span = Math.max(r1 - r0, 1e-4);
@@ -2579,10 +2816,10 @@ function attachAnchor(deps, opts) {
2579
2816
  deps.host.appendChild(wrapper);
2580
2817
  let visible = null;
2581
2818
  let inFlight = null;
2582
- const shouldShow = (state) => {
2583
- if (typeof opts.showOn === "function") return opts.showOn(state);
2584
- if (Array.isArray(opts.showOn)) return opts.showOn.includes(state.activeId);
2585
- return isDock || state.size > 0;
2819
+ const shouldShow = (state3) => {
2820
+ if (typeof opts.showOn === "function") return opts.showOn(state3);
2821
+ if (Array.isArray(opts.showOn)) return opts.showOn.includes(state3.activeId);
2822
+ return isDock || state3.size > 0;
2586
2823
  };
2587
2824
  const applyVisibility = (next, animate) => {
2588
2825
  if (next === visible) return;
@@ -2629,7 +2866,8 @@ function attachAnchor(deps, opts) {
2629
2866
  },
2630
2867
  syncZ: (z) => {
2631
2868
  wrapper.style.zIndex = String(z);
2632
- }
2869
+ },
2870
+ reposition: place
2633
2871
  };
2634
2872
  }
2635
2873
  var init_sheet_anchors = __esm({
@@ -2642,30 +2880,37 @@ var init_sheet_anchors = __esm({
2642
2880
  // src/core/features/scrim-stages.ts
2643
2881
  function installScrimStages(deps, opts) {
2644
2882
  const doc = deps.host.ownerDocument;
2645
- const entries2 = opts.stages.map((def) => {
2883
+ const entries = opts.stages.map((def) => {
2646
2884
  const wrapper = doc.createElement("div");
2647
2885
  wrapper.className = "bs-scrim-stage";
2648
2886
  const ws = wrapper.style;
2649
- ws.position = "absolute";
2650
- applyOverlayPosition(
2651
- ws,
2652
- deps.mode,
2653
- def.position ?? opts.position ?? "center",
2654
- def.inset ?? opts.inset ?? "16px"
2655
- );
2887
+ ws.position = "fixed";
2656
2888
  ws.visibility = "hidden";
2657
2889
  ws.pointerEvents = "none";
2658
2890
  wrapper.appendChild(def.element);
2659
2891
  deps.host.appendChild(wrapper);
2660
2892
  return { def, wrapper, inFlight: null };
2661
2893
  });
2894
+ const place = () => {
2895
+ for (const entry of entries) {
2896
+ const ws = entry.wrapper.style;
2897
+ resetOverlayPosition(ws);
2898
+ applyOverlayPosition(
2899
+ ws,
2900
+ deps.getMode(),
2901
+ entry.def.position ?? opts.position ?? "center",
2902
+ entry.def.inset ?? opts.inset ?? "16px"
2903
+ );
2904
+ }
2905
+ };
2906
+ place();
2662
2907
  let active = null;
2663
2908
  const resolveActive = () => {
2664
- const state = deps.getState();
2665
- if (state.size === 0) {
2666
- return entries2.find((e) => matchesId(e.def, state.activeId)) ?? null;
2909
+ const state3 = deps.getState();
2910
+ if (state3.size === 0) {
2911
+ return entries.find((e) => matchesId(e.def, state3.activeId)) ?? null;
2667
2912
  }
2668
- return entries2.find((e) => matchesId(e.def, state.activeId)) ?? entries2.find((e) => matchesRange(e.def, state.progress)) ?? null;
2913
+ return entries.find((e) => matchesId(e.def, state3.activeId)) ?? entries.find((e) => matchesRange(e.def, state3.progress)) ?? null;
2669
2914
  };
2670
2915
  const hide = (entry, animate) => {
2671
2916
  entry.inFlight?.cancel();
@@ -2714,20 +2959,23 @@ function installScrimStages(deps, opts) {
2714
2959
  deps.on("open", () => update(true)),
2715
2960
  deps.on("close", () => update(true))
2716
2961
  ];
2717
- if (entries2.some((e) => e.def.forRange)) {
2962
+ if (entries.some((e) => e.def.forRange)) {
2718
2963
  offs.push(deps.on("progress", () => update(true)));
2719
2964
  }
2720
2965
  update(false);
2721
- return () => {
2722
- offs.forEach((off) => off());
2723
- for (const entry of entries2) {
2724
- entry.inFlight?.cancel();
2725
- entry.inFlight = null;
2726
- if (entry.wrapper.parentNode) {
2727
- entry.wrapper.parentNode.removeChild(entry.wrapper);
2966
+ return {
2967
+ reposition: place,
2968
+ detach: () => {
2969
+ offs.forEach((off) => off());
2970
+ for (const entry of entries) {
2971
+ entry.inFlight?.cancel();
2972
+ entry.inFlight = null;
2973
+ if (entry.wrapper.parentNode) {
2974
+ entry.wrapper.parentNode.removeChild(entry.wrapper);
2975
+ }
2728
2976
  }
2977
+ active = null;
2729
2978
  }
2730
- active = null;
2731
2979
  };
2732
2980
  }
2733
2981
  var matchesId, matchesRange;
@@ -2777,11 +3025,13 @@ function resolveEngineOptions(opts, extras) {
2777
3025
  scrimMode: opts.scrimMode,
2778
3026
  scrimColor: opts.scrimColor,
2779
3027
  scrimBlur: opts.scrimBlur,
2780
- scrimInteractive: opts.scrimInteractive ?? (opts.scrimTapToClose ? true : void 0),
3028
+ scrimInteractive: opts.scrimInteractive,
2781
3029
  scrimTapToClose: opts.scrimTapToClose,
2782
3030
  scrimPreset: opts.scrimPreset,
2783
3031
  screenRange: opts.screenRange,
2784
- backdropRange: opts.backdropRange
3032
+ backdropRange: opts.backdropRange,
3033
+ backdropOpacity: opts.backdropOpacity,
3034
+ backdropColor: opts.backdropColor
2785
3035
  },
2786
3036
  animation: {
2787
3037
  animation: opts.animation,
@@ -2862,6 +3112,7 @@ var init_BottomSheetCore = __esm({
2862
3112
  init_linked_sheets();
2863
3113
  init_resize_observer();
2864
3114
  init_fit_observer();
3115
+ init_teleport();
2865
3116
  init_max_height_controller();
2866
3117
  init_fit_measurement();
2867
3118
  init_slider_keyboard();
@@ -2906,6 +3157,7 @@ var init_BottomSheetCore = __esm({
2906
3157
  __publicField(this, "fitContentToSnap");
2907
3158
  __publicField(this, "settleAnimation");
2908
3159
  __publicField(this, "persistent");
3160
+ __publicField(this, "keyboardInset", 0);
2909
3161
  __publicField(this, "disableCloseFlag");
2910
3162
  __publicField(this, "disableDragFlag");
2911
3163
  __publicField(this, "closeOnRouteChange");
@@ -2920,6 +3172,7 @@ var init_BottomSheetCore = __esm({
2920
3172
  __publicField(this, "detachSheetGesture", null);
2921
3173
  __publicField(this, "detachSliderKeyboard", null);
2922
3174
  __publicField(this, "rootEl", null);
3175
+ __publicField(this, "homeRoot", null);
2923
3176
  __publicField(this, "destroyed", false);
2924
3177
  __publicField(this, "restClosed", false);
2925
3178
  __publicField(this, "currentViewTransition", null);
@@ -2927,8 +3180,13 @@ var init_BottomSheetCore = __esm({
2927
3180
  __publicField(this, "sizeWriteSentinel", new WriteSentinel());
2928
3181
  __publicField(this, "progressWriteSentinel", new WriteSentinel());
2929
3182
  __publicField(this, "isTopSheet", true);
2930
- __publicField(this, "opening", false);
2931
- __publicField(this, "promotedForOpen", false);
3183
+ __publicField(this, "phase", "closed");
3184
+ __publicField(this, "transition", null);
3185
+ __publicField(this, "inFlight", null);
3186
+ __publicField(this, "outbox", []);
3187
+ __publicField(this, "flushing", false);
3188
+ __publicField(this, "openPending", false);
3189
+ __publicField(this, "settleHolds", []);
2932
3190
  __publicField(this, "allowOvershoot", false);
2933
3191
  __publicField(this, "progressPayload", {
2934
3192
  value: 0,
@@ -2949,6 +3207,7 @@ var init_BottomSheetCore = __esm({
2949
3207
  __publicField(this, "anchorHost", null);
2950
3208
  __publicField(this, "stackZ", 100);
2951
3209
  __publicField(this, "detachScrimStages", null);
3210
+ __publicField(this, "placeScrimStages", null);
2952
3211
  __publicField(this, "stackEffectEnabled", false);
2953
3212
  __publicField(this, "stackEffectPrimed", false);
2954
3213
  __publicField(this, "fitDeps");
@@ -2956,13 +3215,7 @@ var init_BottomSheetCore = __esm({
2956
3215
  __publicField(this, "featureList", []);
2957
3216
  __publicField(this, "featureCtx");
2958
3217
  const resolved = resolveEngineOptions(opts, {
2959
- shouldApplyInertSiblings: () => {
2960
- if (typeof document === "undefined") return false;
2961
- const bodyChildren = Array.from(document.body.children);
2962
- return bodyChildren.some(
2963
- (c) => c === opts.element || c.contains(opts.element)
2964
- );
2965
- }
3218
+ shouldApplyInertSiblings: () => opts.element.isConnected
2966
3219
  });
2967
3220
  this.element = opts.element;
2968
3221
  this.handle = opts.handle ?? opts.element;
@@ -2991,7 +3244,6 @@ var init_BottomSheetCore = __esm({
2991
3244
  void this.snapTo(id);
2992
3245
  },
2993
3246
  close: () => {
2994
- if (!this.canDismiss()) return;
2995
3247
  void this.close("backdrop");
2996
3248
  }
2997
3249
  },
@@ -3021,7 +3273,8 @@ var init_BottomSheetCore = __esm({
3021
3273
  this.lifecycle = new LifecycleController(
3022
3274
  {
3023
3275
  element: this.element,
3024
- close: () => this.close()
3276
+ close: () => this.close(),
3277
+ isTop: () => this.isTopSheet
3025
3278
  },
3026
3279
  resolved.lifecycle
3027
3280
  );
@@ -3048,6 +3301,7 @@ var init_BottomSheetCore = __esm({
3048
3301
  auditVhUsage(this.snapPointsRaw);
3049
3302
  this.auditDuplicateSnapIds(this.snapPointsRaw);
3050
3303
  this.rootEl = this.element.closest(".bs-root");
3304
+ this.homeRoot = homeRootOf(this.rootEl);
3051
3305
  this.maxHeightDeps = {
3052
3306
  element: this.element,
3053
3307
  mode: this.mode,
@@ -3075,7 +3329,9 @@ var init_BottomSheetCore = __esm({
3075
3329
  );
3076
3330
  const initial = this.snaps.findById(this.activeId);
3077
3331
  if (initial) this.size = initial.size;
3332
+ this.phase = this.size > 0 ? "open" : "closed";
3078
3333
  this.applySize(this.size);
3334
+ this.restClosed = this.element.getAttribute("data-bs-rest") === "closed";
3079
3335
  this.setRestClosed(this.size === 0);
3080
3336
  this.updateAriaSlider();
3081
3337
  this.scrollCache = createScrollCache({
@@ -3086,12 +3342,11 @@ var init_BottomSheetCore = __esm({
3086
3342
  this.attach();
3087
3343
  this.registerInStack();
3088
3344
  if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
3089
- const io = new IntersectionObserver((entries2) => {
3090
- for (const entry of entries2) {
3345
+ const io = new IntersectionObserver((entries) => {
3346
+ for (const entry of entries) {
3091
3347
  if (!entry.isIntersecting) continue;
3092
3348
  if (this.destroyed) return;
3093
- this.snaps.recompute();
3094
- this.healActiveSnap();
3349
+ this.recompute();
3095
3350
  io.disconnect();
3096
3351
  return;
3097
3352
  }
@@ -3101,6 +3356,7 @@ var init_BottomSheetCore = __esm({
3101
3356
  }
3102
3357
  this.teardowns.add(
3103
3358
  installFitObserver({
3359
+ element: this.element,
3104
3360
  handle: this.handle,
3105
3361
  scrollContainer: this.scrollContainer,
3106
3362
  hasFitSnap: () => this.snapPointsRaw.some(
@@ -3116,9 +3372,7 @@ var init_BottomSheetCore = __esm({
3116
3372
  this.applyAutoAriaLabelledBy();
3117
3373
  this.runFeatureStage("post");
3118
3374
  this.warnOrphanFeatureOptions();
3119
- if (this.size > 0) {
3120
- this.handleOpen();
3121
- }
3375
+ if (this.phase === "open") this.installLifecycle(true);
3122
3376
  }
3123
3377
  buildFeatureContext(autoCollapseAfter) {
3124
3378
  return {
@@ -3146,21 +3400,27 @@ var init_BottomSheetCore = __esm({
3146
3400
  getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
3147
3401
  resolveSnap: (id) => this.snaps.findById(id),
3148
3402
  resolveActiveSnap: () => this.snaps.findById(this.activeId),
3403
+ getPhase: () => this.phase,
3149
3404
  setSize: (size) => {
3150
3405
  this.size = size;
3151
3406
  },
3152
3407
  setMaxAxisSize: (size) => {
3153
3408
  this.snaps.setMaxAxisSize(size);
3154
3409
  },
3410
+ setKeyboardInset: (px) => this.setKeyboardInset(px),
3155
3411
  applySize: (size) => this.applySize(size),
3156
3412
  recomputeSnaps: () => this.recomputeSnaps(),
3413
+ reseat: () => this.reseat(),
3414
+ holdSettle: (settled) => {
3415
+ this.settleHolds.push(settled);
3416
+ },
3157
3417
  newCycle: () => {
3158
3418
  this.newCycle();
3159
3419
  },
3160
- cancelInFlight: () => {
3161
- this.animation.cancel();
3420
+ cancelInFlight: () => this.suspend(),
3421
+ resyncAfterResize: () => {
3422
+ if (!this.destroyed) this.land(false);
3162
3423
  },
3163
- resyncAfterResize: () => this.resyncAfterResize(),
3164
3424
  snapTo: (id) => {
3165
3425
  void this.snapTo(id);
3166
3426
  },
@@ -3199,8 +3459,9 @@ var init_BottomSheetCore = __esm({
3199
3459
  return {
3200
3460
  size: this.size,
3201
3461
  activeId: this.activeId,
3462
+ phase: this.phase,
3202
3463
  isDragging: this.isDraggingAny(),
3203
- isAnimating: this.animation.isAnimating,
3464
+ isAnimating: this.animation.isAnimating || this.currentViewTransition !== null,
3204
3465
  progress: this.computeProgress(this.size)
3205
3466
  };
3206
3467
  }
@@ -3254,49 +3515,53 @@ var init_BottomSheetCore = __esm({
3254
3515
  getResolvedSnaps() {
3255
3516
  return this.snaps.getResolvedSnaps();
3256
3517
  }
3257
- async snapTo(id, velocityOrOpts = 0, _skipBeforeSnap = false) {
3258
- if (this.destroyed) return;
3518
+ snapTo(id, velocityOrOpts = 0, _skipBeforeSnap = false) {
3259
3519
  const opts = typeof velocityOrOpts === "object" ? velocityOrOpts : { velocity: velocityOrOpts };
3260
- const velocityPxPerMs = opts.velocity ?? 0;
3261
- const externalSignal = opts.signal;
3262
- if (externalSignal?.aborted) return;
3520
+ return this.transitionTo(
3521
+ id,
3522
+ opts.velocity ?? 0,
3523
+ _skipBeforeSnap,
3524
+ opts.signal
3525
+ );
3526
+ }
3527
+ transitionTo(id, velocityPxPerMs = 0, skipBeforeSnap = false, externalSignal) {
3528
+ if (this.destroyed || externalSignal?.aborted) return Promise.resolve();
3263
3529
  const target = this.snaps.findById(id);
3264
3530
  if (!target) {
3265
3531
  devWarn(`[BottomSheet] unknown snap id: ${id}`);
3266
- return;
3532
+ return Promise.resolve();
3267
3533
  }
3268
3534
  if (!this.snaps.getAllowedIds().includes(id)) {
3269
3535
  devWarn(`[BottomSheet] snap "${id}" is not in allowed list`);
3270
- return;
3536
+ return Promise.resolve();
3271
3537
  }
3272
- if (!_skipBeforeSnap && this.emitBeforeSnap(target, this.activeId)) {
3273
- return;
3538
+ if (target.size === 0 && this.closingBlocked()) return Promise.resolve();
3539
+ if (!externalSignal && this.inFlight?.id === id) return this.inFlight.done;
3540
+ if (!skipBeforeSnap && this.emitBeforeSnap(target, this.activeId)) {
3541
+ return Promise.resolve();
3274
3542
  }
3275
- const resumingOpen = this.opening;
3276
- const signal = this.newCycle();
3277
- const onExternalAbort = () => {
3278
- this.animation.cancel();
3279
- this.newCycle();
3280
- };
3543
+ const flight = { id, done: Promise.resolve() };
3544
+ flight.done = this.runTransition(
3545
+ target,
3546
+ velocityPxPerMs,
3547
+ false,
3548
+ externalSignal,
3549
+ flight
3550
+ );
3551
+ return flight.done;
3552
+ }
3553
+ async runTransition(target, velocityPxPerMs, fromDrag, externalSignal, flight = null) {
3554
+ const signal = this.beginTransition(target);
3555
+ const transition = this.transition;
3556
+ if (signal.aborted || !transition) return;
3557
+ this.inFlight = flight;
3558
+ const onExternalAbort = () => this.suspend();
3281
3559
  externalSignal?.addEventListener("abort", onExternalAbort, { once: true });
3282
- const wasClosed = this.size === 0 || resumingOpen;
3283
- const previousId = this.activeId;
3284
- const previousSize = this.size;
3285
- this.scrollCache.cache(previousId, previousSize, target.size);
3286
- this.activeId = id;
3287
- const rawTargetSize = this.snapPointsRaw.find((p) => p.id === id)?.size;
3288
- const opensToRest = id === "closed" || rawTargetSize === 0;
3289
- if (wasClosed && !opensToRest) {
3290
- this.opening = true;
3291
- if (!resumingOpen) {
3292
- this.promotedForOpen = true;
3293
- sheetStack.promote(this.id);
3294
- }
3295
- }
3296
- if (this.animation.viewTransitionsAvailable) {
3560
+ this.allowOvershoot = fromDrag;
3561
+ if (!fromDrag && this.animation.viewTransitionsAvailable) {
3297
3562
  this.currentViewTransition?.skipTransition?.();
3298
3563
  const vt = document.startViewTransition(() => {
3299
- this.applySize(target.size);
3564
+ if (!signal.aborted) this.applySize(transition.size);
3300
3565
  });
3301
3566
  vt.ready?.catch(() => {
3302
3567
  });
@@ -3307,25 +3572,202 @@ var init_BottomSheetCore = __esm({
3307
3572
  }
3308
3573
  if (this.currentViewTransition === vt) this.currentViewTransition = null;
3309
3574
  } else {
3310
- await this.animation.animateTo(target.size, velocityPxPerMs);
3575
+ await this.animation.animateTo(transition.size, velocityPxPerMs);
3311
3576
  }
3312
3577
  externalSignal?.removeEventListener("abort", onExternalAbort);
3313
3578
  if (signal.aborted) return;
3314
- this.opening = false;
3315
- this.completeSnap(id, target.size, previousSize, wasClosed, false);
3579
+ if (this.size !== transition.size) this.applySize(transition.size);
3580
+ this.land(fromDrag);
3581
+ if (this.settleHolds.length > 0) {
3582
+ await Promise.allSettled(this.settleHolds.splice(0));
3583
+ }
3316
3584
  }
3317
- completeSnap(id, targetSize, previousSize, wasClosed, withHaptic) {
3318
- this.scrollCache.restore(id, previousSize, targetSize);
3585
+ beginTransition(target) {
3586
+ const signal = this.newCycle();
3587
+ const cap = this.snaps.getMaxAxisSize();
3588
+ const fromId = this.activeId;
3589
+ const fromSize = this.snaps.findById(fromId)?.size ?? this.size;
3590
+ this.scrollCache.leave(fromId, fromSize, target.size);
3591
+ this.scrollCache.enter(target.id, fromSize, target.size);
3592
+ this.activeId = target.id;
3593
+ this.transition = {
3594
+ size: cap > 0 ? Math.min(target.size, cap) : target.size,
3595
+ cap
3596
+ };
3597
+ if (target.size > 0) {
3598
+ this.enterOpening(target.id);
3599
+ } else {
3600
+ if (this.phase === "closed" && !this.isClosedSnap(target.id)) {
3601
+ sheetStack.promote(this.id);
3602
+ }
3603
+ this.enterClosing();
3604
+ }
3605
+ this.flush();
3606
+ return signal;
3607
+ }
3608
+ enterOpening(id) {
3609
+ if (this.phase === "open" || this.phase === "opening") return;
3610
+ const fresh = this.phase === "closed";
3611
+ this.phase = "opening";
3612
+ this.setRestClosed(false);
3613
+ if (!this.installLifecycle(fresh)) return;
3614
+ this.post("open", { id });
3615
+ this.outbox.push(() => {
3616
+ if (this.phase !== "closed") {
3617
+ notifyLinkedSheets(this.linkedSheets, this);
3618
+ }
3619
+ });
3620
+ }
3621
+ enterClosing() {
3622
+ if (this.phase === "closed" || this.phase === "closing") return;
3623
+ this.phase = "closing";
3624
+ this.post("close", void 0);
3625
+ }
3626
+ settlePhase(heal) {
3627
+ if (this.size > 0) {
3628
+ this.enterOpening(this.activeId);
3629
+ if (this.phase === "opening") {
3630
+ this.phase = "open";
3631
+ this.post("opened", { id: this.activeId });
3632
+ }
3633
+ return;
3634
+ }
3635
+ if (heal && this.phase !== "closing") return;
3636
+ this.enterClosing();
3637
+ if (this.phase === "closing") {
3638
+ this.phase = "closed";
3639
+ this.setRestClosed(true);
3640
+ this.lifecycle.release();
3641
+ sheetStack.update();
3642
+ this.post("closed", void 0);
3643
+ }
3644
+ }
3645
+ land(haptic) {
3646
+ this.transition = null;
3647
+ this.inFlight = null;
3648
+ this.allowOvershoot = false;
3649
+ this.openPending = this.size === 0 && !this.isClosedSnap(this.activeId);
3319
3650
  this.updateAriaSlider();
3320
- this.emit("snap", {
3321
- id,
3651
+ this.setRestClosed(this.size === 0);
3652
+ this.post("snap", {
3653
+ id: this.activeId,
3322
3654
  size: this.size,
3323
3655
  progress: this.computeProgress(this.size)
3324
3656
  });
3325
- if (withHaptic) this.haptic();
3326
- this.setRestClosed(targetSize === 0);
3327
- if (wasClosed && targetSize > 0) this.emitOpenSequence(id);
3328
- if (targetSize === 0) this.emitCloseSequence();
3657
+ this.settlePhase(false);
3658
+ if (haptic) this.haptic();
3659
+ this.flush();
3660
+ }
3661
+ suspend() {
3662
+ this.animation.cancel();
3663
+ this.currentViewTransition?.skipTransition?.();
3664
+ this.newCycle();
3665
+ }
3666
+ landNow() {
3667
+ const transition = this.transition;
3668
+ if (this.destroyed || !transition || this.isDraggingAny()) return;
3669
+ this.animation.cancel();
3670
+ this.currentViewTransition?.skipTransition?.();
3671
+ this.newCycle();
3672
+ this.applySize(transition.size);
3673
+ this.land(false);
3674
+ }
3675
+ reseat() {
3676
+ if (this.destroyed || this.isDraggingAny()) return;
3677
+ const active = this.snaps.findById(this.activeId);
3678
+ if (!active) return;
3679
+ const cap = this.snaps.getMaxAxisSize();
3680
+ const target = cap > 0 ? Math.min(active.size, cap) : active.size;
3681
+ this.updateAriaSlider();
3682
+ const transition = this.transition;
3683
+ if (transition) {
3684
+ if (Math.abs(target - transition.size) < SIZE_WRITE_EPSILON && Math.abs(cap - transition.cap) < SIZE_WRITE_EPSILON) {
3685
+ return;
3686
+ }
3687
+ transition.size = target;
3688
+ transition.cap = cap;
3689
+ this.applySize(this.animation.retarget(target) ? this.size : target);
3690
+ return;
3691
+ }
3692
+ if (this.openPending && target > 0 && this.phase === "closed") {
3693
+ void this.runTransition(active, 0, false);
3694
+ return;
3695
+ }
3696
+ this.applySize(target);
3697
+ this.settlePhase(true);
3698
+ this.flush();
3699
+ }
3700
+ installLifecycle(promote) {
3701
+ if (promote) sheetStack.promote(this.id);
3702
+ if (this.lifecycle.isInstalled) return true;
3703
+ try {
3704
+ this.lifecycle.install();
3705
+ return true;
3706
+ } catch (err) {
3707
+ this.abortOpen();
3708
+ queueMicrotask(() => {
3709
+ throw err;
3710
+ });
3711
+ return false;
3712
+ }
3713
+ }
3714
+ abortOpen() {
3715
+ this.animation.cancel();
3716
+ if (!this.destroyed) this.newCycle();
3717
+ this.phase = "closed";
3718
+ this.openPending = false;
3719
+ this.lifecycle.release();
3720
+ sheetStack.update();
3721
+ this.activeId = this.zeroSnapId() ?? this.activeId;
3722
+ this.applySize(0);
3723
+ this.setRestClosed(true);
3724
+ this.updateAriaSlider();
3725
+ }
3726
+ zeroSnapId() {
3727
+ return this.snapPointsRaw.find((p) => p.id === "closed")?.id ?? this.snaps.getAllowedIds().find((a) => this.snaps.findById(a)?.size === 0);
3728
+ }
3729
+ isClosedSnap(id) {
3730
+ if (id === "closed") return true;
3731
+ return this.snapPointsRaw.find((p) => p.id === id)?.size === 0;
3732
+ }
3733
+ closingBlocked() {
3734
+ return this.disableCloseFlag && this.phase !== "closed";
3735
+ }
3736
+ setKeyboardInset(px) {
3737
+ if (px === this.keyboardInset) return;
3738
+ this.keyboardInset = px;
3739
+ for (const host of this.varHosts()) {
3740
+ host.style.setProperty("--bs-keyboard-inset", `${px}px`);
3741
+ }
3742
+ }
3743
+ varHosts() {
3744
+ const hosts = /* @__PURE__ */ new Set([this.element]);
3745
+ for (const host of [
3746
+ this.anchorHost,
3747
+ this.scrimParent,
3748
+ this.rootEl,
3749
+ this.homeRoot
3750
+ ]) {
3751
+ if (host) hosts.add(host);
3752
+ }
3753
+ return hosts;
3754
+ }
3755
+ dismissBlocked() {
3756
+ return (this.disableCloseFlag || this.persistent) && this.phase !== "closed";
3757
+ }
3758
+ post(event, payload) {
3759
+ this.outbox.push(() => this.bus.emit(event, payload));
3760
+ }
3761
+ flush() {
3762
+ if (this.flushing) return;
3763
+ this.flushing = true;
3764
+ try {
3765
+ for (let next = this.outbox.shift(); next; next = this.outbox.shift()) {
3766
+ next();
3767
+ }
3768
+ } finally {
3769
+ this.flushing = false;
3770
+ }
3329
3771
  }
3330
3772
  setRestClosed(closed) {
3331
3773
  if (closed === this.restClosed) return;
@@ -3333,17 +3775,6 @@ var init_BottomSheetCore = __esm({
3333
3775
  if (closed) this.element.setAttribute("data-bs-rest", "closed");
3334
3776
  else this.element.removeAttribute("data-bs-rest");
3335
3777
  }
3336
- emitOpenSequence(id) {
3337
- this.emit("open", { id });
3338
- this.handleOpen();
3339
- notifyLinkedSheets(this.linkedSheets, this);
3340
- this.emit("opened", { id });
3341
- }
3342
- emitCloseSequence() {
3343
- this.emit("close", void 0);
3344
- this.handleClose();
3345
- this.emit("closed", void 0);
3346
- }
3347
3778
  async dragTo(targetSize, velocityOrOpts = 0) {
3348
3779
  if (this.destroyed) return;
3349
3780
  const opts = typeof velocityOrOpts === "object" ? velocityOrOpts : { velocity: velocityOrOpts };
@@ -3351,27 +3782,31 @@ var init_BottomSheetCore = __esm({
3351
3782
  const externalSignal = opts.signal;
3352
3783
  if (externalSignal?.aborted) return;
3353
3784
  this.newCycle();
3354
- const onExternalAbort = () => {
3355
- this.animation.cancel();
3356
- this.newCycle();
3357
- };
3785
+ const onExternalAbort = () => this.suspend();
3358
3786
  externalSignal?.addEventListener("abort", onExternalAbort, { once: true });
3359
3787
  const clamped = Math.max(0, Math.min(targetSize, this.snaps.getMaxAxisSize()));
3360
3788
  await this.animation.animateTo(clamped, velocityPxPerMs);
3361
3789
  externalSignal?.removeEventListener("abort", onExternalAbort);
3362
- if (this.destroyed || externalSignal?.aborted) return;
3363
3790
  }
3364
3791
  open(id) {
3365
3792
  if (this.destroyed) return Promise.resolve();
3793
+ if (!id && (this.phase === "open" || this.phase === "opening")) {
3794
+ return Promise.resolve();
3795
+ }
3366
3796
  const target = id ?? this.snaps.getAllowedIds().find((a) => (this.snaps.findById(a)?.size ?? 0) > 0) ?? this.activeId;
3367
3797
  return this.snapTo(target);
3368
3798
  }
3369
3799
  close(reason = "programmatic") {
3370
- if (this.destroyed) return Promise.resolve();
3371
- if (this.disableCloseFlag) return Promise.resolve();
3372
- if (this.size > 0 && this.emitBeforeClose(reason)) return Promise.resolve();
3373
- 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];
3374
- return this.snapTo(closedId ?? this.activeId);
3800
+ if (this.destroyed || this.disableCloseFlag) return Promise.resolve();
3801
+ if (this.persistent && reason !== "programmatic") return Promise.resolve();
3802
+ const target = this.zeroSnapId() ?? this.allowedIdsBySize()[0];
3803
+ if (target === void 0) return Promise.resolve();
3804
+ if (this.phase === "closed" && this.activeId === target) {
3805
+ return Promise.resolve();
3806
+ }
3807
+ const visible = this.phase === "open" || this.phase === "opening";
3808
+ if (visible && this.emitBeforeClose(reason)) return Promise.resolve();
3809
+ return this.snapTo(target);
3375
3810
  }
3376
3811
  canDismiss() {
3377
3812
  return !this.persistent && !this.disableCloseFlag && !this.destroyed;
@@ -3394,10 +3829,12 @@ var init_BottomSheetCore = __esm({
3394
3829
  }
3395
3830
  setDragFrom(mode) {
3396
3831
  if (this.destroyed || mode === this.dragFromMode) return;
3832
+ const wasDragging = this.gesture?.isDragging ?? false;
3397
3833
  this.gesture?.forceClearDragState();
3398
3834
  this.detachSheetGesture?.();
3399
3835
  this.dragFromMode = mode;
3400
3836
  this.mountSheetGesture();
3837
+ if (wasDragging) this.restoreAfterDrag();
3401
3838
  }
3402
3839
  getDragFrom() {
3403
3840
  return this.dragFromMode;
@@ -3410,6 +3847,7 @@ var init_BottomSheetCore = __esm({
3410
3847
  const nowVertical = next === "bottom" || next === "top";
3411
3848
  this.gesture?.forceClearDragState();
3412
3849
  this.detachSheetGesture?.();
3850
+ this.landNow();
3413
3851
  this.animation.cancel();
3414
3852
  this.element.style.removeProperty(layoutAxis(this.mode));
3415
3853
  this.mode = next;
@@ -3425,9 +3863,12 @@ var init_BottomSheetCore = __esm({
3425
3863
  this.detachSliderKeyboard?.();
3426
3864
  this.mountSliderKeyboard();
3427
3865
  this.mountSheetGesture();
3866
+ for (const anchor of this.anchors) anchor.reposition();
3867
+ this.placeScrimStages?.();
3868
+ if (this.stackEffectPrimed) {
3869
+ this.element.style.transformOrigin = nowVertical ? "50% 100%" : "0% 50%";
3870
+ }
3428
3871
  this.recompute();
3429
- const active = this.snaps.findById(this.activeId);
3430
- if (active) this.applySize(active.size);
3431
3872
  this.updateAriaSlider();
3432
3873
  }
3433
3874
  getMode() {
@@ -3469,13 +3910,24 @@ var init_BottomSheetCore = __esm({
3469
3910
  if (snap && ids.includes(snap)) {
3470
3911
  void this.snapTo(snap, 0, true);
3471
3912
  } else if (!ids.includes(this.activeId)) {
3472
- const fallback = ids[0];
3473
- if (fallback) void this.snapTo(fallback, 0, true);
3913
+ const fallback = this.fallbackSnap(
3914
+ this.snaps.findById(this.activeId)?.size ?? this.size
3915
+ );
3916
+ if (fallback) void this.snapTo(fallback.id, 0, true);
3474
3917
  }
3475
3918
  }
3919
+ fallbackSnap(from) {
3920
+ return (from > 0 ? this.snaps.nearest(from, true) : null) ?? this.snaps.nearest(from, false);
3921
+ }
3476
3922
  setBackdropRange(range) {
3477
3923
  this.scrim.setBackdropRange(range, () => this.applySize(this.size));
3478
3924
  }
3925
+ setBackdropOpacity(value) {
3926
+ this.scrim.setBackdropOpacity(value, () => this.applySize(this.size));
3927
+ }
3928
+ setBackdropColor(color) {
3929
+ this.scrim.setBackdropColor(color);
3930
+ }
3479
3931
  setScreenRange(range) {
3480
3932
  this.scrim.setScreenRange(range, () => this.applySize(this.size));
3481
3933
  }
@@ -3516,7 +3968,7 @@ var init_BottomSheetCore = __esm({
3516
3968
  }
3517
3969
  const handle = attachAnchor(
3518
3970
  {
3519
- mode: this.mode,
3971
+ getMode: () => this.mode,
3520
3972
  host: this.anchorHost,
3521
3973
  getState: () => ({
3522
3974
  activeId: this.activeId,
@@ -3554,9 +4006,9 @@ var init_BottomSheetCore = __esm({
3554
4006
  return () => {
3555
4007
  };
3556
4008
  }
3557
- const detachInstalled = installScrimStages(
4009
+ const stages = installScrimStages(
3558
4010
  {
3559
- mode: this.mode,
4011
+ getMode: () => this.mode,
3560
4012
  host,
3561
4013
  getState: () => ({
3562
4014
  activeId: this.activeId,
@@ -3569,10 +4021,14 @@ var init_BottomSheetCore = __esm({
3569
4021
  opts
3570
4022
  );
3571
4023
  const detach = () => {
3572
- if (this.detachScrimStages === detach) this.detachScrimStages = null;
3573
- detachInstalled();
4024
+ if (this.detachScrimStages === detach) {
4025
+ this.detachScrimStages = null;
4026
+ this.placeScrimStages = null;
4027
+ }
4028
+ stages.detach();
3574
4029
  };
3575
4030
  this.detachScrimStages = detach;
4031
+ this.placeScrimStages = stages.reposition;
3576
4032
  this.teardowns.add(() => this.detachScrimStages?.());
3577
4033
  return detach;
3578
4034
  }
@@ -3581,32 +4037,29 @@ var init_BottomSheetCore = __esm({
3581
4037
  }
3582
4038
  setSnapPoints(points, allowed) {
3583
4039
  if (this.destroyed) return;
3584
- this.animation.cancel();
3585
- this.newCycle();
4040
+ const from = this.snaps.findById(this.activeId)?.size ?? this.size;
4041
+ const restricted = this.snaps.getResolvedSnaps().some((s) => !this.snaps.getAllowedIds().includes(s.id));
3586
4042
  this.snapPointsRaw = points;
3587
4043
  auditVhUsage(points);
3588
4044
  this.auditDuplicateSnapIds(points);
4045
+ this.maxHeight.resolveCap();
3589
4046
  this.snaps.setRaw(points);
4047
+ this.maxHeight.clampTo();
3590
4048
  if (allowed) {
3591
4049
  this.snaps.setAllowedIds(allowed);
3592
4050
  } else {
3593
4051
  const present = this.snaps.getResolvedSnaps().map((s) => s.id);
3594
- const kept = this.snaps.getAllowedIds().filter((id) => present.includes(id));
4052
+ const kept = restricted ? this.snaps.getAllowedIds().filter((id) => present.includes(id)) : [];
3595
4053
  this.snaps.setAllowedIds(kept.length ? kept : present);
3596
4054
  }
3597
4055
  this.scrollCache.clear();
3598
4056
  this.scrim.invalidateOpacityCache();
3599
- const current = this.snaps.findById(this.activeId);
3600
- if (current) {
3601
- this.applySize(current.size);
3602
- } else {
3603
- const fallback = this.snaps.getResolvedSnaps().find((s) => this.snaps.getAllowedIds().includes(s.id)) ?? this.snaps.getResolvedSnaps()[0];
3604
- if (fallback) {
3605
- this.activeId = fallback.id;
3606
- this.applySize(fallback.size);
3607
- }
4057
+ if (this.snaps.findById(this.activeId)) {
4058
+ this.reseat();
4059
+ return;
3608
4060
  }
3609
- this.updateAriaSlider();
4061
+ const fallback = this.fallbackSnap(from) ?? this.snaps.getResolvedSnaps()[0];
4062
+ if (fallback) void this.transitionTo(fallback.id, 0, true);
3610
4063
  }
3611
4064
  recompute() {
3612
4065
  if (this.destroyed) return;
@@ -3614,22 +4067,11 @@ var init_BottomSheetCore = __esm({
3614
4067
  this.snaps.recompute();
3615
4068
  this.maxHeight.clampTo();
3616
4069
  this.scrim.invalidateOpacityCache();
3617
- if (this.isDraggingAny()) return;
3618
- this.healActiveSnap();
3619
- }
3620
- healActiveSnap() {
3621
- const current = this.snaps.findById(this.activeId);
3622
- if (!current) return;
3623
- this.size = current.size;
3624
- this.applySize(this.size);
3625
- this.updateAriaSlider();
3626
- if (this.size > 0 && !this.lifecycle.isInstalled && !this.opening && !this.animation.isAnimating) {
3627
- this.emitOpenSequence(this.activeId);
3628
- }
4070
+ this.reseat();
3629
4071
  }
3630
4072
  destroy() {
3631
4073
  this.destroyed = true;
3632
- this.opening = false;
4074
+ this.outbox.length = 0;
3633
4075
  this.currentAbort.abort();
3634
4076
  this.currentViewTransition?.skipTransition?.();
3635
4077
  this.currentViewTransition = null;
@@ -3646,11 +4088,19 @@ var init_BottomSheetCore = __esm({
3646
4088
  this.backdrop.style.opacity = "";
3647
4089
  this.backdrop.style.pointerEvents = "";
3648
4090
  }
3649
- for (const host of [this.anchorHost, this.scrimParent, this.rootEl]) {
4091
+ for (const host of [
4092
+ this.anchorHost,
4093
+ this.scrimParent,
4094
+ this.rootEl,
4095
+ this.homeRoot
4096
+ ]) {
3650
4097
  if (!host) continue;
3651
4098
  host.style.removeProperty("--bs-size");
3652
4099
  host.style.removeProperty("--bs-progress");
4100
+ host.style.removeProperty("--bs-z-sheet");
4101
+ host.style.removeProperty("--bs-keyboard-inset");
3653
4102
  }
4103
+ this.element.style.removeProperty("--bs-keyboard-inset");
3654
4104
  if (this.screenComponent) {
3655
4105
  this.screenComponent.style.opacity = "";
3656
4106
  this.screenComponent.style.display = "";
@@ -3663,7 +4113,8 @@ var init_BottomSheetCore = __esm({
3663
4113
  }
3664
4114
  newCycle() {
3665
4115
  this.allowOvershoot = false;
3666
- this.opening = false;
4116
+ this.transition = null;
4117
+ this.inFlight = null;
3667
4118
  this.currentAbort.abort();
3668
4119
  this.currentAbort = new AbortController();
3669
4120
  return this.currentAbort.signal;
@@ -3686,8 +4137,9 @@ var init_BottomSheetCore = __esm({
3686
4137
  if (typeof document === "undefined") return;
3687
4138
  if (!this.lifecycle.focusTrapEnabled) return;
3688
4139
  if (this.element.getAttribute("aria-labelledby")) return;
3689
- const scope = this.handle ?? this.element;
3690
- const titled = scope.querySelector("[data-bs-title]") ?? scope.querySelector("h1,h2,h3,h4,h5,h6");
4140
+ const HEADING = "h1,h2,h3,h4,h5,h6";
4141
+ const header = this.element.querySelector(".bs-header");
4142
+ const titled = this.element.querySelector("[data-bs-title]") ?? this.handle.querySelector(HEADING) ?? header?.querySelector(HEADING);
3691
4143
  if (!titled) return;
3692
4144
  if (!titled.id) {
3693
4145
  titled.id = nextInstanceId("bs-title");
@@ -3729,12 +4181,16 @@ var init_BottomSheetCore = __esm({
3729
4181
  this.stackZ = z;
3730
4182
  this.element.style.zIndex = String(z);
3731
4183
  if (this.backdrop) this.backdrop.style.zIndex = String(z - 1);
4184
+ this.rootEl?.style.setProperty("--bs-z-sheet", String(z));
4185
+ this.homeRoot?.style.setProperty("--bs-z-sheet", String(z));
3732
4186
  for (const anchor of this.anchors) anchor.syncZ(z + 1);
3733
4187
  },
3734
4188
  setIsTop: (isTop) => {
4189
+ if (isTop === this.isTopSheet) return;
3735
4190
  this.isTopSheet = isTop;
4191
+ this.lifecycle.syncTop();
3736
4192
  },
3737
- isOpen: () => this.size > 0 || this.opening,
4193
+ isOpen: () => this.phase !== "closed",
3738
4194
  setDepth: (depth) => this.applyStackDepth(depth)
3739
4195
  }));
3740
4196
  }
@@ -3762,15 +4218,15 @@ var init_BottomSheetCore = __esm({
3762
4218
  const r = this.getAllowedRange();
3763
4219
  buf.size = this.size;
3764
4220
  buf.maxAxisSize = this.snaps.getMaxAxisSize();
3765
- buf.range.min = r.min;
4221
+ buf.range.min = this.dismissBlocked() ? Math.max(r.min, this.smallestOpenSize()) : r.min;
3766
4222
  buf.range.max = r.max;
3767
4223
  buf.rubberBandEnabled = this.rubberBandEnabled;
3768
4224
  return buf;
3769
4225
  },
3770
4226
  getDisableDrag: () => this.disableDragFlag,
3771
- cancelAnimation: () => this.animation.cancel(),
4227
+ cancelAnimation: () => this.suspend(),
3772
4228
  applySize: (size) => this.applySize(size),
3773
- animateTo: (size, velocity) => this.animation.animateTo(size, velocity),
4229
+ restoreAfterDrag: () => this.restoreAfterDrag(),
3774
4230
  settleAfterDrag: (delta, velocity, kind) => this.settleAfterDrag(delta, velocity, kind),
3775
4231
  emit: (event, payload) => this.emit(event, payload),
3776
4232
  listenerCount: (event) => this.bus.listenerCount(event)
@@ -3894,32 +4350,19 @@ var init_BottomSheetCore = __esm({
3894
4350
  element: this.element,
3895
4351
  getMode: () => this.mode,
3896
4352
  isDestroyed: () => this.destroyed,
3897
- isDragging: () => this.isDraggingAny(),
3898
4353
  resolveActiveSnap: () => this.snaps.findById(this.activeId),
3899
4354
  getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
3900
- getSize: () => this.size,
3901
4355
  setMaxAxisSize: (size) => {
3902
4356
  this.snaps.setMaxAxisSize(size);
3903
4357
  },
3904
- setSize: (size) => {
3905
- this.size = size;
3906
- },
3907
4358
  recomputeSnaps: () => this.recomputeSnaps(),
3908
- applySize: (size) => this.applySize(size),
3909
- cancelInFlight: () => {
3910
- this.animation.cancel();
3911
- },
3912
- newCycle: () => {
3913
- this.newCycle();
3914
- },
3915
- isAnimating: () => this.animation.isAnimating,
3916
- resyncAfterCancel: () => this.resyncAfterResize()
4359
+ reseat: () => this.reseat(),
4360
+ landNow: () => this.landNow()
3917
4361
  }));
3918
4362
  if (this.lifecycle.closeOnEscape) {
3919
4363
  const onKey = (e) => {
3920
4364
  if (this.destroyed || e.defaultPrevented) return;
3921
- if (!this.canDismiss()) return;
3922
- if (e.key === "Escape" && this.isTopSheet && this.size > 0) {
4365
+ if (e.key === "Escape" && this.isTopSheet) {
3923
4366
  void this.close("escape");
3924
4367
  }
3925
4368
  };
@@ -3937,7 +4380,10 @@ var init_BottomSheetCore = __esm({
3937
4380
  handle: this.handle,
3938
4381
  mode: this.mode,
3939
4382
  isDestroyed: () => this.destroyed,
3940
- getAllowedIds: () => this.allowedIdsBySize(),
4383
+ getAllowedIds: () => {
4384
+ const ids = this.allowedIdsBySize();
4385
+ return this.dismissBlocked() ? ids.filter((id) => (this.snaps.findById(id)?.size ?? 0) > 0) : ids;
4386
+ },
3941
4387
  getActiveId: () => this.activeId,
3942
4388
  snapTo: (id) => {
3943
4389
  void this.snapTo(id);
@@ -3950,56 +4396,46 @@ var init_BottomSheetCore = __esm({
3950
4396
  });
3951
4397
  }
3952
4398
  settleAfterDrag(delta, velocity, kind = "touch") {
3953
- const signal = this.newCycle();
3954
- const target = this.snaps.findDragSettleTarget({
3955
- delta,
3956
- velocity,
3957
- pointerKind: kind,
3958
- size: this.size,
3959
- activeId: this.activeId,
3960
- flickVelocity: this.flickVelocity,
3961
- dragThreshold: this.dragThreshold
3962
- });
4399
+ const target = this.snaps.findDragSettleTarget(
4400
+ {
4401
+ delta,
4402
+ velocity,
4403
+ pointerKind: kind,
4404
+ size: this.size,
4405
+ activeId: this.activeId,
4406
+ flickVelocity: this.flickVelocity,
4407
+ dragThreshold: this.dragThreshold
4408
+ },
4409
+ this.dismissBlocked()
4410
+ );
3963
4411
  if (!target) {
3964
4412
  this.clearWillChangeIfIdle();
3965
4413
  return;
3966
4414
  }
3967
4415
  const previousId = this.activeId;
3968
4416
  if (target.id === previousId && target.size === this.size) {
4417
+ if (this.phase === "opening" || this.phase === "closing") {
4418
+ this.land(false);
4419
+ }
3969
4420
  this.clearWillChangeIfIdle();
3970
4421
  return;
3971
4422
  }
3972
4423
  if (this.emitBeforeSnap(target, previousId)) {
3973
- const restore2 = this.snaps.findById(previousId);
3974
- if (restore2) {
3975
- void this.animation.animateTo(restore2.size, 0);
3976
- }
4424
+ this.restoreAfterDrag();
3977
4425
  return;
3978
4426
  }
3979
- const previousSize = this.size;
3980
- const previousSnapSize = this.snaps.findById(previousId)?.size;
3981
- this.scrollCache.cache(previousId, previousSize, target.size);
3982
- this.activeId = target.id;
3983
- if (previousSnapSize === 0 && target.size > 0) {
3984
- this.opening = true;
3985
- this.promotedForOpen = true;
3986
- sheetStack.promote(this.id);
3987
- }
3988
- const settleCap = this.snaps.getMaxAxisSize();
3989
- const settleSize = settleCap > 0 ? Math.min(target.size, settleCap) : target.size;
3990
- this.allowOvershoot = true;
3991
- void this.animation.animateTo(settleSize, velocity).then(() => {
3992
- if (signal.aborted) return;
3993
- this.allowOvershoot = false;
3994
- this.opening = false;
3995
- this.completeSnap(
3996
- target.id,
3997
- target.size,
3998
- previousSize,
3999
- previousSnapSize === 0,
4000
- true
4001
- );
4002
- });
4427
+ void this.runTransition(target, velocity, true);
4428
+ }
4429
+ restoreAfterDrag() {
4430
+ const active = this.snaps.findById(this.activeId);
4431
+ if (active) void this.runTransition(active, 0, false);
4432
+ }
4433
+ smallestOpenSize() {
4434
+ const allowed = this.snaps.getAllowedIds();
4435
+ for (const snap of this.snaps.getResolvedSnaps()) {
4436
+ if (snap.size > 0 && allowed.includes(snap.id)) return snap.size;
4437
+ }
4438
+ return 0;
4003
4439
  }
4004
4440
  isDraggingAny() {
4005
4441
  return (this.gesture?.isDragging ?? false) || (this.contentGesture?.isDragging ?? false);
@@ -4024,9 +4460,10 @@ var init_BottomSheetCore = __esm({
4024
4460
  const offset = cap - clamped;
4025
4461
  const style = this.element.style;
4026
4462
  if (!skipTransform) style.transform = this.transformTemplate(offset);
4463
+ const moving = this.animation.isAnimating || this.isDraggingAny();
4027
4464
  const sizeChanged = this.sizeWriteSentinel.shouldWrite(
4028
4465
  clamped,
4029
- this.animation.isAnimating || this.isDraggingAny() ? SIZE_WRITE_EPSILON : 0
4466
+ moving ? SIZE_WRITE_EPSILON : 0
4030
4467
  );
4031
4468
  if (sizeChanged) {
4032
4469
  style.setProperty("--bs-size", `${clamped}px`);
@@ -4039,11 +4476,13 @@ var init_BottomSheetCore = __esm({
4039
4476
  if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
4040
4477
  this.rootEl.style.setProperty("--bs-size", `${clamped}px`);
4041
4478
  }
4479
+ this.homeRoot?.style.setProperty("--bs-size", `${clamped}px`);
4042
4480
  }
4043
4481
  const progress = this.computeProgress(clamped);
4482
+ const opacityEpsilon = moving ? OPACITY_WRITE_EPSILON : 0;
4044
4483
  const progressChanged = this.progressWriteSentinel.shouldWrite(
4045
4484
  progress,
4046
- OPACITY_WRITE_EPSILON
4485
+ opacityEpsilon
4047
4486
  );
4048
4487
  if (progressChanged) {
4049
4488
  style.setProperty("--bs-progress", String(progress));
@@ -4053,8 +4492,9 @@ var init_BottomSheetCore = __esm({
4053
4492
  if (this.rootEl && this.rootEl !== this.anchorHost) {
4054
4493
  this.rootEl.style.setProperty("--bs-progress", String(progress));
4055
4494
  }
4495
+ this.homeRoot?.style.setProperty("--bs-progress", String(progress));
4056
4496
  }
4057
- this.scrim.applyOpacity(progress, progressChanged);
4497
+ this.scrim.applyOpacity(progress, progressChanged, opacityEpsilon);
4058
4498
  if ((progressChanged || sizeChanged) && this.bus.listenerCount("progress") > 0) {
4059
4499
  this.progressPayload.value = progress;
4060
4500
  this.progressPayload.size = clamped;
@@ -4067,245 +4507,330 @@ var init_BottomSheetCore = __esm({
4067
4507
  if (reachableMax <= min) return 0;
4068
4508
  return Math.min(Math.max((size - min) / (reachableMax - min), 0), 1);
4069
4509
  }
4070
- handleOpen() {
4071
- if (this.promotedForOpen) this.promotedForOpen = false;
4072
- else sheetStack.promote(this.id);
4073
- try {
4074
- this.lifecycle.install();
4075
- } catch (err) {
4076
- if (!this.destroyed) this.newCycle();
4077
- this.handleClose();
4078
- this.applySize(0);
4079
- this.activeId = this.snapPointsRaw.find((p) => p.id === "closed")?.id ?? this.activeId;
4080
- this.size = 0;
4081
- queueMicrotask(() => {
4082
- throw err;
4083
- });
4084
- }
4085
- }
4086
- resyncAfterResize() {
4087
- if (this.destroyed) return;
4088
- const target = this.snaps.findById(this.activeId);
4089
- if (!target) return;
4090
- this.updateAriaSlider();
4091
- this.emit("snap", {
4092
- id: target.id,
4093
- size: this.size,
4094
- progress: this.computeProgress(this.size)
4095
- });
4096
- if (target.size > 0 && !this.lifecycle.isInstalled) {
4097
- this.emitOpenSequence(target.id);
4098
- } else if (target.size === 0 && this.lifecycle.isInstalled) {
4099
- this.emitCloseSequence();
4100
- }
4101
- }
4102
- handleClose() {
4103
- this.opening = false;
4104
- this.promotedForOpen = false;
4105
- this.lifecycle.release();
4106
- sheetStack.update();
4107
- }
4108
4510
  };
4109
4511
  }
4110
4512
  });
4111
4513
 
4112
4514
  // src/core/features/history-coordinator.ts
4113
- function onPopState() {
4114
- if (suppress > 0) {
4115
- suppress -= 1;
4116
- const rebrand = pendingRebrands.shift();
4117
- if (rebrand) rebrand();
4118
- maybeTeardownListener();
4119
- return;
4120
- }
4121
- if (entries.length === 0) {
4122
- notifyRouteChange();
4123
- maybeTeardownListener();
4124
- return;
4125
- }
4126
- let target = null;
4127
- let targetIdx = -1;
4128
- for (let i = entries.length - 1; i >= 0; i -= 1) {
4129
- const entry = entries[i];
4130
- if (!entry.surface.isOpen()) continue;
4131
- if (!target) {
4132
- target = entry;
4133
- targetIdx = i;
4515
+ function pushEntry(entry) {
4516
+ const depth = state2.live.length + 1;
4517
+ if (state2.live.length === 0) startStack();
4518
+ const written = runInternal(() => {
4519
+ history.pushState(markerFor(entry.surface, depth), "", entry.surface.url);
4520
+ });
4521
+ if (!written) return false;
4522
+ state2.live.push(entry);
4523
+ state2.position = depth;
4524
+ state2.knownLength = history.length;
4525
+ state2.href = location.href;
4526
+ ensureListener();
4527
+ return true;
4528
+ }
4529
+ function onPopState(event) {
4530
+ const kind = state2.pending.shift();
4531
+ const byUser = kind !== "pop";
4532
+ const landed = plain(event.state);
4533
+ const depth = depthOf(landed);
4534
+ const from = state2.position;
4535
+ const liveBefore = state2.live.length;
4536
+ const grew = history.length > state2.knownLength;
4537
+ state2.knownLength = history.length;
4538
+ const within = inStack(landed);
4539
+ if (within && depth !== null) {
4540
+ state2.position = depth;
4541
+ if (depth > state2.live.length) {
4542
+ const forward = from !== null && from < depth;
4543
+ traverse(forward ? 1 : -1, byUser ? "skip" : "pop");
4544
+ } else if (depth < state2.live.length) {
4545
+ if (byUser) closeAbove(depth);
4546
+ } else {
4547
+ rebrand(depth);
4134
4548
  }
4135
- if (entry.surface.isTop()) {
4136
- target = entry;
4137
- targetIdx = i;
4138
- break;
4549
+ } else if (isMarker(landed)) {
4550
+ state2.position = null;
4551
+ traverse(-1, byUser ? "skip" : "pop");
4552
+ } else {
4553
+ state2.position = null;
4554
+ if (byUser && !grew && state2.live.length > 0) {
4555
+ closeAbove(state2.live.length - 1);
4139
4556
  }
4140
4557
  }
4141
- if (!target) {
4142
- const removed = entries.pop();
4143
- if (removed) removed.live = false;
4144
- maybeTeardownListener();
4145
- return;
4558
+ const moved = location.href !== state2.href;
4559
+ state2.href = location.href;
4560
+ if (kind === void 0 && moved && (liveBefore === 0 || !within)) {
4561
+ notifyRouteChange();
4146
4562
  }
4147
- target.live = false;
4148
- entries.splice(targetIdx, 1);
4149
- const settled = target;
4150
- void Promise.resolve(settled.surface.close()).then(() => {
4151
- if (settled.surface.isOpen()) restore(settled);
4152
- });
4563
+ settleIfIdle();
4153
4564
  maybeTeardownListener();
4154
4565
  }
4155
- function restore(entry) {
4156
- if (!hasWindow() || !hasHistory()) return;
4157
- entry.live = true;
4158
- runInternal(() => {
4159
- try {
4160
- history.pushState(brandMarker(entry.surface), "", entry.surface.url);
4161
- } catch {
4162
- entry.live = false;
4163
- }
4164
- });
4165
- if (entry.live) {
4166
- entries.push(entry);
4167
- ensureListener();
4168
- }
4169
- }
4170
4566
  function pushBackMarker(surface) {
4171
- const entry = { surface, priorUrl: void 0, live: false };
4172
- if (!hasWindow() || !hasHistory()) {
4173
- return entry;
4174
- }
4175
- entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
4176
- runInternal(() => {
4177
- try {
4178
- history.pushState(brandMarker(surface), "", surface.url);
4179
- entry.live = true;
4180
- } catch {
4181
- entry.live = false;
4182
- }
4183
- });
4184
- if (entry.live) {
4185
- entries.push(entry);
4186
- ensureListener();
4187
- }
4567
+ const entry = { surface };
4568
+ if (hasHistory()) enlist(entry);
4188
4569
  return entry;
4189
4570
  }
4190
4571
  function popBackMarker(handle) {
4191
- if (!hasWindow() || !hasHistory()) return;
4572
+ if (!hasHistory()) return Promise.resolve();
4192
4573
  const entry = handle;
4193
- const idx = entries.indexOf(entry);
4194
- if (idx === -1 || !entry.live) return;
4195
- const last = entries.length - 1;
4196
- entry.live = false;
4197
- entries.splice(idx, 1);
4198
- let rebrand = null;
4199
- if (idx !== last) {
4200
- const rebrandSurface = entries[entries.length - 1].surface;
4201
- const rebrandUrl = entry.priorUrl;
4202
- rebrand = () => {
4203
- runInternal(() => {
4204
- history.replaceState(
4205
- brandMarker(rebrandSurface),
4206
- "",
4207
- rebrandUrl !== void 0 ? rebrandUrl : location.href
4208
- );
4209
- });
4210
- };
4574
+ const waiting = state2.deferred.indexOf(entry);
4575
+ if (waiting !== -1) state2.deferred.splice(waiting, 1);
4576
+ const idx = state2.live.indexOf(entry);
4577
+ if (idx === -1) return historySettled();
4578
+ const top = state2.live.length;
4579
+ state2.live.splice(idx, 1);
4580
+ const current = plain(history.state);
4581
+ const onTop = isMarker(current) && inStack(current) && depthOf(current) === top;
4582
+ if (onTop && state2.pending.length === 0) {
4583
+ traverse(-1, "pop");
4584
+ } else {
4585
+ state2.leftovers = true;
4586
+ ensureListener();
4211
4587
  }
4212
- pendingRebrands.push(rebrand);
4213
- suppress += 1;
4214
- runInternal(() => {
4215
- try {
4216
- history.back();
4217
- } catch {
4218
- suppress = Math.max(0, suppress - 1);
4219
- pendingRebrands.pop();
4220
- }
4221
- });
4222
4588
  maybeTeardownListener();
4589
+ return historySettled();
4590
+ }
4591
+ function releaseOrphanMarker() {
4592
+ if (!hasHistory() || state2.orphanChecked) return;
4593
+ state2.orphanChecked = true;
4594
+ if (state2.live.length > 0 || state2.pending.length > 0) return;
4595
+ if (!isMarker(plain(history.state))) return;
4596
+ state2.leftovers = true;
4597
+ traverse(-1, "pop");
4598
+ }
4599
+ function historySettled() {
4600
+ if (state2.pending.length === 0) return Promise.resolve();
4601
+ return new Promise((resolve) => {
4602
+ state2.waiters.push(resolve);
4603
+ });
4223
4604
  }
4224
4605
  function subscribeRouteChange(fn) {
4225
- if (!hasWindow() || !hasHistory()) return () => {
4606
+ if (!hasHistory()) return () => {
4226
4607
  };
4227
- subscribers.add(fn);
4228
- if (subscribers.size === 1) installPatch();
4608
+ state2.subscribers.add(fn);
4609
+ state2.href = location.href;
4610
+ state2.knownLength = history.length;
4611
+ installPatch();
4229
4612
  ensureListener();
4230
4613
  return () => {
4231
- if (!subscribers.has(fn)) return;
4232
- subscribers.delete(fn);
4233
- if (subscribers.size === 0) removePatch();
4614
+ if (!state2.subscribers.delete(fn)) return;
4615
+ if (state2.subscribers.size === 0) removePatch();
4234
4616
  maybeTeardownListener();
4235
4617
  };
4236
4618
  }
4237
- var entries, subscribers, suppress, internalDepth, pendingRebrands, listenerInstalled, patchInstalled, origPushState, origReplaceState, patchedPushState, patchedReplaceState, hasWindow, hasHistory, brandMarker, runInternal, notifyRouteChange, ensureListener, maybeTeardownListener, installPatch, removePatch;
4619
+ 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;
4238
4620
  var init_history_coordinator = __esm({
4239
4621
  "src/core/features/history-coordinator.ts"() {
4240
- entries = [];
4241
- subscribers = /* @__PURE__ */ new Set();
4242
- suppress = 0;
4243
- internalDepth = 0;
4244
- pendingRebrands = [];
4245
- listenerInstalled = false;
4246
- patchInstalled = false;
4247
- origPushState = null;
4248
- origReplaceState = null;
4249
- patchedPushState = null;
4250
- patchedReplaceState = null;
4251
- hasWindow = () => typeof window !== "undefined";
4252
- hasHistory = () => typeof history !== "undefined";
4253
- brandMarker = (surface) => ({
4622
+ init_shared();
4623
+ MARKER = "__bs";
4624
+ STACK = "__bsStack";
4625
+ DEPTH = "__bsDepth";
4626
+ ROUTED = "__bsRouted";
4627
+ SETTLE_TIMEOUT_MS = 1e3;
4628
+ state2 = shared(
4629
+ "history",
4630
+ () => ({
4631
+ live: [],
4632
+ stackId: void 0,
4633
+ baseUrl: void 0,
4634
+ position: null,
4635
+ knownLength: 0,
4636
+ href: "",
4637
+ subscribers: /* @__PURE__ */ new Set(),
4638
+ internal: 0,
4639
+ pending: [],
4640
+ deferred: [],
4641
+ waiters: [],
4642
+ timer: null,
4643
+ listening: false,
4644
+ leftovers: false,
4645
+ orphanChecked: false,
4646
+ push: null,
4647
+ replace: null
4648
+ })
4649
+ );
4650
+ hasHistory = () => typeof window !== "undefined" && typeof history !== "undefined";
4651
+ plain = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
4652
+ depthOf = (value) => {
4653
+ const depth = value?.[DEPTH];
4654
+ return typeof depth === "number" ? depth : null;
4655
+ };
4656
+ isMarker = (value) => value?.[MARKER] === true;
4657
+ inStack = (value) => value !== null && state2.stackId !== void 0 && value[STACK] === state2.stackId && depthOf(value) !== null;
4658
+ foreignKeys = (value) => {
4659
+ const out = {};
4660
+ const source = plain(value);
4661
+ if (!source) return out;
4662
+ for (const key of Object.keys(source)) {
4663
+ if (!key.startsWith(MARKER)) out[key] = source[key];
4664
+ }
4665
+ return out;
4666
+ };
4667
+ markerFor = (surface, depth) => ({
4668
+ ...foreignKeys(history.state),
4254
4669
  ...surface.markerState(),
4255
- __bs: true
4670
+ [MARKER]: true,
4671
+ [STACK]: state2.stackId,
4672
+ [DEPTH]: depth
4256
4673
  });
4674
+ urlForDepth = (depth) => {
4675
+ for (let i = depth - 1; i >= 0; i -= 1) {
4676
+ const url = state2.live[i]?.surface.url;
4677
+ if (url !== void 0) return url;
4678
+ }
4679
+ return state2.baseUrl;
4680
+ };
4257
4681
  runInternal = (fn) => {
4258
- internalDepth += 1;
4682
+ state2.internal += 1;
4259
4683
  try {
4260
4684
  fn();
4685
+ return true;
4686
+ } catch {
4687
+ return false;
4261
4688
  } finally {
4262
- internalDepth -= 1;
4689
+ state2.internal -= 1;
4263
4690
  }
4264
4691
  };
4265
4692
  notifyRouteChange = () => {
4266
- const snapshot = Array.from(subscribers);
4267
- for (const fn of snapshot) fn();
4693
+ for (const fn of Array.from(state2.subscribers)) {
4694
+ try {
4695
+ fn();
4696
+ } catch (err) {
4697
+ queueMicrotask(() => {
4698
+ throw err;
4699
+ });
4700
+ }
4701
+ }
4268
4702
  };
4269
4703
  ensureListener = () => {
4270
- if (listenerInstalled || !hasWindow()) return;
4704
+ if (state2.listening || !hasHistory()) return;
4271
4705
  window.addEventListener("popstate", onPopState);
4272
- listenerInstalled = true;
4706
+ state2.listening = true;
4273
4707
  };
4274
4708
  maybeTeardownListener = () => {
4275
- if (!listenerInstalled) return;
4276
- if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
4277
- if (hasWindow()) window.removeEventListener("popstate", onPopState);
4278
- listenerInstalled = false;
4709
+ if (!state2.listening) return;
4710
+ if (state2.live.length > 0 || state2.subscribers.size > 0 || state2.pending.length > 0 || state2.leftovers) {
4711
+ return;
4712
+ }
4713
+ if (hasHistory()) window.removeEventListener("popstate", onPopState);
4714
+ state2.listening = false;
4715
+ };
4716
+ settleIfIdle = () => {
4717
+ if (state2.pending.length > 0) return;
4718
+ if (state2.timer !== null) {
4719
+ clearTimeout(state2.timer);
4720
+ state2.timer = null;
4721
+ }
4722
+ for (const entry of state2.deferred.splice(0)) pushEntry(entry);
4723
+ for (const resolve of state2.waiters.splice(0)) resolve();
4724
+ };
4725
+ traverse = (delta, kind) => {
4726
+ state2.pending.push(kind);
4727
+ if (state2.timer !== null) clearTimeout(state2.timer);
4728
+ state2.timer = setTimeout(() => {
4729
+ state2.timer = null;
4730
+ state2.pending.length = 0;
4731
+ settleIfIdle();
4732
+ maybeTeardownListener();
4733
+ }, SETTLE_TIMEOUT_MS);
4734
+ ensureListener();
4735
+ const moved = runInternal(() => {
4736
+ if (delta < 0) history.back();
4737
+ else history.forward();
4738
+ });
4739
+ if (!moved) {
4740
+ state2.pending.pop();
4741
+ settleIfIdle();
4742
+ }
4743
+ };
4744
+ newStackId = () => `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
4745
+ startStack = () => {
4746
+ state2.stackId = newStackId();
4747
+ const current = history.state;
4748
+ const leftover = plain(current);
4749
+ state2.baseUrl = isMarker(leftover) && leftover?.[ROUTED] !== void 0 ? void 0 : location.href;
4750
+ if (isMarker(leftover)) return;
4751
+ if (current !== null && current !== void 0 && !leftover) return;
4752
+ runInternal(() => {
4753
+ history.replaceState(
4754
+ { ...foreignKeys(current), [STACK]: state2.stackId, [DEPTH]: 0 },
4755
+ "",
4756
+ location.href
4757
+ );
4758
+ });
4759
+ };
4760
+ enlist = (entry) => {
4761
+ if (state2.pending.length > 0) state2.deferred.push(entry);
4762
+ else pushEntry(entry);
4763
+ };
4764
+ sameBrand = (a, b) => {
4765
+ for (const key of /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)])) {
4766
+ if (key.startsWith(MARKER) && a[key] !== b[key]) return false;
4767
+ }
4768
+ return true;
4769
+ };
4770
+ rebrand = (depth) => {
4771
+ const entry = state2.live[depth - 1];
4772
+ if (!entry) return;
4773
+ const url = urlForDepth(depth);
4774
+ const marker = markerFor(entry.surface, depth);
4775
+ const atUrl = url === void 0 || new URL(url, location.href).href === location.href;
4776
+ if (atUrl && sameBrand(plain(history.state) ?? {}, marker)) return;
4777
+ runInternal(() => {
4778
+ history.replaceState(marker, "", url);
4779
+ });
4780
+ state2.href = location.href;
4781
+ };
4782
+ closeAbove = (depth) => {
4783
+ const dropped = state2.live.splice(depth);
4784
+ for (let i = dropped.length - 1; i >= 0; i -= 1) {
4785
+ const entry = dropped[i];
4786
+ let closing = void 0;
4787
+ try {
4788
+ closing = entry.surface.close();
4789
+ } catch (err) {
4790
+ queueMicrotask(() => {
4791
+ throw err;
4792
+ });
4793
+ }
4794
+ void Promise.resolve(closing).then(() => {
4795
+ if (!entry.surface.isOpen()) return;
4796
+ const known = (e) => e.surface === entry.surface;
4797
+ if (state2.live.some(known) || state2.deferred.some(known)) return;
4798
+ enlist(entry);
4799
+ });
4800
+ }
4801
+ };
4802
+ wrap = (original) => function(...args) {
4803
+ original.apply(this, args);
4804
+ state2.knownLength = history.length;
4805
+ if (location.href === state2.href) return;
4806
+ state2.href = location.href;
4807
+ if (state2.internal === 0 && state2.subscribers.size > 0) {
4808
+ notifyRouteChange();
4809
+ }
4279
4810
  };
4280
4811
  installPatch = () => {
4281
- if (patchInstalled || !hasHistory()) return;
4282
- origPushState = history.pushState;
4283
- origReplaceState = history.replaceState;
4284
- patchedPushState = function(...args) {
4285
- origPushState.apply(this, args);
4286
- if (internalDepth === 0) notifyRouteChange();
4287
- };
4288
- patchedReplaceState = function(...args) {
4289
- origReplaceState.apply(this, args);
4290
- if (internalDepth === 0) notifyRouteChange();
4291
- };
4292
- history.pushState = patchedPushState;
4293
- history.replaceState = patchedReplaceState;
4294
- patchInstalled = true;
4812
+ if (!state2.push || history.pushState === state2.push.original) {
4813
+ const original = history.pushState;
4814
+ const wrapper = wrap(original);
4815
+ history.pushState = wrapper;
4816
+ state2.push = { wrapper, original };
4817
+ }
4818
+ if (!state2.replace || history.replaceState === state2.replace.original) {
4819
+ const original = history.replaceState;
4820
+ const wrapper = wrap(original);
4821
+ history.replaceState = wrapper;
4822
+ state2.replace = { wrapper, original };
4823
+ }
4295
4824
  };
4296
4825
  removePatch = () => {
4297
- if (!patchInstalled) return;
4298
- if (history.pushState === patchedPushState && origPushState) {
4299
- history.pushState = origPushState;
4300
- }
4301
- if (history.replaceState === patchedReplaceState && origReplaceState) {
4302
- history.replaceState = origReplaceState;
4303
- }
4304
- origPushState = null;
4305
- origReplaceState = null;
4306
- patchedPushState = null;
4307
- patchedReplaceState = null;
4308
- patchInstalled = false;
4826
+ if (state2.push && history.pushState === state2.push.wrapper) {
4827
+ history.pushState = state2.push.original;
4828
+ state2.push = null;
4829
+ }
4830
+ if (state2.replace && history.replaceState === state2.replace.wrapper) {
4831
+ history.replaceState = state2.replace.original;
4832
+ state2.replace = null;
4833
+ }
4309
4834
  };
4310
4835
  }
4311
4836
  });
@@ -4321,36 +4846,37 @@ function installRoute(deps) {
4321
4846
  };
4322
4847
  }
4323
4848
  let handle = null;
4849
+ const surface = {
4850
+ isOpen: () => !deps.isDestroyed() && deps.isOpen(),
4851
+ close: deps.close,
4852
+ markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
4853
+ url: deps.routedTo
4854
+ };
4324
4855
  const onOpen = () => {
4325
4856
  if (handle) return;
4326
- handle = pushBackMarker({
4327
- isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
4328
- isTop: deps.isTopSheet,
4329
- close: deps.close,
4330
- markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
4331
- url: deps.routedTo
4332
- });
4857
+ handle = pushBackMarker(surface);
4333
4858
  };
4334
4859
  const onClose = () => {
4335
4860
  if (!handle) return;
4336
- popBackMarker(handle);
4861
+ deps.hold(popBackMarker(handle));
4337
4862
  handle = null;
4338
4863
  };
4339
4864
  const unsubscribeOpen = deps.on("open", onOpen);
4340
4865
  const unsubscribeClose = deps.on("close", onClose);
4341
- if (deps.getSize() > 0) onOpen();
4866
+ if (deps.isOpen()) onOpen();
4867
+ else releaseOrphanMarker();
4342
4868
  return () => {
4343
4869
  unsubscribeOpen();
4344
4870
  unsubscribeClose();
4345
4871
  if (handle) {
4346
- popBackMarker(handle);
4872
+ void popBackMarker(handle);
4347
4873
  handle = null;
4348
4874
  }
4349
4875
  };
4350
4876
  }
4351
4877
  function installRouteChange(deps) {
4352
4878
  return subscribeRouteChange(() => {
4353
- if (deps.isDestroyed() || deps.getSize() <= 0) return;
4879
+ if (deps.isDestroyed() || !deps.isOpen()) return;
4354
4880
  void deps.close();
4355
4881
  });
4356
4882
  }
@@ -4393,7 +4919,10 @@ function installAutoCollapse(deps) {
4393
4919
  };
4394
4920
  const fire = () => {
4395
4921
  if (deps.isDestroyed()) return;
4396
- if (deps.isDragging()) return;
4922
+ if (deps.isDragging() || deps.isAnimating()) {
4923
+ reset();
4924
+ return;
4925
+ }
4397
4926
  const active = deps.resolveSnap(deps.getActiveId());
4398
4927
  if (!active || active.size === 0) return;
4399
4928
  let target = null;
@@ -4444,43 +4973,47 @@ function installVisualViewport(deps) {
4444
4973
  }
4445
4974
  const vv = window.visualViewport;
4446
4975
  let rafId = null;
4976
+ const coveredByKeyboard = () => {
4977
+ if ((vv.scale || 1) > ZOOMED) return 0;
4978
+ const covered = window.innerHeight - ((vv.offsetTop || 0) + vv.height);
4979
+ return covered >= KEYBOARD_MIN_COVER ? Math.round(covered) : 0;
4980
+ };
4447
4981
  const onResize = () => {
4448
4982
  if (rafId !== null) return;
4449
4983
  rafId = requestAnimationFrame(() => {
4450
4984
  rafId = null;
4451
4985
  if (deps.isDestroyed()) return;
4986
+ deps.setKeyboardInset(coveredByKeyboard());
4987
+ const before = seatOf(deps);
4452
4988
  deps.recomputeSnaps();
4453
4989
  const isVertical = deps.isVerticalAxis();
4454
4990
  const visible = isVertical ? vv.height : vv.width;
4455
4991
  const windowSize = isVertical ? window.innerHeight : window.innerWidth;
4456
- const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
4992
+ const pad = windowSize - visible > KEYBOARD_MIN_INSET ? SAFETY_PAD : 0;
4993
+ const clamp = Math.max(0, Math.min(windowSize, visible) - pad);
4457
4994
  if (clamp < deps.getMaxAxisSize()) {
4458
4995
  deps.setMaxAxisSize(clamp);
4459
4996
  }
4460
- const wasAnimating = deps.isAnimating?.() ?? false;
4461
- deps.cancelInFlight();
4462
- deps.newCycle();
4463
- const max = deps.getMaxAxisSize();
4464
- deps.setSize(Math.min(deps.getSize(), max));
4465
- const current = deps.resolveActiveSnap();
4466
- if (current && !deps.isDragging()) {
4467
- deps.applySize(Math.min(current.size, max));
4468
- if (wasAnimating) deps.resyncAfterCancel?.();
4469
- } else {
4470
- deps.applySize(deps.getSize());
4471
- }
4997
+ if (sameSeat(before, seatOf(deps))) return;
4998
+ deps.reseat();
4472
4999
  });
4473
5000
  };
4474
5001
  vv.addEventListener("resize", onResize);
5002
+ vv.addEventListener("scroll", onResize);
4475
5003
  return () => {
4476
5004
  vv.removeEventListener("resize", onResize);
5005
+ vv.removeEventListener("scroll", onResize);
4477
5006
  if (rafId !== null) cancelAnimationFrame(rafId);
4478
5007
  };
4479
5008
  }
4480
- var SAFETY_PAD;
5009
+ var SAFETY_PAD, KEYBOARD_MIN_INSET, KEYBOARD_MIN_COVER, ZOOMED;
4481
5010
  var init_visual_viewport = __esm({
4482
5011
  "src/core/features/visual-viewport.ts"() {
5012
+ init_resize_observer();
4483
5013
  SAFETY_PAD = 8;
5014
+ KEYBOARD_MIN_INSET = 1;
5015
+ KEYBOARD_MIN_COVER = 60;
5016
+ ZOOMED = 1.01;
4484
5017
  }
4485
5018
  });
4486
5019
 
@@ -4494,7 +5027,7 @@ function routeFeature() {
4494
5027
  teardowns.add(
4495
5028
  installRouteChange({
4496
5029
  isDestroyed: ctx.isDestroyed,
4497
- getSize: ctx.getSize,
5030
+ isOpen: () => ctx.getPhase() !== "closed",
4498
5031
  close: () => ctx.close()
4499
5032
  })
4500
5033
  );
@@ -4503,10 +5036,10 @@ function routeFeature() {
4503
5036
  installRoute({
4504
5037
  routedTo: ctx.options.routedTo,
4505
5038
  closeOnBack: ctx.options.closeOnBack,
4506
- isTopSheet: ctx.isTopSheet,
4507
- getSize: ctx.getSize,
5039
+ isOpen: () => ctx.getPhase() !== "closed",
4508
5040
  isDestroyed: ctx.isDestroyed,
4509
5041
  close: () => ctx.close("back"),
5042
+ hold: ctx.holdSettle,
4510
5043
  on: ctx.on,
4511
5044
  sheetId: ctx.sheetId
4512
5045
  })
@@ -4532,6 +5065,7 @@ function autoCollapseFeature() {
4532
5065
  ms: ctx.options.autoCollapseAfter,
4533
5066
  isDestroyed: ctx.isDestroyed,
4534
5067
  isDragging: ctx.isDragging,
5068
+ isAnimating: ctx.isAnimating,
4535
5069
  getAllowedIds: ctx.getAllowedIds,
4536
5070
  getActiveId: ctx.getActiveId,
4537
5071
  resolveSnap: ctx.resolveSnap,
@@ -4559,21 +5093,14 @@ function visualViewportFeature() {
4559
5093
  install: (ctx) => {
4560
5094
  if (typeof window === "undefined") return;
4561
5095
  return installVisualViewport({
4562
- element: ctx.element,
4563
5096
  isVerticalAxis: ctx.isVerticalAxis,
4564
5097
  isDestroyed: ctx.isDestroyed,
4565
- isDragging: ctx.isDragging,
4566
5098
  recomputeSnaps: ctx.recomputeSnaps,
4567
5099
  resolveActiveSnap: ctx.resolveActiveSnap,
4568
5100
  getMaxAxisSize: ctx.getMaxAxisSize,
4569
- getSize: ctx.getSize,
4570
5101
  setMaxAxisSize: ctx.setMaxAxisSize,
4571
- setSize: ctx.setSize,
4572
- applySize: ctx.applySize,
4573
- cancelInFlight: ctx.cancelInFlight,
4574
- newCycle: ctx.newCycle,
4575
- isAnimating: ctx.isAnimating,
4576
- resyncAfterCancel: ctx.resyncAfterResize
5102
+ setKeyboardInset: ctx.setKeyboardInset,
5103
+ reseat: ctx.reseat
4577
5104
  });
4578
5105
  }
4579
5106
  };
@@ -4766,11 +5293,88 @@ var init_BottomSheetEngine = __esm({
4766
5293
  }
4767
5294
  });
4768
5295
 
5296
+ // src/core/primitives/open-state.ts
5297
+ var closedSnapId, syncOpen;
5298
+ var init_open_state = __esm({
5299
+ "src/core/primitives/open-state.ts"() {
5300
+ closedSnapId = (points) => points.find((point) => point.size === 0)?.id;
5301
+ syncOpen = (engine, open) => {
5302
+ const phase = engine.state.phase;
5303
+ const showing = phase === "open" || phase === "opening";
5304
+ if (open && !showing) void engine.open();
5305
+ else if (!open && showing) void engine.close();
5306
+ };
5307
+ }
5308
+ });
5309
+
5310
+ // src/core/primitives/option-keys.ts
5311
+ var ENGINE_OPTION_KEYS, pickEngineOptions;
5312
+ var init_option_keys = __esm({
5313
+ "src/core/primitives/option-keys.ts"() {
5314
+ ENGINE_OPTION_KEYS = [
5315
+ "mode",
5316
+ "snapPoints",
5317
+ "allowed",
5318
+ "initial",
5319
+ "duration",
5320
+ "easing",
5321
+ "respectReducedMotion",
5322
+ "flickVelocity",
5323
+ "dragThreshold",
5324
+ "dragFrom",
5325
+ "dragFromContent",
5326
+ "fitContentToSnap",
5327
+ "rubberBand",
5328
+ "backdropRange",
5329
+ "backdropOpacity",
5330
+ "backdropColor",
5331
+ "screenRange",
5332
+ "scrimMode",
5333
+ "scrimColor",
5334
+ "scrimBlur",
5335
+ "scrimInteractive",
5336
+ "scrimTapToClose",
5337
+ "scrimPreset",
5338
+ "animation",
5339
+ "settleAnimation",
5340
+ "spring",
5341
+ "focusTrap",
5342
+ "initialFocus",
5343
+ "closeOnEscape",
5344
+ "lockBodyScroll",
5345
+ "closeOnBack",
5346
+ "routedTo",
5347
+ "inertSiblings",
5348
+ "persistent",
5349
+ "disableClose",
5350
+ "disableDrag",
5351
+ "closeOnRouteChange",
5352
+ "radius",
5353
+ "maxHeight",
5354
+ "returnFocusTo",
5355
+ "persistKey",
5356
+ "autoCollapseAfter",
5357
+ "linkedSheets",
5358
+ "viewTransitions",
5359
+ "stackEffect",
5360
+ "features"
5361
+ ];
5362
+ pickEngineOptions = (source) => {
5363
+ const out = {};
5364
+ for (const key of ENGINE_OPTION_KEYS) {
5365
+ const value = source[key];
5366
+ if (value !== void 0) out[key] = value;
5367
+ }
5368
+ return out;
5369
+ };
5370
+ }
5371
+ });
5372
+
4769
5373
  // src/web-component/baseStyles.ts
4770
5374
  var baseStyles;
4771
5375
  var init_baseStyles = __esm({
4772
5376
  "src/web-component/baseStyles.ts"() {
4773
- 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}}`;
5377
+ 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}}`;
4774
5378
  }
4775
5379
  });
4776
5380
 
@@ -4867,9 +5471,11 @@ var init_shadow_tree = __esm({
4867
5471
  });
4868
5472
 
4869
5473
  // src/web-component/attributes.ts
4870
- 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;
5474
+ 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;
4871
5475
  var init_attributes = __esm({
4872
5476
  "src/web-component/attributes.ts"() {
5477
+ init_dev_warn();
5478
+ init_option_keys();
4873
5479
  ATTR_SNAP_POINTS = "snap-points";
4874
5480
  ATTR_ALLOWED = "allowed";
4875
5481
  ATTR_INITIAL = "initial";
@@ -4895,6 +5501,10 @@ var init_attributes = __esm({
4895
5501
  ATTR_BACKDROP_COLOR = "backdrop-color";
4896
5502
  ATTR_SCRIM_COLOR = "scrim-color";
4897
5503
  ATTR_SNAP = "snap";
5504
+ ATTR_OPEN = "open";
5505
+ ATTR_OPTIONS = "options";
5506
+ ATTR_HANDLE_LABEL = "handle-label";
5507
+ ATTR_CONTENT_LABEL = "content-label";
4898
5508
  LIVE_ATTRS = /* @__PURE__ */ new Set([
4899
5509
  ATTR_MODE,
4900
5510
  ATTR_RADIUS,
@@ -4906,7 +5516,10 @@ var init_attributes = __esm({
4906
5516
  ATTR_DISABLE_CLOSE,
4907
5517
  ATTR_DISABLE_DRAG,
4908
5518
  ATTR_DRAG_FROM,
4909
- ATTR_DRAG_FROM_CONTENT
5519
+ ATTR_DRAG_FROM_CONTENT,
5520
+ ATTR_HANDLE_LABEL,
5521
+ ATTR_CONTENT_LABEL,
5522
+ ATTR_OPEN
4910
5523
  ]);
4911
5524
  OBSERVED_ATTRS = [
4912
5525
  ATTR_SNAP_POINTS,
@@ -4932,8 +5545,26 @@ var init_attributes = __esm({
4932
5545
  ATTR_RETURN_FOCUS_TO,
4933
5546
  ATTR_BACKDROP_COLOR,
4934
5547
  ATTR_SCRIM_COLOR,
4935
- ATTR_SNAP
5548
+ ATTR_SNAP,
5549
+ ATTR_OPTIONS,
5550
+ ATTR_HANDLE_LABEL,
5551
+ ATTR_CONTENT_LABEL,
5552
+ ATTR_OPEN
4936
5553
  ];
5554
+ parseOptions = (raw) => {
5555
+ if (!raw) return {};
5556
+ try {
5557
+ const parsed = JSON.parse(raw);
5558
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
5559
+ return pickEngineOptions(parsed);
5560
+ }
5561
+ } catch {
5562
+ }
5563
+ devWarn(
5564
+ `[BottomSheet] options="${raw}" is not a JSON object \u2014 ignored.`
5565
+ );
5566
+ return {};
5567
+ };
4937
5568
  isValidSnapPoint = (p) => !!p && typeof p === "object" && typeof p.id === "string" && (typeof p.size === "number" || typeof p.size === "string");
4938
5569
  DEFAULT_SNAP_POINTS = [{ id: "full", size: "full" }];
4939
5570
  parseSnapPoints = (raw) => {
@@ -4946,18 +5577,36 @@ var init_attributes = __esm({
4946
5577
  if (Array.isArray(parsed)) return DEFAULT_SNAP_POINTS;
4947
5578
  } catch {
4948
5579
  }
4949
- return raw.split(",").map((s) => s.trim()).filter(Boolean).map((part) => {
5580
+ const points = [];
5581
+ for (const part of raw.split(",")) {
4950
5582
  const [id, size] = part.split(":").map((s) => s.trim());
5583
+ if (!id || !size) {
5584
+ if (part.trim()) {
5585
+ devWarn(
5586
+ `[BottomSheet] snap-points entry "${part.trim()}" is not "id:size" \u2014 skipped.`
5587
+ );
5588
+ }
5589
+ continue;
5590
+ }
4951
5591
  const numeric = Number(size);
4952
- const resolvedSize = Number.isFinite(numeric) ? numeric : size;
4953
- return { id: id ?? "default", size: resolvedSize };
4954
- });
5592
+ points.push({
5593
+ id,
5594
+ size: Number.isFinite(numeric) ? numeric : size
5595
+ });
5596
+ }
5597
+ if (points.length > 0) return points;
5598
+ devWarn(
5599
+ `[BottomSheet] snap-points="${raw}" has no usable entry \u2014 falling back to a single full-height snap.`
5600
+ );
5601
+ return DEFAULT_SNAP_POINTS;
4955
5602
  };
4956
5603
  VALID_MODES = [
4957
5604
  "bottom",
4958
5605
  "top",
4959
5606
  "left",
4960
- "right"
5607
+ "right",
5608
+ "start",
5609
+ "end"
4961
5610
  ];
4962
5611
  VALID_ANIMATIONS = ["spring", "tween", "ios-spring", "material-bounce", "linear", "snappy"];
4963
5612
  parseMode = (raw) => raw && VALID_MODES.includes(raw) ? raw : "bottom";
@@ -5025,6 +5674,9 @@ var BaseHTMLElement, BottomSheetElement, defineBottomSheet;
5025
5674
  var init_BottomSheetElement = __esm({
5026
5675
  "src/web-component/BottomSheetElement.ts"() {
5027
5676
  init_BottomSheetEngine();
5677
+ init_logical_mode();
5678
+ init_open_state();
5679
+ init_option_keys();
5028
5680
  init_baseStyles();
5029
5681
  init_shadow_tree();
5030
5682
  init_attributes();
@@ -5041,6 +5693,7 @@ var init_BottomSheetElement = __esm({
5041
5693
  __publicField(this, "stylesheetLinked", false);
5042
5694
  __publicField(this, "declarativeAnchors", []);
5043
5695
  __publicField(this, "lastActiveId", null);
5696
+ __publicField(this, "extraOptions", {});
5044
5697
  this.root = this.attachShadow({ mode: "open" });
5045
5698
  const baseStyle = document.createElement("style");
5046
5699
  baseStyle.textContent = baseStyles;
@@ -5065,7 +5718,21 @@ var init_BottomSheetElement = __esm({
5065
5718
  static get observedAttributes() {
5066
5719
  return OBSERVED_ATTRS.slice();
5067
5720
  }
5721
+ get options() {
5722
+ return this.extraOptions;
5723
+ }
5724
+ set options(value) {
5725
+ this.extraOptions = value ? pickEngineOptions(value) : {};
5726
+ if (!this.engine) return;
5727
+ this.teardownEngine();
5728
+ this.initEngine();
5729
+ }
5068
5730
  connectedCallback() {
5731
+ if (Object.prototype.hasOwnProperty.call(this, "options")) {
5732
+ const early = this.options;
5733
+ delete this.options;
5734
+ this.options = early;
5735
+ }
5069
5736
  if (!this.stylesheetLinked) {
5070
5737
  this.stylesheetLinked = true;
5071
5738
  const stylesheet = this.getAttribute(ATTR_STYLESHEET);
@@ -5081,8 +5748,8 @@ var init_BottomSheetElement = __esm({
5081
5748
  disconnectedCallback() {
5082
5749
  this.teardownEngine();
5083
5750
  }
5084
- attributeChangedCallback(name, _old, value) {
5085
- if (!this.engine) return;
5751
+ attributeChangedCallback(name, old, value) {
5752
+ if (!this.engine || old === value) return;
5086
5753
  if (LIVE_ATTRS.has(name)) {
5087
5754
  this.applyLiveAttribute(name, value);
5088
5755
  return;
@@ -5104,6 +5771,8 @@ var init_BottomSheetElement = __esm({
5104
5771
  break;
5105
5772
  }
5106
5773
  case ATTR_BACKDROP_COLOR:
5774
+ this.engine.setBackdropColor(value);
5775
+ break;
5107
5776
  case ATTR_SCRIM_COLOR:
5108
5777
  this.engine.setScrimColor(value);
5109
5778
  break;
@@ -5126,12 +5795,20 @@ var init_BottomSheetElement = __esm({
5126
5795
  }
5127
5796
  case ATTR_MODE:
5128
5797
  this.engine.setMode(parseMode(value));
5798
+ this.writeMode(this.engine.getMode());
5129
5799
  break;
5130
5800
  case ATTR_SNAP:
5131
5801
  if (value && value !== this.engine.state.activeId) {
5132
5802
  void this.engine.snapTo(value);
5133
5803
  }
5134
5804
  break;
5805
+ case ATTR_HANDLE_LABEL:
5806
+ case ATTR_CONTENT_LABEL:
5807
+ this.writeLabels();
5808
+ break;
5809
+ case ATTR_OPEN:
5810
+ syncOpen(this.engine, value !== null && value !== "false");
5811
+ break;
5135
5812
  }
5136
5813
  }
5137
5814
  getEngine() {
@@ -5145,20 +5822,51 @@ var init_BottomSheetElement = __esm({
5145
5822
  this.refs.backdrop.removeEventListener("click", this.backdropClickHandler);
5146
5823
  this.backdropClickHandler = null;
5147
5824
  }
5148
- this.engine?.destroy();
5149
- this.engine = null;
5150
- for (const el of this.declarativeAnchors) {
5151
- this.appendChild(el);
5825
+ for (const anchor of this.declarativeAnchors) {
5826
+ anchor.detach();
5827
+ anchor.el.setAttribute("slot", "anchor");
5152
5828
  }
5153
5829
  this.declarativeAnchors = [];
5830
+ this.engine?.destroy();
5831
+ this.engine = null;
5154
5832
  }
5155
- initEngine() {
5156
- const { sheet, handle, content, backdrop, announcer } = this.refs;
5157
- const mode = parseMode(this.getAttribute(ATTR_MODE));
5158
- sheet.setAttribute("data-mode", mode);
5833
+ reflectOpen(open) {
5834
+ const raw = this.getAttribute(ATTR_OPEN);
5835
+ if (open === (raw !== null && raw !== "false")) return;
5836
+ if (open) this.setAttribute(ATTR_OPEN, "");
5837
+ else this.removeAttribute(ATTR_OPEN);
5838
+ }
5839
+ writeLabels() {
5840
+ this.refs.handle.setAttribute(
5841
+ "aria-label",
5842
+ this.getAttribute(ATTR_HANDLE_LABEL) ?? "Resize sheet"
5843
+ );
5844
+ this.refs.content.setAttribute(
5845
+ "aria-label",
5846
+ this.getAttribute(ATTR_CONTENT_LABEL) ?? "Sheet content"
5847
+ );
5848
+ }
5849
+ writeMode(mode) {
5850
+ this.refs.sheet.setAttribute("data-mode", mode);
5159
5851
  this.refs.leftButton.setAttribute("data-mode", mode);
5160
5852
  this.refs.rightButton.setAttribute("data-mode", mode);
5161
- const focusTrap = this.getAttribute(ATTR_FOCUS_TRAP) === "true";
5853
+ }
5854
+ initEngine() {
5855
+ const { sheet, handle, content, backdrop, announcer } = this.refs;
5856
+ const extra = {
5857
+ ...this.extraOptions,
5858
+ ...parseOptions(this.getAttribute(ATTR_OPTIONS))
5859
+ };
5860
+ const given = (name, read) => {
5861
+ const raw = this.getAttribute(name);
5862
+ return raw === null ? void 0 : read(raw);
5863
+ };
5864
+ const isTrue = (raw) => raw === "true";
5865
+ const notFalse = (raw) => raw !== "false";
5866
+ const mode = given(ATTR_MODE, parseMode) ?? extra.mode ?? parseMode(null);
5867
+ this.writeMode(guessPhysicalMode(mode));
5868
+ this.writeLabels();
5869
+ const focusTrap = given(ATTR_FOCUS_TRAP, isTrue) ?? extra.focusTrap ?? false;
5162
5870
  if (focusTrap) {
5163
5871
  sheet.setAttribute("aria-modal", "true");
5164
5872
  } else {
@@ -5176,10 +5884,12 @@ var init_BottomSheetElement = __esm({
5176
5884
  };
5177
5885
  backdrop.addEventListener("click", this.backdropClickHandler);
5178
5886
  }
5179
- const snapPoints = parseSnapPoints(this.getAttribute(ATTR_SNAP_POINTS));
5180
- const initialAttr = this.getAttribute(ATTR_INITIAL) ?? void 0;
5181
- const initial = this.lastActiveId && snapPoints.some((p) => p.id === this.lastActiveId) ? this.lastActiveId : initialAttr;
5887
+ const snapPoints = given(ATTR_SNAP_POINTS, parseSnapPoints) ?? extra.snapPoints ?? parseSnapPoints(null);
5888
+ const known = (id) => id !== null && snapPoints.some((p) => p.id === id);
5889
+ const snapAttr = this.getAttribute(ATTR_SNAP);
5890
+ 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);
5182
5891
  const opts = {
5892
+ ...extra,
5183
5893
  element: sheet,
5184
5894
  handle,
5185
5895
  scrollContainer: content,
@@ -5187,34 +5897,48 @@ var init_BottomSheetElement = __esm({
5187
5897
  scrim: this.refs.screen,
5188
5898
  mode,
5189
5899
  snapPoints,
5190
- allowed: parseList(this.getAttribute(ATTR_ALLOWED)),
5900
+ allowed: given(ATTR_ALLOWED, parseList) ?? extra.allowed,
5191
5901
  initial,
5192
- animation: parseAnimation(this.getAttribute(ATTR_ANIMATION)),
5902
+ animation: given(ATTR_ANIMATION, parseAnimation) ?? extra.animation,
5193
5903
  focusTrap,
5194
- closeOnEscape: this.getAttribute(ATTR_CLOSE_ON_ESCAPE) !== "false",
5195
- lockBodyScroll: this.getAttribute(ATTR_LOCK_BODY_SCROLL) !== "false",
5196
- stackEffect: this.getAttribute(ATTR_STACK_EFFECT) === "true",
5197
- persistent: this.getAttribute(ATTR_PERSISTENT) === "true",
5198
- disableClose: this.getAttribute(ATTR_DISABLE_CLOSE) === "true",
5199
- disableDrag: this.getAttribute(ATTR_DISABLE_DRAG) === "true",
5200
- dragFrom: parseDragFrom(this.getAttribute(ATTR_DRAG_FROM)),
5201
- dragFromContent: this.getAttribute(ATTR_DRAG_FROM_CONTENT) === null ? void 0 : this.getAttribute(ATTR_DRAG_FROM_CONTENT) !== "false",
5202
- fitContentToSnap: this.hasAttribute(ATTR_FIT_CONTENT_TO_SNAP) && this.getAttribute(ATTR_FIT_CONTENT_TO_SNAP) !== "false",
5203
- closeOnRouteChange: this.getAttribute(ATTR_CLOSE_ON_ROUTE_CHANGE) === "true",
5204
- radius: parseDimension(this.getAttribute(ATTR_RADIUS)),
5205
- maxHeight: parseDimension(this.getAttribute(ATTR_MAX_HEIGHT)),
5206
- returnFocusTo: this.getAttribute(ATTR_RETURN_FOCUS_TO) ?? void 0
5904
+ closeOnEscape: given(ATTR_CLOSE_ON_ESCAPE, notFalse) ?? extra.closeOnEscape,
5905
+ lockBodyScroll: given(ATTR_LOCK_BODY_SCROLL, notFalse) ?? extra.lockBodyScroll,
5906
+ stackEffect: given(ATTR_STACK_EFFECT, isTrue) ?? extra.stackEffect,
5907
+ persistent: given(ATTR_PERSISTENT, isTrue) ?? extra.persistent,
5908
+ disableClose: given(ATTR_DISABLE_CLOSE, isTrue) ?? extra.disableClose,
5909
+ disableDrag: given(ATTR_DISABLE_DRAG, isTrue) ?? extra.disableDrag,
5910
+ dragFrom: given(ATTR_DRAG_FROM, parseDragFrom) ?? extra.dragFrom,
5911
+ dragFromContent: given(ATTR_DRAG_FROM_CONTENT, notFalse) ?? extra.dragFromContent,
5912
+ fitContentToSnap: given(ATTR_FIT_CONTENT_TO_SNAP, notFalse) ?? extra.fitContentToSnap,
5913
+ closeOnRouteChange: given(ATTR_CLOSE_ON_ROUTE_CHANGE, isTrue) ?? extra.closeOnRouteChange,
5914
+ radius: given(ATTR_RADIUS, parseDimension) ?? extra.radius,
5915
+ maxHeight: given(ATTR_MAX_HEIGHT, parseDimension) ?? extra.maxHeight,
5916
+ returnFocusTo: this.getAttribute(ATTR_RETURN_FOCUS_TO) ?? extra.returnFocusTo,
5917
+ backdropColor: this.getAttribute(ATTR_BACKDROP_COLOR) ?? extra.backdropColor,
5918
+ scrimColor: this.getAttribute(ATTR_SCRIM_COLOR) ?? extra.scrimColor
5207
5919
  };
5208
5920
  this.engine = new BottomSheetEngine(opts);
5921
+ const wanted = this.getAttribute(ATTR_OPEN);
5922
+ if (wanted !== null) syncOpen(this.engine, wanted !== "false");
5923
+ this.reflectOpen(this.engine.state.phase !== "closed");
5924
+ this.writeMode(this.engine.getMode());
5209
5925
  sheet.setAttribute("data-active", this.engine.state.activeId);
5210
- const scrimColor = this.getAttribute(ATTR_SCRIM_COLOR) ?? this.getAttribute(ATTR_BACKDROP_COLOR);
5211
- if (scrimColor !== null) this.engine.setScrimColor(scrimColor);
5212
- for (const el of Array.from(
5213
- this.querySelectorAll('[slot="anchor"]')
5214
- )) {
5215
- this.declarativeAnchors.push(el);
5216
- this.engine.addAnchor({ ...parseAnchorOptions(el), element: el });
5217
- }
5926
+ const anchors = Array.from(this.children).filter(
5927
+ (child) => child.getAttribute("slot") === "anchor"
5928
+ );
5929
+ anchors.forEach((el, index) => {
5930
+ const name = `bs-anchor-${index}`;
5931
+ const host = document.createElement("div");
5932
+ const slot = document.createElement("slot");
5933
+ slot.name = name;
5934
+ host.appendChild(slot);
5935
+ el.setAttribute("slot", name);
5936
+ const detach = this.engine.addAnchor({
5937
+ ...parseAnchorOptions(el),
5938
+ element: host
5939
+ });
5940
+ this.declarativeAnchors.push({ el, detach });
5941
+ });
5218
5942
  this.offHandlers = [
5219
5943
  this.engine.on("snap", (payload) => {
5220
5944
  sheet.setAttribute("data-active", payload.id);
@@ -5230,14 +5954,14 @@ var init_BottomSheetElement = __esm({
5230
5954
  );
5231
5955
  if (!accepted) payload.cancel();
5232
5956
  }),
5233
- this.engine.on(
5234
- "open",
5235
- (payload) => this.dispatchEvent(new CustomEvent("open", { detail: payload }))
5236
- ),
5237
- this.engine.on(
5238
- "close",
5239
- () => this.dispatchEvent(new CustomEvent("close"))
5240
- ),
5957
+ this.engine.on("open", (payload) => {
5958
+ this.reflectOpen(true);
5959
+ this.dispatchEvent(new CustomEvent("open", { detail: payload }));
5960
+ }),
5961
+ this.engine.on("close", () => {
5962
+ this.reflectOpen(false);
5963
+ this.dispatchEvent(new CustomEvent("close"));
5964
+ }),
5241
5965
  this.engine.on(
5242
5966
  "progress",
5243
5967
  (payload) => this.dispatchEvent(new CustomEvent("progress", { detail: payload }))
@@ -5317,6 +6041,11 @@ var init_BottomSheetElement = __esm({
5317
6041
  recompute() {
5318
6042
  this.engine?.recompute();
5319
6043
  }
6044
+ setMode(mode) {
6045
+ if (!this.engine) return;
6046
+ this.engine.setMode(mode);
6047
+ this.writeMode(this.engine.getMode());
6048
+ }
5320
6049
  get sheetState() {
5321
6050
  return this.engine?.state ?? null;
5322
6051
  }