@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
package/dist/svelte.cjs CHANGED
@@ -207,11 +207,18 @@ var resolveSnap = (point, mode, measureFit) => {
207
207
  return Math.max(0, el.getBoundingClientRect().width);
208
208
  };
209
209
 
210
+ // src/core/primitives/devWarn.ts
211
+ function devWarn(...args) {
212
+ if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
213
+ console.warn(...args);
214
+ }
215
+ }
216
+
210
217
  // src/core/primitives/snap-points.ts
211
218
  var resolveSnapList = (points, mode, measureFit) => points.map((p) => {
212
219
  const raw = resolveSnap(p.size, mode, measureFit);
213
220
  if (!Number.isFinite(raw) || raw < 0) {
214
- console.warn(
221
+ devWarn(
215
222
  `[BottomSheet] snap "${p.id}" resolved to invalid size (${String(p.size)} \u2192 ${raw}); clamped to 0.`
216
223
  );
217
224
  return { id: p.id, size: 0 };
@@ -223,7 +230,7 @@ var auditVhUsage = (points) => {
223
230
  for (const p of points) {
224
231
  if (typeof p.size !== "string") continue;
225
232
  if (!VH_NOT_DVH.test(p.size)) continue;
226
- console.warn(
233
+ devWarn(
227
234
  `[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`
228
235
  );
229
236
  }
@@ -277,6 +284,26 @@ var findDragSettleTarget = (input) => {
277
284
  );
278
285
  };
279
286
 
287
+ // src/core/primitives/cancelable-emit.ts
288
+ function emitCancelable(emit, base, warnLabel) {
289
+ let cancelled = false;
290
+ let frozen = false;
291
+ emit({
292
+ ...base,
293
+ cancel: () => {
294
+ if (frozen) {
295
+ devWarn(
296
+ `[BottomSheet] ${warnLabel}.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener.`
297
+ );
298
+ return;
299
+ }
300
+ cancelled = true;
301
+ }
302
+ });
303
+ frozen = true;
304
+ return cancelled;
305
+ }
306
+
280
307
  // src/core/primitives/snap-resolver.ts
281
308
  var SnapResolver = class {
282
309
  constructor(raw, allowed, mode, measureFit, onMaxAxisSizeChange) {
@@ -421,7 +448,9 @@ function notifyLinkedSheets(sheets, self) {
421
448
  try {
422
449
  if (linked.state.size === 0) continue;
423
450
  const ids = linked.getAllowedIds();
424
- const target = ids.find((id) => id !== "closed");
451
+ const resolved = linked.getResolvedSnaps();
452
+ const sizeOf = (id) => resolved.find((s) => s.id === id)?.size ?? 0;
453
+ const target = ids.find((id) => sizeOf(id) > 0);
425
454
  if (target && target !== linked.state.activeId) {
426
455
  void linked.snapTo(target);
427
456
  }
@@ -638,11 +667,15 @@ function installVisualViewport(deps) {
638
667
  if (clamp < deps.getMaxAxisSize()) {
639
668
  deps.setMaxAxisSize(clamp);
640
669
  }
670
+ const wasAnimating = deps.isAnimating?.() ?? false;
671
+ deps.cancelInFlight();
672
+ deps.newCycle();
641
673
  const max = deps.getMaxAxisSize();
642
674
  deps.setSize(Math.min(deps.getSize(), max));
643
675
  const current = deps.resolveActiveSnap();
644
676
  if (current && !deps.isDragging()) {
645
677
  deps.applySize(Math.min(current.size, max));
678
+ if (wasAnimating) deps.resyncAfterCancel?.();
646
679
  } else {
647
680
  deps.applySize(deps.getSize());
648
681
  }
@@ -783,6 +816,54 @@ function installFitObserver(deps) {
783
816
  };
784
817
  }
785
818
 
819
+ // src/core/features/max-height-controller.ts
820
+ function createMaxHeightController(deps) {
821
+ let maxHeightCap;
822
+ let maxHeightRaw;
823
+ const resolveCap = () => {
824
+ const raw = maxHeightRaw;
825
+ if (raw === void 0) {
826
+ maxHeightCap = void 0;
827
+ return;
828
+ }
829
+ if (typeof raw === "number") {
830
+ maxHeightCap = raw;
831
+ return;
832
+ }
833
+ if (typeof window === "undefined") return;
834
+ const measured = resolveSnap(raw, deps.mode);
835
+ maxHeightCap = measured > 0 ? measured : void 0;
836
+ };
837
+ const clampTo = () => {
838
+ if (maxHeightCap === void 0) return;
839
+ if (deps.getMaxAxisSize() > maxHeightCap) {
840
+ deps.setMaxAxisSize(maxHeightCap);
841
+ }
842
+ };
843
+ return {
844
+ setRadius(r) {
845
+ deps.element.style.setProperty(
846
+ "--bs-radius",
847
+ typeof r === "number" ? `${r}px` : r
848
+ );
849
+ },
850
+ setMaxHeight(h) {
851
+ const value = typeof h === "number" ? `${h}px` : h;
852
+ const axis = layoutAxis(deps.mode);
853
+ deps.element.style.setProperty(
854
+ axis === "height" ? "max-height" : "max-width",
855
+ value
856
+ );
857
+ maxHeightRaw = h;
858
+ resolveCap();
859
+ deps.recompute();
860
+ },
861
+ resolveCap,
862
+ clampTo,
863
+ getCap: () => maxHeightCap
864
+ };
865
+ }
866
+
786
867
  // src/core/features/fit-measurement.ts
787
868
  var measureSheetNatural = (element, content, vertical) => {
788
869
  if (!content) {
@@ -914,13 +995,6 @@ var WriteSentinel = class {
914
995
  }
915
996
  };
916
997
 
917
- // src/core/primitives/devWarn.ts
918
- function devWarn(...args) {
919
- if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
920
- console.warn(...args);
921
- }
922
- }
923
-
924
998
  // src/core/primitives/overlay-position.ts
925
999
  function resolveSheetAnchoredStyle(mode, position, inset) {
926
1000
  const sizeOffset = `calc(var(--bs-size, 0px) + ${inset})`;
@@ -2566,8 +2640,7 @@ var BottomSheetEngine = class {
2566
2640
  __publicField(this, "disableCloseFlag");
2567
2641
  __publicField(this, "disableDragFlag");
2568
2642
  __publicField(this, "closeOnRouteChange");
2569
- __publicField(this, "maxHeightCap");
2570
- __publicField(this, "maxHeightRaw");
2643
+ __publicField(this, "maxHeight");
2571
2644
  __publicField(this, "snapPointsRaw");
2572
2645
  __publicField(this, "snaps");
2573
2646
  __publicField(this, "activeId");
@@ -2678,11 +2751,20 @@ var BottomSheetEngine = class {
2678
2751
  auditVhUsage(this.snapPointsRaw);
2679
2752
  this.auditDuplicateSnapIds(this.snapPointsRaw);
2680
2753
  this.rootEl = this.element.closest(".bs-root");
2754
+ this.maxHeight = createMaxHeightController({
2755
+ element: this.element,
2756
+ mode: this.mode,
2757
+ getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
2758
+ setMaxAxisSize: (size) => {
2759
+ this.snaps.setMaxAxisSize(size);
2760
+ },
2761
+ recompute: () => this.recompute()
2762
+ });
2681
2763
  this.fitDeps = {
2682
2764
  element: this.element,
2683
2765
  scrollContainer: this.scrollContainer,
2684
2766
  mode: this.mode,
2685
- getMaxHeightCap: () => this.maxHeightCap
2767
+ getMaxHeightCap: () => this.maxHeight.getCap()
2686
2768
  };
2687
2769
  this.snaps = new SnapResolver(
2688
2770
  this.snapPointsRaw,
@@ -2793,7 +2875,7 @@ var BottomSheetEngine = class {
2793
2875
  }
2794
2876
  use(plugin) {
2795
2877
  if (this.destroyed) {
2796
- console.warn(
2878
+ devWarn(
2797
2879
  `[BottomSheet] use("${plugin.name}") called on destroyed engine \u2014 ignored.`
2798
2880
  );
2799
2881
  return this;
@@ -2835,6 +2917,9 @@ var BottomSheetEngine = class {
2835
2917
  getAllowedIds() {
2836
2918
  return this.snaps.getAllowedIds().slice();
2837
2919
  }
2920
+ getResolvedSnaps() {
2921
+ return this.snaps.getResolvedSnaps();
2922
+ }
2838
2923
  async snapTo(id, velocityOrOpts = 0, _skipBeforeSnap = false) {
2839
2924
  if (this.destroyed) return;
2840
2925
  const opts = typeof velocityOrOpts === "object" ? velocityOrOpts : { velocity: velocityOrOpts };
@@ -2843,11 +2928,11 @@ var BottomSheetEngine = class {
2843
2928
  if (externalSignal?.aborted) return;
2844
2929
  const target = this.snaps.findById(id);
2845
2930
  if (!target) {
2846
- console.warn(`[BottomSheet] unknown snap id: ${id}`);
2931
+ devWarn(`[BottomSheet] unknown snap id: ${id}`);
2847
2932
  return;
2848
2933
  }
2849
2934
  if (!this.snaps.getAllowedIds().includes(id)) {
2850
- console.warn(`[BottomSheet] snap "${id}" is not in allowed list`);
2935
+ devWarn(`[BottomSheet] snap "${id}" is not in allowed list`);
2851
2936
  return;
2852
2937
  }
2853
2938
  if (!_skipBeforeSnap && this.emitBeforeSnap(target, this.activeId)) {
@@ -2979,42 +3064,11 @@ var BottomSheetEngine = class {
2979
3064
  }
2980
3065
  setRadius(r) {
2981
3066
  if (this.destroyed) return;
2982
- this.element.style.setProperty(
2983
- "--bs-radius",
2984
- typeof r === "number" ? `${r}px` : r
2985
- );
3067
+ this.maxHeight.setRadius(r);
2986
3068
  }
2987
3069
  setMaxHeight(h) {
2988
3070
  if (this.destroyed) return;
2989
- const value = typeof h === "number" ? `${h}px` : h;
2990
- const axis = layoutAxis(this.mode);
2991
- this.element.style.setProperty(
2992
- axis === "height" ? "max-height" : "max-width",
2993
- value
2994
- );
2995
- this.maxHeightRaw = h;
2996
- this.resolveMaxHeightCap();
2997
- this.recompute();
2998
- }
2999
- resolveMaxHeightCap() {
3000
- const raw = this.maxHeightRaw;
3001
- if (raw === void 0) {
3002
- this.maxHeightCap = void 0;
3003
- return;
3004
- }
3005
- if (typeof raw === "number") {
3006
- this.maxHeightCap = raw;
3007
- return;
3008
- }
3009
- if (typeof window === "undefined") return;
3010
- const measured = resolveSnap(raw, this.mode);
3011
- this.maxHeightCap = measured > 0 ? measured : void 0;
3012
- }
3013
- clampToMaxHeight() {
3014
- if (this.maxHeightCap === void 0) return;
3015
- if (this.snaps.getMaxAxisSize() > this.maxHeightCap) {
3016
- this.snaps.setMaxAxisSize(this.maxHeightCap);
3017
- }
3071
+ this.maxHeight.setMaxHeight(h);
3018
3072
  }
3019
3073
  setAllowed(ids, snap) {
3020
3074
  if (this.destroyed) return;
@@ -3102,7 +3156,7 @@ var BottomSheetEngine = class {
3102
3156
  };
3103
3157
  const host = this.screenComponent?.parentElement;
3104
3158
  if (!host) {
3105
- console.warn(
3159
+ devWarn(
3106
3160
  "[BottomSheet] setScrimStages: no scrim element mounted \u2014 pass `scrim` to the engine first."
3107
3161
  );
3108
3162
  return () => {
@@ -3152,9 +3206,9 @@ var BottomSheetEngine = class {
3152
3206
  }
3153
3207
  recompute() {
3154
3208
  if (this.destroyed) return;
3155
- this.resolveMaxHeightCap();
3209
+ this.maxHeight.resolveCap();
3156
3210
  this.snaps.recompute();
3157
- this.clampToMaxHeight();
3211
+ this.maxHeight.clampTo();
3158
3212
  this.scrim.invalidateOpacityCache();
3159
3213
  if (this.gesture?.isDragging) return;
3160
3214
  const current = this.snaps.findById(this.activeId);
@@ -3204,42 +3258,18 @@ var BottomSheetEngine = class {
3204
3258
  return this.currentAbort.signal;
3205
3259
  }
3206
3260
  emitBeforeSnap(target, previousId) {
3207
- let cancelled = false;
3208
- let frozen = false;
3209
- this.emit("before-snap", {
3210
- id: target.id,
3211
- size: target.size,
3212
- previousId,
3213
- cancel: () => {
3214
- if (frozen) {
3215
- console.warn(
3216
- "[BottomSheet] before-snap.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener."
3217
- );
3218
- return;
3219
- }
3220
- cancelled = true;
3221
- }
3222
- });
3223
- frozen = true;
3224
- return cancelled;
3261
+ return emitCancelable(
3262
+ (payload) => this.emit("before-snap", payload),
3263
+ { id: target.id, size: target.size, previousId },
3264
+ "before-snap"
3265
+ );
3225
3266
  }
3226
3267
  emitBeforeClose(reason) {
3227
- let cancelled = false;
3228
- let frozen = false;
3229
- this.emit("before-close", {
3230
- reason,
3231
- cancel: () => {
3232
- if (frozen) {
3233
- console.warn(
3234
- "[BottomSheet] before-close.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener."
3235
- );
3236
- return;
3237
- }
3238
- cancelled = true;
3239
- }
3240
- });
3241
- frozen = true;
3242
- return cancelled;
3268
+ return emitCancelable(
3269
+ (payload) => this.emit("before-close", payload),
3270
+ { reason },
3271
+ "before-close"
3272
+ );
3243
3273
  }
3244
3274
  applyAutoAriaLabelledBy() {
3245
3275
  if (typeof document === "undefined") return;
@@ -3254,16 +3284,16 @@ var BottomSheetEngine = class {
3254
3284
  this.element.setAttribute("aria-labelledby", titled.id);
3255
3285
  }
3256
3286
  recomputeSnaps() {
3257
- this.resolveMaxHeightCap();
3287
+ this.maxHeight.resolveCap();
3258
3288
  this.snaps.setRaw(this.snapPointsRaw);
3259
- this.clampToMaxHeight();
3289
+ this.maxHeight.clampTo();
3260
3290
  this.scrim.invalidateOpacityCache();
3261
3291
  }
3262
3292
  auditDuplicateSnapIds(points) {
3263
3293
  const seen = /* @__PURE__ */ new Set();
3264
3294
  for (const p of points) {
3265
3295
  if (seen.has(p.id)) {
3266
- console.warn(
3296
+ devWarn(
3267
3297
  `[BottomSheet] duplicate snap id "${p.id}" \u2014 only the first occurrence is reachable.`
3268
3298
  );
3269
3299
  }
@@ -3430,7 +3460,15 @@ var BottomSheetEngine = class {
3430
3460
  setSize: (size) => {
3431
3461
  this.size = size;
3432
3462
  },
3433
- applySize: (size) => this.applySize(size)
3463
+ applySize: (size) => this.applySize(size),
3464
+ cancelInFlight: () => {
3465
+ this.animation.cancel();
3466
+ },
3467
+ newCycle: () => {
3468
+ this.newCycle();
3469
+ },
3470
+ isAnimating: () => this.animation.isAnimating,
3471
+ resyncAfterCancel: () => this.resyncAfterResize()
3434
3472
  }));
3435
3473
  }
3436
3474
  this.teardowns.add(installSliderKeyboard({
@@ -3795,6 +3833,8 @@ function BottomSheet($$anchor, $$props) {
3795
3833
  sync();
3796
3834
  $$props.ondragend?.();
3797
3835
  });
3836
+ if ($$props.ondrag) engine.on("drag", (payload) => $$props.ondrag(payload));
3837
+ if ($$props.onprogress) engine.on("progress", (payload) => $$props.onprogress(payload));
3798
3838
  });
3799
3839
  svelte.onDestroy(() => {
3800
3840
  restoreTeleport?.();
package/dist/svelte.d.cts CHANGED
@@ -115,6 +115,8 @@ export type BottomSheetProps<TId extends string = string> = {
115
115
  onclosed?: () => void;
116
116
  ondragstart?: () => void;
117
117
  ondragend?: () => void;
118
+ ondrag?: (payload: SheetEventMap["drag"]) => void;
119
+ onprogress?: (payload: SheetEventMap["progress"]) => void;
118
120
  onchange?: (state: EngineState & { activeId: TId }) => void;
119
121
  };
120
122
 
package/dist/svelte.d.ts CHANGED
@@ -115,6 +115,8 @@ export type BottomSheetProps<TId extends string = string> = {
115
115
  onclosed?: () => void;
116
116
  ondragstart?: () => void;
117
117
  ondragend?: () => void;
118
+ ondrag?: (payload: SheetEventMap["drag"]) => void;
119
+ onprogress?: (payload: SheetEventMap["progress"]) => void;
118
120
  onchange?: (state: EngineState & { activeId: TId }) => void;
119
121
  };
120
122