@lodev09/react-native-true-sheet 4.0.0-beta.1 → 4.0.0-beta.10

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 (221) hide show
  1. package/README.md +25 -4
  2. package/android/build.gradle +22 -1
  3. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +24 -7
  4. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +211 -182
  5. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentViewManager.kt +5 -1
  6. package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterView.kt +14 -19
  7. package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayView.kt +106 -0
  8. package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayViewManager.kt +45 -0
  9. package/android/src/main/java/com/lodev09/truesheet/TrueSheetPackage.kt +2 -1
  10. package/android/src/main/java/com/lodev09/truesheet/TrueSheetStateUpdater.kt +18 -0
  11. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +82 -39
  12. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +275 -88
  13. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +26 -1
  14. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +75 -3
  15. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +56 -34
  16. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetOverlayRootView.kt +137 -0
  17. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetLifecycleEvents.kt +15 -0
  18. package/android/src/main/java/com/lodev09/truesheet/utils/KeyboardUtils.kt +1 -1
  19. package/android/src/main/java/com/lodev09/truesheet/utils/TouchEventDeduper.kt +31 -0
  20. package/android/src/main/java/com/lodev09/truesheet/utils/ViewUtils.kt +19 -7
  21. package/android/src/main/jni/TrueSheetSpec.h +1 -0
  22. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +0 -8
  23. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +54 -29
  24. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h +6 -1
  25. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.cpp +1 -1
  26. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h +6 -4
  27. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.cpp +7 -0
  28. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetLayoutUtils.h +46 -0
  29. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewComponentDescriptor.h +21 -0
  30. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.cpp +17 -0
  31. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.h +36 -0
  32. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +4 -35
  33. package/ios/TrueSheetContainerView.h +14 -7
  34. package/ios/TrueSheetContainerView.mm +10 -7
  35. package/ios/TrueSheetContentView.h +31 -15
  36. package/ios/TrueSheetContentView.mm +133 -179
  37. package/ios/TrueSheetFooterView.h +6 -0
  38. package/ios/TrueSheetFooterView.mm +48 -2
  39. package/ios/TrueSheetModule.h +2 -7
  40. package/ios/TrueSheetModule.mm +7 -16
  41. package/ios/TrueSheetOverlayView.h +32 -0
  42. package/ios/TrueSheetOverlayView.mm +161 -0
  43. package/ios/TrueSheetView.mm +171 -29
  44. package/ios/TrueSheetViewController.h +10 -0
  45. package/ios/TrueSheetViewController.mm +256 -74
  46. package/ios/core/TrueSheetGrabberView.mm +13 -3
  47. package/ios/core/TrueSheetOverlayContainerView.h +31 -0
  48. package/ios/core/TrueSheetOverlayContainerView.mm +35 -0
  49. package/ios/events/TrueSheetLifecycleEvents.h +2 -0
  50. package/ios/events/TrueSheetLifecycleEvents.mm +8 -0
  51. package/ios/tvos/TrueSheetStubs.mm +12 -0
  52. package/ios/utils/UIView+ScrollEdgeInteraction.h +1 -0
  53. package/ios/utils/UIView+ScrollEdgeInteraction.mm +24 -2
  54. package/lib/module/TrueSheet.js +149 -34
  55. package/lib/module/TrueSheet.js.map +1 -1
  56. package/lib/module/TrueSheet.web.js +122 -53
  57. package/lib/module/TrueSheet.web.js.map +1 -1
  58. package/lib/module/TrueSheetOverlay.js +30 -0
  59. package/lib/module/TrueSheetOverlay.js.map +1 -0
  60. package/lib/module/TrueSheetOverlay.web.js +35 -0
  61. package/lib/module/TrueSheetOverlay.web.js.map +1 -0
  62. package/lib/module/TrueSheetPeek.web.js +3 -3
  63. package/lib/module/TrueSheetPeek.web.js.map +1 -1
  64. package/lib/module/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
  65. package/lib/module/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
  66. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +5 -0
  67. package/lib/module/index.js +1 -0
  68. package/lib/module/index.js.map +1 -1
  69. package/lib/module/mocks/index.js +10 -0
  70. package/lib/module/mocks/index.js.map +1 -1
  71. package/lib/module/mocks/navigation.js +31 -21
  72. package/lib/module/mocks/navigation.js.map +1 -1
  73. package/lib/module/mocks/navigationExpoRouter.js +21 -0
  74. package/lib/module/mocks/navigationExpoRouter.js.map +1 -0
  75. package/lib/module/mocks/reanimated.js +1 -1
  76. package/lib/module/mocks/reanimated.js.map +1 -1
  77. package/lib/module/navigation/{TrueSheetView.js → TrueSheetNavigatorContent.js} +14 -12
  78. package/lib/module/navigation/TrueSheetNavigatorContent.js.map +1 -0
  79. package/lib/module/navigation/actions.js +50 -0
  80. package/lib/module/navigation/actions.js.map +1 -0
  81. package/lib/module/navigation/base-types.js +2 -0
  82. package/lib/module/navigation/base-types.js.map +1 -0
  83. package/lib/module/navigation/{TrueSheetRouter.js → createTrueSheetRouter.js} +11 -24
  84. package/lib/module/navigation/createTrueSheetRouter.js.map +1 -0
  85. package/lib/module/navigation/expo-router/base-types.js +2 -0
  86. package/lib/module/navigation/expo-router/base-types.js.map +1 -0
  87. package/lib/module/navigation/expo-router/index.js +50 -0
  88. package/lib/module/navigation/expo-router/index.js.map +1 -0
  89. package/lib/module/navigation/expo-router/types.js +4 -0
  90. package/lib/module/navigation/expo-router/types.js.map +1 -0
  91. package/lib/module/navigation/index.js +43 -2
  92. package/lib/module/navigation/index.js.map +1 -1
  93. package/lib/module/navigation/navigator.js +10 -0
  94. package/lib/module/navigation/navigator.js.map +1 -0
  95. package/lib/module/navigation/screen/ReanimatedTrueSheetScreen.js +2 -2
  96. package/lib/module/navigation/screen/ReanimatedTrueSheetScreen.js.map +1 -1
  97. package/lib/module/navigation/screen/TrueSheetScreen.js +2 -2
  98. package/lib/module/navigation/screen/TrueSheetScreen.js.map +1 -1
  99. package/lib/module/navigation/screen/useSheetScreenState.js +5 -4
  100. package/lib/module/navigation/screen/useSheetScreenState.js.map +1 -1
  101. package/lib/module/navigation/useTrueSheetNavigation.js +1 -1
  102. package/lib/module/navigation/useTrueSheetNavigation.js.map +1 -1
  103. package/lib/module/web/dom.js +10 -0
  104. package/lib/module/web/dom.js.map +1 -0
  105. package/lib/module/web/vaul/constants.js +4 -0
  106. package/lib/module/web/vaul/constants.js.map +1 -1
  107. package/lib/module/web/vaul/context.js.map +1 -1
  108. package/lib/module/web/vaul/helpers.js +10 -4
  109. package/lib/module/web/vaul/helpers.js.map +1 -1
  110. package/lib/module/web/vaul/index.js +35 -2
  111. package/lib/module/web/vaul/index.js.map +1 -1
  112. package/lib/typescript/src/TrueSheet.d.ts +6 -0
  113. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  114. package/lib/typescript/src/TrueSheet.types.d.ts +72 -1
  115. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  116. package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -1
  117. package/lib/typescript/src/TrueSheetOverlay.d.ts +8 -0
  118. package/lib/typescript/src/TrueSheetOverlay.d.ts.map +1 -0
  119. package/lib/typescript/src/TrueSheetOverlay.web.d.ts +8 -0
  120. package/lib/typescript/src/TrueSheetOverlay.web.d.ts.map +1 -0
  121. package/lib/typescript/src/TrueSheetPeek.web.d.ts.map +1 -1
  122. package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts +6 -0
  123. package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts.map +1 -0
  124. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +4 -0
  125. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  126. package/lib/typescript/src/index.d.ts +1 -0
  127. package/lib/typescript/src/index.d.ts.map +1 -1
  128. package/lib/typescript/src/mocks/index.d.ts +4 -0
  129. package/lib/typescript/src/mocks/index.d.ts.map +1 -1
  130. package/lib/typescript/src/mocks/navigation.d.ts +5 -1
  131. package/lib/typescript/src/mocks/navigation.d.ts.map +1 -1
  132. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts +22 -0
  133. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts.map +1 -0
  134. package/lib/typescript/src/mocks/reanimated.d.ts.map +1 -1
  135. package/lib/typescript/src/navigation/TrueSheetNavigatorContent.d.ts +5 -0
  136. package/lib/typescript/src/navigation/TrueSheetNavigatorContent.d.ts.map +1 -0
  137. package/lib/typescript/src/navigation/actions.d.ts +71 -0
  138. package/lib/typescript/src/navigation/actions.d.ts.map +1 -0
  139. package/lib/typescript/src/navigation/base-types.d.ts +9 -0
  140. package/lib/typescript/src/navigation/base-types.d.ts.map +1 -0
  141. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts +3 -0
  142. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts.map +1 -0
  143. package/lib/typescript/src/navigation/expo-router/base-types.d.ts +8 -0
  144. package/lib/typescript/src/navigation/expo-router/base-types.d.ts.map +1 -0
  145. package/lib/typescript/src/navigation/expo-router/index.d.ts +37 -0
  146. package/lib/typescript/src/navigation/expo-router/index.d.ts.map +1 -0
  147. package/lib/typescript/src/navigation/expo-router/types.d.ts +44 -0
  148. package/lib/typescript/src/navigation/expo-router/types.d.ts.map +1 -0
  149. package/lib/typescript/src/navigation/index.d.ts +42 -3
  150. package/lib/typescript/src/navigation/index.d.ts.map +1 -1
  151. package/lib/typescript/src/navigation/navigator.d.ts +7 -0
  152. package/lib/typescript/src/navigation/navigator.d.ts.map +1 -0
  153. package/lib/typescript/src/navigation/screen/ReanimatedTrueSheetScreen.d.ts +1 -1
  154. package/lib/typescript/src/navigation/screen/ReanimatedTrueSheetScreen.d.ts.map +1 -1
  155. package/lib/typescript/src/navigation/screen/TrueSheetScreen.d.ts +1 -1
  156. package/lib/typescript/src/navigation/screen/TrueSheetScreen.d.ts.map +1 -1
  157. package/lib/typescript/src/navigation/screen/types.d.ts +3 -4
  158. package/lib/typescript/src/navigation/screen/types.d.ts.map +1 -1
  159. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts +5 -6
  160. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts.map +1 -1
  161. package/lib/typescript/src/navigation/types.d.ts +65 -5
  162. package/lib/typescript/src/navigation/types.d.ts.map +1 -1
  163. package/lib/typescript/src/navigation/useTrueSheetNavigation.d.ts +1 -1
  164. package/lib/typescript/src/navigation/useTrueSheetNavigation.d.ts.map +1 -1
  165. package/lib/typescript/src/web/dom.d.ts +7 -0
  166. package/lib/typescript/src/web/dom.d.ts.map +1 -0
  167. package/lib/typescript/src/web/vaul/constants.d.ts +1 -0
  168. package/lib/typescript/src/web/vaul/constants.d.ts.map +1 -1
  169. package/lib/typescript/src/web/vaul/context.d.ts +1 -0
  170. package/lib/typescript/src/web/vaul/context.d.ts.map +1 -1
  171. package/lib/typescript/src/web/vaul/helpers.d.ts.map +1 -1
  172. package/lib/typescript/src/web/vaul/index.d.ts +7 -1
  173. package/lib/typescript/src/web/vaul/index.d.ts.map +1 -1
  174. package/package.json +32 -9
  175. package/react-native.config.js +1 -0
  176. package/src/TrueSheet.tsx +184 -46
  177. package/src/TrueSheet.types.ts +77 -1
  178. package/src/TrueSheet.web.tsx +135 -64
  179. package/src/TrueSheetOverlay.tsx +24 -0
  180. package/src/TrueSheetOverlay.web.tsx +33 -0
  181. package/src/TrueSheetPeek.web.tsx +4 -3
  182. package/src/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
  183. package/src/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
  184. package/src/fabric/TrueSheetViewNativeComponent.ts +5 -0
  185. package/src/index.ts +1 -0
  186. package/src/mocks/index.ts +7 -0
  187. package/src/mocks/navigation.ts +32 -25
  188. package/src/mocks/navigationExpoRouter.ts +41 -0
  189. package/src/mocks/reanimated.ts +8 -9
  190. package/src/navigation/{TrueSheetView.tsx → TrueSheetNavigatorContent.tsx} +24 -17
  191. package/src/navigation/actions.ts +78 -0
  192. package/src/navigation/base-types.ts +20 -0
  193. package/src/navigation/createTrueSheetRouter.ts +194 -0
  194. package/src/navigation/expo-router/base-types.ts +18 -0
  195. package/src/navigation/expo-router/index.ts +90 -0
  196. package/src/navigation/expo-router/types.ts +116 -0
  197. package/src/navigation/index.ts +68 -2
  198. package/src/navigation/navigator.ts +18 -0
  199. package/src/navigation/screen/ReanimatedTrueSheetScreen.tsx +2 -2
  200. package/src/navigation/screen/TrueSheetScreen.tsx +2 -2
  201. package/src/navigation/screen/types.ts +4 -6
  202. package/src/navigation/screen/useSheetScreenState.ts +10 -15
  203. package/src/navigation/types.ts +99 -16
  204. package/src/navigation/useTrueSheetNavigation.ts +1 -1
  205. package/src/web/dom.ts +9 -0
  206. package/src/web/vaul/constants.ts +4 -0
  207. package/src/web/vaul/context.ts +1 -0
  208. package/src/web/vaul/helpers.ts +13 -6
  209. package/src/web/vaul/index.tsx +46 -1
  210. package/lib/module/navigation/TrueSheetRouter.js.map +0 -1
  211. package/lib/module/navigation/TrueSheetView.js.map +0 -1
  212. package/lib/module/navigation/createTrueSheetNavigator.js +0 -63
  213. package/lib/module/navigation/createTrueSheetNavigator.js.map +0 -1
  214. package/lib/typescript/src/navigation/TrueSheetRouter.d.ts +0 -57
  215. package/lib/typescript/src/navigation/TrueSheetRouter.d.ts.map +0 -1
  216. package/lib/typescript/src/navigation/TrueSheetView.d.ts +0 -10
  217. package/lib/typescript/src/navigation/TrueSheetView.d.ts.map +0 -1
  218. package/lib/typescript/src/navigation/createTrueSheetNavigator.d.ts +0 -35
  219. package/lib/typescript/src/navigation/createTrueSheetNavigator.d.ts.map +0 -1
  220. package/src/navigation/TrueSheetRouter.ts +0 -234
  221. package/src/navigation/createTrueSheetNavigator.tsx +0 -93
