@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.
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +2 -2
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +22 -4
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +56 -4
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +18 -5
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +51 -14
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +3 -3
- package/android/src/main/java/com/lodev09/truesheet/utils/ScreenUtils.kt +11 -0
- package/ios/TrueSheetContainerView.h +1 -1
- package/ios/TrueSheetContainerView.mm +1 -1
- package/ios/TrueSheetView.mm +36 -18
- package/ios/TrueSheetViewController.h +7 -3
- package/ios/TrueSheetViewController.mm +70 -16
- package/ios/core/TrueSheetBlurView.h +1 -1
- package/ios/core/TrueSheetBlurView.mm +6 -2
- package/ios/utils/BlurUtil.h +1 -1
- package/ios/utils/BlurUtil.mm +49 -33
- package/lib/module/TrueSheet.js +8 -2
- package/lib/module/TrueSheet.js.map +1 -1
- package/lib/module/TrueSheet.web.js +13 -4
- package/lib/module/TrueSheet.web.js.map +1 -1
- package/lib/module/fabric/TrueSheetViewNativeComponent.ts +29 -2
- package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.types.d.ts +30 -2
- package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -1
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +5 -2
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/navigation/types.d.ts +1 -1
- package/lib/typescript/src/navigation/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/TrueSheet.tsx +8 -3
- package/src/TrueSheet.types.ts +33 -2
- package/src/TrueSheet.web.tsx +12 -4
- package/src/fabric/TrueSheetViewNativeComponent.ts +29 -2
- 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:
|
|
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 ==
|
|
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
|
|
200
|
-
if (viewController.
|
|
201
|
-
viewController.
|
|
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
|
|
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:
|
|
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 ==
|
|
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
|
|
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 = "
|
|
170
|
-
override fun
|
|
171
|
-
if (height > 0)
|
|
172
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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 (
|
|
103
|
+
if (_insetAdjustment == (NSInteger)TrueSheetViewInsetAdjustment::Automatic) {
|
|
104
104
|
bottomInset = [WindowUtil keyWindow].safeAreaInsets.bottom;
|
|
105
105
|
}
|
|
106
106
|
[_contentView setupScrollable:_scrollableEnabled bottomInset:bottomInset];
|
package/ios/TrueSheetView.mm
CHANGED
|
@@ -50,7 +50,7 @@ using namespace facebook::react;
|
|
|
50
50
|
UIView *_snapshotView;
|
|
51
51
|
CGSize _lastStateSize;
|
|
52
52
|
NSInteger _initialDetentIndex;
|
|
53
|
-
|
|
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 =
|
|
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
|
-
//
|
|
190
|
-
|
|
191
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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 *
|
|
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,
|
|
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,
|
|
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
|
|