@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
package/dist/react.js CHANGED
@@ -2903,11 +2903,54 @@ var BottomSheetEngine = class {
2903
2903
  this.updateAriaSlider();
2904
2904
  }
2905
2905
  }
2906
+ contentTargets() {
2907
+ const scroller = this.scrollContainer;
2908
+ if (!scroller) return [];
2909
+ const hasSlot = typeof HTMLSlotElement !== "undefined";
2910
+ const out = [];
2911
+ for (const child of Array.from(scroller.children)) {
2912
+ if (hasSlot && child instanceof HTMLSlotElement) {
2913
+ for (const el of child.assignedElements()) out.push(el);
2914
+ } else {
2915
+ out.push(child);
2916
+ }
2917
+ }
2918
+ return out;
2919
+ }
2920
+ measureContentExtent(vertical) {
2921
+ const content = this.scrollContainer;
2922
+ if (!content) return 0;
2923
+ const targets = this.contentTargets();
2924
+ if (targets.length === 0) {
2925
+ return vertical ? content.scrollHeight : content.scrollWidth;
2926
+ }
2927
+ let min = Infinity;
2928
+ let max = -Infinity;
2929
+ for (const el of targets) {
2930
+ const r = el.getBoundingClientRect();
2931
+ if (vertical) {
2932
+ if (r.top < min) min = r.top;
2933
+ if (r.bottom > max) max = r.bottom;
2934
+ } else {
2935
+ if (r.left < min) min = r.left;
2936
+ if (r.right > max) max = r.right;
2937
+ }
2938
+ }
2939
+ if (!isFinite(min) || !isFinite(max) || max <= min) {
2940
+ return vertical ? content.scrollHeight : content.scrollWidth;
2941
+ }
2942
+ let pad = 0;
2943
+ if (typeof getComputedStyle !== "undefined") {
2944
+ const cs = getComputedStyle(content);
2945
+ pad = vertical ? (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.paddingBottom) || 0) : (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.paddingRight) || 0);
2946
+ }
2947
+ return max - min + pad;
2948
+ }
2906
2949
  measureFitSize() {
2907
2950
  const vertical = layoutAxis(this.mode) === "height";
2908
2951
  const handleSize = vertical ? this.handle.offsetHeight : this.handle.offsetWidth;
2909
2952
  const content = this.scrollContainer;
2910
- const natural = content ? handleSize + (vertical ? content.scrollHeight : content.scrollWidth) : handleSize;
2953
+ const natural = content ? handleSize + this.measureContentExtent(vertical) : handleSize;
2911
2954
  if (typeof window === "undefined") return natural;
2912
2955
  const viewport = vertical ? window.innerHeight : window.innerWidth;
2913
2956
  return viewport > 0 ? Math.min(natural, viewport) : natural;
@@ -2916,22 +2959,62 @@ var BottomSheetEngine = class {
2916
2959
  if (typeof ResizeObserver === "undefined") return;
2917
2960
  if (!this.snapPointsRaw.some((p) => p.size === "fit" || p.size === "content"))
2918
2961
  return;
2919
- const targets = [this.handle];
2920
- if (this.scrollContainer && this.scrollContainer !== this.handle) {
2921
- targets.push(this.scrollContainer);
2922
- }
2923
2962
  let raf = 0;
2924
- const ro = new ResizeObserver(() => {
2963
+ const schedule = () => {
2925
2964
  if (raf) return;
2926
2965
  raf = requestAnimationFrame(() => {
2927
2966
  raf = 0;
2928
2967
  if (this.destroyed || this.gesture?.isDragging) return;
2929
2968
  this.recompute();
2930
2969
  });
2931
- });
2932
- for (const t of targets) ro.observe(t);
2970
+ };
2971
+ const ro = new ResizeObserver(schedule);
2972
+ ro.observe(this.handle);
2973
+ const scroller = this.scrollContainer;
2974
+ const observed = /* @__PURE__ */ new Set();
2975
+ const slots = /* @__PURE__ */ new Set();
2976
+ const hasSlot = typeof HTMLSlotElement !== "undefined";
2977
+ const onSlotChange = () => resync();
2978
+ const trackSlots = () => {
2979
+ if (!scroller || !hasSlot) return;
2980
+ for (const child of Array.from(scroller.children)) {
2981
+ if (child instanceof HTMLSlotElement && !slots.has(child)) {
2982
+ child.addEventListener("slotchange", onSlotChange);
2983
+ slots.add(child);
2984
+ }
2985
+ }
2986
+ };
2987
+ const resync = () => {
2988
+ trackSlots();
2989
+ const targets = this.contentTargets();
2990
+ for (const el of observed) {
2991
+ if (!targets.includes(el)) {
2992
+ ro.unobserve(el);
2993
+ observed.delete(el);
2994
+ }
2995
+ }
2996
+ for (const el of targets) {
2997
+ if (!observed.has(el)) {
2998
+ ro.observe(el);
2999
+ observed.add(el);
3000
+ }
3001
+ }
3002
+ schedule();
3003
+ };
3004
+ let mo;
3005
+ if (scroller) {
3006
+ resync();
3007
+ if (typeof MutationObserver !== "undefined") {
3008
+ mo = new MutationObserver(resync);
3009
+ mo.observe(scroller, { childList: true });
3010
+ }
3011
+ }
2933
3012
  this.teardowns.add(() => {
2934
3013
  ro.disconnect();
3014
+ mo?.disconnect();
3015
+ for (const slot of slots) {
3016
+ slot.removeEventListener("slotchange", onSlotChange);
3017
+ }
2935
3018
  if (raf) cancelAnimationFrame(raf);
2936
3019
  });
2937
3020
  }
@@ -3279,6 +3362,9 @@ var BottomSheetEngine = class {
3279
3362
  if (this.anchorHost && this.anchorHost !== this.scrimParent) {
3280
3363
  this.anchorHost.style.setProperty("--bs-size", `${size}px`);
3281
3364
  }
3365
+ if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
3366
+ this.rootEl.style.setProperty("--bs-size", `${size}px`);
3367
+ }
3282
3368
  }
