@surdeddd/bottom-sheet 0.21.1 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +32 -0
  2. package/dist/{BottomSheetCore-CK_mq14p.d.ts → BottomSheetCore-9i-Uh6T3.d.ts} +4 -1
  3. package/dist/{BottomSheetCore-BHv6LPmS.d.cts → BottomSheetCore-CQStdVy2.d.cts} +4 -1
  4. package/dist/{BottomSheetEngine-mmFzIK1Z.d.cts → BottomSheetEngine-CsQWHLNb.d.cts} +1 -1
  5. package/dist/{BottomSheetEngine-wLn6Q2kA.d.ts → BottomSheetEngine-Dn6h-7gF.d.ts} +1 -1
  6. package/dist/core.cjs +25 -7
  7. package/dist/core.d.cts +2 -2
  8. package/dist/core.d.ts +2 -2
  9. package/dist/core.js +25 -7
  10. package/dist/debug.d.cts +1 -1
  11. package/dist/debug.d.ts +1 -1
  12. package/dist/default-features-C3cilcW9.d.ts +11 -0
  13. package/dist/default-features-DkG9aho0.d.cts +11 -0
  14. package/dist/element.cjs +106 -15
  15. package/dist/element.d.cts +2 -2
  16. package/dist/element.d.ts +2 -2
  17. package/dist/element.iife.global.js +2 -2
  18. package/dist/element.js +106 -15
  19. package/dist/features.cjs +65 -1
  20. package/dist/features.d.cts +5 -10
  21. package/dist/features.d.ts +5 -10
  22. package/dist/features.js +65 -2
  23. package/dist/{index-juAyT76E.d.cts → index-CVGC5B5D.d.cts} +1 -1
  24. package/dist/{index-CWKv1Xy4.d.ts → index-CnsJQZp2.d.ts} +1 -1
  25. package/dist/index.cjs +89 -8
  26. package/dist/index.d.cts +5 -5
  27. package/dist/index.d.ts +5 -5
  28. package/dist/index.js +89 -8
  29. package/dist/integrations/formik.d.cts +1 -1
  30. package/dist/integrations/formik.d.ts +1 -1
  31. package/dist/integrations/react-hook-form.d.cts +1 -1
  32. package/dist/integrations/react-hook-form.d.ts +1 -1
  33. package/dist/preact.d.cts +2 -2
  34. package/dist/preact.d.ts +2 -2
  35. package/dist/qwik-lib/index.qwik.cjs +84 -6
  36. package/dist/qwik-lib/index.qwik.mjs +84 -6
  37. package/dist/qwik.cjs +90 -8
  38. package/dist/qwik.d.cts +3 -2
  39. package/dist/qwik.d.ts +3 -2
  40. package/dist/qwik.js +90 -8
  41. package/dist/react.cjs +89 -8
  42. package/dist/react.d.cts +3 -3
  43. package/dist/react.d.ts +3 -3
  44. package/dist/react.js +89 -8
  45. package/dist/solid.cjs +90 -8
  46. package/dist/solid.d.cts +4 -0
  47. package/dist/solid.d.ts +4 -0
  48. package/dist/solid.js +90 -8
  49. package/dist/solid.source.jsx +90 -8
  50. package/dist/styles.css +11 -0
  51. package/dist/svelte-core.cjs +89 -8
  52. package/dist/svelte-core.js +89 -8
  53. package/dist/svelte-src/BottomSheet.svelte +3 -0
  54. package/dist/svelte.cjs +90 -8
  55. package/dist/svelte.d.cts +1 -0
  56. package/dist/svelte.d.ts +1 -0
  57. package/dist/svelte.js +90 -8
  58. package/dist/vue.cjs +93 -8
  59. package/dist/vue.js +93 -8
  60. package/dist/webgl.d.cts +1 -1
  61. package/dist/webgl.d.ts +1 -1
  62. package/package.json +9 -9
package/dist/react.js CHANGED
@@ -383,14 +383,26 @@ function notifyLinkedSheets(sheets, self) {
383
383
  }
384
384
  }
385
385
 
