@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
@@ -10,18 +10,32 @@
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"
20
+ #import "TrueSheetView.h"
17
21
  #import "TrueSheetViewController.h"
18
- #import "utils/LayoutUtil.h"
22
+ #import "utils/PlatformUtil.h"
23
+ #import "utils/UIView+FirstResponder.h"
19
24
 
20
25
  using namespace facebook::react;
21
26
 
27
+ static void *TrueSheetContentSizeContext = &TrueSheetContentSizeContext;
28
+
22
29
  @implementation TrueSheetContentView {
30
+ TrueSheetContentViewShadowNode::ConcreteState::Shared _state;
23
31
  RCTScrollViewComponentView *_pinnedScrollView;
32
+ UIScrollView *_observedScrollView;
24
33
  CGSize _lastSize;
34
+ CGFloat _bottomInset;
35
+ CGFloat _originalIndicatorBottomInset;
36
+ BOOL _observingTextChanges;
37
+ BOOL _scrollableBounded;
38
+ BOOL _isReportPending;
25
39
  }
26
40
 
27
41
  + (ComponentDescriptorProvider)componentDescriptorProvider {
@@ -32,83 +46,439 @@ using namespace facebook::react;
32
46
  if (self = [super initWithFrame:frame]) {
33
47
  static const auto defaultProps = std::make_shared<const TrueSheetContentViewProps>();
34
48
  _props = defaultProps;
35
-
36
- _pinnedScrollView = nil;
37
- _lastSize = CGSizeZero;
38
49
  }
39
50
  return self;
40
51
  }
41
52
 
53
+ - (void)dealloc {
54
+ [self stopObservingTextChanges];
55
+ [self unobserveScrollViewContentSize];
56
+ }
57
+
58
+ - (void)updateState:(const State::Shared &)state oldState:(const State::Shared &)oldState {
59
+ _state = std::static_pointer_cast<TrueSheetContentViewShadowNode::ConcreteState const>(state);
60
+ }
61
+
62
+ // Tells the shadow node to fill the container (flexGrow/flexShrink) so the
63
+ // pinned ScrollView's viewport is bounded to the visible space. Only applied
64
+ // for auto detents — otherwise content lays out naturally like a regular view.
65
+ - (void)setScrollableBounded:(BOOL)bounded {
66
+ if (_scrollableBounded == bounded) {
67
+ return;
68
+ }
69
+ _scrollableBounded = bounded;
70
+
71
+ if (_state) {
72
+ TrueSheetContentViewState newState;
73
+ newState.scrollableBounded = bounded;
74
+ _state->updateState(std::move(newState));
75
+ }
76
+ }
77
+
78
+ - (void)setHasAutoDetent:(BOOL)hasAutoDetent {
79
+ if (_hasAutoDetent == hasAutoDetent) {
80
+ return;
81
+ }
82
+ _hasAutoDetent = hasAutoDetent;
83
+
84
+ if (_pinnedScrollView) {
85
+ [self setScrollableBounded:hasAutoDetent];
86
+ }
87
+ }
88
+
89
+ #pragma mark - Text Change Observing
90
+
91
+ // The notification is app-wide (object:nil), so only observe while the keyboard is up
92
+ - (void)startObservingTextChanges {
93
+ if (_observingTextChanges) {
94
+ return;
95
+ }
96
+ _observingTextChanges = YES;
97
+ [[NSNotificationCenter defaultCenter] addObserver:self
98
+ selector:@selector(focusedInputTextDidChange:)
99
+ name:UITextViewTextDidChangeNotification
100
+ object:nil];
101
+ }
102
+
103
+ - (void)stopObservingTextChanges {
104
+ if (!_observingTextChanges) {
105
+ return;
106
+ }
107
+ _observingTextChanges = NO;
108
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextViewTextDidChangeNotification object:nil];
109
+ }
110
+
111
+ #pragma mark - Layout
112
+
113
+ - (CGFloat)naturalHeight {
114
+ CGFloat height = self.frame.size.height;
115
+ if (_pinnedScrollView) {
116
+ height += _pinnedScrollView.scrollView.contentSize.height - _pinnedScrollView.frame.size.height;
117
+ }
118
+ return MAX(0, height);
119
+ }
120
+
121
+ - (void)reportSizeIfChanged {
122
+ // A deep ScrollView unmount doesn't pass through this view's mount hooks —
123
+ // detect the stale pin here so it (and its contentSize observation) is
124
+ // released instead of lingering until the next explicit setup or recycle.
125
+ if (_pinnedScrollView && ![_pinnedScrollView isDescendantOfView:self]) {
126
+ [self.delegate contentViewScrollViewDidChange];
127
+ }
128
+
129
+ // naturalHeight mixes frames from different views; mid-transaction they're
130
+ // momentarily inconsistent (parent updates before the ScrollView), which
131
+ // feeds back into the auto detent and oscillates. Coalesce to the next
132
+ // main-queue tick so frames are settled before measuring.
133
+ if (_pinnedScrollView) {
134
+ if (_isReportPending) {
135
+ return;
136
+ }
137
+ _isReportPending = YES;
138
+
139
+ __weak __typeof(self) weakSelf = self;
140
+ dispatch_async(dispatch_get_main_queue(), ^{
141
+ __typeof(self) strongSelf = weakSelf;
142
+ if (!strongSelf) {
143
+ return;
144
+ }
145
+ strongSelf->_isReportPending = NO;
146
+ [strongSelf reportSizeNow];
147
+ });
148
+ return;
149
+ }
150
+
151
+ [self reportSizeNow];
152
+ }
153
+
154
+ - (void)reportSizeNow {
155
+ CGSize newSize = CGSizeMake(self.frame.size.width, self.naturalHeight);
156
+ if (!CGSizeEqualToSize(newSize, _lastSize)) {
157
+ _lastSize = newSize;
158
+ [self.delegate contentViewDidChangeSize:newSize];
159
+ }
160
+ }
161
+
42
162
  - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics
