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