@surdeddd/bottom-sheet 0.4.0 → 0.5.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 (41) hide show
  1. package/dist/{BottomSheetEngine-L05jGZvU.d.ts → BottomSheetEngine-BHjKFtnM.d.ts} +2 -0
  2. package/dist/{BottomSheetEngine-BJrH7qY3.d.cts → BottomSheetEngine-CqiCz64W.d.cts} +2 -0
  3. package/dist/element.cjs +120 -13
  4. package/dist/element.d.cts +1 -1
  5. package/dist/element.d.ts +1 -1
  6. package/dist/element.iife.global.js +2 -2
  7. package/dist/element.js +120 -13
  8. package/dist/index.cjs +97 -8
  9. package/dist/index.d.cts +2 -2
  10. package/dist/index.d.ts +2 -2
  11. package/dist/index.js +97 -8
  12. package/dist/integrations/formik.d.cts +1 -1
  13. package/dist/integrations/formik.d.ts +1 -1
  14. package/dist/integrations/react-hook-form.d.cts +1 -1
  15. package/dist/integrations/react-hook-form.d.ts +1 -1
  16. package/dist/preact.d.cts +1 -1
  17. package/dist/preact.d.ts +1 -1
  18. package/dist/qwik.cjs +100 -10
  19. package/dist/qwik.d.cts +2 -2
  20. package/dist/qwik.d.ts +2 -2
  21. package/dist/qwik.js +100 -10
  22. package/dist/react.cjs +119 -12
  23. package/dist/react.d.cts +4 -2
  24. package/dist/react.d.ts +4 -2
  25. package/dist/react.js +119 -12
  26. package/dist/solid.cjs +128 -18
  27. package/dist/solid.d.cts +3 -0
  28. package/dist/solid.d.ts +3 -0
  29. package/dist/solid.js +130 -20
  30. package/dist/solid.source.jsx +106 -12
  31. package/dist/styles.css +34 -5
  32. package/dist/svelte-core.cjs +97 -8
  33. package/dist/svelte-core.js +97 -8
  34. package/dist/svelte-src/BottomSheet.svelte +15 -13
  35. package/dist/svelte.cjs +159 -53
  36. package/dist/svelte.d.cts +1 -0
  37. package/dist/svelte.d.ts +1 -0
  38. package/dist/svelte.js +159 -53
  39. package/dist/vue.cjs +126 -30
  40. package/dist/vue.js +126 -30
  41. package/package.json +3 -3
@@ -5,7 +5,8 @@ import {
5
5
  createEffect,
6
6
  on,
7
7
  onCleanup,
8
- onMount
8
+ onMount,
9
+ Show
9
10
  } from "solid-js";
10
11
 
11
12
  // src/core/lifecycle/sheetStack.ts
@@ -2897,11 +2898,54 @@ var BottomSheetEngine = class {
2897
2898
  this.updateAriaSlider();
2898
2899
  }
2899
2900
  }
