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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (367) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +42 -31
  3. package/RNTrueSheet.podspec +10 -2
  4. package/android/build.gradle +2 -1
  5. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +174 -49
  6. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerViewManager.kt +7 -0
  7. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +371 -18
  8. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentViewManager.kt +14 -0
  9. package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterView.kt +150 -21
  10. package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterViewManager.kt +14 -0
  11. package/android/src/main/java/com/lodev09/truesheet/TrueSheetHeaderView.kt +38 -0
  12. package/android/src/main/java/com/lodev09/truesheet/TrueSheetHeaderViewManager.kt +28 -0
  13. package/android/src/main/java/com/lodev09/truesheet/TrueSheetModule.kt +84 -24
  14. package/android/src/main/java/com/lodev09/truesheet/TrueSheetPackage.kt +5 -4
  15. package/android/src/main/java/com/lodev09/truesheet/TrueSheetPeekView.kt +72 -0
  16. package/android/src/main/java/com/lodev09/truesheet/TrueSheetPeekViewManager.kt +33 -0
  17. package/android/src/main/java/com/lodev09/truesheet/TrueSheetStateUpdater.kt +45 -0
  18. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +526 -231
  19. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +1217 -603
  20. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +136 -29
  21. package/android/src/main/java/com/lodev09/truesheet/core/RNScreensEventObserver.kt +63 -0
  22. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetBehavior.kt +36 -0
  23. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +255 -0
  24. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +303 -0
  25. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +277 -0
  26. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDimView.kt +162 -0
  27. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetGrabberView.kt +180 -0
  28. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetKeyboardObserver.kt +207 -0
  29. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetStackManager.kt +220 -0
  30. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetDragEvents.kt +71 -0
  31. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetFocusEvents.kt +65 -0
  32. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetLifecycleEvents.kt +112 -0
  33. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetStateEvents.kt +56 -0
  34. package/android/src/main/java/com/lodev09/truesheet/utils/KeyboardUtils.kt +84 -0
  35. package/android/src/main/java/com/lodev09/truesheet/utils/ScreenUtils.kt +93 -67
  36. package/android/src/main/java/com/lodev09/truesheet/utils/ViewUtils.kt +30 -0
  37. package/android/src/main/jni/CMakeLists.txt +63 -0
  38. package/android/src/main/jni/TrueSheetSpec.h +19 -0
  39. package/android/src/main/jni/TrueSheetStateUpdater.cpp +96 -0
  40. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +24 -0
  41. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +43 -0
  42. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h +28 -0
  43. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.cpp +11 -0
  44. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h +37 -0
  45. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h +24 -0
  46. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.cpp +56 -0
  47. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.h +28 -0
  48. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.cpp +11 -0
  49. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.h +41 -0
  50. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.cpp +18 -0
  51. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.h +16 -0
  52. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h +28 -0
  53. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +61 -0
  54. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h +45 -0
  55. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.cpp +23 -0
  56. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.h +52 -0
  57. package/ios/TrueSheetContainerView.h +81 -6
  58. package/ios/TrueSheetContainerView.mm +275 -21
  59. package/ios/TrueSheetContentView.h +38 -1
  60. package/ios/TrueSheetContentView.mm +413 -43
  61. package/ios/TrueSheetFooterView.h +27 -2
  62. package/ios/TrueSheetFooterView.mm +141 -35
  63. package/ios/{events/OnDidDismissEvent.h → TrueSheetHeaderView.h} +10 -7
  64. package/ios/TrueSheetHeaderView.mm +64 -0
  65. package/ios/TrueSheetModule.mm +92 -5
  66. package/ios/TrueSheetPeekView.h +32 -0
  67. package/ios/TrueSheetPeekView.mm +99 -0
  68. package/ios/TrueSheetView.h +7 -15
  69. package/ios/TrueSheetView.mm +633 -215
  70. package/ios/TrueSheetViewController.h +84 -16
  71. package/ios/TrueSheetViewController.mm +1136 -333
  72. package/ios/core/RNScreensEventObserver.h +46 -0
  73. package/ios/core/RNScreensEventObserver.mm +280 -0
  74. package/ios/core/TrueSheetBlurView.h +27 -0
  75. package/ios/core/TrueSheetBlurView.mm +82 -0
  76. package/ios/core/TrueSheetDetentCalculator.h +107 -0
  77. package/ios/core/TrueSheetDetentCalculator.mm +197 -0
  78. package/ios/core/TrueSheetGrabberView.h +72 -0
  79. package/ios/core/TrueSheetGrabberView.mm +178 -0
  80. package/ios/core/TrueSheetKeyboardObserver.h +39 -0
  81. package/ios/core/TrueSheetKeyboardObserver.mm +112 -0
  82. package/ios/events/TrueSheetDragEvents.h +39 -0
  83. package/ios/events/TrueSheetDragEvents.mm +62 -0
  84. package/ios/events/{OnPositionChangeEvent.h → TrueSheetFocusEvents.h} +8 -5
  85. package/ios/events/TrueSheetFocusEvents.mm +49 -0
  86. package/ios/events/TrueSheetLifecycleEvents.h +40 -0
  87. package/ios/events/TrueSheetLifecycleEvents.mm +71 -0
  88. package/ios/events/TrueSheetStateEvents.h +35 -0
  89. package/ios/events/TrueSheetStateEvents.mm +49 -0
  90. package/ios/tvos/TrueSheetStubs.mm +154 -0
  91. package/ios/{events/OnMountEvent.h → utils/BlurUtil.h} +5 -7
  92. package/ios/utils/BlurUtil.mm +69 -0
  93. package/ios/utils/GestureUtil.h +7 -0
  94. package/ios/utils/GestureUtil.mm +12 -0
  95. package/ios/utils/PlatformUtil.h +15 -0
  96. package/ios/utils/UIView+FirstResponder.h +15 -0
  97. package/ios/utils/UIView+FirstResponder.mm +26 -0
  98. package/ios/{events/OnWillDismissEvent.h → utils/UIView+ScrollEdgeInteraction.h} +6 -7
  99. package/ios/utils/UIView+ScrollEdgeInteraction.mm +62 -0
  100. package/ios/utils/WindowUtil.mm +17 -1
  101. package/lib/module/TrueSheet.js +224 -64
  102. package/lib/module/TrueSheet.js.map +1 -1
  103. package/lib/module/TrueSheet.web.js +1201 -0
  104. package/lib/module/TrueSheet.web.js.map +1 -0
  105. package/lib/module/TrueSheetPeek.js +15 -0
  106. package/lib/module/TrueSheetPeek.js.map +1 -0
  107. package/lib/module/TrueSheetPeek.web.js +55 -0
  108. package/lib/module/TrueSheetPeek.web.js.map +1 -0
  109. package/lib/module/TrueSheetProvider.js +28 -0
  110. package/lib/module/TrueSheetProvider.js.map +1 -0
  111. package/lib/module/TrueSheetProvider.web.js +157 -0
  112. package/lib/module/TrueSheetProvider.web.js.map +1 -0
  113. package/lib/module/fabric/TrueSheetContainerViewNativeComponent.ts +1 -1
  114. package/lib/module/fabric/TrueSheetContentViewNativeComponent.ts +5 -1
  115. package/lib/module/fabric/TrueSheetFooterViewNativeComponent.ts +10 -2
  116. package/lib/module/fabric/TrueSheetHeaderViewNativeComponent.ts +8 -0
  117. package/lib/module/fabric/TrueSheetPeekViewNativeComponent.ts +8 -0
  118. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +105 -18
  119. package/lib/module/index.js +3 -3
  120. package/lib/module/index.js.map +1 -1
  121. package/lib/module/mocks/index.js +93 -0
  122. package/lib/module/mocks/index.js.map +1 -0
  123. package/lib/module/mocks/navigation.js +85 -0
  124. package/lib/module/mocks/navigation.js.map +1 -0
  125. package/lib/module/mocks/reanimated.js +91 -0
  126. package/lib/module/mocks/reanimated.js.map +1 -0
  127. package/lib/module/navigation/TrueSheetRouter.js +170 -0
  128. package/lib/module/navigation/TrueSheetRouter.js.map +1 -0
  129. package/lib/module/navigation/TrueSheetView.js +71 -0
  130. package/lib/module/navigation/TrueSheetView.js.map +1 -0
  131. package/lib/module/navigation/createTrueSheetNavigator.js +63 -0
  132. package/lib/module/navigation/createTrueSheetNavigator.js.map +1 -0
  133. package/lib/module/navigation/index.js +6 -0
  134. package/lib/module/navigation/index.js.map +1 -0
  135. package/lib/module/navigation/screen/ReanimatedTrueSheetScreen.js +56 -0
  136. package/lib/module/navigation/screen/ReanimatedTrueSheetScreen.js.map +1 -0
  137. package/lib/module/navigation/screen/TrueSheetScreen.js +49 -0
  138. package/lib/module/navigation/screen/TrueSheetScreen.js.map +1 -0
  139. package/lib/module/navigation/screen/index.js +5 -0
  140. package/lib/module/navigation/screen/index.js.map +1 -0
  141. package/lib/module/navigation/screen/types.js +4 -0
  142. package/lib/module/navigation/screen/types.js.map +1 -0
  143. package/lib/module/navigation/screen/useSheetScreenState.js +68 -0
  144. package/lib/module/navigation/screen/useSheetScreenState.js.map +1 -0
  145. package/lib/module/navigation/types.js +4 -0
  146. package/lib/module/navigation/types.js.map +1 -0
  147. package/lib/module/navigation/useTrueSheetNavigation.js +24 -0
  148. package/lib/module/navigation/useTrueSheetNavigation.js.map +1 -0
  149. package/lib/module/reanimated/ReanimatedTrueSheet.js +15 -9
  150. package/lib/module/reanimated/ReanimatedTrueSheet.js.map +1 -1
  151. package/lib/module/reanimated/ReanimatedTrueSheet.web.js +81 -0
  152. package/lib/module/reanimated/ReanimatedTrueSheet.web.js.map +1 -0
  153. package/lib/module/reanimated/ReanimatedTrueSheetProvider.js +4 -2
  154. package/lib/module/reanimated/ReanimatedTrueSheetProvider.js.map +1 -1
  155. package/lib/module/reanimated/index.js +2 -2
  156. package/lib/module/reanimated/index.js.map +1 -1
  157. package/lib/module/reanimated/useReanimatedPositionChangeHandler.web.js +20 -0
  158. package/lib/module/reanimated/useReanimatedPositionChangeHandler.web.js.map +1 -0
  159. package/lib/module/specs/NativeTrueSheetModule.js.map +1 -1
  160. package/lib/module/web/constants.js +16 -0
  161. package/lib/module/web/constants.js.map +1 -0
  162. package/lib/module/web/vaul/README.md +9 -0
  163. package/lib/module/web/vaul/browser.js +30 -0
  164. package/lib/module/web/vaul/browser.js.map +1 -0
  165. package/lib/module/web/vaul/constants.js +15 -0
  166. package/lib/module/web/vaul/constants.js.map +1 -0
  167. package/lib/module/web/vaul/context.js +59 -0
  168. package/lib/module/web/vaul/context.js.map +1 -0
  169. package/lib/module/web/vaul/helpers.js +93 -0
  170. package/lib/module/web/vaul/helpers.js.map +1 -0
  171. package/lib/module/web/vaul/index.js +1309 -0
  172. package/lib/module/web/vaul/index.js.map +1 -0
  173. package/lib/module/web/vaul/style.css +287 -0
  174. package/lib/module/web/vaul/style.css.d.js +2 -0
  175. package/lib/module/web/vaul/style.css.d.js.map +1 -0
  176. package/lib/module/web/vaul/types.js +2 -0
  177. package/lib/module/web/vaul/types.js.map +1 -0
  178. package/lib/module/web/vaul/use-composed-refs.js +34 -0
  179. package/lib/module/web/vaul/use-composed-refs.js.map +1 -0
  180. package/lib/module/web/vaul/use-controllable-state.js +54 -0
  181. package/lib/module/web/vaul/use-controllable-state.js.map +1 -0
  182. package/lib/module/web/vaul/use-position-fixed.js +123 -0
  183. package/lib/module/web/vaul/use-position-fixed.js.map +1 -0
  184. package/lib/module/web/vaul/use-prevent-scroll.js +258 -0
  185. package/lib/module/web/vaul/use-prevent-scroll.js.map +1 -0
  186. package/lib/module/web/vaul/use-scale-background.js +57 -0
  187. package/lib/module/web/vaul/use-scale-background.js.map +1 -0
  188. package/lib/module/web/vaul/use-snap-points.js +305 -0
  189. package/lib/module/web/vaul/use-snap-points.js.map +1 -0
  190. package/lib/typescript/src/TrueSheet.d.ts +51 -14
  191. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  192. package/lib/typescript/src/TrueSheet.types.d.ts +463 -54
  193. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  194. package/lib/typescript/src/TrueSheet.web.d.ts +5 -0
  195. package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -0
  196. package/lib/typescript/src/TrueSheetPeek.d.ts +9 -0
  197. package/lib/typescript/src/TrueSheetPeek.d.ts.map +1 -0
  198. package/lib/typescript/src/TrueSheetPeek.web.d.ts +28 -0
  199. package/lib/typescript/src/TrueSheetPeek.web.d.ts.map +1 -0
  200. package/lib/typescript/src/TrueSheetProvider.d.ts +18 -0
  201. package/lib/typescript/src/TrueSheetProvider.d.ts.map +1 -0
  202. package/lib/typescript/src/TrueSheetProvider.web.d.ts +27 -0
  203. package/lib/typescript/src/TrueSheetProvider.web.d.ts.map +1 -0
  204. package/lib/typescript/src/fabric/TrueSheetContainerViewNativeComponent.d.ts.map +1 -1
  205. package/lib/typescript/src/fabric/TrueSheetContentViewNativeComponent.d.ts.map +1 -1
  206. package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts +2 -0
  207. package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts.map +1 -1
  208. package/lib/typescript/src/fabric/TrueSheetHeaderViewNativeComponent.d.ts +6 -0
  209. package/lib/typescript/src/fabric/TrueSheetHeaderViewNativeComponent.d.ts.map +1 -0
  210. package/lib/typescript/src/fabric/TrueSheetPeekViewNativeComponent.d.ts +6 -0
  211. package/lib/typescript/src/fabric/TrueSheetPeekViewNativeComponent.d.ts.map +1 -0
  212. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +67 -16
  213. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  214. package/lib/typescript/src/index.d.ts +2 -2
  215. package/lib/typescript/src/index.d.ts.map +1 -1
  216. package/lib/typescript/src/mocks/index.d.ts +43 -0
  217. package/lib/typescript/src/mocks/index.d.ts.map +1 -0
  218. package/lib/typescript/src/mocks/navigation.d.ts +66 -0
  219. package/lib/typescript/src/mocks/navigation.d.ts.map +1 -0
  220. package/lib/typescript/src/mocks/reanimated.d.ts +48 -0
  221. package/lib/typescript/src/mocks/reanimated.d.ts.map +1 -0
  222. package/lib/typescript/src/navigation/TrueSheetRouter.d.ts +57 -0
  223. package/lib/typescript/src/navigation/TrueSheetRouter.d.ts.map +1 -0
  224. package/lib/typescript/src/navigation/TrueSheetView.d.ts +10 -0
  225. package/lib/typescript/src/navigation/TrueSheetView.d.ts.map +1 -0
  226. package/lib/typescript/src/navigation/createTrueSheetNavigator.d.ts +35 -0
  227. package/lib/typescript/src/navigation/createTrueSheetNavigator.d.ts.map +1 -0
  228. package/lib/typescript/src/navigation/index.d.ts +6 -0
  229. package/lib/typescript/src/navigation/index.d.ts.map +1 -0
  230. package/lib/typescript/src/navigation/screen/ReanimatedTrueSheetScreen.d.ts +3 -0
  231. package/lib/typescript/src/navigation/screen/ReanimatedTrueSheetScreen.d.ts.map +1 -0
  232. package/lib/typescript/src/navigation/screen/TrueSheetScreen.d.ts +3 -0
  233. package/lib/typescript/src/navigation/screen/TrueSheetScreen.d.ts.map +1 -0
  234. package/lib/typescript/src/navigation/screen/index.d.ts +4 -0
  235. package/lib/typescript/src/navigation/screen/index.d.ts.map +1 -0
  236. package/lib/typescript/src/navigation/screen/types.d.ts +15 -0
  237. package/lib/typescript/src/navigation/screen/types.d.ts.map +1 -0
  238. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts +35 -0
  239. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts.map +1 -0
  240. package/lib/typescript/src/navigation/types.d.ts +153 -0
  241. package/lib/typescript/src/navigation/types.d.ts.map +1 -0
  242. package/lib/typescript/src/navigation/useTrueSheetNavigation.d.ts +23 -0
  243. package/lib/typescript/src/navigation/useTrueSheetNavigation.d.ts.map +1 -0
  244. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.d.ts.map +1 -1
  245. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts +41 -0
  246. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts.map +1 -0
  247. package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts +8 -2
  248. package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts.map +1 -1
  249. package/lib/typescript/src/reanimated/useReanimatedPositionChangeHandler.web.d.ts +15 -0
  250. package/lib/typescript/src/reanimated/useReanimatedPositionChangeHandler.web.d.ts.map +1 -0
  251. package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts +25 -3
  252. package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts.map +1 -1
  253. package/lib/typescript/src/web/constants.d.ts +14 -0
  254. package/lib/typescript/src/web/constants.d.ts.map +1 -0
  255. package/lib/typescript/src/web/vaul/browser.d.ts +8 -0
  256. package/lib/typescript/src/web/vaul/browser.d.ts.map +1 -0
  257. package/lib/typescript/src/web/vaul/constants.d.ts +13 -0
  258. package/lib/typescript/src/web/vaul/constants.d.ts.map +1 -0
  259. package/lib/typescript/src/web/vaul/context.d.ts +53 -0
  260. package/lib/typescript/src/web/vaul/context.d.ts.map +1 -0
  261. package/lib/typescript/src/web/vaul/helpers.d.ts +17 -0
  262. package/lib/typescript/src/web/vaul/helpers.d.ts.map +1 -0
  263. package/lib/typescript/src/web/vaul/index.d.ts +228 -0
  264. package/lib/typescript/src/web/vaul/index.d.ts.map +1 -0
  265. package/lib/typescript/src/web/vaul/types.d.ts +7 -0
  266. package/lib/typescript/src/web/vaul/types.d.ts.map +1 -0
  267. package/lib/typescript/src/web/vaul/use-composed-refs.d.ts +14 -0
  268. package/lib/typescript/src/web/vaul/use-composed-refs.d.ts.map +1 -0
  269. package/lib/typescript/src/web/vaul/use-controllable-state.d.ts +9 -0
  270. package/lib/typescript/src/web/vaul/use-controllable-state.d.ts.map +1 -0
  271. package/lib/typescript/src/web/vaul/use-position-fixed.d.ts +19 -0
  272. package/lib/typescript/src/web/vaul/use-position-fixed.d.ts.map +1 -0
  273. package/lib/typescript/src/web/vaul/use-prevent-scroll.d.ts +18 -0
  274. package/lib/typescript/src/web/vaul/use-prevent-scroll.d.ts.map +1 -0
  275. package/lib/typescript/src/web/vaul/use-scale-background.d.ts +2 -0
  276. package/lib/typescript/src/web/vaul/use-scale-background.d.ts.map +1 -0
  277. package/lib/typescript/src/web/vaul/use-snap-points.d.ts +38 -0
  278. package/lib/typescript/src/web/vaul/use-snap-points.d.ts.map +1 -0
  279. package/package.json +78 -34
  280. package/react-native.config.js +9 -2
  281. package/src/TrueSheet.tsx +276 -60
  282. package/src/TrueSheet.types.ts +525 -71
  283. package/src/TrueSheet.web.tsx +1366 -0
  284. package/src/TrueSheetPeek.tsx +11 -0
  285. package/src/TrueSheetPeek.web.tsx +63 -0
  286. package/src/TrueSheetProvider.tsx +33 -0
  287. package/src/TrueSheetProvider.web.tsx +220 -0
  288. package/src/fabric/TrueSheetContainerViewNativeComponent.ts +1 -1
  289. package/src/fabric/TrueSheetContentViewNativeComponent.ts +5 -1
  290. package/src/fabric/TrueSheetFooterViewNativeComponent.ts +10 -2
  291. package/src/fabric/TrueSheetHeaderViewNativeComponent.ts +8 -0
  292. package/src/fabric/TrueSheetPeekViewNativeComponent.ts +8 -0
  293. package/src/fabric/TrueSheetViewNativeComponent.ts +105 -18
  294. package/src/index.ts +2 -2
  295. package/src/mocks/index.ts +89 -0
  296. package/src/mocks/navigation.ts +72 -0
  297. package/src/mocks/reanimated.ts +101 -0
  298. package/src/navigation/TrueSheetRouter.ts +234 -0
  299. package/src/navigation/TrueSheetView.tsx +99 -0
  300. package/src/navigation/createTrueSheetNavigator.tsx +93 -0
  301. package/src/navigation/index.ts +14 -0
  302. package/src/navigation/screen/ReanimatedTrueSheetScreen.tsx +61 -0
  303. package/src/navigation/screen/TrueSheetScreen.tsx +54 -0
  304. package/src/navigation/screen/index.ts +3 -0
  305. package/src/navigation/screen/types.ts +21 -0
  306. package/src/navigation/screen/useSheetScreenState.ts +107 -0
  307. package/src/navigation/types.ts +219 -0
  308. package/src/navigation/useTrueSheetNavigation.ts +26 -0
  309. package/src/reanimated/ReanimatedTrueSheet.tsx +12 -7
  310. package/src/reanimated/ReanimatedTrueSheet.web.tsx +75 -0
  311. package/src/reanimated/ReanimatedTrueSheetProvider.tsx +12 -8
  312. package/src/reanimated/useReanimatedPositionChangeHandler.web.ts +31 -0
  313. package/src/specs/NativeTrueSheetModule.ts +28 -3
  314. package/src/web/constants.ts +13 -0
  315. package/src/web/vaul/README.md +9 -0
  316. package/src/web/vaul/browser.ts +38 -0
  317. package/src/web/vaul/constants.ts +20 -0
  318. package/src/web/vaul/context.ts +101 -0
  319. package/src/web/vaul/helpers.ts +124 -0
  320. package/src/web/vaul/index.tsx +1740 -0
  321. package/src/web/vaul/style.css +287 -0
  322. package/src/web/vaul/style.css.d.ts +1 -0
  323. package/src/web/vaul/types.ts +7 -0
  324. package/src/web/vaul/use-composed-refs.ts +35 -0
  325. package/src/web/vaul/use-controllable-state.ts +66 -0
  326. package/src/web/vaul/use-position-fixed.ts +147 -0
  327. package/src/web/vaul/use-prevent-scroll.ts +309 -0
  328. package/src/web/vaul/use-scale-background.ts +64 -0
  329. package/src/web/vaul/use-snap-points.ts +455 -0
  330. package/android/src/main/java/com/lodev09/truesheet/events/DetentChangeEvent.kt +0 -26
  331. package/android/src/main/java/com/lodev09/truesheet/events/DidDismissEvent.kt +0 -20
  332. package/android/src/main/java/com/lodev09/truesheet/events/DidPresentEvent.kt +0 -26
  333. package/android/src/main/java/com/lodev09/truesheet/events/DragBeginEvent.kt +0 -26
  334. package/android/src/main/java/com/lodev09/truesheet/events/DragChangeEvent.kt +0 -26
  335. package/android/src/main/java/com/lodev09/truesheet/events/DragEndEvent.kt +0 -26
  336. package/android/src/main/java/com/lodev09/truesheet/events/MountEvent.kt +0 -20
  337. package/android/src/main/java/com/lodev09/truesheet/events/PositionChangeEvent.kt +0 -32
  338. package/android/src/main/java/com/lodev09/truesheet/events/SizeChangeEvent.kt +0 -27
  339. package/android/src/main/java/com/lodev09/truesheet/events/WillDismissEvent.kt +0 -20
  340. package/android/src/main/java/com/lodev09/truesheet/events/WillPresentEvent.kt +0 -26
  341. package/android/src/main/res/values/styles.xml +0 -8
  342. package/ios/events/OnDetentChangeEvent.h +0 -28
  343. package/ios/events/OnDetentChangeEvent.mm +0 -30
  344. package/ios/events/OnDidDismissEvent.mm +0 -25
  345. package/ios/events/OnDidPresentEvent.h +0 -28
  346. package/ios/events/OnDidPresentEvent.mm +0 -30
  347. package/ios/events/OnDragBeginEvent.h +0 -28
  348. package/ios/events/OnDragBeginEvent.mm +0 -30
  349. package/ios/events/OnDragChangeEvent.h +0 -28
  350. package/ios/events/OnDragChangeEvent.mm +0 -30
  351. package/ios/events/OnDragEndEvent.h +0 -28
  352. package/ios/events/OnDragEndEvent.mm +0 -30
  353. package/ios/events/OnMountEvent.mm +0 -25
  354. package/ios/events/OnPositionChangeEvent.mm +0 -32
  355. package/ios/events/OnSizeChangeEvent.h +0 -28
  356. package/ios/events/OnSizeChangeEvent.mm +0 -30
  357. package/ios/events/OnWillDismissEvent.mm +0 -25
  358. package/ios/events/OnWillPresentEvent.h +0 -28
  359. package/ios/events/OnWillPresentEvent.mm +0 -30
  360. package/ios/utils/LayoutUtil.h +0 -44
  361. package/ios/utils/LayoutUtil.mm +0 -50
  362. package/lib/module/TrueSheetGrabber.js +0 -51
  363. package/lib/module/TrueSheetGrabber.js.map +0 -1
  364. package/lib/typescript/src/TrueSheetGrabber.d.ts +0 -39
  365. package/lib/typescript/src/TrueSheetGrabber.d.ts.map +0 -1
  366. package/src/TrueSheetGrabber.tsx +0 -82
  367. package/src/__mocks__/index.js +0 -67
