@lodev09/react-native-true-sheet 4.0.0-beta.3 → 4.0.0-beta.30

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 (244) hide show
  1. package/README.md +28 -5
  2. package/android/build.gradle +23 -1
  3. package/android/proguard-rules.pro +3 -0
  4. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +50 -16
  5. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +303 -184
  6. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentViewManager.kt +5 -1
  7. package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterView.kt +38 -109
  8. package/android/src/main/java/com/lodev09/truesheet/TrueSheetModule.kt +13 -0
  9. package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayView.kt +127 -0
  10. package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayViewManager.kt +45 -0
  11. package/android/src/main/java/com/lodev09/truesheet/TrueSheetPackage.kt +2 -1
  12. package/android/src/main/java/com/lodev09/truesheet/TrueSheetStateUpdater.kt +29 -3
  13. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +234 -66
  14. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +491 -186
  15. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +64 -10
  16. package/android/src/main/java/com/lodev09/truesheet/core/RNScreensEventObserver.kt +31 -14
  17. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetBehavior.kt +135 -0
  18. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +23 -23
  19. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +130 -6
  20. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +104 -39
  21. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDimView.kt +14 -17
  22. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetGrabberView.kt +2 -4
  23. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetOverlayRootView.kt +148 -0
  24. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetStackManager.kt +33 -40
  25. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetLifecycleEvents.kt +15 -0
  26. package/android/src/main/java/com/lodev09/truesheet/utils/ColorUtils.kt +19 -0
  27. package/android/src/main/java/com/lodev09/truesheet/utils/KeyboardUtils.kt +15 -2
  28. package/android/src/main/java/com/lodev09/truesheet/utils/ScreenUtils.kt +0 -12
  29. package/android/src/main/java/com/lodev09/truesheet/utils/ViewUtils.kt +19 -7
  30. package/android/src/main/jni/TrueSheetSpec.h +1 -0
  31. package/android/src/main/jni/TrueSheetStateUpdater.cpp +37 -6
  32. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +1 -9
  33. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +114 -30
  34. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h +30 -7
  35. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.cpp +2 -2
  36. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h +9 -8
  37. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h +3 -5
  38. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.cpp +14 -3
  39. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.h +5 -6
  40. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.cpp +1 -1
  41. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.h +10 -6
  42. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.cpp +1 -1
  43. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.h +1 -1
  44. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetLayoutUtils.h +43 -0
  45. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewComponentDescriptor.h +21 -0
  46. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.cpp +17 -0
  47. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.h +33 -0
  48. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h +3 -5
  49. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +7 -40
  50. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h +3 -7
  51. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.cpp +3 -5
  52. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.h +4 -5
  53. package/ios/TrueSheetContainerView.h +23 -7
  54. package/ios/TrueSheetContainerView.mm +45 -25
  55. package/ios/TrueSheetContentView.h +44 -15
  56. package/ios/TrueSheetContentView.mm +221 -190
  57. package/ios/TrueSheetFooterView.mm +133 -28
  58. package/ios/TrueSheetModule.h +2 -7
  59. package/ios/TrueSheetModule.mm +18 -18
  60. package/ios/TrueSheetOverlayView.h +42 -0
  61. package/ios/TrueSheetOverlayView.mm +175 -0
  62. package/ios/TrueSheetView.h +2 -0
  63. package/ios/TrueSheetView.mm +268 -52
  64. package/ios/TrueSheetViewController.h +36 -3
  65. package/ios/TrueSheetViewController.mm +797 -102
  66. package/ios/core/RNScreensEventObserver.mm +31 -28
  67. package/ios/core/TrueSheetBlurView.h +0 -2
  68. package/ios/core/TrueSheetBlurView.mm +3 -36
  69. package/ios/core/TrueSheetDetentCalculator.h +18 -1
  70. package/ios/core/TrueSheetDetentCalculator.mm +44 -9
  71. package/ios/core/TrueSheetDimView.h +27 -0
  72. package/ios/core/TrueSheetDimView.mm +41 -0
  73. package/ios/core/TrueSheetGrabberView.mm +13 -3
  74. package/ios/core/TrueSheetKeyboardObserver.h +7 -0
  75. package/ios/core/TrueSheetKeyboardObserver.mm +107 -15
  76. package/ios/core/TrueSheetOverlayContainerView.h +31 -0
  77. package/ios/core/TrueSheetOverlayContainerView.mm +35 -0
  78. package/ios/events/TrueSheetLifecycleEvents.h +2 -0
  79. package/ios/events/TrueSheetLifecycleEvents.mm +8 -0
  80. package/ios/tvos/TrueSheetStubs.mm +12 -0
  81. package/ios/utils/UIView+ScrollEdgeInteraction.h +1 -0
  82. package/ios/utils/UIView+ScrollEdgeInteraction.mm +24 -2
  83. package/lib/module/TrueSheet.js +222 -54
  84. package/lib/module/TrueSheet.js.map +1 -1
  85. package/lib/module/TrueSheet.web.js +364 -275
  86. package/lib/module/TrueSheet.web.js.map +1 -1
  87. package/lib/module/TrueSheetBackground.js +15 -0
  88. package/lib/module/TrueSheetBackground.js.map +1 -0
  89. package/lib/module/TrueSheetOverlay.js +30 -0
  90. package/lib/module/TrueSheetOverlay.js.map +1 -0
  91. package/lib/module/TrueSheetOverlay.web.js +35 -0
  92. package/lib/module/TrueSheetOverlay.web.js.map +1 -0
  93. package/lib/module/TrueSheetPeek.web.js +20 -15
  94. package/lib/module/TrueSheetPeek.web.js.map +1 -1
  95. package/lib/module/TrueSheetProvider.web.js +13 -9
  96. package/lib/module/TrueSheetProvider.web.js.map +1 -1
  97. package/lib/module/detentBackgrounds.js +21 -0
  98. package/lib/module/detentBackgrounds.js.map +1 -0
  99. package/lib/module/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
  100. package/lib/module/fabric/TrueSheetFooterViewNativeComponent.ts +2 -3
  101. package/lib/module/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
  102. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +89 -73
  103. package/lib/module/index.js +1 -0
  104. package/lib/module/index.js.map +1 -1
  105. package/lib/module/mocks/index.js +18 -2
  106. package/lib/module/mocks/index.js.map +1 -1
  107. package/lib/module/mocks/navigationExpoRouter.js.map +1 -1
  108. package/lib/module/navigation/base-types.js +2 -0
  109. package/lib/module/navigation/base-types.js.map +1 -0
  110. package/lib/module/navigation/createTrueSheetRouter.js +158 -100
  111. package/lib/module/navigation/createTrueSheetRouter.js.map +1 -1
  112. package/lib/module/navigation/expo-router/base-types.js +2 -0
  113. package/lib/module/navigation/expo-router/base-types.js.map +1 -0
  114. package/lib/module/navigation/expo-router/extendTrueSheetRouter.js +71 -0
  115. package/lib/module/navigation/expo-router/extendTrueSheetRouter.js.map +1 -0
  116. package/lib/module/navigation/expo-router/index.js +18 -7
  117. package/lib/module/navigation/expo-router/index.js.map +1 -1
  118. package/lib/module/navigation/expo-router/types.js +4 -0
  119. package/lib/module/navigation/expo-router/types.js.map +1 -0
  120. package/lib/module/navigation/index.js.map +1 -1
  121. package/lib/module/navigation/screen/useSheetScreenState.js +1 -0
  122. package/lib/module/navigation/screen/useSheetScreenState.js.map +1 -1
  123. package/lib/module/scrollable.js +28 -0
  124. package/lib/module/scrollable.js.map +1 -0
  125. package/lib/module/web/constants.js +1 -1
  126. package/lib/module/web/constants.js.map +1 -1
  127. package/lib/module/web/keyboard.js +69 -0
  128. package/lib/module/web/keyboard.js.map +1 -0
  129. package/lib/module/web/layout.js +168 -0
  130. package/lib/module/web/layout.js.map +1 -0
  131. package/lib/module/web/vaul/constants.js +9 -0
  132. package/lib/module/web/vaul/constants.js.map +1 -1
  133. package/lib/module/web/vaul/context.js +4 -0
  134. package/lib/module/web/vaul/context.js.map +1 -1
  135. package/lib/module/web/vaul/helpers.js +1 -0
  136. package/lib/module/web/vaul/helpers.js.map +1 -1
  137. package/lib/module/web/vaul/index.js +83 -21
  138. package/lib/module/web/vaul/index.js.map +1 -1
  139. package/lib/module/web/vaul/use-snap-points.js +57 -28
  140. package/lib/module/web/vaul/use-snap-points.js.map +1 -1
  141. package/lib/typescript/src/TrueSheet.d.ts +18 -1
  142. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  143. package/lib/typescript/src/TrueSheet.types.d.ts +209 -35
  144. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  145. package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -1
  146. package/lib/typescript/src/TrueSheetBackground.d.ts +3 -0
  147. package/lib/typescript/src/TrueSheetBackground.d.ts.map +1 -0
  148. package/lib/typescript/src/TrueSheetOverlay.d.ts +8 -0
  149. package/lib/typescript/src/TrueSheetOverlay.d.ts.map +1 -0
  150. package/lib/typescript/src/TrueSheetOverlay.web.d.ts +8 -0
  151. package/lib/typescript/src/TrueSheetOverlay.web.d.ts.map +1 -0
  152. package/lib/typescript/src/TrueSheetPeek.web.d.ts +8 -4
  153. package/lib/typescript/src/TrueSheetPeek.web.d.ts.map +1 -1
  154. package/lib/typescript/src/TrueSheetProvider.web.d.ts +5 -1
  155. package/lib/typescript/src/TrueSheetProvider.web.d.ts.map +1 -1
  156. package/lib/typescript/src/detentBackgrounds.d.ts +10 -0
  157. package/lib/typescript/src/detentBackgrounds.d.ts.map +1 -0
  158. package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts +2 -3
  159. package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts.map +1 -1
  160. package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts +6 -0
  161. package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts.map +1 -0
  162. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +76 -65
  163. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  164. package/lib/typescript/src/index.d.ts +1 -0
  165. package/lib/typescript/src/index.d.ts.map +1 -1
  166. package/lib/typescript/src/mocks/index.d.ts +4 -0
  167. package/lib/typescript/src/mocks/index.d.ts.map +1 -1
  168. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts +3 -3
  169. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts.map +1 -1
  170. package/lib/typescript/src/navigation/base-types.d.ts +9 -0
  171. package/lib/typescript/src/navigation/base-types.d.ts.map +1 -0
  172. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts +36 -10
  173. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts.map +1 -1
  174. package/lib/typescript/src/navigation/expo-router/base-types.d.ts +8 -0
  175. package/lib/typescript/src/navigation/expo-router/base-types.d.ts.map +1 -0
  176. package/lib/typescript/src/navigation/expo-router/extendTrueSheetRouter.d.ts +33 -0
  177. package/lib/typescript/src/navigation/expo-router/extendTrueSheetRouter.d.ts.map +1 -0
  178. package/lib/typescript/src/navigation/expo-router/index.d.ts +9 -6
  179. package/lib/typescript/src/navigation/expo-router/index.d.ts.map +1 -1
  180. package/lib/typescript/src/navigation/expo-router/types.d.ts +44 -0
  181. package/lib/typescript/src/navigation/expo-router/types.d.ts.map +1 -0
  182. package/lib/typescript/src/navigation/index.d.ts +3 -4
  183. package/lib/typescript/src/navigation/index.d.ts.map +1 -1
  184. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts +2 -1
  185. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts.map +1 -1
  186. package/lib/typescript/src/navigation/types.d.ts +43 -6
  187. package/lib/typescript/src/navigation/types.d.ts.map +1 -1
  188. package/lib/typescript/src/scrollable.d.ts +2 -0
  189. package/lib/typescript/src/scrollable.d.ts.map +1 -0
  190. package/lib/typescript/src/web/constants.d.ts +1 -1
  191. package/lib/typescript/src/web/constants.d.ts.map +1 -1
  192. package/lib/typescript/src/web/keyboard.d.ts +15 -0
  193. package/lib/typescript/src/web/keyboard.d.ts.map +1 -0
  194. package/lib/typescript/src/web/layout.d.ts +20 -0
  195. package/lib/typescript/src/web/layout.d.ts.map +1 -0
  196. package/lib/typescript/src/web/vaul/constants.d.ts +3 -0
  197. package/lib/typescript/src/web/vaul/constants.d.ts.map +1 -1
  198. package/lib/typescript/src/web/vaul/context.d.ts +5 -1
  199. package/lib/typescript/src/web/vaul/context.d.ts.map +1 -1
  200. package/lib/typescript/src/web/vaul/helpers.d.ts +1 -0
  201. package/lib/typescript/src/web/vaul/helpers.d.ts.map +1 -1
  202. package/lib/typescript/src/web/vaul/index.d.ts +20 -1
  203. package/lib/typescript/src/web/vaul/index.d.ts.map +1 -1
  204. package/lib/typescript/src/web/vaul/types.d.ts +9 -0
  205. package/lib/typescript/src/web/vaul/types.d.ts.map +1 -1
  206. package/lib/typescript/src/web/vaul/use-snap-points.d.ts +6 -4
  207. package/lib/typescript/src/web/vaul/use-snap-points.d.ts.map +1 -1
  208. package/package.json +18 -8
  209. package/react-native.config.js +1 -0
  210. package/src/TrueSheet.tsx +257 -62
  211. package/src/TrueSheet.types.ts +225 -35
  212. package/src/TrueSheet.web.tsx +445 -333
  213. package/src/TrueSheetBackground.tsx +17 -0
  214. package/src/TrueSheetOverlay.tsx +24 -0
  215. package/src/TrueSheetOverlay.web.tsx +33 -0
  216. package/src/TrueSheetPeek.web.tsx +25 -23
  217. package/src/TrueSheetProvider.web.tsx +22 -13
  218. package/src/detentBackgrounds.ts +24 -0
  219. package/src/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
  220. package/src/fabric/TrueSheetFooterViewNativeComponent.ts +2 -3
  221. package/src/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
  222. package/src/fabric/TrueSheetViewNativeComponent.ts +89 -73
  223. package/src/index.ts +1 -0
  224. package/src/mocks/index.ts +17 -2
  225. package/src/mocks/navigationExpoRouter.ts +6 -5
  226. package/src/navigation/base-types.ts +20 -0
  227. package/src/navigation/createTrueSheetRouter.ts +220 -144
  228. package/src/navigation/expo-router/base-types.ts +18 -0
  229. package/src/navigation/expo-router/extendTrueSheetRouter.ts +99 -0
  230. package/src/navigation/expo-router/index.ts +41 -30
  231. package/src/navigation/expo-router/types.ts +116 -0
  232. package/src/navigation/index.ts +6 -7
  233. package/src/navigation/screen/useSheetScreenState.ts +2 -0
  234. package/src/navigation/types.ts +81 -23
  235. package/src/scrollable.ts +25 -0
  236. package/src/web/constants.ts +1 -1
  237. package/src/web/keyboard.ts +79 -0
  238. package/src/web/layout.ts +196 -0
  239. package/src/web/vaul/constants.ts +9 -0
  240. package/src/web/vaul/context.ts +7 -1
  241. package/src/web/vaul/helpers.ts +5 -0
  242. package/src/web/vaul/index.tsx +113 -16
  243. package/src/web/vaul/types.ts +10 -0
  244. package/src/web/vaul/use-snap-points.ts +86 -33