@@ -5,6 +5,7 @@ import com.facebook.react.bridge.ReadableArray
5
5
  import com.facebook.react.bridge.ReadableMap
6
6
  import com.facebook.react.module.annotations.ReactModule
7
7
  import com.facebook.react.uimanager.PixelUtil.dpToPx
8
+ import com.facebook.react.uimanager.PointerEvents
8
9
  import com.facebook.react.uimanager.ReactStylesDiffMap
9
10
  import com.facebook.react.uimanager.StateWrapper
10
11
  import com.facebook.react.uimanager.ThemedReactContext
@@ -55,6 +56,20 @@ class TrueSheetViewManager :
55
56
 
56
57
  override fun getDelegate(): ViewManagerDelegate<TrueSheetView> = delegate
57
58
 
59
+ // The codegen delegate drops props outside the spec (pointerEvents comes from the
60
+ // host's style), so apply it here after the delegate pass.
61
+ override fun updateProperties(viewToUpdate: TrueSheetView, props: ReactStylesDiffMap) {
62
+ super.updateProperties(viewToUpdate, props)
63
+ if (props.hasKey("pointerEvents")) {
64
+ setPointerEvents(viewToUpdate, props.getString("pointerEvents"))
65
+ }
66
+ }
67
+
68
+ @ReactProp(name = "pointerEvents")
69
+ fun setPointerEvents(view: TrueSheetView, pointerEventsStr: String?) {
70
+ view.pointerEvents = PointerEvents.parsePointerEvents(pointerEventsStr)
71
+ }
72
+
58
73
  /**
59
74
  * Export custom direct event types for Fabric
60
75
  * Uses Kotlin native collections with decoupled event classes
@@ -66,6 +81,7 @@ class TrueSheetViewManager :
66
81
  DidPresentEvent.EVENT_NAME to hashMapOf("registrationName" to DidPresentEvent.REGISTRATION_NAME),
67
82
  WillDismissEvent.EVENT_NAME to hashMapOf("registrationName" to WillDismissEvent.REGISTRATION_NAME),
68
83
  DidDismissEvent.EVENT_NAME to hashMapOf("registrationName" to DidDismissEvent.REGISTRATION_NAME),
84
+ DismissAttemptEvent.EVENT_NAME to hashMapOf("registrationName" to DismissAttemptEvent.REGISTRATION_NAME),
69
85
  DetentChangeEvent.EVENT_NAME to hashMapOf("registrationName" to DetentChangeEvent.REGISTRATION_NAME),
70
86
  DragBeginEvent.EVENT_NAME to hashMapOf("registrationName" to DragBeginEvent.REGISTRATION_NAME),
71
87
  DragChangeEvent.EVENT_NAME to hashMapOf("registrationName" to DragChangeEvent.REGISTRATION_NAME),
@@ -179,6 +195,7 @@ class TrueSheetViewManager :
179
195
  @ReactProp(name = "initialDetentIndex", defaultInt = -1)
180
196
  override fun setInitialDetentIndex(view: TrueSheetView, index: Int) {
181
197
  view.initialDetentIndex = index
198
+ view.presentInitialIfNeeded()
182
199
  }
183
200
 
184
201
  @ReactProp(name = "initialDetentAnimated", defaultBoolean = true)
@@ -231,6 +248,11 @@ class TrueSheetViewManager :
231
248
  view.setSheetElevation(elevation.toFloat())
232
249
  }
233
250
 
251
+ @ReactProp(name = "scrollableHandle", defaultInt = -1)
252
+ override fun setScrollableHandle(view: TrueSheetView, handle: Int) {
253
+ view.setScrollableHandle(handle)
254
+ }
255
+
234
256
  @ReactProp(name = "scrollableOptions")
235
257
  override fun setScrollableOptions(view: TrueSheetView, options: ReadableMap?) {
236
258
  if (options == null) {
@@ -240,7 +262,10 @@ class TrueSheetViewManager :
240
262
 
241
263
  val scrollableOptions = ScrollableOptions(
242
264
  keyboardScrollOffset = if (options.hasKey("keyboardScrollOffset")) options.getDouble("keyboardScrollOffset").toFloat() else 0f,
243
- scrollingExpandsSheet = if (options.hasKey("scrollingExpandsSheet")) options.getBoolean("scrollingExpandsSheet") else true
265
+ keyboardOffset = if (options.hasKey("keyboardOffset")) options.getDouble("keyboardOffset").toFloat() else 0f,
266
+ scrollingExpandsSheet = if (options.hasKey("scrollingExpandsSheet")) options.getBoolean("scrollingExpandsSheet") else true,
267
+ contentInsetAdjustment = !options.hasKey("contentInsetAdjustmentBehavior") ||
268
+ options.getBoolean("contentInsetAdjustmentBehavior")
244
269
  )
245
270
  view.setScrollableOptions(scrollableOptions)
246
271
  }
@@ -10,9 +10,11 @@ import android.view.ViewGroup
10
10
  import android.widget.EditText
11
11
  import androidx.coordinatorlayout.widget.CoordinatorLayout
12
12
  import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
13
+ import com.facebook.react.uimanager.PixelUtil.dpToPx
13
14
  import com.facebook.react.uimanager.PointerEvents
14
15
  import com.facebook.react.uimanager.ReactPointerEventsView
15
16
  import com.facebook.react.uimanager.TouchTargetHelper
17
+ import com.lodev09.truesheet.utils.KeyboardUtils
16
18
  import com.lodev09.truesheet.utils.isDescendantOf
17
19
 
18
20
  interface TrueSheetCoordinatorLayoutDelegate {
@@ -20,6 +22,12 @@ interface TrueSheetCoordinatorLayoutDelegate {
20
22
  fun coordinatorLayoutDidChangeConfiguration()
21
23
  fun findScrollView(): ViewGroup?
22
24
  fun findSheetView(): TrueSheetBottomSheetView?
25
+
26
+ /**
27
+ * A downward pull the sheet couldn't follow ended; `overdragPx` is the travel it
28
+ * didn't follow, `keyboardWasVisible` whether the keyboard was up when it began.
29
+ */
30
+ fun coordinatorLayoutDidPullDown(overdragPx: Int, keyboardWasVisible: Boolean)
23
31
  }
