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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (430) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +62 -30
  3. package/RNTrueSheet.podspec +10 -2
  4. package/android/build.gradle +24 -2
  5. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +189 -47
  6. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerViewManager.kt +7 -0
  7. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +401 -19
  8. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentViewManager.kt +18 -0
  9. package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterView.kt +145 -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/TrueSheetOverlayView.kt +106 -0
  15. package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayViewManager.kt +45 -0
  16. package/android/src/main/java/com/lodev09/truesheet/TrueSheetPackage.kt +6 -4
  17. package/android/src/main/java/com/lodev09/truesheet/TrueSheetPeekView.kt +72 -0
  18. package/android/src/main/java/com/lodev09/truesheet/TrueSheetPeekViewManager.kt +33 -0
  19. package/android/src/main/java/com/lodev09/truesheet/TrueSheetStateUpdater.kt +63 -0
  20. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +564 -226
  21. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +1399 -598
  22. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +161 -29
  23. package/android/src/main/java/com/lodev09/truesheet/core/RNScreensEventObserver.kt +63 -0
  24. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetBehavior.kt +36 -0
  25. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +255 -0
  26. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +375 -0
  27. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +299 -0
  28. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDimView.kt +162 -0
  29. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetGrabberView.kt +180 -0
  30. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetKeyboardObserver.kt +207 -0
  31. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetOverlayRootView.kt +137 -0
  32. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetStackManager.kt +220 -0
  33. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetDragEvents.kt +71 -0
  34. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetFocusEvents.kt +65 -0
  35. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetLifecycleEvents.kt +127 -0
  36. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetStateEvents.kt +56 -0
  37. package/android/src/main/java/com/lodev09/truesheet/utils/KeyboardUtils.kt +84 -0
  38. package/android/src/main/java/com/lodev09/truesheet/utils/ScreenUtils.kt +93 -67
  39. package/android/src/main/java/com/lodev09/truesheet/utils/TouchEventDeduper.kt +31 -0
  40. package/android/src/main/java/com/lodev09/truesheet/utils/ViewUtils.kt +42 -0
  41. package/android/src/main/jni/CMakeLists.txt +63 -0
  42. package/android/src/main/jni/TrueSheetSpec.h +20 -0
  43. package/android/src/main/jni/TrueSheetStateUpdater.cpp +96 -0
  44. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +16 -0
  45. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +68 -0
  46. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h +33 -0
  47. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.cpp +11 -0
  48. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h +39 -0
  49. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h +24 -0
  50. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.cpp +63 -0
  51. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.h +28 -0
  52. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.cpp +11 -0
  53. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.h +41 -0
  54. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.cpp +18 -0
  55. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.h +16 -0
  56. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetLayoutUtils.h +46 -0
  57. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewComponentDescriptor.h +21 -0
  58. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.cpp +17 -0
  59. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.h +36 -0
  60. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h +28 -0
  61. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +30 -0
  62. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h +45 -0
  63. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.cpp +23 -0
  64. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.h +52 -0
  65. package/ios/TrueSheetContainerView.h +88 -6
  66. package/ios/TrueSheetContainerView.mm +278 -21
  67. package/ios/TrueSheetContentView.h +54 -1
  68. package/ios/TrueSheetContentView.mm +371 -47
  69. package/ios/TrueSheetFooterView.h +33 -2
  70. package/ios/TrueSheetFooterView.mm +187 -35
  71. package/ios/{events/OnWillDismissEvent.h → TrueSheetHeaderView.h} +10 -7
  72. package/ios/TrueSheetHeaderView.mm +64 -0
  73. package/ios/TrueSheetModule.h +2 -7
  74. package/ios/TrueSheetModule.mm +98 -20
  75. package/ios/TrueSheetOverlayView.h +32 -0
  76. package/ios/TrueSheetOverlayView.mm +161 -0
  77. package/ios/TrueSheetPeekView.h +32 -0
  78. package/ios/TrueSheetPeekView.mm +99 -0
  79. package/ios/TrueSheetView.h +7 -15
  80. package/ios/TrueSheetView.mm +775 -215
  81. package/ios/TrueSheetViewController.h +94 -16
  82. package/ios/TrueSheetViewController.mm +1316 -331
  83. package/ios/core/RNScreensEventObserver.h +46 -0
  84. package/ios/core/RNScreensEventObserver.mm +280 -0
  85. package/ios/core/TrueSheetBlurView.h +27 -0
  86. package/ios/core/TrueSheetBlurView.mm +82 -0
  87. package/ios/core/TrueSheetDetentCalculator.h +107 -0
  88. package/ios/core/TrueSheetDetentCalculator.mm +197 -0
  89. package/ios/core/TrueSheetGrabberView.h +72 -0
  90. package/ios/core/TrueSheetGrabberView.mm +188 -0
  91. package/ios/core/TrueSheetKeyboardObserver.h +39 -0
  92. package/ios/core/TrueSheetKeyboardObserver.mm +112 -0
  93. package/ios/core/TrueSheetOverlayContainerView.h +31 -0
  94. package/ios/core/TrueSheetOverlayContainerView.mm +35 -0
  95. package/ios/events/TrueSheetDragEvents.h +39 -0
  96. package/ios/events/TrueSheetDragEvents.mm +62 -0
  97. package/ios/events/{OnPositionChangeEvent.h → TrueSheetFocusEvents.h} +8 -5
  98. package/ios/events/TrueSheetFocusEvents.mm +49 -0
  99. package/ios/events/TrueSheetLifecycleEvents.h +42 -0
  100. package/ios/events/TrueSheetLifecycleEvents.mm +79 -0
  101. package/ios/events/TrueSheetStateEvents.h +35 -0
  102. package/ios/events/TrueSheetStateEvents.mm +49 -0
  103. package/ios/tvos/TrueSheetStubs.mm +166 -0
  104. package/ios/{events/OnMountEvent.h → utils/BlurUtil.h} +5 -7
  105. package/ios/utils/BlurUtil.mm +69 -0
  106. package/ios/utils/GestureUtil.h +7 -0
  107. package/ios/utils/GestureUtil.mm +12 -0
  108. package/ios/utils/PlatformUtil.h +15 -0
  109. package/ios/utils/UIView+FirstResponder.h +15 -0
  110. package/ios/utils/UIView+FirstResponder.mm +26 -0
  111. package/ios/utils/UIView+ScrollEdgeInteraction.h +26 -0
  112. package/ios/utils/UIView+ScrollEdgeInteraction.mm +84 -0
  113. package/ios/utils/WindowUtil.mm +17 -1
  114. package/lib/module/TrueSheet.js +349 -74
  115. package/lib/module/TrueSheet.js.map +1 -1
  116. package/lib/module/TrueSheet.web.js +1270 -0
  117. package/lib/module/TrueSheet.web.js.map +1 -0
  118. package/lib/module/TrueSheetOverlay.js +30 -0
  119. package/lib/module/TrueSheetOverlay.js.map +1 -0
  120. package/lib/module/TrueSheetOverlay.web.js +35 -0
  121. package/lib/module/TrueSheetOverlay.web.js.map +1 -0
  122. package/lib/module/TrueSheetPeek.js +15 -0
  123. package/lib/module/TrueSheetPeek.js.map +1 -0
  124. package/lib/module/TrueSheetPeek.web.js +55 -0
  125. package/lib/module/TrueSheetPeek.web.js.map +1 -0
  126. package/lib/module/TrueSheetProvider.js +28 -0
  127. package/lib/module/TrueSheetProvider.js.map +1 -0
  128. package/lib/module/TrueSheetProvider.web.js +157 -0
  129. package/lib/module/TrueSheetProvider.web.js.map +1 -0
  130. package/lib/module/fabric/TrueSheetContainerViewNativeComponent.ts +1 -1
  131. package/lib/module/fabric/TrueSheetContentViewNativeComponent.ts +5 -1
  132. package/lib/module/fabric/TrueSheetFooterViewNativeComponent.ts +10 -2
  133. package/lib/module/fabric/TrueSheetHeaderViewNativeComponent.ts +8 -0
  134. package/lib/module/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
  135. package/lib/module/fabric/TrueSheetPeekViewNativeComponent.ts +8 -0
  136. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +110 -18
  137. package/lib/module/index.js +4 -3
  138. package/lib/module/index.js.map +1 -1
  139. package/lib/module/mocks/index.js +103 -0
  140. package/lib/module/mocks/index.js.map +1 -0
  141. package/lib/module/mocks/navigation.js +95 -0
  142. package/lib/module/mocks/navigation.js.map +1 -0
  143. package/lib/module/mocks/navigationExpoRouter.js +21 -0
  144. package/lib/module/mocks/navigationExpoRouter.js.map +1 -0
  145. package/lib/module/mocks/reanimated.js +91 -0
  146. package/lib/module/mocks/reanimated.js.map +1 -0
  147. package/lib/module/navigation/TrueSheetNavigatorContent.js +73 -0
  148. package/lib/module/navigation/TrueSheetNavigatorContent.js.map +1 -0
  149. package/lib/module/navigation/actions.js +50 -0
  150. package/lib/module/navigation/actions.js.map +1 -0
  151. package/lib/module/navigation/base-types.js +2 -0
  152. package/lib/module/navigation/base-types.js.map +1 -0
  153. package/lib/module/navigation/createTrueSheetRouter.js +157 -0
  154. package/lib/module/navigation/createTrueSheetRouter.js.map +1 -0
  155. package/lib/module/navigation/expo-router/base-types.js +2 -0
  156. package/lib/module/navigation/expo-router/base-types.js.map +1 -0
  157. package/lib/module/navigation/expo-router/index.js +50 -0
  158. package/lib/module/navigation/expo-router/index.js.map +1 -0
  159. package/lib/module/navigation/expo-router/types.js +4 -0
  160. package/lib/module/navigation/expo-router/types.js.map +1 -0
  161. package/lib/module/navigation/index.js +47 -0
  162. package/lib/module/navigation/index.js.map +1 -0
  163. package/lib/module/navigation/navigator.js +10 -0
  164. package/lib/module/navigation/navigator.js.map +1 -0
  165. package/lib/module/navigation/screen/ReanimatedTrueSheetScreen.js +56 -0
  166. package/lib/module/navigation/screen/ReanimatedTrueSheetScreen.js.map +1 -0
  167. package/lib/module/navigation/screen/TrueSheetScreen.js +49 -0
  168. package/lib/module/navigation/screen/TrueSheetScreen.js.map +1 -0
  169. package/lib/module/navigation/screen/index.js +5 -0
  170. package/lib/module/navigation/screen/index.js.map +1 -0
  171. package/lib/module/navigation/screen/types.js +4 -0
  172. package/lib/module/navigation/screen/types.js.map +1 -0
  173. package/lib/module/navigation/screen/useSheetScreenState.js +69 -0
  174. package/lib/module/navigation/screen/useSheetScreenState.js.map +1 -0
  175. package/lib/module/navigation/types.js +4 -0
  176. package/lib/module/navigation/types.js.map +1 -0
  177. package/lib/module/navigation/useTrueSheetNavigation.js +24 -0
  178. package/lib/module/navigation/useTrueSheetNavigation.js.map +1 -0
  179. package/lib/module/reanimated/ReanimatedTrueSheet.js +15 -9
  180. package/lib/module/reanimated/ReanimatedTrueSheet.js.map +1 -1
  181. package/lib/module/reanimated/ReanimatedTrueSheet.web.js +81 -0
  182. package/lib/module/reanimated/ReanimatedTrueSheet.web.js.map +1 -0
  183. package/lib/module/reanimated/ReanimatedTrueSheetProvider.js +4 -2
  184. package/lib/module/reanimated/ReanimatedTrueSheetProvider.js.map +1 -1
  185. package/lib/module/reanimated/index.js +2 -2
  186. package/lib/module/reanimated/index.js.map +1 -1
  187. package/lib/module/reanimated/useReanimatedPositionChangeHandler.web.js +20 -0
  188. package/lib/module/reanimated/useReanimatedPositionChangeHandler.web.js.map +1 -0
  189. package/lib/module/specs/NativeTrueSheetModule.js.map +1 -1
  190. package/lib/module/web/constants.js +16 -0
  191. package/lib/module/web/constants.js.map +1 -0
  192. package/lib/module/web/dom.js +10 -0
  193. package/lib/module/web/dom.js.map +1 -0
  194. package/lib/module/web/vaul/README.md +9 -0
  195. package/lib/module/web/vaul/browser.js +30 -0
  196. package/lib/module/web/vaul/browser.js.map +1 -0
  197. package/lib/module/web/vaul/constants.js +19 -0
  198. package/lib/module/web/vaul/constants.js.map +1 -0
  199. package/lib/module/web/vaul/context.js +59 -0
  200. package/lib/module/web/vaul/context.js.map +1 -0
  201. package/lib/module/web/vaul/helpers.js +99 -0
  202. package/lib/module/web/vaul/helpers.js.map +1 -0
  203. package/lib/module/web/vaul/index.js +1342 -0
  204. package/lib/module/web/vaul/index.js.map +1 -0
  205. package/lib/module/web/vaul/style.css +287 -0
  206. package/lib/module/web/vaul/style.css.d.js +2 -0
  207. package/lib/module/web/vaul/style.css.d.js.map +1 -0
  208. package/lib/module/web/vaul/types.js +2 -0
  209. package/lib/module/web/vaul/types.js.map +1 -0
  210. package/lib/module/web/vaul/use-composed-refs.js +34 -0
  211. package/lib/module/web/vaul/use-composed-refs.js.map +1 -0
  212. package/lib/module/web/vaul/use-controllable-state.js +54 -0
  213. package/lib/module/web/vaul/use-controllable-state.js.map +1 -0
  214. package/lib/module/web/vaul/use-position-fixed.js +123 -0
  215. package/lib/module/web/vaul/use-position-fixed.js.map +1 -0
  216. package/lib/module/web/vaul/use-prevent-scroll.js +258 -0
  217. package/lib/module/web/vaul/use-prevent-scroll.js.map +1 -0
  218. package/lib/module/web/vaul/use-scale-background.js +57 -0
  219. package/lib/module/web/vaul/use-scale-background.js.map +1 -0
  220. package/lib/module/web/vaul/use-snap-points.js +305 -0
  221. package/lib/module/web/vaul/use-snap-points.js.map +1 -0
  222. package/lib/typescript/src/TrueSheet.d.ts +57 -14
  223. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  224. package/lib/typescript/src/TrueSheet.types.d.ts +535 -55
  225. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  226. package/lib/typescript/src/TrueSheet.web.d.ts +5 -0
  227. package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -0
  228. package/lib/typescript/src/TrueSheetOverlay.d.ts +8 -0
  229. package/lib/typescript/src/TrueSheetOverlay.d.ts.map +1 -0
  230. package/lib/typescript/src/TrueSheetOverlay.web.d.ts +8 -0
  231. package/lib/typescript/src/TrueSheetOverlay.web.d.ts.map +1 -0
  232. package/lib/typescript/src/TrueSheetPeek.d.ts +9 -0
  233. package/lib/typescript/src/TrueSheetPeek.d.ts.map +1 -0
  234. package/lib/typescript/src/TrueSheetPeek.web.d.ts +28 -0
  235. package/lib/typescript/src/TrueSheetPeek.web.d.ts.map +1 -0
  236. package/lib/typescript/src/TrueSheetProvider.d.ts +18 -0
  237. package/lib/typescript/src/TrueSheetProvider.d.ts.map +1 -0
  238. package/lib/typescript/src/TrueSheetProvider.web.d.ts +27 -0
  239. package/lib/typescript/src/TrueSheetProvider.web.d.ts.map +1 -0
  240. package/lib/typescript/src/fabric/TrueSheetContainerViewNativeComponent.d.ts.map +1 -1
  241. package/lib/typescript/src/fabric/TrueSheetContentViewNativeComponent.d.ts.map +1 -1
  242. package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts +2 -0
  243. package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts.map +1 -1
  244. package/lib/typescript/src/fabric/TrueSheetHeaderViewNativeComponent.d.ts +6 -0
  245. package/lib/typescript/src/fabric/TrueSheetHeaderViewNativeComponent.d.ts.map +1 -0
  246. package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts +6 -0
  247. package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts.map +1 -0
  248. package/lib/typescript/src/fabric/TrueSheetPeekViewNativeComponent.d.ts +6 -0
  249. package/lib/typescript/src/fabric/TrueSheetPeekViewNativeComponent.d.ts.map +1 -0
  250. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +71 -16
  251. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  252. package/lib/typescript/src/index.d.ts +3 -2
  253. package/lib/typescript/src/index.d.ts.map +1 -1
  254. package/lib/typescript/src/mocks/index.d.ts +47 -0
  255. package/lib/typescript/src/mocks/index.d.ts.map +1 -0
  256. package/lib/typescript/src/mocks/navigation.d.ts +70 -0
  257. package/lib/typescript/src/mocks/navigation.d.ts.map +1 -0
  258. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts +22 -0
  259. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts.map +1 -0
  260. package/lib/typescript/src/mocks/reanimated.d.ts +48 -0
  261. package/lib/typescript/src/mocks/reanimated.d.ts.map +1 -0
  262. package/lib/typescript/src/navigation/TrueSheetNavigatorContent.d.ts +5 -0
  263. package/lib/typescript/src/navigation/TrueSheetNavigatorContent.d.ts.map +1 -0
  264. package/lib/typescript/src/navigation/actions.d.ts +71 -0
  265. package/lib/typescript/src/navigation/actions.d.ts.map +1 -0
  266. package/lib/typescript/src/navigation/base-types.d.ts +9 -0
  267. package/lib/typescript/src/navigation/base-types.d.ts.map +1 -0
  268. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts +3 -0
  269. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts.map +1 -0
  270. package/lib/typescript/src/navigation/expo-router/base-types.d.ts +8 -0
  271. package/lib/typescript/src/navigation/expo-router/base-types.d.ts.map +1 -0
  272. package/lib/typescript/src/navigation/expo-router/index.d.ts +37 -0
  273. package/lib/typescript/src/navigation/expo-router/index.d.ts.map +1 -0
  274. package/lib/typescript/src/navigation/expo-router/types.d.ts +44 -0
  275. package/lib/typescript/src/navigation/expo-router/types.d.ts.map +1 -0
  276. package/lib/typescript/src/navigation/index.d.ts +45 -0
  277. package/lib/typescript/src/navigation/index.d.ts.map +1 -0
  278. package/lib/typescript/src/navigation/navigator.d.ts +7 -0
  279. package/lib/typescript/src/navigation/navigator.d.ts.map +1 -0
  280. package/lib/typescript/src/navigation/screen/ReanimatedTrueSheetScreen.d.ts +3 -0
  281. package/lib/typescript/src/navigation/screen/ReanimatedTrueSheetScreen.d.ts.map +1 -0
  282. package/lib/typescript/src/navigation/screen/TrueSheetScreen.d.ts +3 -0
  283. package/lib/typescript/src/navigation/screen/TrueSheetScreen.d.ts.map +1 -0
  284. package/lib/typescript/src/navigation/screen/index.d.ts +4 -0
  285. package/lib/typescript/src/navigation/screen/index.d.ts.map +1 -0
  286. package/lib/typescript/src/navigation/screen/types.d.ts +14 -0
  287. package/lib/typescript/src/navigation/screen/types.d.ts.map +1 -0
  288. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts +34 -0
  289. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts.map +1 -0
  290. package/lib/typescript/src/navigation/types.d.ts +213 -0
  291. package/lib/typescript/src/navigation/types.d.ts.map +1 -0
  292. package/lib/typescript/src/navigation/useTrueSheetNavigation.d.ts +23 -0
  293. package/lib/typescript/src/navigation/useTrueSheetNavigation.d.ts.map +1 -0
  294. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.d.ts.map +1 -1
  295. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts +41 -0
  296. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts.map +1 -0
  297. package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts +8 -2
  298. package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts.map +1 -1
  299. package/lib/typescript/src/reanimated/useReanimatedPositionChangeHandler.web.d.ts +15 -0
  300. package/lib/typescript/src/reanimated/useReanimatedPositionChangeHandler.web.d.ts.map +1 -0
  301. package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts +25 -3
  302. package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts.map +1 -1
  303. package/lib/typescript/src/web/constants.d.ts +14 -0
  304. package/lib/typescript/src/web/constants.d.ts.map +1 -0
  305. package/lib/typescript/src/web/dom.d.ts +7 -0
  306. package/lib/typescript/src/web/dom.d.ts.map +1 -0
  307. package/lib/typescript/src/web/vaul/browser.d.ts +8 -0
  308. package/lib/typescript/src/web/vaul/browser.d.ts.map +1 -0
  309. package/lib/typescript/src/web/vaul/constants.d.ts +14 -0
  310. package/lib/typescript/src/web/vaul/constants.d.ts.map +1 -0
  311. package/lib/typescript/src/web/vaul/context.d.ts +54 -0
  312. package/lib/typescript/src/web/vaul/context.d.ts.map +1 -0
  313. package/lib/typescript/src/web/vaul/helpers.d.ts +17 -0
  314. package/lib/typescript/src/web/vaul/helpers.d.ts.map +1 -0
  315. package/lib/typescript/src/web/vaul/index.d.ts +234 -0
  316. package/lib/typescript/src/web/vaul/index.d.ts.map +1 -0
  317. package/lib/typescript/src/web/vaul/types.d.ts +7 -0
  318. package/lib/typescript/src/web/vaul/types.d.ts.map +1 -0
  319. package/lib/typescript/src/web/vaul/use-composed-refs.d.ts +14 -0
  320. package/lib/typescript/src/web/vaul/use-composed-refs.d.ts.map +1 -0
  321. package/lib/typescript/src/web/vaul/use-controllable-state.d.ts +9 -0
  322. package/lib/typescript/src/web/vaul/use-controllable-state.d.ts.map +1 -0
  323. package/lib/typescript/src/web/vaul/use-position-fixed.d.ts +19 -0
  324. package/lib/typescript/src/web/vaul/use-position-fixed.d.ts.map +1 -0
  325. package/lib/typescript/src/web/vaul/use-prevent-scroll.d.ts +18 -0
  326. package/lib/typescript/src/web/vaul/use-prevent-scroll.d.ts.map +1 -0
  327. package/lib/typescript/src/web/vaul/use-scale-background.d.ts +2 -0
  328. package/lib/typescript/src/web/vaul/use-scale-background.d.ts.map +1 -0
  329. package/lib/typescript/src/web/vaul/use-snap-points.d.ts +38 -0
  330. package/lib/typescript/src/web/vaul/use-snap-points.d.ts.map +1 -0
  331. package/package.json +104 -37
  332. package/react-native.config.js +10 -2
  333. package/src/TrueSheet.tsx +424 -70
  334. package/src/TrueSheet.types.ts +602 -72
  335. package/src/TrueSheet.web.tsx +1437 -0
  336. package/src/TrueSheetOverlay.tsx +24 -0
  337. package/src/TrueSheetOverlay.web.tsx +33 -0
  338. package/src/TrueSheetPeek.tsx +11 -0
  339. package/src/TrueSheetPeek.web.tsx +64 -0
  340. package/src/TrueSheetProvider.tsx +33 -0
  341. package/src/TrueSheetProvider.web.tsx +220 -0
  342. package/src/fabric/TrueSheetContainerViewNativeComponent.ts +1 -1
  343. package/src/fabric/TrueSheetContentViewNativeComponent.ts +5 -1
  344. package/src/fabric/TrueSheetFooterViewNativeComponent.ts +10 -2
  345. package/src/fabric/TrueSheetHeaderViewNativeComponent.ts +8 -0
  346. package/src/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
  347. package/src/fabric/TrueSheetPeekViewNativeComponent.ts +8 -0
  348. package/src/fabric/TrueSheetViewNativeComponent.ts +110 -18
  349. package/src/index.ts +3 -2
  350. package/src/mocks/index.ts +96 -0
  351. package/src/mocks/navigation.ts +79 -0
  352. package/src/mocks/navigationExpoRouter.ts +41 -0
  353. package/src/mocks/reanimated.ts +100 -0
  354. package/src/navigation/TrueSheetNavigatorContent.tsx +106 -0
  355. package/src/navigation/actions.ts +78 -0
  356. package/src/navigation/base-types.ts +20 -0
  357. package/src/navigation/createTrueSheetRouter.ts +194 -0
  358. package/src/navigation/expo-router/base-types.ts +18 -0
  359. package/src/navigation/expo-router/index.ts +90 -0
  360. package/src/navigation/expo-router/types.ts +116 -0
  361. package/src/navigation/index.ts +80 -0
  362. package/src/navigation/navigator.ts +18 -0
  363. package/src/navigation/screen/ReanimatedTrueSheetScreen.tsx +61 -0
  364. package/src/navigation/screen/TrueSheetScreen.tsx +54 -0
  365. package/src/navigation/screen/index.ts +3 -0
  366. package/src/navigation/screen/types.ts +19 -0
  367. package/src/navigation/screen/useSheetScreenState.ts +102 -0
  368. package/src/navigation/types.ts +302 -0
  369. package/src/navigation/useTrueSheetNavigation.ts +26 -0
  370. package/src/reanimated/ReanimatedTrueSheet.tsx +12 -7
  371. package/src/reanimated/ReanimatedTrueSheet.web.tsx +75 -0
  372. package/src/reanimated/ReanimatedTrueSheetProvider.tsx +12 -8
  373. package/src/reanimated/useReanimatedPositionChangeHandler.web.ts +31 -0
  374. package/src/specs/NativeTrueSheetModule.ts +28 -3
  375. package/src/web/constants.ts +13 -0
  376. package/src/web/dom.ts +9 -0
  377. package/src/web/vaul/README.md +9 -0
  378. package/src/web/vaul/browser.ts +38 -0
  379. package/src/web/vaul/constants.ts +24 -0
  380. package/src/web/vaul/context.ts +102 -0
  381. package/src/web/vaul/helpers.ts +131 -0
  382. package/src/web/vaul/index.tsx +1785 -0
  383. package/src/web/vaul/style.css +287 -0
  384. package/src/web/vaul/style.css.d.ts +1 -0
  385. package/src/web/vaul/types.ts +7 -0
  386. package/src/web/vaul/use-composed-refs.ts +35 -0
  387. package/src/web/vaul/use-controllable-state.ts +66 -0
  388. package/src/web/vaul/use-position-fixed.ts +147 -0
  389. package/src/web/vaul/use-prevent-scroll.ts +309 -0
  390. package/src/web/vaul/use-scale-background.ts +64 -0
  391. package/src/web/vaul/use-snap-points.ts +455 -0
  392. package/android/src/main/java/com/lodev09/truesheet/events/DetentChangeEvent.kt +0 -26
  393. package/android/src/main/java/com/lodev09/truesheet/events/DidDismissEvent.kt +0 -20
  394. package/android/src/main/java/com/lodev09/truesheet/events/DidPresentEvent.kt +0 -26
  395. package/android/src/main/java/com/lodev09/truesheet/events/DragBeginEvent.kt +0 -26
  396. package/android/src/main/java/com/lodev09/truesheet/events/DragChangeEvent.kt +0 -26
  397. package/android/src/main/java/com/lodev09/truesheet/events/DragEndEvent.kt +0 -26
  398. package/android/src/main/java/com/lodev09/truesheet/events/MountEvent.kt +0 -20
  399. package/android/src/main/java/com/lodev09/truesheet/events/PositionChangeEvent.kt +0 -32
  400. package/android/src/main/java/com/lodev09/truesheet/events/SizeChangeEvent.kt +0 -27
  401. package/android/src/main/java/com/lodev09/truesheet/events/WillDismissEvent.kt +0 -20
  402. package/android/src/main/java/com/lodev09/truesheet/events/WillPresentEvent.kt +0 -26
  403. package/android/src/main/res/values/styles.xml +0 -8
  404. package/ios/events/OnDetentChangeEvent.h +0 -28
  405. package/ios/events/OnDetentChangeEvent.mm +0 -30
  406. package/ios/events/OnDidDismissEvent.h +0 -26
  407. package/ios/events/OnDidDismissEvent.mm +0 -25
  408. package/ios/events/OnDidPresentEvent.h +0 -28
  409. package/ios/events/OnDidPresentEvent.mm +0 -30
  410. package/ios/events/OnDragBeginEvent.h +0 -28
  411. package/ios/events/OnDragBeginEvent.mm +0 -30
  412. package/ios/events/OnDragChangeEvent.h +0 -28
  413. package/ios/events/OnDragChangeEvent.mm +0 -30
  414. package/ios/events/OnDragEndEvent.h +0 -28
  415. package/ios/events/OnDragEndEvent.mm +0 -30
  416. package/ios/events/OnMountEvent.mm +0 -25
  417. package/ios/events/OnPositionChangeEvent.mm +0 -32
  418. package/ios/events/OnSizeChangeEvent.h +0 -28
  419. package/ios/events/OnSizeChangeEvent.mm +0 -30
  420. package/ios/events/OnWillDismissEvent.mm +0 -25
  421. package/ios/events/OnWillPresentEvent.h +0 -28
  422. package/ios/events/OnWillPresentEvent.mm +0 -30
  423. package/ios/utils/LayoutUtil.h +0 -44
  424. package/ios/utils/LayoutUtil.mm +0 -50
  425. package/lib/module/TrueSheetGrabber.js +0 -51
  426. package/lib/module/TrueSheetGrabber.js.map +0 -1
  427. package/lib/typescript/src/TrueSheetGrabber.d.ts +0 -39
  428. package/lib/typescript/src/TrueSheetGrabber.d.ts.map +0 -1
  429. package/src/TrueSheetGrabber.tsx +0 -82
  430. package/src/__mocks__/index.js +0 -67