2901
+ contentTargets() {
2902
+ const scroller = this.scrollContainer;
2903
+ if (!scroller) return [];
2904
+ const hasSlot = typeof HTMLSlotElement !== "undefined";
2905
+ const out = [];
2906
+ for (const child of Array.from(scroller.children)) {
2907
+ if (hasSlot && child instanceof HTMLSlotElement) {
2908
+ for (const el of child.assignedElements()) out.push(el);
2909
+ } else {
2910
+ out.push(child);
2911
+ }
2912
+ }
2913
+ return out;
2914
+ }
2915
+ measureContentExtent(vertical) {
2916
+ const content = this.scrollContainer;
2917
+ if (!content) return 0;
2918
+ const targets = this.contentTargets();
2919
+ if (targets.length === 0) {
2920
+ return vertical ? content.scrollHeight : content.scrollWidth;
2921
+ }
2922
+ let min = Infinity;
2923
+ let max = -Infinity;
2924
+ for (const el of targets) {
2925
+ const r = el.getBoundingClientRect();
2926
+ if (vertical) {
2927
+ if (r.top < min) min = r.top;
2928
+ if (r.bottom > max) max = r.bottom;
2929
+ } else {
2930
+ if (r.left < min) min = r.left;
2931
+ if (r.right > max) max = r.right;
2932
+ }
2933
+ }
2934
+ if (!isFinite(min) || !isFinite(max) || max <= min) {
2935
+ return vertical ? content.scrollHeight : content.scrollWidth;
2936
+ }
2937
+ let pad = 0;
2938
+ if (typeof getComputedStyle !== "undefined") {
2939
+ const cs = getComputedStyle(content);
2940
+ pad = vertical ? (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.paddingBottom) || 0) : (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.paddingRight) || 0);
2941
+ }
2942
+ return max - min + pad;
2943
+ }
2900
2944
  measureFitSize() {
2901
2945
  const vertical = layoutAxis(this.mode) === "height";
2902
2946
  const handleSize = vertical ? this.handle.offsetHeight : this.handle.offsetWidth;
2903
2947
  const content = this.scrollContainer;
2904
- const natural = content ? handleSize + (vertical ? content.scrollHeight : content.scrollWidth) : handleSize;
2948
+ const natural = content ? handleSize + this.measureContentExtent(vertical) : handleSize;
2905
2949
  if (typeof window === "undefined") return natural;
2906
2950
  const viewport = vertical ? window.innerHeight : window.innerWidth;
2907
2951
  return viewport > 0 ? Math.min(natural, viewport) : natural;
@@ -2910,22 +2954,62 @@ var BottomSheetEngine = class {
2910
2954
  if (typeof ResizeObserver === "undefined") return;
2911
2955
  if (!this.snapPointsRaw.some((p) => p.size === "fit" || p.size === "content"))
2912
2956
  return;
2913
- const targets = [this.handle];
2914
- if (this.scrollContainer && this.scrollContainer !== this.handle) {
2915
- targets.push(this.scrollContainer);
2916
- }
2917
2957
  let raf = 0;
2918
- const ro = new ResizeObserver(() => {
2958
+ const schedule = () => {
2919
2959
  if (raf) return;
2920
2960
  raf = requestAnimationFrame(() => {
2921
2961
  raf = 0;
2922
2962
  if (this.destroyed || this.gesture?.isDragging) return;
2923
2963
  this.recompute();
2924
2964
  });
2925
- });
2926
- for (const t of targets) ro.observe(t);
2965
+ };
2966
+ const ro = new ResizeObserver(schedule);
2967
+ ro.observe(this.handle);
2968
+ const scroller = this.scrollContainer;
2969
+ const observed = /* @__PURE__ */ new Set();
2970
+ const slots = /* @__PURE__ */ new Set();
2971
+ const hasSlot = typeof HTMLSlotElement !== "undefined";
2972
+ const onSlotChange = () => resync();
2973
+ const trackSlots = () => {
2974
+ if (!scroller || !hasSlot) return;
2975
+ for (const child of Array.from(scroller.children)) {
2976
+ if (child instanceof HTMLSlotElement && !slots.has(child)) {
2977
+ child.addEventListener("slotchange", onSlotChange);
2978
+ slots.add(child);
2979
+ }
2980
+ }
2981
+ };
2982
+ const resync = () => {
2983
+ trackSlots();
2984
+ const targets = this.contentTargets();
2985
+ for (const el of observed) {
2986
+ if (!targets.includes(el)) {
2987
+ ro.unobserve(el);
2988
+ observed.delete(el);
2989
+ }
2990
+ }
2991
+ for (const el of targets) {
2992
+ if (!observed.has(el)) {
2993
+ ro.observe(el);
2994
+ observed.add(el);
2995
+ }
2996
+ }
2997
+ schedule();
2998
+ };
2999
+ let mo;
3000
+ if (scroller) {
3001
+ resync();
3002
+ if (typeof MutationObserver !== "undefined") {
3003
+ mo = new MutationObserver(resync);
3004
+ mo.observe(scroller, { childList: true });
3005
+ }
3006
+ }
2927
3007
  this.teardowns.add(() => {
2928
3008
  ro.disconnect();
3009
+ mo?.disconnect();
3010
+ for (const slot of slots) {
3011
+ slot.removeEventListener("slotchange", onSlotChange);
3012
+ }
2929
3013
  if (raf) cancelAnimationFrame(raf);
2930
3014
  });
2931
3015
  }
@@ -3273,6 +3357,9 @@ var BottomSheetEngine = class {
3273
3357
  if (this.anchorHost && this.anchorHost !== this.scrimParent) {
3274
3358
  this.anchorHost.style.setProperty("--bs-size", `${size}px`);
3275
3359
  }
3360
+ if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
3361
+ this.rootEl.style.setProperty("--bs-size", `${size}px`);
3362
+ }
3276
3363
  }