3283
3369
  const progress = this.computeProgress(size);
3284
3370
  const progressChanged = this.progressWriteSentinel.shouldWrite(
@@ -3290,6 +3376,9 @@ var BottomSheetEngine = class {
3290
3376
  if (this.anchorHost) {
3291
3377
  this.anchorHost.style.setProperty("--bs-progress", String(progress));
3292
3378
  }
3379
+ if (this.rootEl && this.rootEl !== this.anchorHost) {
3380
+ this.rootEl.style.setProperty("--bs-progress", String(progress));
3381
+ }
3293
3382
  }
3294
3383
  this.scrim.applyOpacity(progress, progressChanged);
3295
3384
  if (progressChanged && this.bus.listenerCount("progress") > 0) {
@@ -3524,6 +3613,7 @@ var BottomSheet = forwardRef(
3524
3613
  className = "",
3525
3614
  style,
3526
3615
  header,
3616
+ footer,
3527
3617
  children,
3528
3618
  leftButton,
3529
3619
  rightButton,
@@ -3704,8 +3794,6 @@ var BottomSheet = forwardRef(
3704
3794
  "aria-label": ariaLabelledBy ? void 0 : ariaLabel,
3705
3795
  "aria-labelledby": ariaLabelledBy,
3706
3796
  children: [
3707
- leftButton && /* @__PURE__ */ jsx("div", { className: "bs-button-slot", "data-side": "left", children: leftButton }),
3708
- rightButton && /* @__PURE__ */ jsx("div", { className: "bs-button-slot", "data-side": "right", children: rightButton }),
3709
3797
  /* @__PURE__ */ jsx(
3710
3798
  "div",
3711
3799
  {
@@ -3713,10 +3801,10 @@ var BottomSheet = forwardRef(
3713
3801
  className: "bs-handle",
3714
3802
  role: "slider",
3715
3803
  tabIndex: 0,
3716
- "aria-label": "Resize sheet",
3717
- children: typeof header === "function" ? header(state) : header
3804
+ "aria-label": "Resize sheet"
3718
3805
  }
3719
3806
  ),
3807
+ header != null && header !== false && /* @__PURE__ */ jsx("div", { className: "bs-header", children: typeof header === "function" ? header(state) : header }),
3720
3808
  /* @__PURE__ */ jsx(
3721
3809
  "div",
3722
3810
  {
@@ -3728,10 +3816,29 @@ var BottomSheet = forwardRef(
3728
3816
  children
3729
3817
  }
3730
3818
  ),
3819
+ footer != null && footer !== false && /* @__PURE__ */ jsx("div", { className: "bs-footer", children: typeof footer === "function" ? footer(state) : footer }),
3731
3820
  /* @__PURE__ */ jsx("span", { className: "bs-sr-only", role: "status", "aria-live": "polite", children: announce })
3732
3821
  ]
3733
3822
  }
3734
3823
  ),
3824
+ leftButton && /* @__PURE__ */ jsx(
3825
+ "div",
3826
+ {
3827
+ className: "bs-button-slot",
3828
+ "data-side": "left",
3829
+ "data-mode": engineOpts.mode ?? "bottom",
3830
+ children: leftButton
3831
+ }
3832
+ ),
3833
+ rightButton && /* @__PURE__ */ jsx(
3834
+ "div",
3835
+ {
3836
+ className: "bs-button-slot",
3837
+ "data-side": "right",
3838
+ "data-mode": engineOpts.mode ?? "bottom",
3839
+ children: rightButton
3840
+ }
3841
+ ),
3735
3842
  anchorHosts.map(
3736
3843
  (host, i) => anchors?.[i] ? createPortal(anchors[i].node, host) : null
3737
3844
  ),
package/dist/solid.cjs CHANGED
@@ -2898,11 +2898,54 @@ var BottomSheetEngine = class {
2898
2898
  this.updateAriaSlider();
2899
2899
  }
2900
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
+ }
2901
2944
  measureFitSize() {
2902
2945
  const vertical = layoutAxis(this.mode) === "height";
2903
2946
  const handleSize = vertical ? this.handle.offsetHeight : this.handle.offsetWidth;
2904
2947
  const content = this.scrollContainer;
2905
- const natural = content ? handleSize + (vertical ? content.scrollHeight : content.scrollWidth) : handleSize;
2948
+ const natural = content ? handleSize + this.measureContentExtent(vertical) : handleSize;
2906
2949
  if (typeof window === "undefined") return natural;
2907
2950
  const viewport = vertical ? window.innerHeight : window.innerWidth;
2908
2951
  return viewport > 0 ? Math.min(natural, viewport) : natural;
@@ -2911,22 +2954,62 @@ var BottomSheetEngine = class {
2911
2954
  if (typeof ResizeObserver === "undefined") return;
2912
2955
  if (!this.snapPointsRaw.some((p) => p.size === "fit" || p.size === "content"))
2913
2956
  return;
2914
- const targets = [this.handle];
2915
- if (this.scrollContainer && this.scrollContainer !== this.handle) {
2916
- targets.push(this.scrollContainer);
2917
- }
2918
2957
  let raf = 0;
2919
- const ro = new ResizeObserver(() => {
2958
+ const schedule = () => {
2920
2959
  if (raf) return;
2921
2960
  raf = requestAnimationFrame(() => {
2922
2961
  raf = 0;
2923
2962
  if (this.destroyed || this.gesture?.isDragging) return;
2924
2963
  this.recompute();
2925
2964
  });
2926
- });
2927
- 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
+ }
2928
3007
  this.teardowns.add(() => {
2929
3008
  ro.disconnect();
3009
+ mo?.disconnect();
3010
+ for (const slot of slots) {
3011
+ slot.removeEventListener("slotchange", onSlotChange);
3012
+ }
2930
3013
  if (raf) cancelAnimationFrame(raf);
2931
3014
  });
2932
3015
  }
@@ -3274,6 +3357,9 @@ var BottomSheetEngine = class {
3274
3357
  if (this.anchorHost && this.anchorHost !== this.scrimParent) {
3275
3358
  this.anchorHost.style.setProperty("--bs-size", `${size}px`);
3276
3359
  }
3360
+ if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
3361
+ this.rootEl.style.setProperty("--bs-size", `${size}px`);
3362
+ }
3277
3363
  }
3278
3364
  const progress = this.computeProgress(size);
3279
3365
  const progressChanged = this.progressWriteSentinel.shouldWrite(
@@ -3285,6 +3371,9 @@ var BottomSheetEngine = class {
3285
3371
  if (this.anchorHost) {
3286
3372
  this.anchorHost.style.setProperty("--bs-progress", String(progress));
3287
3373
  }
3374
+ if (this.rootEl && this.rootEl !== this.anchorHost) {
3375
+ this.rootEl.style.setProperty("--bs-progress", String(progress));
3376
+ }
3288
3377
  }
3289
3378
  this.scrim.applyOpacity(progress, progressChanged);
3290
3379
  if (progressChanged && this.bus.listenerCount("progress") > 0) {
@@ -3342,8 +3431,10 @@ var BottomSheetEngine = class {
3342
3431
  };
3343
3432
 
3344
3433
  // src/solid/index.tsx
3345
- var _tmpl$ = /* @__PURE__ */ web.template(`<div class=bs-root><div class=bs-screen></div><section class=bs-sheet role=dialog><div class=bs-handle role=slider tabindex=0 aria-label="Resize sheet"></div><div class=bs-content tabindex=0 role=region aria-label="Sheet content"></div><span class=bs-sr-only role=status aria-live=polite>`);
3346
- var _tmpl$2 = /* @__PURE__ */ web.template(`<div class=bs-backdrop>`);
3434
+ var _tmpl$ = /* @__PURE__ */ web.template(`<div class=bs-header>`);
3435
+ var _tmpl$2 = /* @__PURE__ */ web.template(`<div class=bs-footer>`);
3436
+ var _tmpl$3 = /* @__PURE__ */ web.template(`<div class=bs-root><div class=bs-screen></div><section class=bs-sheet role=dialog><div class=bs-handle role=slider tabindex=0 aria-label="Resize sheet"></div><div class=bs-content tabindex=0 role=region aria-label="Sheet content"></div><span class=bs-sr-only role=status aria-live=polite>`);
3437
+ var _tmpl$4 = /* @__PURE__ */ web.template(`<div class=bs-backdrop>`);
3347
3438
  var BottomSheet = (props) => {
3348
3439
  let sheetEl;
3349
3440
  let handleEl;
@@ -3428,23 +3519,42 @@ var BottomSheet = (props) => {
3428
3519
  const mode = solidJs.createMemo(() => props.mode ?? "bottom");
3429
3520
  const ariaLabel = solidJs.createMemo(() => props.ariaLabel ?? "Bottom sheet");
3430
3521
  return (() => {
3431
- var _el$ = _tmpl$(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling, _el$4 = _el$3.firstChild, _el$5 = _el$4.nextSibling, _el$6 = _el$5.nextSibling;
3522
+ var _el$ = _tmpl$3(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling, _el$4 = _el$3.firstChild, _el$6 = _el$4.nextSibling, _el$8 = _el$6.nextSibling;
3432
3523
  web.insert(_el$, (() => {
3433
3524
  var _c$ = web.memo(() => !!showBackdrop());
3434
3525
  return () => _c$() ? (() => {
3435
- var _el$7 = _tmpl$2();
3436
- web.use((el) => backdropEl = el, _el$7);
3437
- return _el$7;
3526
+ var _el$9 = _tmpl$4();
3527
+ web.use((el) => backdropEl = el, _el$9);
3528
+ return _el$9;
3438
3529
  })() : null;
3439
3530
  })(), _el$2);
3440
3531
  web.use((el) => scrimEl = el, _el$2);
3441
3532
  web.insert(_el$2, () => props.screen);
3442
3533
  web.use((el) => sheetEl = el, _el$3);
3443
3534
  web.use((el) => handleEl = el, _el$4);
3444
- web.insert(_el$4, () => props.header);
3445
- web.use((el) => contentEl = el, _el$5);
3446
- web.insert(_el$5, () => props.children);
3447
- web.insert(_el$6, () => state().activeId);
3535
+ web.insert(_el$3, web.createComponent(solidJs.Show, {
3536
+ get when() {
3537
+ return props.header;
3538
+ },
3539
+ get children() {
3540
+ var _el$5 = _tmpl$();
3541
+ web.insert(_el$5, () => props.header);
3542
+ return _el$5;
3543
+ }
3544
+ }), _el$6);
3545
+ web.use((el) => contentEl = el, _el$6);
3546
+ web.insert(_el$6, () => props.children);
3547
+ web.insert(_el$3, web.createComponent(solidJs.Show, {
3548
+ get when() {
3549
+ return props.footer;
3550
+ },
3551
+ get children() {
3552
+ var _el$7 = _tmpl$2();
3553
+ web.insert(_el$7, () => props.footer);
3554
+ return _el$7;
3555
+ }
3556
+ }), _el$8);
3557
+ web.insert(_el$8, () => state().activeId);
3448
3558
  web.effect((_p$) => {
3449
3559
  var _v$ = mode(), _v$2 = state().activeId, _v$3 = props.focusTrap ? "true" : void 0, _v$4 = ariaLabel();
3450
3560
  _v$ !== _p$.e && web.setAttribute(_el$3, "data-mode", _p$.e = _v$);
package/dist/solid.d.cts CHANGED
@@ -273,6 +273,8 @@ declare class BottomSheetEngine {
273
273
  };
274
274
  setSnapPoints(points: EngineOptions["snapPoints"], allowed?: string[]): void;
275
275
  recompute(): void;
276
+ private contentTargets;
277
+ private measureContentExtent;
276
278
  private measureFitSize;
277
279
  private installFitObserver;
278
280
  destroy(): void;
@@ -326,6 +328,7 @@ type BottomSheetProps<TId extends string = string> = {
326
328
  }) => void;
327
329
  engineRef?: (engine: BottomSheetEngine | null) => void;
328
330
  header?: JSX.Element;
331
+ footer?: JSX.Element;
329
332
  screen?: JSX.Element;
330
333
  children?: JSX.Element;
331
334
  };
package/dist/solid.d.ts CHANGED
@@ -273,6 +273,8 @@ declare class BottomSheetEngine {
273
273
  };
274
274
  setSnapPoints(points: EngineOptions["snapPoints"], allowed?: string[]): void;
275
275
  recompute(): void;
276
+ private contentTargets;
277
+ private measureContentExtent;
276
278
  private measureFitSize;
277
279
  private installFitObserver;
278
280
  destroy(): void;
@@ -326,6 +328,7 @@ type BottomSheetProps<TId extends string = string> = {
326
328
  }) => void;
327
329
  engineRef?: (engine: BottomSheetEngine | null) => void;
328
330
  header?: JSX.Element;
331
+ footer?: JSX.Element;
329
332
  screen?: JSX.Element;
330
333
  children?: JSX.Element;
331
334
  };
package/dist/solid.js CHANGED
@@ -1,5 +1,5 @@
1
- import { insert, memo, use, effect, setAttribute, template } from 'solid-js/web';
2
- import { createSignal, onMount, onCleanup, createEffect, on, createMemo } from 'solid-js';
1
+ import { insert, memo, use, createComponent, effect, setAttribute, template } from 'solid-js/web';
2
+ import { createSignal, onMount, onCleanup, createEffect, on, createMemo, Show } from 'solid-js';
3
3
 
4
4
  var __defProp = Object.defineProperty;
5
5
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -2896,11 +2896,54 @@ var BottomSheetEngine = class {
2896
2896
  this.updateAriaSlider();
2897
2897
  }
2898
2898
  }
2899
+ contentTargets() {
2900
+ const scroller = this.scrollContainer;
2901
+ if (!scroller) return [];
2902
+ const hasSlot = typeof HTMLSlotElement !== "undefined";
2903
+ const out = [];
2904
+ for (const child of Array.from(scroller.children)) {
2905
+ if (hasSlot && child instanceof HTMLSlotElement) {
2906
+ for (const el of child.assignedElements()) out.push(el);
2907
+ } else {
2908
+ out.push(child);
2909
+ }
2910
+ }
2911
+ return out;
2912
+ }
2913
+ measureContentExtent(vertical) {
2914
+ const content = this.scrollContainer;
2915
+ if (!content) return 0;
2916
+ const targets = this.contentTargets();
2917
+ if (targets.length === 0) {
2918
+ return vertical ? content.scrollHeight : content.scrollWidth;
2919
+ }
2920
+ let min = Infinity;
2921
+ let max = -Infinity;
2922
+ for (const el of targets) {
2923
+ const r = el.getBoundingClientRect();
2924
+ if (vertical) {
2925
+ if (r.top < min) min = r.top;
2926
+ if (r.bottom > max) max = r.bottom;
2927
+ } else {
2928
+ if (r.left < min) min = r.left;
2929
+ if (r.right > max) max = r.right;
2930
+ }
2931
+ }
2932
+ if (!isFinite(min) || !isFinite(max) || max <= min) {
2933
+ return vertical ? content.scrollHeight : content.scrollWidth;
2934
+ }
2935
+ let pad = 0;
2936
+ if (typeof getComputedStyle !== "undefined") {
2937
+ const cs = getComputedStyle(content);
2938
+ pad = vertical ? (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.paddingBottom) || 0) : (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.paddingRight) || 0);
2939
+ }
2940
+ return max - min + pad;
2941
+ }
2899
2942
  measureFitSize() {
2900
2943
  const vertical = layoutAxis(this.mode) === "height";
2901
2944
  const handleSize = vertical ? this.handle.offsetHeight : this.handle.offsetWidth;
2902
2945
  const content = this.scrollContainer;
2903
- const natural = content ? handleSize + (vertical ? content.scrollHeight : content.scrollWidth) : handleSize;
2946
+ const natural = content ? handleSize + this.measureContentExtent(vertical) : handleSize;
2904
2947
  if (typeof window === "undefined") return natural;
2905
2948
  const viewport = vertical ? window.innerHeight : window.innerWidth;
2906
2949
  return viewport > 0 ? Math.min(natural, viewport) : natural;
@@ -2909,22 +2952,62 @@ var BottomSheetEngine = class {
2909
2952
  if (typeof ResizeObserver === "undefined") return;
2910
2953
  if (!this.snapPointsRaw.some((p) => p.size === "fit" || p.size === "content"))
2911
2954
  return;
2912
- const targets = [this.handle];
2913
- if (this.scrollContainer && this.scrollContainer !== this.handle) {
2914
- targets.push(this.scrollContainer);
2915
- }
2916
2955
  let raf = 0;
2917
- const ro = new ResizeObserver(() => {
2956
+ const schedule = () => {
2918
2957
  if (raf) return;
2919
2958
  raf = requestAnimationFrame(() => {
2920
2959
  raf = 0;
2921
2960
  if (this.destroyed || this.gesture?.isDragging) return;
2922
2961
  this.recompute();
2923
2962
  });
2924
- });
2925
- for (const t of targets) ro.observe(t);
2963
+ };
2964
+ const ro = new ResizeObserver(schedule);
2965
+ ro.observe(this.handle);
2966
+ const scroller = this.scrollContainer;
2967
+ const observed = /* @__PURE__ */ new Set();
2968
+ const slots = /* @__PURE__ */ new Set();
2969
+ const hasSlot = typeof HTMLSlotElement !== "undefined";
2970
+ const onSlotChange = () => resync();
2971
+ const trackSlots = () => {
2972
+ if (!scroller || !hasSlot) return;
2973
+ for (const child of Array.from(scroller.children)) {
2974
+ if (child instanceof HTMLSlotElement && !slots.has(child)) {
2975
+ child.addEventListener("slotchange", onSlotChange);
2976
+ slots.add(child);
2977
+ }
2978
+ }
2979
+ };
2980
+ const resync = () => {
2981
+ trackSlots();
2982
+ const targets = this.contentTargets();
2983
+ for (const el of observed) {
2984
+ if (!targets.includes(el)) {
2985
+ ro.unobserve(el);
2986
+ observed.delete(el);
2987
+ }
2988
+ }
2989
+ for (const el of targets) {
2990
+ if (!observed.has(el)) {
2991
+ ro.observe(el);
2992
+ observed.add(el);
2993
+ }
2994
+ }
2995
+ schedule();
2996
+ };
2997
+ let mo;
2998
+ if (scroller) {
2999
+ resync();
3000
+ if (typeof MutationObserver !== "undefined") {
3001
+ mo = new MutationObserver(resync);
3002
+ mo.observe(scroller, { childList: true });
3003
+ }
3004
+ }
2926
3005
  this.teardowns.add(() => {
2927
3006
  ro.disconnect();
3007
+ mo?.disconnect();
3008
+ for (const slot of slots) {
3009
+ slot.removeEventListener("slotchange", onSlotChange);
3010
+ }
2928
3011
  if (raf) cancelAnimationFrame(raf);
2929
3012
  });
2930
3013
  }
@@ -3272,6 +3355,9 @@ var BottomSheetEngine = class {
3272
3355
  if (this.anchorHost && this.anchorHost !== this.scrimParent) {
3273
3356
  this.anchorHost.style.setProperty("--bs-size", `${size}px`);
3274
3357
  }
3358
+ if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
3359
+ this.rootEl.style.setProperty("--bs-size", `${size}px`);
3360
+ }
3275
3361
  }
3276
3362
  const progress = this.computeProgress(size);
3277
3363
  const progressChanged = this.progressWriteSentinel.shouldWrite(
@@ -3283,6 +3369,9 @@ var BottomSheetEngine = class {
3283
3369
  if (this.anchorHost) {
3284
3370
  this.anchorHost.style.setProperty("--bs-progress", String(progress));
3285
3371
  }
3372
+ if (this.rootEl && this.rootEl !== this.anchorHost) {
3373
+ this.rootEl.style.setProperty("--bs-progress", String(progress));
3374
+ }
3286
3375
  }
3287
3376
  this.scrim.applyOpacity(progress, progressChanged);
3288
3377
  if (progressChanged && this.bus.listenerCount("progress") > 0) {
@@ -3340,8 +3429,10 @@ var BottomSheetEngine = class {
3340
3429
  };
3341
3430
 
3342
3431
  // src/solid/index.tsx
3343
- var _tmpl$ = /* @__PURE__ */ template(`<div class=bs-root><div class=bs-screen></div><section class=bs-sheet role=dialog><div class=bs-handle role=slider tabindex=0 aria-label="Resize sheet"></div><div class=bs-content tabindex=0 role=region aria-label="Sheet content"></div><span class=bs-sr-only role=status aria-live=polite>`);
3344
- var _tmpl$2 = /* @__PURE__ */ template(`<div class=bs-backdrop>`);
3432
+ var _tmpl$ = /* @__PURE__ */ template(`<div class=bs-header>`);
3433
+ var _tmpl$2 = /* @__PURE__ */ template(`<div class=bs-footer>`);
3434
+ var _tmpl$3 = /* @__PURE__ */ template(`<div class=bs-root><div class=bs-screen></div><section class=bs-sheet role=dialog><div class=bs-handle role=slider tabindex=0 aria-label="Resize sheet"></div><div class=bs-content tabindex=0 role=region aria-label="Sheet content"></div><span class=bs-sr-only role=status aria-live=polite>`);
3435
+ var _tmpl$4 = /* @__PURE__ */ template(`<div class=bs-backdrop>`);
3345
3436
  var BottomSheet = (props) => {
3346
3437
  let sheetEl;
3347
3438
  let handleEl;
@@ -3426,23 +3517,42 @@ var BottomSheet = (props) => {
3426
3517
  const mode = createMemo(() => props.mode ?? "bottom");
3427
3518
  const ariaLabel = createMemo(() => props.ariaLabel ?? "Bottom sheet");
3428
3519
  return (() => {
3429
- var _el$ = _tmpl$(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling, _el$4 = _el$3.firstChild, _el$5 = _el$4.nextSibling, _el$6 = _el$5.nextSibling;
3520
+ var _el$ = _tmpl$3(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling, _el$4 = _el$3.firstChild, _el$6 = _el$4.nextSibling, _el$8 = _el$6.nextSibling;
3430
3521
  insert(_el$, (() => {
3431
3522
  var _c$ = memo(() => !!showBackdrop());
3432
3523
  return () => _c$() ? (() => {
3433
- var _el$7 = _tmpl$2();
3434
- use((el) => backdropEl = el, _el$7);
3435
- return _el$7;
3524
+ var _el$9 = _tmpl$4();
3525
+ use((el) => backdropEl = el, _el$9);
3526
+ return _el$9;
3436
3527
  })() : null;
3437
3528
  })(), _el$2);
3438
3529
  use((el) => scrimEl = el, _el$2);
3439
3530
  insert(_el$2, () => props.screen);
3440
3531
  use((el) => sheetEl = el, _el$3);
3441
3532
  use((el) => handleEl = el, _el$4);
3442
- insert(_el$4, () => props.header);
3443
- use((el) => contentEl = el, _el$5);
3444
- insert(_el$5, () => props.children);
3445
- insert(_el$6, () => state().activeId);
3533
+ insert(_el$3, createComponent(Show, {
3534
+ get when() {
3535
+ return props.header;
3536
+ },
3537
+ get children() {
3538
+ var _el$5 = _tmpl$();
3539
+ insert(_el$5, () => props.header);
3540
+ return _el$5;
3541
+ }
3542
+ }), _el$6);
3543
+ use((el) => contentEl = el, _el$6);
3544
+ insert(_el$6, () => props.children);
3545
+ insert(_el$3, createComponent(Show, {
3546
+ get when() {
3547
+ return props.footer;
3548
+ },
3549
+ get children() {
3550
+ var _el$7 = _tmpl$2();
3551
+ insert(_el$7, () => props.footer);
3552
+ return _el$7;
3553
+ }
3554
+ }), _el$8);
3555
+ insert(_el$8, () => state().activeId);
3446
3556
  effect((_p$) => {
3447
3557
  var _v$ = mode(), _v$2 = state().activeId, _v$3 = props.focusTrap ? "true" : void 0, _v$4 = ariaLabel();
3448
3558
  _v$ !== _p$.e && setAttribute(_el$3, "data-mode", _p$.e = _v$);