386
+ // src/core/primitives/hot-path-thresholds.ts
387
+ var SIZE_WRITE_EPSILON = 0.5;
388
+ var OPACITY_WRITE_EPSILON = 5e-3;
389
+ var POINTER_EVENTS_OPACITY_THRESHOLD = 0.05;
390
+ var RANGE_DIVISION_EPSILON = 1e-4;
391
+
386
392
  // src/core/features/resize-observer.ts
387
393
  function installResizeObserver(deps) {
388
394
  if (typeof window === "undefined") {
389
395
  return () => {
390
396
  };
391
397
  }
398
+ const seatFor = () => {
399
+ const snap = deps.resolveActiveSnap();
400
+ const max = deps.getMaxAxisSize();
401
+ return { target: snap ? Math.min(snap.size, max) : null, max };
402
+ };
392
403
  const onResize = () => {
393
404
  if (deps.isDestroyed()) return;
405
+ const before = seatFor();
394
406
  deps.recomputeSnaps();
395
407
  const mode = deps.getMode();
396
408
  const isVerticalAxis = mode === "bottom" || mode === "top";
@@ -399,6 +411,10 @@ function installResizeObserver(deps) {
399
411
  if (viewportSize2 > 0 && viewportSize2 < max) {
400
412
  deps.setMaxAxisSize(viewportSize2);
401
413
  }
414
+ const after = seatFor();
415
+ if (before.target !== null && after.target !== null && Math.abs(after.target - before.target) < SIZE_WRITE_EPSILON && Math.abs(after.max - before.max) < SIZE_WRITE_EPSILON) {
416
+ return;
417
+ }
402
418
  const wasAnimating = deps.isAnimating?.() ?? false;
403
419
  deps.cancelInFlight();
404
420
  deps.newCycle();
@@ -667,12 +683,6 @@ var SCRIM_PRESETS = Object.freeze({
667
683
  }
668
684
  });
669
685
 
670
- // src/core/primitives/hot-path-thresholds.ts
671
- var SIZE_WRITE_EPSILON = 0.5;
672
- var OPACITY_WRITE_EPSILON = 5e-3;
673
- var POINTER_EVENTS_OPACITY_THRESHOLD = 0.05;
674
- var RANGE_DIVISION_EPSILON = 1e-4;
675
-
676
686
  // src/core/primitives/opacity-dedup.ts
677
687
  var WriteSentinel = class {
678
688
  constructor() {
@@ -2602,6 +2612,7 @@ var BottomSheetCore = class {
2602
2612
  __publicField(this, "lifecycle");
2603
2613
  __publicField(this, "closeOnBack");
2604
2614
  __publicField(this, "routedTo");
2615
+ __publicField(this, "fitContentToSnap");
2605
2616
  __publicField(this, "persistent");
2606
2617
  __publicField(this, "disableCloseFlag");
2607
2618
  __publicField(this, "disableDragFlag");
@@ -2715,6 +2726,7 @@ var BottomSheetCore = class {
2715
2726
  );
2716
2727
  this.closeOnBack = resolved.closeOnBack;
2717
2728
  this.routedTo = opts.routedTo;
2729
+ this.fitContentToSnap = opts.fitContentToSnap === true;
2718
2730
  this.persistent = resolved.persistent;
2719
2731
  this.disableCloseFlag = resolved.disableClose;
2720
2732
  this.disableDragFlag = resolved.disableDrag;
@@ -2816,7 +2828,8 @@ var BottomSheetCore = class {
2816
2828
  closeOnBack: this.closeOnBack,
2817
2829
  closeOnRouteChange: this.closeOnRouteChange,
2818
2830
  persistKey: this.persistKey,
2819
- autoCollapseAfter
2831
+ autoCollapseAfter,
2832
+ fitContentToSnap: this.fitContentToSnap
2820
2833
  },
2821
2834
  isDestroyed: () => this.destroyed,
2822
2835
  isDragging: () => this.isDraggingAny(),
@@ -2868,6 +2881,11 @@ var BottomSheetCore = class {
2868
2881
  "[BottomSheet] closeOnBack/routedTo/closeOnRouteChange need routeFeature() \u2014 option ignored"
2869
2882
  );
2870
2883
  }
2884
+ if (this.fitContentToSnap && !names.has("content-fit")) {
2885
+ devWarn(
2886
+ "[BottomSheet] fitContentToSnap needs contentFitFeature() \u2014 option ignored"
2887
+ );
2888
+ }
2871
2889
  if (this.persistKey && !names.has("persist")) {
2872
2890
  devWarn(
2873
2891
  "[BottomSheet] persistKey needs persistFeature() \u2014 snaps will not be saved"
@@ -4225,6 +4243,68 @@ function visualViewportFeature() {
4225
4243
  };
4226
4244
  }
4227
4245
 
4246
+ // src/core/features/content-fit.ts
4247
+ var INSET_VAR = "--bs-content-inset";
4248
+ var FIT_ATTR = "data-bs-fit-content";
4249
+ function contentFitFeature() {
4250
+ return {
4251
+ name: "content-fit",
4252
+ install: (ctx) => {
4253
+ const scroller = ctx.scrollContainer;
4254
+ if (!ctx.options.fitContentToSnap || !scroller || typeof window === "undefined") {
4255
+ return;
4256
+ }
4257
+ const sheet = ctx.element;
4258
+ let inset = 0;
4259
+ let unpaddedMax = -1;
4260
+ let top = 0;
4261
+ const hiddenAt = (size) => sheet.dataset.mode === "bottom" ? Math.max(0, ctx.getMaxAxisSize() - size) : 0;
4262
+ const follow = (size) => {
4263
+ if (unpaddedMax < 0) {
4264
+ unpaddedMax = scroller.scrollHeight - scroller.clientHeight - inset;
4265
+ top = scroller.scrollTop;
4266
+ }
4267
+ const limit = Math.max(0, unpaddedMax + hiddenAt(size));
4268
+ if (top > limit) {
4269
+ if (scroller.scrollTop > limit) scroller.scrollTop = limit;
4270
+ top = limit;
4271
+ }
4272
+ };
4273
+ const settle = () => {
4274
+ if (ctx.isDestroyed()) return;
4275
+ const size = ctx.getSize();
4276
+ unpaddedMax = -1;
4277
+ follow(size);
4278
+ inset = hiddenAt(size);
4279
+ sheet.style.setProperty(INSET_VAR, `${inset}px`);
4280
+ unpaddedMax = -1;
4281
+ };
4282
+ const moving = () => ctx.isAnimating() || ctx.isDragging();
4283
+ const whenIdle = () => {
4284
+ if (!moving()) settle();
4285
+ };
4286
+ sheet.setAttribute(FIT_ATTR, "");
4287
+ settle();
4288
+ const offProgress = ctx.on(
4289
+ "progress",
4290
+ (p) => moving() ? follow(p.size) : settle()
4291
+ );
4292
+ const offSnap = ctx.on("snap", settle);
4293
+ const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(whenIdle);
4294
+ observer?.observe(document.documentElement);
4295
+ window.addEventListener("orientationchange", whenIdle);
4296
+ return () => {
4297
+ offProgress();
4298
+ offSnap();
4299
+ observer?.disconnect();
4300
+ window.removeEventListener("orientationchange", whenIdle);
4301
+ sheet.removeAttribute(FIT_ATTR);
4302
+ sheet.style.removeProperty(INSET_VAR);
4303
+ };
4304
+ }
4305
+ };
4306
+ }
4307
+
4228
4308
  // src/core/default-features.ts
4229
4309
  function defaultEngineFeatures() {
4230
4310
  return [
@@ -4232,7 +4312,8 @@ function defaultEngineFeatures() {
4232
4312
  visualViewportFeature(),
4233
4313
  persistFeature(),
4234
4314
  autoCollapseFeature(),
4235
- routeFeature()
4315
+ routeFeature(),
4316
+ contentFitFeature()
4236
4317
  ];
4237
4318
  }
4238
4319
 
package/dist/solid.cjs CHANGED
@@ -378,14 +378,26 @@ function notifyLinkedSheets(sheets, self) {
378
378
  }
379
379
  }
380
380
 
381
+ // src/core/primitives/hot-path-thresholds.ts
382
+ var SIZE_WRITE_EPSILON = 0.5;
383
+ var OPACITY_WRITE_EPSILON = 5e-3;
384
+ var POINTER_EVENTS_OPACITY_THRESHOLD = 0.05;
385
+ var RANGE_DIVISION_EPSILON = 1e-4;
386
+
381
387
  // src/core/features/resize-observer.ts
382
388
  function installResizeObserver(deps) {
383
389
  if (typeof window === "undefined") {
384
390
  return () => {
385
391
  };
386
392
  }
393
+ const seatFor = () => {
394
+ const snap = deps.resolveActiveSnap();
395
+ const max = deps.getMaxAxisSize();
396
+ return { target: snap ? Math.min(snap.size, max) : null, max };
397
+ };
387
398
  const onResize = () => {
388
399
  if (deps.isDestroyed()) return;
400
+ const before = seatFor();
389
401
  deps.recomputeSnaps();
390
402
  const mode = deps.getMode();
391
403
  const isVerticalAxis = mode === "bottom" || mode === "top";
@@ -394,6 +406,10 @@ function installResizeObserver(deps) {
394
406
  if (viewportSize2 > 0 && viewportSize2 < max) {
395
407
  deps.setMaxAxisSize(viewportSize2);
396
408
  }
409
+ const after = seatFor();
410
+ if (before.target !== null && after.target !== null && Math.abs(after.target - before.target) < SIZE_WRITE_EPSILON && Math.abs(after.max - before.max) < SIZE_WRITE_EPSILON) {
411
+ return;
412
+ }
397
413
  const wasAnimating = deps.isAnimating?.() ?? false;
398
414
  deps.cancelInFlight();
399
415
  deps.newCycle();
@@ -662,12 +678,6 @@ var SCRIM_PRESETS = Object.freeze({
662
678
  }
663
679
  });
664
680
 
665
- // src/core/primitives/hot-path-thresholds.ts
666
- var SIZE_WRITE_EPSILON = 0.5;
667
- var OPACITY_WRITE_EPSILON = 5e-3;
668
- var POINTER_EVENTS_OPACITY_THRESHOLD = 0.05;
669
- var RANGE_DIVISION_EPSILON = 1e-4;
670
-
671
681
  // src/core/primitives/opacity-dedup.ts
672
682
  var WriteSentinel = class {
673
683
  constructor() {
@@ -2597,6 +2607,7 @@ var BottomSheetCore = class {
2597
2607
  __publicField(this, "lifecycle");
2598
2608
  __publicField(this, "closeOnBack");
2599
2609
  __publicField(this, "routedTo");
2610
+ __publicField(this, "fitContentToSnap");
2600
2611
  __publicField(this, "persistent");
2601
2612
  __publicField(this, "disableCloseFlag");
2602
2613
  __publicField(this, "disableDragFlag");
@@ -2710,6 +2721,7 @@ var BottomSheetCore = class {
2710
2721
  );
2711
2722
  this.closeOnBack = resolved.closeOnBack;
2712
2723
  this.routedTo = opts.routedTo;
2724
+ this.fitContentToSnap = opts.fitContentToSnap === true;
2713
2725
  this.persistent = resolved.persistent;
2714
2726
  this.disableCloseFlag = resolved.disableClose;
2715
2727
  this.disableDragFlag = resolved.disableDrag;
@@ -2811,7 +2823,8 @@ var BottomSheetCore = class {
2811
2823
  closeOnBack: this.closeOnBack,
2812
2824
  closeOnRouteChange: this.closeOnRouteChange,
2813
2825
  persistKey: this.persistKey,
2814
- autoCollapseAfter
2826
+ autoCollapseAfter,
2827
+ fitContentToSnap: this.fitContentToSnap
2815
2828
  },
2816
2829
  isDestroyed: () => this.destroyed,
2817
2830
  isDragging: () => this.isDraggingAny(),
@@ -2863,6 +2876,11 @@ var BottomSheetCore = class {
2863
2876
  "[BottomSheet] closeOnBack/routedTo/closeOnRouteChange need routeFeature() \u2014 option ignored"
2864
2877
  );
2865
2878
  }
2879
+ if (this.fitContentToSnap && !names.has("content-fit")) {
2880
+ devWarn(
2881
+ "[BottomSheet] fitContentToSnap needs contentFitFeature() \u2014 option ignored"
2882
+ );
2883
+ }
2866
2884
  if (this.persistKey && !names.has("persist")) {
2867
2885
  devWarn(
2868
2886
  "[BottomSheet] persistKey needs persistFeature() \u2014 snaps will not be saved"
@@ -4220,6 +4238,68 @@ function visualViewportFeature() {
4220
4238
  };
4221
4239
  }
4222
4240
 
4241
+ // src/core/features/content-fit.ts
4242
+ var INSET_VAR = "--bs-content-inset";
4243
+ var FIT_ATTR = "data-bs-fit-content";
4244
+ function contentFitFeature() {
4245
+ return {
4246
+ name: "content-fit",
4247
+ install: (ctx) => {
4248
+ const scroller = ctx.scrollContainer;
4249
+ if (!ctx.options.fitContentToSnap || !scroller || typeof window === "undefined") {
4250
+ return;
4251
+ }
4252
+ const sheet = ctx.element;
4253
+ let inset = 0;
4254
+ let unpaddedMax = -1;
4255
+ let top = 0;
4256
+ const hiddenAt = (size) => sheet.dataset.mode === "bottom" ? Math.max(0, ctx.getMaxAxisSize() - size) : 0;
4257
+ const follow = (size) => {
4258
+ if (unpaddedMax < 0) {
4259
+ unpaddedMax = scroller.scrollHeight - scroller.clientHeight - inset;
4260
+ top = scroller.scrollTop;
4261
+ }
4262
+ const limit = Math.max(0, unpaddedMax + hiddenAt(size));
4263
+ if (top > limit) {
4264
+ if (scroller.scrollTop > limit) scroller.scrollTop = limit;
4265
+ top = limit;
4266
+ }
4267
+ };
4268
+ const settle = () => {
4269
+ if (ctx.isDestroyed()) return;
4270
+ const size = ctx.getSize();
4271
+ unpaddedMax = -1;
4272
+ follow(size);
4273
+ inset = hiddenAt(size);
4274
+ sheet.style.setProperty(INSET_VAR, `${inset}px`);
4275
+ unpaddedMax = -1;
4276
+ };
4277
+ const moving = () => ctx.isAnimating() || ctx.isDragging();
4278
+ const whenIdle = () => {
4279
+ if (!moving()) settle();
4280
+ };
4281
+ sheet.setAttribute(FIT_ATTR, "");
4282
+ settle();
4283
+ const offProgress = ctx.on(
4284
+ "progress",
4285
+ (p) => moving() ? follow(p.size) : settle()
4286
+ );
4287
+ const offSnap = ctx.on("snap", settle);
4288
+ const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(whenIdle);
4289
+ observer?.observe(document.documentElement);
4290
+ window.addEventListener("orientationchange", whenIdle);
4291
+ return () => {
4292
+ offProgress();
4293
+ offSnap();
4294
+ observer?.disconnect();
4295
+ window.removeEventListener("orientationchange", whenIdle);
4296
+ sheet.removeAttribute(FIT_ATTR);
4297
+ sheet.style.removeProperty(INSET_VAR);
4298
+ };
4299
+ }
4300
+ };
4301
+ }
4302
+
4223
4303
  // src/core/default-features.ts
4224
4304
  function defaultEngineFeatures() {
4225
4305
  return [
@@ -4227,7 +4307,8 @@ function defaultEngineFeatures() {
4227
4307
  visualViewportFeature(),
4228
4308
  persistFeature(),
4229
4309
  autoCollapseFeature(),
4230
- routeFeature()
4310
+ routeFeature(),
4311
+ contentFitFeature()
4231
4312
  ];
4232
4313
  }
4233
4314
 
@@ -4323,6 +4404,7 @@ var BottomSheet = (props) => {
4323
4404
  disableDrag: props.disableDrag,
4324
4405
  dragFrom: props.dragFrom,
4325
4406
  dragFromContent: props.dragFromContent,
4407
+ fitContentToSnap: props.fitContentToSnap,
4326
4408
  closeOnRouteChange: props.closeOnRouteChange,
4327
4409
  stackEffect: props.stackEffect,
4328
4410
  returnFocusTo: props.returnFocusTo
package/dist/solid.d.cts CHANGED
@@ -94,6 +94,7 @@ type EngineOptions = {
94
94
  dragThreshold?: number;
95
95
  dragFrom?: DragFrom;
96
96
  dragFromContent?: boolean;
97
+ fitContentToSnap?: boolean;
97
98
  rubberBand?: boolean;
98
99
  backdropRange?: [number, number];
99
100
  screenRange?: [number, number];
@@ -140,6 +141,7 @@ type EngineFeatureOptions = {
140
141
  closeOnRouteChange: boolean;
141
142
  persistKey?: string;
142
143
  autoCollapseAfter?: number;
144
+ fitContentToSnap: boolean;
143
145
  };
144
146
  type EngineFeatureContext = {
145
147
  element: HTMLElement;
@@ -262,6 +264,7 @@ declare class BottomSheetCore {
262
264
  private lifecycle;
263
265
  private closeOnBack;
264
266
  private routedTo;
267
+ private fitContentToSnap;
265
268
  private persistent;
266
269
  private disableCloseFlag;
267
270
  private disableDragFlag;
@@ -432,6 +435,7 @@ type BottomSheetProps<TId extends string = string> = {
432
435
  disableDrag?: boolean;
433
436
  dragFrom?: EngineOptions["dragFrom"];
434
437
  dragFromContent?: boolean;
438
+ fitContentToSnap?: boolean;
435
439
  closeOnRouteChange?: boolean;
436
440
  stackEffect?: boolean;
437
441
  teleport?: boolean;
package/dist/solid.d.ts CHANGED
@@ -94,6 +94,7 @@ type EngineOptions = {
94
94
  dragThreshold?: number;
95
95
  dragFrom?: DragFrom;
96
96
  dragFromContent?: boolean;
97
+ fitContentToSnap?: boolean;
97
98
  rubberBand?: boolean;
98
99
  backdropRange?: [number, number];
99
100
  screenRange?: [number, number];
@@ -140,6 +141,7 @@ type EngineFeatureOptions = {
140
141
  closeOnRouteChange: boolean;
141
142
  persistKey?: string;
142
143
  autoCollapseAfter?: number;
144
+ fitContentToSnap: boolean;
143
145
  };
144
146
  type EngineFeatureContext = {
145
147
  element: HTMLElement;
@@ -262,6 +264,7 @@ declare class BottomSheetCore {
262
264
  private lifecycle;
263
265
  private closeOnBack;
264
266
  private routedTo;
267
+ private fitContentToSnap;
265
268
  private persistent;
266
269
  private disableCloseFlag;
267
270
  private disableDragFlag;
@@ -432,6 +435,7 @@ type BottomSheetProps<TId extends string = string> = {
432
435
  disableDrag?: boolean;
433
436
  dragFrom?: EngineOptions["dragFrom"];
434
437
  dragFromContent?: boolean;
438
+ fitContentToSnap?: boolean;
435
439
  closeOnRouteChange?: boolean;
436
440
  stackEffect?: boolean;
437
441
  teleport?: boolean;
package/dist/solid.js CHANGED
@@ -376,14 +376,26 @@ function notifyLinkedSheets(sheets, self) {
376
376
  }
377
377
  }
378
378
 
379
+ // src/core/primitives/hot-path-thresholds.ts
380
+ var SIZE_WRITE_EPSILON = 0.5;
381
+ var OPACITY_WRITE_EPSILON = 5e-3;
382
+ var POINTER_EVENTS_OPACITY_THRESHOLD = 0.05;
383
+ var RANGE_DIVISION_EPSILON = 1e-4;
384
+
379
385
  // src/core/features/resize-observer.ts
380
386
  function installResizeObserver(deps) {
381
387
  if (typeof window === "undefined") {
382
388
  return () => {
383
389
  };
384
390
  }
391
+ const seatFor = () => {
392
+ const snap = deps.resolveActiveSnap();
393
+ const max = deps.getMaxAxisSize();
394
+ return { target: snap ? Math.min(snap.size, max) : null, max };
395
+ };
385
396
  const onResize = () => {
386
397
  if (deps.isDestroyed()) return;
398
+ const before = seatFor();
387
399
  deps.recomputeSnaps();
388
400
  const mode = deps.getMode();
389
401
  const isVerticalAxis = mode === "bottom" || mode === "top";
@@ -392,6 +404,10 @@ function installResizeObserver(deps) {
392
404
  if (viewportSize2 > 0 && viewportSize2 < max) {
393
405
  deps.setMaxAxisSize(viewportSize2);
394
406
  }
407
+ const after = seatFor();
408
+ if (before.target !== null && after.target !== null && Math.abs(after.target - before.target) < SIZE_WRITE_EPSILON && Math.abs(after.max - before.max) < SIZE_WRITE_EPSILON) {
409
+ return;
410
+ }
395
411
  const wasAnimating = deps.isAnimating?.() ?? false;
396
412
  deps.cancelInFlight();
397
413
  deps.newCycle();
@@ -660,12 +676,6 @@ var SCRIM_PRESETS = Object.freeze({
660
676
  }
661
677
  });
662
678
 
663
- // src/core/primitives/hot-path-thresholds.ts
664
- var SIZE_WRITE_EPSILON = 0.5;
665
- var OPACITY_WRITE_EPSILON = 5e-3;
666
- var POINTER_EVENTS_OPACITY_THRESHOLD = 0.05;
667
- var RANGE_DIVISION_EPSILON = 1e-4;
668
-
669
679
  // src/core/primitives/opacity-dedup.ts
670
680
  var WriteSentinel = class {
671
681
  constructor() {
@@ -2595,6 +2605,7 @@ var BottomSheetCore = class {
2595
2605
  __publicField(this, "lifecycle");
2596
2606
  __publicField(this, "closeOnBack");
2597
2607
  __publicField(this, "routedTo");
2608
+ __publicField(this, "fitContentToSnap");
2598
2609
  __publicField(this, "persistent");
2599
2610
  __publicField(this, "disableCloseFlag");
2600
2611
  __publicField(this, "disableDragFlag");
@@ -2708,6 +2719,7 @@ var BottomSheetCore = class {
2708
2719
  );
2709
2720
  this.closeOnBack = resolved.closeOnBack;
2710
2721
  this.routedTo = opts.routedTo;
2722
+ this.fitContentToSnap = opts.fitContentToSnap === true;
2711
2723
  this.persistent = resolved.persistent;
2712
2724
  this.disableCloseFlag = resolved.disableClose;
2713
2725
  this.disableDragFlag = resolved.disableDrag;
@@ -2809,7 +2821,8 @@ var BottomSheetCore = class {
2809
2821
  closeOnBack: this.closeOnBack,
2810
2822
  closeOnRouteChange: this.closeOnRouteChange,
2811
2823
  persistKey: this.persistKey,
2812
- autoCollapseAfter
2824
+ autoCollapseAfter,
2825
+ fitContentToSnap: this.fitContentToSnap
2813
2826
  },
2814
2827
  isDestroyed: () => this.destroyed,
2815
2828
  isDragging: () => this.isDraggingAny(),
@@ -2861,6 +2874,11 @@ var BottomSheetCore = class {
2861
2874
  "[BottomSheet] closeOnBack/routedTo/closeOnRouteChange need routeFeature() \u2014 option ignored"
2862
2875
  );
2863
2876
  }
2877
+ if (this.fitContentToSnap && !names.has("content-fit")) {
2878
+ devWarn(
2879
+ "[BottomSheet] fitContentToSnap needs contentFitFeature() \u2014 option ignored"
2880
+ );
2881
+ }
2864
2882
  if (this.persistKey && !names.has("persist")) {
2865
2883
  devWarn(
2866
2884
  "[BottomSheet] persistKey needs persistFeature() \u2014 snaps will not be saved"
@@ -4218,6 +4236,68 @@ function visualViewportFeature() {
4218
4236
  };
4219
4237
  }
4220
4238
 
4239
+ // src/core/features/content-fit.ts
4240
+ var INSET_VAR = "--bs-content-inset";
4241
+ var FIT_ATTR = "data-bs-fit-content";
4242
+ function contentFitFeature() {
4243
+ return {
4244
+ name: "content-fit",
4245
+ install: (ctx) => {
4246
+ const scroller = ctx.scrollContainer;
4247
+ if (!ctx.options.fitContentToSnap || !scroller || typeof window === "undefined") {
4248
+ return;
4249
+ }
4250
+ const sheet = ctx.element;
4251
+ let inset = 0;
4252
+ let unpaddedMax = -1;
4253
+ let top = 0;
4254
+ const hiddenAt = (size) => sheet.dataset.mode === "bottom" ? Math.max(0, ctx.getMaxAxisSize() - size) : 0;
4255
+ const follow = (size) => {
4256
+ if (unpaddedMax < 0) {
4257
+ unpaddedMax = scroller.scrollHeight - scroller.clientHeight - inset;
4258
+ top = scroller.scrollTop;
4259
+ }
4260
+ const limit = Math.max(0, unpaddedMax + hiddenAt(size));
4261
+ if (top > limit) {
4262
+ if (scroller.scrollTop > limit) scroller.scrollTop = limit;
4263
+ top = limit;
4264
+ }
4265
+ };
4266
+ const settle = () => {
4267
+ if (ctx.isDestroyed()) return;
4268
+ const size = ctx.getSize();
4269
+ unpaddedMax = -1;
4270
+ follow(size);
4271
+ inset = hiddenAt(size);
4272
+ sheet.style.setProperty(INSET_VAR, `${inset}px`);
4273
+ unpaddedMax = -1;
4274
+ };
4275
+ const moving = () => ctx.isAnimating() || ctx.isDragging();
4276
+ const whenIdle = () => {
4277
+ if (!moving()) settle();
4278
+ };
4279
+ sheet.setAttribute(FIT_ATTR, "");
4280
+ settle();
4281
+ const offProgress = ctx.on(
4282
+ "progress",
4283
+ (p) => moving() ? follow(p.size) : settle()
4284
+ );
4285
+ const offSnap = ctx.on("snap", settle);
4286
+ const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(whenIdle);
4287
+ observer?.observe(document.documentElement);
4288
+ window.addEventListener("orientationchange", whenIdle);
4289
+ return () => {
4290
+ offProgress();
4291
+ offSnap();
4292
+ observer?.disconnect();
4293
+ window.removeEventListener("orientationchange", whenIdle);
4294
+ sheet.removeAttribute(FIT_ATTR);
4295
+ sheet.style.removeProperty(INSET_VAR);
4296
+ };
4297
+ }
4298
+ };
4299
+ }
4300
+
4221
4301
  // src/core/default-features.ts
4222
4302
  function defaultEngineFeatures() {
4223
4303
  return [
@@ -4225,7 +4305,8 @@ function defaultEngineFeatures() {
4225
4305
  visualViewportFeature(),
4226
4306
  persistFeature(),
4227
4307
  autoCollapseFeature(),
4228
- routeFeature()
4308
+ routeFeature(),
4309
+ contentFitFeature()
4229
4310
  ];
4230
4311
  }
4231
4312
 
@@ -4321,6 +4402,7 @@ var BottomSheet = (props) => {
4321
4402
  disableDrag: props.disableDrag,
4322
4403
  dragFrom: props.dragFrom,
4323
4404
  dragFromContent: props.dragFromContent,
4405
+ fitContentToSnap: props.fitContentToSnap,
4324
4406
  closeOnRouteChange: props.closeOnRouteChange,
4325
4407
  stackEffect: props.stackEffect,
4326
4408
  returnFocusTo: props.returnFocusTo