@surdeddd/bottom-sheet 0.23.4 → 0.24.0

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