@surdeddd/bottom-sheet 0.6.1 → 0.8.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.
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
@@ -2652,8 +2653,8 @@ var BottomSheetEngine = class {
2652
2653
  this.updateAriaSlider();
2653
2654
  this.emit("snap", {
2654
2655
  id,
2655
- size: target.size,
2656
- progress: this.computeProgress(target.size)
2656
+ size: this.size,
2657
+ progress: this.computeProgress(this.size)
2657
2658
  });
2658
2659
  if (wasClosed && target.size > 0) {
2659
2660
  this.emit("open", { id });
@@ -2732,12 +2733,12 @@ var BottomSheetEngine = class {
2732
2733
  const value = typeof h === "number" ? `${h}px` : h;
2733
2734
  const axis = layoutAxis(this.mode);
2734
2735
  this.element.style.setProperty(
2735
- axis === "height" ? "maxHeight" : "maxWidth",
2736
+ axis === "height" ? "max-height" : "max-width",
2736
2737
  value
2737
2738
  );
2738
2739
  if (typeof h === "number") {
2739
2740
  this.maxHeightCap = h;
2740
- this.clampToMaxHeight();
2741
+ this.recompute();
2741
2742
  } else if (typeof window !== "undefined") {
2742
2743
  const probe2 = document.createElement("div");
2743
2744
  probe2.style.cssText = `position:absolute;visibility:hidden;pointer-events:none;${axis === "height" ? "height" : "width"}:${value};`;
@@ -2745,7 +2746,7 @@ var BottomSheetEngine = class {
2745
2746
  const measured = axis === "height" ? probe2.offsetHeight : probe2.offsetWidth;
2746
2747
  probe2.remove();
2747
2748
  this.maxHeightCap = measured > 0 ? measured : void 0;
2748
- this.clampToMaxHeight();
2749
+ this.recompute();
2749
2750
  }
2750
2751
  }
2751
2752
  clampToMaxHeight() {
@@ -2753,9 +2754,6 @@ var BottomSheetEngine = class {
2753
2754
  if (this.snaps.getMaxAxisSize() > this.maxHeightCap) {
2754
2755
  this.snaps.setMaxAxisSize(this.maxHeightCap);
2755
2756
  }
2756
- if (this.size > this.maxHeightCap && !this.gesture?.isDragging) {
2757
- this.applySize(this.maxHeightCap);
2758
- }
2759
2757
  }
2760
2758
  setAllowed(ids, snap) {
2761
2759
  if (this.destroyed) return;
@@ -2893,6 +2891,7 @@ var BottomSheetEngine = class {
2893
2891
  recompute() {
2894
2892
  if (this.destroyed) return;
2895
2893
  this.snaps.recompute();
2894
+ this.clampToMaxHeight();
2896
2895
  this.scrim.invalidateOpacityCache();
2897
2896
  if (this.gesture?.isDragging) return;
2898
2897
  const current = this.snaps.findById(this.activeId);
@@ -2916,43 +2915,36 @@ var BottomSheetEngine = class {
2916
2915
  }
2917
2916
  return out;
2918
2917
  }
2919
- measureContentExtent(vertical) {
2918
+ measureSheetNatural(vertical) {
2919
+ const el = this.element;
2920
2920
  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;
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 natural = vertical ? el.offsetHeight : el.offsetWidth;
2935
+ sheetStyle[axis] = prevSheet;
2936
+ cs.flex = prevFlex;
2937
+ if (vertical) cs.height = prevContent;
2938
+ else cs.width = prevContent;
2939
+ return natural;
2947
2940
  }
2948
2941
  measureFitSize() {
2949
2942
  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;
2953
- if (typeof window === "undefined") return natural;
2943
+ const natural = this.measureSheetNatural(vertical);
2944
+ const capped = this.maxHeightCap !== void 0 ? Math.min(natural, this.maxHeightCap) : natural;
2945
+ if (typeof window === "undefined") return capped;
2954
2946
  const viewport = vertical ? window.innerHeight : window.innerWidth;
2955
- return viewport > 0 ? Math.min(natural, viewport) : natural;
2947
+ return viewport > 0 ? Math.min(capped, viewport) : capped;
2956
2948
  }
2957
2949
  installFitObserver() {
2958
2950
  if (typeof ResizeObserver === "undefined") return;
@@ -3034,6 +3026,10 @@ var BottomSheetEngine = class {
3034
3026
  this.backdrop.style.opacity = "";
3035
3027
  this.backdrop.style.pointerEvents = "";
3036
3028
  }
3029
+ if (this.anchorHost) {
3030
+ this.anchorHost.style.removeProperty("--bs-size");
3031
+ this.anchorHost.style.removeProperty("--bs-progress");
3032
+ }
3037
3033
  if (this.screenComponent) {
3038
3034
  this.screenComponent.style.opacity = "";
3039
3035
  this.screenComponent.style.display = "";
@@ -3045,6 +3041,7 @@ var BottomSheetEngine = class {
3045
3041
  this.bus.emit(event, payload);
3046
3042
  }
3047
3043
  newCycle() {
3044
+ this.allowOvershoot = false;
3048
3045
  this.currentAbort.abort();
3049
3046
  this.currentAbort = new AbortController();
3050
3047
  return this.currentAbort.signal;
@@ -3110,6 +3107,7 @@ var BottomSheetEngine = class {
3110
3107
  seen.add(p.id);
3111
3108
  }
3112
3109
  this.snaps.setRaw(this.snapPointsRaw);
3110
+ this.clampToMaxHeight();
3113
3111
  this.scrim.invalidateOpacityCache();
3114
3112
  }
3115
3113
  getAllowedRange() {
@@ -3316,15 +3314,19 @@ var BottomSheetEngine = class {
3316
3314
  this.opening = true;
3317
3315
  sheetStack.promote(this.id);
3318
3316
  }
3319
- void this.animation.animateTo(target.size, velocity).then(() => {
3320
- this.opening = false;
3317
+ const settleCap = this.snaps.getMaxAxisSize();
3318
+ const settleSize = settleCap > 0 ? Math.min(target.size, settleCap) : target.size;
3319
+ this.allowOvershoot = true;
3320
+ void this.animation.animateTo(settleSize, velocity).then(() => {
3321
3321
  if (signal.aborted) return;
3322
+ this.allowOvershoot = false;
3323
+ this.opening = false;
3322
3324
  this.scrollCache.restore(target.id, previousSize, target.size);
3323
3325
  this.updateAriaSlider();
3324
3326
  this.emit("snap", {
3325
3327
  id: target.id,
3326
- size: target.size,
3327
- progress: this.computeProgress(target.size)
3328
+ size: this.size,
3329
+ progress: this.computeProgress(this.size)
3328
3330
  });
3329
3331
  this.haptic();
3330
3332
  if (previousSnapSize === 0 && target.size > 0) {
@@ -3349,23 +3351,25 @@ var BottomSheetEngine = class {
3349
3351
  }
3350
3352
  }
3351
3353
  applySize(size) {
3352
- this.size = size;
3353
- const offset = this.snaps.getMaxAxisSize() - size;
3354
+ const cap = this.snaps.getMaxAxisSize();
3355
+ const clamped = cap > 0 && size > cap && !this.gesture?.isDragging && !this.allowOvershoot ? cap : size;
3356
+ this.size = clamped;
3357
+ const offset = cap - clamped;
3354
3358
  const style = this.element.style;
3355
3359
  style.transform = this.transformTemplate(offset);
3356
- if (this.sizeWriteSentinel.shouldWrite(size, SIZE_WRITE_EPSILON)) {
3357
- style.setProperty("--bs-size", `${size}px`);
3360
+ if (this.sizeWriteSentinel.shouldWrite(clamped, SIZE_WRITE_EPSILON)) {
3361
+ style.setProperty("--bs-size", `${clamped}px`);
3358
3362
  if (this.scrimParent) {
3359
- this.scrimParent.style.setProperty("--bs-size", `${size}px`);
3363
+ this.scrimParent.style.setProperty("--bs-size", `${clamped}px`);
3360
3364
  }
3361
3365
  if (this.anchorHost && this.anchorHost !== this.scrimParent) {
3362
- this.anchorHost.style.setProperty("--bs-size", `${size}px`);
3366
+ this.anchorHost.style.setProperty("--bs-size", `${clamped}px`);
3363
3367
  }
3364
3368
  if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
3365
- this.rootEl.style.setProperty("--bs-size", `${size}px`);
3369
+ this.rootEl.style.setProperty("--bs-size", `${clamped}px`);
3366
3370
  }
3367
3371
  }
3368
- const progress = this.computeProgress(size);
3372
+ const progress = this.computeProgress(clamped);
3369
3373
  const progressChanged = this.progressWriteSentinel.shouldWrite(
3370
3374
  progress,
3371
3375
  OPACITY_WRITE_EPSILON
@@ -3382,14 +3386,15 @@ var BottomSheetEngine = class {
3382
3386
  this.scrim.applyOpacity(progress, progressChanged);
3383
3387
  if (progressChanged && this.bus.listenerCount("progress") > 0) {
3384
3388
  this.progressPayload.value = progress;
3385
- this.progressPayload.size = size;
3389
+ this.progressPayload.size = clamped;
3386
3390
  this.emit("progress", this.progressPayload);
3387
3391
  }
3388
3392
  }
3389
3393
  computeProgress(size) {
3390
3394
  const { min, max } = this.getAllowedRange();
3391
- if (max <= min) return 0;
3392
- return Math.min(Math.max((size - min) / (max - min), 0), 1);
3395
+ const reachableMax = Math.min(max, this.snaps.getMaxAxisSize());
3396
+ if (reachableMax <= min) return 0;
3397
+ return Math.min(Math.max((size - min) / (reachableMax - min), 0), 1);
3393
3398
  }
3394
3399
  handleOpen() {
3395
3400
  sheetStack.promote(this.id);
@@ -3413,8 +3418,8 @@ var BottomSheetEngine = class {
3413
3418
  this.updateAriaSlider();
3414
3419
  this.emit("snap", {
3415
3420
  id: target.id,
3416
- size: target.size,
3417
- progress: this.computeProgress(target.size)
3421
+ size: this.size,
3422
+ progress: this.computeProgress(this.size)
3418
3423
  });
3419
3424
  if (target.size > 0 && !this.lifecycle.isInstalled) {
3420
3425
  this.emit("open", { id: target.id });
@@ -1,4 +1,4 @@
1
- import { e as SheetEventMap } from '../BottomSheetEngine-CqiCz64W.cjs';
1
+ import { e as SheetEventMap } from '../BottomSheetEngine-BD1mSExI.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-BDGRWa2i.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-BD1mSExI.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-BDGRWa2i.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-BD1mSExI.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-BDGRWa2i.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
@@ -2650,8 +2651,8 @@ var BottomSheetEngine = class {
2650
2651
  this.updateAriaSlider();
2651
2652
  this.emit("snap", {
2652
2653
  id,
2653
- size: target.size,
2654
- progress: this.computeProgress(target.size)
2654
+ size: this.size,
2655
+ progress: this.computeProgress(this.size)
2655
2656
  });
2656
2657
  if (wasClosed && target.size > 0) {
2657
2658
  this.emit("open", { id });
@@ -2730,12 +2731,12 @@ var BottomSheetEngine = class {
2730
2731
  const value = typeof h === "number" ? `${h}px` : h;
2731
2732
  const axis = layoutAxis(this.mode);
2732
2733
  this.element.style.setProperty(
2733
- axis === "height" ? "maxHeight" : "maxWidth",
2734
+ axis === "height" ? "max-height" : "max-width",
2734
2735
  value
2735
2736
  );
2736
2737
  if (typeof h === "number") {
2737
2738
  this.maxHeightCap = h;
2738
- this.clampToMaxHeight();
2739
+ this.recompute();
2739
2740
  } else if (typeof window !== "undefined") {
2740
2741
  const probe2 = document.createElement("div");
2741
2742
  probe2.style.cssText = `position:absolute;visibility:hidden;pointer-events:none;${axis === "height" ? "height" : "width"}:${value};`;
@@ -2743,7 +2744,7 @@ var BottomSheetEngine = class {
2743
2744
  const measured = axis === "height" ? probe2.offsetHeight : probe2.offsetWidth;
2744
2745
  probe2.remove();
2745
2746
  this.maxHeightCap = measured > 0 ? measured : void 0;
2746
- this.clampToMaxHeight();
2747
+ this.recompute();
2747
2748
  }
2748
2749
  }
2749
2750
  clampToMaxHeight() {
@@ -2751,9 +2752,6 @@ var BottomSheetEngine = class {
2751
2752
  if (this.snaps.getMaxAxisSize() > this.maxHeightCap) {
2752
2753
  this.snaps.setMaxAxisSize(this.maxHeightCap);
2753
2754
  }
2754
- if (this.size > this.maxHeightCap && !this.gesture?.isDragging) {
2755
- this.applySize(this.maxHeightCap);
2756
- }
2757
2755
  }
2758
2756
  setAllowed(ids, snap) {
2759
2757
  if (this.destroyed) return;
@@ -2891,6 +2889,7 @@ var BottomSheetEngine = class {
2891
2889
  recompute() {
2892
2890
  if (this.destroyed) return;
2893
2891
  this.snaps.recompute();
2892
+ this.clampToMaxHeight();
2894
2893
  this.scrim.invalidateOpacityCache();
2895
2894
  if (this.gesture?.isDragging) return;
2896
2895
  const current = this.snaps.findById(this.activeId);
@@ -2914,43 +2913,36 @@ var BottomSheetEngine = class {
2914
2913
  }
2915
2914
  return out;
2916
2915
  }
2917
- measureContentExtent(vertical) {
2916
+ measureSheetNatural(vertical) {
2917
+ const el = this.element;
2918
2918
  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;
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 natural = vertical ? el.offsetHeight : el.offsetWidth;
2933
+ sheetStyle[axis] = prevSheet;
2934
+ cs.flex = prevFlex;
2935
+ if (vertical) cs.height = prevContent;
2936
+ else cs.width = prevContent;
2937
+ return natural;
2945
2938
  }
2946
2939
  measureFitSize() {
2947
2940
  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;
2951
- if (typeof window === "undefined") return natural;
2941
+ const natural = this.measureSheetNatural(vertical);
2942
+ const capped = this.maxHeightCap !== void 0 ? Math.min(natural, this.maxHeightCap) : natural;
2943
+ if (typeof window === "undefined") return capped;
2952
2944
  const viewport = vertical ? window.innerHeight : window.innerWidth;
2953
- return viewport > 0 ? Math.min(natural, viewport) : natural;
2945
+ return viewport > 0 ? Math.min(capped, viewport) : capped;
2954
2946
  }
2955
2947
  installFitObserver() {
2956
2948
  if (typeof ResizeObserver === "undefined") return;
@@ -3032,6 +3024,10 @@ var BottomSheetEngine = class {
3032
3024
  this.backdrop.style.opacity = "";
3033
3025
  this.backdrop.style.pointerEvents = "";
3034
3026
  }
3027
+ if (this.anchorHost) {
3028
+ this.anchorHost.style.removeProperty("--bs-size");
3029
+ this.anchorHost.style.removeProperty("--bs-progress");
3030
+ }
3035
3031
  if (this.screenComponent) {
3036
3032
  this.screenComponent.style.opacity = "";
3037
3033
  this.screenComponent.style.display = "";
@@ -3043,6 +3039,7 @@ var BottomSheetEngine = class {
3043
3039
  this.bus.emit(event, payload);
3044
3040
  }
3045
3041
  newCycle() {
3042
+ this.allowOvershoot = false;
3046
3043
  this.currentAbort.abort();
3047
3044
  this.currentAbort = new AbortController();
3048
3045
  return this.currentAbort.signal;
@@ -3108,6 +3105,7 @@ var BottomSheetEngine = class {
3108
3105
  seen.add(p.id);
3109
3106
  }
3110
3107
  this.snaps.setRaw(this.snapPointsRaw);
3108
+ this.clampToMaxHeight();
3111
3109
  this.scrim.invalidateOpacityCache();
3112
3110
  }
3113
3111
  getAllowedRange() {
@@ -3314,15 +3312,19 @@ var BottomSheetEngine = class {
3314
3312
  this.opening = true;
3315
3313
  sheetStack.promote(this.id);
3316
3314
  }
3317
- void this.animation.animateTo(target.size, velocity).then(() => {
3318
- this.opening = false;
3315
+ const settleCap = this.snaps.getMaxAxisSize();
3316
+ const settleSize = settleCap > 0 ? Math.min(target.size, settleCap) : target.size;
3317
+ this.allowOvershoot = true;
3318
+ void this.animation.animateTo(settleSize, velocity).then(() => {
3319
3319
  if (signal.aborted) return;
3320
+ this.allowOvershoot = false;
3321
+ this.opening = false;
3320
3322
  this.scrollCache.restore(target.id, previousSize, target.size);
3321
3323
  this.updateAriaSlider();
3322
3324
  this.emit("snap", {
3323
3325
  id: target.id,
3324
- size: target.size,
3325
- progress: this.computeProgress(target.size)
3326
+ size: this.size,
3327
+ progress: this.computeProgress(this.size)
3326
3328
  });
3327
3329
  this.haptic();
3328
3330
  if (previousSnapSize === 0 && target.size > 0) {
@@ -3347,23 +3349,25 @@ var BottomSheetEngine = class {
3347
3349
  }
3348
3350
  }
3349
3351
  applySize(size) {
3350
- this.size = size;
3351
- const offset = this.snaps.getMaxAxisSize() - size;
3352
+ const cap = this.snaps.getMaxAxisSize();
3353
+ const clamped = cap > 0 && size > cap && !this.gesture?.isDragging && !this.allowOvershoot ? cap : size;
3354
+ this.size = clamped;
3355
+ const offset = cap - clamped;
3352
3356
  const style = this.element.style;
3353
3357
  style.transform = this.transformTemplate(offset);
3354
- if (this.sizeWriteSentinel.shouldWrite(size, SIZE_WRITE_EPSILON)) {
3355
- style.setProperty("--bs-size", `${size}px`);
3358
+ if (this.sizeWriteSentinel.shouldWrite(clamped, SIZE_WRITE_EPSILON)) {
3359
+ style.setProperty("--bs-size", `${clamped}px`);
3356
3360
  if (this.scrimParent) {
3357
- this.scrimParent.style.setProperty("--bs-size", `${size}px`);
3361
+ this.scrimParent.style.setProperty("--bs-size", `${clamped}px`);
3358
3362
  }
3359
3363
  if (this.anchorHost && this.anchorHost !== this.scrimParent) {
3360
- this.anchorHost.style.setProperty("--bs-size", `${size}px`);
3364
+ this.anchorHost.style.setProperty("--bs-size", `${clamped}px`);
3361
3365
  }
3362
3366
  if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
3363
- this.rootEl.style.setProperty("--bs-size", `${size}px`);
3367
+ this.rootEl.style.setProperty("--bs-size", `${clamped}px`);
3364
3368
  }
3365
3369
  }
3366
- const progress = this.computeProgress(size);
3370
+ const progress = this.computeProgress(clamped);
3367
3371
  const progressChanged = this.progressWriteSentinel.shouldWrite(
3368
3372
  progress,
3369
3373
  OPACITY_WRITE_EPSILON
@@ -3380,14 +3384,15 @@ var BottomSheetEngine = class {
3380
3384
  this.scrim.applyOpacity(progress, progressChanged);
3381
3385
  if (progressChanged && this.bus.listenerCount("progress") > 0) {
3382
3386
  this.progressPayload.value = progress;
3383
- this.progressPayload.size = size;
3387
+ this.progressPayload.size = clamped;
3384
3388
  this.emit("progress", this.progressPayload);
3385
3389
  }
3386
3390
  }
3387
3391
  computeProgress(size) {
3388
3392
  const { min, max } = this.getAllowedRange();
3389
- if (max <= min) return 0;
3390
- return Math.min(Math.max((size - min) / (max - min), 0), 1);
3393
+ const reachableMax = Math.min(max, this.snaps.getMaxAxisSize());
3394
+ if (reachableMax <= min) return 0;
3395
+ return Math.min(Math.max((size - min) / (reachableMax - min), 0), 1);
3391
3396
  }
3392
3397
  handleOpen() {
3393
3398
  sheetStack.promote(this.id);
@@ -3411,8 +3416,8 @@ var BottomSheetEngine = class {
3411
3416
  this.updateAriaSlider();
3412
3417
  this.emit("snap", {
3413
3418
  id: target.id,
3414
- size: target.size,
3415
- progress: this.computeProgress(target.size)
3419
+ size: this.size,
3420
+ progress: this.computeProgress(this.size)
3416
3421
  });
3417
3422
  if (target.size > 0 && !this.lifecycle.isInstalled) {
3418
3423
  this.emit("open", { id: target.id });
@@ -3437,6 +3442,8 @@ var BottomSheet = qwik.component$((props) => {
3437
3442
  const contentRef = qwik.useSignal();
3438
3443
  const backdropRef = qwik.useSignal();
3439
3444
  const scrimRef = qwik.useSignal();
3445
+ const headerRef = qwik.useSignal();
3446
+ const footerRef = qwik.useSignal();
3440
3447
  const initialActive = props.initial ?? props.snapPoints[0]?.id ?? "default";
3441
3448
  const state = qwik.useStore({
3442
3449
  size: 0,
@@ -3471,6 +3478,11 @@ var BottomSheet = qwik.component$((props) => {
3471
3478
  lockBodyScroll: props.lockBodyScroll,
3472
3479
  rubberBand: props.rubberBand,
3473
3480
  backdropRange: props.backdropRange,
3481
+ persistent: props.persistent,
3482
+ disableClose: props.disableClose,
3483
+ disableDrag: props.disableDrag,
3484
+ closeOnRouteChange: props.closeOnRouteChange,
3485
+ returnFocusTo: props.returnFocusTo,
3474
3486
  radius: props.radius,
3475
3487
  maxHeight: props.maxHeight
3476
3488
  };
@@ -3492,7 +3504,25 @@ var BottomSheet = qwik.component$((props) => {
3492
3504
  });
3493
3505
  engine.on("dragstart", sync);
3494
3506
  engine.on("dragend", sync);
3507
+ let onBackdropClick;
3508
+ if (props.backdrop !== false && props.closeOnBackdrop !== false && backdropRef.value) {
3509
+ onBackdropClick = () => {
3510
+ if (engine.canDismiss()) void engine.close("backdrop");
3511
+ };
3512
+ backdropRef.value.addEventListener("click", onBackdropClick);
3513
+ }
3514
+ const collapseEmpty = (el) => {
3515
+ if (!el) return;
3516
+ const empty = el.children.length === 0 && el.textContent?.trim() === "";
3517
+ if (empty) el.setAttribute("hidden", "");
3518
+ else el.removeAttribute("hidden");
3519
+ };
3520
+ collapseEmpty(headerRef.value);
3521
+ collapseEmpty(footerRef.value);
3495
3522
  cleanup(() => {
3523
+ if (onBackdropClick && backdropRef.value) {
3524
+ backdropRef.value.removeEventListener("click", onBackdropClick);
3525
+ }
3496
3526
  engineStore.engine = void 0;
3497
3527
  engine.destroy();
3498
3528
  });
@@ -3542,9 +3572,9 @@ var BottomSheet = qwik.component$((props) => {
3542
3572
  "aria-label": "Resize sheet"
3543
3573
  }
3544
3574
  ),
3545
- /* @__PURE__ */ jsxRuntime.jsx("div", { class: "bs-header", children: /* @__PURE__ */ jsxRuntime.jsx(qwik.Slot, { name: "header" }) }),
3575
+ /* @__PURE__ */ jsxRuntime.jsx("div", { class: "bs-header", ref: headerRef, children: /* @__PURE__ */ jsxRuntime.jsx(qwik.Slot, { name: "header" }) }),
3546
3576
  /* @__PURE__ */ jsxRuntime.jsx("div", { class: "bs-content", ref: contentRef, children: /* @__PURE__ */ jsxRuntime.jsx(qwik.Slot, {}) }),
3547
- /* @__PURE__ */ jsxRuntime.jsx("div", { class: "bs-footer", children: /* @__PURE__ */ jsxRuntime.jsx(qwik.Slot, { name: "footer" }) }),
3577
+ /* @__PURE__ */ jsxRuntime.jsx("div", { class: "bs-footer", ref: footerRef, children: /* @__PURE__ */ jsxRuntime.jsx(qwik.Slot, { name: "footer" }) }),
3548
3578
  /* @__PURE__ */ jsxRuntime.jsx("span", { class: "bs-sr-only", role: "status", "aria-live": "polite", children: state.activeId })
3549
3579
  ]
3550
3580
  }
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-BD1mSExI.cjs';
4
+ export { d as SnapPoint } from './BottomSheetEngine-BD1mSExI.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-BDGRWa2i.js';
4
+ export { d as SnapPoint } from './BottomSheetEngine-BDGRWa2i.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 };