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

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 (388) 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 +156 -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 +1224 -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/TouchEventDeduper.kt +31 -0
  37. package/android/src/main/java/com/lodev09/truesheet/utils/ViewUtils.kt +30 -0
  38. package/android/src/main/jni/CMakeLists.txt +63 -0
  39. package/android/src/main/jni/TrueSheetSpec.h +19 -0
  40. package/android/src/main/jni/TrueSheetStateUpdater.cpp +96 -0
  41. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +24 -0
  42. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +43 -0
  43. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h +28 -0
  44. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.cpp +11 -0
  45. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h +37 -0
  46. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h +24 -0
  47. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.cpp +56 -0
  48. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.h +28 -0
  49. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.cpp +11 -0
  50. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.h +41 -0
  51. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.cpp +18 -0
  52. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.h +16 -0
  53. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h +28 -0
  54. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +61 -0
  55. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h +45 -0
  56. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.cpp +23 -0
  57. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.h +52 -0
  58. package/ios/TrueSheetContainerView.h +81 -6
  59. package/ios/TrueSheetContainerView.mm +275 -21
  60. package/ios/TrueSheetContentView.h +38 -1
  61. package/ios/TrueSheetContentView.mm +413 -43
  62. package/ios/TrueSheetFooterView.h +27 -2
  63. package/ios/TrueSheetFooterView.mm +141 -35
  64. package/ios/{events/OnDidDismissEvent.h → TrueSheetHeaderView.h} +10 -7
  65. package/ios/TrueSheetHeaderView.mm +64 -0
  66. package/ios/TrueSheetModule.mm +92 -5
  67. package/ios/TrueSheetPeekView.h +32 -0
  68. package/ios/TrueSheetPeekView.mm +99 -0
  69. package/ios/TrueSheetView.h +7 -15
  70. package/ios/TrueSheetView.mm +633 -215
  71. package/ios/TrueSheetViewController.h +84 -16
  72. package/ios/TrueSheetViewController.mm +1133 -333
  73. package/ios/core/RNScreensEventObserver.h +46 -0
  74. package/ios/core/RNScreensEventObserver.mm +280 -0
  75. package/ios/core/TrueSheetBlurView.h +27 -0
  76. package/ios/core/TrueSheetBlurView.mm +82 -0
  77. package/ios/core/TrueSheetDetentCalculator.h +107 -0
  78. package/ios/core/TrueSheetDetentCalculator.mm +197 -0
  79. package/ios/core/TrueSheetGrabberView.h +72 -0
  80. package/ios/core/TrueSheetGrabberView.mm +178 -0
  81. package/ios/core/TrueSheetKeyboardObserver.h +39 -0
  82. package/ios/core/TrueSheetKeyboardObserver.mm +112 -0
  83. package/ios/events/TrueSheetDragEvents.h +39 -0
  84. package/ios/events/TrueSheetDragEvents.mm +62 -0
  85. package/ios/events/{OnPositionChangeEvent.h → TrueSheetFocusEvents.h} +8 -5
  86. package/ios/events/TrueSheetFocusEvents.mm +49 -0
  87. package/ios/events/TrueSheetLifecycleEvents.h +40 -0
  88. package/ios/events/TrueSheetLifecycleEvents.mm +71 -0
  89. package/ios/events/TrueSheetStateEvents.h +35 -0
  90. package/ios/events/TrueSheetStateEvents.mm +49 -0
  91. package/ios/tvos/TrueSheetStubs.mm +154 -0
  92. package/ios/{events/OnMountEvent.h → utils/BlurUtil.h} +5 -7
  93. package/ios/utils/BlurUtil.mm +69 -0
  94. package/ios/utils/GestureUtil.h +7 -0
  95. package/ios/utils/GestureUtil.mm +12 -0
  96. package/ios/utils/PlatformUtil.h +15 -0
  97. package/ios/utils/UIView+FirstResponder.h +15 -0
  98. package/ios/utils/UIView+FirstResponder.mm +26 -0
  99. package/ios/{events/OnWillDismissEvent.h → utils/UIView+ScrollEdgeInteraction.h} +6 -7
  100. package/ios/utils/UIView+ScrollEdgeInteraction.mm +62 -0
  101. package/ios/utils/WindowUtil.mm +17 -1
  102. package/lib/module/TrueSheet.js +230 -64
  103. package/lib/module/TrueSheet.js.map +1 -1
  104. package/lib/module/TrueSheet.web.js +1203 -0
  105. package/lib/module/TrueSheet.web.js.map +1 -0
  106. package/lib/module/TrueSheetPeek.js +15 -0
  107. package/lib/module/TrueSheetPeek.js.map +1 -0
  108. package/lib/module/TrueSheetPeek.web.js +55 -0
  109. package/lib/module/TrueSheetPeek.web.js.map +1 -0
  110. package/lib/module/TrueSheetProvider.js +28 -0
  111. package/lib/module/TrueSheetProvider.js.map +1 -0
  112. package/lib/module/TrueSheetProvider.web.js +157 -0
  113. package/lib/module/TrueSheetProvider.web.js.map +1 -0
  114. package/lib/module/fabric/TrueSheetContainerViewNativeComponent.ts +1 -1
  115. package/lib/module/fabric/TrueSheetContentViewNativeComponent.ts +5 -1
  116. package/lib/module/fabric/TrueSheetFooterViewNativeComponent.ts +10 -2
  117. package/lib/module/fabric/TrueSheetHeaderViewNativeComponent.ts +8 -0
  118. package/lib/module/fabric/TrueSheetPeekViewNativeComponent.ts +8 -0
  119. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +105 -18
  120. package/lib/module/index.js +3 -3
  121. package/lib/module/index.js.map +1 -1
  122. package/lib/module/mocks/index.js +93 -0
  123. package/lib/module/mocks/index.js.map +1 -0
  124. package/lib/module/mocks/navigation.js +95 -0
  125. package/lib/module/mocks/navigation.js.map +1 -0
  126. package/lib/module/mocks/navigationExpoRouter.js +21 -0
  127. package/lib/module/mocks/navigationExpoRouter.js.map +1 -0
  128. package/lib/module/mocks/reanimated.js +91 -0
  129. package/lib/module/mocks/reanimated.js.map +1 -0
  130. package/lib/module/navigation/TrueSheetNavigatorContent.js +73 -0
  131. package/lib/module/navigation/TrueSheetNavigatorContent.js.map +1 -0
  132. package/lib/module/navigation/actions.js +50 -0
  133. package/lib/module/navigation/actions.js.map +1 -0
  134. package/lib/module/navigation/createTrueSheetRouter.js +166 -0
  135. package/lib/module/navigation/createTrueSheetRouter.js.map +1 -0
  136. package/lib/module/navigation/expo-router/index.js +48 -0
  137. package/lib/module/navigation/expo-router/index.js.map +1 -0
  138. package/lib/module/navigation/index.js +47 -0
  139. package/lib/module/navigation/index.js.map +1 -0
  140. package/lib/module/navigation/navigator.js +10 -0
  141. package/lib/module/navigation/navigator.js.map +1 -0
  142. package/lib/module/navigation/screen/ReanimatedTrueSheetScreen.js +56 -0
  143. package/lib/module/navigation/screen/ReanimatedTrueSheetScreen.js.map +1 -0
  144. package/lib/module/navigation/screen/TrueSheetScreen.js +49 -0
  145. package/lib/module/navigation/screen/TrueSheetScreen.js.map +1 -0
  146. package/lib/module/navigation/screen/index.js +5 -0
  147. package/lib/module/navigation/screen/index.js.map +1 -0
  148. package/lib/module/navigation/screen/types.js +4 -0
  149. package/lib/module/navigation/screen/types.js.map +1 -0
  150. package/lib/module/navigation/screen/useSheetScreenState.js +68 -0
  151. package/lib/module/navigation/screen/useSheetScreenState.js.map +1 -0
  152. package/lib/module/navigation/types.js +4 -0
  153. package/lib/module/navigation/types.js.map +1 -0
  154. package/lib/module/navigation/useTrueSheetNavigation.js +24 -0
  155. package/lib/module/navigation/useTrueSheetNavigation.js.map +1 -0
  156. package/lib/module/reanimated/ReanimatedTrueSheet.js +15 -9
  157. package/lib/module/reanimated/ReanimatedTrueSheet.js.map +1 -1
  158. package/lib/module/reanimated/ReanimatedTrueSheet.web.js +81 -0
  159. package/lib/module/reanimated/ReanimatedTrueSheet.web.js.map +1 -0
  160. package/lib/module/reanimated/ReanimatedTrueSheetProvider.js +4 -2
  161. package/lib/module/reanimated/ReanimatedTrueSheetProvider.js.map +1 -1
  162. package/lib/module/reanimated/index.js +2 -2
  163. package/lib/module/reanimated/index.js.map +1 -1
  164. package/lib/module/reanimated/useReanimatedPositionChangeHandler.web.js +20 -0
  165. package/lib/module/reanimated/useReanimatedPositionChangeHandler.web.js.map +1 -0
  166. package/lib/module/specs/NativeTrueSheetModule.js.map +1 -1
  167. package/lib/module/web/constants.js +16 -0
  168. package/lib/module/web/constants.js.map +1 -0
  169. package/lib/module/web/dom.js +10 -0
  170. package/lib/module/web/dom.js.map +1 -0
  171. package/lib/module/web/vaul/README.md +9 -0
  172. package/lib/module/web/vaul/browser.js +30 -0
  173. package/lib/module/web/vaul/browser.js.map +1 -0
  174. package/lib/module/web/vaul/constants.js +15 -0
  175. package/lib/module/web/vaul/constants.js.map +1 -0
  176. package/lib/module/web/vaul/context.js +59 -0
  177. package/lib/module/web/vaul/context.js.map +1 -0
  178. package/lib/module/web/vaul/helpers.js +99 -0
  179. package/lib/module/web/vaul/helpers.js.map +1 -0
  180. package/lib/module/web/vaul/index.js +1309 -0
  181. package/lib/module/web/vaul/index.js.map +1 -0
  182. package/lib/module/web/vaul/style.css +287 -0
  183. package/lib/module/web/vaul/style.css.d.js +2 -0
  184. package/lib/module/web/vaul/style.css.d.js.map +1 -0
  185. package/lib/module/web/vaul/types.js +2 -0
  186. package/lib/module/web/vaul/types.js.map +1 -0
  187. package/lib/module/web/vaul/use-composed-refs.js +34 -0
  188. package/lib/module/web/vaul/use-composed-refs.js.map +1 -0
  189. package/lib/module/web/vaul/use-controllable-state.js +54 -0
  190. package/lib/module/web/vaul/use-controllable-state.js.map +1 -0
  191. package/lib/module/web/vaul/use-position-fixed.js +123 -0
  192. package/lib/module/web/vaul/use-position-fixed.js.map +1 -0
  193. package/lib/module/web/vaul/use-prevent-scroll.js +258 -0
  194. package/lib/module/web/vaul/use-prevent-scroll.js.map +1 -0
  195. package/lib/module/web/vaul/use-scale-background.js +57 -0
  196. package/lib/module/web/vaul/use-scale-background.js.map +1 -0
  197. package/lib/module/web/vaul/use-snap-points.js +305 -0
  198. package/lib/module/web/vaul/use-snap-points.js.map +1 -0
  199. package/lib/typescript/src/TrueSheet.d.ts +51 -14
  200. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  201. package/lib/typescript/src/TrueSheet.types.d.ts +463 -54
  202. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  203. package/lib/typescript/src/TrueSheet.web.d.ts +5 -0
  204. package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -0
  205. package/lib/typescript/src/TrueSheetPeek.d.ts +9 -0
  206. package/lib/typescript/src/TrueSheetPeek.d.ts.map +1 -0
  207. package/lib/typescript/src/TrueSheetPeek.web.d.ts +28 -0
  208. package/lib/typescript/src/TrueSheetPeek.web.d.ts.map +1 -0
  209. package/lib/typescript/src/TrueSheetProvider.d.ts +18 -0
  210. package/lib/typescript/src/TrueSheetProvider.d.ts.map +1 -0
  211. package/lib/typescript/src/TrueSheetProvider.web.d.ts +27 -0
  212. package/lib/typescript/src/TrueSheetProvider.web.d.ts.map +1 -0
  213. package/lib/typescript/src/fabric/TrueSheetContainerViewNativeComponent.d.ts.map +1 -1
  214. package/lib/typescript/src/fabric/TrueSheetContentViewNativeComponent.d.ts.map +1 -1
  215. package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts +2 -0
  216. package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts.map +1 -1
  217. package/lib/typescript/src/fabric/TrueSheetHeaderViewNativeComponent.d.ts +6 -0
  218. package/lib/typescript/src/fabric/TrueSheetHeaderViewNativeComponent.d.ts.map +1 -0
  219. package/lib/typescript/src/fabric/TrueSheetPeekViewNativeComponent.d.ts +6 -0
  220. package/lib/typescript/src/fabric/TrueSheetPeekViewNativeComponent.d.ts.map +1 -0
  221. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +67 -16
  222. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  223. package/lib/typescript/src/index.d.ts +2 -2
  224. package/lib/typescript/src/index.d.ts.map +1 -1
  225. package/lib/typescript/src/mocks/index.d.ts +43 -0
  226. package/lib/typescript/src/mocks/index.d.ts.map +1 -0
  227. package/lib/typescript/src/mocks/navigation.d.ts +70 -0
  228. package/lib/typescript/src/mocks/navigation.d.ts.map +1 -0
  229. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts +22 -0
  230. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts.map +1 -0
  231. package/lib/typescript/src/mocks/reanimated.d.ts +48 -0
  232. package/lib/typescript/src/mocks/reanimated.d.ts.map +1 -0
  233. package/lib/typescript/src/navigation/TrueSheetNavigatorContent.d.ts +5 -0
  234. package/lib/typescript/src/navigation/TrueSheetNavigatorContent.d.ts.map +1 -0
  235. package/lib/typescript/src/navigation/actions.d.ts +71 -0
  236. package/lib/typescript/src/navigation/actions.d.ts.map +1 -0
  237. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts +14 -0
  238. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts.map +1 -0
  239. package/lib/typescript/src/navigation/expo-router/index.d.ts +37 -0
  240. package/lib/typescript/src/navigation/expo-router/index.d.ts.map +1 -0
  241. package/lib/typescript/src/navigation/index.d.ts +46 -0
  242. package/lib/typescript/src/navigation/index.d.ts.map +1 -0
  243. package/lib/typescript/src/navigation/navigator.d.ts +7 -0
  244. package/lib/typescript/src/navigation/navigator.d.ts.map +1 -0
  245. package/lib/typescript/src/navigation/screen/ReanimatedTrueSheetScreen.d.ts +3 -0
  246. package/lib/typescript/src/navigation/screen/ReanimatedTrueSheetScreen.d.ts.map +1 -0
  247. package/lib/typescript/src/navigation/screen/TrueSheetScreen.d.ts +3 -0
  248. package/lib/typescript/src/navigation/screen/TrueSheetScreen.d.ts.map +1 -0
  249. package/lib/typescript/src/navigation/screen/index.d.ts +4 -0
  250. package/lib/typescript/src/navigation/screen/index.d.ts.map +1 -0
  251. package/lib/typescript/src/navigation/screen/types.d.ts +14 -0
  252. package/lib/typescript/src/navigation/screen/types.d.ts.map +1 -0
  253. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts +33 -0
  254. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts.map +1 -0
  255. package/lib/typescript/src/navigation/types.d.ts +177 -0
  256. package/lib/typescript/src/navigation/types.d.ts.map +1 -0
  257. package/lib/typescript/src/navigation/useTrueSheetNavigation.d.ts +23 -0
  258. package/lib/typescript/src/navigation/useTrueSheetNavigation.d.ts.map +1 -0
  259. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.d.ts.map +1 -1
  260. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts +41 -0
  261. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts.map +1 -0
  262. package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts +8 -2
  263. package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts.map +1 -1
  264. package/lib/typescript/src/reanimated/useReanimatedPositionChangeHandler.web.d.ts +15 -0
  265. package/lib/typescript/src/reanimated/useReanimatedPositionChangeHandler.web.d.ts.map +1 -0
  266. package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts +25 -3
  267. package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts.map +1 -1
  268. package/lib/typescript/src/web/constants.d.ts +14 -0
  269. package/lib/typescript/src/web/constants.d.ts.map +1 -0
  270. package/lib/typescript/src/web/dom.d.ts +7 -0
  271. package/lib/typescript/src/web/dom.d.ts.map +1 -0
  272. package/lib/typescript/src/web/vaul/browser.d.ts +8 -0
  273. package/lib/typescript/src/web/vaul/browser.d.ts.map +1 -0
  274. package/lib/typescript/src/web/vaul/constants.d.ts +13 -0
  275. package/lib/typescript/src/web/vaul/constants.d.ts.map +1 -0
  276. package/lib/typescript/src/web/vaul/context.d.ts +53 -0
  277. package/lib/typescript/src/web/vaul/context.d.ts.map +1 -0
  278. package/lib/typescript/src/web/vaul/helpers.d.ts +17 -0
  279. package/lib/typescript/src/web/vaul/helpers.d.ts.map +1 -0
  280. package/lib/typescript/src/web/vaul/index.d.ts +228 -0
  281. package/lib/typescript/src/web/vaul/index.d.ts.map +1 -0
  282. package/lib/typescript/src/web/vaul/types.d.ts +7 -0
  283. package/lib/typescript/src/web/vaul/types.d.ts.map +1 -0
  284. package/lib/typescript/src/web/vaul/use-composed-refs.d.ts +14 -0
  285. package/lib/typescript/src/web/vaul/use-composed-refs.d.ts.map +1 -0
  286. package/lib/typescript/src/web/vaul/use-controllable-state.d.ts +9 -0
  287. package/lib/typescript/src/web/vaul/use-controllable-state.d.ts.map +1 -0
  288. package/lib/typescript/src/web/vaul/use-position-fixed.d.ts +19 -0
  289. package/lib/typescript/src/web/vaul/use-position-fixed.d.ts.map +1 -0
  290. package/lib/typescript/src/web/vaul/use-prevent-scroll.d.ts +18 -0
  291. package/lib/typescript/src/web/vaul/use-prevent-scroll.d.ts.map +1 -0
  292. package/lib/typescript/src/web/vaul/use-scale-background.d.ts +2 -0
  293. package/lib/typescript/src/web/vaul/use-scale-background.d.ts.map +1 -0
  294. package/lib/typescript/src/web/vaul/use-snap-points.d.ts +38 -0
  295. package/lib/typescript/src/web/vaul/use-snap-points.d.ts.map +1 -0
  296. package/package.json +95 -36
  297. package/react-native.config.js +9 -2
  298. package/src/TrueSheet.tsx +281 -62
  299. package/src/TrueSheet.types.ts +525 -71
  300. package/src/TrueSheet.web.tsx +1362 -0
  301. package/src/TrueSheetPeek.tsx +11 -0
  302. package/src/TrueSheetPeek.web.tsx +64 -0
  303. package/src/TrueSheetProvider.tsx +33 -0
  304. package/src/TrueSheetProvider.web.tsx +220 -0
  305. package/src/fabric/TrueSheetContainerViewNativeComponent.ts +1 -1
  306. package/src/fabric/TrueSheetContentViewNativeComponent.ts +5 -1
  307. package/src/fabric/TrueSheetFooterViewNativeComponent.ts +10 -2
  308. package/src/fabric/TrueSheetHeaderViewNativeComponent.ts +8 -0
  309. package/src/fabric/TrueSheetPeekViewNativeComponent.ts +8 -0
  310. package/src/fabric/TrueSheetViewNativeComponent.ts +105 -18
  311. package/src/index.ts +2 -2
  312. package/src/mocks/index.ts +89 -0
  313. package/src/mocks/navigation.ts +79 -0
  314. package/src/mocks/navigationExpoRouter.ts +40 -0
  315. package/src/mocks/reanimated.ts +100 -0
  316. package/src/navigation/TrueSheetNavigatorContent.tsx +106 -0
  317. package/src/navigation/actions.ts +78 -0
  318. package/src/navigation/createTrueSheetRouter.ts +222 -0
  319. package/src/navigation/expo-router/index.ts +89 -0
  320. package/src/navigation/index.ts +81 -0
  321. package/src/navigation/navigator.ts +18 -0
  322. package/src/navigation/screen/ReanimatedTrueSheetScreen.tsx +61 -0
  323. package/src/navigation/screen/TrueSheetScreen.tsx +54 -0
  324. package/src/navigation/screen/index.ts +3 -0
  325. package/src/navigation/screen/types.ts +19 -0
  326. package/src/navigation/screen/useSheetScreenState.ts +100 -0
  327. package/src/navigation/types.ts +251 -0
  328. package/src/navigation/useTrueSheetNavigation.ts +26 -0
  329. package/src/reanimated/ReanimatedTrueSheet.tsx +12 -7
  330. package/src/reanimated/ReanimatedTrueSheet.web.tsx +75 -0
  331. package/src/reanimated/ReanimatedTrueSheetProvider.tsx +12 -8
  332. package/src/reanimated/useReanimatedPositionChangeHandler.web.ts +31 -0
  333. package/src/specs/NativeTrueSheetModule.ts +28 -3
  334. package/src/web/constants.ts +13 -0
  335. package/src/web/dom.ts +9 -0
  336. package/src/web/vaul/README.md +9 -0
  337. package/src/web/vaul/browser.ts +38 -0
  338. package/src/web/vaul/constants.ts +20 -0
  339. package/src/web/vaul/context.ts +101 -0
  340. package/src/web/vaul/helpers.ts +131 -0
  341. package/src/web/vaul/index.tsx +1740 -0
  342. package/src/web/vaul/style.css +287 -0
  343. package/src/web/vaul/style.css.d.ts +1 -0
  344. package/src/web/vaul/types.ts +7 -0
  345. package/src/web/vaul/use-composed-refs.ts +35 -0
  346. package/src/web/vaul/use-controllable-state.ts +66 -0
  347. package/src/web/vaul/use-position-fixed.ts +147 -0
  348. package/src/web/vaul/use-prevent-scroll.ts +309 -0
  349. package/src/web/vaul/use-scale-background.ts +64 -0
  350. package/src/web/vaul/use-snap-points.ts +455 -0
  351. package/android/src/main/java/com/lodev09/truesheet/events/DetentChangeEvent.kt +0 -26
  352. package/android/src/main/java/com/lodev09/truesheet/events/DidDismissEvent.kt +0 -20
  353. package/android/src/main/java/com/lodev09/truesheet/events/DidPresentEvent.kt +0 -26
  354. package/android/src/main/java/com/lodev09/truesheet/events/DragBeginEvent.kt +0 -26
  355. package/android/src/main/java/com/lodev09/truesheet/events/DragChangeEvent.kt +0 -26
  356. package/android/src/main/java/com/lodev09/truesheet/events/DragEndEvent.kt +0 -26
  357. package/android/src/main/java/com/lodev09/truesheet/events/MountEvent.kt +0 -20
  358. package/android/src/main/java/com/lodev09/truesheet/events/PositionChangeEvent.kt +0 -32
  359. package/android/src/main/java/com/lodev09/truesheet/events/SizeChangeEvent.kt +0 -27
  360. package/android/src/main/java/com/lodev09/truesheet/events/WillDismissEvent.kt +0 -20
  361. package/android/src/main/java/com/lodev09/truesheet/events/WillPresentEvent.kt +0 -26
  362. package/android/src/main/res/values/styles.xml +0 -8
  363. package/ios/events/OnDetentChangeEvent.h +0 -28
  364. package/ios/events/OnDetentChangeEvent.mm +0 -30
  365. package/ios/events/OnDidDismissEvent.mm +0 -25
  366. package/ios/events/OnDidPresentEvent.h +0 -28
  367. package/ios/events/OnDidPresentEvent.mm +0 -30
  368. package/ios/events/OnDragBeginEvent.h +0 -28
  369. package/ios/events/OnDragBeginEvent.mm +0 -30
  370. package/ios/events/OnDragChangeEvent.h +0 -28
  371. package/ios/events/OnDragChangeEvent.mm +0 -30
  372. package/ios/events/OnDragEndEvent.h +0 -28
  373. package/ios/events/OnDragEndEvent.mm +0 -30
  374. package/ios/events/OnMountEvent.mm +0 -25
  375. package/ios/events/OnPositionChangeEvent.mm +0 -32
  376. package/ios/events/OnSizeChangeEvent.h +0 -28
  377. package/ios/events/OnSizeChangeEvent.mm +0 -30
  378. package/ios/events/OnWillDismissEvent.mm +0 -25
  379. package/ios/events/OnWillPresentEvent.h +0 -28
  380. package/ios/events/OnWillPresentEvent.mm +0 -30
  381. package/ios/utils/LayoutUtil.h +0 -44
  382. package/ios/utils/LayoutUtil.mm +0 -50
  383. package/lib/module/TrueSheetGrabber.js +0 -51
  384. package/lib/module/TrueSheetGrabber.js.map +0 -1
  385. package/lib/typescript/src/TrueSheetGrabber.d.ts +0 -39
  386. package/lib/typescript/src/TrueSheetGrabber.d.ts.map +0 -1
  387. package/src/TrueSheetGrabber.tsx +0 -82
  388. 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,182 @@
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
18
+ import com.lodev09.truesheet.utils.TouchEventDeduper
6
19
 