@@ -1,28 +1,18 @@
1
1
  package com.lodev09.truesheet
2
2
 
3
3
  import android.annotation.SuppressLint
4
- import android.view.MotionEvent
5
- import android.view.View
6
- import android.view.ViewParent
7
4
  import com.facebook.react.bridge.WritableNativeMap
8
- import com.facebook.react.uimanager.JSPointerDispatcher
9
- import com.facebook.react.uimanager.JSTouchDispatcher
10
5
  import com.facebook.react.uimanager.PixelUtil.pxToDp
11
- import com.facebook.react.uimanager.PointerEvents
12
- import com.facebook.react.uimanager.RootView
13
6
  import com.facebook.react.uimanager.StateWrapper
14
7
  import com.facebook.react.uimanager.ThemedReactContext
15
- import com.facebook.react.uimanager.events.EventDispatcher
16
8
  import com.facebook.react.views.view.ReactViewGroup
17
- import com.lodev09.truesheet.core.TrueSheetCoordinatorLayout
18
- import com.lodev09.truesheet.utils.TouchEventDeduper
19
9
 
20
10
  /**
21
- * Delegate interface for footer view size changes and event dispatching
11
+ * Delegate interface for footer view size changes
22
12
  */
23
13
  interface TrueSheetFooterViewDelegate {
24
14
  fun footerViewDidChangeSize(width: Int, height: Int)
25
- val eventDispatcher: EventDispatcher?
15
+ fun footerViewDidLayout()
26
16
  }
