@surdeddd/bottom-sheet 0.9.0 → 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/solid.js CHANGED
@@ -184,11 +184,18 @@ var resolveSnap = (point, mode, measureFit) => {
184
184
  return Math.max(0, el.getBoundingClientRect().width);
185
185
  };
186
186
 
187
+ // src/core/primitives/devWarn.ts
188
+ function devWarn(...args) {
189
+ if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
190
+ console.warn(...args);
191
+ }
192
+ }
193
+
187
194
  // src/core/primitives/snap-points.ts
188
195
  var resolveSnapList = (points, mode, measureFit) => points.map((p) => {
189
196
  const raw = resolveSnap(p.size, mode, measureFit);
190
197
  if (!Number.isFinite(raw) || raw < 0) {
191
- console.warn(
198
+ devWarn(
192
199
  `[BottomSheet] snap "${p.id}" resolved to invalid size (${String(p.size)} \u2192 ${raw}); clamped to 0.`
193
200
  );
194
201
  return { id: p.id, size: 0 };
@@ -200,7 +207,7 @@ var auditVhUsage = (points) => {
200
207
  for (const p of points) {
201
208
  if (typeof p.size !== "string") continue;
202
209
  if (!VH_NOT_DVH.test(p.size)) continue;
203
- console.warn(
210
+ devWarn(
204
211
  `[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`
205
212
  );
206
213
  }
@@ -254,6 +261,26 @@ var findDragSettleTarget = (input) => {
254
261
  );
255
262
  };
256
263
 
264
+ // src/core/primitives/cancelable-emit.ts
265
+ function emitCancelable(emit, base, warnLabel) {
266
+ let cancelled = false;
267
+ let frozen = false;
268
+ emit({
269
+ ...base,
270
+ cancel: () => {
271
+ if (frozen) {
272
+ devWarn(
273
+ `[BottomSheet] ${warnLabel}.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener.`
274
+ );
275
+ return;
276
+ }
277
+ cancelled = true;
278
+ }
279
+ });
280
+ frozen = true;
281
+ return cancelled;
282
+ }
283
+
257
284
  // src/core/primitives/snap-resolver.ts
258
285
  var SnapResolver = class {
259
286
  constructor(raw, allowed, mode, measureFit, onMaxAxisSizeChange) {
@@ -398,7 +425,9 @@ function notifyLinkedSheets(sheets, self) {
398
425
  try {
399
426
  if (linked.state.size === 0) continue;
400
427
  const ids = linked.getAllowedIds();
401
- const target = ids.find((id) => id !== "closed");
428
+ const resolved = linked.getResolvedSnaps();
429
+ const sizeOf = (id) => resolved.find((s) => s.id === id)?.size ?? 0;
430
+ const target = ids.find((id) => sizeOf(id) > 0);
402
431
  if (target && target !== linked.state.activeId) {
403
432
  void linked.snapTo(target);
404
433
  }
@@ -615,11 +644,15 @@ function installVisualViewport(deps) {
615
644
  if (clamp < deps.getMaxAxisSize()) {
616
645
  deps.setMaxAxisSize(clamp);
617
646
  }
647
+ const wasAnimating = deps.isAnimating?.() ?? false;
648
+ deps.cancelInFlight();
649
+ deps.newCycle();
618
650
  const max = deps.getMaxAxisSize();
619
651
  deps.setSize(Math.min(deps.getSize(), max));
620
652
  const current = deps.resolveActiveSnap();
621
653
  if (current && !deps.isDragging()) {
622
654
  deps.applySize(Math.min(current.size, max));
655
+ if (wasAnimating) deps.resyncAfterCancel?.();
623
656
  } else {
624
657
  deps.applySize(deps.getSize());
625
658
  }
@@ -760,6 +793,54 @@ function installFitObserver(deps) {
760
793
  };
761
794
  }
762
795
 
796
+ // src/core/features/max-height-controller.ts
797
+ function createMaxHeightController(deps) {
798
+ let maxHeightCap;
799
+ let maxHeightRaw;
800
+ const resolveCap = () => {
801
+ const raw = maxHeightRaw;
802
+ if (raw === void 0) {
803
+ maxHeightCap = void 0;
804
+ return;
805
+ }
806
+ if (typeof raw === "number") {
807
+ maxHeightCap = raw;
808
+ return;
809
+ }
810
+ if (typeof window === "undefined") return;
811
+ const measured = resolveSnap(raw, deps.mode);
812
+ maxHeightCap = measured > 0 ? measured : void 0;
813
+ };
814
+ const clampTo = () => {
815
+ if (maxHeightCap === void 0) return;
816
+ if (deps.getMaxAxisSize() > maxHeightCap) {
817
+ deps.setMaxAxisSize(maxHeightCap);
818
+ }
819
+ };
820
+ return {
821
+ setRadius(r) {
822
+ deps.element.style.setProperty(
823
+ "--bs-radius",
824
+ typeof r === "number" ? `${r}px` : r
825
+ );
826
+ },
827
+ setMaxHeight(h) {
828
+ const value = typeof h === "number" ? `${h}px` : h;
829
+ const axis = layoutAxis(deps.mode);
830
+ deps.element.style.setProperty(
831
+ axis === "height" ? "max-height" : "max-width",
832
+ value
833
+ );
834
+ maxHeightRaw = h;
835
+ resolveCap();
836
+ deps.recompute();
837
+ },
838
+ resolveCap,
839
+ clampTo,
840
+ getCap: () => maxHeightCap
841
+ };
842
+ }
843
+
763
844
  // src/core/features/fit-measurement.ts
764
845
  var measureSheetNatural = (element, content, vertical) => {
765
846
  if (!content) {
@@ -891,13 +972,6 @@ var WriteSentinel = class {
891
972
  }
892
973
  };
893
974
 
894
- // src/core/primitives/devWarn.ts
895
- function devWarn(...args) {
896
- if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
897
- console.warn(...args);
898
- }
899
- }
900
-
901
975
  // src/core/primitives/overlay-position.ts
902
976
  function resolveSheetAnchoredStyle(mode, position, inset) {
903
977
  const sizeOffset = `calc(var(--bs-size, 0px) + ${inset})`;
@@ -2543,8 +2617,7 @@ var BottomSheetEngine = class {
2543
2617
  __publicField(this, "disableCloseFlag");
2544
2618
  __publicField(this, "disableDragFlag");
2545
2619
  __publicField(this, "closeOnRouteChange");
2546
- __publicField(this, "maxHeightCap");
2547
- __publicField(this, "maxHeightRaw");
2620
+ __publicField(this, "maxHeight");
2548
2621
  __publicField(this, "snapPointsRaw");
2549
2622
  __publicField(this, "snaps");
2550
2623
  __publicField(this, "activeId");
@@ -2655,11 +2728,20 @@ var BottomSheetEngine = class {
2655
2728
  auditVhUsage(this.snapPointsRaw);
2656
2729
  this.auditDuplicateSnapIds(this.snapPointsRaw);
2657
2730
  this.rootEl = this.element.closest(".bs-root");
2731
+ this.maxHeight = createMaxHeightController({
2732
+ element: this.element,
2733
+ mode: this.mode,
2734
+ getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
2735
+ setMaxAxisSize: (size) => {
2736
+ this.snaps.setMaxAxisSize(size);
2737
+ },
2738
+ recompute: () => this.recompute()
2739
+ });
2658
2740
  this.fitDeps = {
2659
2741
  element: this.element,
2660
2742
  scrollContainer: this.scrollContainer,
2661
2743
  mode: this.mode,
2662
- getMaxHeightCap: () => this.maxHeightCap
2744
+ getMaxHeightCap: () => this.maxHeight.getCap()
2663
2745
  };
2664
2746
  this.snaps = new SnapResolver(
2665
2747
  this.snapPointsRaw,
@@ -2770,7 +2852,7 @@ var BottomSheetEngine = class {
2770
2852
  }
2771
2853
  use(plugin) {
2772
2854
  if (this.destroyed) {
2773
- console.warn(
2855
+ devWarn(
2774
2856
  `[BottomSheet] use("${plugin.name}") called on destroyed engine \u2014 ignored.`
2775
2857
  );
2776
2858
  return this;
@@ -2812,6 +2894,9 @@ var BottomSheetEngine = class {
2812
2894
  getAllowedIds() {
2813
2895
  return this.snaps.getAllowedIds().slice();
2814
2896
  }
2897
+ getResolvedSnaps() {
2898
+ return this.snaps.getResolvedSnaps();
2899
+ }
2815
2900
  async snapTo(id, velocityOrOpts = 0, _skipBeforeSnap = false) {
2816
2901
  if (this.destroyed) return;
2817
2902
  const opts = typeof velocityOrOpts === "object" ? velocityOrOpts : { velocity: velocityOrOpts };
@@ -2820,11 +2905,11 @@ var BottomSheetEngine = class {
2820
2905
  if (externalSignal?.aborted) return;
2821
2906
  const target = this.snaps.findById(id);
2822
2907
  if (!target) {
2823
- console.warn(`[BottomSheet] unknown snap id: ${id}`);
2908
+ devWarn(`[BottomSheet] unknown snap id: ${id}`);
2824
2909
  return;
2825
2910
  }
2826
2911
  if (!this.snaps.getAllowedIds().includes(id)) {
2827
- console.warn(`[BottomSheet] snap "${id}" is not in allowed list`);
2912
+ devWarn(`[BottomSheet] snap "${id}" is not in allowed list`);
2828
2913
  return;
2829
2914
  }
2830
2915
  if (!_skipBeforeSnap && this.emitBeforeSnap(target, this.activeId)) {
@@ -2956,42 +3041,11 @@ var BottomSheetEngine = class {
2956
3041
  }
2957
3042
  setRadius(r) {
2958
3043
  if (this.destroyed) return;
2959
- this.element.style.setProperty(
2960
- "--bs-radius",
2961
- typeof r === "number" ? `${r}px` : r
2962
- );
3044
+ this.maxHeight.setRadius(r);
2963
3045
  }
2964
3046
  setMaxHeight(h) {
2965
3047
  if (this.destroyed) return;
2966
- const value = typeof h === "number" ? `${h}px` : h;
2967
- const axis = layoutAxis(this.mode);
2968
- this.element.style.setProperty(
2969
- axis === "height" ? "max-height" : "max-width",
2970
- value
2971
- );
2972
- this.maxHeightRaw = h;
2973
- this.resolveMaxHeightCap();
2974
- this.recompute();
2975
- }
2976
- resolveMaxHeightCap() {
2977
- const raw = this.maxHeightRaw;
2978
- if (raw === void 0) {
2979
- this.maxHeightCap = void 0;
2980
- return;
2981
- }
2982
- if (typeof raw === "number") {
2983
- this.maxHeightCap = raw;
2984
- return;
2985
- }
2986
- if (typeof window === "undefined") return;
2987
- const measured = resolveSnap(raw, this.mode);
2988
- this.maxHeightCap = measured > 0 ? measured : void 0;
2989
- }
2990
- clampToMaxHeight() {
2991
- if (this.maxHeightCap === void 0) return;
2992
- if (this.snaps.getMaxAxisSize() > this.maxHeightCap) {
2993
- this.snaps.setMaxAxisSize(this.maxHeightCap);
2994
- }
3048
+ this.maxHeight.setMaxHeight(h);
2995
3049
  }
2996
3050
  setAllowed(ids, snap) {
2997
3051
  if (this.destroyed) return;
@@ -3079,7 +3133,7 @@ var BottomSheetEngine = class {
3079
3133
  };
3080
3134
  const host = this.screenComponent?.parentElement;
3081
3135
  if (!host) {
3082
- console.warn(
3136
+ devWarn(
3083
3137
  "[BottomSheet] setScrimStages: no scrim element mounted \u2014 pass `scrim` to the engine first."
3084
3138
  );
3085
3139
  return () => {
@@ -3129,9 +3183,9 @@ var BottomSheetEngine = class {
3129
3183
  }
3130
3184
  recompute() {
3131
3185
  if (this.destroyed) return;
3132
- this.resolveMaxHeightCap();
3186
+ this.maxHeight.resolveCap();
3133
3187
  this.snaps.recompute();
3134
- this.clampToMaxHeight();
3188
+ this.maxHeight.clampTo();
3135
3189
  this.scrim.invalidateOpacityCache();
3136
3190
  if (this.gesture?.isDragging) return;
3137
3191
  const current = this.snaps.findById(this.activeId);
@@ -3181,42 +3235,18 @@ var BottomSheetEngine = class {
3181
3235
  return this.currentAbort.signal;
3182
3236
  }
3183
3237
  emitBeforeSnap(target, previousId) {
3184
- let cancelled = false;
3185
- let frozen = false;
3186
- this.emit("before-snap", {
3187
- id: target.id,
3188
- size: target.size,
3189
- previousId,
3190
- cancel: () => {
3191
- if (frozen) {
3192
- console.warn(
3193
- "[BottomSheet] before-snap.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener."
3194
- );
3195
- return;
3196
- }
3197
- cancelled = true;
3198
- }
3199
- });
3200
- frozen = true;
3201
- return cancelled;
3238
+ return emitCancelable(
3239
+ (payload) => this.emit("before-snap", payload),
3240
+ { id: target.id, size: target.size, previousId },
3241
+ "before-snap"
3242
+ );
3202
3243
  }
3203
3244
  emitBeforeClose(reason) {
3204
- let cancelled = false;
3205
- let frozen = false;
3206
- this.emit("before-close", {
3207
- reason,
3208
- cancel: () => {
3209
- if (frozen) {
3210
- console.warn(
3211
- "[BottomSheet] before-close.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener."
3212
- );
3213
- return;
3214
- }
3215
- cancelled = true;
3216
- }
3217
- });
3218
- frozen = true;
3219
- return cancelled;
3245
+ return emitCancelable(
3246
+ (payload) => this.emit("before-close", payload),
3247
+ { reason },
3248
+ "before-close"
3249
+ );
3220
3250
  }
3221
3251
  applyAutoAriaLabelledBy() {
3222
3252
  if (typeof document === "undefined") return;
@@ -3231,16 +3261,16 @@ var BottomSheetEngine = class {
3231
3261
  this.element.setAttribute("aria-labelledby", titled.id);
3232
3262
  }
3233
3263
  recomputeSnaps() {
3234
- this.resolveMaxHeightCap();
3264
+ this.maxHeight.resolveCap();
3235
3265
  this.snaps.setRaw(this.snapPointsRaw);
3236
- this.clampToMaxHeight();
3266
+ this.maxHeight.clampTo();
3237
3267
  this.scrim.invalidateOpacityCache();
3238
3268
  }
3239
3269
  auditDuplicateSnapIds(points) {
3240
3270
  const seen = /* @__PURE__ */ new Set();
3241
3271
  for (const p of points) {
3242
3272
  if (seen.has(p.id)) {
3243
- console.warn(
3273
+ devWarn(
3244
3274
  `[BottomSheet] duplicate snap id "${p.id}" \u2014 only the first occurrence is reachable.`
3245
3275
  );
3246
3276
  }
@@ -3407,7 +3437,15 @@ var BottomSheetEngine = class {
3407
3437
  setSize: (size) => {
3408
3438
  this.size = size;
3409
3439
  },
3410
- applySize: (size) => this.applySize(size)
3440
+ applySize: (size) => this.applySize(size),
3441
+ cancelInFlight: () => {
3442
+ this.animation.cancel();
3443
+ },
3444
+ newCycle: () => {
3445
+ this.newCycle();
3446
+ },
3447
+ isAnimating: () => this.animation.isAnimating,
3448
+ resyncAfterCancel: () => this.resyncAfterResize()
3411
3449
  }));
3412
3450
  }
3413
3451
  this.teardowns.add(installSliderKeyboard({
@@ -3673,8 +3711,23 @@ var BottomSheet = (props) => {
3673
3711
  props.onSnap?.(payload.id);
3674
3712
  });
3675
3713
  engine.on("before-snap", (payload) => props.onBeforeSnap?.(payload));
3676
- engine.on("dragstart", sync);
3677
- engine.on("dragend", sync);
3714
+ engine.on("before-close", (payload) => props.onBeforeClose?.(payload));
3715
+ engine.on("open", (payload) => props.onOpen?.(payload.id));
3716
+ engine.on("close", () => props.onClose?.());
3717
+ engine.on("opened", (payload) => props.onOpened?.(payload.id));
3718
+ engine.on("closed", () => props.onClosed?.());
3719
+ engine.on("dragstart", (payload) => {
3720
+ sync();
3721
+ props.onDragStart?.(payload);
3722
+ });
3723
+ engine.on("dragend", (payload) => {
3724
+ sync();
3725
+ props.onDragEnd?.(payload);
3726
+ });
3727
+ if (props.onDrag) engine.on("drag", (payload) => props.onDrag?.(payload));
3728
+ if (props.onProgress) {
3729
+ engine.on("progress", (payload) => props.onProgress?.(payload));
3730
+ }
3678
3731
  if (props.backdrop !== false && props.closeOnBackdrop !== false && backdropEl) {
3679
3732
  const onBackdropClick = () => {
3680
3733
  if (engine?.canDismiss()) void engine.close("backdrop");