@@ -10,18 +10,27 @@
10
10
 
11
11
  #import "TrueSheetContentView.h"
12
12
  #import <React/RCTScrollViewComponentView.h>
13
- #import <react/renderer/components/TrueSheetSpec/ComponentDescriptors.h>
14
13
  #import <react/renderer/components/TrueSheetSpec/EventEmitters.h>
15
14
  #import <react/renderer/components/TrueSheetSpec/Props.h>
16
15
  #import <react/renderer/components/TrueSheetSpec/RCTComponentViewHelpers.h>
16
+ #import <react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h>
17
+ #import <react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h>
18
+ #import "TrueSheetContainerView.h"
19
+ #import "TrueSheetFooterView.h"
17
20
  #import "TrueSheetViewController.h"
18
- #import "utils/LayoutUtil.h"
21
+ #import "utils/PlatformUtil.h"
22
+ #import "utils/UIView+FirstResponder.h"
19
23
 
20
24
  using namespace facebook::react;
21
25
 
22
26
  @implementation TrueSheetContentView {
23
- RCTScrollViewComponentView *_pinnedScrollView;
24
- CGSize _lastSize;
27
+ TrueSheetContentViewShadowNode::ConcreteState::Shared _state;
28
+ RCTScrollViewComponentView *_detectedScrollView;
29
+ CGFloat _lastReportedNaturalHeight;
30
+ CGFloat _appliedKeyboardOffset;
31
+ BOOL _observingTextChanges;
32
+ UIScrollViewContentInsetAdjustmentBehavior _originalInsetAdjustmentBehavior;
33
+ BOOL _appliedContentInsetAdjustment;
25
34
  }