27
17
 
28
18
  /**
@@ -30,40 +20,43 @@ interface TrueSheetFooterViewDelegate {
30
20
  * This is the second child of TrueSheetContainerView
31
21
  * Positioned absolutely at the bottom of the sheet
32
22
  *
33
- * Implements RootView to handle touch events when positioned outside parent bounds.
23
+ * Touches reach it through the controller's RootView like any other sheet
24
+ * content — the container tracks the sheet's visible height, so the footer
25
+ * always lays out inside the container's bounds.
34
26
  */
35
27
  @SuppressLint("ViewConstructor")
36
- class TrueSheetFooterView(private val reactContext: ThemedReactContext) :
37
- ReactViewGroup(reactContext),
38
- RootView {
28
+ class TrueSheetFooterView(reactContext: ThemedReactContext) : ReactViewGroup(reactContext) {
39
29
 
40
30
  var delegate: TrueSheetFooterViewDelegate? = null
41
31
  var stateWrapper: StateWrapper? = null
42
32
 
43
- private val eventDispatcher: EventDispatcher?
44
- get() = delegate?.eventDispatcher
45
-
46
33
  private var lastWidth = 0
47
34
  private var lastHeight = 0
48
- private var bottomInset = 0
35
+ private var stateTranslationY = 0f
36
+
37
+ var bottomInset = 0
38
+ private set
49
39
 
50
40
  /**
51
- * Skips the inset while the keyboard is open — an absolute footer rises
52
- * above the keyboard, so the inset would leave a gap.
41
+ * positionFooter slides the footer off its Yoga position (above the
42
+ * keyboard, or riding the sheet). Mirror where it rests into the shadow
43
+ * node so measure() — and Pressability's press region — match where it's
44
+ * drawn. Called once the footer settles: every push is a commit.
53
45
  */
54
- var keyboardVisible = false
55
- set(value) {
56
- if (field == value) return
57
- field = value
58
- pushBottomInsetState()
59
- }
46
+ fun syncTranslationState() {
47
+ if (translationY == stateTranslationY) return
48
+ val sw = stateWrapper ?: return
49
+ stateTranslationY = translationY
50
+ TrueSheetStateUpdater.updateFooterTranslation(sw, translationY.pxToDp())
51
+ }
60
52
 
61
53
  /**
62
54
  * Height the footer occupies above the keyboard — its layout height minus
63
- * the safe-area inset it drops while the keyboard is open.
55
+ * the safe-area inset, which rides below the keyboard's top edge while the
56
+ * keyboard is open (see positionFooter).
64
57
  */
65
58
  val keyboardOcclusionHeight: Int
66
- get() = maxOf(0, height - if (keyboardVisible) 0 else bottomInset)
59
+ get() = maxOf(0, height - bottomInset)
67
60
 
68
61
  /**
69
62
  * Tells the shadow node to pad the footer's bottom edge with the sheet's
@@ -73,31 +66,24 @@ class TrueSheetFooterView(private val reactContext: ThemedReactContext) :
73
66
  fun setBottomInset(inset: Int) {
74
67
  if (bottomInset == inset) return
75
68
  bottomInset = inset
76
- pushBottomInsetState()
77
- }
78
69
 
79
- private fun pushBottomInsetState() {
80
70
  val sw = stateWrapper ?: return
81
- val insetDp = (if (keyboardVisible) 0 else bottomInset).toFloat().pxToDp()
71
+ val insetDp = bottomInset.toFloat().pxToDp()
72
+ // Carried along — this update replaces a still-queued translation update
73
+ stateTranslationY = translationY
74
+ val translateYDp = translationY.pxToDp()
82
75
 
83
76
  // Synchronous update — the footer must be padded before detents are
84
77
  // configured, otherwise the auto detent is set up an inset short
85
- if (TrueSheetStateUpdater.updateFooterState(sw, insetDp)) return
78
+ if (TrueSheetStateUpdater.updateFooterState(sw, insetDp, translateYDp)) return
86
79
 
87
80
  // Fallback: async state update
88
81
  val newState = WritableNativeMap()
89
82
  newState.putDouble("bottomInset", insetDp.toDouble())
83
+ newState.putDouble("translateY", translateYDp.toDouble())
90
84
  sw.updateState(newState)
91
85
  }
92
86
 
93
- private val jsTouchDispatcher = JSTouchDispatcher(this)
94
- private var jsPointerDispatcher: JSPointerDispatcher? = null
95
- private val touchDeduper = TouchEventDeduper()
96
-
97
- init {
98
- jsPointerDispatcher = JSPointerDispatcher(this)
99
- }
100
-
101
87
  override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
102
88
  super.onSizeChanged(w, h, oldw, oldh)
103
89
 
@@ -108,72 +94,15 @@ class TrueSheetFooterView(private val reactContext: ThemedReactContext) :
108
94
  }
109
95
  }
110
96
 
111
- // ==================== RootView Implementation ====================
112
-
113
- override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
114
- eventDispatcher?.let { dispatcher ->
115
- if (touchDeduper.shouldDispatch(event)) {
116
- jsTouchDispatcher.handleTouchEvent(event, dispatcher, reactContext)
117
- }
118
- jsPointerDispatcher?.handleMotionEvent(event, dispatcher, true)
119
- }
120
- return super.onInterceptTouchEvent(event)
121
- }
122
-
123
- override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
124
- // Mirrors ReactSurfaceView: keep receiving onInterceptTouchEvent so
125
- // jsTouchDispatcher sees the gesture end, but forward the request up the tree.
126
- parent?.requestDisallowInterceptTouchEvent(disallowIntercept)
127
- }
128
-
129
- override fun onTouchEvent(event: MotionEvent): Boolean {
130
- if (pointerEvents == PointerEvents.NONE || pointerEvents == PointerEvents.BOX_NONE) {
131
- return false
132
- }
133
-
134
- eventDispatcher?.let { dispatcher ->
135
- if (touchDeduper.shouldDispatch(event)) {
136
- jsTouchDispatcher.handleTouchEvent(event, dispatcher, reactContext)
137
- }
138
- jsPointerDispatcher?.handleMotionEvent(event, dispatcher, false)
139
- }
140
- super.onTouchEvent(event)
141
- return true
142
- }
143
-
144
- override fun onInterceptHoverEvent(event: MotionEvent): Boolean {
145
- eventDispatcher?.let { jsPointerDispatcher?.handleMotionEvent(event, it, true) }
146
- return super.onHoverEvent(event)
147
- }
148
-
149
- override fun onHoverEvent(event: MotionEvent): Boolean {
150
- eventDispatcher?.let { jsPointerDispatcher?.handleMotionEvent(event, it, false) }
151
- return super.onHoverEvent(event)
152
- }
153
-
154
- override fun onChildStartedNativeGesture(childView: View?, ev: MotionEvent) {
155
- findCoordinatorLayout()?.childDidClaimNativeGesture()
156
- eventDispatcher?.let { dispatcher ->
157
- jsTouchDispatcher.onChildStartedNativeGesture(ev, dispatcher)
158
- jsPointerDispatcher?.onChildStartedNativeGesture(childView, ev, dispatcher)
159
- }
160
- }
161
-
162
- private fun findCoordinatorLayout(): TrueSheetCoordinatorLayout? {
163
- var current: ViewParent? = parent
164
- while (current != null && current !is TrueSheetCoordinatorLayout) {
165
- current = current.parent
166
- }
167
- return current as? TrueSheetCoordinatorLayout
168
- }
169
-
170
- override fun onChildEndedNativeGesture(childView: View, ev: MotionEvent) {
171
- eventDispatcher?.let { jsTouchDispatcher.onChildEndedNativeGesture(ev, it) }
172
- jsPointerDispatcher?.onChildEndedNativeGesture()
173
- }
174
-
175
- override fun handleException(t: Throwable) {
176
- reactContext.reactApplicationContext.handleException(RuntimeException(t))
97
+ override fun onLayout(
98
+ changed: Boolean,
99
+ left: Int,
100
+ top: Int,
101
+ right: Int,
102
+ bottom: Int
103
+ ) {
104
+ super.onLayout(changed, left, top, right, bottom)
105
+ delegate?.footerViewDidLayout()
177
106
  }
178
107
 
179
108
  companion object {
@@ -125,6 +125,9 @@ class TrueSheetModule(reactContext: ReactApplicationContext) :
125
125
  fun dismissAll(animated: Boolean, promise: Promise) {
126
126
  Handler(Looper.getMainLooper()).post {
127
127
  try {
128
+ // Drop presents still waiting on the keyboard
129
+ viewRegistry.values.forEach { it.cancelPendingPresent() }
130
+
128
131
  val rootSheet = TrueSheetStackManager.getRootSheet()
129
132
  if (rootSheet == null) {
130
133
  promise.resolve(null)
@@ -221,5 +224,15 @@ class TrueSheetModule(reactContext: ReactApplicationContext) :
221
224
  */
222
225
  @JvmStatic
223
226
  fun getSheetByTag(tag: Int): TrueSheetView? = viewRegistry[tag]
227
+
228
+ /**
229
+ * Drop presents still waiting on the keyboard that would stack on [parent]
230
+ */
231
+ @JvmStatic
232
+ fun cancelPendingPresents(parent: TrueSheetView, restoreFocus: Boolean = true) {
233
+ viewRegistry.values.forEach {
234
+ if (it.pendingPresentParent === parent) it.cancelPendingPresent(restoreFocus)
235
+ }
236
+ }
224
237
  }
225
238
  }