24
32
 
25
33
  /**
@@ -57,7 +65,7 @@ class TrueSheetCoordinatorLayout(context: Context) :
57
65
  private var streamGestureClaimed = false
58
66
 
59
67
  // Whether the sheet owns vertical drags for this stream: the touch target is inside
60
- // the sheet but outside the pinned scrollable (e.g. a header overlaying it), with
68
+ // the sheet but outside the detected scrollable (e.g. a header overlaying it), with
61
69
  // nothing vertically scrollable along its chain. Such targets consume the stream
62
70
  // natively (no nested scroll), and BottomSheetBehavior won't intercept because the
63
71
  // scrollable's bounds still contain the point (touchingScrollingChild) — intercept
@@ -65,6 +73,18 @@ class TrueSheetCoordinatorLayout(context: Context) :
65
73
  private var streamSheetDraggable = false
66
74
  private var streamDraggableEditText = false
67
75
 
76
+ // Pull-down tracking. BottomSheetBehavior gives no callback when a downward drag
77
+ // is clamped by `isHideable = false` — the sheet stays put (or the scrollable
78
+ // overscrolls) and no state change fires. Accumulate the downward finger travel
79
+ // neither the sheet nor its scrollable followed and report it on release so the
80
+ // controller can surface a blocked dismiss attempt.
81
+ private var pullTracking = false
82
+ private var pullStartX = 0f
83
+ private var pullStartY = 0f
84
+ private var pullLastY = 0f
85
+ private var pullOverdrag = 0f
86
+ private var pullKeyboardVisible = false
87
+
68
88
  init {
69
89
  layoutParams = LayoutParams(
70
90
  LayoutParams.MATCH_PARENT,
@@ -94,6 +114,49 @@ class TrueSheetCoordinatorLayout(context: Context) :
94
114
  override val pointerEvents: PointerEvents
95
115
  get() = PointerEvents.BOX_NONE
96
116
 
117
+ override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
118
+ when (ev.actionMasked) {
119
+ MotionEvent.ACTION_DOWN -> {
120
+ val sheet = delegate?.findSheetView()
121
+ pullTracking = sheet != null && isTouchInside(sheet, ev)
122
+ pullStartX = ev.rawX
123
+ pullStartY = ev.rawY
124
+ pullLastY = ev.rawY
125
+ pullOverdrag = 0f
126
+ pullKeyboardVisible = pullTracking && KeyboardUtils.isKeyboardVisible(this)
127
+ }
128
+
129
+ MotionEvent.ACTION_MOVE -> if (pullTracking) {
130
+ val sheet = delegate?.findSheetView()
131
+ val topBefore = sheet?.top
132
+ val handled = super.dispatchTouchEvent(ev)
133
+ val step = ev.rawY - pullLastY
134
+ pullLastY = ev.rawY
135
+ // Finger moved down but the sheet stayed put and the scrollable is at
136
+ // its top — the pull was clamped
137
+ if (step > 0 && sheet != null && sheet.top == topBefore && delegate?.findScrollView()?.canScrollVertically(-1) != true) {
138
+ pullOverdrag += step
139
+ }
140
+ return handled
141
+ }
142
+
143
+ MotionEvent.ACTION_UP -> if (pullTracking) {
144
+ pullTracking = false
145
+ val dx = kotlin.math.abs(ev.rawX - pullStartX)
146
+ val dy = ev.rawY - pullStartY
147
+ // Let the behavior settle first so the controller sees the resting position.
148
+ val handled = super.dispatchTouchEvent(ev)
149
+ if (dy > dx && pullOverdrag > PULL_DOWN_THRESHOLD_DP.dpToPx()) {
150
+ delegate?.coordinatorLayoutDidPullDown(pullOverdrag.toInt(), pullKeyboardVisible)
151
+ }
152
+ return handled
153
+ }
154
+
155
+ MotionEvent.ACTION_CANCEL -> pullTracking = false
156
+ }
157
+ return super.dispatchTouchEvent(ev)
158
+ }
159
+
97
160
  /**
98
161
  * Clears stale `nestedScrollingChildRef` from BottomSheetBehavior.
99
162
  *
@@ -127,7 +190,7 @@ class TrueSheetCoordinatorLayout(context: Context) :
127
190
 
128
191
  /**
129
192
  * Resolves the stream's touch target (respecting zIndex and pointerEvents) and
130
- * decides whether the sheet may drag from it — inside the sheet, outside the pinned
193
+ * decides whether the sheet may drag from it — inside the sheet, outside the detected
131
194
  * scrollable, and nothing along the target's chain scrolls vertically.
132
195
  */
