@surdeddd/bottom-sheet 0.9.1 → 0.10.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 (50) hide show
  1. package/README.md +108 -66
  2. package/dist/{BottomSheetEngine-CBRcBwV-.d.ts → BottomSheetEngine-DRjCU73e.d.ts} +6 -5
  3. package/dist/{BottomSheetEngine-BcyruNP1.d.cts → BottomSheetEngine-DzsIwD28.d.cts} +6 -5
  4. package/dist/element.cjs +161 -99
  5. package/dist/element.d.cts +1 -1
  6. package/dist/element.d.ts +1 -1
  7. package/dist/element.iife.global.js +2 -2
  8. package/dist/element.js +161 -99
  9. package/dist/index.cjs +155 -115
  10. package/dist/index.d.cts +2 -2
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.js +155 -115
  13. package/dist/integrations/formik.d.cts +1 -1
  14. package/dist/integrations/formik.d.ts +1 -1
  15. package/dist/integrations/react-hook-form.d.cts +1 -1
  16. package/dist/integrations/react-hook-form.d.ts +1 -1
  17. package/dist/overlay.cjs +34 -25
  18. package/dist/overlay.d.cts +3 -0
  19. package/dist/overlay.d.ts +3 -0
  20. package/dist/overlay.js +34 -25
  21. package/dist/preact.d.cts +2 -1
  22. package/dist/preact.d.ts +2 -1
  23. package/dist/qwik.cjs +179 -93
  24. package/dist/qwik.d.cts +11 -2
  25. package/dist/qwik.d.ts +11 -2
  26. package/dist/qwik.js +179 -93
  27. package/dist/react.cjs +266 -181
  28. package/dist/react.d.cts +26 -4
  29. package/dist/react.d.ts +26 -4
  30. package/dist/react.js +266 -181
  31. package/dist/solid.cjs +145 -92
  32. package/dist/solid.d.cts +14 -4
  33. package/dist/solid.d.ts +14 -4
  34. package/dist/solid.js +145 -92
  35. package/dist/solid.source.jsx +145 -92
  36. package/dist/styles.css +17 -1
  37. package/dist/svelte-core.cjs +128 -90
  38. package/dist/svelte-core.js +128 -90
  39. package/dist/svelte-src/BottomSheet.svelte +6 -0
  40. package/dist/svelte.cjs +130 -90
  41. package/dist/svelte.d.cts +2 -0
  42. package/dist/svelte.d.ts +2 -0
  43. package/dist/svelte.js +130 -90
  44. package/dist/teleport-7uYNiEAT.d.cts +3 -0
  45. package/dist/teleport-7uYNiEAT.d.ts +3 -0
  46. package/dist/vue.cjs +136 -91
  47. package/dist/vue.d.cts +3 -1
  48. package/dist/vue.d.ts +3 -1
  49. package/dist/vue.js +136 -91
  50. package/package.json +6 -6
@@ -185,11 +185,18 @@ var resolveSnap = (point, mode, measureFit) => {
185
185
  return Math.max(0, el.getBoundingClientRect().width);
186
186
  };
187
187
 
188
+ // src/core/primitives/devWarn.ts
189
+ function devWarn(...args) {
190
+ if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
191
+ console.warn(...args);
192
+ }
193
+ }
194
+
188
195
  // src/core/primitives/snap-points.ts