3277
3364
  const progress = this.computeProgress(size);
3278
3365
  const progressChanged = this.progressWriteSentinel.shouldWrite(
@@ -3284,6 +3371,9 @@ var BottomSheetEngine = class {
3284
3371
  if (this.anchorHost) {
3285
3372
  this.anchorHost.style.setProperty("--bs-progress", String(progress));
3286
3373
  }
3374
+ if (this.rootEl && this.rootEl !== this.anchorHost) {
3375
+ this.rootEl.style.setProperty("--bs-progress", String(progress));
3376
+ }
3287
3377
  }
3288
3378
  this.scrim.applyOpacity(progress, progressChanged);
3289
3379
  if (progressChanged && this.bus.listenerCount("progress") > 0) {
@@ -3453,9 +3543,10 @@ var BottomSheet = (props) => {
3453
3543
  role="slider"
3454
3544
  tabIndex={0}
3455
3545
  aria-label="Resize sheet"
3456
- >
3457
- {props.header}
3458
- </div>
3546
+ />
3547
+ <Show when={props.header}>
3548
+ <div class="bs-header">{props.header}</div>
3549
+ </Show>
3459
3550
  <div
3460
3551
  class="bs-content"
3461
3552
  ref={(el) => contentEl = el}
@@ -3465,6 +3556,9 @@ var BottomSheet = (props) => {
3465
3556
  >
3466
3557
  {props.children}
3467
3558
  </div>
3559
+ <Show when={props.footer}>
3560
+ <div class="bs-footer">{props.footer}</div>
3561
+ </Show>
3468
3562
  <span class="bs-sr-only" role="status" aria-live="polite">
3469
3563
  {state().activeId}
3470
3564
  </span>
package/dist/styles.css CHANGED
@@ -244,6 +244,12 @@
244
244
  margin-left: calc(-1 * (var(--bs-handle-height) + 6px));
245
245
  }
246
246
 
247
+ .bs-header {
248
+ flex: 0 0 auto;
249
+ padding: 0 16px 8px;
250
+ background: var(--bs-surface, var(--bs-surface-d));
251
+ }
252
+
247
253
  .bs-content {
248
254
  flex: 1;
249
255
  min-height: 0;
@@ -261,6 +267,17 @@
261
267
  background: var(--bs-surface, var(--bs-surface-d));
262
268
  }
263
269
 
270
+ .bs-sheet[data-mode="bottom"]:has(.bs-footer:not([hidden]):has(*)) {
271
+ padding-bottom: 0;
272
+ }
273
+
274
+ .bs-header:not(:has(*)),
275
+ .bs-footer:not(:has(*)),
276
+ .bs-header[hidden],
277
+ .bs-footer[hidden] {
278
+ display: none;
279
+ }
280
+
264
281
  .bs-screen {
265
282
  position: absolute;
266
283
  inset: 0;
@@ -282,21 +299,33 @@
282
299
  }
283
300
 
284
301
  .bs-button-slot {
285
- position: absolute;
302
+ position: fixed;
286
303
  z-index: calc(var(--bs-z-sheet) + 1);
287
304
  pointer-events: auto;
288
305
  }
289
306
  .bs-button-slot[data-side="left"] {
290
307
  left: 16px;
291
- bottom: calc(100% + 12px);
308
+ bottom: calc(var(--bs-size, 0px) + 12px);
292
309
  }
293
310
  .bs-button-slot[data-side="right"] {
294
311
  right: 16px;
295
- bottom: calc(100% + 12px);
312
+ bottom: calc(var(--bs-size, 0px) + 12px);
313
+ }
314
+ .bs-button-slot[data-mode="top"] {
315
+ bottom: auto;
316
+ top: calc(var(--bs-size, 0px) + 12px);
317
+ }
318
+ .bs-button-slot[data-mode="left"] {
319
+ left: calc(var(--bs-size, 0px) + 12px);
320
+ right: auto;
321
+ bottom: auto;
322
+ top: 16px;
296
323
  }
297
- .bs-sheet[data-mode="top"] .bs-button-slot {
324
+ .bs-button-slot[data-mode="right"] {
325
+ right: calc(var(--bs-size, 0px) + 12px);
326
+ left: auto;
298
327
  bottom: auto;
299
- top: calc(100% + 12px);
328
+ top: 16px;
300
329
  }
301
330
 
302
331
  @media (prefers-reduced-motion: reduce) {
@@ -2897,11 +2897,54 @@ var BottomSheetEngine = class {
2897
2897
  this.updateAriaSlider();
2898
2898
  }
2899
2899
  }
2900
+ contentTargets() {
2901
+ const scroller = this.scrollContainer;
2902
+ if (!scroller) return [];
2903
+ const hasSlot = typeof HTMLSlotElement !== "undefined";
2904
+ const out = [];
2905
+ for (const child of Array.from(scroller.children)) {
2906
+ if (hasSlot && child instanceof HTMLSlotElement) {
2907
+ for (const el of child.assignedElements()) out.push(el);
2908
+ } else {
2909
+ out.push(child);
2910
+ }
2911
+ }
2912
+ return out;
2913
+ }
2914
+ measureContentExtent(vertical) {
2915
+ const content = this.scrollContainer;
2916
+ if (!content) return 0;
2917
+ const targets = this.contentTargets();
2918
+ if (targets.length === 0) {
2919
+ return vertical ? content.scrollHeight : content.scrollWidth;
2920
+ }
2921
+ let min = Infinity;
2922
+ let max = -Infinity;
2923
+ for (const el of targets) {
2924
+ const r = el.getBoundingClientRect();
2925
+ if (vertical) {
2926
+ if (r.top < min) min = r.top;
2927
+ if (r.bottom > max) max = r.bottom;
2928
+ } else {
2929
+ if (r.left < min) min = r.left;
2930
+ if (r.right > max) max = r.right;
2931
+ }
2932
+ }
2933
+ if (!isFinite(min) || !isFinite(max) || max <= min) {
2934
+ return vertical ? content.scrollHeight : content.scrollWidth;
2935
+ }
2936
+ let pad = 0;
2937
+ if (typeof getComputedStyle !== "undefined") {
2938
+ const cs = getComputedStyle(content);
2939
+ pad = vertical ? (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.paddingBottom) || 0) : (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.paddingRight) || 0);
2940
+ }
2941
+ return max - min + pad;
2942
+ }
2900
2943
  measureFitSize() {
2901
2944
  const vertical = layoutAxis(this.mode) === "height";
2902
2945
  const handleSize = vertical ? this.handle.offsetHeight : this.handle.offsetWidth;
2903
2946
  const content = this.scrollContainer;
2904
- const natural = content ? handleSize + (vertical ? content.scrollHeight : content.scrollWidth) : handleSize;
2947
+ const natural = content ? handleSize + this.measureContentExtent(vertical) : handleSize;
2905
2948
  if (typeof window === "undefined") return natural;
2906
2949
  const viewport = vertical ? window.innerHeight : window.innerWidth;
2907
2950
  return viewport > 0 ? Math.min(natural, viewport) : natural;
@@ -2910,22 +2953,62 @@ var BottomSheetEngine = class {
2910
2953
  if (typeof ResizeObserver === "undefined") return;
2911
2954
  if (!this.snapPointsRaw.some((p) => p.size === "fit" || p.size === "content"))
2912
2955
  return;
2913
- const targets = [this.handle];
2914
- if (this.scrollContainer && this.scrollContainer !== this.handle) {
2915
- targets.push(this.scrollContainer);
2916
- }
2917
2956
  let raf = 0;
2918
- const ro = new ResizeObserver(() => {
2957
+ const schedule = () => {
2919
2958
  if (raf) return;
2920
2959
  raf = requestAnimationFrame(() => {
2921
2960
  raf = 0;
2922
2961
  if (this.destroyed || this.gesture?.isDragging) return;
2923
2962
  this.recompute();
2924
2963
  });
2925
- });
2926
- for (const t of targets) ro.observe(t);
2964
+ };
2965
+ const ro = new ResizeObserver(schedule);
2966
+ ro.observe(this.handle);
2967
+ const scroller = this.scrollContainer;
2968
+ const observed = /* @__PURE__ */ new Set();
2969
+ const slots = /* @__PURE__ */ new Set();
2970
+ const hasSlot = typeof HTMLSlotElement !== "undefined";
2971
+ const onSlotChange = () => resync();
2972
+ const trackSlots = () => {
2973
+ if (!scroller || !hasSlot) return;
2974
+ for (const child of Array.from(scroller.children)) {
2975
+ if (child instanceof HTMLSlotElement && !slots.has(child)) {
2976
+ child.addEventListener("slotchange", onSlotChange);
2977
+ slots.add(child);
2978
+ }
2979
+ }
2980
+ };
2981
+ const resync = () => {
2982
+ trackSlots();
2983
+ const targets = this.contentTargets();
2984
+ for (const el of observed) {
2985
+ if (!targets.includes(el)) {
2986
+ ro.unobserve(el);
2987
+ observed.delete(el);
2988
+ }
2989
+ }
2990
+ for (const el of targets) {
2991
+ if (!observed.has(el)) {
2992
+ ro.observe(el);
2993
+ observed.add(el);
2994
+ }
2995
+ }
2996
+ schedule();
2997
+ };
2998
+ let mo;
2999
+ if (scroller) {
3000
+ resync();
3001
+ if (typeof MutationObserver !== "undefined") {
3002
+ mo = new MutationObserver(resync);
3003
+ mo.observe(scroller, { childList: true });
3004
+ }
3005
+ }
2927
3006
  this.teardowns.add(() => {
2928
3007
  ro.disconnect();
3008
+ mo?.disconnect();
3009
+ for (const slot of slots) {
3010
+ slot.removeEventListener("slotchange", onSlotChange);
3011
+ }
2929
3012
  if (raf) cancelAnimationFrame(raf);
2930
3013
  });
2931
3014
  }
@@ -3273,6 +3356,9 @@ var BottomSheetEngine = class {
3273
3356
  if (this.anchorHost && this.anchorHost !== this.scrimParent) {
3274
3357
  this.anchorHost.style.setProperty("--bs-size", `${size}px`);
3275
3358
  }
3359
+ if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
3360
+ this.rootEl.style.setProperty("--bs-size", `${size}px`);
3361
+ }
3276
3362
  }
3277
3363
  const progress = this.computeProgress(size);
3278
3364
  const progressChanged = this.progressWriteSentinel.shouldWrite(
@@ -3284,6 +3370,9 @@ var BottomSheetEngine = class {
3284
3370
  if (this.anchorHost) {
3285
3371
  this.anchorHost.style.setProperty("--bs-progress", String(progress));
3286
3372
  }
3373
+ if (this.rootEl && this.rootEl !== this.anchorHost) {
3374
+ this.rootEl.style.setProperty("--bs-progress", String(progress));
3375
+ }
3287
3376
  }
3288
3377
  this.scrim.applyOpacity(progress, progressChanged);
3289
3378
  if (progressChanged && this.bus.listenerCount("progress") > 0) {
@@ -2895,11 +2895,54 @@ var BottomSheetEngine = class {
2895
2895
  this.updateAriaSlider();
2896
2896
  }
2897
2897
  }
2898
+ contentTargets() {
2899
+ const scroller = this.scrollContainer;
2900
+ if (!scroller) return [];
2901
+ const hasSlot = typeof HTMLSlotElement !== "undefined";
2902
+ const out = [];
2903
+ for (const child of Array.from(scroller.children)) {
2904
+ if (hasSlot && child instanceof HTMLSlotElement) {
2905
+ for (const el of child.assignedElements()) out.push(el);
2906
+ } else {
2907
+ out.push(child);
2908
+ }
2909
+ }
2910
+ return out;
2911
+ }
2912
+ measureContentExtent(vertical) {
2913
+ const content = this.scrollContainer;
2914
+ if (!content) return 0;
2915
+ const targets = this.contentTargets();
2916
+ if (targets.length === 0) {
2917
+ return vertical ? content.scrollHeight : content.scrollWidth;
2918
+ }
2919
+ let min = Infinity;
2920
+ let max = -Infinity;
2921
+ for (const el of targets) {
2922
+ const r = el.getBoundingClientRect();
2923
+ if (vertical) {
2924
+ if (r.top < min) min = r.top;
2925
+ if (r.bottom > max) max = r.bottom;
2926
+ } else {
2927
+ if (r.left < min) min = r.left;
2928
+ if (r.right > max) max = r.right;
2929
+ }
2930
+ }
2931
+ if (!isFinite(min) || !isFinite(max) || max <= min) {
2932
+ return vertical ? content.scrollHeight : content.scrollWidth;
2933
+ }
2934
+ let pad = 0;
2935
+ if (typeof getComputedStyle !== "undefined") {
2936
+ const cs = getComputedStyle(content);
2937
+ pad = vertical ? (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.paddingBottom) || 0) : (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.paddingRight) || 0);
2938
+ }
2939
+ return max - min + pad;
2940
+ }
2898
2941
  measureFitSize() {
2899
2942
  const vertical = layoutAxis(this.mode) === "height";
2900
2943
  const handleSize = vertical ? this.handle.offsetHeight : this.handle.offsetWidth;
2901
2944
  const content = this.scrollContainer;
2902
- const natural = content ? handleSize + (vertical ? content.scrollHeight : content.scrollWidth) : handleSize;
2945
+ const natural = content ? handleSize + this.measureContentExtent(vertical) : handleSize;
2903
2946
  if (typeof window === "undefined") return natural;
2904
2947
  const viewport = vertical ? window.innerHeight : window.innerWidth;
2905
2948
  return viewport > 0 ? Math.min(natural, viewport) : natural;
@@ -2908,22 +2951,62 @@ var BottomSheetEngine = class {
2908
2951
  if (typeof ResizeObserver === "undefined") return;
2909
2952
  if (!this.snapPointsRaw.some((p) => p.size === "fit" || p.size === "content"))
2910
2953
  return;
2911
- const targets = [this.handle];
2912
- if (this.scrollContainer && this.scrollContainer !== this.handle) {
2913
- targets.push(this.scrollContainer);
2914
- }
2915
2954
  let raf = 0;
2916
- const ro = new ResizeObserver(() => {
2955
+ const schedule = () => {
2917
2956
  if (raf) return;
2918
2957
  raf = requestAnimationFrame(() => {
2919
2958
  raf = 0;
2920
2959
  if (this.destroyed || this.gesture?.isDragging) return;
2921
2960
  this.recompute();
2922
2961
  });
2923
- });
2924
- for (const t of targets) ro.observe(t);
2962
+ };
2963
+ const ro = new ResizeObserver(schedule);
2964
+ ro.observe(this.handle);
2965
+ const scroller = this.scrollContainer;
2966
+ const observed = /* @__PURE__ */ new Set();
2967
+ const slots = /* @__PURE__ */ new Set();
2968
+ const hasSlot = typeof HTMLSlotElement !== "undefined";
2969
+ const onSlotChange = () => resync();
2970
+ const trackSlots = () => {
2971
+ if (!scroller || !hasSlot) return;
2972
+ for (const child of Array.from(scroller.children)) {
2973
+ if (child instanceof HTMLSlotElement && !slots.has(child)) {
2974
+ child.addEventListener("slotchange", onSlotChange);
2975
+ slots.add(child);
2976
+ }
2977
+ }
2978
+ };
2979
+ const resync = () => {
2980
+ trackSlots();
2981
+ const targets = this.contentTargets();
2982
+ for (const el of observed) {
2983
+ if (!targets.includes(el)) {
2984
+ ro.unobserve(el);
2985
+ observed.delete(el);
2986
+ }
2987
+ }
2988
+ for (const el of targets) {
2989
+ if (!observed.has(el)) {
2990
+ ro.observe(el);
2991
+ observed.add(el);
2992
+ }
2993
+ }
2994
+ schedule();
2995
+ };
2996
+ let mo;
2997
+ if (scroller) {
2998
+ resync();
2999
+ if (typeof MutationObserver !== "undefined") {
3000
+ mo = new MutationObserver(resync);
3001
+ mo.observe(scroller, { childList: true });
3002
+ }
3003
+ }
2925
3004
  this.teardowns.add(() => {
2926
3005
  ro.disconnect();
3006
+ mo?.disconnect();
3007
+ for (const slot of slots) {
3008
+ slot.removeEventListener("slotchange", onSlotChange);
3009
+ }
2927
3010
  if (raf) cancelAnimationFrame(raf);
2928
3011
  });
2929
3012
  }
@@ -3271,6 +3354,9 @@ var BottomSheetEngine = class {
3271
3354
  if (this.anchorHost && this.anchorHost !== this.scrimParent) {
3272
3355
  this.anchorHost.style.setProperty("--bs-size", `${size}px`);
3273
3356
  }
3357
+ if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
3358
+ this.rootEl.style.setProperty("--bs-size", `${size}px`);
3359
+ }
3274
3360
  }
3275
3361
  const progress = this.computeProgress(size);
3276
3362
  const progressChanged = this.progressWriteSentinel.shouldWrite(
@@ -3282,6 +3368,9 @@ var BottomSheetEngine = class {
3282
3368
  if (this.anchorHost) {
3283
3369
  this.anchorHost.style.setProperty("--bs-progress", String(progress));
3284
3370
  }
3371
+ if (this.rootEl && this.rootEl !== this.anchorHost) {
3372
+ this.rootEl.style.setProperty("--bs-progress", String(progress));
3373
+ }
3285
3374
  }
3286
3375
  this.scrim.applyOpacity(progress, progressChanged);
3287
3376
  if (progressChanged && this.bus.listenerCount("progress") > 0) {
@@ -39,6 +39,7 @@
39
39
  returnFocusTo?: HTMLElement | string | (() => HTMLElement | null);
40
40
  ariaLabel?: string;
41
41
  header?: Snippet<[EngineState & { activeId: TId }]>;
42
+ footer?: Snippet<[EngineState & { activeId: TId }]>;
42
43
  leftButton?: Snippet;
43
44
  rightButton?: Snippet;
44
45
  screen?: Snippet;
@@ -82,6 +83,7 @@
82
83
  returnFocusTo,
83
84
  ariaLabel = "Bottom sheet",
84
85
  header,
86
+ footer,
85
87
  leftButton,
86
88
  rightButton,
87
89
  screen,
@@ -273,16 +275,6 @@
273
275
  aria-modal={focusTrap ? "true" : undefined}
274
276
  aria-label={ariaLabel}
275
277
  >
276
- {#if leftButton}
277
- <div class="bs-button-slot" data-side="left">
278
- {@render leftButton()}
279
- </div>
280
- {/if}
281
- {#if rightButton}
282
- <div class="bs-button-slot" data-side="right">
283
- {@render rightButton()}
284
- </div>
285
- {/if}
286
278
  <div
287
279
  class="bs-handle"
288
280
  bind:this={handleEl}
@@ -294,15 +286,25 @@
294
286
  aria-valuemax={Math.max(0, allowedIds.length - 1)}
295
287
  aria-valuenow={Math.max(0, activeIdx)}
296
288
  aria-valuetext={viewState.activeId}
297
- >
298
- {#if header}{@render header(viewState)}{/if}
299
- </div>
289
+ ></div>
290
+ {#if header}<div class="bs-header">{@render header(viewState)}</div>{/if}
300
291
  <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
301
292
  <div class="bs-content" bind:this={contentEl} tabindex="0" role="region" aria-label="Sheet content">
302
293
  {#if children}{@render children()}{/if}
303
294
  </div>
295
+ {#if footer}<div class="bs-footer">{@render footer(viewState)}</div>{/if}
304
296
  <span class="bs-sr-only" role="status" aria-live="polite">
305
297
  {viewState.activeId}
306
298
  </span>
307
299
  </section>
300
+ {#if leftButton}
301
+ <div class="bs-button-slot" data-side="left" data-mode={mode}>
302
+ {@render leftButton()}
303
+ </div>
304
+ {/if}
305
+ {#if rightButton}
306
+ <div class="bs-button-slot" data-side="right" data-mode={mode}>
307
+ {@render rightButton()}
308
+ </div>
309
+ {/if}
308
310
  </div>