7
20
  /**
8
- * Delegate interface for footer view size changes
21
+ * Delegate interface for footer view size changes and event dispatching
9
22
  */
10
23
  interface TrueSheetFooterViewDelegate {
11
24
  fun footerViewDidChangeSize(width: Int, height: Int)
25
+ val eventDispatcher: EventDispatcher?
12
26
  }
13
27
 
14
28
  /**
15
29
  * Footer view that holds the footer content
16
30
  * This is the second child of TrueSheetContainerView
17
31
  * Positioned absolutely at the bottom of the sheet
32
+ *
33
+ * Implements RootView to handle touch events when positioned outside parent bounds.
18
34
  */
19
35
  @SuppressLint("ViewConstructor")
20
- class TrueSheetFooterView(context: ThemedReactContext) : ReactViewGroup(context) {
36
+ class TrueSheetFooterView(private val reactContext: ThemedReactContext) :
37
+ ReactViewGroup(reactContext),
38
+ RootView {
39
+
21
40
  var delegate: TrueSheetFooterViewDelegate? = null
41
+ var stateWrapper: StateWrapper? = null
42
+
43
+ private val eventDispatcher: EventDispatcher?
44
+ get() = delegate?.eventDispatcher
22
45
 
23
46
  private var lastWidth = 0
24
47
  private var lastHeight = 0
48
+ private var bottomInset = 0
49
+
50
+ /**
51
+ * Skips the inset while the keyboard is open — an absolute footer rises
52
+ * above the keyboard, so the inset would leave a gap.
53
+ */
54
+ var keyboardVisible = false
55
+ set(value) {
56
+ if (field == value) return
57
+ field = value
58
+ pushBottomInsetState()
59
+ }
60
+
61
+ /**
62
+ * Height the footer occupies above the keyboard — its layout height minus
63
+ * the safe-area inset it drops while the keyboard is open.
64
+ */
65
+ val keyboardOcclusionHeight: Int
66
+ get() = maxOf(0, height - if (keyboardVisible) 0 else bottomInset)
67
+
68
+ /**
69
+ * Tells the shadow node to pad the footer's bottom edge with the sheet's
70
+ * bottom safe-area inset — the footer owns the sheet's bottom edge, so it
71
+ * absorbs the inset and its background fills it.
72
+ */
73
+ fun setBottomInset(inset: Int) {
74
+ if (bottomInset == inset) return
75
+ bottomInset = inset
76
+ pushBottomInsetState()
77
+ }
78
+
79
+ private fun pushBottomInsetState() {
80
+ val sw = stateWrapper ?: return
81
+ val insetDp = (if (keyboardVisible) 0 else bottomInset).toFloat().pxToDp()
82
+
83
+ // Synchronous update — the footer must be padded before detents are
84
+ // configured, otherwise the auto detent is set up an inset short
85
+ if (TrueSheetStateUpdater.updateFooterState(sw, insetDp)) return
86
+
87
+ // Fallback: async state update
88
+ val newState = WritableNativeMap()
89
+ newState.putDouble("bottomInset", insetDp.toDouble())
90
+ sw.updateState(newState)
91
+ }
92
+
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
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
102
+ super.onSizeChanged(w, h, oldw, oldh)
103
+
104
+ if (w != lastWidth || h != lastHeight) {
105
+ lastWidth = w
106
+ lastHeight = h
107
+ delegate?.footerViewDidChangeSize(w, h)
108
+ }
109
+ }
110
+
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
+ }
25
128
 
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)
129
+ override fun onTouchEvent(event: MotionEvent): Boolean {
130
+ if (pointerEvents == PointerEvents.NONE || pointerEvents == PointerEvents.BOX_NONE) {
131
+ return false
45
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))
177
+ }
178
+
179
+ companion object {
180
+ const val TAG_NAME = "TrueSheet"
46
181
  }
47
182
  }
@@ -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
  }