@surdeddd/bottom-sheet 0.7.0 → 0.8.1

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.
package/dist/index.cjs CHANGED
@@ -2364,6 +2364,7 @@ var BottomSheetEngine = class {
2364
2364
  __publicField(this, "progressWriteSentinel", new WriteSentinel());
2365
2365
  __publicField(this, "isTopSheet", true);
2366
2366
  __publicField(this, "opening", false);
2367
+ __publicField(this, "allowOvershoot", false);
2367
2368
  __publicField(this, "progressPayload", {
2368
2369
  value: 0,
2369
2370
  size: 0
@@ -2916,45 +2917,52 @@ var BottomSheetEngine = class {
2916
2917
  }
2917
2918
  return out;
2918
2919
  }
2919
- measureContentExtent(vertical) {
2920
+ measureSheetNatural(vertical) {
2921
+ const el = this.element;
2920
2922
  const content = this.scrollContainer;
2921
- if (!content) return 0;
2922
- const targets = this.contentTargets();
2923
- if (targets.length === 0) {
2924
- return vertical ? content.scrollHeight : content.scrollWidth;
2925
- }
2926
- let min = Infinity;
2927
- let max = -Infinity;
2928
- for (const el of targets) {
2929
- const r = el.getBoundingClientRect();
2930
- if (vertical) {
2931
- if (r.top < min) min = r.top;
2932
- if (r.bottom > max) max = r.bottom;
2933
- } else {
2934
- if (r.left < min) min = r.left;
2935
- if (r.right > max) max = r.right;
2936
- }
2937
- }
2938
- if (!isFinite(min) || !isFinite(max) || max <= min) {
2939
- return vertical ? content.scrollHeight : content.scrollWidth;
2940
- }
2941
- let pad = 0;
2942
- if (typeof getComputedStyle !== "undefined") {
2943
- const cs = getComputedStyle(content);
2944
- pad = vertical ? (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.paddingBottom) || 0) : (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.paddingRight) || 0);
2945
- }
2946
- return max - min + pad;
2923
+ if (!content) {
2924
+ return vertical ? el.offsetHeight : el.offsetWidth;
2925
+ }
2926
+ const axis = vertical ? "height" : "width";
2927
+ const sheetStyle = el.style;
2928
+ const cs = content.style;
2929
+ const prevSheet = sheetStyle[axis];
2930
+ const prevFlex = cs.flex;
2931
+ const prevContent = vertical ? cs.height : cs.width;
2932
+ sheetStyle[axis] = "auto";
2933
+ cs.flex = "none";
2934
+ if (vertical) cs.height = "auto";
2935
+ else cs.width = "auto";
2936
+ const poked = vertical ? el.offsetHeight : el.offsetWidth;
2937
+ const contentBox = vertical ? content.clientHeight : content.clientWidth;
2938
+ const contentScroll = vertical ? content.scrollHeight : content.scrollWidth;
2939
+ const natural = Math.max(poked, poked - contentBox + contentScroll);
2940
+ sheetStyle[axis] = prevSheet;
2941
+ cs.flex = prevFlex;
2942
+ if (vertical) cs.height = prevContent;
2943
+ else cs.width = prevContent;
2944
+ return natural;
2947
2945
  }
2948
2946
  measureFitSize() {
2949
2947
  const vertical = layoutAxis(this.mode) === "height";
2950
- const handleSize = vertical ? this.handle.offsetHeight : this.handle.offsetWidth;
2951
- const content = this.scrollContainer;
2952
- const natural = content ? handleSize + this.measureContentExtent(vertical) : handleSize;
2948
+ const natural = this.measureSheetNatural(vertical);
2953
2949
  const capped = this.maxHeightCap !== void 0 ? Math.min(natural, this.maxHeightCap) : natural;
2954
2950
  if (typeof window === "undefined") return capped;
2955
- const viewport = vertical ? window.innerHeight : window.innerWidth;
2951
+ const viewport = this.containingExtent(vertical);
2956
2952
  return viewport > 0 ? Math.min(capped, viewport) : capped;
2957
2953
  }
2954
+ // The fit cap is the sheet's containing block, not always the window: a
2955
+ // position:fixed sheet nested under a transform/filter/will-change ancestor
2956
+ // is clipped to that ancestor, so capping by window.innerHeight oversizes the
2957
+ // sheet and the content/footer get clipped. offsetParent resolves to that
2958
+ // ancestor when present, and is null (→ viewport) for a plain fixed sheet.
2959
+ containingExtent(vertical) {
2960
+ const op = this.element.offsetParent;
2961
+ if (op && op !== document.body && op !== document.documentElement) {
2962
+ return vertical ? op.clientHeight : op.clientWidth;
2963
+ }
2964
+ return vertical ? window.innerHeight : window.innerWidth;
2965
+ }
2958
2966
  installFitObserver() {
2959
2967
  if (typeof ResizeObserver === "undefined") return;
2960
2968
  if (!this.snapPointsRaw.some((p) => p.size === "fit" || p.size === "content"))
@@ -3035,6 +3043,10 @@ var BottomSheetEngine = class {
3035
3043
  this.backdrop.style.opacity = "";
3036
3044
  this.backdrop.style.pointerEvents = "";
3037
3045
  }
3046
+ if (this.anchorHost) {
3047
+ this.anchorHost.style.removeProperty("--bs-size");
3048
+ this.anchorHost.style.removeProperty("--bs-progress");
3049
+ }
3038
3050
  if (this.screenComponent) {
3039
3051
  this.screenComponent.style.opacity = "";
3040
3052
  this.screenComponent.style.display = "";
@@ -3046,6 +3058,7 @@ var BottomSheetEngine = class {
3046
3058
  this.bus.emit(event, payload);
3047
3059
  }
3048
3060
  newCycle() {
3061
+ this.allowOvershoot = false;
3049
3062
  this.currentAbort.abort();
3050
3063
  this.currentAbort = new AbortController();
3051
3064
  return this.currentAbort.signal;
@@ -3111,6 +3124,7 @@ var BottomSheetEngine = class {
3111
3124
  seen.add(p.id);
3112
3125
  }
3113
3126
  this.snaps.setRaw(this.snapPointsRaw);
3127
+ this.clampToMaxHeight();
3114
3128
  this.scrim.invalidateOpacityCache();
3115
3129
  }
3116
3130
  getAllowedRange() {
@@ -3317,9 +3331,13 @@ var BottomSheetEngine = class {
3317
3331
  this.opening = true;
3318
3332
  sheetStack.promote(this.id);
3319
3333
  }
3320
- void this.animation.animateTo(target.size, velocity).then(() => {
3321
- this.opening = false;
3334
+ const settleCap = this.snaps.getMaxAxisSize();
3335
+ const settleSize = settleCap > 0 ? Math.min(target.size, settleCap) : target.size;
3336
+ this.allowOvershoot = true;
3337
+ void this.animation.animateTo(settleSize, velocity).then(() => {
3322
3338
  if (signal.aborted) return;
3339
+ this.allowOvershoot = false;
3340
+ this.opening = false;
3323
3341
  this.scrollCache.restore(target.id, previousSize, target.size);
3324
3342
  this.updateAriaSlider();
3325
3343
  this.emit("snap", {
@@ -3351,7 +3369,7 @@ var BottomSheetEngine = class {
3351
3369
  }
3352
3370
  applySize(size) {
3353
3371
  const cap = this.snaps.getMaxAxisSize();
3354
- const clamped = cap > 0 && size > cap && !this.gesture?.isDragging ? cap : size;
3372
+ const clamped = cap > 0 && size > cap && !this.gesture?.isDragging && !this.allowOvershoot ? cap : size;
3355
3373
  this.size = clamped;
3356
3374
  const offset = cap - clamped;
3357
3375
  const style = this.element.style;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { d as SnapPoint, b as SheetMode, a as SnapPointDef, c as EngineOptions, f as ScrimOverlayPosition } from './BottomSheetEngine-CqiCz64W.cjs';
2
- export { g as AnchorAnimationPreset, h as AnchorAnimationSpec, i as AnchorHandle, A as AnchorOptions, j as AnchorPosition, k as AnchorState, B as BottomSheetEngine, C as CloseReason, E as EngineState, P as Plugin, l as SCRIM_PRESETS, m as ScrimOverlayOptions, n as ScrimPreset, o as ScrimPresetConfig, p as ScrimStageDef, S as ScrimStagesOptions, q as ScrimUpdate, e as SheetEventMap, r as SnapId, T as TeardownScope, s as runAnchorTransition } from './BottomSheetEngine-CqiCz64W.cjs';
1
+ import { d as SnapPoint, b as SheetMode, a as SnapPointDef, c as EngineOptions, f as ScrimOverlayPosition } from './BottomSheetEngine-7BDK2OWX.cjs';
2
+ export { g as AnchorAnimationPreset, h as AnchorAnimationSpec, i as AnchorHandle, A as AnchorOptions, j as AnchorPosition, k as AnchorState, B as BottomSheetEngine, C as CloseReason, E as EngineState, P as Plugin, l as SCRIM_PRESETS, m as ScrimOverlayOptions, n as ScrimPreset, o as ScrimPresetConfig, p as ScrimStageDef, S as ScrimStagesOptions, q as ScrimUpdate, e as SheetEventMap, r as SnapId, T as TeardownScope, s as runAnchorTransition } from './BottomSheetEngine-7BDK2OWX.cjs';
3
3
  export { OVERLAY_PRESETS, Overlay, OverlayAnimation, OverlayCloseReason, OverlayEdge, Overlay as OverlayEngine, OverlayEventMap, OverlayMountTarget, OverlayOptions, OverlayPreset, OverlayState, OverlayUpdate, SwipeToCloseConfig, createOverlay } from './overlay.cjs';
4
4
  import './transform-jVfAikE9.cjs';
5
5
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { d as SnapPoint, b as SheetMode, a as SnapPointDef, c as EngineOptions, f as ScrimOverlayPosition } from './BottomSheetEngine-BHjKFtnM.js';
2
- export { g as AnchorAnimationPreset, h as AnchorAnimationSpec, i as AnchorHandle, A as AnchorOptions, j as AnchorPosition, k as AnchorState, B as BottomSheetEngine, C as CloseReason, E as EngineState, P as Plugin, l as SCRIM_PRESETS, m as ScrimOverlayOptions, n as ScrimPreset, o as ScrimPresetConfig, p as ScrimStageDef, S as ScrimStagesOptions, q as ScrimUpdate, e as SheetEventMap, r as SnapId, T as TeardownScope, s as runAnchorTransition } from './BottomSheetEngine-BHjKFtnM.js';
1
+ import { d as SnapPoint, b as SheetMode, a as SnapPointDef, c as EngineOptions, f as ScrimOverlayPosition } from './BottomSheetEngine-BFTb0-4Z.js';
2
+ export { g as AnchorAnimationPreset, h as AnchorAnimationSpec, i as AnchorHandle, A as AnchorOptions, j as AnchorPosition, k as AnchorState, B as BottomSheetEngine, C as CloseReason, E as EngineState, P as Plugin, l as SCRIM_PRESETS, m as ScrimOverlayOptions, n as ScrimPreset, o as ScrimPresetConfig, p as ScrimStageDef, S as ScrimStagesOptions, q as ScrimUpdate, e as SheetEventMap, r as SnapId, T as TeardownScope, s as runAnchorTransition } from './BottomSheetEngine-BFTb0-4Z.js';
3
3
  export { OVERLAY_PRESETS, Overlay, OverlayAnimation, OverlayCloseReason, OverlayEdge, Overlay as OverlayEngine, OverlayEventMap, OverlayMountTarget, OverlayOptions, OverlayPreset, OverlayState, OverlayUpdate, SwipeToCloseConfig, createOverlay } from './overlay.js';
4
4
  import './transform-jVfAikE9.js';
5
5
 
package/dist/index.js CHANGED
@@ -2362,6 +2362,7 @@ var BottomSheetEngine = class {
2362
2362
  __publicField(this, "progressWriteSentinel", new WriteSentinel());
2363
2363
  __publicField(this, "isTopSheet", true);
2364
2364
  __publicField(this, "opening", false);
2365
+ __publicField(this, "allowOvershoot", false);
2365
2366
  __publicField(this, "progressPayload", {
2366
2367
  value: 0,
2367
2368
  size: 0
@@ -2914,45 +2915,52 @@ var BottomSheetEngine = class {
2914
2915
  }
2915
2916
  return out;
2916
2917
  }
2917
- measureContentExtent(vertical) {
2918
+ measureSheetNatural(vertical) {
2919
+ const el = this.element;
2918
2920
  const content = this.scrollContainer;
2919
- if (!content) return 0;
2920
- const targets = this.contentTargets();
2921
- if (targets.length === 0) {
2922
- return vertical ? content.scrollHeight : content.scrollWidth;
2923
- }
2924
- let min = Infinity;
2925
- let max = -Infinity;
2926
- for (const el of targets) {
2927
- const r = el.getBoundingClientRect();
2928
- if (vertical) {
2929
- if (r.top < min) min = r.top;
2930
- if (r.bottom > max) max = r.bottom;
2931
- } else {
2932
- if (r.left < min) min = r.left;
2933
- if (r.right > max) max = r.right;
2934
- }
2935
- }
2936
- if (!isFinite(min) || !isFinite(max) || max <= min) {
2937
- return vertical ? content.scrollHeight : content.scrollWidth;
2938
- }
2939
- let pad = 0;
2940
- if (typeof getComputedStyle !== "undefined") {
2941
- const cs = getComputedStyle(content);
2942
- pad = vertical ? (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.paddingBottom) || 0) : (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.paddingRight) || 0);
2943
- }
2944
- return max - min + pad;
2921
+ if (!content) {
2922
+ return vertical ? el.offsetHeight : el.offsetWidth;
2923
+ }
2924
+ const axis = vertical ? "height" : "width";
2925
+ const sheetStyle = el.style;
2926
+ const cs = content.style;
2927
+ const prevSheet = sheetStyle[axis];
2928
+ const prevFlex = cs.flex;
2929
+ const prevContent = vertical ? cs.height : cs.width;
2930
+ sheetStyle[axis] = "auto";
2931
+ cs.flex = "none";
2932
+ if (vertical) cs.height = "auto";
2933
+ else cs.width = "auto";
2934
+ const poked = vertical ? el.offsetHeight : el.offsetWidth;
2935
+ const contentBox = vertical ? content.clientHeight : content.clientWidth;
2936
+ const contentScroll = vertical ? content.scrollHeight : content.scrollWidth;
2937
+ const natural = Math.max(poked, poked - contentBox + contentScroll);
2938
+ sheetStyle[axis] = prevSheet;
2939
+ cs.flex = prevFlex;
2940
+ if (vertical) cs.height = prevContent;
2941
+ else cs.width = prevContent;
2942
+ return natural;
2945
2943
  }
2946
2944
  measureFitSize() {
2947
2945
  const vertical = layoutAxis(this.mode) === "height";
2948
- const handleSize = vertical ? this.handle.offsetHeight : this.handle.offsetWidth;
2949
- const content = this.scrollContainer;
2950
- const natural = content ? handleSize + this.measureContentExtent(vertical) : handleSize;
2946
+ const natural = this.measureSheetNatural(vertical);
2951
2947
  const capped = this.maxHeightCap !== void 0 ? Math.min(natural, this.maxHeightCap) : natural;
2952
2948
  if (typeof window === "undefined") return capped;
2953
- const viewport = vertical ? window.innerHeight : window.innerWidth;
2949
+ const viewport = this.containingExtent(vertical);
2954
2950
  return viewport > 0 ? Math.min(capped, viewport) : capped;
2955
2951
  }
2952
+ // The fit cap is the sheet's containing block, not always the window: a
2953
+ // position:fixed sheet nested under a transform/filter/will-change ancestor
2954
+ // is clipped to that ancestor, so capping by window.innerHeight oversizes the
2955
+ // sheet and the content/footer get clipped. offsetParent resolves to that
2956
+ // ancestor when present, and is null (→ viewport) for a plain fixed sheet.
2957
+ containingExtent(vertical) {
2958
+ const op = this.element.offsetParent;
2959
+ if (op && op !== document.body && op !== document.documentElement) {
2960
+ return vertical ? op.clientHeight : op.clientWidth;
2961
+ }
2962
+ return vertical ? window.innerHeight : window.innerWidth;
2963
+ }
2956
2964
  installFitObserver() {
2957
2965
  if (typeof ResizeObserver === "undefined") return;
2958
2966
  if (!this.snapPointsRaw.some((p) => p.size === "fit" || p.size === "content"))
@@ -3033,6 +3041,10 @@ var BottomSheetEngine = class {
3033
3041
  this.backdrop.style.opacity = "";
3034
3042
  this.backdrop.style.pointerEvents = "";
3035
3043
  }
3044
+ if (this.anchorHost) {
3045
+ this.anchorHost.style.removeProperty("--bs-size");
3046
+ this.anchorHost.style.removeProperty("--bs-progress");
3047
+ }
3036
3048
  if (this.screenComponent) {
3037
3049
  this.screenComponent.style.opacity = "";
3038
3050
  this.screenComponent.style.display = "";
@@ -3044,6 +3056,7 @@ var BottomSheetEngine = class {
3044
3056
  this.bus.emit(event, payload);
3045
3057
  }
3046
3058
  newCycle() {
3059
+ this.allowOvershoot = false;
3047
3060
  this.currentAbort.abort();
3048
3061
  this.currentAbort = new AbortController();
3049
3062
  return this.currentAbort.signal;
@@ -3109,6 +3122,7 @@ var BottomSheetEngine = class {
3109
3122
  seen.add(p.id);
3110
3123
  }
3111
3124
  this.snaps.setRaw(this.snapPointsRaw);
3125
+ this.clampToMaxHeight();
3112
3126
  this.scrim.invalidateOpacityCache();
3113
3127
  }
3114
3128
  getAllowedRange() {
@@ -3315,9 +3329,13 @@ var BottomSheetEngine = class {
3315
3329
  this.opening = true;
3316
3330
  sheetStack.promote(this.id);
3317
3331
  }
3318
- void this.animation.animateTo(target.size, velocity).then(() => {
3319
- this.opening = false;
3332
+ const settleCap = this.snaps.getMaxAxisSize();
3333
+ const settleSize = settleCap > 0 ? Math.min(target.size, settleCap) : target.size;
3334
+ this.allowOvershoot = true;
3335
+ void this.animation.animateTo(settleSize, velocity).then(() => {
3320
3336
  if (signal.aborted) return;
3337
+ this.allowOvershoot = false;
3338
+ this.opening = false;
3321
3339
  this.scrollCache.restore(target.id, previousSize, target.size);
3322
3340
  this.updateAriaSlider();
3323
3341
  this.emit("snap", {
@@ -3349,7 +3367,7 @@ var BottomSheetEngine = class {
3349
3367
  }
3350
3368
  applySize(size) {
3351
3369
  const cap = this.snaps.getMaxAxisSize();
3352
- const clamped = cap > 0 && size > cap && !this.gesture?.isDragging ? cap : size;
3370
+ const clamped = cap > 0 && size > cap && !this.gesture?.isDragging && !this.allowOvershoot ? cap : size;
3353
3371
  this.size = clamped;
3354
3372
  const offset = cap - clamped;
3355
3373
  const style = this.element.style;
@@ -1,4 +1,4 @@
1
- import { e as SheetEventMap } from '../BottomSheetEngine-CqiCz64W.cjs';
1
+ import { e as SheetEventMap } from '../BottomSheetEngine-7BDK2OWX.cjs';
2
2
  import '../transform-jVfAikE9.cjs';
3
3
 
4
4
  type FormikStateLike = {
@@ -1,4 +1,4 @@
1
- import { e as SheetEventMap } from '../BottomSheetEngine-BHjKFtnM.js';
1
+ import { e as SheetEventMap } from '../BottomSheetEngine-BFTb0-4Z.js';
2
2
  import '../transform-jVfAikE9.js';
3
3
 
4
4
  type FormikStateLike = {
@@ -1,4 +1,4 @@
1
- import { e as SheetEventMap } from '../BottomSheetEngine-CqiCz64W.cjs';
1
+ import { e as SheetEventMap } from '../BottomSheetEngine-7BDK2OWX.cjs';
2
2
  import '../transform-jVfAikE9.cjs';
3
3
 
4
4
  type RhfFormStateLike = {
@@ -1,4 +1,4 @@
1
- import { e as SheetEventMap } from '../BottomSheetEngine-BHjKFtnM.js';
1
+ import { e as SheetEventMap } from '../BottomSheetEngine-BFTb0-4Z.js';
2
2
  import '../transform-jVfAikE9.js';
3
3
 
4
4
  type RhfFormStateLike = {
package/dist/preact.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { BottomSheet, BottomSheetFromConfig, BottomSheetFromConfigProps, BottomSheetHandle, BottomSheetProps, HeaderProp, Overlay, OverlayHandle, OverlayProps, SheetConfig, UseBottomSheetRefs, UseBottomSheetReturn, UseOverlayReturn, useBottomSheet, useOverlay } from './react.cjs';
2
- export { E as EngineState, b as SheetMode, d as SnapPoint, a as SnapPointDef } from './BottomSheetEngine-CqiCz64W.cjs';
2
+ export { E as EngineState, b as SheetMode, d as SnapPoint, a as SnapPointDef } from './BottomSheetEngine-7BDK2OWX.cjs';
3
3
  export { OverlayEdge, OverlayOptions, OverlayState } from './overlay.cjs';
4
4
  import 'react';
5
5
  import './transform-jVfAikE9.cjs';
package/dist/preact.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { BottomSheet, BottomSheetFromConfig, BottomSheetFromConfigProps, BottomSheetHandle, BottomSheetProps, HeaderProp, Overlay, OverlayHandle, OverlayProps, SheetConfig, UseBottomSheetRefs, UseBottomSheetReturn, UseOverlayReturn, useBottomSheet, useOverlay } from './react.js';
2
- export { E as EngineState, b as SheetMode, d as SnapPoint, a as SnapPointDef } from './BottomSheetEngine-BHjKFtnM.js';
2
+ export { E as EngineState, b as SheetMode, d as SnapPoint, a as SnapPointDef } from './BottomSheetEngine-BFTb0-4Z.js';
3
3
  export { OverlayEdge, OverlayOptions, OverlayState } from './overlay.js';
4
4
  import 'react';
5
5
  import './transform-jVfAikE9.js';
package/dist/qwik.cjs CHANGED
@@ -2360,6 +2360,7 @@ var BottomSheetEngine = class {
2360
2360
  __publicField(this, "progressWriteSentinel", new WriteSentinel());
2361
2361
  __publicField(this, "isTopSheet", true);
2362
2362
  __publicField(this, "opening", false);
2363
+ __publicField(this, "allowOvershoot", false);
2363
2364
  __publicField(this, "progressPayload", {
2364
2365
  value: 0,
2365
2366
  size: 0
@@ -2912,45 +2913,52 @@ var BottomSheetEngine = class {
2912
2913
  }
2913
2914
  return out;
2914
2915
  }
2915
- measureContentExtent(vertical) {
2916
+ measureSheetNatural(vertical) {
2917
+ const el = this.element;
2916
2918
  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;
2919
+ if (!content) {
2920
+ return vertical ? el.offsetHeight : el.offsetWidth;
2921
+ }
2922
+ const axis = vertical ? "height" : "width";
2923
+ const sheetStyle = el.style;
2924
+ const cs = content.style;
2925
+ const prevSheet = sheetStyle[axis];
2926
+ const prevFlex = cs.flex;
2927
+ const prevContent = vertical ? cs.height : cs.width;
2928
+ sheetStyle[axis] = "auto";
2929
+ cs.flex = "none";
2930
+ if (vertical) cs.height = "auto";
2931
+ else cs.width = "auto";
2932
+ const poked = vertical ? el.offsetHeight : el.offsetWidth;
2933
+ const contentBox = vertical ? content.clientHeight : content.clientWidth;
2934
+ const contentScroll = vertical ? content.scrollHeight : content.scrollWidth;
2935
+ const natural = Math.max(poked, poked - contentBox + contentScroll);
2936
+ sheetStyle[axis] = prevSheet;
2937
+ cs.flex = prevFlex;
2938
+ if (vertical) cs.height = prevContent;
2939
+ else cs.width = prevContent;
2940
+ return natural;
2943
2941
  }
2944
2942
  measureFitSize() {
2945
2943
  const vertical = layoutAxis(this.mode) === "height";
2946
- const handleSize = vertical ? this.handle.offsetHeight : this.handle.offsetWidth;
2947
- const content = this.scrollContainer;
2948
- const natural = content ? handleSize + this.measureContentExtent(vertical) : handleSize;
2944
+ const natural = this.measureSheetNatural(vertical);
2949
2945
  const capped = this.maxHeightCap !== void 0 ? Math.min(natural, this.maxHeightCap) : natural;
2950
2946
  if (typeof window === "undefined") return capped;
2951
- const viewport = vertical ? window.innerHeight : window.innerWidth;
2947
+ const viewport = this.containingExtent(vertical);
2952
2948
  return viewport > 0 ? Math.min(capped, viewport) : capped;
2953
2949
  }
2950
+ // The fit cap is the sheet's containing block, not always the window: a
2951
+ // position:fixed sheet nested under a transform/filter/will-change ancestor
2952
+ // is clipped to that ancestor, so capping by window.innerHeight oversizes the
2953
+ // sheet and the content/footer get clipped. offsetParent resolves to that
2954
+ // ancestor when present, and is null (→ viewport) for a plain fixed sheet.
2955
+ containingExtent(vertical) {
2956
+ const op = this.element.offsetParent;
2957
+ if (op && op !== document.body && op !== document.documentElement) {
2958
+ return vertical ? op.clientHeight : op.clientWidth;
2959
+ }
2960
+ return vertical ? window.innerHeight : window.innerWidth;
2961
+ }
2954
2962
  installFitObserver() {
2955
2963
  if (typeof ResizeObserver === "undefined") return;
2956
2964
  if (!this.snapPointsRaw.some((p) => p.size === "fit" || p.size === "content"))
@@ -3031,6 +3039,10 @@ var BottomSheetEngine = class {
3031
3039
  this.backdrop.style.opacity = "";
3032
3040
  this.backdrop.style.pointerEvents = "";
3033
3041
  }
3042
+ if (this.anchorHost) {
3043
+ this.anchorHost.style.removeProperty("--bs-size");
3044
+ this.anchorHost.style.removeProperty("--bs-progress");
3045
+ }
3034
3046
  if (this.screenComponent) {
3035
3047
  this.screenComponent.style.opacity = "";
3036
3048
  this.screenComponent.style.display = "";
@@ -3042,6 +3054,7 @@ var BottomSheetEngine = class {
3042
3054
  this.bus.emit(event, payload);
3043
3055
  }
3044
3056
  newCycle() {
3057
+ this.allowOvershoot = false;
3045
3058
  this.currentAbort.abort();
3046
3059
  this.currentAbort = new AbortController();
3047
3060
  return this.currentAbort.signal;
@@ -3107,6 +3120,7 @@ var BottomSheetEngine = class {
3107
3120
  seen.add(p.id);
3108
3121
  }
3109
3122
  this.snaps.setRaw(this.snapPointsRaw);
3123
+ this.clampToMaxHeight();
3110
3124
  this.scrim.invalidateOpacityCache();
3111
3125
  }
3112
3126
  getAllowedRange() {
@@ -3313,9 +3327,13 @@ var BottomSheetEngine = class {
3313
3327
  this.opening = true;
3314
3328
  sheetStack.promote(this.id);
3315
3329
  }
3316
- void this.animation.animateTo(target.size, velocity).then(() => {
3317
- this.opening = false;
3330
+ const settleCap = this.snaps.getMaxAxisSize();
3331
+ const settleSize = settleCap > 0 ? Math.min(target.size, settleCap) : target.size;
3332
+ this.allowOvershoot = true;
3333
+ void this.animation.animateTo(settleSize, velocity).then(() => {
3318
3334
  if (signal.aborted) return;
3335
+ this.allowOvershoot = false;
3336
+ this.opening = false;
3319
3337
  this.scrollCache.restore(target.id, previousSize, target.size);
3320
3338
  this.updateAriaSlider();
3321
3339
  this.emit("snap", {
@@ -3347,7 +3365,7 @@ var BottomSheetEngine = class {
3347
3365
  }
3348
3366
  applySize(size) {
3349
3367
  const cap = this.snaps.getMaxAxisSize();
3350
- const clamped = cap > 0 && size > cap && !this.gesture?.isDragging ? cap : size;
3368
+ const clamped = cap > 0 && size > cap && !this.gesture?.isDragging && !this.allowOvershoot ? cap : size;
3351
3369
  this.size = clamped;
3352
3370
  const offset = cap - clamped;
3353
3371
  const style = this.element.style;
@@ -3439,6 +3457,8 @@ var BottomSheet = qwik.component$((props) => {
3439
3457
  const contentRef = qwik.useSignal();
3440
3458
  const backdropRef = qwik.useSignal();
3441
3459
  const scrimRef = qwik.useSignal();
3460
+ const headerRef = qwik.useSignal();
3461
+ const footerRef = qwik.useSignal();
3442
3462
  const initialActive = props.initial ?? props.snapPoints[0]?.id ?? "default";
3443
3463
  const state = qwik.useStore({
3444
3464
  size: 0,
@@ -3473,6 +3493,11 @@ var BottomSheet = qwik.component$((props) => {
3473
3493
  lockBodyScroll: props.lockBodyScroll,
3474
3494
  rubberBand: props.rubberBand,
3475
3495
  backdropRange: props.backdropRange,
3496
+ persistent: props.persistent,
3497
+ disableClose: props.disableClose,
3498
+ disableDrag: props.disableDrag,
3499
+ closeOnRouteChange: props.closeOnRouteChange,
3500
+ returnFocusTo: props.returnFocusTo,
3476
3501
  radius: props.radius,
3477
3502
  maxHeight: props.maxHeight
3478
3503
  };
@@ -3494,7 +3519,25 @@ var BottomSheet = qwik.component$((props) => {
3494
3519
  });
3495
3520
  engine.on("dragstart", sync);
3496
3521
  engine.on("dragend", sync);
3522
+ let onBackdropClick;
3523
+ if (props.backdrop !== false && props.closeOnBackdrop !== false && backdropRef.value) {
3524
+ onBackdropClick = () => {
3525
+ if (engine.canDismiss()) void engine.close("backdrop");
3526
+ };
3527
+ backdropRef.value.addEventListener("click", onBackdropClick);
3528
+ }
3529
+ const collapseEmpty = (el) => {
3530
+ if (!el) return;
3531
+ const empty = el.children.length === 0 && el.textContent?.trim() === "";
3532
+ if (empty) el.setAttribute("hidden", "");
3533
+ else el.removeAttribute("hidden");
3534
+ };
3535
+ collapseEmpty(headerRef.value);
3536
+ collapseEmpty(footerRef.value);
3497
3537
  cleanup(() => {
3538
+ if (onBackdropClick && backdropRef.value) {
3539
+ backdropRef.value.removeEventListener("click", onBackdropClick);
3540
+ }
3498
3541
  engineStore.engine = void 0;
3499
3542
  engine.destroy();
3500
3543
  });
@@ -3544,9 +3587,9 @@ var BottomSheet = qwik.component$((props) => {
3544
3587
  "aria-label": "Resize sheet"
3545
3588
  }
3546
3589
  ),
3547
- /* @__PURE__ */ jsxRuntime.jsx("div", { class: "bs-header", children: /* @__PURE__ */ jsxRuntime.jsx(qwik.Slot, { name: "header" }) }),
3590
+ /* @__PURE__ */ jsxRuntime.jsx("div", { class: "bs-header", ref: headerRef, children: /* @__PURE__ */ jsxRuntime.jsx(qwik.Slot, { name: "header" }) }),
3548
3591
  /* @__PURE__ */ jsxRuntime.jsx("div", { class: "bs-content", ref: contentRef, children: /* @__PURE__ */ jsxRuntime.jsx(qwik.Slot, {}) }),
3549
- /* @__PURE__ */ jsxRuntime.jsx("div", { class: "bs-footer", children: /* @__PURE__ */ jsxRuntime.jsx(qwik.Slot, { name: "footer" }) }),
3592
+ /* @__PURE__ */ jsxRuntime.jsx("div", { class: "bs-footer", ref: footerRef, children: /* @__PURE__ */ jsxRuntime.jsx(qwik.Slot, { name: "footer" }) }),
3550
3593
  /* @__PURE__ */ jsxRuntime.jsx("span", { class: "bs-sr-only", role: "status", "aria-live": "polite", children: state.activeId })
3551
3594
  ]
3552
3595
  }
package/dist/qwik.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as _builder_io_qwik from '@builder.io/qwik';
2
2
  import { QRL } from '@builder.io/qwik';
3
- import { a as SnapPointDef, b as SheetMode, E as EngineState } from './BottomSheetEngine-CqiCz64W.cjs';
4
- export { c as EngineOptions, d as SnapPoint } from './BottomSheetEngine-CqiCz64W.cjs';
3
+ import { a as SnapPointDef, b as SheetMode, c as EngineOptions, E as EngineState } from './BottomSheetEngine-7BDK2OWX.cjs';
4
+ export { d as SnapPoint } from './BottomSheetEngine-7BDK2OWX.cjs';
5
5
  import './transform-jVfAikE9.cjs';
6
6
 
7
7
  type BottomSheetProps<TId extends string = string> = {
@@ -23,6 +23,11 @@ type BottomSheetProps<TId extends string = string> = {
23
23
  backdropRange?: [number, number];
24
24
  backdrop?: boolean;
25
25
  closeOnBackdrop?: boolean;
26
+ persistent?: boolean;
27
+ disableClose?: boolean;
28
+ disableDrag?: boolean;
29
+ closeOnRouteChange?: boolean;
30
+ returnFocusTo?: EngineOptions["returnFocusTo"];
26
31
  ariaLabel?: string;
27
32
  radius?: string | number;
28
33
  maxHeight?: string | number;
@@ -33,4 +38,4 @@ type BottomSheetProps<TId extends string = string> = {
33
38
  };
34
39
  declare const BottomSheet: _builder_io_qwik.Component<BottomSheetProps<string>>;
35
40
 
36
- export { BottomSheet, type BottomSheetProps, EngineState, SheetMode, SnapPointDef };
41
+ export { BottomSheet, type BottomSheetProps, EngineOptions, EngineState, SheetMode, SnapPointDef };
package/dist/qwik.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as _builder_io_qwik from '@builder.io/qwik';
2
2
  import { QRL } from '@builder.io/qwik';
3
- import { a as SnapPointDef, b as SheetMode, E as EngineState } from './BottomSheetEngine-BHjKFtnM.js';
4
- export { c as EngineOptions, d as SnapPoint } from './BottomSheetEngine-BHjKFtnM.js';
3
+ import { a as SnapPointDef, b as SheetMode, c as EngineOptions, E as EngineState } from './BottomSheetEngine-BFTb0-4Z.js';
4
+ export { d as SnapPoint } from './BottomSheetEngine-BFTb0-4Z.js';
5
5
  import './transform-jVfAikE9.js';
6
6
 
7
7
  type BottomSheetProps<TId extends string = string> = {
@@ -23,6 +23,11 @@ type BottomSheetProps<TId extends string = string> = {
23
23
  backdropRange?: [number, number];
24
24
  backdrop?: boolean;
25
25
  closeOnBackdrop?: boolean;
26
+ persistent?: boolean;
27
+ disableClose?: boolean;
28
+ disableDrag?: boolean;
29
+ closeOnRouteChange?: boolean;
30
+ returnFocusTo?: EngineOptions["returnFocusTo"];
26
31
  ariaLabel?: string;
27
32
  radius?: string | number;
28
33
  maxHeight?: string | number;
@@ -33,4 +38,4 @@ type BottomSheetProps<TId extends string = string> = {
33
38
  };
34
39
  declare const BottomSheet: _builder_io_qwik.Component<BottomSheetProps<string>>;
35
40
 
36
- export { BottomSheet, type BottomSheetProps, EngineState, SheetMode, SnapPointDef };
41
+ export { BottomSheet, type BottomSheetProps, EngineOptions, EngineState, SheetMode, SnapPointDef };