133
196
  private fun updateStreamTargetFlags(ev: MotionEvent) {
@@ -139,7 +202,7 @@ class TrueSheetCoordinatorLayout(context: Context) :
139
202
  .firstNotNullOfOrNull { it.getView() } ?: return
140
203
  if (target !== sheet && !target.isDescendantOf(sheet)) return
141
204
 
142
- // A pinned scrollable that can scroll (or hosts pull-to-refresh) owns its
205
+ // A detected scrollable that can scroll (or hosts pull-to-refresh) owns its
143
206
  // touches — nested scrolling drags the sheet. When it can't scroll (e.g.
144
207
  // the sheet is fully expanded and the content fits) it eats the gesture
145
208
  // instead, so fall through and let the sheet drag from it — an EditText
@@ -160,6 +223,14 @@ class TrueSheetCoordinatorLayout(context: Context) :
160
223
  streamDraggableEditText = target is EditText
161
224
  }
162
225
 
226
+ private fun isTouchInside(view: View, ev: MotionEvent): Boolean {
227
+ val loc = IntArray(2)
228
+ view.getLocationOnScreen(loc)
229
+ val x = ev.rawX.toInt()
230
+ val y = ev.rawY.toInt()
231
+ return x >= loc[0] && x <= loc[0] + view.width && y >= loc[1] && y <= loc[1] + view.height
232
+ }
233
+
163
234
  private fun findDescendantViewAt(view: View, rawX: Int, rawY: Int, predicate: (View) -> Boolean): View? {
164
235
  val loc = IntArray(2)
165
236
  view.getLocationOnScreen(loc)
@@ -299,5 +370,6 @@ class TrueSheetCoordinatorLayout(context: Context) :
299
370
  companion object {
300
371
  private const val GESTURE_HANDLER_ROOT_VIEW_CLASS = "com.swmansion.gesturehandler.react.RNGestureHandlerRootView"
301
372
  private const val GESTURE_CLAIM_SLOP_FACTOR = 3
373
+ private const val PULL_DOWN_THRESHOLD_DP = 24f
302
374
  }
303
375
  }