43
163
  oldLayoutMetrics:(const LayoutMetrics &)oldLayoutMetrics {
44
164
  [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
165
+ [self reportSizeIfChanged];
166
+ }
45
167
 
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
- }
168
+ #pragma mark - Child Mounting
169
+
170
+ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
171
+ [super mountChildComponentView:childComponentView index:index];
172
+ [self checkScrollViewChanged];
173
+ }
174
+
175
+ - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
176
+ [super unmountChildComponentView:childComponentView index:index];
177
+ [self checkScrollViewChanged];
178
+ }
179
+
180
+ - (void)checkScrollViewChanged {
181
+ if (!_pinnedScrollView || ![_pinnedScrollView isDescendantOfView:self]) {
182
+ [self.delegate contentViewScrollViewDidChange];
53
183
  }
54
184
  }
55
185
 
56
- - (void)didMoveToSuperview {
57
- [super didMoveToSuperview];
186
+ #pragma mark - Scrollable
187
+
188
+ - (void)setScrollViewContentInset:(CGFloat)contentBottom indicatorInset:(CGFloat)indicatorBottom {
189
+ if (!_pinnedScrollView)
190
+ return;
191
+
192
+ UIEdgeInsets contentInset = _pinnedScrollView.scrollView.contentInset;
193
+ contentInset.bottom = contentBottom;
194
+ _pinnedScrollView.scrollView.contentInset = contentInset;
195
+
196
+ UIEdgeInsets indicatorInsets = _pinnedScrollView.scrollView.verticalScrollIndicatorInsets;
197
+ indicatorInsets.bottom = indicatorBottom;
198
+ _pinnedScrollView.scrollView.verticalScrollIndicatorInsets = indicatorInsets;
199
+ }
58
200
 
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];
201
+ - (void)clearScrollable {
202
+ if (_pinnedScrollView) {
203
+ [self setScrollViewContentInset:0 indicatorInset:_originalIndicatorBottomInset];
63
204
  }
205
+ [self unobserveScrollViewContentSize];
206
+ [self setScrollableBounded:NO];
207
+ _pinnedScrollView = nil;
208
+ _bottomInset = 0;
209
+ _originalIndicatorBottomInset = 0;
210
+ [self reportSizeIfChanged];
64
211
  }