@@ -0,0 +1,127 @@
1
+ package com.lodev09.truesheet
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.view.View
5
+ import android.view.ViewGroup
6
+ import android.view.ViewTreeObserver
7
+ import android.view.accessibility.AccessibilityEvent
8
+ import com.facebook.react.uimanager.StateWrapper
9
+ import com.facebook.react.uimanager.ThemedReactContext
10
+ import com.facebook.react.uimanager.events.EventDispatcher
11
+ import com.facebook.react.views.view.ReactViewGroup
12
+ import com.lodev09.truesheet.core.TrueSheetOverlayRootView
13
+ import com.lodev09.truesheet.core.TrueSheetOverlayRootViewDelegate
14
+ import com.lodev09.truesheet.utils.findRootContainerView
15
+
16
+ /**
17
+ * Hidden host that renders its children in a root view attached to the
18
+ * activity's content view, above every presented sheet.
19
+ */
20
+ @SuppressLint("ViewConstructor")
21
+ class TrueSheetOverlayView(private val reactContext: ThemedReactContext) :
22
+ ReactViewGroup(reactContext),
23
+ TrueSheetOverlayRootViewDelegate {
24
+
25
+ private val rootView = TrueSheetOverlayRootView(reactContext).apply {
26
+ delegate = this@TrueSheetOverlayView
27
+ }
28
+
29
+ private var rootContainerView: ViewGroup? = null
30
+
31
+ override var eventDispatcher: EventDispatcher? = null
32
+
33
+ private var lastWidth = 0
34
+ private var lastHeight = 0
35
+
36
+ // Fabric hands back a new StateWrapper on every state commit — including our
37
+ // own pushes — so pushState dedupes against the last pushed size to break the loop
38
+ private var lastStateWidth = 0
39
+ private var lastStateHeight = 0
40
+
41
+ var stateWrapper: StateWrapper? = null
42
+ set(value) {
43
+ field = value
44
+ pushState()
45
+ }
46
+
47
+ init {
48
+ // The host stays in the React tree for layout only — children render in the root view
49
+ visibility = GONE
50
+ }
51
+
52
+ // ==================== View Hierarchy Management ====================
53
+
54
+ // When the whole window goes away (e.g. activity destroyed), the container is mid-way through
55
+ // detaching its children by then, so removing the root view in onDetachedFromWindow crashes.
56
+ // This fires before that pass begins.
57
+ private val windowAttachListener = object : ViewTreeObserver.OnWindowAttachListener {
58
+ override fun onWindowAttached() {}
59
+ override fun onWindowDetached() = detachRootView()
60
+ }
61
+
62
+ override fun onAttachedToWindow() {
63
+ super.onAttachedToWindow()
64
+ viewTreeObserver.addOnWindowAttachListener(windowAttachListener)
65
+ attachRootView()
66
+ }
67
+
68
+ override fun onDetachedFromWindow() {
69
+ viewTreeObserver.removeOnWindowAttachListener(windowAttachListener)
70
+ rootContainerView?.post { if (!isAttachedToWindow) detachRootView() }
71
+ super.onDetachedFromWindow()
72
+ }
73
+
74
+ private fun attachRootView() {
75
+ if (rootView.parent != null) return
76
+
77
+ val container = findRootContainerView(reactContext) ?: return
78
+ container.addView(rootView)
79
+ rootContainerView = container
80
+ }
81
+
82
+ private fun detachRootView() {
83
+ rootContainerView?.removeView(rootView)
84
+ rootContainerView = null
85
+ }
86
+
87
+ fun onDropInstance() {
88
+ detachRootView()
89
+ rootView.delegate = null
90
+ }
91
+
92
+ override fun addView(child: View?, index: Int) {
93
+ rootView.addView(child, index)
94
+ }
95
+
96
+ override fun getChildCount(): Int = rootView.childCount
97
+
98
+ override fun getChildAt(index: Int): View? = rootView.getChildAt(index)
99
+
100
+ override fun removeViewAt(index: Int) {
101
+ rootView.removeViewAt(index)
102
+ }
103
+
104
+ // Accessibility: children live in the root view since this view is hidden
105
+ override fun addChildrenForAccessibility(outChildren: ArrayList<View>) {}
106
+ override fun dispatchPopulateAccessibilityEvent(event: AccessibilityEvent): Boolean = false
107
+
108
+ // ==================== State ====================
109
+
110
+ override fun overlayRootViewDidChangeSize(width: Int, height: Int) {
111
+ if (width == lastWidth && height == lastHeight) return
112
+
113
+ lastWidth = width
114
+ lastHeight = height
115
+ pushState()
116
+ }
117
+
118
+ private fun pushState() {
119
+ if (lastWidth == 0 && lastHeight == 0) return
120
+ if (lastWidth == lastStateWidth && lastHeight == lastStateHeight) return
121
+ val sw = stateWrapper ?: return
122
+
123
+ lastStateWidth = lastWidth
124
+ lastStateHeight = lastHeight
125
+ TrueSheetStateUpdater.updateContainerSize(sw, lastWidth, lastHeight)
126
+ }
127
+ }
@@ -0,0 +1,45 @@
1
+ package com.lodev09.truesheet
2
+
3
+ import com.facebook.react.module.annotations.ReactModule
4
+ import com.facebook.react.uimanager.PointerEvents
5
+ import com.facebook.react.uimanager.ReactStylesDiffMap
6
+ import com.facebook.react.uimanager.StateWrapper
7
+ import com.facebook.react.uimanager.ThemedReactContext
8
+ import com.facebook.react.uimanager.UIManagerHelper
9
+ import com.facebook.react.uimanager.ViewGroupManager
10
+ import com.facebook.react.uimanager.annotations.ReactProp
11
+
12
+ /**
13
+ * ViewManager for TrueSheetOverlayView
14
+ * Renders content above every presented sheet
15
+ */
16
+ @ReactModule(name = TrueSheetOverlayViewManager.REACT_CLASS)
17
+ class TrueSheetOverlayViewManager : ViewGroupManager<TrueSheetOverlayView>() {
18
+
19
+ override fun getName(): String = REACT_CLASS
20
+
21
+ override fun createViewInstance(reactContext: ThemedReactContext): TrueSheetOverlayView = TrueSheetOverlayView(reactContext)
22
+
23
+ override fun onDropViewInstance(view: TrueSheetOverlayView) {
24
+ super.onDropViewInstance(view)
25
+ view.onDropInstance()
26
+ }
27
+
28
+ override fun addEventEmitters(reactContext: ThemedReactContext, view: TrueSheetOverlayView) {
29
+ view.eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id)
30
+ }
31
+
32
+ override fun updateState(view: TrueSheetOverlayView, props: ReactStylesDiffMap?, stateWrapper: StateWrapper?): Any? {
33
+ view.stateWrapper = stateWrapper
34
+ return null
35
+ }
36
+
37
+ @ReactProp(name = "pointerEvents")
38
+ fun setPointerEvents(view: TrueSheetOverlayView, pointerEventsStr: String?) {
39
+ view.pointerEvents = PointerEvents.parsePointerEvents(pointerEventsStr)
40
+ }
41
+
42
+ companion object {
43
+ const val REACT_CLASS = "TrueSheetOverlayView"
44
+ }
45
+ }
@@ -40,6 +40,7 @@ class TrueSheetPackage : BaseReactPackage() {
40
40
  TrueSheetContentViewManager(),
41
41
  TrueSheetHeaderViewManager(),
42
42
  TrueSheetFooterViewManager(),
43
- TrueSheetPeekViewManager()
43
+ TrueSheetPeekViewManager(),
44
+ TrueSheetOverlayViewManager()
44
45
  )
