@lodev09/react-native-true-sheet 3.8.2 → 3.9.0-beta.1

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 (35) hide show
  1. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +2 -2
  2. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +22 -4
  3. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +56 -4
  4. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +18 -5
  5. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +51 -14
  6. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +3 -3
  7. package/android/src/main/java/com/lodev09/truesheet/utils/ScreenUtils.kt +11 -0
  8. package/ios/TrueSheetContainerView.h +1 -1
  9. package/ios/TrueSheetContainerView.mm +1 -1
  10. package/ios/TrueSheetView.mm +36 -18
  11. package/ios/TrueSheetViewController.h +7 -3
  12. package/ios/TrueSheetViewController.mm +70 -16
  13. package/ios/core/TrueSheetBlurView.h +1 -1
  14. package/ios/core/TrueSheetBlurView.mm +6 -2
  15. package/ios/utils/BlurUtil.h +1 -1
  16. package/ios/utils/BlurUtil.mm +49 -33
  17. package/lib/module/TrueSheet.js +8 -2
  18. package/lib/module/TrueSheet.js.map +1 -1
  19. package/lib/module/TrueSheet.web.js +13 -4
  20. package/lib/module/TrueSheet.web.js.map +1 -1
  21. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +29 -2
  22. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  23. package/lib/typescript/src/TrueSheet.types.d.ts +30 -2
  24. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  25. package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -1
  26. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +5 -2
  27. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  28. package/lib/typescript/src/navigation/types.d.ts +1 -1
  29. package/lib/typescript/src/navigation/types.d.ts.map +1 -1
  30. package/package.json +1 -1
  31. package/src/TrueSheet.tsx +8 -3
  32. package/src/TrueSheet.types.ts +33 -2
  33. package/src/TrueSheet.web.tsx +12 -4
  34. package/src/fabric/TrueSheetViewNativeComponent.ts +29 -2
  35. package/src/navigation/types.ts +2 -1
@@ -35,7 +35,7 @@ class TrueSheetContainerView(reactContext: ThemedReactContext) :
35
35
  var headerHeight: Int = 0
36
36
  var footerHeight: Int = 0
37
37
 
38
- var insetAdjustment: String = "automatic"
38
+ var insetAdjustment: TrueSheetInsetAdjustment = TrueSheetInsetAdjustment.AUTOMATIC
39
39
  var scrollViewBottomInset: Int = 0
40
40
  var scrollableEnabled: Boolean = false
41
41
  var scrollableOptions: ReadableMap? = null
@@ -54,7 +54,7 @@ class TrueSheetContainerView(reactContext: ThemedReactContext) :
54
54
  }
55
55
 
56
56
  fun setupScrollable() {
57
- val bottomInset = if (insetAdjustment == "automatic") scrollViewBottomInset else 0
57
+ val bottomInset = if (insetAdjustment == TrueSheetInsetAdjustment.AUTOMATIC) scrollViewBottomInset else 0
58
58
  contentView?.setupScrollable(scrollableEnabled, bottomInset)
59
59
  }
60
60
 
@@ -190,15 +190,33 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
190
190
  if (viewController.isPresented) {
191
191
  viewController.sheetView?.setupBackground()
192
192
  viewController.sheetView?.setupGrabber()
193
+ viewController.sheetView?.updateGravity()
194
+ viewController.updateBehaviorMaxWidth()
193
195
  updateSheetIfNeeded()
194
196
  }
195
197
  }
196
198
 
197
199
  // ==================== Property Setters ====================
198
200
 
