@swmansion/react-native-bottom-sheet 0.15.0-next.6 → 0.15.0-next.8

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.
@@ -825,12 +825,42 @@ class BottomSheetHostView(context: Context) : ReactViewGroup(context) {
825
825
  }
826
826
  }
827
827
 
828
- if (view.canScrollVertically(1) || view.canScrollVertically(-1)) {
828
+ if (isVerticallyScrollable(view)) {
829
829
  return view
830
830
  }
831
831
  return null
832
832
  }
833
833
 
834
+ private fun isVerticallyScrollable(view: View): Boolean {
835
+ if (!view.canScrollVertically(1) && !view.canScrollVertically(-1)) {
836
+ return false
837
+ }
838
+ return getReactScrollEnabled(view) != false
839
+ }
840
+
841
+ private fun getReactScrollEnabled(view: View): Boolean? {
842
+ val method =
843
+ try {
844
+ view.javaClass.getMethod("getScrollEnabled")
845
+ } catch (_: NoSuchMethodException) {
846
+ return null
847
+ }
848
+
849
+ if (
850
+ method.returnType != Boolean::class.javaPrimitiveType &&
851
+ method.returnType != Boolean::class.javaObjectType
852
+ ) {
853
+ return null
854
+ }
855
+
856
+ return try {
857
+ method.isAccessible = true
858
+ method.invoke(view) as? Boolean
859
+ } catch (_: Exception) {
860
+ null
861
+ }
862
+ }
863
+
834
864
  private fun isViewInverted(view: View): Boolean {
835
865
  val values = FloatArray(9)
836
866
  var current: View? = view
@@ -189,10 +189,18 @@ public final class BottomSheetHostingView: UIView {
189
189
  }
190
190
 
191
191
  private var presentedSheetFrame: CGRect {
192
- if activeSpring != nil, let presentation = sheetContainer.layer.presentation() {
193
- return presentation.frame
194
- }
195
- return sheetContainer.frame
192
+ guard activeSpring != nil else { return sheetContainer.frame }
193
+ // Mid-settle, derive the on-screen frame from the spring instead of the
194
+ // presentation layer (which lags one commit behind right after a snap
195
+ // starts). The container's transform is translation-only.
196
+ let size = sheetContainer.bounds.size
197
+ let center = sheetContainer.center
198
+ return CGRect(
199
+ x: center.x - size.width / 2,
200
+ y: center.y - size.height / 2 + currentTranslationY,
201
+ width: size.width,
202
+ height: size.height
203
+ )
196
204
  }
197
205
 
198
206
  override public func point(inside point: CGPoint, with _: UIEvent?) -> Bool {
@@ -518,7 +526,7 @@ public final class BottomSheetHostingView: UIView {
518
526
 
519
527
  @discardableResult
520
528
  private func cancelActiveSpring() -> CGFloat {
521
- let visualTy = sheetContainer.layer.presentation()?.affineTransform().ty ?? sheetContainer.transform.ty
529
+ let visualTy = currentTranslationY
522
530
  activeSpring = nil
523
531
  activeSpringEmitsSettle = false
524
532
  stopDisplayLink()
@@ -612,6 +620,7 @@ public final class BottomSheetHostingView: UIView {
612
620
  }
613
621
 
614
622
  private func isVerticallyScrollable(_ scrollView: UIScrollView) -> Bool {
623
+ guard scrollView.isScrollEnabled else { return false }
615
624
  let verticalInset = scrollView.adjustedContentInset.top + scrollView.adjustedContentInset.bottom
616
625
  let visibleHeight = max(0, scrollView.bounds.height - verticalInset)
617
626
  return scrollView.alwaysBounceVertical || scrollView.contentSize.height > visibleHeight
@@ -914,11 +923,15 @@ extension BottomSheetHostingView: UIGestureRecognizerDelegate {
914
923
  private extension BottomSheetHostingView {
915
924
  var currentTranslationY: CGFloat {
916
925
  // During a settle the modal is driven by a keyframe animation on the render
917
- // server, so the live on-screen value lives on the presentation layer (the
918
- // model `transform` already holds the final target). A drag assigns
919
- // `transform` directly, so outside a settle the model value is correct.
920
- if activeSpring != nil, let presentation = sheetContainer.layer.presentation() {
921
- return presentation.affineTransform().ty
926
+ // server (the model `transform` already holds the final target), so read the
927
+ // analytical spring the keyframes were sampled from. The presentation layer
928
+ // is deliberately not used: right after a snap starts it still holds the
929
+ // previously committed transform, and that stale value (e.g. the identity
930
+ // transform from before the first layout) reads as a wide-open sheet — which
931
+ // briefly flashed the scrim on mount. A drag assigns `transform` directly,
932
+ // so outside a settle the model value is correct.
933
+ if let spring = activeSpring {
934
+ return spring.value(at: CACurrentMediaTime())
922
935
  }
923
936
  return sheetContainer.transform.ty
924
937
  }
@@ -940,6 +953,14 @@ private extension BottomSheetHostingView {
940
953
  return
941
954
  }
942
955
 
956
+ // Until the first layout places the sheet, the identity transform reads as
957
+ // a fully-open sheet; keep the scrim hidden until the sheet is positioned.
958
+ if !hasLaidOut {
959
+ scrimView.alpha = 0
960
+ scrimView.isHidden = true
961
+ return
962
+ }
963
+
943
964
  // If we're settled on the closed detent, dynamic detent/content updates can
944
965
  // momentarily report a stale non-zero position. Keep scrim fully hidden.
945
966
  if
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swmansion/react-native-bottom-sheet",
3
- "version": "0.15.0-next.6",
3
+ "version": "0.15.0-next.8",
4
4
  "description": "Provides bottom-sheet components for React Native.",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",