45
46
  }
@@ -1,5 +1,7 @@
1
1
  package com.lodev09.truesheet
2
2
 
3
+ import com.facebook.react.bridge.WritableNativeMap
4
+ import com.facebook.react.uimanager.PixelUtil.pxToDp
3
5
  import com.facebook.react.uimanager.StateWrapper
4
6
 
5
7
  /**
@@ -22,9 +24,30 @@ object TrueSheetStateUpdater {
22
24
  fun updateState(stateWrapper: StateWrapper, widthDp: Float, heightDp: Float): Boolean =
23
25
  isAvailable && nativeUpdateState(stateWrapper, widthDp, heightDp)
24
26
 
27
+ /**
28
+ * Pushes the container size (px) into the Fabric state — synchronously when
29
+ * the bridge is available, async otherwise.
30
+ */
31
+ fun updateContainerSize(stateWrapper: StateWrapper, widthPx: Int, heightPx: Int) {
32
+ val widthDp = widthPx.toFloat().pxToDp()
33
+ val heightDp = heightPx.toFloat().pxToDp()
34
+
35
+ if (updateState(stateWrapper, widthDp, heightDp)) return
36
+
37
+ val newStateData = WritableNativeMap()
38
+ newStateData.putDouble("containerWidth", widthDp.toDouble())
39
+ newStateData.putDouble("containerHeight", heightDp.toDouble())
40
+ stateWrapper.updateState(newStateData)
41
+ }
42
+
25
43
  /** Returns false when unavailable — caller should fall back to async updateState. */