@@ -23,6 +23,13 @@ interface TrueSheetDetentCalculatorDelegate {
23
23
  val maxContentHeight: Int?
24
24
  val keyboardInset: Int
25
25
  val topInset: Int
26
+
27
+ /**
28
+ * True while the keyboard holds the sheet up: the collapsed stop then sits at
29
+ * the keyboard-free first detent (the "floor") so a drag-down dismisses the
30
+ * keyboard before it can dismiss the sheet.
31
+ */
32
+ val hasKeyboardFloor: Boolean
26
33
  }
27
34
 
28
35
  /**
@@ -44,6 +51,7 @@ class TrueSheetDetentCalculator(private val reactContext: ThemedReactContext) {
44
51
  private val maxContentHeight: Int? get() = delegate?.maxContentHeight
45
52
  private val keyboardInset: Int get() = delegate?.keyboardInset ?: 0
46
53
  private val topInset: Int get() = delegate?.topInset ?: 0
54
+ private val hasKeyboardFloor: Boolean get() = delegate?.hasKeyboardFloor == true
47
55
 
48
56
  /**
49
57
  * Height for auto (-1.0) detents: content + header + footer height.
@@ -110,12 +118,31 @@ class TrueSheetDetentCalculator(private val reactContext: ThemedReactContext) {
110
118
  RNLog.w(reactContext, "TrueSheet: Detent index ($index) is out of bounds (0..${detents.size - 1})")
111
119
  return realScreenHeight
112
120
  }
113
- // Clamp to the space the sheet can actually occupymatching
114
- // setupSheetDetents. A keyboard-inflated detent height can exceed it,
115
- // placing the expected top above the screen while the real sheet stops
116
- // at the top inset.
121
+ // With a keyboard floor only the last detent stays keyboard-shiftedit's
122
+ // the keyboard-expanded resting position; the stops below it are keyboard-free
123
+ val isKeyboardFreeStop = hasKeyboardFloor && index != detents.size - 1
124
+ return getSheetTop(detents[index], includeKeyboard = !isKeyboardFreeStop)
125
+ }
126
+
127
+ /**
128
+ * Top of the lowest stop the sheet can rest at: the keyboard floor while it's
129
+ * active, else the first detent.
130
+ */
131
+ fun getLowestSheetTop(): Int = if (hasKeyboardFloor) getSheetTop(detents[0], includeKeyboard = false) else getSheetTopForDetentIndex(0)
132
+
133
+ /**
134
+ * Top of the half stop while the keyboard floor is active: the keyboard-free
135
+ * second detent, or the floor itself for a single detent.
136
+ */
137
+ fun getKeyboardHalfStopTop(): Int = getSheetTop(detents[minOf(1, detents.size - 1)], includeKeyboard = false)
138
+
139
+ // Clamp to the space the sheet can actually occupy — matching
140
+ // setupSheetDetents. A keyboard-inflated detent height can exceed it,
141
+ // placing the expected top above the screen while the real sheet stops
142
+ // at the top inset.
143
+ private fun getSheetTop(detent: Double, includeKeyboard: Boolean = true): Int {
117
144
  val maxAvailableHeight = realScreenHeight - topInset
118
- return realScreenHeight - minOf(getDetentHeight(detents[index]), maxAvailableHeight)
145
+ return realScreenHeight - minOf(getDetentHeight(detent, includeKeyboard), maxAvailableHeight)
119
146
  }