@@ -1,14 +1,41 @@
1
1
  package com.lodev09.truesheet
2
2
 
3
3
  import android.annotation.SuppressLint
4
+ import android.text.Editable
5
+ import android.text.TextWatcher
6
+ import android.view.View
7
+ import android.view.ViewGroup
8
+ import android.widget.EditText
9
+ import android.widget.ScrollView
10
+ import androidx.core.widget.NestedScrollView
11
+ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
12
+ import com.facebook.react.bridge.WritableNativeMap
13
+ import com.facebook.react.uimanager.PixelUtil.dpToPx
14
+ import com.facebook.react.uimanager.StateWrapper
4
15
  import com.facebook.react.uimanager.ThemedReactContext
5
16
  import com.facebook.react.views.view.ReactViewGroup
17
+ import com.lodev09.truesheet.core.TrueSheetKeyboardObserver
18
+ import com.lodev09.truesheet.core.TrueSheetKeyboardObserverDelegate
19
+ import com.lodev09.truesheet.utils.isDescendantOf
20
+ import com.lodev09.truesheet.utils.smoothScrollBy
21
+ import com.lodev09.truesheet.utils.smoothScrollTo
22
+
23
+ data class ScrollableOptions(val keyboardScrollOffset: Float = 0f, val scrollingExpandsSheet: Boolean = true)
6
24
 