189
196
  var resolveSnapList = (points, mode, measureFit) => points.map((p) => {
190
197
  const raw = resolveSnap(p.size, mode, measureFit);
191
198
  if (!Number.isFinite(raw) || raw < 0) {
192
- console.warn(
199
+ devWarn(
193
200
  `[BottomSheet] snap "${p.id}" resolved to invalid size (${String(p.size)} \u2192 ${raw}); clamped to 0.`
194
201
  );
195
202
  return { id: p.id, size: 0 };
@@ -201,7 +208,7 @@ var auditVhUsage = (points) => {
201
208
  for (const p of points) {
202
209
  if (typeof p.size !== "string") continue;
203
210
  if (!VH_NOT_DVH.test(p.size)) continue;
204
- console.warn(
211
+ devWarn(
205
212
  `[BottomSheet] snap "${p.id}" uses "vh" \u2014 prefer "dvh" on mobile (iOS Safari URL bar makes vh unstable). See https://web.dev/blog/viewport-units`
206
213
  );
207
214
  }
@@ -255,6 +262,26 @@ var findDragSettleTarget = (input) => {
255
262
  );
256
263
  };
257
264
 
265
+ // src/core/primitives/cancelable-emit.ts
266
+ function emitCancelable(emit, base, warnLabel) {
267
+ let cancelled = false;
268
+ let frozen = false;
269
+ emit({
270
+ ...base,
271
+ cancel: () => {
272
+ if (frozen) {
273
+ devWarn(
274
+ `[BottomSheet] ${warnLabel}.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener.`
275
+ );
276
+ return;
277
+ }
278
+ cancelled = true;
279
+ }
280
+ });
281
+ frozen = true;
282
+ return cancelled;
283
+ }
284
+
258
285
  // src/core/primitives/snap-resolver.ts
259
286
  var SnapResolver = class {
260
287
  constructor(raw, allowed, mode, measureFit, onMaxAxisSizeChange) {
@@ -399,7 +426,9 @@ function notifyLinkedSheets(sheets, self) {
399
426
  try {
400
427
  if (linked.state.size === 0) continue;
401
428
  const ids = linked.getAllowedIds();
402
- const target = ids.find((id) => id !== "closed");
429
+ const resolved = linked.getResolvedSnaps();
430
+ const sizeOf = (id) => resolved.find((s) => s.id === id)?.size ?? 0;
431
+ const target = ids.find((id) => sizeOf(id) > 0);
403
432
  if (target && target !== linked.state.activeId) {
404
433
  void linked.snapTo(target);
405
434
  }
@@ -616,11 +645,15 @@ function installVisualViewport(deps) {
616
645
  if (clamp < deps.getMaxAxisSize()) {
617
646
  deps.setMaxAxisSize(clamp);
618
647
  }
648
+ const wasAnimating = deps.isAnimating?.() ?? false;
649
+ deps.cancelInFlight();
650
+ deps.newCycle();
619
651
  const max = deps.getMaxAxisSize();
620
652
  deps.setSize(Math.min(deps.getSize(), max));
621
653
  const current = deps.resolveActiveSnap();
622
654
  if (current && !deps.isDragging()) {
623
655
  deps.applySize(Math.min(current.size, max));
656
+ if (wasAnimating) deps.resyncAfterCancel?.();
624
657
  } else {
625
658
  deps.applySize(deps.getSize());
626
659
  }
@@ -761,6 +794,54 @@ function installFitObserver(deps) {
761
794
  };
762
795
  }
763
796
 
797
+ // src/core/features/max-height-controller.ts
798
+ function createMaxHeightController(deps) {
799
+ let maxHeightCap;
800
+ let maxHeightRaw;
801
+ const resolveCap = () => {
802
+ const raw = maxHeightRaw;
803
+ if (raw === void 0) {
804
+ maxHeightCap = void 0;
805
+ return;
806
+ }
807
+ if (typeof raw === "number") {
808
+ maxHeightCap = raw;
809
+ return;
810
+ }
811
+ if (typeof window === "undefined") return;
812
+ const measured = resolveSnap(raw, deps.mode);
813
+ maxHeightCap = measured > 0 ? measured : void 0;
814
+ };
815
+ const clampTo = () => {
816
+ if (maxHeightCap === void 0) return;
817
+ if (deps.getMaxAxisSize() > maxHeightCap) {
818
+ deps.setMaxAxisSize(maxHeightCap);
819
+ }
820
+ };
821
+ return {
822
+ setRadius(r) {
823
+ deps.element.style.setProperty(
824
+ "--bs-radius",
825
+ typeof r === "number" ? `${r}px` : r
826
+ );
827
+ },
828
+ setMaxHeight(h) {
829
+ const value = typeof h === "number" ? `${h}px` : h;
830
+ const axis = layoutAxis(deps.mode);
831
+ deps.element.style.setProperty(
832
+ axis === "height" ? "max-height" : "max-width",
833
+ value
834
+ );
835
+ maxHeightRaw = h;
836
+ resolveCap();
837
+ deps.recompute();
838
+ },
839
+ resolveCap,
840
+ clampTo,
841
+ getCap: () => maxHeightCap
842
+ };
843
+ }
844
+
764
845
  // src/core/features/fit-measurement.ts
765
846
  var measureSheetNatural = (element, content, vertical) => {
766
847
  if (!content) {
@@ -892,13 +973,6 @@ var WriteSentinel = class {
892
973
  }
893
974
  };
894
975
 
895
- // src/core/primitives/devWarn.ts
896
- function devWarn(...args) {
897
- if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
898
- console.warn(...args);
899
- }
900
- }
901
-
902
976
  // src/core/primitives/overlay-position.ts
903
977
  function resolveSheetAnchoredStyle(mode, position, inset) {
904
978
  const sizeOffset = `calc(var(--bs-size, 0px) + ${inset})`;
@@ -2544,8 +2618,7 @@ var BottomSheetEngine = class {
2544
2618
  __publicField(this, "disableCloseFlag");
2545
2619
  __publicField(this, "disableDragFlag");
2546
2620
  __publicField(this, "closeOnRouteChange");
2547
- __publicField(this, "maxHeightCap");
2548
- __publicField(this, "maxHeightRaw");
2621
+ __publicField(this, "maxHeight");
2549
2622
  __publicField(this, "snapPointsRaw");
2550
2623
  __publicField(this, "snaps");
2551
2624
  __publicField(this, "activeId");
@@ -2656,11 +2729,20 @@ var BottomSheetEngine = class {
2656
2729
  auditVhUsage(this.snapPointsRaw);
2657
2730
  this.auditDuplicateSnapIds(this.snapPointsRaw);
2658
2731
  this.rootEl = this.element.closest(".bs-root");
2732
+ this.maxHeight = createMaxHeightController({
2733
+ element: this.element,
2734
+ mode: this.mode,
2735
+ getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
2736
+ setMaxAxisSize: (size) => {
2737
+ this.snaps.setMaxAxisSize(size);
2738
+ },
2739
+ recompute: () => this.recompute()
2740
+ });
2659
2741
  this.fitDeps = {
2660
2742
  element: this.element,
2661
2743
  scrollContainer: this.scrollContainer,
2662
2744
  mode: this.mode,
2663
- getMaxHeightCap: () => this.maxHeightCap
2745
+ getMaxHeightCap: () => this.maxHeight.getCap()
2664
2746
  };
2665
2747
  this.snaps = new SnapResolver(
2666
2748
  this.snapPointsRaw,
@@ -2771,7 +2853,7 @@ var BottomSheetEngine = class {
2771
2853
  }
2772
2854
  use(plugin) {
2773
2855
  if (this.destroyed) {
2774
- console.warn(
2856
+ devWarn(
2775
2857
  `[BottomSheet] use("${plugin.name}") called on destroyed engine \u2014 ignored.`
2776
2858
  );
2777
2859
  return this;
@@ -2813,6 +2895,9 @@ var BottomSheetEngine = class {
2813
2895
  getAllowedIds() {
2814
2896
  return this.snaps.getAllowedIds().slice();
2815
2897
  }
2898
+ getResolvedSnaps() {
2899
+ return this.snaps.getResolvedSnaps();
2900
+ }
2816
2901
  async snapTo(id, velocityOrOpts = 0, _skipBeforeSnap = false) {
2817
2902
  if (this.destroyed) return;
2818
2903
  const opts = typeof velocityOrOpts === "object" ? velocityOrOpts : { velocity: velocityOrOpts };
@@ -2821,11 +2906,11 @@ var BottomSheetEngine = class {
2821
2906
  if (externalSignal?.aborted) return;
2822
2907
  const target = this.snaps.findById(id);
2823
2908
  if (!target) {
2824
- console.warn(`[BottomSheet] unknown snap id: ${id}`);
2909
+ devWarn(`[BottomSheet] unknown snap id: ${id}`);
2825
2910
  return;
2826
2911
  }
2827
2912
  if (!this.snaps.getAllowedIds().includes(id)) {
2828
- console.warn(`[BottomSheet] snap "${id}" is not in allowed list`);
2913
+ devWarn(`[BottomSheet] snap "${id}" is not in allowed list`);
2829
2914
  return;
2830
2915
  }
2831
2916
  if (!_skipBeforeSnap && this.emitBeforeSnap(target, this.activeId)) {
@@ -2957,42 +3042,11 @@ var BottomSheetEngine = class {
2957
3042
  }
2958
3043
  setRadius(r) {
2959
3044
  if (this.destroyed) return;
2960
- this.element.style.setProperty(
2961
- "--bs-radius",
2962
- typeof r === "number" ? `${r}px` : r
2963
- );
3045
+ this.maxHeight.setRadius(r);
2964
3046
  }
2965
3047
  setMaxHeight(h) {
2966
3048
  if (this.destroyed) return;
2967
- const value = typeof h === "number" ? `${h}px` : h;
2968
- const axis = layoutAxis(this.mode);
2969
- this.element.style.setProperty(
2970
- axis === "height" ? "max-height" : "max-width",
2971
- value
2972
- );
2973
- this.maxHeightRaw = h;
2974
- this.resolveMaxHeightCap();
2975
- this.recompute();
2976
- }
2977
- resolveMaxHeightCap() {
2978
- const raw = this.maxHeightRaw;
2979
- if (raw === void 0) {
2980
- this.maxHeightCap = void 0;
2981
- return;
2982
- }
2983
- if (typeof raw === "number") {
2984
- this.maxHeightCap = raw;
2985
- return;
2986
- }
2987
- if (typeof window === "undefined") return;
2988
- const measured = resolveSnap(raw, this.mode);
2989
- this.maxHeightCap = measured > 0 ? measured : void 0;
2990
- }
2991
- clampToMaxHeight() {
2992
- if (this.maxHeightCap === void 0) return;
2993
- if (this.snaps.getMaxAxisSize() > this.maxHeightCap) {
2994
- this.snaps.setMaxAxisSize(this.maxHeightCap);
2995
- }
3049
+ this.maxHeight.setMaxHeight(h);
2996
3050
  }
2997
3051
  setAllowed(ids, snap) {
2998
3052
  if (this.destroyed) return;
@@ -3080,7 +3134,7 @@ var BottomSheetEngine = class {
3080
3134
  };
3081
3135
  const host = this.screenComponent?.parentElement;
3082
3136
  if (!host) {
3083
- console.warn(
3137
+ devWarn(
3084
3138
  "[BottomSheet] setScrimStages: no scrim element mounted \u2014 pass `scrim` to the engine first."
3085
3139
  );
3086
3140
  return () => {
@@ -3130,9 +3184,9 @@ var BottomSheetEngine = class {
3130
3184
  }
3131
3185
  recompute() {
3132
3186
  if (this.destroyed) return;
3133
- this.resolveMaxHeightCap();
3187
+ this.maxHeight.resolveCap();
3134
3188
  this.snaps.recompute();
3135
- this.clampToMaxHeight();
3189
+ this.maxHeight.clampTo();
3136
3190
  this.scrim.invalidateOpacityCache();
3137
3191
  if (this.gesture?.isDragging) return;
3138
3192
  const current = this.snaps.findById(this.activeId);
@@ -3182,42 +3236,18 @@ var BottomSheetEngine = class {
3182
3236
  return this.currentAbort.signal;
3183
3237
  }
3184
3238
  emitBeforeSnap(target, previousId) {
3185
- let cancelled = false;
3186
- let frozen = false;
3187
- this.emit("before-snap", {
3188
- id: target.id,
3189
- size: target.size,
3190
- previousId,
3191
- cancel: () => {
3192
- if (frozen) {
3193
- console.warn(
3194
- "[BottomSheet] before-snap.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener."
3195
- );
3196
- return;
3197
- }
3198
- cancelled = true;
3199
- }
3200
- });
3201
- frozen = true;
3202
- return cancelled;
3239
+ return emitCancelable(
3240
+ (payload) => this.emit("before-snap", payload),
3241
+ { id: target.id, size: target.size, previousId },
3242
+ "before-snap"
3243
+ );
3203
3244
  }
3204
3245
  emitBeforeClose(reason) {
3205
- let cancelled = false;
3206
- let frozen = false;
3207
- this.emit("before-close", {
3208
- reason,
3209
- cancel: () => {
3210
- if (frozen) {
3211
- console.warn(
3212
- "[BottomSheet] before-close.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener."
3213
- );
3214
- return;
3215
- }
3216
- cancelled = true;
3217
- }
3218
- });
3219
- frozen = true;
3220
- return cancelled;
3246
+ return emitCancelable(
3247
+ (payload) => this.emit("before-close", payload),
3248
+ { reason },
3249
+ "before-close"
3250
+ );
3221
3251
  }
3222
3252
  applyAutoAriaLabelledBy() {
3223
3253
  if (typeof document === "undefined") return;
@@ -3232,16 +3262,16 @@ var BottomSheetEngine = class {
3232
3262
  this.element.setAttribute("aria-labelledby", titled.id);
3233
3263
  }
3234
3264
  recomputeSnaps() {
3235
- this.resolveMaxHeightCap();
3265
+ this.maxHeight.resolveCap();
3236
3266
  this.snaps.setRaw(this.snapPointsRaw);
3237
- this.clampToMaxHeight();
3267
+ this.maxHeight.clampTo();
3238
3268
  this.scrim.invalidateOpacityCache();
3239
3269
  }
3240
3270
  auditDuplicateSnapIds(points) {
3241
3271
  const seen = /* @__PURE__ */ new Set();
3242
3272
  for (const p of points) {
3243
3273
  if (seen.has(p.id)) {
3244
- console.warn(
3274
+ devWarn(
3245
3275
  `[BottomSheet] duplicate snap id "${p.id}" \u2014 only the first occurrence is reachable.`
3246
3276
  );
3247
3277
  }
@@ -3408,7 +3438,15 @@ var BottomSheetEngine = class {
3408
3438
  setSize: (size) => {
3409
3439
  this.size = size;
3410
3440
  },
3411
- applySize: (size) => this.applySize(size)
3441
+ applySize: (size) => this.applySize(size),
3442
+ cancelInFlight: () => {
3443
+ this.animation.cancel();
3444
+ },
3445
+ newCycle: () => {
3446
+ this.newCycle();
3447
+ },
3448
+ isAnimating: () => this.animation.isAnimating,
3449
+ resyncAfterCancel: () => this.resyncAfterResize()
3412
3450
  }));
3413
3451
  }
3414
3452
  this.teardowns.add(installSliderKeyboard({