65
212
 
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
213
+ - (void)setupScrollableWithBottomInset:(CGFloat)bottomInset {
214
+ // Check if pinned scroll view is still valid (still in view hierarchy)
215
+ if (_pinnedScrollView && ![_pinnedScrollView isDescendantOfView:self]) {
216
+ [self clearScrollable];
217
+ }
218
+
219
+ // Already set up with same inset and valid scroll view
220
+ if (_pinnedScrollView && _bottomInset == bottomInset) {
221
+ return;
222
+ }
223
+
69
224
  RCTScrollViewComponentView *scrollView = [self findScrollView];
225
+ if (!scrollView) {
226
+ return;
227
+ }
70
228
 
71
- if (scrollView && scrollView != _pinnedScrollView) {
72
- // Unpin previous scroll view if exists
73
- if (_pinnedScrollView) {
74
- [LayoutUtil unpinView:_pinnedScrollView];
75
- }
229
+ // Only capture originals on first pin
230
+ if (!_pinnedScrollView) {
231
+ _originalIndicatorBottomInset = scrollView.scrollView.verticalScrollIndicatorInsets.bottom;
232
+ _pinnedScrollView = scrollView;
76
233
 
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
- }
234
+ [self observeScrollViewContentSize];
235
+ [self setScrollableBounded:_hasAutoDetent];
236
+ [self reportSizeIfChanged];
237
+ }
238
+
239
+ _bottomInset = bottomInset;
240
+
241
+ [self setScrollViewContentInset:_bottomInset indicatorInset:_originalIndicatorBottomInset];
242
+
243
+ // If keyboard is currently showing, re-apply the keyboard inset to the new ScrollView
244
+ CGFloat keyboardHeight = _keyboardObserver ? _keyboardObserver.currentHeight : 0;
245
+ if (keyboardHeight > 0) {
246
+ CGFloat inset = [self keyboardInsetWithHeight:keyboardHeight];
247
+ [self setScrollViewContentInset:inset indicatorInset:_originalIndicatorBottomInset + inset];
83
248
  }
84
249
  }
85
250
 
251
+ // An absolute footer rises above the keyboard and covers the content's bottom
252
+ // edge — include it so the caret clears the footer, not just the keyboard.
253
+ // A relative footer stays behind the keyboard below the content, so its
254
+ // height shields that much of the keyboard's overlap.
255
+ - (CGFloat)keyboardInsetWithHeight:(CGFloat)height {
256
+ if (!self.footerView) {
257
+ return height;
258
+ }
259
+ if (_keyboardObserver.viewController.absoluteFooter) {
260
+ return height + [self.footerView keyboardOcclusionHeight];
261
+ }
262
+ return MAX(0, height - self.footerView.frame.size.height);
263
+ }
264
+
265
+ // Content growth is invisible to layout once the viewport is bounded, so track
266
+ // the scroll content size directly to keep the auto detent height in sync.
267
+ - (void)observeScrollViewContentSize {
268
+ UIScrollView *scrollView = _pinnedScrollView.scrollView;
269
+ if (_observedScrollView == scrollView) {
270
+ return;
271
+ }
272
+ [self unobserveScrollViewContentSize];
273
+ _observedScrollView = scrollView;
274
+ [scrollView addObserver:self
275
+ forKeyPath:@"contentSize"
276
+ options:NSKeyValueObservingOptionNew
277
+ context:TrueSheetContentSizeContext];
278
+ }
279
+
280
+ - (void)unobserveScrollViewContentSize {
281
+ if (_observedScrollView) {
282
+ [_observedScrollView removeObserver:self forKeyPath:@"contentSize" context:TrueSheetContentSizeContext];
283
+ _observedScrollView = nil;
284
+ }
285
+ }
286
+
287
+ - (void)observeValueForKeyPath:(NSString *)keyPath
288
+ ofObject:(id)object
289
+ change:(NSDictionary *)change
290
+ context:(void *)context {
291
+ if (context == TrueSheetContentSizeContext) {
292
+ [self reportSizeIfChanged];
293
+ return;
294
+ }
295
+ [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
296
+ }
297
+
86
298
  - (RCTScrollViewComponentView *)findScrollView {
87
- // Get the React component's root view
299
+ if (_pinnedScrollView) {
300
+ return _pinnedScrollView;
301
+ }
302
+
88
303
  if (self.subviews.count == 0) {
89
304
  return nil;
90
305
  }
91
306
 
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);
307
+ RCTScrollViewComponentView *scrollView = [self findScrollViewInSubviews:self.subviews];
308
+
309
+ if (!scrollView) {
310
+ for (UIView *subview in self.subviews) {
311
+ scrollView = [self findScrollViewInSubviews:subview.subviews];
312
+ if (scrollView) {
313
+ break;
314
+ }
96
315
  }
97
316
  }
98
317
 
318
+ return scrollView;
319
+ }
320
+
321
+ - (RCTScrollViewComponentView *)findScrollViewInSubviews:(NSArray<UIView *> *)subviews {
322
+ for (UIView *subview in subviews) {
323
+ if ([subview isKindOfClass:RCTScrollViewComponentView.class] && ![subview isKindOfClass:TrueSheetView.class]) {
324
+ return (RCTScrollViewComponentView *)subview;
325
+ }
326
+ }
99
327
  return nil;
100
328
  }