120
147
 
121
148
  /**
@@ -152,6 +179,9 @@ class TrueSheetDetentCalculator(private val reactContext: ThemedReactContext) {
152
179
  */
153
180
  fun getStateForDetentIndex(index: Int): Int {
154
181
  val stateMap = getDetentStateMap() ?: return BottomSheetBehavior.STATE_HIDDEN
182
+ // With a keyboard floor the keyboard-expanded last detent lives at the
183
+ // expanded stop — the half stop (which may share its index) is keyboard-free
184
+ if (hasKeyboardFloor && index == detents.size - 1) return BottomSheetBehavior.STATE_EXPANDED
155
185
  return stateMap.entries.find { it.value == index }?.key ?: BottomSheetBehavior.STATE_HIDDEN
156
186
  }
157
187
 
@@ -169,8 +199,12 @@ class TrueSheetDetentCalculator(private val reactContext: ThemedReactContext) {
169
199
  */
170
200
  private fun getDetentStateMap(): Map<Int, Int>? =
171
201
  when (detents.size) {
202
+ // With one detent halfExpandedRatio matches the peek height, so the
203
+ // behavior can settle HALF_EXPANDED at the same position (e.g. an upward
204
+ // drag release) — map it too, or the settle is unmappable
172
205
  1 -> mapOf(
173
206
  BottomSheetBehavior.STATE_COLLAPSED to 0,
207
+ BottomSheetBehavior.STATE_HALF_EXPANDED to 0,
174
208
  BottomSheetBehavior.STATE_EXPANDED to 0
175
209
  )
176
210
 
@@ -197,16 +231,18 @@ class TrueSheetDetentCalculator(private val reactContext: ThemedReactContext) {
197
231
  * Find which segment the position falls into for interpolation.
198
232
  * @return Triple(fromIndex, toIndex, progress) where progress is 0-1, or null if no detents
199
233
  */
200
- fun findSegmentForPosition(positionPx: Int): Triple<Int, Int, Float>? {
234
+ private fun findSegmentForPosition(positionPx: Int): Triple<Int, Int, Float>? {
201
235
  val count = detents.size
202
236
  if (count == 0) return null
203
237
 
204
- val firstPos = getSheetTopForDetentIndex(0)
238
+ // A single keyboard-shifted detent can rest down at its keyboard floor —
239
+ // that range is still index 0, not a dismissal
240
+ val floorPos = getLowestSheetTop()
205
241
 
206
- // Position is below first detent (sheet is being dragged down to dismiss)
207
- if (positionPx > firstPos) {
208
- val range = realScreenHeight - firstPos
209
- val progress = if (range > 0) (positionPx - firstPos).toFloat() / range else 0f
242
+ // Position is below the lowest stop (sheet is being dragged down to dismiss)
243
+ if (positionPx > floorPos) {
244
+ val range = realScreenHeight - floorPos
245
+ val progress = if (range > 0) (positionPx - floorPos).toFloat() / range else 0f
210
246
  return Triple(-1, 0, progress)
211
247
  }
212
248
 
@@ -238,37 +274,23 @@ class TrueSheetDetentCalculator(private val reactContext: ThemedReactContext) {
238
274
  }
239
275
 
240
276
  /**
241
- * Returns continuous index (e.g., 0.5 = halfway between detent 0 and 1).
277
+ * Returns interpolated continuous index (e.g., 0.5 = halfway between detent
278
+ * 0 and 1) and screen fraction for a position, sharing a single segment
279
+ * lookup — this runs on every position frame.
242
280
  */
243
- fun getInterpolatedIndexForPosition(positionPx: Int): Float {
244
- val count = detents.size
245
- if (count == 0) return -1f
246
-
247
- val segment = findSegmentForPosition(positionPx) ?: return 0f
248
- val (fromIndex, _, progress) = segment
249
-
250
- if (fromIndex == -1) return -progress
251
- return fromIndex + progress
252
- }
253
-
254
- /**
255
- * Returns interpolated screen fraction for position.
256
- */
257
- fun getInterpolatedDetentForPosition(positionPx: Int): Float {
258
- val count = detents.size
259
- if (count == 0) return 0f
281
+ fun getInterpolatedPositionInfo(positionPx: Int): Pair<Float, Float> {
282
+ if (detents.isEmpty()) return Pair(-1f, 0f)
260
283
 
261
- val segment = findSegmentForPosition(positionPx) ?: return getDetentValueForIndex(0)
262
- val (fromIndex, toIndex, progress) = segment
284
+ val (fromIndex, toIndex, progress) = findSegmentForPosition(positionPx)
285
+ ?: return Pair(0f, getDetentValueForIndex(0))
263
286
 
264
287
  if (fromIndex == -1) {
265
- val firstDetent = getDetentValueForIndex(0)
266
- return maxOf(0f, firstDetent * (1 - progress))
288
+ return Pair(-progress, maxOf(0f, getDetentValueForIndex(0) * (1 - progress)))
267
289
  }
268
290
 
269
291
  val fromDetent = getDetentValueForIndex(fromIndex)
270
292
  val toDetent = getDetentValueForIndex(toIndex)
271
- return fromDetent + progress * (toDetent - fromDetent)
293
+ return Pair(fromIndex + progress, fromDetent + progress * (toDetent - fromDetent))
272
294
  }
273
295
 
274
296
  companion object {
@@ -0,0 +1,137 @@
1
+ package com.lodev09.truesheet.core
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.view.MotionEvent
5
+ import android.view.View
6
+ import android.widget.FrameLayout
7
+ import com.facebook.react.uimanager.JSPointerDispatcher
8
+ import com.facebook.react.uimanager.JSTouchDispatcher
9
+ import com.facebook.react.uimanager.RootView
10
+ import com.facebook.react.uimanager.ThemedReactContext
11
+ import com.facebook.react.uimanager.TouchTargetHelper
12
+ import com.facebook.react.uimanager.events.EventDispatcher
13
+ import com.lodev09.truesheet.utils.TouchEventDeduper
14
+
15
+ interface TrueSheetOverlayRootViewDelegate {
16
+ val eventDispatcher: EventDispatcher?
17
+ fun overlayRootViewDidChangeSize(width: Int, height: Int)
18
+ }
19
+
20
+ /**
21
+ * Window-level view hosting an overlay's children, attached to the activity's
22
+ * content view above the sheet coordinators.
23
+ *
24
+ * Implements RootView to dispatch touches to JS. Touches that miss every child
25
+ * fall through to the views beneath.
26
+ */
27
+ @SuppressLint("ViewConstructor")
28
+ class TrueSheetOverlayRootView(private val reactContext: ThemedReactContext) :
29
+ FrameLayout(reactContext),
30
+ RootView {
31
+
32
+ var delegate: TrueSheetOverlayRootViewDelegate? = null
33
+
34
+ private val eventDispatcher: EventDispatcher?
35
+ get() = delegate?.eventDispatcher
36
+
37
+ private val jsTouchDispatcher = JSTouchDispatcher(this)
38
+ private val jsPointerDispatcher = JSPointerDispatcher(this)
39
+ private val touchDeduper = TouchEventDeduper()
40
+
41
+ // Whether the current touch stream landed on a child
42
+ private var isHandlingStream = false
43
+
44
+ init {
45
+ layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
46
+
47
+ // Draws and receives touches above the sheet coordinators regardless of add order
48
+ translationZ = OVERLAY_Z
49
+ }
50
+
51
+ // Children are positioned by Fabric — a FrameLayout pass would stretch them to match_parent
52
+ override fun onLayout(
53
+ changed: Boolean,
54
+ left: Int,
55
+ top: Int,
56
+ right: Int,
57
+ bottom: Int
58
+ ) {
59
+ }
60
+
61
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
62
+ super.onSizeChanged(w, h, oldw, oldh)
63
+ delegate?.overlayRootViewDidChangeSize(w, h)
64
+ }
65
+
66
+ override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
67
+ if (ev.actionMasked == MotionEvent.ACTION_DOWN) {
68
+ // The path ends with this root, so a touch that misses every child resolves to it
69
+ val target = TouchTargetHelper
70
+ .findTargetPathAndCoordinatesForTouch(ev.x, ev.y, this, FloatArray(2))
71
+ .firstNotNullOfOrNull { it.getView() }
72
+ isHandlingStream = target != null && target !== this
73
+ }
74
+ if (!isHandlingStream) return false
75
+ return super.dispatchTouchEvent(ev)
76
+ }
77
+
78
+ // ==================== RootView Implementation ====================
79
+
80
+ override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
81
+ eventDispatcher?.let { dispatcher ->
82
+ if (touchDeduper.shouldDispatch(event)) {
83
+ jsTouchDispatcher.handleTouchEvent(event, dispatcher, reactContext)
84
+ }
85
+ jsPointerDispatcher.handleMotionEvent(event, dispatcher, true)
86
+ }
87
+ return super.onInterceptTouchEvent(event)
88
+ }
89
+
90
+ override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
91
+ // Mirrors ReactSurfaceView: keep receiving onInterceptTouchEvent so
92
+ // jsTouchDispatcher sees the gesture end, but forward the request up the tree.
93
+ parent?.requestDisallowInterceptTouchEvent(disallowIntercept)
94
+ }
95
+
96
+ @SuppressLint("ClickableViewAccessibility")
97
+ override fun onTouchEvent(event: MotionEvent): Boolean {
98
+ eventDispatcher?.let { dispatcher ->
99
+ if (touchDeduper.shouldDispatch(event)) {
100
+ jsTouchDispatcher.handleTouchEvent(event, dispatcher, reactContext)
101
+ }
102
+ jsPointerDispatcher.handleMotionEvent(event, dispatcher, false)
103
+ }
104
+ super.onTouchEvent(event)
105
+ return true
106
+ }
107
+
108
+ override fun onInterceptHoverEvent(event: MotionEvent): Boolean {
109
+ eventDispatcher?.let { jsPointerDispatcher.handleMotionEvent(event, it, true) }
110
+ return super.onHoverEvent(event)
111
+ }
112
+
113
+ override fun onHoverEvent(event: MotionEvent): Boolean {
114
+ eventDispatcher?.let { jsPointerDispatcher.handleMotionEvent(event, it, false) }
115
+ return super.onHoverEvent(event)
116
+ }
117
+
118
+ override fun onChildStartedNativeGesture(childView: View?, ev: MotionEvent) {
119
+ eventDispatcher?.let { dispatcher ->
120
+ jsTouchDispatcher.onChildStartedNativeGesture(ev, dispatcher)
121
+ jsPointerDispatcher.onChildStartedNativeGesture(childView, ev, dispatcher)
122
+ }
123
+ }
124
+
125
+ override fun onChildEndedNativeGesture(childView: View, ev: MotionEvent) {
126
+ eventDispatcher?.let { jsTouchDispatcher.onChildEndedNativeGesture(ev, it) }
127
+ jsPointerDispatcher.onChildEndedNativeGesture()
128
+ }
129
+
130
+ override fun handleException(t: Throwable) {
131
+ reactContext.reactApplicationContext.handleException(RuntimeException(t))
132
+ }
133
+
134
+ companion object {
135
+ private const val OVERLAY_Z = 1000f
136
+ }
137
+ }
@@ -93,6 +93,21 @@ class DidDismissEvent(surfaceId: Int, viewId: Int) : Event<DidDismissEvent>(surf
93
93
  }
94
94
  }
95
95
 
96
+ /**
97
+ * Fired when the user tries to dismiss a non-dismissible sheet
98
+ */
99
+ class DismissAttemptEvent(surfaceId: Int, viewId: Int) : Event<DismissAttemptEvent>(surfaceId, viewId) {
100
+
101
+ override fun getEventName(): String = EVENT_NAME
102
+
103
+ override fun getEventData(): WritableMap = Arguments.createMap()
104
+
105
+ companion object {
106
+ const val EVENT_NAME = "topDismissAttempt"
107
+ const val REGISTRATION_NAME = "onDismissAttempt"
108
+ }
109
+ }
110
+
96
111
  /**
97
112
  * Fired when the sheet visibility changes due to screen transitions
98
113
  */
@@ -19,7 +19,7 @@ object KeyboardUtils {
19
19
  return isKeyboardVisible(rootView)
20
20
  }
21
21
 
22
- private fun isKeyboardVisible(view: View): Boolean {
22
+ fun isKeyboardVisible(view: View): Boolean {
23
23
  val insets = ViewCompat.getRootWindowInsets(view) ?: return false
24
24
  return insets.isVisible(WindowInsetsCompat.Type.ime())
25
25
  }
@@ -0,0 +1,31 @@
1
+ package com.lodev09.truesheet.utils
2
+
3
+ import android.view.MotionEvent
4
+
5
+ /**
6
+ * Guards a nested RootView against dispatching the same [MotionEvent] to JS twice.
7
+ *
8
+ * An event that no child consumes reaches both `onInterceptTouchEvent` and `onTouchEvent`,
9
+ * so dispatching from both starts a second JS touch stream for the same gesture.
10
+ *
11
+ * A plain root can live with that, but the sheet's roots are nested: touches that hit no
12
+ * React child resolve to the root's own tag, and the second stream then finds that view
13
+ * already holding the responder, so React only asks its ancestors - handing the touch to
14
+ * touchables outside the sheet.
15
+ */
16
+ internal class TouchEventDeduper {
17
+ private var downTime = Long.MIN_VALUE
18
+ private var eventTime = Long.MIN_VALUE
19
+ private var action = -1
20
+
21
+ fun shouldDispatch(event: MotionEvent): Boolean {
22
+ if (event.downTime == downTime && event.eventTime == eventTime && event.action == action) {
23
+ return false
24
+ }
25
+
26
+ downTime = event.downTime
27
+ eventTime = event.eventTime
28
+ action = event.action
29
+ return true
30
+ }
31
+ }
@@ -2,8 +2,10 @@ package com.lodev09.truesheet.utils
2
2
 
3
3
  import android.view.View
4
4
  import android.view.ViewGroup
5
+ import android.view.ViewParent
5
6
  import android.widget.ScrollView
6
7
  import androidx.core.widget.NestedScrollView
8
+ import com.facebook.react.uimanager.ThemedReactContext
7
9
 
8
10
  fun View.isDescendantOf(ancestor: View): Boolean {
9
11
  if (!isAttachedToWindow) return false
@@ -15,16 +17,26 @@ fun View.isDescendantOf(ancestor: View): Boolean {
15
17
  return false
16
18
  }
17
19
 
18
- fun ViewGroup.smoothScrollBy(dx: Int, dy: Int) {
19
- when (this) {
20
- is ScrollView -> smoothScrollBy(dx, dy)
21
- is NestedScrollView -> smoothScrollBy(dx, dy)
22
- }
23
- }
24
-
25
20
  fun ViewGroup.smoothScrollTo(x: Int, y: Int) {
26
21
  when (this) {
27
22
  is ScrollView -> smoothScrollTo(x, y)
28
23
  is NestedScrollView -> smoothScrollTo(x, y)
29
24
  }
30
25
  }
26
+
27
+ /**
28
+ * The content view hosting this view — the activity's, or a Modal dialog's.
29
+ * Window-level views (sheet coordinators, overlays) attach here.
30
+ */
31
+ fun View.findRootContainerView(reactContext: ThemedReactContext): ViewGroup? {
32
+ var current: ViewParent? = parent
33
+
34
+ while (current != null) {
35
+ if (current is ViewGroup && current.id == android.R.id.content) {
36
+ return current
37
+ }
38
+ current = current.parent
39
+ }
40
+
41
+ return reactContext.currentActivity?.findViewById(android.R.id.content)
42
+ }
@@ -5,6 +5,7 @@
5
5
  #include <jsi/jsi.h>
6
6
  #include <react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h>
7
7
  #include <react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h>
8
+ #include <react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewComponentDescriptor.h>
8
9
  #include <react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h>
9
10
 
10
11
  namespace facebook {
@@ -11,14 +11,6 @@ namespace facebook::react {
11
11
  class TrueSheetContentViewComponentDescriptor final
12
12
  : public ConcreteComponentDescriptor<TrueSheetContentViewShadowNode> {
13
13
  using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
14
-
15
- void adopt(ShadowNode &shadowNode) const override {
16
- auto &concreteShadowNode =
17
- static_cast<TrueSheetContentViewShadowNode &>(shadowNode);
18
- concreteShadowNode.adjustLayoutWithState();
19
-
20
- ConcreteComponentDescriptor::adopt(shadowNode);
21
- }
22
14
  };
23
15
 
24
16
  } // namespace facebook::react