26
- fun updateFooterState(stateWrapper: StateWrapper, bottomInsetDp: Float): Boolean =
27
- isAvailable && nativeUpdateFooterState(stateWrapper, bottomInsetDp)
44
+ fun updateFooterState(stateWrapper: StateWrapper, bottomInsetDp: Float, translateYDp: Float): Boolean =
45
+ isAvailable && nativeUpdateFooterState(stateWrapper, bottomInsetDp, translateYDp)
46
+
47
+ /** Mirrors the footer's native translation so measure() matches where it's drawn. */
48
+ fun updateFooterTranslation(stateWrapper: StateWrapper, translateYDp: Float) {
49
+ if (isAvailable) nativeUpdateFooterTranslation(stateWrapper, translateYDp)
50
+ }
28
51
 
29
52
  /**
30
53
  * Publishes the precalculated bottom safe-area inset so a late-mounted
@@ -38,7 +61,10 @@ object TrueSheetStateUpdater {
38
61
  private external fun nativeUpdateState(stateWrapper: Any, width: Float, height: Float): Boolean
39
62
 
40
63
  @JvmStatic
41
- private external fun nativeUpdateFooterState(stateWrapper: Any, bottomInset: Float): Boolean
64
+ private external fun nativeUpdateFooterState(stateWrapper: Any, bottomInset: Float, translateY: Float): Boolean
65
+
66
+ @JvmStatic
67
+ private external fun nativeUpdateFooterTranslation(stateWrapper: Any, translateY: Float)
42
68
 
43
69
  @JvmStatic
44
70
  private external fun nativeSetBottomSafeArea(insetDp: Float)