199
- fun setMaxHeight(height: Int) {
200
- if (viewController.maxSheetHeight == height) return
201
- viewController.maxSheetHeight = height
201
+ fun setMaxContentHeight(height: Int?) {
202
+ if (viewController.maxContentHeight == height) return
203
+ viewController.maxContentHeight = height
204
+ }
205
+
206
+ fun setMaxContentWidth(width: Int?) {
207
+ if (viewController.maxContentWidth == width) return
208
+ viewController.maxContentWidth = width
209
+ }
210
+
211
+ fun setAnchor(anchor: String?) {
212
+ val value = TrueSheetAnchor.fromString(anchor)
213
+ if (viewController.anchor == value) return
214
+ viewController.anchor = value
215
+ }
216
+
217
+ fun setAnchorOffset(offset: Int) {
218
+ if (viewController.anchorOffset == offset) return
219
+ viewController.anchorOffset = offset
202
220
  }
203
221
 
204
222
  fun setDimmed(dimmed: Boolean) {
@@ -254,7 +272,7 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
254
272
  }
255
273
 
256
274
  fun setInsetAdjustment(insetAdjustment: String) {
257
- viewController.insetAdjustment = insetAdjustment
275
+ viewController.insetAdjustment = TrueSheetInsetAdjustment.fromString(insetAdjustment)
258
276
  setupScrollable()
259
277
  }
260
278
 
@@ -11,8 +11,10 @@ import android.widget.ImageView
11
11
  import android.widget.ScrollView
12
12
  import androidx.activity.OnBackPressedCallback
13
13
  import androidx.appcompat.app.AppCompatActivity
14
+ import androidx.coordinatorlayout.widget.CoordinatorLayout
14
15
  import androidx.core.graphics.createBitmap
15
16
  import androidx.core.view.isNotEmpty
17
+ import androidx.transition.TransitionManager
16
18
  import com.facebook.react.R
17
19
  import com.facebook.react.bridge.ReadableMap
18
20
  import com.facebook.react.uimanager.JSPointerDispatcher
@@ -77,6 +79,34 @@ interface TrueSheetViewControllerDelegate {
77
79
  * enabling touch pass-through to underlying views. Handles detent configuration, drag interactions,
78
80
  * keyboard avoidance, dimmed backgrounds, back button, and lifecycle events for stacked sheets.
79
81
  */
82
+ enum class TrueSheetAnchor {
83
+ LEFT,
84
+ CENTER,
85
+ RIGHT;
86
+
87
+ companion object {
88
+ fun fromString(value: String?): TrueSheetAnchor =
89
+ when (value) {
90
+ "left" -> LEFT
91
+ "right" -> RIGHT
92
+ else -> CENTER
93
+ }
94
+ }
95
+ }
96
+
97
+ enum class TrueSheetInsetAdjustment {
98
+ AUTOMATIC,
99
+ NEVER;
100
+
101
+ companion object {
102
+ fun fromString(value: String?): TrueSheetInsetAdjustment =
103
+ when (value) {
104
+ "never" -> NEVER
105
+ else -> AUTOMATIC
106
+ }
107
+ }
108
+ }
109
+
80
110
  @SuppressLint("ClickableViewAccessibility", "ViewConstructor")
81
111
  class TrueSheetViewController(private val reactContext: ThemedReactContext) :
82
112
  ReactViewGroup(reactContext),
@@ -89,6 +119,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
89
119
  companion object {
90
120
  private const val DEFAULT_MAX_WIDTH = 640 // dp
91
121
  private const val DEFAULT_CORNER_RADIUS = 16 // dp
122
+ private const val DEFAULT_ANCHOR_OFFSET = 16 // dp
92
123
  private const val TRANSLATE_ANIMATION_DURATION = 200L
93
124
  private const val DISMISS_DURATION = 200L
94
125
  private const val SCREEN_FADE_DURATION = 150L
@@ -166,7 +197,10 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
166
197
  get() = delegate?.eventDispatcher
167
198
 
168
199
  // Detent Configuration
169
- override var maxSheetHeight: Int? = null
200
+ override var maxContentHeight: Int? = null
201
+ override var maxContentWidth: Int? = null
202
+ override var anchor: TrueSheetAnchor = TrueSheetAnchor.CENTER
203
+ override var anchorOffset: Int = DEFAULT_ANCHOR_OFFSET.dpToPx().toInt()
170
204
  override var detents: MutableList<Double> = mutableListOf(0.5, 1.0)
171
205
 
172
206
  // Appearance Configuration
@@ -175,7 +209,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
175
209
  override var grabber: Boolean = true
176
210
  override var grabberOptions: GrabberOptions? = null
177
211
  override var sheetBackgroundColor: Int? = null
178
- var insetAdjustment: String = "automatic"
212
+ var insetAdjustment: TrueSheetInsetAdjustment = TrueSheetInsetAdjustment.AUTOMATIC
179
213
 
180
214
  var scrollable: Boolean = false
181
215
  set(value) {
@@ -267,7 +301,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
267
301
  get() = if (edgeToEdgeEnabled) ScreenUtils.getInsets(reactContext).top else 0
268
302
 
269
303
  override val contentBottomInset: Int
270
- get() = if (insetAdjustment == "automatic") bottomInset else 0
304
+ get() = if (insetAdjustment == TrueSheetInsetAdjustment.AUTOMATIC) bottomInset else 0
271
305
 
272
306
  @Suppress("KotlinConstantConditions", "SimplifyBooleanWithConstants")
273
307
  private val edgeToEdgeEnabled: Boolean
@@ -417,6 +451,8 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
417
451
  override fun coordinatorLayoutDidChangeConfiguration() {
418
452
  if (!isPresented) return
419
453
 
454
+ sheetView?.updateGravity(animated = false)
455
+ updateBehaviorMaxWidth(animated = false)
420
456
  updateStateDimensions()
421
457
  sheetView?.let { emitChangePositionDelegate(it.top, realtime = false) }
422
458
  }
@@ -1094,11 +1130,27 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
1094
1130
  // MARK: - Detent Helpers
1095
1131
  // =============================================================================
1096
1132
 
1133
+ fun updateBehaviorMaxWidth(animated: Boolean = true) {
1134
+ val behavior = this.behavior ?: return
1135
+ val applyMaxWidth = maxContentWidth != null && !ScreenUtils.isPortraitPhone(reactContext)
1136
+ val newMaxWidth = if (applyMaxWidth) maxContentWidth!! else DEFAULT_MAX_WIDTH.dpToPx().toInt()
1137
+ if (behavior.maxWidth == newMaxWidth) return
1138
+
1139
+ if (animated) {
1140
+ sheetView?.let { view ->
1141
+ (view.parent as? CoordinatorLayout)?.let { TransitionManager.beginDelayedTransition(it) }
1142
+ }
1143
+ }
1144
+ behavior.maxWidth = newMaxWidth
1145
+ }
1146
+
1097
1147
  private fun updateStateDimensions(expandedOffset: Int? = null) {
1098
1148
  val offset = expandedOffset ?: (realScreenHeight - detentCalculator.getDetentHeight(detents.last()))
1099
1149
  val topOffset = if (offset == 0) topInset else 0
1100
1150
  val newHeight = realScreenHeight - offset - topOffset
1101
- val newWidth = minOf(screenWidth, DEFAULT_MAX_WIDTH.dpToPx().toInt())
1151
+ val applyMaxWidth = maxContentWidth != null && !ScreenUtils.isPortraitPhone(reactContext)
1152
+ val effectiveMaxWidth = if (applyMaxWidth) maxContentWidth!! else DEFAULT_MAX_WIDTH.dpToPx().toInt()
1153
+ val newWidth = minOf(screenWidth, effectiveMaxWidth)
1102
1154
 
1103
1155
  if (lastStateWidth != newWidth || lastStateHeight != newHeight) {
1104
1156
  lastStateWidth = newWidth
@@ -166,11 +166,24 @@ class TrueSheetViewManager :
166
166
  view.initialDetentAnimated = animate
167
167
  }
168
168
 
169
- @ReactProp(name = "maxHeight", defaultDouble = 0.0)
170
- override fun setMaxHeight(view: TrueSheetView, height: Double) {
171
- if (height > 0) {
172
- view.setMaxHeight(height.dpToPx().toInt())
173
- }
169
+ @ReactProp(name = "maxContentHeight", defaultDouble = 0.0)
170
+ override fun setMaxContentHeight(view: TrueSheetView, height: Double) {
171
+ view.setMaxContentHeight(if (height > 0) height.dpToPx().toInt() else null)
172
+ }
173
+
174
+ @ReactProp(name = "maxContentWidth", defaultDouble = 0.0)
175
+ override fun setMaxContentWidth(view: TrueSheetView, width: Double) {
176
+ view.setMaxContentWidth(if (width > 0) width.dpToPx().toInt() else null)
177
+ }
178
+
179
+ @ReactProp(name = "anchor")
180
+ override fun setAnchor(view: TrueSheetView, anchor: String?) {
181
+ view.setAnchor(anchor)
182
+ }
183
+
184
+ @ReactProp(name = "anchorOffset", defaultDouble = 0.0)
185
+ override fun setAnchorOffset(view: TrueSheetView, offset: Double) {
186
+ view.setAnchorOffset(if (offset > 0) offset.dpToPx().toInt() else 0)
174
187
  }
175
188
 
176
189
  @ReactProp(name = "backgroundBlur")
@@ -1,12 +1,12 @@
1
1
  package com.lodev09.truesheet.core
2
2
 
3
3
  import android.annotation.SuppressLint
4
+ import android.content.res.Configuration
4
5
  import android.graphics.Color
5
6
  import android.graphics.Outline
6
7
  import android.graphics.Rect
7
8
  import android.graphics.drawable.ShapeDrawable
8
9
  import android.graphics.drawable.shapes.RoundRectShape
9
- import android.util.TypedValue
10
10
  import android.view.GestureDetector
11
11
  import android.view.Gravity
12
12
  import android.view.MotionEvent
@@ -14,15 +14,21 @@ import android.view.View
14
14
  import android.view.ViewOutlineProvider
15
15
  import android.widget.FrameLayout
16
16
  import androidx.coordinatorlayout.widget.CoordinatorLayout
17
+ import androidx.transition.TransitionManager
17
18
  import com.facebook.react.uimanager.PixelUtil.dpToPx
18
19
  import com.facebook.react.uimanager.ThemedReactContext
19
20
  import com.google.android.material.bottomsheet.BottomSheetBehavior
21
+ import com.lodev09.truesheet.TrueSheetAnchor
22
+ import com.lodev09.truesheet.utils.ScreenUtils
20
23
 
21
24
  interface TrueSheetBottomSheetViewDelegate {
22
25
  val isTopmostSheet: Boolean
23
26
  val sheetCornerRadius: Float
24
27
  val sheetElevation: Float
25
28
  val sheetBackgroundColor: Int?
29
+ val maxContentWidth: Int?
30
+ val anchor: TrueSheetAnchor
31
+ val anchorOffset: Int
26
32
  val grabber: Boolean
27
33
  val grabberOptions: GrabberOptions?
28
34
  val draggable: Boolean
@@ -44,6 +50,10 @@ class TrueSheetBottomSheetView(private val reactContext: ThemedReactContext) : F
44
50
  private const val DEFAULT_CORNER_RADIUS = 16f // dp
45
51
  private const val DEFAULT_MAX_WIDTH = 640 // dp
46
52
  private const val DEFAULT_ELEVATION = 4f // dp
53
+
54
+ // M3 baseline surfaceContainerLow
55
+ private val COLOR_SURFACE_CONTAINER_LOW_LIGHT = Color.parseColor("#F7F2FA")
56
+ private val COLOR_SURFACE_CONTAINER_LOW_DARK = Color.parseColor("#1D1B20")
47
57
  }
48
58
 
49
59
  // =============================================================================
@@ -80,24 +90,57 @@ class TrueSheetBottomSheetView(private val reactContext: ThemedReactContext) : F
80
90
  // MARK: - Layout
81
91
  // =============================================================================
82
92
 
93
+ private fun resolveAnchor(): Pair<Int, Int> {
94
+ val anchor = if (ScreenUtils.isPortraitPhone(reactContext)) null else delegate?.anchor
95
+ val gravity = when (anchor) {
96
+ TrueSheetAnchor.LEFT -> Gravity.START
97
+ TrueSheetAnchor.RIGHT -> Gravity.END
98
+ else -> Gravity.CENTER_HORIZONTAL
99
+ } or Gravity.BOTTOM
100
+ val margin = if (anchor == TrueSheetAnchor.LEFT || anchor == TrueSheetAnchor.RIGHT) delegate?.anchorOffset ?: 0 else 0
101
+ return Pair(gravity, margin)
102
+ }
103
+
83
104
  /**
84
105
  * Creates layout params with BottomSheetBehavior attached.
85
106
  */
86
107
  fun createLayoutParams(): CoordinatorLayout.LayoutParams {
108
+ val applyMaxWidth = delegate?.maxContentWidth != null && !ScreenUtils.isPortraitPhone(reactContext)
109
+ val effectiveMaxWidth = if (applyMaxWidth) delegate!!.maxContentWidth!! else DEFAULT_MAX_WIDTH.dpToPx().toInt()
87
110
  val behavior = BottomSheetBehavior<TrueSheetBottomSheetView>().apply {
88
111
  isHideable = true
89
- maxWidth = DEFAULT_MAX_WIDTH.dpToPx().toInt()
112
+ maxWidth = effectiveMaxWidth
90
113
  }
91
114
 
115
+ val (gravity, margin) = resolveAnchor()
116
+
92
117
  return CoordinatorLayout.LayoutParams(
93
118
  CoordinatorLayout.LayoutParams.MATCH_PARENT,
94
119
  CoordinatorLayout.LayoutParams.MATCH_PARENT
95
120
  ).apply {
96
121
  this.behavior = behavior
97
- this.gravity = Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM
122
+ this.gravity = gravity
123
+ this.marginStart = margin
124
+ this.marginEnd = margin
98
125
  }
99
126
  }
100
127
 
128
+ fun updateGravity(animated: Boolean = true) {
129
+ val params = layoutParams as? CoordinatorLayout.LayoutParams ?: return
130
+ val (gravity, margin) = resolveAnchor()
131
+
132
+ if (params.gravity == gravity && params.marginStart == margin) return
133
+
134
+ if (animated) {
135
+ (parent as? CoordinatorLayout)?.let { TransitionManager.beginDelayedTransition(it) }
136
+ }
137
+
138
+ params.gravity = gravity
139
+ params.marginStart = margin
140
+ params.marginEnd = margin
141
+ layoutParams = params
142
+ }
143
+
101
144
  // =============================================================================
102
145
  // MARK: - Background & Styling
103
146
  // =============================================================================
@@ -132,17 +175,11 @@ class TrueSheetBottomSheetView(private val reactContext: ThemedReactContext) : F
132
175
  }
133
176
 
134
177
  private fun getDefaultBackgroundColor(): Int {
135
- val typedValue = TypedValue()
136
- return if (reactContext.theme.resolveAttribute(
137
- com.google.android.material.R.attr.colorSurfaceContainerLow,
138
- typedValue,
139
- true
140
- )
141
- ) {
142
- typedValue.data
143
- } else {
144
- Color.WHITE
145
- }
178
+ val isNight = (
179
+ reactContext.resources.configuration.uiMode and
180
+ Configuration.UI_MODE_NIGHT_MASK
181
+ ) == Configuration.UI_MODE_NIGHT_YES
182
+ return if (isNight) COLOR_SURFACE_CONTAINER_LOW_DARK else COLOR_SURFACE_CONTAINER_LOW_LIGHT
146
183
  }
147
184
 
148
185
  fun setupElevation() {
@@ -15,7 +15,7 @@ interface TrueSheetDetentCalculatorDelegate {
15
15
  val contentHeight: Int
16
16
  val headerHeight: Int
17
17
  val contentBottomInset: Int
18
- val maxSheetHeight: Int?
18
+ val maxContentHeight: Int?
19
19
  val keyboardInset: Int
20
20
  }
21
21
 
@@ -32,7 +32,7 @@ class TrueSheetDetentCalculator(private val reactContext: ThemedReactContext) {
32
32
  private val contentHeight: Int get() = delegate?.contentHeight ?: 0
33
33
  private val headerHeight: Int get() = delegate?.headerHeight ?: 0
34
34
  private val contentBottomInset: Int get() = delegate?.contentBottomInset ?: 0
35
- private val maxSheetHeight: Int? get() = delegate?.maxSheetHeight
35
+ private val maxContentHeight: Int? get() = delegate?.maxContentHeight
36
36
  private val keyboardInset: Int get() = delegate?.keyboardInset ?: 0
37
37
 
38
38
  /**
@@ -51,7 +51,7 @@ class TrueSheetDetentCalculator(private val reactContext: ThemedReactContext) {
51
51
 
52
52
  val height = baseHeight + keyboardInset
53
53
  val maxAllowedHeight = screenHeight + contentBottomInset
54
- return maxSheetHeight?.let { minOf(height, it, maxAllowedHeight) } ?: minOf(height, maxAllowedHeight)
54
+ return maxContentHeight?.let { minOf(height, it, maxAllowedHeight) } ?: minOf(height, maxAllowedHeight)
55
55
  }
56
56
 
57
57
  /**
@@ -1,5 +1,6 @@
1
1
  package com.lodev09.truesheet.utils
2
2
 
3
+ import android.content.res.Configuration
3
4
  import android.graphics.Point
4
5
  import android.os.Build
5
6
  import android.view.View
@@ -114,4 +115,14 @@ object ScreenUtils {
114
115
  view.getLocationOnScreen(location)
115
116
  return location
116
117
  }
118
+
119
+ /**
120
+ * Returns true if the device is a phone in portrait orientation.
121
+ */
122
+ fun isPortraitPhone(reactContext: ReactContext): Boolean {
123
+ val config = reactContext.resources.configuration
124
+ val isPortrait = config.orientation == Configuration.ORIENTATION_PORTRAIT
125
+ val isPhone = config.smallestScreenWidthDp < 600
126
+ return isPortrait && isPhone
127
+ }
117
128
  }
@@ -46,7 +46,7 @@ NS_ASSUME_NONNULL_BEGIN
46
46
  /**
47
47
  * Inset adjustment mode for scrollable content
48
48
  */
49
- @property (nonatomic, copy, nullable) NSString *insetAdjustment;
49
+ @property (nonatomic, assign) NSInteger insetAdjustment;
50
50
 
51
51
  /**
52
52
  * Options for scrollable behavior
@@ -100,7 +100,7 @@ using namespace facebook::react;
100
100
  - (void)setupScrollable {
101
101
  if (_scrollableSet && _contentView) {
102
102
  CGFloat bottomInset = 0;
103
- if ([_insetAdjustment isEqualToString:@"automatic"]) {
103
+ if (_insetAdjustment == (NSInteger)TrueSheetViewInsetAdjustment::Automatic) {
104
104
  bottomInset = [WindowUtil keyWindow].safeAreaInsets.bottom;
105
105
  }
106
106
  [_contentView setupScrollable:_scrollableEnabled bottomInset:bottomInset];
@@ -50,7 +50,7 @@ using namespace facebook::react;
50
50
  UIView *_snapshotView;
51
51
  CGSize _lastStateSize;
52
52
  NSInteger _initialDetentIndex;
53
- NSString *_insetAdjustment;
53
+ NSInteger _insetAdjustment;
54
54
  BOOL _scrollable;
55
55
  NSDictionary *_scrollableOptions;
56
56
  BOOL _initialDetentAnimated;
@@ -176,7 +176,7 @@ using namespace facebook::react;
176
176
  _controller.backgroundColor = RCTUIColorFromSharedColor(newProps.backgroundColor);
177
177
 
178
178
  // Blur tint
179
- _controller.backgroundBlur = !newProps.backgroundBlur.empty() ? RCTNSStringFromString(newProps.backgroundBlur) : nil;
179
+ _controller.backgroundBlur = (NSInteger)newProps.backgroundBlur;
180
180
 
181
181
  // Blur options
182
182
  const auto &blurOpts = newProps.blurOptions;
@@ -186,10 +186,14 @@ using namespace facebook::react;
186
186
  // Corner radius
187
187
  _controller.cornerRadius = newProps.cornerRadius < 0 ? nil : @(newProps.cornerRadius);
188
188
 
189
- // Max height
190
- if (newProps.maxHeight != 0.0) {
191
- _controller.maxHeight = @(newProps.maxHeight);
192
- }
189
+ // Content height
190
+ _controller.maxContentHeight = newProps.maxContentHeight != 0.0 ? @(newProps.maxContentHeight) : nil;
191
+
192
+ // Content width
193
+ _controller.maxContentWidth = newProps.maxContentWidth != 0.0 ? @(newProps.maxContentWidth) : nil;
194
+
195
+ // Anchor
196
+ _controller.anchor = (NSInteger)newProps.anchor;
193
197
 
194
198
  _controller.grabber = newProps.grabber;
195
199
 
@@ -250,7 +254,7 @@ using namespace facebook::react;
250
254
  _scrollableOptions = nil;
251
255
  }
252
256
 
253
- _insetAdjustment = RCTNSStringFromString(toString(newProps.insetAdjustment));
257
+ _insetAdjustment = (NSInteger)newProps.insetAdjustment;
254
258
  _controller.insetAdjustment = _insetAdjustment;
255
259
 
256
260
  if (_containerView) {
@@ -311,6 +315,11 @@ using namespace facebook::react;
311
315
  BOOL pendingLayoutUpdate = _pendingLayoutUpdate;
312
316
  _pendingLayoutUpdate = NO;
313
317
 
318
+ UIView *presenterView = _controller.presentingViewController.view;
319
+ [_controller setupAnchorViewInView:presenterView];
320
+
321
+ [_controller setupSheetSizing];
322
+
314
323
  [_controller.sheetPresentationController animateChanges:^{
315
324
  [self->_controller setupSheetProps];
316
325
  if (pendingLayoutUpdate) {
@@ -339,13 +348,25 @@ using namespace facebook::react;
339
348
 
340
349
  #pragma mark - Child Component Mounting
341
350
 
351
+ - (void)cleanupContainerView {
352
+ if (_containerView == nil)
353
+ return;
354
+
355
+ _containerView.delegate = nil;
356
+ [_touchHandler detachFromView:_containerView];
357
+ [LayoutUtil unpinView:_containerView fromParentView:nil];
358
+ [_containerView removeFromSuperview];
359
+
360
+ _containerView = nil;
361
+ }
362
+
342
363
  - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
343
364
  if (![childComponentView isKindOfClass:[TrueSheetContainerView class]])
344
365
  return;
345
366
 
346
- if (_containerView != nil) {
367
+ if (_containerView != nil && _containerView != childComponentView) {
347
368
  RCTLogWarn(@"TrueSheet: Sheet can only have one container component.");
348
- return;
369
+ [self cleanupContainerView];
349
370
  }
350
371
 
351
372
  if (_snapshotView) {
@@ -387,6 +408,9 @@ using namespace facebook::react;
387
408
  if (![childComponentView isKindOfClass:[TrueSheetContainerView class]])
388
409
  return;
389
410
 
411
+ if (_containerView == nil || _containerView != childComponentView)
412
+ return;
413
+
390
414
  if (_controller.isPresented) {
391
415
  UIView *superView = _containerView.superview;
392
416
  UIView *snapshot = [_containerView snapshotViewAfterScreenUpdates:NO];
@@ -397,15 +421,7 @@ using namespace facebook::react;
397
421
  }
398
422
  }
399
423
 
400
- _containerView.delegate = nil;
401
-
402
- if (_touchHandler) {
403
- [_touchHandler detachFromView:_containerView];
404
- }
405
-
406
- [LayoutUtil unpinView:_containerView fromParentView:nil];
407
- [_containerView removeFromSuperview];
408
- _containerView = nil;
424
+ [self cleanupContainerView];
409
425
  }
410
426
 
411
427
  #pragma mark - TurboModule Methods
@@ -435,6 +451,8 @@ using namespace facebook::react;
435
451
  return;
436
452
  }
437
453
 
454
+ [_controller setupAnchorViewInView:presentingViewController.view];
455
+ [_controller setupSheetSizing];
438
456
  [_controller setupSheetProps];
439
457
  [_controller setupSheetDetents];
440
458
  [_controller setupActiveDetentWithIndex:index];
@@ -51,7 +51,8 @@ NS_ASSUME_NONNULL_BEGIN
51
51
 
52
52
  @property (nonatomic, weak, nullable) id<TrueSheetViewControllerDelegate> delegate;
53
53
  @property (nonatomic, strong) NSArray<NSNumber *> *detents;
54
- @property (nonatomic, strong, nullable) NSNumber *maxHeight;
54
+ @property (nonatomic, strong, nullable) NSNumber *maxContentHeight;
55
+ @property (nonatomic, strong, nullable) NSNumber *maxContentWidth;
55
56
  @property (nonatomic, strong, nullable) NSNumber *contentHeight;
56
57
  @property (nonatomic, strong, nullable) NSNumber *headerHeight;
57
58
  @property (nonatomic, strong, nullable) UIColor *backgroundColor;
@@ -61,11 +62,12 @@ NS_ASSUME_NONNULL_BEGIN
61
62
  @property (nonatomic, assign) BOOL draggable;
62
63
  @property (nonatomic, assign) BOOL dimmed;
63
64
  @property (nonatomic, strong, nullable) NSNumber *dimmedDetentIndex;
64
- @property (nonatomic, copy, nullable) NSString *backgroundBlur;
65
+ @property (nonatomic, assign) NSInteger backgroundBlur;
65
66
  @property (nonatomic, strong, nullable) NSNumber *blurIntensity;
66
67
  @property (nonatomic, assign) BOOL blurInteraction;
67
68
  @property (nonatomic, assign) BOOL pageSizing;
68
- @property (nonatomic, copy, nullable) NSString *insetAdjustment;
69
+ @property (nonatomic, assign) NSInteger anchor;
70
+ @property (nonatomic, assign) NSInteger insetAdjustment;
69
71
  @property (nonatomic, assign) BOOL isPresented;
70
72
  @property (nonatomic, assign) NSInteger activeDetentIndex;
71
73
  @property (nonatomic, readonly) BOOL isTopmostPresentedController;
@@ -75,11 +77,13 @@ NS_ASSUME_NONNULL_BEGIN
75
77
  - (void)applyActiveDetent;
76
78
  - (void)setupActiveDetentWithIndex:(NSInteger)index;
77
79
  - (void)resizeToDetentIndex:(NSInteger)index;
80
+ - (void)setupSheetSizing;
78
81
  - (void)setupSheetProps;
79
82
  - (void)setupSheetDetents;
80
83
  - (void)setupSheetDetentsForSizeChange;
81
84
  - (void)setupSheetDetentsForDetentsChange;
82
85
  - (void)setupDraggable;
86
+ - (void)setupAnchorViewInView:(UIView *)parentView;
83
87
 
84
88
  @end
85
89