26
35
 
27
36
  + (ComponentDescriptorProvider)componentDescriptorProvider {
@@ -32,83 +41,398 @@ using namespace facebook::react;
32
41
  if (self = [super initWithFrame:frame]) {
33
42
  static const auto defaultProps = std::make_shared<const TrueSheetContentViewProps>();
34
43
  _props = defaultProps;
35
-
36
- _pinnedScrollView = nil;
37
- _lastSize = CGSizeZero;
38
44
  }
39
45
  return self;
40
46
  }
41
47
 
48
+ - (void)dealloc {
49
+ [self stopObservingTextChanges];
50
+ }
51
+
52
+ - (void)updateState:(const State::Shared &)state oldState:(const State::Shared &)oldState {
53
+ _state = std::static_pointer_cast<TrueSheetContentViewShadowNode::ConcreteState const>(state);
54
+
55
+ CGFloat naturalHeight = _state->getData().naturalHeight;
56
+ if (naturalHeight != _lastReportedNaturalHeight) {
57
+ _lastReportedNaturalHeight = naturalHeight;
58
+ [self.delegate contentViewDidChangeSize:CGSizeMake(self.frame.size.width, naturalHeight)];
59
+ }
60
+ }
61
+
62
+ - (void)setScrollableHandle:(NSInteger)scrollableHandle {
63
+ if (_scrollableHandle == scrollableHandle) {
64
+ return;
65
+ }
66
+ _scrollableHandle = scrollableHandle;
67
+
68
+ // Release the previously resolved ScrollView — setupScrollable re-resolves
69
+ [self clearScrollable];
70
+ }
71
+
72
+ - (void)setContentInsetAdjustment:(BOOL)contentInsetAdjustment {
73
+ if (_contentInsetAdjustment == contentInsetAdjustment) {
74
+ return;
75
+ }
76
+ _contentInsetAdjustment = contentInsetAdjustment;
77
+ [self applyContentInsetAdjustment];
78
+ }
79
+
80
+ // Hands the bottom safe-area inset to UIKit — `automatic` only insets while
81
+ // the content can scroll, which the Android counterpart mirrors manually.
82
+ - (void)applyContentInsetAdjustment {
83
+ if (!_detectedScrollView) {
84
+ return;
85
+ }
86
+
87
+ UIScrollView *scrollView = _detectedScrollView.scrollView;
88
+ if (_contentInsetAdjustment && !_appliedContentInsetAdjustment) {
89
+ _originalInsetAdjustmentBehavior = scrollView.contentInsetAdjustmentBehavior;
90
+ scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentAutomatic;
91
+ _appliedContentInsetAdjustment = YES;
92
+ } else if (!_contentInsetAdjustment && _appliedContentInsetAdjustment) {
93
+ scrollView.contentInsetAdjustmentBehavior = _originalInsetAdjustmentBehavior;
94
+ _appliedContentInsetAdjustment = NO;
95
+ }
96
+ }
97
+
98
+ #pragma mark - Text Change Observing
99
+
100
+ // The notification is app-wide (object:nil), so only observe while the keyboard is up
101
+ - (void)startObservingTextChanges {
102
+ if (_observingTextChanges) {
103
+ return;
104
+ }
105
+ _observingTextChanges = YES;
106
+ [[NSNotificationCenter defaultCenter] addObserver:self
107
+ selector:@selector(focusedInputTextDidChange:)
108
+ name:UITextViewTextDidChangeNotification
109
+ object:nil];
110
+ }
111
+
112
+ - (void)stopObservingTextChanges {
113
+ if (!_observingTextChanges) {
114
+ return;
115
+ }
116
+ _observingTextChanges = NO;
117
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextViewTextDidChangeNotification object:nil];
118
+ }
119
+
120
+ #pragma mark - Layout
121
+
122
+ - (CGFloat)naturalHeight {
123
+ if (_state) {
124
+ CGFloat height = _state->getData().naturalHeight;
125
+ if (height > 0) {
126
+ return height;
127
+ }
128
+ }
129
+ return self.frame.size.height;
130
+ }
131
+
42
132
  - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics
43
133
  oldLayoutMetrics:(const LayoutMetrics &)oldLayoutMetrics {
44
134
  [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
45
135
 
46
- // Notify delegate when content size changes for sheet height updates
47
- CGSize newSize = CGSizeMake(layoutMetrics.frame.size.width, layoutMetrics.frame.size.height);
48
- if (!CGSizeEqualToSize(newSize, _lastSize)) {
49
- _lastSize = newSize;
50
- if ([self.delegate respondsToSelector:@selector(contentViewDidChangeSize:)]) {
51
- [self.delegate contentViewDidChangeSize:newSize];
52
- }
136
+ // A deep ScrollView unmount doesn't pass through this view's mount hooks —
137
+ // detect the stale reference here so it's released instead of lingering until the
138
+ // next explicit setup or recycle.
139
+ if (_detectedScrollView && ![_detectedScrollView isDescendantOfView:self]) {
140
+ [self.delegate contentViewScrollViewDidChange];
53
141
  }
54
142
  }
55
143
 
56
- - (void)didMoveToSuperview {
57
- [super didMoveToSuperview];
144
+ #pragma mark - Child Mounting
145
+
146
+ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
147
+ [super mountChildComponentView:childComponentView index:index];
148
+ [self checkScrollViewChanged];
149
+ }
150
+
151
+ - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
152
+ [super unmountChildComponentView:childComponentView index:index];
153
+ [self checkScrollViewChanged];
154
+ }
58
155
 
59
- // Setup scroll view pinning after Fabric mounts the view in container
60
- // Ensures proper view hierarchy for scroll detection and pinning
61
- if (self.superview) {
62
- [self setupScrollViewPinning];
156
+ - (void)checkScrollViewChanged {
157
+ if (!_detectedScrollView || ![_detectedScrollView isDescendantOfView:self]) {
158
+ [self.delegate contentViewScrollViewDidChange];
63
159
  }
64
160
  }
65
161
 
66
- - (void)setupScrollViewPinning {
67
- // Auto-detect and pin scroll views for proper sheet scrolling behavior
68
- // Pinning ensures ScrollView fills the sheet area and scrolls correctly with the sheet
162
+ // A handle that commits in the same transaction as the ScrollView's insertion
163
+ // resolves to nothing prop updates process before mount instructions, and a
164
+ // deep insertion doesn't pass through this view's mount hooks. Retry once the
165
+ // whole transaction has mounted.
166
+ - (void)mountingTransactionDidMount:(const MountingTransaction &)transaction
167
+ withSurfaceTelemetry:(const SurfaceTelemetry &)surfaceTelemetry {
168
+ if (_scrollableHandle > 0 && !_detectedScrollView) {
169
+ [self.delegate contentViewScrollViewDidChange];
170
+ }
171
+ }
172
+
173
+ #pragma mark - Scrollable
174
+
175
+ // The scroll indicator follows automatically — UIKit derives its insets from
176
+ // the content inset while `automaticallyAdjustsScrollIndicatorInsets` is set.
177
+ - (void)setKeyboardInset:(CGFloat)inset {
178
+ if (!_detectedScrollView)
179
+ return;
180
+
181
+ UIEdgeInsets contentInset = _detectedScrollView.scrollView.contentInset;
182
+ contentInset.bottom = inset;
183
+ _detectedScrollView.scrollView.contentInset = contentInset;
184
+ }
185
+
186
+ - (void)clearScrollable {
187
+ [self setKeyboardInset:0];
188
+ _appliedKeyboardOffset = 0;
189
+ if (_appliedContentInsetAdjustment) {
190
+ _detectedScrollView.scrollView.contentInsetAdjustmentBehavior = _originalInsetAdjustmentBehavior;
191
+ _appliedContentInsetAdjustment = NO;
192
+ }
193
+ _detectedScrollView = nil;
194
+ }
195
+
196
+ - (void)setupScrollable {
197
+ // Check if the detected scroll view is still valid (still in view hierarchy)
198
+ if (_detectedScrollView && ![_detectedScrollView isDescendantOfView:self]) {
199
+ [self clearScrollable];
200
+ }
201
+
202
+ if (_detectedScrollView) {
203
+ return;
204
+ }
205
+
69
206
  RCTScrollViewComponentView *scrollView = [self findScrollView];
207
+ if (!scrollView) {
208
+ return;
209
+ }
70
210
 
71
- if (scrollView && scrollView != _pinnedScrollView) {
72
- // Unpin previous scroll view if exists
73
- if (_pinnedScrollView) {
74
- [LayoutUtil unpinView:_pinnedScrollView];
75
- }
211
+ _detectedScrollView = scrollView;
76
212
 
77
- // Pin to container view to enable proper scrolling within the sheet
78
- UIView *containerView = self.superview;
79
- if (containerView) {
80
- [LayoutUtil pinView:scrollView toParentView:containerView edges:UIRectEdgeAll];
81
- _pinnedScrollView = scrollView;
82
- }
213
+ [self applyContentInsetAdjustment];
214
+
215
+ // If keyboard is currently showing, re-apply the keyboard inset to the new ScrollView
216
+ CGFloat keyboardHeight = _keyboardObserver ? _keyboardObserver.currentHeight : 0;
217
+ if (keyboardHeight > 0) {
218
+ [self setKeyboardInset:[self keyboardInsetWithHeight:keyboardHeight]];
83
219
  }
84
220
  }
85
221
 
222
+ // A relative footer stays behind the keyboard below the content, so its
223
+ // height shields that much of the keyboard's overlap. An absolute footer
224
+ // floats within the viewport — its clearance is the content padding's job
225
+ // (the caret reveal accounts for it, see footerOcclusion).
226
+ - (CGFloat)keyboardInsetWithHeight:(CGFloat)height {
227
+ CGFloat inset = height;
228
+ if (self.footerView && !_keyboardObserver.viewController.absoluteFooter) {
229
+ inset = MAX(0, height - self.footerView.frame.size.height);
230
+ }
231
+
232
+ // UIKit stacks the safe area on top of contentInset while the adjustment
233
+ // behavior is automatic — take it out so the total lands on the keyboard edge.
234
+ if (_appliedContentInsetAdjustment) {
235
+ inset = MAX(0, inset - _detectedScrollView.scrollView.safeAreaInsets.bottom);
236
+ }
237
+
238
+ // Track how much of keyboardOffset actually lands in the inset so the caret
239
+ // reveal can compensate — the offset shifts the inset, not the keyboard edge.
240
+ CGFloat adjustedInset = MAX(0, inset + self.keyboardOffset);
241
+ _appliedKeyboardOffset = adjustedInset - inset;
242
+
243
+ // Content that already fits above the keyboard has nothing to reveal — the
244
+ // inset would only open blank scroll range below it (huge gap at the bottom).
245
+ UIScrollView *scrollView = _detectedScrollView.scrollView;
246
+ if (scrollView.contentSize.height <= scrollView.bounds.size.height - adjustedInset) {
247
+ _appliedKeyboardOffset = 0;
248
+ return 0;
249
+ }
250
+
251
+ return adjustedInset;
252
+ }
253
+
254
+ // An absolute footer floats over the viewport's bottom edge — extend the
255
+ // caret target so it clears the footer, not just the keyboard.
256
+ - (CGFloat)footerOcclusion {
257
+ if (self.footerView && _keyboardObserver.viewController.absoluteFooter) {
258
+ return [self.footerView keyboardOcclusionHeight];
259
+ }
260
+ return 0;
261
+ }
262
+
263
+ // Resolves the user-provided `scrollableHandle` within the content subtree —
264
+ // Fabric component views carry their React tag as `UIView.tag`.
86
265
  - (RCTScrollViewComponentView *)findScrollView {
87
- // Get the React component's root view
88
- if (self.subviews.count == 0) {
266
+ if (_detectedScrollView) {
267
+ return _detectedScrollView;
268
+ }
269
+
270
+ if (_scrollableHandle <= 0) {
89
271
  return nil;
90
272
  }
91
273
 
92
- // Check first-level children for scroll views (ScrollView or FlatList)
93
- for (UIView *subview in self.subviews) {
94
- if ([subview isKindOfClass:RCTScrollViewComponentView.class]) {
95
- return static_cast<RCTScrollViewComponentView *>(subview);
96
- }
274
+ UIView *view = [self viewWithTag:_scrollableHandle];
275
+ if ([view isKindOfClass:RCTScrollViewComponentView.class]) {
276
+ return (RCTScrollViewComponentView *)view;
97
277
  }
98
278
 
99
279
  return nil;
100
280
  }
101
281
 
102
- - (void)prepareForRecycle {
103
- [super prepareForRecycle];
282
+ #pragma mark - Scroll Edge Effects
283
+
284
+ - (void)applyScrollEdgeEffects:(nullable ScrollableOptions *)options {
285
+ #if RNTS_IPHONE_OS_VERSION_AVAILABLE(26_0)
286
+ if (!_detectedScrollView)
287
+ return;
288
+
289
+ if (@available(iOS 26.0, *)) {
290
+ UIScrollView *scrollView = _detectedScrollView.scrollView;
291
+ auto topEffect = options ? options.topScrollEdgeEffect : TrueSheetViewTopScrollEdgeEffect::Hidden;
292
+ auto bottomEffect = options ? options.bottomScrollEdgeEffect : TrueSheetViewBottomScrollEdgeEffect::Hidden;
293
+
294
+ [self applyEdgeEffect:topEffect toEdge:scrollView.topEdgeEffect];
295
+ [self applyEdgeEffect:(TrueSheetViewTopScrollEdgeEffect)bottomEffect toEdge:scrollView.bottomEdgeEffect];
296
+ }
297
+ #endif
298
+ }
299
+
300
+ #if RNTS_IPHONE_OS_VERSION_AVAILABLE(26_0)
301
+ - (void)applyEdgeEffect:(TrueSheetViewTopScrollEdgeEffect)effect
302
+ toEdge:(UIScrollEdgeEffect *)edgeEffect API_AVAILABLE(ios(26.0)) {
303
+ switch (effect) {
304
+ case TrueSheetViewTopScrollEdgeEffect::Automatic:
305
+ edgeEffect.hidden = NO;
306
+ edgeEffect.style = UIScrollEdgeEffectStyle.automaticStyle;
307
+ break;
308
+ case TrueSheetViewTopScrollEdgeEffect::Hard:
309
+ edgeEffect.hidden = NO;
310
+ edgeEffect.style = UIScrollEdgeEffectStyle.hardStyle;
311
+ break;
312
+ case TrueSheetViewTopScrollEdgeEffect::Soft:
313
+ edgeEffect.hidden = NO;
314
+ edgeEffect.style = UIScrollEdgeEffectStyle.softStyle;
315
+ break;
316
+ case TrueSheetViewTopScrollEdgeEffect::Hidden:
317
+ edgeEffect.hidden = YES;
318
+ break;
319
+ }
320
+ }
321
+ #endif
322
+
323
+ #pragma mark - TrueSheetKeyboardObserverDelegate
324
+
325
+ - (void)keyboardWillShow:(CGFloat)height duration:(NSTimeInterval)duration curve:(UIViewAnimationOptions)curve {
326
+ if (!_detectedScrollView) {
327
+ return;
328
+ }
329
+
330
+ [self startObservingTextChanges];
331
+
332
+ TrueSheetViewController *sheetController = _keyboardObserver.viewController;
333
+ UIView *firstResponder = sheetController ? [sheetController.view findFirstResponder] : nil;
334
+
335
+ CGFloat inset = [self keyboardInsetWithHeight:height];
336
+ [UIView animateWithDuration:duration
337
+ delay:0
338
+ options:curve | UIViewAnimationOptionBeginFromCurrentState
339
+ animations:^{
340
+ [self setKeyboardInset:inset];
341
+ }
342
+ completion:nil];
104
343
 
105
- // Remove scroll view constraints
106
- if (_pinnedScrollView) {
107
- [LayoutUtil unpinView:_pinnedScrollView];
108
- _pinnedScrollView = nil;
344
+ // Defer scroll until the next run loop so content insets are applied first
345
+ if (firstResponder) {
346
+ dispatch_async(dispatch_get_main_queue(), ^{
347
+ [self scrollToFocusedCaretAnimated:YES];
348
+ });
109
349
  }
110
350
  }
111
351
 
352
+ - (void)focusedInputTextDidChange:(NSNotification *)notification {
353
+ if (!_detectedScrollView || !_keyboardObserver || _keyboardObserver.currentHeight <= 0) {
354
+ return;
355
+ }
356
+
357
+ TrueSheetViewController *sheetController = _keyboardObserver.viewController;
358
+ UIView *firstResponder = sheetController ? [sheetController.view findFirstResponder] : nil;
359
+ if (!firstResponder || notification.object != firstResponder) {
360
+ return;
361
+ }
362
+
363
+ dispatch_async(dispatch_get_main_queue(), ^{
364
+ // Typing can grow the content (e.g. a multiline input) past the fits-above-
365
+ // the-keyboard threshold — keep the inset in sync before revealing the caret.
366
+ [self setKeyboardInset:[self keyboardInsetWithHeight:self->_keyboardObserver.currentHeight]];
367
+ [self scrollToFocusedCaretAnimated:YES];
368
+ });
369
+ }
370
+
371
+ - (void)scrollToFocusedCaretAnimated:(BOOL)animated {
372
+ if (!_detectedScrollView) {
373
+ return;
374
+ }
375
+
376
+ TrueSheetViewController *sheetController = _keyboardObserver.viewController;
377
+ UIView *firstResponder = sheetController ? [sheetController.view findFirstResponder] : nil;
378
+ if (!firstResponder) {
379
+ return;
380
+ }
381
+
382
+ UIScrollView *scrollView = _detectedScrollView.scrollView;
383
+ CGRect targetRect = [firstResponder convertRect:firstResponder.bounds toView:scrollView];
384
+
385
+ if ([firstResponder conformsToProtocol:@protocol(UITextInput)]) {
386
+ id<UITextInput> textInput = (id<UITextInput>)firstResponder;
387
+ UITextRange *selectedRange = textInput.selectedTextRange;
388
+ if (selectedRange) {
389
+ CGRect caretRect = [textInput caretRectForPosition:selectedRange.end];
390
+ // caretRectForPosition: can return non-finite coordinates during layout/selection transitions
391
+ BOOL caretRectValid = !CGRectIsNull(caretRect) && !CGRectIsInfinite(caretRect) && isfinite(caretRect.origin.x) &&
392
+ isfinite(caretRect.origin.y) && isfinite(caretRect.size.width) &&
393
+ isfinite(caretRect.size.height);
394
+ if (caretRectValid) {
395
+ targetRect = [firstResponder convertRect:caretRect toView:scrollView];
396
+ }
397
+ }
398
+ }
399
+
400
+ targetRect.size.height += self.keyboardScrollOffset + [self footerOcclusion] - _appliedKeyboardOffset;
401
+ [scrollView scrollRectToVisible:targetRect animated:animated];
402
+ }
403
+
404
+ - (void)keyboardWillHide:(NSTimeInterval)duration curve:(UIViewAnimationOptions)curve {
405
+ [self stopObservingTextChanges];
406
+
407
+ if (!_detectedScrollView) {
408
+ return;
409
+ }
410
+
411
+ [UIView animateWithDuration:duration
412
+ delay:0
413
+ options:curve | UIViewAnimationOptionBeginFromCurrentState
414
+ animations:^{
415
+ [self setKeyboardInset:0];
416
+ }
417
+ completion:nil];
418
+ }
419
+
420
+ #pragma mark - Lifecycle
421
+
422
+ - (void)prepareForRecycle {
423
+ [super prepareForRecycle];
424
+ [self stopObservingTextChanges];
425
+ [self clearScrollable];
426
+ _state.reset();
427
+ _scrollableHandle = 0;
428
+ _contentInsetAdjustment = NO;
429
+ _lastReportedNaturalHeight = 0;
430
+ }
431
+
112
432
  @end
113
433
 
434
+ Class<RCTComponentViewProtocol> TrueSheetContentViewCls(void) {
435
+ return TrueSheetContentView.class;
436
+ }
437
+
114
438
  #endif
@@ -11,14 +11,45 @@
11
11
  #import <React/RCTSurfaceTouchHandler.h>
12
12
  #import <React/RCTViewComponentView.h>
13
13
  #import <UIKit/UIKit.h>
14
+ #import "core/TrueSheetKeyboardObserver.h"
14
15
 
15
16
  @class TrueSheetViewController;
16
17
 
17
18
  NS_ASSUME_NONNULL_BEGIN
18
19
 
19
- @interface TrueSheetFooterView : RCTViewComponentView
20
+ @protocol TrueSheetFooterViewDelegate <NSObject>
21
+ @optional
22
+ - (void)footerViewDidChangeSize:(CGSize)size;
23
+ @end
20
24
 
21
- - (void)setupConstraintsWithHeight:(CGFloat)height;
25
+ @interface TrueSheetFooterView : RCTViewComponentView <TrueSheetKeyboardObserverDelegate>
26
+
27
+ @property (nonatomic, weak, nullable) TrueSheetKeyboardObserver *keyboardObserver;
28
+ @property (nonatomic, weak, nullable) id<TrueSheetFooterViewDelegate> delegate;
29
+
30
+ /**
31
+ * Bottom inset currently baked into the footer's layout height — pairs with
32
+ * the measured frame so detent math can subtract exactly what's baked in.
33
+ */
34
+ @property (nonatomic, readonly) CGFloat appliedBottomInset;
35
+
36
+ /**
37
+ * Re-applies the footer's keyboard slide using the current keyboard height.
38
+ * No-op when the keyboard is hidden. Used to reflect live `keyboardOffset` changes.
39
+ */
40
+ - (void)applyKeyboardOffset;
41
+
42
+ /**
43
+ * Bottom safe-area inset the footer absorbs as padding (via the shadow node)
44
+ * so its content clears the home indicator and the background fills the inset.
45
+ */
46
+ - (void)setBottomInset:(CGFloat)bottomInset;
47
+
48
+ /**
49
+ * Height the footer occupies above the keyboard — its layout height minus
50
+ * the safe-area inset it drops while the keyboard is open.
51
+ */
52
+ - (CGFloat)keyboardOcclusionHeight;
22
53
 
23
54
  @end
24
55