101
329
 
102
- - (void)prepareForRecycle {
103
- [super prepareForRecycle];
330
+ #pragma mark - Scroll Edge Effects
104
331
 
105
- // Remove scroll view constraints
106
- if (_pinnedScrollView) {
107
- [LayoutUtil unpinView:_pinnedScrollView];
108
- _pinnedScrollView = nil;
332
+ - (void)applyScrollEdgeEffects:(nullable ScrollableOptions *)options {
333
+ #if RNTS_IPHONE_OS_VERSION_AVAILABLE(26_0)
334
+ if (!_pinnedScrollView)
335
+ return;
336
+
337
+ if (@available(iOS 26.0, *)) {
338
+ UIScrollView *scrollView = _pinnedScrollView.scrollView;
339
+ auto topEffect = options ? options.topScrollEdgeEffect : TrueSheetViewTopScrollEdgeEffect::Hidden;
340
+ auto bottomEffect = options ? options.bottomScrollEdgeEffect : TrueSheetViewBottomScrollEdgeEffect::Hidden;
341
+
342
+ [self applyEdgeEffect:topEffect toEdge:scrollView.topEdgeEffect];
343
+ [self applyEdgeEffect:(TrueSheetViewTopScrollEdgeEffect)bottomEffect toEdge:scrollView.bottomEdgeEffect];
344
+ }
345
+ #endif
346
+ }
347
+
348
+ #if RNTS_IPHONE_OS_VERSION_AVAILABLE(26_0)
349
+ - (void)applyEdgeEffect:(TrueSheetViewTopScrollEdgeEffect)effect
350
+ toEdge:(UIScrollEdgeEffect *)edgeEffect API_AVAILABLE(ios(26.0)) {
351
+ switch (effect) {
352
+ case TrueSheetViewTopScrollEdgeEffect::Automatic:
353
+ edgeEffect.hidden = NO;
354
+ edgeEffect.style = UIScrollEdgeEffectStyle.automaticStyle;
355
+ break;
356
+ case TrueSheetViewTopScrollEdgeEffect::Hard:
357
+ edgeEffect.hidden = NO;
358
+ edgeEffect.style = UIScrollEdgeEffectStyle.hardStyle;
359
+ break;
360
+ case TrueSheetViewTopScrollEdgeEffect::Soft:
361
+ edgeEffect.hidden = NO;
362
+ edgeEffect.style = UIScrollEdgeEffectStyle.softStyle;
363
+ break;
364
+ case TrueSheetViewTopScrollEdgeEffect::Hidden:
365
+ edgeEffect.hidden = YES;
366
+ break;
367
+ }
368
+ }
369
+ #endif
370
+
371
+ #pragma mark - TrueSheetKeyboardObserverDelegate
372
+
373
+ - (void)keyboardWillShow:(CGFloat)height duration:(NSTimeInterval)duration curve:(UIViewAnimationOptions)curve {
374
+ if (!_pinnedScrollView) {
375
+ return;
376
+ }
377
+
378
+ [self startObservingTextChanges];
379
+
380
+ TrueSheetViewController *sheetController = _keyboardObserver.viewController;
381
+ UIView *firstResponder = sheetController ? [sheetController.view findFirstResponder] : nil;
382
+
383
+ CGFloat inset = [self keyboardInsetWithHeight:height];
384
+ [UIView animateWithDuration:duration
385
+ delay:0
386
+ options:curve | UIViewAnimationOptionBeginFromCurrentState
387
+ animations:^{
388
+ [self setScrollViewContentInset:inset indicatorInset:self->_originalIndicatorBottomInset + inset];
389
+ }
390
+ completion:nil];
391
+
392
+ // Defer scroll until the next run loop so content insets are applied first
393
+ if (firstResponder) {
394
+ dispatch_async(dispatch_get_main_queue(), ^{
395
+ [self scrollToFocusedCaretAnimated:YES];
396
+ });
397
+ }
398
+ }
399
+
400
+ - (void)focusedInputTextDidChange:(NSNotification *)notification {
401
+ if (!_pinnedScrollView || !_keyboardObserver || _keyboardObserver.currentHeight <= 0) {
402
+ return;
403
+ }
404
+
405
+ TrueSheetViewController *sheetController = _keyboardObserver.viewController;
406
+ UIView *firstResponder = sheetController ? [sheetController.view findFirstResponder] : nil;
407
+ if (!firstResponder || notification.object != firstResponder) {
408
+ return;
409
+ }
410
+
411
+ dispatch_async(dispatch_get_main_queue(), ^{
412
+ [self scrollToFocusedCaretAnimated:YES];
413
+ });
414
+ }
415
+
416
+ - (void)scrollToFocusedCaretAnimated:(BOOL)animated {
417
+ if (!_pinnedScrollView) {
418
+ return;
419
+ }
420
+
421
+ TrueSheetViewController *sheetController = _keyboardObserver.viewController;
422
+ UIView *firstResponder = sheetController ? [sheetController.view findFirstResponder] : nil;
423
+ if (!firstResponder) {
424
+ return;
109
425
  }
426
+
427
+ UIScrollView *scrollView = _pinnedScrollView.scrollView;
428
+ CGRect targetRect = [firstResponder convertRect:firstResponder.bounds toView:scrollView];
429
+
430
+ if ([firstResponder conformsToProtocol:@protocol(UITextInput)]) {
431
+ id<UITextInput> textInput = (id<UITextInput>)firstResponder;
432
+ UITextRange *selectedRange = textInput.selectedTextRange;
433
+ if (selectedRange) {
434
+ CGRect caretRect = [textInput caretRectForPosition:selectedRange.end];
435
+ // caretRectForPosition: can return non-finite coordinates during layout/selection transitions
436
+ BOOL caretRectValid = !CGRectIsNull(caretRect) && !CGRectIsInfinite(caretRect) && isfinite(caretRect.origin.x) &&
437
+ isfinite(caretRect.origin.y) && isfinite(caretRect.size.width) &&
438
+ isfinite(caretRect.size.height);
439
+ if (caretRectValid) {
440
+ targetRect = [firstResponder convertRect:caretRect toView:scrollView];
441
+ }
442
+ }
443
+ }
444
+
445
+ targetRect.size.height += self.keyboardScrollOffset;
446
+ [scrollView scrollRectToVisible:targetRect animated:animated];
447
+ }
448
+
449
+ - (void)keyboardWillHide:(NSTimeInterval)duration curve:(UIViewAnimationOptions)curve {
450
+ [self stopObservingTextChanges];
451
+
452
+ if (!_pinnedScrollView) {
453
+ return;
454
+ }
455
+
456
+ [UIView animateWithDuration:duration
457
+ delay:0
458
+ options:curve | UIViewAnimationOptionBeginFromCurrentState
459
+ animations:^{
460
+ [self setScrollViewContentInset:self->_bottomInset
461
+ indicatorInset:self->_originalIndicatorBottomInset];
462
+ }
463
+ completion:nil];
464
+ }
465
+
466
+ #pragma mark - Lifecycle
467
+
468
+ - (void)prepareForRecycle {
469
+ [super prepareForRecycle];
470
+ [self stopObservingTextChanges];
471
+ [self clearScrollable];
472
+ _state.reset();
473
+ _scrollableBounded = NO;
474
+ _hasAutoDetent = NO;
475
+ _lastSize = CGSizeZero;
110
476
  }
111
477
 
112
478
  @end
113
479
 
480
+ Class<RCTComponentViewProtocol> TrueSheetContentViewCls(void) {
481
+ return TrueSheetContentView.class;
482
+ }
483
+
114
484
  #endif
@@ -11,14 +11,39 @@
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
24
+
25
+ @interface TrueSheetFooterView : RCTViewComponentView <TrueSheetKeyboardObserverDelegate>
26
+
27
+ @property (nonatomic, weak, nullable) TrueSheetKeyboardObserver *keyboardObserver;
28
+ @property (nonatomic, weak, nullable) id<TrueSheetFooterViewDelegate> delegate;
29
+
30
+ /**
31
+ * Re-applies the footer's keyboard slide using the current keyboard height.
32
+ * No-op when the keyboard is hidden. Used to reflect live `keyboardOffset` changes.
33
+ */
34
+ - (void)applyKeyboardOffset;
35
+
36
+ /**
37
+ * Bottom safe-area inset the footer absorbs as padding (via the shadow node)
38
+ * so its content clears the home indicator and the background fills the inset.
39
+ */
40
+ - (void)setBottomInset:(CGFloat)bottomInset;
20
41
 
21
- - (void)setupConstraintsWithHeight:(CGFloat)height;
42
+ /**
43
+ * Height the footer occupies above the keyboard — its layout height minus
44
+ * the safe-area inset it drops while the keyboard is open.
45
+ */
46
+ - (CGFloat)keyboardOcclusionHeight;
22
47
 
23
48
  @end
24
49