7
25
  /**
8
26
  * Delegate interface for content view size changes
9
27
  */
10
28
  interface TrueSheetContentViewDelegate {
11
29
  fun contentViewDidChangeSize(width: Int, height: Int)
30
+ fun contentViewDidScroll()
31
+ fun contentViewScrollViewDidChange()
32
+
33
+ /**
34
+ * Keyboard occlusion adjustment below the content — positive for an absolute
35
+ * footer risen above the keyboard covering the content's bottom edge,
36
+ * negative for a relative footer sitting behind the keyboard shielding it.
37
+ */
38
+ val footerKeyboardOcclusion: Int
12
39
  }
13
40
 
14
41
  /**
@@ -16,31 +43,357 @@ interface TrueSheetContentViewDelegate {
16
43
  * This is the first child of TrueSheetContainerView
17
44
  */
18
45
  @SuppressLint("ViewConstructor")
19
- class TrueSheetContentView(context: ThemedReactContext) : ReactViewGroup(context) {
46
+ class TrueSheetContentView(private val reactContext: ThemedReactContext) : ReactViewGroup(reactContext) {
20
47
  var delegate: TrueSheetContentViewDelegate? = null
48
+ var stateWrapper: StateWrapper? = null
21
49
 
22
50
  private var lastWidth = 0
23
51
  private var lastHeight = 0
24
52
 
25
- override fun onLayout(
26
- changed: Boolean,
27
- left: Int,
28
- top: Int,
29
- right: Int,
30
- bottom: Int
31
- ) {
32
- super.onLayout(changed, left, top, right, bottom)
33
-
34
- // Notify delegate when content size changes
35
- val newWidth = right - left
36
- val newHeight = bottom - top
37
-
38
- if (newWidth != lastWidth || newHeight != lastHeight) {
39
- lastWidth = newWidth
53
+ private var pinnedScrollView: ViewGroup? = null
54
+ private var observedScrollChild: View? = null
55
+ private var originalScrollViewPaddingBottom: Int = 0
56
+ private var bottomInset: Int = 0
57
+ private var scrollableBounded = false
58
+ private var isReportPending = false
59
+
60
+ // Content growth is invisible to layout once the viewport is bounded, so track
61
+ // the scroll content size directly to keep the auto detent height in sync.
62
+ private val scrollChildLayoutListener =
63
+ View.OnLayoutChangeListener { _, _, top, _, bottom, _, oldTop, _, oldBottom ->
64
+ if (bottom - top != oldBottom - oldTop) {
65
+ reportSizeIfChanged()
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Content height with the pinned ScrollView's viewport replaced by its content
71
+ * size — the height the content wants regardless of container bounds.
72
+ * Falls back to the view height when no ScrollView is pinned.
73
+ */
74
+ val naturalHeight: Int
75
+ get() {
76
+ var naturalHeight = height
77
+ pinnedScrollView?.let { scrollView ->
78
+ scrollView.getChildAt(0)?.let { child ->
79
+ naturalHeight += child.height - scrollView.height
80
+ }
81
+ }
82
+ return maxOf(0, naturalHeight)
83
+ }
84
+
85
+ private var keyboardScrollOffset: Float = 0f
86
+ private var keyboardObserver: TrueSheetKeyboardObserver? = null
87
+
88
+ private var watchedEditText: EditText? = null
89
+ private var caretTextWatcher: TextWatcher? = null
90
+
91
+ var scrollableOptions: ScrollableOptions? = null
92
+ set(value) {
93
+ field = value
94
+ keyboardScrollOffset = value?.keyboardScrollOffset?.dpToPx() ?: 0f
95
+ }
96
+
97
+ /**
98
+ * Whether the sheet has an `auto` detent. Deriving the sheet height from the
99
+ * scroll content is circular with natural layout, so the pinned ScrollView's
100
+ * viewport is force-bounded to the container only in this case.
101
+ */
102
+ var hasAutoDetent = false
103
+ set(value) {
104
+ if (field == value) return
105
+ field = value
106
+ if (pinnedScrollView != null) {
107
+ setScrollableBounded(value)
108
+ }
109
+ }
110
+
111
+ override fun addView(child: View?, index: Int) {
112
+ super.addView(child, index)
113
+ checkScrollViewChanged()
114
+ }
115
+
116
+ override fun removeViewAt(index: Int) {
117
+ super.removeViewAt(index)
118
+ checkScrollViewChanged()
119
+ }
120
+
121
+ private fun checkScrollViewChanged() {
122
+ if (pinnedScrollView == null || pinnedScrollView?.isDescendantOf(this) == false) {
123
+ delegate?.contentViewScrollViewDidChange()
124
+ }
125
+ }
126
+
127
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
128
+ super.onSizeChanged(w, h, oldw, oldh)
129
+ reportSizeIfChanged()
130
+ }
131
+
132
+ private fun reportSizeIfChanged() {
133
+ // naturalHeight mixes sizes from different views; mid-layout they're
134
+ // momentarily inconsistent (parent resizes before its children), which
135
+ // feeds back into the auto detent and oscillates. Coalesce to the next
136
+ // frame so sizes are settled before measuring.
137
+ if (pinnedScrollView != null) {
138
+ if (isReportPending) return
139
+ isReportPending = true
140
+
141
+ post {
142
+ isReportPending = false
143
+ reportSizeNow()
144
+ }
145
+ return
146
+ }
147
+
148
+ reportSizeNow()
149
+ }
150
+
151
+ private fun reportSizeNow() {
152
+ val newHeight = naturalHeight
153
+ if (width != lastWidth || newHeight != lastHeight) {
154
+ lastWidth = width
40
155
  lastHeight = newHeight
156
+ delegate?.contentViewDidChangeSize(width, newHeight)
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Tells the shadow node to fill the container (flexGrow/flexShrink) so the
162
+ * pinned ScrollView's viewport is bounded to the visible space. Only applied
163
+ * for auto detents — otherwise content lays out naturally like a regular view.
164
+ */
165
+ private fun setScrollableBounded(bounded: Boolean) {
166
+ if (scrollableBounded == bounded) return
167
+ scrollableBounded = bounded
168
+
169
+ stateWrapper?.let {
170
+ val newState = WritableNativeMap()
171
+ newState.putBoolean("scrollableBounded", bounded)
172
+ it.updateState(newState)
173
+ }
174
+ }
175
+
176
+ fun setupScrollable(bottomInset: Int) {
177
+ // Check if pinned scroll view is still valid (still in view hierarchy)
178
+ if (pinnedScrollView != null && pinnedScrollView?.isDescendantOf(this) == false) {
179
+ clearScrollable()
180
+ }
181
+
182
+ // Already set up with same inset and valid scroll view
183
+ if (pinnedScrollView != null && this.bottomInset == bottomInset) {
184
+ return
185
+ }
186
+
187
+ val scrollView = findScrollView(this) ?: return
188
+
189
+ // Only capture originals on first pin
190
+ if (pinnedScrollView == null) {
191
+ originalScrollViewPaddingBottom = scrollView.paddingBottom
192
+ pinnedScrollView = scrollView
193
+
194
+ scrollView.isNestedScrollingEnabled = true
195
+ (scrollView.parent as? SwipeRefreshLayout)?.isNestedScrollingEnabled = false
196
+
197
+ scrollView.setOnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
198
+ if (scrollY != oldScrollY) {
199
+ delegate?.contentViewDidScroll()
200
+ }
201
+ }
202
+
203
+ scrollView.getChildAt(0)?.let { child ->
204
+ observedScrollChild = child
205
+ child.addOnLayoutChangeListener(scrollChildLayoutListener)
206
+ }
207
+ setScrollableBounded(hasAutoDetent)
208
+ reportSizeIfChanged()
209
+ }
210
+
211
+ this.bottomInset = bottomInset
212
+
213
+ setScrollViewPaddingBottom(originalScrollViewPaddingBottom + bottomInset)
41
214
 
42
- // Notify delegate of size change
43
- delegate?.contentViewDidChangeSize(newWidth, newHeight)
215
+ // If keyboard is currently showing, re-apply the keyboard inset to the new ScrollView
216
+ val keyboardHeight = keyboardObserver?.currentHeight ?: 0
217
+ if (keyboardHeight > 0) {
218
+ updateScrollViewInsetForKeyboard(keyboardHeight)
44
219
  }
45
220
  }
221
+
222
+ private fun setScrollViewPaddingBottom(paddingBottom: Int) {
223
+ val scrollView = pinnedScrollView ?: return
224
+ scrollView.clipToPadding = false
225
+ scrollView.setPadding(
226
+ scrollView.paddingLeft,
227
+ scrollView.paddingTop,
228
+ scrollView.paddingRight,
229
+ paddingBottom
230
+ )
231
+ }
232
+
233
+ fun clearScrollable() {
234
+ pinnedScrollView?.setOnScrollChangeListener(null as View.OnScrollChangeListener?)
235
+ pinnedScrollView?.isNestedScrollingEnabled = false
236
+ (pinnedScrollView?.parent as? SwipeRefreshLayout)?.isNestedScrollingEnabled = true
237
+ setScrollViewPaddingBottom(originalScrollViewPaddingBottom)
238
+ observedScrollChild?.removeOnLayoutChangeListener(scrollChildLayoutListener)
239
+ observedScrollChild = null
240
+ setScrollableBounded(false)
241
+ pinnedScrollView = null
242
+ originalScrollViewPaddingBottom = 0
243
+ bottomInset = 0
244
+ reportSizeIfChanged()
245
+ }
246
+
247
+ fun findScrollView(): ViewGroup? {
248
+ if (pinnedScrollView != null) return pinnedScrollView
249
+ return findScrollView(this as View)
250
+ }
251
+
252
+ private fun findScrollView(view: View): ViewGroup? {
253
+ if (view is ScrollView || view is NestedScrollView) {
254
+ return view as ViewGroup
255
+ }
256
+
257
+ if (view is ViewGroup) {
258
+ for (i in 0 until view.childCount) {
259
+ val scrollView = findScrollView(view.getChildAt(i))
260
+ if (scrollView != null) {
261
+ return scrollView
262
+ }
263
+ }
264
+ }
265
+
266
+ return null
267
+ }
268
+
269
+ // ==================== Keyboard Handling ====================
270
+
271
+ fun setupKeyboardHandler() {
272
+ if (keyboardObserver != null) return
273
+
274
+ keyboardObserver = TrueSheetKeyboardObserver(this, reactContext).apply {
275
+ delegate = object : TrueSheetKeyboardObserverDelegate {
276
+ override fun keyboardWillShow(height: Int) {
277
+ updateScrollViewInsetForKeyboard(height)
278
+ }
279
+
280
+ override fun keyboardDidShow(height: Int) {
281
+ attachCaretListener()
282
+ scrollToFocusedInput()
283
+ }
284
+
285
+ override fun keyboardWillHide() {
286
+ detachCaretListener()
287
+ updateScrollViewInsetForKeyboard(0)
288
+ }
289
+
290
+ override fun focusDidChange(newFocus: View) {
291
+ attachCaretListener()
292
+ scrollToFocusedInput()
293
+ }
294
+ }
295
+ start()
296
+ }
297
+ }
298
+
299
+ fun cleanupKeyboardHandler() {
300
+ detachCaretListener()
301
+ keyboardObserver?.stop()
302
+ keyboardObserver = null
303
+ }
304
+
305
+ private fun attachCaretListener() {
306
+ val focused = findFocus() as? EditText
307
+ if (focused === watchedEditText) return
308
+
309
+ detachCaretListener()
310
+ if (focused == null) return
311
+
312
+ val watcher = object : TextWatcher {
313
+ override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
314
+ override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
315
+ override fun afterTextChanged(s: Editable?) {
316
+ focused.post { scrollToFocusedInput() }
317
+ }
318
+ }
319
+
320
+ focused.addTextChangedListener(watcher)
321
+ watchedEditText = focused
322
+ caretTextWatcher = watcher
323
+ }
324
+
325
+ private fun detachCaretListener() {
326
+ caretTextWatcher?.let { watchedEditText?.removeTextChangedListener(it) }
327
+ caretTextWatcher = null
328
+ watchedEditText = null
329
+ }
330
+
331
+ private fun updateScrollViewInsetForKeyboard(keyboardHeight: Int) {
332
+ val scrollView = pinnedScrollView ?: return
333
+
334
+ // An absolute footer rises above the keyboard and covers the content's
335
+ // bottom edge — include it so the caret clears the footer, not just the
336
+ // keyboard. A relative footer stays behind the keyboard below the content,
337
+ // so its height shields that much of the keyboard's overlap.
338
+ val totalBottomInset = if (keyboardHeight > 0) {
339
+ maxOf(0, keyboardHeight + (delegate?.footerKeyboardOcclusion ?: 0))
340
+ } else {
341
+ bottomInset
342
+ }
343
+ setScrollViewPaddingBottom(originalScrollViewPaddingBottom + totalBottomInset)
344
+
345
+ scrollView.post { nudgeScrollView() }
346
+ }
347
+
348
+ private fun nudgeScrollView() {
349
+ val scrollView = pinnedScrollView ?: return
350
+ scrollView.smoothScrollBy(0, 1)
351
+ scrollView.smoothScrollBy(0, -1)
352
+ }
353
+
354
+ private fun scrollToFocusedInput() {
355
+ val scrollView = pinnedScrollView ?: findScrollView() ?: return
356
+ val focusedView = findFocus() ?: return
357
+
358
+ val focusedLocation = IntArray(2)
359
+ val scrollViewLocation = IntArray(2)
360
+ focusedView.getLocationOnScreen(focusedLocation)
361
+ scrollView.getLocationOnScreen(scrollViewLocation)
362
+
363
+ val viewTop = focusedLocation[1] - scrollViewLocation[1] + scrollView.scrollY
364
+
365
+ // Resolve the caret's line within the focused input so we follow the cursor
366
+ // rather than the input's full bounds (which over-scrolls tall inputs).
367
+ val editText = focusedView as? EditText
368
+ val layout = editText?.layout
369
+
370
+ val caretTop: Int
371
+ val caretBottom: Int
372
+ if (editText != null && layout != null) {
373
+ val line = layout.getLineForOffset(editText.selectionEnd.coerceAtLeast(0))
374
+ val textTop = viewTop + editText.totalPaddingTop - editText.scrollY
375
+ caretTop = textTop + layout.getLineTop(line)
376
+ caretBottom = textTop + layout.getLineBottom(line)
377
+ } else {
378
+ caretTop = viewTop
379
+ caretBottom = viewTop + focusedView.height
380
+ }
381
+
382
+ val offset = keyboardScrollOffset.toInt()
383
+ val visibleHeight = scrollView.height - scrollView.paddingBottom
384
+ val visibleTop = scrollView.scrollY
385
+ val visibleBottom = scrollView.scrollY + visibleHeight
386
+
387
+ when {
388
+ caretBottom + offset > visibleBottom ->
389
+ scrollView.smoothScrollTo(0, caretBottom + offset - visibleHeight)
390
+
391
+ caretTop - offset < visibleTop ->
392
+ scrollView.smoothScrollTo(0, (caretTop - offset).coerceAtLeast(0))
393
+ }
394
+ }
395
+
396
+ companion object {
397
+ const val TAG_NAME = "TrueSheet"
398
+ }
46
399
  }
@@ -1,8 +1,12 @@
1
1
  package com.lodev09.truesheet
2
2
 
3
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
4
7
  import com.facebook.react.uimanager.ThemedReactContext
5
8
  import com.facebook.react.uimanager.ViewGroupManager
9
+ import com.facebook.react.uimanager.annotations.ReactProp
6
10
 
7
11
  /**
8
12
  * ViewManager for TrueSheetContentView
@@ -15,6 +19,16 @@ class TrueSheetContentViewManager : ViewGroupManager<TrueSheetContentView>() {
15
19
 
16
20
  override fun createViewInstance(reactContext: ThemedReactContext): TrueSheetContentView = TrueSheetContentView(reactContext)
17
21
 
22
+ override fun updateState(view: TrueSheetContentView, props: ReactStylesDiffMap?, stateWrapper: StateWrapper?): Any? {
23
+ view.stateWrapper = stateWrapper
24
+ return null
25
+ }
26
+
27
+ @ReactProp(name = "pointerEvents")
28
+ fun setPointerEvents(view: TrueSheetContentView, pointerEventsStr: String?) {
29
+ view.pointerEvents = PointerEvents.parsePointerEvents(pointerEventsStr)
30
+ }
31
+
18
32
  companion object {
19
33
  const val REACT_CLASS = "TrueSheetContentView"
20
34
  }
@@ -1,47 +1,176 @@
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
+ import com.facebook.react.bridge.WritableNativeMap
8
+ import com.facebook.react.uimanager.JSPointerDispatcher
9
+ import com.facebook.react.uimanager.JSTouchDispatcher
10
+ import com.facebook.react.uimanager.PixelUtil.pxToDp
11
+ import com.facebook.react.uimanager.PointerEvents
12
+ import com.facebook.react.uimanager.RootView
13
+ import com.facebook.react.uimanager.StateWrapper
4
14
  import com.facebook.react.uimanager.ThemedReactContext
15
+ import com.facebook.react.uimanager.events.EventDispatcher
5
16
  import com.facebook.react.views.view.ReactViewGroup
17
+ import com.lodev09.truesheet.core.TrueSheetCoordinatorLayout
6
18
 
7
19
  /**
8
- * Delegate interface for footer view size changes
20
+ * Delegate interface for footer view size changes and event dispatching
9
21
  */
10
22
  interface TrueSheetFooterViewDelegate {
11
23
  fun footerViewDidChangeSize(width: Int, height: Int)
24
+ val eventDispatcher: EventDispatcher?
12
25
  }
13
26
 
14
27
  /**
15
28
  * Footer view that holds the footer content
16
29
  * This is the second child of TrueSheetContainerView
17
30
  * Positioned absolutely at the bottom of the sheet
31
+ *
32
+ * Implements RootView to handle touch events when positioned outside parent bounds.
18
33
  */
19
34
  @SuppressLint("ViewConstructor")
20
- class TrueSheetFooterView(context: ThemedReactContext) : ReactViewGroup(context) {
35
+ class TrueSheetFooterView(private val reactContext: ThemedReactContext) :
36
+ ReactViewGroup(reactContext),
37
+ RootView {
38
+
21
39
  var delegate: TrueSheetFooterViewDelegate? = null
40
+ var stateWrapper: StateWrapper? = null
41
+
42
+ private val eventDispatcher: EventDispatcher?
43
+ get() = delegate?.eventDispatcher
22
44
 
23
45
  private var lastWidth = 0
24
46
  private var lastHeight = 0
47
+ private var bottomInset = 0
48
+
49
+ /**
50
+ * Skips the inset while the keyboard is open — an absolute footer rises
51
+ * above the keyboard, so the inset would leave a gap.
52
+ */
53
+ var keyboardVisible = false
54
+ set(value) {
55
+ if (field == value) return
56
+ field = value
57
+ pushBottomInsetState()
58
+ }
59
+
60
+ /**
61
+ * Height the footer occupies above the keyboard — its layout height minus
62
+ * the safe-area inset it drops while the keyboard is open.
63
+ */
64
+ val keyboardOcclusionHeight: Int
65
+ get() = maxOf(0, height - if (keyboardVisible) 0 else bottomInset)
66
+
67
+ /**
68
+ * Tells the shadow node to pad the footer's bottom edge with the sheet's
69
+ * bottom safe-area inset — the footer owns the sheet's bottom edge, so it
70
+ * absorbs the inset and its background fills it.
71
+ */
72
+ fun setBottomInset(inset: Int) {
73
+ if (bottomInset == inset) return
74
+ bottomInset = inset
75
+ pushBottomInsetState()
76
+ }
77
+
78
+ private fun pushBottomInsetState() {
79
+ val sw = stateWrapper ?: return
80
+ val insetDp = (if (keyboardVisible) 0 else bottomInset).toFloat().pxToDp()
81
+
82
+ // Synchronous update — the footer must be padded before detents are
83
+ // configured, otherwise the auto detent is set up an inset short
84
+ if (TrueSheetStateUpdater.updateFooterState(sw, insetDp)) return
85
+
86
+ // Fallback: async state update
87
+ val newState = WritableNativeMap()
88
+ newState.putDouble("bottomInset", insetDp.toDouble())
89
+ sw.updateState(newState)
90
+ }
91
+
92
+ private val jsTouchDispatcher = JSTouchDispatcher(this)
93
+ private var jsPointerDispatcher: JSPointerDispatcher? = null
94
+
95
+ init {
96
+ jsPointerDispatcher = JSPointerDispatcher(this)
97
+ }
98
+
99
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
100
+ super.onSizeChanged(w, h, oldw, oldh)
101
+
102
+ if (w != lastWidth || h != lastHeight) {
103
+ lastWidth = w
104
+ lastHeight = h
105
+ delegate?.footerViewDidChangeSize(w, h)
106
+ }
107
+ }
108
+
109
+ // ==================== RootView Implementation ====================
110
+
111
+ override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
112
+ eventDispatcher?.let { dispatcher ->
113
+ jsTouchDispatcher.handleTouchEvent(event, dispatcher, reactContext)
114
+ jsPointerDispatcher?.handleMotionEvent(event, dispatcher, true)
115
+ }
116
+ return super.onInterceptTouchEvent(event)
117
+ }
118
+
119
+ override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
120
+ // Mirrors ReactSurfaceView: keep receiving onInterceptTouchEvent so
121
+ // jsTouchDispatcher sees the gesture end, but forward the request up the tree.
122
+ parent?.requestDisallowInterceptTouchEvent(disallowIntercept)
123
+ }
25
124
 
26
- override fun onLayout(
27
- changed: Boolean,
28
- left: Int,
29
- top: Int,
30
- right: Int,
31
- bottom: Int
32
- ) {
33
- super.onLayout(changed, left, top, right, bottom)
34
-
35
- // Notify delegate when footer size changes
36
- val newWidth = right - left
37
- val newHeight = bottom - top
38
-
39
- if (newWidth != lastWidth || newHeight != lastHeight) {
40
- lastWidth = newWidth
41
- lastHeight = newHeight
42
-
43
- // Notify delegate of size change
44
- delegate?.footerViewDidChangeSize(newWidth, newHeight)
125
+ override fun onTouchEvent(event: MotionEvent): Boolean {
126
+ if (pointerEvents == PointerEvents.NONE || pointerEvents == PointerEvents.BOX_NONE) {
127
+ return false
45
128
  }
129
+
130
+ eventDispatcher?.let { dispatcher ->
131
+ jsTouchDispatcher.handleTouchEvent(event, dispatcher, reactContext)
132
+ jsPointerDispatcher?.handleMotionEvent(event, dispatcher, false)
133
+ }
134
+ super.onTouchEvent(event)
135
+ return true
136
+ }
137
+
138
+ override fun onInterceptHoverEvent(event: MotionEvent): Boolean {
139
+ eventDispatcher?.let { jsPointerDispatcher?.handleMotionEvent(event, it, true) }
140
+ return super.onHoverEvent(event)
141
+ }
142
+
143
+ override fun onHoverEvent(event: MotionEvent): Boolean {
144
+ eventDispatcher?.let { jsPointerDispatcher?.handleMotionEvent(event, it, false) }
145
+ return super.onHoverEvent(event)
146
+ }
147
+
148
+ override fun onChildStartedNativeGesture(childView: View?, ev: MotionEvent) {
149
+ findCoordinatorLayout()?.childDidClaimNativeGesture()
150
+ eventDispatcher?.let { dispatcher ->
151
+ jsTouchDispatcher.onChildStartedNativeGesture(ev, dispatcher)
152
+ jsPointerDispatcher?.onChildStartedNativeGesture(childView, ev, dispatcher)
153
+ }
154
+ }
155
+
156
+ private fun findCoordinatorLayout(): TrueSheetCoordinatorLayout? {
157
+ var current: ViewParent? = parent
158
+ while (current != null && current !is TrueSheetCoordinatorLayout) {
159
+ current = current.parent
160
+ }
161
+ return current as? TrueSheetCoordinatorLayout
162
+ }
163
+
164
+ override fun onChildEndedNativeGesture(childView: View, ev: MotionEvent) {
165
+ eventDispatcher?.let { jsTouchDispatcher.onChildEndedNativeGesture(ev, it) }
166
+ jsPointerDispatcher?.onChildEndedNativeGesture()
167
+ }
168
+
169
+ override fun handleException(t: Throwable) {
170
+ reactContext.reactApplicationContext.handleException(RuntimeException(t))
171
+ }
172
+
173
+ companion object {
174
+ const val TAG_NAME = "TrueSheet"
46
175
  }
47
176
  }
@@ -1,8 +1,12 @@
1
1
  package com.lodev09.truesheet
2
2
 
3
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
4
7
  import com.facebook.react.uimanager.ThemedReactContext
5
8
  import com.facebook.react.uimanager.ViewGroupManager
9
+ import com.facebook.react.uimanager.annotations.ReactProp
6
10
 
7
11
  /**
8
12
  * ViewManager for TrueSheetFooterView
@@ -15,6 +19,16 @@ class TrueSheetFooterViewManager : ViewGroupManager<TrueSheetFooterView>() {
15
19
 
16
20
  override fun createViewInstance(reactContext: ThemedReactContext): TrueSheetFooterView = TrueSheetFooterView(reactContext)
17
21
 
22
+ override fun updateState(view: TrueSheetFooterView, props: ReactStylesDiffMap?, stateWrapper: StateWrapper?): Any? {
23
+ view.stateWrapper = stateWrapper
24
+ return null
25
+ }
26
+
27
+ @ReactProp(name = "pointerEvents")
28
+ fun setPointerEvents(view: TrueSheetFooterView, pointerEventsStr: String?) {
29
+ view.pointerEvents = PointerEvents.parsePointerEvents(pointerEventsStr)
30
+ }
31
+
18
32
  companion object {
19
33
  const val REACT_CLASS = "TrueSheetFooterView"
20
34
  }