@lodev09/react-native-true-sheet 3.7.4-beta.2 → 3.8.0-beta.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.
- package/README.md +9 -48
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +24 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +162 -1
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetPackage.kt +2 -3
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +76 -8
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +70 -74
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +5 -0
- package/android/src/main/java/com/lodev09/truesheet/core/RNScreensEventObserver.kt +63 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +1 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +2 -19
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetKeyboardObserver.kt +34 -6
- package/android/src/main/java/com/lodev09/truesheet/utils/ViewUtils.kt +12 -0
- package/ios/TrueSheetContainerView.h +15 -4
- package/ios/TrueSheetContainerView.mm +45 -6
- package/ios/TrueSheetContentView.h +6 -2
- package/ios/TrueSheetContentView.mm +88 -2
- package/ios/TrueSheetFooterView.h +4 -3
- package/ios/TrueSheetFooterView.mm +16 -63
- package/ios/TrueSheetView.mm +31 -7
- package/ios/core/TrueSheetKeyboardObserver.h +38 -0
- package/ios/core/TrueSheetKeyboardObserver.mm +90 -0
- package/lib/module/TrueSheet.js +3 -1
- package/lib/module/TrueSheet.js.map +1 -1
- package/lib/module/fabric/TrueSheetViewNativeComponent.ts +5 -0
- package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.types.d.ts +15 -0
- package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +4 -0
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/TrueSheet.tsx +3 -1
- package/src/TrueSheet.types.ts +17 -0
- package/src/fabric/TrueSheetViewNativeComponent.ts +5 -0
- package/android/src/main/java/com/lodev09/truesheet/core/RNScreensFragmentObserver.kt +0 -266
package/README.md
CHANGED
|
@@ -29,9 +29,16 @@ The true native bottom sheet experience for your React Native Apps. 💩
|
|
|
29
29
|
|
|
30
30
|
### Prerequisites
|
|
31
31
|
|
|
32
|
-
- React Native
|
|
32
|
+
- React Native 0.80+
|
|
33
33
|
- New Architecture enabled (default in RN 0.76+)
|
|
34
|
-
- Xcode 26.
|
|
34
|
+
- Xcode 26.1+ (liquid glass support)
|
|
35
|
+
|
|
36
|
+
### Compatibility
|
|
37
|
+
|
|
38
|
+
| TrueSheet | React Native | Expo SDK |
|
|
39
|
+
|-----------|--------------|----------|
|
|
40
|
+
| 3.7+ | 0.80+ | 54+ |
|
|
41
|
+
| 3.6 | 0.79 | 52-53 |
|
|
35
42
|
|
|
36
43
|
### Expo
|
|
37
44
|
|
|
@@ -46,27 +53,6 @@ yarn add @lodev09/react-native-true-sheet
|
|
|
46
53
|
cd ios && pod install
|
|
47
54
|
```
|
|
48
55
|
|
|
49
|
-
### EAS Build (iOS)
|
|
50
|
-
|
|
51
|
-
When using [EAS Build](https://docs.expo.dev/build/introduction/) to build your iOS app, you must configure your `eas.json` to use a build image that includes Xcode 26.2. Use `"image": "latest"` or choose from the [available build images](https://docs.expo.dev/build-reference/infrastructure/#ios-server-images):
|
|
52
|
-
|
|
53
|
-
```json
|
|
54
|
-
{
|
|
55
|
-
"build": {
|
|
56
|
-
"production": {
|
|
57
|
-
"ios": {
|
|
58
|
-
"image": "latest"
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
"development": {
|
|
62
|
-
"ios": {
|
|
63
|
-
"image": "latest"
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
56
|
## Documentation
|
|
71
57
|
|
|
72
58
|
- [Example](example)
|
|
@@ -111,31 +97,6 @@ export const App = () => {
|
|
|
111
97
|
}
|
|
112
98
|
```
|
|
113
99
|
|
|
114
|
-
## Testing
|
|
115
|
-
|
|
116
|
-
TrueSheet exports mocks for easy testing:
|
|
117
|
-
|
|
118
|
-
```tsx
|
|
119
|
-
// Main component
|
|
120
|
-
jest.mock('@lodev09/react-native-true-sheet', () =>
|
|
121
|
-
require('@lodev09/react-native-true-sheet/mock')
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
// Navigation (if using)
|
|
125
|
-
jest.mock('@lodev09/react-native-true-sheet/navigation', () =>
|
|
126
|
-
require('@lodev09/react-native-true-sheet/navigation/mock')
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
// Reanimated (if using)
|
|
130
|
-
jest.mock('@lodev09/react-native-true-sheet/reanimated', () =>
|
|
131
|
-
require('@lodev09/react-native-true-sheet/reanimated/mock')
|
|
132
|
-
);
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
All methods (`present`, `dismiss`, `resize`) are mocked as Jest functions, allowing you to test your components without native dependencies.
|
|
136
|
-
|
|
137
|
-
**[Full Testing Guide](https://sheet.lodev09.com/guides/jest)**
|
|
138
|
-
|
|
139
100
|
## Contributing
|
|
140
101
|
|
|
141
102
|
See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
|
|
@@ -2,6 +2,7 @@ package com.lodev09.truesheet
|
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.view.View
|
|
5
|
+
import com.facebook.react.bridge.ReadableMap
|
|
5
6
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
6
7
|
import com.facebook.react.uimanager.events.EventDispatcher
|
|
7
8
|
import com.facebook.react.views.view.ReactViewGroup
|
|
@@ -34,6 +35,15 @@ class TrueSheetContainerView(reactContext: ThemedReactContext) :
|
|
|
34
35
|
var headerHeight: Int = 0
|
|
35
36
|
var footerHeight: Int = 0
|
|
36
37
|
|
|
38
|
+
var insetAdjustment: String = "automatic"
|
|
39
|
+
var scrollViewBottomInset: Int = 0
|
|
40
|
+
var scrollViewPinningEnabled: Boolean = false
|
|
41
|
+
var scrollableOptions: ReadableMap? = null
|
|
42
|
+
set(value) {
|
|
43
|
+
field = value
|
|
44
|
+
contentView?.scrollableOptions = value
|
|
45
|
+
}
|
|
46
|
+
|
|
37
47
|
override val eventDispatcher: EventDispatcher?
|
|
38
48
|
get() = delegate?.eventDispatcher
|
|
39
49
|
|
|
@@ -43,12 +53,26 @@ class TrueSheetContainerView(reactContext: ThemedReactContext) :
|
|
|
43
53
|
clipToPadding = false
|
|
44
54
|
}
|
|
45
55
|
|
|
56
|
+
fun setupContentScrollViewPinning() {
|
|
57
|
+
val bottomInset = if (insetAdjustment == "automatic") scrollViewBottomInset else 0
|
|
58
|
+
contentView?.setupScrollViewPinning(scrollViewPinningEnabled, bottomInset)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
fun setupKeyboardHandler() {
|
|
62
|
+
contentView?.setupKeyboardHandler()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
fun cleanupKeyboardHandler() {
|
|
66
|
+
contentView?.cleanupKeyboardHandler()
|
|
67
|
+
}
|
|
68
|
+
|
|
46
69
|
override fun addView(child: View?, index: Int) {
|
|
47
70
|
super.addView(child, index)
|
|
48
71
|
|
|
49
72
|
when (child) {
|
|
50
73
|
is TrueSheetContentView -> {
|
|
51
74
|
child.delegate = this
|
|
75
|
+
child.scrollableOptions = scrollableOptions
|
|
52
76
|
contentView = child
|
|
53
77
|
}
|
|
54
78
|
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
package com.lodev09.truesheet
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
|
+
import android.view.View
|
|
5
|
+
import android.view.ViewGroup
|
|
6
|
+
import android.widget.ScrollView
|
|
7
|
+
import com.facebook.react.bridge.ReadableMap
|
|
8
|
+
import com.facebook.react.uimanager.PixelUtil.dpToPx
|
|
4
9
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
5
10
|
import com.facebook.react.views.view.ReactViewGroup
|
|
11
|
+
import com.lodev09.truesheet.core.TrueSheetKeyboardObserver
|
|
12
|
+
import com.lodev09.truesheet.core.TrueSheetKeyboardObserverDelegate
|
|
6
13
|
|
|
7
14
|
/**
|
|
8
15
|
* Delegate interface for content view size changes
|
|
@@ -16,12 +23,25 @@ interface TrueSheetContentViewDelegate {
|
|
|
16
23
|
* This is the first child of TrueSheetContainerView
|
|
17
24
|
*/
|
|
18
25
|
@SuppressLint("ViewConstructor")
|
|
19
|
-
class TrueSheetContentView(
|
|
26
|
+
class TrueSheetContentView(private val reactContext: ThemedReactContext) : ReactViewGroup(reactContext) {
|
|
20
27
|
var delegate: TrueSheetContentViewDelegate? = null
|
|
21
28
|
|
|
22
29
|
private var lastWidth = 0
|
|
23
30
|
private var lastHeight = 0
|
|
24
31
|
|
|
32
|
+
private var pinnedScrollView: ScrollView? = null
|
|
33
|
+
private var originalScrollViewPaddingBottom: Int = 0
|
|
34
|
+
private var bottomInset: Int = 0
|
|
35
|
+
|
|
36
|
+
private var keyboardScrollOffset: Float = 0f
|
|
37
|
+
private var keyboardObserver: TrueSheetKeyboardObserver? = null
|
|
38
|
+
|
|
39
|
+
var scrollableOptions: ReadableMap? = null
|
|
40
|
+
set(value) {
|
|
41
|
+
field = value
|
|
42
|
+
keyboardScrollOffset = value?.getDouble("keyboardScrollOffset")?.toFloat()?.dpToPx() ?: 0f
|
|
43
|
+
}
|
|
44
|
+
|
|
25
45
|
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
|
26
46
|
super.onSizeChanged(w, h, oldw, oldh)
|
|
27
47
|
|
|
@@ -32,6 +52,147 @@ class TrueSheetContentView(context: ThemedReactContext) : ReactViewGroup(context
|
|
|
32
52
|
}
|
|
33
53
|
}
|
|
34
54
|
|
|
55
|
+
fun setupScrollViewPinning(enabled: Boolean, bottomInset: Int) {
|
|
56
|
+
if (!enabled) {
|
|
57
|
+
clearScrollViewPinning()
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this.bottomInset = bottomInset
|
|
62
|
+
applyScrollViewBottomInset()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private fun applyScrollViewBottomInset() {
|
|
66
|
+
val scrollView = findScrollView(this)
|
|
67
|
+
|
|
68
|
+
if (scrollView != pinnedScrollView) {
|
|
69
|
+
// Restore previous scroll view's padding
|
|
70
|
+
pinnedScrollView?.setPadding(
|
|
71
|
+
pinnedScrollView!!.paddingLeft,
|
|
72
|
+
pinnedScrollView!!.paddingTop,
|
|
73
|
+
pinnedScrollView!!.paddingRight,
|
|
74
|
+
originalScrollViewPaddingBottom
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
pinnedScrollView = scrollView
|
|
78
|
+
originalScrollViewPaddingBottom = scrollView?.paddingBottom ?: 0
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
scrollView?.let {
|
|
82
|
+
it.clipToPadding = false
|
|
83
|
+
it.setPadding(
|
|
84
|
+
it.paddingLeft,
|
|
85
|
+
it.paddingTop,
|
|
86
|
+
it.paddingRight,
|
|
87
|
+
originalScrollViewPaddingBottom + bottomInset
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
fun clearScrollViewPinning() {
|
|
93
|
+
pinnedScrollView?.setPadding(
|
|
94
|
+
pinnedScrollView!!.paddingLeft,
|
|
95
|
+
pinnedScrollView!!.paddingTop,
|
|
96
|
+
pinnedScrollView!!.paddingRight,
|
|
97
|
+
originalScrollViewPaddingBottom
|
|
98
|
+
)
|
|
99
|
+
pinnedScrollView = null
|
|
100
|
+
originalScrollViewPaddingBottom = 0
|
|
101
|
+
bottomInset = 0
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
fun findScrollView(): ScrollView? = findScrollView(this)
|
|
105
|
+
|
|
106
|
+
private fun findScrollView(view: View): ScrollView? {
|
|
107
|
+
if (view is ScrollView) {
|
|
108
|
+
return view
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (view is ViewGroup) {
|
|
112
|
+
for (i in 0 until view.childCount) {
|
|
113
|
+
val scrollView = findScrollView(view.getChildAt(i))
|
|
114
|
+
if (scrollView != null) {
|
|
115
|
+
return scrollView
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return null
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ==================== Keyboard Handling ====================
|
|
124
|
+
|
|
125
|
+
fun setupKeyboardHandler() {
|
|
126
|
+
if (keyboardObserver != null) return
|
|
127
|
+
|
|
128
|
+
keyboardObserver = TrueSheetKeyboardObserver(this, reactContext).apply {
|
|
129
|
+
delegate = object : TrueSheetKeyboardObserverDelegate {
|
|
130
|
+
override fun keyboardWillShow(height: Int) {
|
|
131
|
+
updateScrollViewInsetForKeyboard(height)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
override fun keyboardDidShow(height: Int) {
|
|
135
|
+
scrollToFocusedInput()
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
override fun keyboardWillHide() {
|
|
139
|
+
updateScrollViewInsetForKeyboard(0)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
override fun focusDidChange(newFocus: View) {
|
|
143
|
+
scrollToFocusedInput()
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
start()
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
fun cleanupKeyboardHandler() {
|
|
151
|
+
keyboardObserver?.stop()
|
|
152
|
+
keyboardObserver = null
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private fun updateScrollViewInsetForKeyboard(keyboardHeight: Int) {
|
|
156
|
+
val scrollView = pinnedScrollView ?: return
|
|
157
|
+
|
|
158
|
+
val totalBottomInset = if (keyboardHeight > 0) keyboardHeight else bottomInset
|
|
159
|
+
val newPaddingBottom = originalScrollViewPaddingBottom + totalBottomInset
|
|
160
|
+
|
|
161
|
+
scrollView.clipToPadding = false
|
|
162
|
+
scrollView.setPadding(
|
|
163
|
+
scrollView.paddingLeft,
|
|
164
|
+
scrollView.paddingTop,
|
|
165
|
+
scrollView.paddingRight,
|
|
166
|
+
newPaddingBottom
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
// Trigger a scroll to force update
|
|
170
|
+
scrollView.post {
|
|
171
|
+
scrollView.smoothScrollBy(0, 1)
|
|
172
|
+
scrollView.smoothScrollBy(0, -1)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private fun scrollToFocusedInput() {
|
|
177
|
+
val scrollView = pinnedScrollView ?: findScrollView() ?: return
|
|
178
|
+
val focusedView = findFocus() ?: return
|
|
179
|
+
|
|
180
|
+
val focusedLocation = IntArray(2)
|
|
181
|
+
val scrollViewLocation = IntArray(2)
|
|
182
|
+
focusedView.getLocationOnScreen(focusedLocation)
|
|
183
|
+
scrollView.getLocationOnScreen(scrollViewLocation)
|
|
184
|
+
|
|
185
|
+
val relativeTop = focusedLocation[1] - scrollViewLocation[1] + scrollView.scrollY
|
|
186
|
+
val relativeBottom = relativeTop + focusedView.height + keyboardScrollOffset.toInt()
|
|
187
|
+
|
|
188
|
+
val visibleHeight = scrollView.height - scrollView.paddingBottom
|
|
189
|
+
val visibleBottom = scrollView.scrollY + visibleHeight
|
|
190
|
+
|
|
191
|
+
if (relativeBottom > visibleBottom) {
|
|
192
|
+
scrollView.smoothScrollTo(0, relativeBottom - visibleHeight)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
35
196
|
companion object {
|
|
36
197
|
const val TAG_NAME = "TrueSheet"
|
|
37
198
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
package com.lodev09.truesheet
|
|
2
2
|
|
|
3
|
-
import com.facebook.react.
|
|
3
|
+
import com.facebook.react.BaseReactPackage
|
|
4
4
|
import com.facebook.react.bridge.NativeModule
|
|
5
5
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
6
|
import com.facebook.react.module.model.ReactModuleInfo
|
|
@@ -11,7 +11,7 @@ import com.facebook.react.uimanager.ViewManager
|
|
|
11
11
|
* TrueSheet package for Fabric architecture
|
|
12
12
|
* Registers all view managers and the TurboModule
|
|
13
13
|
*/
|
|
14
|
-
class TrueSheetPackage :
|
|
14
|
+
class TrueSheetPackage : BaseReactPackage() {
|
|
15
15
|
|
|
16
16
|
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? =
|
|
17
17
|
when (name) {
|
|
@@ -27,7 +27,6 @@ class TrueSheetPackage : TurboReactPackage() {
|
|
|
27
27
|
TrueSheetModule::class.java.name,
|
|
28
28
|
false, // canOverrideExistingModule
|
|
29
29
|
false, // needsEagerInit
|
|
30
|
-
true, // hasConstants
|
|
31
30
|
false, // isCxxModule
|
|
32
31
|
true // isTurboModule
|
|
33
32
|
)
|
|
@@ -6,6 +6,7 @@ import android.view.ViewGroup
|
|
|
6
6
|
import android.view.accessibility.AccessibilityEvent
|
|
7
7
|
import androidx.annotation.UiThread
|
|
8
8
|
import com.facebook.react.bridge.LifecycleEventListener
|
|
9
|
+
import com.facebook.react.bridge.ReadableMap
|
|
9
10
|
import com.facebook.react.bridge.WritableNativeMap
|
|
10
11
|
import com.facebook.react.uimanager.PixelUtil.pxToDp
|
|
11
12
|
import com.facebook.react.uimanager.StateWrapper
|
|
@@ -15,6 +16,8 @@ import com.facebook.react.uimanager.events.EventDispatcher
|
|
|
15
16
|
import com.facebook.react.util.RNLog
|
|
16
17
|
import com.facebook.react.views.view.ReactViewGroup
|
|
17
18
|
import com.lodev09.truesheet.core.GrabberOptions
|
|
19
|
+
import com.lodev09.truesheet.core.RNScreensEventObserver
|
|
20
|
+
import com.lodev09.truesheet.core.RNScreensEventObserverDelegate
|
|
18
21
|
import com.lodev09.truesheet.core.TrueSheetStackManager
|
|
19
22
|
import com.lodev09.truesheet.events.*
|
|
20
23
|
import com.lodev09.truesheet.utils.KeyboardUtils
|
|
@@ -29,7 +32,8 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
|
|
29
32
|
ReactViewGroup(reactContext),
|
|
30
33
|
LifecycleEventListener,
|
|
31
34
|
TrueSheetViewControllerDelegate,
|
|
32
|
-
TrueSheetContainerViewDelegate
|
|
35
|
+
TrueSheetContainerViewDelegate,
|
|
36
|
+
RNScreensEventObserverDelegate {
|
|
33
37
|
|
|
34
38
|
// ==================== Properties ====================
|
|
35
39
|
|
|
@@ -60,6 +64,9 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
|
|
60
64
|
// Root container for the coordinator layout (activity or Modal dialog content view)
|
|
61
65
|
internal var rootContainerView: ViewGroup? = null
|
|
62
66
|
|
|
67
|
+
// Screen event observer for react-native-screens integration
|
|
68
|
+
internal var screensEventObserver: RNScreensEventObserver? = null
|
|
69
|
+
|
|
63
70
|
// ==================== Initialization ====================
|
|
64
71
|
|
|
65
72
|
init {
|
|
@@ -113,6 +120,7 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
|
|
113
120
|
if (child is TrueSheetContainerView) {
|
|
114
121
|
child.delegate = this
|
|
115
122
|
viewController.createSheet()
|
|
123
|
+
setupContentScrollViewPinning()
|
|
116
124
|
|
|
117
125
|
val surfaceId = UIManagerHelper.getSurfaceId(this)
|
|
118
126
|
eventDispatcher?.dispatchEvent(MountEvent(surfaceId, id))
|
|
@@ -160,6 +168,7 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
|
|
160
168
|
TrueSheetModule.unregisterView(id)
|
|
161
169
|
TrueSheetStackManager.removeSheet(this)
|
|
162
170
|
|
|
171
|
+
cleanupScreenEventObserver()
|
|
163
172
|
didInitiallyPresent = false
|
|
164
173
|
|
|
165
174
|
if (viewController.isPresented) {
|
|
@@ -177,6 +186,8 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
|
|
177
186
|
* Reconfigures the sheet if it's currently presented.
|
|
178
187
|
*/
|
|
179
188
|
fun finalizeUpdates() {
|
|
189
|
+
setupContentScrollViewPinning()
|
|
190
|
+
|
|
180
191
|
if (viewController.isPresented) {
|
|
181
192
|
viewController.sheetView?.setupBackground()
|
|
182
193
|
viewController.sheetView?.setupGrabber()
|
|
@@ -245,10 +256,51 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
|
|
245
256
|
|
|
246
257
|
fun setInsetAdjustment(insetAdjustment: String) {
|
|
247
258
|
viewController.insetAdjustment = insetAdjustment
|
|
259
|
+
setupContentScrollViewPinning()
|
|
248
260
|
}
|
|
249
261
|
|
|
250
262
|
fun setScrollable(scrollable: Boolean) {
|
|
251
263
|
viewController.scrollable = scrollable
|
|
264
|
+
setupContentScrollViewPinning()
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
fun setScrollableOptions(options: ReadableMap?) {
|
|
268
|
+
viewController.scrollableOptions = options
|
|
269
|
+
setupContentScrollViewPinning()
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
private fun setupContentScrollViewPinning() {
|
|
273
|
+
viewController.containerView?.let {
|
|
274
|
+
it.insetAdjustment = viewController.insetAdjustment
|
|
275
|
+
it.scrollViewPinningEnabled = viewController.scrollable
|
|
276
|
+
it.scrollViewBottomInset = viewController.contentBottomInset
|
|
277
|
+
it.scrollableOptions = viewController.scrollableOptions
|
|
278
|
+
it.setupContentScrollViewPinning()
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// ==================== Screen Event Observer ====================
|
|
283
|
+
|
|
284
|
+
private fun setupScreenEventObserver() {
|
|
285
|
+
screensEventObserver = RNScreensEventObserver().apply {
|
|
286
|
+
delegate = this@TrueSheetView
|
|
287
|
+
|
|
288
|
+
// For stacked sheets on the same screen, inherit parent's presenter screen tag.
|
|
289
|
+
// If parent was hidden by screen navigation, this sheet is on a different screen.
|
|
290
|
+
val parentScreenTag = viewController.parentSheetView?.screensEventObserver?.presenterScreenTag ?: 0
|
|
291
|
+
val parentHiddenByScreen = viewController.parentSheetView?.viewController?.wasHiddenByScreen == true
|
|
292
|
+
if (parentScreenTag != 0 && !parentHiddenByScreen) {
|
|
293
|
+
presenterScreenTag = parentScreenTag
|
|
294
|
+
} else {
|
|
295
|
+
capturePresenterScreenFromView(this@TrueSheetView)
|
|
296
|
+
}
|
|
297
|
+
startObserving(eventDispatcher)
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
private fun cleanupScreenEventObserver() {
|
|
302
|
+
screensEventObserver?.stopObserving()
|
|
303
|
+
screensEventObserver = null
|
|
252
304
|
}
|
|
253
305
|
|
|
254
306
|
// ==================== State Management ====================
|
|
@@ -328,13 +380,8 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
|
|
328
380
|
|
|
329
381
|
@UiThread
|
|
330
382
|
fun resize(detentIndex: Int, promiseCallback: () -> Unit) {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
promiseCallback()
|
|
334
|
-
return
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
present(detentIndex, true, promiseCallback)
|
|
383
|
+
viewController.resizePromise = promiseCallback
|
|
384
|
+
viewController.resize(detentIndex)
|
|
338
385
|
}
|
|
339
386
|
|
|
340
387
|
/**
|
|
@@ -409,6 +456,8 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
|
|
409
456
|
}
|
|
410
457
|
|
|
411
458
|
override fun viewControllerDidPresent(index: Int, position: Float, detent: Float) {
|
|
459
|
+
setupScreenEventObserver()
|
|
460
|
+
|
|
412
461
|
val surfaceId = UIManagerHelper.getSurfaceId(this)
|
|
413
462
|
eventDispatcher?.dispatchEvent(DidPresentEvent(surfaceId, id, index, position, detent))
|
|
414
463
|
}
|
|
@@ -423,6 +472,8 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
|
|
423
472
|
viewController.coordinatorLayout?.let { rootContainerView?.removeView(it) }
|
|
424
473
|
rootContainerView = null
|
|
425
474
|
|
|
475
|
+
cleanupScreenEventObserver()
|
|
476
|
+
|
|
426
477
|
val surfaceId = UIManagerHelper.getSurfaceId(this)
|
|
427
478
|
eventDispatcher?.dispatchEvent(DidDismissEvent(surfaceId, id))
|
|
428
479
|
|
|
@@ -502,6 +553,23 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
|
|
502
553
|
viewController.positionFooter()
|
|
503
554
|
}
|
|
504
555
|
|
|
556
|
+
// ==================== RNScreensEventObserverDelegate ====================
|
|
557
|
+
|
|
558
|
+
override fun presenterScreenWillDisappear() {
|
|
559
|
+
if (viewController.isPresented && viewController.isSheetVisible) {
|
|
560
|
+
KeyboardUtils.dismiss(this) {}
|
|
561
|
+
viewController.post { viewController.hideForScreen() }
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
override fun presenterScreenWillAppear() {
|
|
566
|
+
if (viewController.isPresented && viewController.wasHiddenByScreen) {
|
|
567
|
+
viewController.wasHiddenByScreen = false
|
|
568
|
+
viewController.showAfterScreen()
|
|
569
|
+
viewControllerDidDetectScreenDismiss()
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
505
573
|
// ==================== Private Helpers ====================
|
|
506
574
|
|
|
507
575
|
/**
|