@surdeddd/bottom-sheet 0.6.0 → 0.7.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/svelte.cjs CHANGED
@@ -2644,7 +2644,9 @@ var BottomSheetEngine = class {
2644
2644
  const previousSize = this.size;
2645
2645
  this.scrollCache.cache(previousId, previousSize, target.size);
2646
2646
  this.activeId = id;
2647
- if (wasClosed && target.size > 0) {
2647
+ const rawTargetSize = this.snapPointsRaw.find((p) => p.id === id)?.size;
2648
+ const opensToRest = id === "closed" || rawTargetSize === 0;
2649
+ if (wasClosed && !opensToRest) {
2648
2650
  this.opening = true;
2649
2651
  sheetStack.promote(this.id);
2650
2652
  }
@@ -2669,8 +2671,8 @@ var BottomSheetEngine = class {
2669
2671
  this.updateAriaSlider();
2670
2672
  this.emit("snap", {
2671
2673
  id,
2672
- size: target.size,
2673
- progress: this.computeProgress(target.size)
2674
+ size: this.size,
2675
+ progress: this.computeProgress(this.size)
2674
2676
  });
2675
2677
  if (wasClosed && target.size > 0) {
2676
2678
  this.emit("open", { id });
@@ -2749,12 +2751,12 @@ var BottomSheetEngine = class {
2749
2751
  const value = typeof h === "number" ? `${h}px` : h;
2750
2752
  const axis = layoutAxis(this.mode);
2751
2753
  this.element.style.setProperty(
2752
- axis === "height" ? "maxHeight" : "maxWidth",
2754
+ axis === "height" ? "max-height" : "max-width",
2753
2755
  value
2754
2756
  );
2755
2757
  if (typeof h === "number") {
2756
2758
  this.maxHeightCap = h;
2757
- this.clampToMaxHeight();
2759
+ this.recompute();
2758
2760
  } else if (typeof window !== "undefined") {
2759
2761
  const probe2 = document.createElement("div");
2760
2762
  probe2.style.cssText = `position:absolute;visibility:hidden;pointer-events:none;${axis === "height" ? "height" : "width"}:${value};`;
@@ -2762,7 +2764,7 @@ var BottomSheetEngine = class {
2762
2764
  const measured = axis === "height" ? probe2.offsetHeight : probe2.offsetWidth;
2763
2765
  probe2.remove();
2764
2766
  this.maxHeightCap = measured > 0 ? measured : void 0;
2765
- this.clampToMaxHeight();
2767
+ this.recompute();
2766
2768
  }
2767
2769
  }
2768
2770
  clampToMaxHeight() {
@@ -2770,9 +2772,6 @@ var BottomSheetEngine = class {
2770
2772
  if (this.snaps.getMaxAxisSize() > this.maxHeightCap) {
2771
2773
  this.snaps.setMaxAxisSize(this.maxHeightCap);
2772
2774
  }
2773
- if (this.size > this.maxHeightCap && !this.gesture?.isDragging) {
2774
- this.applySize(this.maxHeightCap);
2775
- }
2776
2775
  }
2777
2776
  setAllowed(ids, snap) {
2778
2777
  if (this.destroyed) return;
@@ -2910,6 +2909,7 @@ var BottomSheetEngine = class {
2910
2909
  recompute() {
2911
2910
  if (this.destroyed) return;
2912
2911
  this.snaps.recompute();
2912
+ this.clampToMaxHeight();
2913
2913
  this.scrim.invalidateOpacityCache();
2914
2914
  if (this.gesture?.isDragging) return;
2915
2915
  const current = this.snaps.findById(this.activeId);
@@ -2967,9 +2967,10 @@ var BottomSheetEngine = class {
2967
2967
  const handleSize = vertical ? this.handle.offsetHeight : this.handle.offsetWidth;
2968
2968
  const content = this.scrollContainer;
2969
2969
  const natural = content ? handleSize + this.measureContentExtent(vertical) : handleSize;
2970
- if (typeof window === "undefined") return natural;
2970
+ const capped = this.maxHeightCap !== void 0 ? Math.min(natural, this.maxHeightCap) : natural;
2971
+ if (typeof window === "undefined") return capped;
2971
2972
  const viewport = vertical ? window.innerHeight : window.innerWidth;
2972
- return viewport > 0 ? Math.min(natural, viewport) : natural;
2973
+ return viewport > 0 ? Math.min(capped, viewport) : capped;
2973
2974
  }
2974
2975
  installFitObserver() {
2975
2976
  if (typeof ResizeObserver === "undefined") return;
@@ -3340,8 +3341,8 @@ var BottomSheetEngine = class {
3340
3341
  this.updateAriaSlider();
3341
3342
  this.emit("snap", {
3342
3343
  id: target.id,
3343
- size: target.size,
3344
- progress: this.computeProgress(target.size)
3344
+ size: this.size,
3345
+ progress: this.computeProgress(this.size)
3345
3346
  });
3346
3347
  this.haptic();
3347
3348
  if (previousSnapSize === 0 && target.size > 0) {
@@ -3366,23 +3367,25 @@ var BottomSheetEngine = class {
3366
3367
  }
3367
3368
  }
3368
3369
  applySize(size) {
3369
- this.size = size;
3370
- const offset = this.snaps.getMaxAxisSize() - size;
3370
+ const cap = this.snaps.getMaxAxisSize();
3371
+ const clamped = cap > 0 && size > cap && !this.gesture?.isDragging ? cap : size;
3372
+ this.size = clamped;
3373
+ const offset = cap - clamped;
3371
3374
  const style = this.element.style;
3372
3375
  style.transform = this.transformTemplate(offset);
3373
- if (this.sizeWriteSentinel.shouldWrite(size, SIZE_WRITE_EPSILON)) {
3374
- style.setProperty("--bs-size", `${size}px`);
3376
+ if (this.sizeWriteSentinel.shouldWrite(clamped, SIZE_WRITE_EPSILON)) {
3377
+ style.setProperty("--bs-size", `${clamped}px`);
3375
3378
  if (this.scrimParent) {
3376
- this.scrimParent.style.setProperty("--bs-size", `${size}px`);
3379
+ this.scrimParent.style.setProperty("--bs-size", `${clamped}px`);
3377
3380
  }
3378
3381
  if (this.anchorHost && this.anchorHost !== this.scrimParent) {
3379
- this.anchorHost.style.setProperty("--bs-size", `${size}px`);
3382
+ this.anchorHost.style.setProperty("--bs-size", `${clamped}px`);
3380
3383
  }
3381
3384
  if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
3382
- this.rootEl.style.setProperty("--bs-size", `${size}px`);
3385
+ this.rootEl.style.setProperty("--bs-size", `${clamped}px`);
3383
3386
  }
3384
3387
  }
3385
- const progress = this.computeProgress(size);
3388
+ const progress = this.computeProgress(clamped);
3386
3389
  const progressChanged = this.progressWriteSentinel.shouldWrite(
3387
3390
  progress,
3388
3391
  OPACITY_WRITE_EPSILON
@@ -3399,14 +3402,15 @@ var BottomSheetEngine = class {
3399
3402
  this.scrim.applyOpacity(progress, progressChanged);
3400
3403
  if (progressChanged && this.bus.listenerCount("progress") > 0) {
3401
3404
  this.progressPayload.value = progress;
3402
- this.progressPayload.size = size;
3405
+ this.progressPayload.size = clamped;
3403
3406
  this.emit("progress", this.progressPayload);
3404
3407
  }
3405
3408
  }
3406
3409
  computeProgress(size) {
3407
3410
  const { min, max } = this.getAllowedRange();
3408
- if (max <= min) return 0;
3409
- return Math.min(Math.max((size - min) / (max - min), 0), 1);
3411
+ const reachableMax = Math.min(max, this.snaps.getMaxAxisSize());
3412
+ if (reachableMax <= min) return 0;
3413
+ return Math.min(Math.max((size - min) / (reachableMax - min), 0), 1);
3410
3414
  }
3411
3415
  handleOpen() {
3412
3416
  sheetStack.promote(this.id);
@@ -3430,8 +3434,8 @@ var BottomSheetEngine = class {
3430
3434
  this.updateAriaSlider();
3431
3435
  this.emit("snap", {
3432
3436
  id: target.id,
3433
- size: target.size,
3434
- progress: this.computeProgress(target.size)
3437
+ size: this.size,
3438
+ progress: this.computeProgress(this.size)
3435
3439
  });
3436
3440
  if (target.size > 0 && !this.lifecycle.isInstalled) {
3437
3441
  this.emit("open", { id: target.id });
package/dist/svelte.d.cts CHANGED
@@ -27,6 +27,9 @@ export type SvelteBottomSheetOpts<TId extends string = string> = Omit<
27
27
  snapPoints: SnapPointDef<TId>[] | ReadonlyArray<SnapPointDef<TId>>;
28
28
  allowed?: TId[] | ReadonlyArray<TId>;
29
29
  initial?: TId;
30
+ teleportTo?: string | HTMLElement | null;
31
+ backdropColor?: string;
32
+ backdropOpacity?: number;
30
33
  onSnap?: (id: TId) => void;
31
34
  };
32
35
 
package/dist/svelte.d.ts CHANGED
@@ -27,6 +27,9 @@ export type SvelteBottomSheetOpts<TId extends string = string> = Omit<
27
27
  snapPoints: SnapPointDef<TId>[] | ReadonlyArray<SnapPointDef<TId>>;
28
28
  allowed?: TId[] | ReadonlyArray<TId>;
29
29
  initial?: TId;
30
+ teleportTo?: string | HTMLElement | null;
31
+ backdropColor?: string;
32
+ backdropOpacity?: number;
30
33
  onSnap?: (id: TId) => void;
31
34
  };
32
35
 
package/dist/svelte.js CHANGED
@@ -2622,7 +2622,9 @@ var BottomSheetEngine = class {
2622
2622
  const previousSize = this.size;
2623
2623
  this.scrollCache.cache(previousId, previousSize, target.size);
2624
2624
  this.activeId = id;
2625
- if (wasClosed && target.size > 0) {
2625
+ const rawTargetSize = this.snapPointsRaw.find((p) => p.id === id)?.size;
2626
+ const opensToRest = id === "closed" || rawTargetSize === 0;
2627
+ if (wasClosed && !opensToRest) {
2626
2628
  this.opening = true;
2627
2629
  sheetStack.promote(this.id);
2628
2630
  }
@@ -2647,8 +2649,8 @@ var BottomSheetEngine = class {
2647
2649
  this.updateAriaSlider();
2648
2650
  this.emit("snap", {
2649
2651
  id,
2650
- size: target.size,
2651
- progress: this.computeProgress(target.size)
2652
+ size: this.size,
2653
+ progress: this.computeProgress(this.size)
2652
2654
  });
2653
2655
  if (wasClosed && target.size > 0) {
2654
2656
  this.emit("open", { id });
@@ -2727,12 +2729,12 @@ var BottomSheetEngine = class {
2727
2729
  const value = typeof h === "number" ? `${h}px` : h;
2728
2730
  const axis = layoutAxis(this.mode);
2729
2731
  this.element.style.setProperty(
2730
- axis === "height" ? "maxHeight" : "maxWidth",
2732
+ axis === "height" ? "max-height" : "max-width",
2731
2733
  value
2732
2734
  );
2733
2735
  if (typeof h === "number") {
2734
2736
  this.maxHeightCap = h;
2735
- this.clampToMaxHeight();
2737
+ this.recompute();
2736
2738
  } else if (typeof window !== "undefined") {
2737
2739
  const probe2 = document.createElement("div");
2738
2740
  probe2.style.cssText = `position:absolute;visibility:hidden;pointer-events:none;${axis === "height" ? "height" : "width"}:${value};`;
@@ -2740,7 +2742,7 @@ var BottomSheetEngine = class {
2740
2742
  const measured = axis === "height" ? probe2.offsetHeight : probe2.offsetWidth;
2741
2743
  probe2.remove();
2742
2744
  this.maxHeightCap = measured > 0 ? measured : void 0;
2743
- this.clampToMaxHeight();
2745
+ this.recompute();
2744
2746
  }
2745
2747
  }
2746
2748
  clampToMaxHeight() {
@@ -2748,9 +2750,6 @@ var BottomSheetEngine = class {
2748
2750
  if (this.snaps.getMaxAxisSize() > this.maxHeightCap) {
2749
2751
  this.snaps.setMaxAxisSize(this.maxHeightCap);
2750
2752
  }
2751
- if (this.size > this.maxHeightCap && !this.gesture?.isDragging) {
2752
- this.applySize(this.maxHeightCap);
2753
- }
2754
2753
  }
2755
2754
  setAllowed(ids, snap) {
2756
2755
  if (this.destroyed) return;
@@ -2888,6 +2887,7 @@ var BottomSheetEngine = class {
2888
2887
  recompute() {
2889
2888
  if (this.destroyed) return;
2890
2889
  this.snaps.recompute();
2890
+ this.clampToMaxHeight();
2891
2891
  this.scrim.invalidateOpacityCache();
2892
2892
  if (this.gesture?.isDragging) return;
2893
2893
  const current = this.snaps.findById(this.activeId);
@@ -2945,9 +2945,10 @@ var BottomSheetEngine = class {
2945
2945
  const handleSize = vertical ? this.handle.offsetHeight : this.handle.offsetWidth;
2946
2946
  const content = this.scrollContainer;
2947
2947
  const natural = content ? handleSize + this.measureContentExtent(vertical) : handleSize;
2948
- if (typeof window === "undefined") return natural;
2948
+ const capped = this.maxHeightCap !== void 0 ? Math.min(natural, this.maxHeightCap) : natural;
2949
+ if (typeof window === "undefined") return capped;
2949
2950
  const viewport = vertical ? window.innerHeight : window.innerWidth;
2950
- return viewport > 0 ? Math.min(natural, viewport) : natural;
2951
+ return viewport > 0 ? Math.min(capped, viewport) : capped;
2951
2952
  }
2952
2953
  installFitObserver() {
2953
2954
  if (typeof ResizeObserver === "undefined") return;
@@ -3318,8 +3319,8 @@ var BottomSheetEngine = class {
3318
3319
  this.updateAriaSlider();
3319
3320
  this.emit("snap", {
3320
3321
  id: target.id,
3321
- size: target.size,
3322
- progress: this.computeProgress(target.size)
3322
+ size: this.size,
3323
+ progress: this.computeProgress(this.size)
3323
3324
  });
3324
3325
  this.haptic();
3325
3326
  if (previousSnapSize === 0 && target.size > 0) {
@@ -3344,23 +3345,25 @@ var BottomSheetEngine = class {
3344
3345
  }
3345
3346
  }
3346
3347
  applySize(size) {
3347
- this.size = size;
3348
- const offset = this.snaps.getMaxAxisSize() - size;
3348
+ const cap = this.snaps.getMaxAxisSize();
3349
+ const clamped = cap > 0 && size > cap && !this.gesture?.isDragging ? cap : size;
3350
+ this.size = clamped;
3351
+ const offset = cap - clamped;
3349
3352
  const style = this.element.style;
3350
3353
  style.transform = this.transformTemplate(offset);
3351
- if (this.sizeWriteSentinel.shouldWrite(size, SIZE_WRITE_EPSILON)) {
3352
- style.setProperty("--bs-size", `${size}px`);
3354
+ if (this.sizeWriteSentinel.shouldWrite(clamped, SIZE_WRITE_EPSILON)) {
3355
+ style.setProperty("--bs-size", `${clamped}px`);
3353
3356
  if (this.scrimParent) {
3354
- this.scrimParent.style.setProperty("--bs-size", `${size}px`);
3357
+ this.scrimParent.style.setProperty("--bs-size", `${clamped}px`);
3355
3358
  }
3356
3359
  if (this.anchorHost && this.anchorHost !== this.scrimParent) {
3357
- this.anchorHost.style.setProperty("--bs-size", `${size}px`);
3360
+ this.anchorHost.style.setProperty("--bs-size", `${clamped}px`);
3358
3361
  }
3359
3362
  if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
3360
- this.rootEl.style.setProperty("--bs-size", `${size}px`);
3363
+ this.rootEl.style.setProperty("--bs-size", `${clamped}px`);
3361
3364
  }
3362
3365
  }
3363
- const progress = this.computeProgress(size);
3366
+ const progress = this.computeProgress(clamped);
3364
3367
  const progressChanged = this.progressWriteSentinel.shouldWrite(
3365
3368
  progress,
3366
3369
  OPACITY_WRITE_EPSILON
@@ -3377,14 +3380,15 @@ var BottomSheetEngine = class {
3377
3380
  this.scrim.applyOpacity(progress, progressChanged);
3378
3381
  if (progressChanged && this.bus.listenerCount("progress") > 0) {
3379
3382
  this.progressPayload.value = progress;
3380
- this.progressPayload.size = size;
3383
+ this.progressPayload.size = clamped;
3381
3384
  this.emit("progress", this.progressPayload);
3382
3385
  }
3383
3386
  }
3384
3387
  computeProgress(size) {
3385
3388
  const { min, max } = this.getAllowedRange();
3386
- if (max <= min) return 0;
3387
- return Math.min(Math.max((size - min) / (max - min), 0), 1);
3389
+ const reachableMax = Math.min(max, this.snaps.getMaxAxisSize());
3390
+ if (reachableMax <= min) return 0;
3391
+ return Math.min(Math.max((size - min) / (reachableMax - min), 0), 1);
3388
3392
  }
3389
3393
  handleOpen() {
3390
3394
  sheetStack.promote(this.id);
@@ -3408,8 +3412,8 @@ var BottomSheetEngine = class {
3408
3412
  this.updateAriaSlider();
3409
3413
  this.emit("snap", {
3410
3414
  id: target.id,
3411
- size: target.size,
3412
- progress: this.computeProgress(target.size)
3415
+ size: this.size,
3416
+ progress: this.computeProgress(this.size)
3413
3417
  });
3414
3418
  if (target.size > 0 && !this.lifecycle.isInstalled) {
3415
3419
  this.emit("open", { id: target.id });
package/dist/vue.cjs CHANGED
@@ -2622,7 +2622,9 @@ var BottomSheetEngine = class {
2622
2622
  const previousSize = this.size;
2623
2623
  this.scrollCache.cache(previousId, previousSize, target.size);
2624
2624
  this.activeId = id;
2625
- if (wasClosed && target.size > 0) {
2625
+ const rawTargetSize = this.snapPointsRaw.find((p) => p.id === id)?.size;
2626
+ const opensToRest = id === "closed" || rawTargetSize === 0;
2627
+ if (wasClosed && !opensToRest) {
2626
2628
  this.opening = true;
2627
2629
  sheetStack.promote(this.id);
2628
2630
  }
@@ -2647,8 +2649,8 @@ var BottomSheetEngine = class {
2647
2649
  this.updateAriaSlider();
2648
2650
  this.emit("snap", {
2649
2651
  id,
2650
- size: target.size,
2651
- progress: this.computeProgress(target.size)
2652
+ size: this.size,
2653
+ progress: this.computeProgress(this.size)
2652
2654
  });
2653
2655
  if (wasClosed && target.size > 0) {
2654
2656
  this.emit("open", { id });
@@ -2727,12 +2729,12 @@ var BottomSheetEngine = class {
2727
2729
  const value = typeof h === "number" ? `${h}px` : h;
2728
2730
  const axis = layoutAxis(this.mode);
2729
2731
  this.element.style.setProperty(
2730
- axis === "height" ? "maxHeight" : "maxWidth",
2732
+ axis === "height" ? "max-height" : "max-width",
2731
2733
  value
2732
2734
  );
2733
2735
  if (typeof h === "number") {
2734
2736
  this.maxHeightCap = h;
2735
- this.clampToMaxHeight();
2737
+ this.recompute();
2736
2738
  } else if (typeof window !== "undefined") {
2737
2739
  const probe2 = document.createElement("div");
2738
2740
  probe2.style.cssText = `position:absolute;visibility:hidden;pointer-events:none;${axis === "height" ? "height" : "width"}:${value};`;
@@ -2740,7 +2742,7 @@ var BottomSheetEngine = class {
2740
2742
  const measured = axis === "height" ? probe2.offsetHeight : probe2.offsetWidth;
2741
2743
  probe2.remove();
2742
2744
  this.maxHeightCap = measured > 0 ? measured : void 0;
2743
- this.clampToMaxHeight();
2745
+ this.recompute();
2744
2746
  }
2745
2747
  }
2746
2748
  clampToMaxHeight() {
@@ -2748,9 +2750,6 @@ var BottomSheetEngine = class {
2748
2750
  if (this.snaps.getMaxAxisSize() > this.maxHeightCap) {
2749
2751
  this.snaps.setMaxAxisSize(this.maxHeightCap);
2750
2752
  }
2751
- if (this.size > this.maxHeightCap && !this.gesture?.isDragging) {
2752
- this.applySize(this.maxHeightCap);
2753
- }
2754
2753
  }
2755
2754
  setAllowed(ids, snap) {
2756
2755
  if (this.destroyed) return;
@@ -2888,6 +2887,7 @@ var BottomSheetEngine = class {
2888
2887
  recompute() {
2889
2888
  if (this.destroyed) return;
2890
2889
  this.snaps.recompute();
2890
+ this.clampToMaxHeight();
2891
2891
  this.scrim.invalidateOpacityCache();
2892
2892
  if (this.gesture?.isDragging) return;
2893
2893
  const current = this.snaps.findById(this.activeId);
@@ -2945,9 +2945,10 @@ var BottomSheetEngine = class {
2945
2945
  const handleSize = vertical ? this.handle.offsetHeight : this.handle.offsetWidth;
2946
2946
  const content = this.scrollContainer;
2947
2947
  const natural = content ? handleSize + this.measureContentExtent(vertical) : handleSize;
2948
- if (typeof window === "undefined") return natural;
2948
+ const capped = this.maxHeightCap !== void 0 ? Math.min(natural, this.maxHeightCap) : natural;
2949
+ if (typeof window === "undefined") return capped;
2949
2950
  const viewport = vertical ? window.innerHeight : window.innerWidth;
2950
- return viewport > 0 ? Math.min(natural, viewport) : natural;
2951
+ return viewport > 0 ? Math.min(capped, viewport) : capped;
2951
2952
  }
2952
2953
  installFitObserver() {
2953
2954
  if (typeof ResizeObserver === "undefined") return;
@@ -3318,8 +3319,8 @@ var BottomSheetEngine = class {
3318
3319
  this.updateAriaSlider();
3319
3320
  this.emit("snap", {
3320
3321
  id: target.id,
3321
- size: target.size,
3322
- progress: this.computeProgress(target.size)
3322
+ size: this.size,
3323
+ progress: this.computeProgress(this.size)
3323
3324
  });
3324
3325
  this.haptic();
3325
3326
  if (previousSnapSize === 0 && target.size > 0) {
@@ -3344,23 +3345,25 @@ var BottomSheetEngine = class {
3344
3345
  }
3345
3346
  }
3346
3347
  applySize(size) {
3347
- this.size = size;
3348
- const offset = this.snaps.getMaxAxisSize() - size;
3348
+ const cap = this.snaps.getMaxAxisSize();
3349
+ const clamped = cap > 0 && size > cap && !this.gesture?.isDragging ? cap : size;
3350
+ this.size = clamped;
3351
+ const offset = cap - clamped;
3349
3352
  const style = this.element.style;
3350
3353
  style.transform = this.transformTemplate(offset);
3351
- if (this.sizeWriteSentinel.shouldWrite(size, SIZE_WRITE_EPSILON)) {
3352
- style.setProperty("--bs-size", `${size}px`);
3354
+ if (this.sizeWriteSentinel.shouldWrite(clamped, SIZE_WRITE_EPSILON)) {
3355
+ style.setProperty("--bs-size", `${clamped}px`);
3353
3356
  if (this.scrimParent) {
3354
- this.scrimParent.style.setProperty("--bs-size", `${size}px`);
3357
+ this.scrimParent.style.setProperty("--bs-size", `${clamped}px`);
3355
3358
  }
3356
3359
  if (this.anchorHost && this.anchorHost !== this.scrimParent) {
3357
- this.anchorHost.style.setProperty("--bs-size", `${size}px`);
3360
+ this.anchorHost.style.setProperty("--bs-size", `${clamped}px`);
3358
3361
  }
3359
3362
  if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
3360
- this.rootEl.style.setProperty("--bs-size", `${size}px`);
3363
+ this.rootEl.style.setProperty("--bs-size", `${clamped}px`);
3361
3364
  }
3362
3365
  }
3363
- const progress = this.computeProgress(size);
3366
+ const progress = this.computeProgress(clamped);
3364
3367
  const progressChanged = this.progressWriteSentinel.shouldWrite(
3365
3368
  progress,
3366
3369
  OPACITY_WRITE_EPSILON
@@ -3377,14 +3380,15 @@ var BottomSheetEngine = class {
3377
3380
  this.scrim.applyOpacity(progress, progressChanged);
3378
3381
  if (progressChanged && this.bus.listenerCount("progress") > 0) {
3379
3382
  this.progressPayload.value = progress;
3380
- this.progressPayload.size = size;
3383
+ this.progressPayload.size = clamped;
3381
3384
  this.emit("progress", this.progressPayload);
3382
3385
  }
3383
3386
  }
3384
3387
  computeProgress(size) {
3385
3388
  const { min, max } = this.getAllowedRange();
3386
- if (max <= min) return 0;
3387
- return Math.min(Math.max((size - min) / (max - min), 0), 1);
3389
+ const reachableMax = Math.min(max, this.snaps.getMaxAxisSize());
3390
+ if (reachableMax <= min) return 0;
3391
+ return Math.min(Math.max((size - min) / (reachableMax - min), 0), 1);
3388
3392
  }
3389
3393
  handleOpen() {
3390
3394
  sheetStack.promote(this.id);
@@ -3408,8 +3412,8 @@ var BottomSheetEngine = class {
3408
3412
  this.updateAriaSlider();
3409
3413
  this.emit("snap", {
3410
3414
  id: target.id,
3411
- size: target.size,
3412
- progress: this.computeProgress(target.size)
3415
+ size: this.size,
3416
+ progress: this.computeProgress(this.size)
3413
3417
  });
3414
3418
  if (target.size > 0 && !this.lifecycle.isInstalled) {
3415
3419
  this.emit("open", { id: target.id });
package/dist/vue.d.cts CHANGED
@@ -28,6 +28,9 @@ export type UseBottomSheetVueOptions<TId extends string = string> = Omit<
28
28
  snapPoints: SnapPointDef<TId>[] | ReadonlyArray<SnapPointDef<TId>>;
29
29
  allowed?: TId[] | ReadonlyArray<TId>;
30
30
  initial?: TId;
31
+ teleportTo?: string | HTMLElement | null;
32
+ backdropColor?: string;
33
+ backdropOpacity?: number;
31
34
  onSnap?: (id: TId) => void;
32
35
  };
33
36
 
package/dist/vue.d.ts CHANGED
@@ -28,6 +28,9 @@ export type UseBottomSheetVueOptions<TId extends string = string> = Omit<
28
28
  snapPoints: SnapPointDef<TId>[] | ReadonlyArray<SnapPointDef<TId>>;
29
29
  allowed?: TId[] | ReadonlyArray<TId>;
30
30
  initial?: TId;
31
+ teleportTo?: string | HTMLElement | null;
32
+ backdropColor?: string;
33
+ backdropOpacity?: number;
31
34
  onSnap?: (id: TId) => void;
32
35
  };
33
36
 
package/dist/vue.js CHANGED
@@ -2620,7 +2620,9 @@ var BottomSheetEngine = class {
2620
2620
  const previousSize = this.size;
2621
2621
  this.scrollCache.cache(previousId, previousSize, target.size);
2622
2622
  this.activeId = id;
2623
- if (wasClosed && target.size > 0) {
2623
+ const rawTargetSize = this.snapPointsRaw.find((p) => p.id === id)?.size;
2624
+ const opensToRest = id === "closed" || rawTargetSize === 0;
2625
+ if (wasClosed && !opensToRest) {
2624
2626
  this.opening = true;
2625
2627
  sheetStack.promote(this.id);
2626
2628
  }
@@ -2645,8 +2647,8 @@ var BottomSheetEngine = class {
2645
2647
  this.updateAriaSlider();
2646
2648
  this.emit("snap", {
2647
2649
  id,
2648
- size: target.size,
2649
- progress: this.computeProgress(target.size)
2650
+ size: this.size,
2651
+ progress: this.computeProgress(this.size)
2650
2652
  });
2651
2653
  if (wasClosed && target.size > 0) {
2652
2654
  this.emit("open", { id });
@@ -2725,12 +2727,12 @@ var BottomSheetEngine = class {
2725
2727
  const value = typeof h === "number" ? `${h}px` : h;
2726
2728
  const axis = layoutAxis(this.mode);
2727
2729
  this.element.style.setProperty(
2728
- axis === "height" ? "maxHeight" : "maxWidth",
2730
+ axis === "height" ? "max-height" : "max-width",
2729
2731
  value
2730
2732
  );
2731
2733
  if (typeof h === "number") {
2732
2734
  this.maxHeightCap = h;
2733
- this.clampToMaxHeight();
2735
+ this.recompute();
2734
2736
  } else if (typeof window !== "undefined") {
2735
2737
  const probe2 = document.createElement("div");
2736
2738
  probe2.style.cssText = `position:absolute;visibility:hidden;pointer-events:none;${axis === "height" ? "height" : "width"}:${value};`;
@@ -2738,7 +2740,7 @@ var BottomSheetEngine = class {
2738
2740
  const measured = axis === "height" ? probe2.offsetHeight : probe2.offsetWidth;
2739
2741
  probe2.remove();
2740
2742
  this.maxHeightCap = measured > 0 ? measured : void 0;
2741
- this.clampToMaxHeight();
2743
+ this.recompute();
2742
2744
  }
2743
2745
  }
2744
2746
  clampToMaxHeight() {
@@ -2746,9 +2748,6 @@ var BottomSheetEngine = class {
2746
2748
  if (this.snaps.getMaxAxisSize() > this.maxHeightCap) {
2747
2749
  this.snaps.setMaxAxisSize(this.maxHeightCap);
2748
2750
  }
2749
- if (this.size > this.maxHeightCap && !this.gesture?.isDragging) {
2750
- this.applySize(this.maxHeightCap);
2751
- }
2752
2751
  }
2753
2752
  setAllowed(ids, snap) {
2754
2753
  if (this.destroyed) return;
@@ -2886,6 +2885,7 @@ var BottomSheetEngine = class {
2886
2885
  recompute() {
2887
2886
  if (this.destroyed) return;
2888
2887
  this.snaps.recompute();
2888
+ this.clampToMaxHeight();
2889
2889
  this.scrim.invalidateOpacityCache();
2890
2890
  if (this.gesture?.isDragging) return;
2891
2891
  const current = this.snaps.findById(this.activeId);
@@ -2943,9 +2943,10 @@ var BottomSheetEngine = class {
2943
2943
  const handleSize = vertical ? this.handle.offsetHeight : this.handle.offsetWidth;
2944
2944
  const content = this.scrollContainer;
2945
2945
  const natural = content ? handleSize + this.measureContentExtent(vertical) : handleSize;
2946
- if (typeof window === "undefined") return natural;
2946
+ const capped = this.maxHeightCap !== void 0 ? Math.min(natural, this.maxHeightCap) : natural;
2947
+ if (typeof window === "undefined") return capped;
2947
2948
  const viewport = vertical ? window.innerHeight : window.innerWidth;
2948
- return viewport > 0 ? Math.min(natural, viewport) : natural;
2949
+ return viewport > 0 ? Math.min(capped, viewport) : capped;
2949
2950
  }
2950
2951
  installFitObserver() {
2951
2952
  if (typeof ResizeObserver === "undefined") return;
@@ -3316,8 +3317,8 @@ var BottomSheetEngine = class {
3316
3317
  this.updateAriaSlider();
3317
3318
  this.emit("snap", {
3318
3319
  id: target.id,
3319
- size: target.size,
3320
- progress: this.computeProgress(target.size)
3320
+ size: this.size,
3321
+ progress: this.computeProgress(this.size)
3321
3322
  });
3322
3323
  this.haptic();
3323
3324
  if (previousSnapSize === 0 && target.size > 0) {
@@ -3342,23 +3343,25 @@ var BottomSheetEngine = class {
3342
3343
  }
3343
3344
  }
3344
3345
  applySize(size) {
3345
- this.size = size;
3346
- const offset = this.snaps.getMaxAxisSize() - size;
3346
+ const cap = this.snaps.getMaxAxisSize();
3347
+ const clamped = cap > 0 && size > cap && !this.gesture?.isDragging ? cap : size;
3348
+ this.size = clamped;
3349
+ const offset = cap - clamped;
3347
3350
  const style = this.element.style;
3348
3351
  style.transform = this.transformTemplate(offset);
3349
- if (this.sizeWriteSentinel.shouldWrite(size, SIZE_WRITE_EPSILON)) {
3350
- style.setProperty("--bs-size", `${size}px`);
3352
+ if (this.sizeWriteSentinel.shouldWrite(clamped, SIZE_WRITE_EPSILON)) {
3353
+ style.setProperty("--bs-size", `${clamped}px`);
3351
3354
  if (this.scrimParent) {
3352
- this.scrimParent.style.setProperty("--bs-size", `${size}px`);
3355
+ this.scrimParent.style.setProperty("--bs-size", `${clamped}px`);
3353
3356
  }
3354
3357
  if (this.anchorHost && this.anchorHost !== this.scrimParent) {
3355
- this.anchorHost.style.setProperty("--bs-size", `${size}px`);
3358
+ this.anchorHost.style.setProperty("--bs-size", `${clamped}px`);
3356
3359
  }
3357
3360
  if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
3358
- this.rootEl.style.setProperty("--bs-size", `${size}px`);
3361
+ this.rootEl.style.setProperty("--bs-size", `${clamped}px`);
3359
3362
  }
3360
3363
  }
3361
- const progress = this.computeProgress(size);
3364
+ const progress = this.computeProgress(clamped);
3362
3365
  const progressChanged = this.progressWriteSentinel.shouldWrite(
3363
3366
  progress,
3364
3367
  OPACITY_WRITE_EPSILON
@@ -3375,14 +3378,15 @@ var BottomSheetEngine = class {
3375
3378
  this.scrim.applyOpacity(progress, progressChanged);
3376
3379
  if (progressChanged && this.bus.listenerCount("progress") > 0) {
3377
3380
  this.progressPayload.value = progress;
3378
- this.progressPayload.size = size;
3381
+ this.progressPayload.size = clamped;
3379
3382
  this.emit("progress", this.progressPayload);
3380
3383
  }
3381
3384
  }
3382
3385
  computeProgress(size) {
3383
3386
  const { min, max } = this.getAllowedRange();
3384
- if (max <= min) return 0;
3385
- return Math.min(Math.max((size - min) / (max - min), 0), 1);
3387
+ const reachableMax = Math.min(max, this.snaps.getMaxAxisSize());
3388
+ if (reachableMax <= min) return 0;
3389
+ return Math.min(Math.max((size - min) / (reachableMax - min), 0), 1);
3386
3390
  }
3387
3391
  handleOpen() {
3388
3392
  sheetStack.promote(this.id);
@@ -3406,8 +3410,8 @@ var BottomSheetEngine = class {
3406
3410
  this.updateAriaSlider();
3407
3411
  this.emit("snap", {
3408
3412
  id: target.id,
3409
- size: target.size,
3410
- progress: this.computeProgress(target.size)
3413
+ size: this.size,
3414
+ progress: this.computeProgress(this.size)
3411
3415
  });
3412
3416
  if (target.size > 0 && !this.lifecycle.isInstalled) {
3413
3417
  this.emit("open", { id: target.id });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@surdeddd/bottom-sheet",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Universal, headless bottom sheet — framework-agnostic core with React, Vue 3, Svelte, Solid, Qwik, Preact, Lit and Custom Element adapters. Pointer Events, snap points, momentum, a11y, SSR-safe.",
5
5
  "type": "module",
6
6
  "license": "MIT",