@lodev09/react-native-true-sheet 3.5.1-beta.3 → 3.5.1-beta.5

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 (33) hide show
  1. package/android/src/main/java/com/lodev09/truesheet/TrueSheetModule.kt +2 -2
  2. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +31 -28
  3. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +358 -271
  4. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +0 -5
  5. package/android/src/main/java/com/lodev09/truesheet/core/RNScreensFragmentObserver.kt +7 -8
  6. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +158 -0
  7. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +55 -0
  8. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +18 -12
  9. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDimView.kt +91 -2
  10. package/android/src/main/java/com/lodev09/truesheet/core/{TrueSheetDialogObserver.kt → TrueSheetStackManager.kt} +7 -5
  11. package/ios/TrueSheetViewController.h +2 -3
  12. package/ios/TrueSheetViewController.mm +11 -4
  13. package/ios/core/TrueSheetDetentCalculator.h +2 -3
  14. package/ios/core/TrueSheetDetentCalculator.mm +7 -9
  15. package/lib/module/TrueSheet.js +0 -2
  16. package/lib/module/TrueSheet.js.map +1 -1
  17. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +0 -1
  18. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  19. package/lib/typescript/src/TrueSheet.types.d.ts +0 -8
  20. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  21. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +0 -1
  22. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  23. package/lib/typescript/src/navigation/types.d.ts +1 -1
  24. package/lib/typescript/src/navigation/types.d.ts.map +1 -1
  25. package/package.json +1 -1
  26. package/src/TrueSheet.tsx +0 -2
  27. package/src/TrueSheet.types.ts +0 -9
  28. package/src/fabric/TrueSheetViewNativeComponent.ts +0 -1
  29. package/src/navigation/types.ts +0 -1
  30. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetAnimator.kt +0 -144
  31. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDialogFragment.kt +0 -317
  32. package/android/src/main/res/anim/fast_fade_out.xml +0 -6
  33. package/android/src/main/res/values/styles.xml +0 -21
@@ -183,11 +183,6 @@ class TrueSheetViewManager :
183
183
  // iOS-specific prop - no-op on Android
184
184
  }
185
185
 
186
- @ReactProp(name = "edgeToEdgeFullScreen", defaultBoolean = false)
187
- override fun setEdgeToEdgeFullScreen(view: TrueSheetView, edgeToEdgeFullScreen: Boolean) {
188
- view.setEdgeToEdgeFullScreen(edgeToEdgeFullScreen)
189
- }
190
-
191
186
  @ReactProp(name = "insetAdjustment")
192
187
  override fun setInsetAdjustment(view: TrueSheetView, insetAdjustment: String?) {
193
188
  view.setInsetAdjustment(insetAdjustment ?: "automatic")
@@ -66,8 +66,11 @@ class RNScreensFragmentObserver(
66
66
  // Ignore if app is going to background (fragments stop with activity)
67
67
  if (!isActivityInForeground) return
68
68
 
69
- if (activeModalFragments.contains(f)) {
70
- if (activeModalFragments.size == 1) {
69
+ // Only trigger when fragment is being removed (not just stopped for navigation)
70
+ if (activeModalFragments.contains(f) && f.isRemoving) {
71
+ activeModalFragments.remove(f)
72
+
73
+ if (activeModalFragments.isEmpty()) {
71
74
  onModalWillDismiss()
72
75
  }
73
76
  }
@@ -76,12 +79,8 @@ class RNScreensFragmentObserver(
76
79
  override fun onFragmentDestroyed(fm: FragmentManager, f: Fragment) {
77
80
  super.onFragmentDestroyed(fm, f)
78
81
 
79
- if (activeModalFragments.contains(f)) {
80
- activeModalFragments.remove(f)
81
-
82
- if (activeModalFragments.isEmpty()) {
83
- onModalDidDismiss()
84
- }
82
+ if (activeModalFragments.isEmpty()) {
83
+ onModalDidDismiss()
85
84
  }
86
85
  }
87
86
  }
@@ -0,0 +1,158 @@
1
+ package com.lodev09.truesheet.core
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.graphics.Color
5
+ import android.graphics.Outline
6
+ import android.graphics.drawable.ShapeDrawable
7
+ import android.graphics.drawable.shapes.RoundRectShape
8
+ import android.util.TypedValue
9
+ import android.view.Gravity
10
+ import android.view.View
11
+ import android.view.ViewOutlineProvider
12
+ import android.widget.FrameLayout
13
+ import androidx.coordinatorlayout.widget.CoordinatorLayout
14
+ import com.facebook.react.uimanager.PixelUtil.dpToPx
15
+ import com.facebook.react.uimanager.ThemedReactContext
16
+ import com.google.android.material.bottomsheet.BottomSheetBehavior
17
+
18
+ interface TrueSheetBottomSheetViewDelegate {
19
+ val isTopmostSheet: Boolean
20
+ val sheetCornerRadius: Float
21
+ val sheetBackgroundColor: Int?
22
+ val grabber: Boolean
23
+ val grabberOptions: GrabberOptions?
24
+ }
25
+
26
+ /**
27
+ * The bottom sheet view that holds the content.
28
+ * This view has BottomSheetBehavior attached via CoordinatorLayout.LayoutParams.
29
+ *
30
+ * Touch dispatching to React Native is handled by TrueSheetViewController,
31
+ * which is the actual RootView containing the React content.
32
+ */
33
+ @SuppressLint("ViewConstructor")
34
+ class TrueSheetBottomSheetView(private val reactContext: ThemedReactContext) : FrameLayout(reactContext) {
35
+
36
+ companion object {
37
+ private const val GRABBER_TAG = "TrueSheetGrabber"
38
+ private const val DEFAULT_CORNER_RADIUS = 16f // dp
39
+ private const val DEFAULT_MAX_WIDTH = 640 // dp
40
+ }
41
+
42
+ // =============================================================================
43
+ // MARK: - Properties
44
+ // =============================================================================
45
+
46
+ var delegate: TrueSheetBottomSheetViewDelegate? = null
47
+
48
+ // Behavior reference (set after adding to CoordinatorLayout)
49
+ val behavior: BottomSheetBehavior<TrueSheetBottomSheetView>?
50
+ get() = (layoutParams as? CoordinatorLayout.LayoutParams)
51
+ ?.behavior as? BottomSheetBehavior<TrueSheetBottomSheetView>
52
+
53
+ // =============================================================================
54
+ // MARK: - Initialization
55
+ // =============================================================================
56
+
57
+ init {
58
+ // Allow content to extend beyond bounds (for footer positioning)
59
+ clipChildren = false
60
+ clipToPadding = false
61
+ }
62
+
63
+ override fun setTranslationY(translationY: Float) {
64
+ // Skip resetting translation to 0 for parent sheets (non-topmost)
65
+ // This prevents keyboard inset animations from resetting parent sheet translation
66
+ if (delegate?.isTopmostSheet == false && translationY == 0f && this.translationY != 0f) {
67
+ return
68
+ }
69
+ super.setTranslationY(translationY)
70
+ }
71
+
72
+ // =============================================================================
73
+ // MARK: - Layout
74
+ // =============================================================================
75
+
76
+ /**
77
+ * Creates layout params with BottomSheetBehavior attached.
78
+ */
79
+ fun createLayoutParams(): CoordinatorLayout.LayoutParams {
80
+ val behavior = BottomSheetBehavior<TrueSheetBottomSheetView>().apply {
81
+ isHideable = true
82
+ maxWidth = DEFAULT_MAX_WIDTH.dpToPx().toInt()
83
+ }
84
+
85
+ return CoordinatorLayout.LayoutParams(
86
+ CoordinatorLayout.LayoutParams.MATCH_PARENT,
87
+ CoordinatorLayout.LayoutParams.MATCH_PARENT
88
+ ).apply {
89
+ this.behavior = behavior
90
+ this.gravity = Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM
91
+ }
92
+ }
93
+
94
+ // =============================================================================
95
+ // MARK: - Background & Styling
96
+ // =============================================================================
97
+
98
+ fun setupBackground() {
99
+ val radius = delegate?.sheetCornerRadius ?: DEFAULT_CORNER_RADIUS.dpToPx()
100
+ val effectiveRadius = if (radius < 0) DEFAULT_CORNER_RADIUS.dpToPx() else radius
101
+
102
+ val outerRadii = floatArrayOf(
103
+ effectiveRadius,
104
+ effectiveRadius, // top-left
105
+ effectiveRadius,
106
+ effectiveRadius, // top-right
107
+ 0f,
108
+ 0f, // bottom-right
109
+ 0f,
110
+ 0f // bottom-left
111
+ )
112
+
113
+ val color = delegate?.sheetBackgroundColor ?: getDefaultBackgroundColor()
114
+
115
+ background = ShapeDrawable(RoundRectShape(outerRadii, null, null)).apply {
116
+ paint.color = color
117
+ }
118
+
119
+ outlineProvider = object : ViewOutlineProvider() {
120
+ override fun getOutline(view: View, outline: Outline) {
121
+ outline.setRoundRect(0, 0, view.width, view.height, effectiveRadius)
122
+ }
123
+ }
124
+ clipToOutline = true
125
+ }
126
+
127
+ private fun getDefaultBackgroundColor(): Int {
128
+ val typedValue = TypedValue()
129
+ return if (reactContext.theme.resolveAttribute(
130
+ com.google.android.material.R.attr.colorSurfaceContainerLow,
131
+ typedValue,
132
+ true
133
+ )
134
+ ) {
135
+ typedValue.data
136
+ } else {
137
+ Color.WHITE
138
+ }
139
+ }
140
+
141
+ // =============================================================================
142
+ // MARK: - Grabber
143
+ // =============================================================================
144
+
145
+ fun setupGrabber() {
146
+ findViewWithTag<View>(GRABBER_TAG)?.let { removeView(it) }
147
+
148
+ val isEnabled = delegate?.grabber ?: true
149
+ val isDraggable = behavior?.isDraggable ?: true
150
+ if (!isEnabled || !isDraggable) return
151
+
152
+ val grabberView = TrueSheetGrabberView(reactContext, delegate?.grabberOptions).apply {
153
+ tag = GRABBER_TAG
154
+ }
155
+
156
+ addView(grabberView, 0)
157
+ }
158
+ }
@@ -0,0 +1,55 @@
1
+ package com.lodev09.truesheet.core
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.content.Context
5
+ import android.view.View
6
+ import androidx.coordinatorlayout.widget.CoordinatorLayout
7
+ import com.facebook.react.uimanager.PointerEvents
8
+ import com.facebook.react.uimanager.ReactPointerEventsView
9
+
10
+ interface TrueSheetCoordinatorLayoutDelegate {
11
+ fun coordinatorLayoutDidLayout(changed: Boolean)
12
+ }
13
+
14
+ /**
15
+ * Custom CoordinatorLayout that hosts the bottom sheet and dim view.
16
+ * Implements ReactPointerEventsView to allow touch events to pass through
17
+ * to underlying React Native views when appropriate.
18
+ */
19
+ @SuppressLint("ViewConstructor")
20
+ class TrueSheetCoordinatorLayout(context: Context) :
21
+ CoordinatorLayout(context),
22
+ ReactPointerEventsView {
23
+
24
+ var delegate: TrueSheetCoordinatorLayoutDelegate? = null
25
+
26
+ init {
27
+ // Fill the entire screen
28
+ layoutParams = LayoutParams(
29
+ LayoutParams.MATCH_PARENT,
30
+ LayoutParams.MATCH_PARENT
31
+ )
32
+
33
+ // Ensure we don't clip the sheet during animations
34
+ clipChildren = false
35
+ clipToPadding = false
36
+ }
37
+
38
+ override fun onLayout(
39
+ changed: Boolean,
40
+ l: Int,
41
+ t: Int,
42
+ r: Int,
43
+ b: Int
44
+ ) {
45
+ super.onLayout(changed, l, t, r, b)
46
+ delegate?.coordinatorLayoutDidLayout(changed)
47
+ }
48
+
49
+ /**
50
+ * Allow pointer events to pass through to underlying views.
51
+ * The DimView and BottomSheetView handle their own touch interception.
52
+ */
53
+ override val pointerEvents: PointerEvents
54
+ get() = PointerEvents.BOX_NONE
55
+ }
@@ -1,12 +1,14 @@
1
1
  package com.lodev09.truesheet.core
2
2
 
3
3
  import com.facebook.react.uimanager.PixelUtil.pxToDp
4
+ import com.facebook.react.uimanager.ThemedReactContext
5
+ import com.facebook.react.util.RNLog
4
6
  import com.google.android.material.bottomsheet.BottomSheetBehavior
5
7
 
6
8
  /**
7
9
  * Provides screen dimensions and content measurements for detent calculations.
8
10
  */
9
- interface TrueSheetDetentMeasurements {
11
+ interface TrueSheetDetentCalculatorDelegate {
10
12
  val screenHeight: Int
11
13
  val realScreenHeight: Int
12
14
  val detents: MutableList<Double>
@@ -19,18 +21,19 @@ interface TrueSheetDetentMeasurements {
19
21
 
20
22
  /**
21
23
  * Handles all detent-related calculations for the bottom sheet.
22
- * Takes a measurements provider to always read current values.
23
24
  */
24
- class TrueSheetDetentCalculator(private val measurements: TrueSheetDetentMeasurements) {
25
+ class TrueSheetDetentCalculator(private val reactContext: ThemedReactContext) {
25
26
 
26
- private val screenHeight: Int get() = measurements.screenHeight
27
- private val realScreenHeight: Int get() = measurements.realScreenHeight
28
- private val detents: List<Double> get() = measurements.detents
29
- private val contentHeight: Int get() = measurements.contentHeight
30
- private val headerHeight: Int get() = measurements.headerHeight
31
- private val contentBottomInset: Int get() = measurements.contentBottomInset
32
- private val maxSheetHeight: Int? get() = measurements.maxSheetHeight
33
- private val keyboardInset: Int get() = measurements.keyboardInset
27
+ var delegate: TrueSheetDetentCalculatorDelegate? = null
28
+
29
+ private val screenHeight: Int get() = delegate?.screenHeight ?: 0
30
+ private val realScreenHeight: Int get() = delegate?.realScreenHeight ?: 0
31
+ private val detents: List<Double> get() = delegate?.detents ?: emptyList()
32
+ private val contentHeight: Int get() = delegate?.contentHeight ?: 0
33
+ private val headerHeight: Int get() = delegate?.headerHeight ?: 0
34
+ private val contentBottomInset: Int get() = delegate?.contentBottomInset ?: 0
35
+ private val maxSheetHeight: Int? get() = delegate?.maxSheetHeight
36
+ private val keyboardInset: Int get() = delegate?.keyboardInset ?: 0
34
37
 
35
38
  /**
36
39
  * Calculate the height in pixels for a given detent value.
@@ -55,7 +58,10 @@ class TrueSheetDetentCalculator(private val measurements: TrueSheetDetentMeasure
55
58
  * Get the expected sheet top position for a detent index.
56
59
  */
57
60
  fun getSheetTopForDetentIndex(index: Int): Int {
58
- if (index < 0 || index >= detents.size) return realScreenHeight
61
+ if (index < 0 || index >= detents.size) {
62
+ RNLog.w(reactContext, "TrueSheet: Detent index ($index) is out of bounds (0..${detents.size - 1})")
63
+ return realScreenHeight
64
+ }
59
65
  return realScreenHeight - getDetentHeight(detents[index])
60
66
  }
61
67
 
@@ -3,21 +3,51 @@ package com.lodev09.truesheet.core
3
3
  import android.annotation.SuppressLint
4
4
  import android.graphics.Color
5
5
  import android.graphics.Outline
6
+ import android.view.MotionEvent
6
7
  import android.view.View
7
8
  import android.view.ViewGroup
8
9
  import android.view.ViewOutlineProvider
10
+ import com.facebook.react.uimanager.PointerEvents
11
+ import com.facebook.react.uimanager.ReactPointerEventsView
9
12
  import com.facebook.react.uimanager.ThemedReactContext
10
13
  import com.lodev09.truesheet.utils.ScreenUtils
11
14
 
12
- @SuppressLint("ViewConstructor")
13
- class TrueSheetDimView(private val reactContext: ThemedReactContext) : View(reactContext) {
15
+ /**
16
+ * Delegate for handling dim view interactions.
17
+ */
18
+ interface TrueSheetDimViewDelegate {
19
+ fun dimViewDidTap()
20
+ }
21
+
22
+ /**
23
+ * Dim view that sits behind the bottom sheet in the CoordinatorLayout.
24
+ *
25
+ * Key behaviors:
26
+ * - When alpha > 0 (dimmed): blocks touches and calls delegate on tap
27
+ * - When alpha == 0 (not dimmed): passes touches through to views below
28
+ *
29
+ * This implements the "dimmedDetentIndex" equivalent functionality:
30
+ * the view only becomes interactive when the sheet is at or above the dimmed detent.
31
+ */
32
+ @SuppressLint("ViewConstructor", "ClickableViewAccessibility")
33
+ class TrueSheetDimView(private val reactContext: ThemedReactContext) :
34
+ View(reactContext),
35
+ ReactPointerEventsView {
14
36
 
15
37
  companion object {
16
38
  private const val MAX_ALPHA = 0.5f
17
39
  }
18
40
 
41
+ var delegate: TrueSheetDimViewDelegate? = null
42
+
19
43
  private var targetView: ViewGroup? = null
20
44
 
45
+ /**
46
+ * Whether this view should block gestures (when dimmed).
47
+ */
48
+ private val blockGestures: Boolean
49
+ get() = alpha > 0f
50
+
21
51
  init {
22
52
  layoutParams = ViewGroup.LayoutParams(
23
53
  ViewGroup.LayoutParams.MATCH_PARENT,
@@ -25,8 +55,22 @@ class TrueSheetDimView(private val reactContext: ThemedReactContext) : View(reac
25
55
  )
26
56
  setBackgroundColor(Color.BLACK)
27
57
  alpha = 0f
58
+
59
+ // Handle taps on the dim view
60
+ setOnClickListener {
61
+ delegate?.dimViewDidTap()
62
+ }
28
63
  }
29
64
 
65
+ // =============================================================================
66
+ // MARK: - Attachment
67
+ // =============================================================================
68
+
69
+ /**
70
+ * Attaches this dim view to a target view group.
71
+ * For CoordinatorLayout usage, pass null to use the default (activity's decor view).
72
+ * For stacked sheets, pass the parent sheet's bottom sheet view with corner radius.
73
+ */
30
74
  fun attach(view: ViewGroup? = null, cornerRadius: Float = 0f) {
31
75
  if (parent != null) return
32
76
  targetView = view ?: reactContext.currentActivity?.window?.decorView as? ViewGroup
@@ -38,16 +82,34 @@ class TrueSheetDimView(private val reactContext: ThemedReactContext) : View(reac
38
82
  }
39
83
  }
40
84
  clipToOutline = true
85
+ } else {
86
+ outlineProvider = null
87
+ clipToOutline = false
41
88
  }
42
89
 
43
90
  targetView?.addView(this)
44
91
  }
45
92
 
93
+ /**
94
+ * Attaches this dim view to a CoordinatorLayout at index 0 (behind the sheet).
95
+ */
96
+ fun attachToCoordinator(coordinator: TrueSheetCoordinatorLayout) {
97
+ if (parent != null) return
98
+ targetView = coordinator
99
+ outlineProvider = null
100
+ clipToOutline = false
101
+ coordinator.addView(this, 0)
102
+ }
103
+
46
104
  fun detach() {
47
105
  targetView?.removeView(this)
48
106
  targetView = null
49
107
  }
50
108
 
109
+ // =============================================================================
110
+ // MARK: - Alpha Calculation
111
+ // =============================================================================
112
+
51
113
  fun calculateAlpha(sheetTop: Int, dimmedDetentIndex: Int, getSheetTopForDetentIndex: (Int) -> Int): Float {
52
114
  val realHeight = ScreenUtils.getRealScreenHeight(reactContext)
53
115
  val dimmedDetentTop = getSheetTopForDetentIndex(dimmedDetentIndex)
@@ -68,4 +130,31 @@ class TrueSheetDimView(private val reactContext: ThemedReactContext) : View(reac
68
130
  fun interpolateAlpha(sheetTop: Int, dimmedDetentIndex: Int, getSheetTopForDetentIndex: (Int) -> Int) {
69
131
  alpha = calculateAlpha(sheetTop, dimmedDetentIndex, getSheetTopForDetentIndex)
70
132
  }
133
+
134
+ // =============================================================================
135
+ // MARK: - Touch Handling
136
+ // =============================================================================
137
+
138
+ override fun onTouchEvent(event: MotionEvent): Boolean {
139
+ if (blockGestures) {
140
+ // When dimmed, consume touch and trigger click on ACTION_UP
141
+ if (event.action == MotionEvent.ACTION_UP) {
142
+ performClick()
143
+ }
144
+ return true
145
+ }
146
+ // When not dimmed, let touches pass through
147
+ return false
148
+ }
149
+
150
+ // =============================================================================
151
+ // MARK: - ReactPointerEventsView
152
+ // =============================================================================
153
+
154
+ /**
155
+ * When dimmed (alpha > 0), intercept touches (AUTO).
156
+ * When not dimmed (alpha == 0), pass through (NONE).
157
+ */
158
+ override val pointerEvents: PointerEvents
159
+ get() = if (blockGestures) PointerEvents.AUTO else PointerEvents.NONE
71
160
  }
@@ -6,7 +6,7 @@ import com.lodev09.truesheet.TrueSheetView
6
6
  * Manages TrueSheet stacking behavior.
7
7
  * Tracks presented sheets and handles visibility when sheets stack on top of each other.
8
8
  */
9
- object TrueSheetDialogObserver {
9
+ object TrueSheetStackManager {
10
10
 
11
11
  private val presentedSheetStack = mutableListOf<TrueSheetView>()
12
12
 
@@ -18,9 +18,9 @@ object TrueSheetDialogObserver {
18
18
  fun onSheetWillPresent(sheetView: TrueSheetView, detentIndex: Int): TrueSheetView? {
19
19
  synchronized(presentedSheetStack) {
20
20
  val parentSheet = presentedSheetStack.lastOrNull()
21
- ?.takeIf { it.viewController.isPresented && it.viewController.isDialogVisible }
21
+ ?.takeIf { it.viewController.isPresented && it.viewController.isSheetVisible }
22
22
 
23
- val childSheetTop = sheetView.viewController.getExpectedSheetTop(detentIndex)
23
+ val childSheetTop = sheetView.viewController.detentCalculator.getSheetTopForDetentIndex(detentIndex)
24
24
  parentSheet?.updateTranslationForChild(childSheetTop)
25
25
 
26
26
  if (!presentedSheetStack.contains(sheetView)) {
@@ -59,8 +59,10 @@ object TrueSheetDialogObserver {
59
59
 
60
60
  // Post to ensure layout is complete before reading position
61
61
  sheetView.viewController.post {
62
- val childMinSheetTop = sheetView.viewController.getExpectedSheetTop(0)
63
- val childCurrentSheetTop = sheetView.viewController.getExpectedSheetTop(sheetView.viewController.currentDetentIndex)
62
+ val childMinSheetTop = sheetView.viewController.detentCalculator.getSheetTopForDetentIndex(0)
63
+ val childCurrentSheetTop = sheetView.viewController.detentCalculator.getSheetTopForDetentIndex(
64
+ sheetView.viewController.currentDetentIndex
65
+ )
64
66
  // Cap to minimum detent position
65
67
  val childSheetTop = maxOf(childMinSheetTop, childCurrentSheetTop)
66
68
  parentSheet.updateTranslationForChild(childSheetTop)
@@ -7,6 +7,7 @@
7
7
  //
8
8
 
9
9
  #import <UIKit/UIKit.h>
10
+ #import "core/TrueSheetDetentCalculator.h"
10
11
 
11
12
  #if __has_include(<RNScreens/RNSDismissibleModalProtocol.h>)
12
13
  #import <RNScreens/RNSDismissibleModalProtocol.h>
@@ -40,10 +41,8 @@ NS_ASSUME_NONNULL_BEGIN
40
41
 
41
42
  @end
42
43
 
43
- @protocol TrueSheetDetentMeasurements;
44
-
45
44
  @interface TrueSheetViewController : UIViewController <UISheetPresentationControllerDelegate,
46
- TrueSheetDetentMeasurements
45
+ TrueSheetDetentCalculatorDelegate
47
46
  #if RNS_DISMISSIBLE_MODAL_PROTOCOL_AVAILABLE
48
47
  ,
49
48
  RNSDismissibleModalProtocol
@@ -65,7 +65,8 @@
65
65
 
66
66
  _blurInteraction = YES;
67
67
  _insetAdjustment = @"automatic";
68
- _detentCalculator = [[TrueSheetDetentCalculator alloc] initWithMeasurements:self];
68
+ _detentCalculator = [[TrueSheetDetentCalculator alloc] init];
69
+ _detentCalculator.delegate = self;
69
70
  }
70
71
  return self;
71
72
  }
@@ -503,8 +504,10 @@
503
504
 
504
505
  - (void)setupSheetDetents {
505
506
  UISheetPresentationController *sheet = self.sheetPresentationController;
506
- if (!sheet)
507
+ if (!sheet) {
508
+ RCTLogError(@"TrueSheet: sheetPresentationController is nil in setupSheetDetents");
507
509
  return;
510
+ }
508
511
 
509
512
  NSMutableArray<UISheetPresentationControllerDetent *> *detents = [NSMutableArray array];
510
513
  [_detentCalculator clearResolvedPositions];
@@ -591,8 +594,10 @@
591
594
 
592
595
  - (UISheetPresentationControllerDetentIdentifier)detentIdentifierForIndex:(NSInteger)index {
593
596
  UISheetPresentationController *sheet = self.sheetPresentationController;
594
- if (!sheet)
597
+ if (!sheet) {
598
+ RCTLogError(@"TrueSheet: sheetPresentationController is nil in detentIdentifierForIndex");
595
599
  return UISheetPresentationControllerDetentIdentifierMedium;
600
+ }
596
601
 
597
602
  UISheetPresentationControllerDetentIdentifier identifier = UISheetPresentationControllerDetentIdentifierMedium;
598
603
  if (index >= 0 && index < (NSInteger)sheet.detents.count) {
@@ -611,8 +616,10 @@
611
616
 
612
617
  - (void)applyActiveDetent {
613
618
  UISheetPresentationController *sheet = self.sheetPresentationController;
614
- if (!sheet)
619
+ if (!sheet) {
620
+ RCTLogError(@"TrueSheet: sheetPresentationController is nil in applyActiveDetent");
615
621
  return;
622
+ }
616
623
 
617
624
  NSInteger detentCount = _detents.count;
618
625
  if (detentCount == 0)
@@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
14
14
  Protocol that provides dynamic measurements for detent calculations.
15
15
  Implemented by TrueSheetViewController to supply real-time values.
16
16
  */
17
- @protocol TrueSheetDetentMeasurements <NSObject>
17
+ @protocol TrueSheetDetentCalculatorDelegate <NSObject>
18
18
 
19
19
  @property (nonatomic, readonly) CGFloat screenHeight;
20
20
  @property (nonatomic, readonly) CGFloat currentPosition;
@@ -26,11 +26,10 @@ NS_ASSUME_NONNULL_BEGIN
26
26
 
27
27
  /**
28
28
  Encapsulates all detent-related calculations for the sheet.
29
- Uses the TrueSheetDetentMeasurements protocol to read dynamic values.
30
29
  */
31
30
  @interface TrueSheetDetentCalculator : NSObject
32
31
 
33
- - (instancetype)initWithMeasurements:(id<TrueSheetDetentMeasurements>)measurements;
32
+ @property (nonatomic, weak, nullable) id<TrueSheetDetentCalculatorDelegate> delegate;
34
33
 
35
34
  /**
36
35
  Returns the detent value (0-1 fraction) for a given index.
@@ -9,13 +9,11 @@
9
9
  #import "TrueSheetDetentCalculator.h"
10
10
 
11
11
  @implementation TrueSheetDetentCalculator {
12
- __weak id<TrueSheetDetentMeasurements> _measurements;
13
12
  NSMutableArray<NSNumber *> *_resolvedDetentPositions;
14
13
  }
15
14
 
16
- - (instancetype)initWithMeasurements:(id<TrueSheetDetentMeasurements>)measurements {
15
+ - (instancetype)init {
17
16
  if (self = [super init]) {
18
- _measurements = measurements;
19
17
  _resolvedDetentPositions = [NSMutableArray array];
20
18
  }
21
19
  return self;
@@ -24,12 +22,12 @@
24
22
  #pragma mark - Public Methods
25
23
 
26
24
  - (CGFloat)detentValueForIndex:(NSInteger)index {
27
- NSArray<NSNumber *> *detents = _measurements.detents;
25
+ NSArray<NSNumber *> *detents = self.delegate.detents;
28
26
  if (index >= 0 && index < (NSInteger)detents.count) {
29
27
  CGFloat value = [detents[index] doubleValue];
30
28
  if (value == -1) {
31
- CGFloat autoHeight = [_measurements.contentHeight floatValue] + [_measurements.headerHeight floatValue];
32
- return autoHeight / _measurements.screenHeight;
29
+ CGFloat autoHeight = [self.delegate.contentHeight floatValue] + [self.delegate.headerHeight floatValue];
30
+ return autoHeight / self.delegate.screenHeight;
33
31
  }
34
32
  return value;
35
33
  }
@@ -46,7 +44,7 @@
46
44
  return storedPos;
47
45
  }
48
46
 
49
- CGFloat screenHeight = _measurements.screenHeight;
47
+ CGFloat screenHeight = self.delegate.screenHeight;
50
48
  CGFloat detentValue = [self detentValueForIndex:index];
51
49
  CGFloat basePosition = screenHeight - (detentValue * screenHeight);
52
50
 
@@ -66,7 +64,7 @@
66
64
 
67
65
  - (void)storeResolvedPositionForIndex:(NSInteger)index {
68
66
  if (index >= 0 && index < (NSInteger)_resolvedDetentPositions.count) {
69
- _resolvedDetentPositions[index] = @(_measurements.currentPosition);
67
+ _resolvedDetentPositions[index] = @(self.delegate.currentPosition);
70
68
  }
71
69
  }
72
70
 
@@ -78,7 +76,7 @@
78
76
  return NO;
79
77
  }
80
78
 
81
- CGFloat screenHeight = _measurements.screenHeight;
79
+ CGFloat screenHeight = self.delegate.screenHeight;
82
80
  CGFloat firstPos = [self estimatedPositionForIndex:0];
83
81
 
84
82
  // Above first detent - interpolating toward closed
@@ -264,7 +264,6 @@ export class TrueSheet extends PureComponent {
264
264
  blurOptions,
265
265
  cornerRadius,
266
266
  maxHeight,
267
- edgeToEdgeFullScreen,
268
267
  scrollable = false,
269
268
  pageSizing = true,
270
269
  children,
@@ -312,7 +311,6 @@ export class TrueSheet extends PureComponent {
312
311
  dismissible: dismissible,
313
312
  draggable: draggable,
314
313
  maxHeight: maxHeight,
315
- edgeToEdgeFullScreen: edgeToEdgeFullScreen,
316
314
  scrollable: scrollable,
317
315
  pageSizing: pageSizing,
318
316
  insetAdjustment: insetAdjustment,