@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
@@ -2,72 +2,84 @@ package com.lodev09.truesheet
2
2
 
3
3
  import android.annotation.SuppressLint
4
4
  import android.view.View
5
- import android.view.ViewStructure
5
+ import android.view.ViewGroup
6
6
  import android.view.accessibility.AccessibilityEvent
7
7
  import androidx.annotation.UiThread
8
8
  import com.facebook.react.bridge.LifecycleEventListener
9
+ import com.facebook.react.uimanager.PixelUtil.dpToPx
10
+ import com.facebook.react.uimanager.PixelUtil.pxToDp
11
+ import com.facebook.react.uimanager.StateWrapper
9
12
  import com.facebook.react.uimanager.ThemedReactContext
10
13
  import com.facebook.react.uimanager.UIManagerHelper
11
14
  import com.facebook.react.uimanager.events.EventDispatcher
15
+ import com.facebook.react.util.RNLog
12
16
  import com.facebook.react.views.view.ReactViewGroup
13
- import com.lodev09.truesheet.events.DetentChangeEvent
14
- import com.lodev09.truesheet.events.DidDismissEvent
15
- import com.lodev09.truesheet.events.DidPresentEvent
16
- import com.lodev09.truesheet.events.DragBeginEvent
17
- import com.lodev09.truesheet.events.DragChangeEvent
18
- import com.lodev09.truesheet.events.DragEndEvent
19
- import com.lodev09.truesheet.events.MountEvent
20
- import com.lodev09.truesheet.events.PositionChangeEvent
21
- import com.lodev09.truesheet.events.SizeChangeEvent
22
- import com.lodev09.truesheet.events.WillDismissEvent
23
- import com.lodev09.truesheet.events.WillPresentEvent
17
+ import com.lodev09.truesheet.core.AccessibilityOptions
18
+ import com.lodev09.truesheet.core.GrabberOptions
19
+ import com.lodev09.truesheet.core.RNScreensEventObserver
20
+ import com.lodev09.truesheet.core.RNScreensEventObserverDelegate
21
+ import com.lodev09.truesheet.core.TrueSheetStackManager
22
+ import com.lodev09.truesheet.events.*
23
+ import com.lodev09.truesheet.utils.KeyboardUtils
24
+ import com.lodev09.truesheet.utils.findRootContainerView
24
25
 
25
26
  /**
26
- * Main TrueSheet host view.
27
- * Manages the sheet dialog and container, and dispatches events to JavaScript.
27
+ * Main TrueSheet host view that manages the sheet and dispatches events to JavaScript.
28
+ * This view is hidden (GONE) and delegates all rendering to TrueSheetViewController
29
+ * using a CoordinatorLayout approach (no separate dialog window).
28
30
  */
29
31
  @SuppressLint("ViewConstructor")
30
32
  class TrueSheetView(private val reactContext: ThemedReactContext) :
31
33
  ReactViewGroup(reactContext),
32
34
  LifecycleEventListener,
33
35
  TrueSheetViewControllerDelegate,
34
- TrueSheetContainerViewDelegate {
36
+ TrueSheetContainerViewDelegate,
37
+ RNScreensEventObserverDelegate {
35
38
 
36
- /**
37
- * The TrueSheetViewController instance that acts as both root view and controller
38
- */
39
- private val viewController: TrueSheetViewController = TrueSheetViewController(reactContext)
40
-
41
- /**
42
- * Gets the container view (first child of view controller)
43
- */
44
- private val containerView: TrueSheetContainerView?
45
- get() = viewController.getChildAt(0) as? TrueSheetContainerView
39
+ // ==================== Properties ====================
46
40
 
47
- var eventDispatcher: EventDispatcher? = null
41
+ internal val viewController: TrueSheetViewController = TrueSheetViewController(reactContext)
42
+ override var eventDispatcher: EventDispatcher? = null
48
43
 
44
+ // Initial present configuration (set by ViewManager before mount)
49
45
  var initialDetentIndex: Int = -1
50
46
  var initialDetentAnimated: Boolean = true
47
+ private var didInitiallyPresent: Boolean = false
51
48
 
52
- /**
53
- * Tracks if initial presentation has been handled
54
- */
55
- private var hasHandledInitialPresentation = false
49
+ private var lastContainerWidth: Int = 0
50
+ private var lastContainerHeight: Int = 0
51
+
52
+ var stateWrapper: StateWrapper? = null
53
+ set(value) {
54
+ field = value
55
+
56
+ // On first state wrapper assignment, immediately update state with screen dimensions.
57
+ // This ensures Yoga has initial width/height for content layout before presenting.
58
+ if (value != null && lastContainerWidth == 0 && lastContainerHeight == 0) {
59
+ updateState(viewController.screenWidth, viewController.screenHeight)
60
+ }
61
+ }
62
+
63
+ // Debounce flag to coalesce rapid layout changes into a single sheet update
64
+ private var isSheetUpdatePending: Boolean = false
65
+
66
+ // Root container for the coordinator layout (activity or Modal dialog content view)
67
+ internal var rootContainerView: ViewGroup? = null
68
+
69
+ // Screen event observer for react-native-screens integration
70
+ internal var screensEventObserver: RNScreensEventObserver? = null
71
+
72
+ // ==================== Initialization ====================
56
73
 
57
74
  init {
58
75
  reactContext.addLifecycleEventListener(this)
59
-
60
- // Set delegates
61
76
  viewController.delegate = this
62
77
 
63
- // Hide the host view from layout and touch handling
64
- // The actual content is shown in a dialog window
78
+ // Hide the host view - actual content is rendered in the dialog window
65
79
  visibility = GONE
66
80
  }
67
81
 
68
- override fun dispatchProvideStructure(structure: ViewStructure) {
69
- super.dispatchProvideStructure(structure)
70
- }
82
+ // ==================== ReactViewGroup Overrides ====================
71
83
 
72
84
  override fun onLayout(
73
85
  changed: Boolean,
@@ -76,317 +88,643 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
76
88
  right: Int,
77
89
  bottom: Int
78
90
  ) {
79
- // Do nothing as we are laid out by UIManager
91
+ // No-op: layout is managed by React Native's UIManager
80
92
  }
81
93
 
82
94
  override fun setId(id: Int) {
83
95
  super.setId(id)
84
-
85
96
  viewController.id = id
86
97
  TrueSheetModule.registerView(this, id)
87
98
  }
88
99
 
100
+ // ==================== View Hierarchy Management ====================
101
+
89
102
  override fun onAttachedToWindow() {
90
103
  super.onAttachedToWindow()
91
- }
92
-
93
- override fun onDetachedFromWindow() {
94
- super.onDetachedFromWindow()
95
- onDropInstance()
96
-
97
- TrueSheetModule.unregisterView(id)
104
+ presentInitialIfNeeded()
98
105
  }
99
106
 
100
107
  /**
101
- * showOrUpdate will display the Dialog. It is called by the manager once all properties are set
102
- * because we need to know all of them before creating the Dialog. It is also smart during updates
103
- * if the changed properties can be applied directly to the Dialog or require the recreation of a
104
- * new Dialog.
108
+ * JS holds initialDetentIndex back one commit so effect-driven content (e.g. a
109
+ * navigation footer set via setOptions) commits together with it. The prop then
110
+ * arrives after attach, so the ViewManager triggers this on prop update too.
111
+ * Posted so sibling mounts from the current transaction land before measuring.
105
112
  */
106
- fun showOrUpdate() {
107
- // Only handle initial presentation once on mount
108
- if (!hasHandledInitialPresentation && initialDetentIndex >= 0) {
109
- hasHandledInitialPresentation = true
110
-
111
- // Create dialog if not created yet
112
- if (!viewController.isPresented) {
113
- viewController.createDialog()
113
+ fun presentInitialIfNeeded() {
114
+ if (initialDetentIndex < 0 || didInitiallyPresent || !isAttachedToWindow) return
115
+
116
+ didInitiallyPresent = true
117
+ post {
118
+ // The view may have been dropped (flag reset) or detached before this
119
+ // ran — roll back so a later attach retries instead of presenting a
120
+ // sheet with no live host.
121
+ if (!didInitiallyPresent) return@post
122
+ if (!isAttachedToWindow) {
123
+ didInitiallyPresent = false
124
+ return@post
114
125
  }
115
-
116
- post {
126
+ if (!viewController.isPresented) {
117
127
  present(initialDetentIndex, initialDetentAnimated) { }
118
128
  }
119
- } else if (viewController.isPresented) {
120
- viewController.setupSheetDetents()
121
- viewController.setStateForDetentIndex(viewController.currentDetentIndex)
122
- viewController.positionFooter()
123
129
  }
124
130
  }
125
131
 
126
- // ==================== View Management ====================
127
-
128
132
  override fun addView(child: View?, index: Int) {
129
- // Add the child to our ViewController
130
- // This is the TrueSheetContainerView
133
+ if (child is TrueSheetContainerView) {
134
+ viewController.removeSheetSnapshot()
135
+ }
136
+
131
137
  viewController.addView(child, index)
132
138
 
133
- // Create dialog and dispatch mount event when TrueSheetContainerView is added
134
139
  if (child is TrueSheetContainerView) {
135
- // Set up container delegate to listen for content size changes
136
140
  child.delegate = this
137
-
138
- // Get initial content height from container
139
- val contentHeight = child.contentHeight
140
- if (contentHeight > 0) {
141
- viewController.contentHeight = contentHeight
142
- }
143
-
144
- // Create the dialog now that the container is mounted
145
- viewController.createDialog()
146
-
147
141
  val surfaceId = UIManagerHelper.getSurfaceId(this)
148
- eventDispatcher?.dispatchEvent(
149
- MountEvent(surfaceId, id)
150
- )
142
+ eventDispatcher?.dispatchEvent(MountEvent(surfaceId, id))
151
143
  }
152
144
  }
153
145
 
154
146
  override fun getChildCount(): Int = viewController.childCount
155
- override fun getChildAt(index: Int): View? = viewController.getChildAt(index)
156
147
 
157
- override fun removeView(child: View?) {
158
- if (child != null) {
159
- // Clean up container delegate
160
- if (child is TrueSheetContainerView) {
161
- child.delegate = null
162
- }
163
-
164
- viewController.removeView(child)
165
- }
166
- }
148
+ override fun getChildAt(index: Int): View? = viewController.getChildAt(index)
167
149
 
168
150
  override fun removeViewAt(index: Int) {
169
151
  val child = getChildAt(index)
152
+ if (child is TrueSheetContainerView) {
153
+ child.delegate = null
154
+
155
+ // Skip if already dismissing - snapshot preserves visuals during dismiss
156
+ if (!viewController.isBeingDismissed) {
157
+ viewController.createSheetSnapshot()
158
+ if (viewController.isPresented) {
159
+ dismiss(true) {}
160
+ }
161
+ }
162
+ }
170
163
  viewController.removeView(child)
171
164
  }
172
165
 
173
- override fun addChildrenForAccessibility(outChildren: ArrayList<View>) {
174
- // Explicitly override this to prevent accessibility events being passed down to children
175
- // Those will be handled by the mHostView which lives in the dialog
176
- }
177
-
178
- // Explicitly override this to prevent accessibility events being passed down to children
179
- // Those will be handled by the mHostView which lives in the dialog
166
+ // Accessibility: delegate to dialog's host view since this view is hidden
167
+ override fun addChildrenForAccessibility(outChildren: ArrayList<View>) {}
180
168
  override fun dispatchPopulateAccessibilityEvent(event: AccessibilityEvent): Boolean = false
181
169
 
182
- fun onDropInstance() {
183
- reactContext.removeLifecycleEventListener(this)
184
- TrueSheetModule.unregisterView(id)
185
-
186
- if (viewController.isPresented) {
187
- viewController.dismiss()
188
- }
189
- viewController.delegate = null
190
- }
170
+ // ==================== Lifecycle ====================
191
171
 
192
172
  override fun onHostResume() {
193
- showOrUpdate()
173
+ viewController.reapplyHiddenState()
174
+ finalizeUpdates()
194
175
  }
195
176
 
196
- override fun onHostPause() {
197
- }
177
+ override fun onHostPause() {}
198
178
 
199
179
  override fun onHostDestroy() {
200
180
  onDropInstance()
201
181
  }
202
182
 
203
- // ==================== TrueSheetViewControllerDelegate Implementation ====================
183
+ fun onDropInstance() {
184
+ reactContext.removeLifecycleEventListener(this)
204
185
 
205
- override fun viewControllerWillPresent(index: Int, position: Float) {
206
- val surfaceId = UIManagerHelper.getSurfaceId(this)
207
- eventDispatcher?.dispatchEvent(
208
- WillPresentEvent(surfaceId, id, index, position)
209
- )
210
- }
186
+ TrueSheetModule.unregisterView(id)
187
+ TrueSheetStackManager.removeSheet(this)
211
188
 
212
- override fun viewControllerDidPresent(index: Int, position: Float) {
213
- val surfaceId = UIManagerHelper.getSurfaceId(this)
214
- eventDispatcher?.dispatchEvent(
215
- DidPresentEvent(surfaceId, id, index, position)
216
- )
189
+ cleanupScreenEventObserver()
190
+ didInitiallyPresent = false
217
191
 
218
- // Set our touch event dispatcher on the view controller
219
- viewController.eventDispatcher = eventDispatcher
220
- }
192
+ viewController.dismissPromise = { viewController.delegate = null }
221
193
 
222
- override fun viewControllerWillDismiss() {
223
- val surfaceId = UIManagerHelper.getSurfaceId(this)
224
- eventDispatcher?.dispatchEvent(
225
- WillDismissEvent(surfaceId, id)
226
- )
227
-
228
- // Clear our touch event dispatcher on the view controller
229
- viewController.eventDispatcher = null
194
+ if (viewController.isPresented && !viewController.isBeingDismissed) {
195
+ viewController.dismiss(animated = false)
196
+ }
230
197
  }
231
198
 
232
- override fun viewControllerDidDismiss() {
233
- val surfaceId = UIManagerHelper.getSurfaceId(this)
234
- eventDispatcher?.dispatchEvent(
235
- DidDismissEvent(surfaceId, id)
236
- )
237
- }
199
+ /**
200
+ * Called by the ViewManager after all properties are set.
201
+ * Reconfigures the sheet if it's currently presented.
202
+ */
203
+ fun finalizeUpdates() {
204
+ setupScrollable()
238
205
 
239
- override fun viewControllerDidChangeDetent(index: Int, position: Float) {
240
- val surfaceId = UIManagerHelper.getSurfaceId(this)
241
- eventDispatcher?.dispatchEvent(
242
- DetentChangeEvent(surfaceId, id, index, position)
243
- )
206
+ if (viewController.isPresented) {
207
+ viewController.sheetView?.setupBackground()
208
+ viewController.sheetView?.setupGrabber()
209
+ viewController.sheetView?.updateGravity()
210
+ viewController.updateBehaviorMaxWidth()
211
+ updateSheetIfNeeded()
212
+ }
244
213
  }
245
214
 
246
- override fun viewControllerDidDragBegin(index: Int, position: Float) {
247
- val surfaceId = UIManagerHelper.getSurfaceId(this)
248
- eventDispatcher?.dispatchEvent(
249
- DragBeginEvent(surfaceId, id, index, position)
250
- )
251
- }
215
+ // ==================== Property Setters ====================
252
216
 
253
- override fun viewControllerDidDragChange(index: Int, position: Float) {
254
- val surfaceId = UIManagerHelper.getSurfaceId(this)
255
- eventDispatcher?.dispatchEvent(
256
- DragChangeEvent(surfaceId, id, index, position)
257
- )
217
+ fun setMaxContentHeight(height: Int?) {
218
+ if (viewController.maxContentHeight == height) return
219
+ viewController.maxContentHeight = height
258
220
  }
259
221
 
260
- override fun viewControllerDidDragEnd(index: Int, position: Float) {
261
- val surfaceId = UIManagerHelper.getSurfaceId(this)
262
- eventDispatcher?.dispatchEvent(
263
- DragEndEvent(surfaceId, id, index, position)
264
- )
222
+ fun setMaxContentWidth(width: Int?) {
223
+ if (viewController.maxContentWidth == width) return
224
+ viewController.maxContentWidth = width
265
225
  }
266
226
 
267
- override fun viewControllerDidChangePosition(index: Int, position: Float, transitioning: Boolean) {
268
- val surfaceId = UIManagerHelper.getSurfaceId(this)
269
- eventDispatcher?.dispatchEvent(
270
- PositionChangeEvent(surfaceId, id, index, position, transitioning)
271
- )
227
+ fun setAnchor(anchor: String?) {
228
+ val value = TrueSheetAnchor.fromString(anchor)
229
+ if (viewController.anchor == value) return
230
+ viewController.anchor = value
272
231
  }
273
232
 
274
- // ==================== Property Setters (forward to controller) ====================
275
-
276
- fun setMaxHeight(height: Int) {
277
- if (viewController.maxSheetHeight == height) return
278
- viewController.maxSheetHeight = height
233
+ fun setAnchorOffset(offset: Int) {
234
+ if (viewController.anchorOffset == offset) return
235
+ viewController.anchorOffset = offset
279
236
  }
280
237
 
281
238
  fun setDimmed(dimmed: Boolean) {
282
239
  if (viewController.dimmed == dimmed) return
283
240
  viewController.dimmed = dimmed
284
241
  if (viewController.isPresented) {
285
- viewController.setupDimmedBackground(viewController.currentDetentIndex)
242
+ viewController.setupDimmedBackground()
243
+ viewController.updateDimAmount()
244
+ TrueSheetStackManager.updateBackgroundAccessibility()
286
245
  }
287
246
  }
288
247
 
289
- fun setDimmedIndex(index: Int) {
290
- if (viewController.dimmedIndex == index) return
291
- viewController.dimmedIndex = index
248
+ fun setDimmedDetentIndex(index: Int) {
249
+ if (viewController.dimmedDetentIndex == index) return
250
+ viewController.dimmedDetentIndex = index
292
251
  if (viewController.isPresented) {
293
- viewController.setupDimmedBackground(viewController.currentDetentIndex)
252
+ viewController.setupDimmedBackground()
253
+ viewController.updateDimAmount()
254
+ TrueSheetStackManager.updateBackgroundAccessibility()
294
255
  }
295
256
  }
296
257
 
297
258
  fun setCornerRadius(radius: Float) {
298
- if (viewController.cornerRadius == radius) return
299
- viewController.cornerRadius = radius
300
- viewController.setupBackground()
259
+ if (viewController.sheetCornerRadius == radius) return
260
+ viewController.sheetCornerRadius = radius
301
261
  }
302
262
 
303
- fun setSheetBackgroundColor(color: Int) {
263
+ fun setSheetBackgroundColor(color: Int?) {
304
264
  if (viewController.sheetBackgroundColor == color) return
305
265
  viewController.sheetBackgroundColor = color
306
- viewController.setupBackground()
307
- }
308
-
309
- fun setSoftInputMode(mode: Int) {
310
- viewController.setSoftInputMode(mode)
311
266
  }
312
267
 
313
268
  fun setDismissible(dismissible: Boolean) {
314
269
  viewController.dismissible = dismissible
315
270
  }
316
271
 
317
- fun setGrabber(grabber: Boolean) {}
272
+ fun setDraggable(draggable: Boolean) {
273
+ viewController.draggable = draggable
274
+ }
275
+
276
+ fun setGrabber(grabber: Boolean) {
277
+ viewController.grabber = grabber
278
+ }
279
+
280
+ fun setGrabberOptions(options: GrabberOptions?) {
281
+ viewController.grabberOptions = options
282
+ }
283
+
284
+ fun setAccessibilityOptions(options: AccessibilityOptions?) {
285
+ viewController.accessibilityOptions = options
286
+ }
287
+
288
+ fun setSheetElevation(elevation: Float) {
289
+ viewController.sheetElevation = elevation
290
+ }
318
291
 
319
292
  fun setDetents(newDetents: MutableList<Double>) {
320
293
  viewController.detents = newDetents
294
+ setupScrollable()
321
295
  }
322
296
 
323
- fun setBlurTint(tint: String?) {}
297
+ fun setInsetAdjustment(insetAdjustment: String) {
298
+ viewController.insetAdjustment = TrueSheetInsetAdjustment.fromString(insetAdjustment)
299
+ setupScrollable()
300
+ }
301
+
302
+ fun setScrollableOptions(options: ScrollableOptions?) {
303
+ viewController.scrollableOptions = options
304
+ setupScrollable()
305
+ }
306
+
307
+ fun setScrollableHandle(handle: Int) {
308
+ if (viewController.scrollableHandle == handle) return
309
+ viewController.scrollableHandle = handle
310
+ setupScrollable()
311
+ }
312
+
313
+ fun setAbsoluteHeader(absolute: Boolean) {
314
+ viewController.absoluteHeader = absolute
315
+ }
316
+
317
+ fun setAbsoluteFooter(absolute: Boolean) {
318
+ viewController.absoluteFooter = absolute
319
+ }
320
+
321
+ fun setFooterKeyboardOffset(offset: Float) {
322
+ viewController.footerKeyboardOffset = offset.dpToPx().toInt()
323
+ viewController.positionFooter()
324
+ }
325
+
326
+ private fun setupScrollable() {
327
+ viewController.containerView?.let {
328
+ it.scrollableOptions = viewController.scrollableOptions
329
+ it.scrollableHandle = viewController.scrollableHandle
330
+ it.scrollableBottomInset = viewController.contentBottomInset
331
+ it.footerBottomInset = viewController.contentBottomInset
332
+ it.absoluteFooter = viewController.absoluteFooter
333
+ it.setupScrollable()
334
+ }
335
+
336
+ // Publish the inset so a footer set later (e.g. navigation setOptions) is
337
+ // padded on its very first layout instead of resizing the sheet twice.
338
+ if (viewController.insetAdjustment == TrueSheetInsetAdjustment.AUTOMATIC) {
339
+ TrueSheetStateUpdater.setBottomSafeArea(viewController.contentBottomInset.toFloat().pxToDp())
340
+ }
341
+ }
324
342
 
325
- fun setEdgeToEdgeFullScreen(edgeToEdgeFullScreen: Boolean) {
326
- viewController.edgeToEdgeFullScreen = edgeToEdgeFullScreen
343
+ // ==================== Screen Event Observer ====================
344
+
345
+ private fun setupScreenEventObserver() {
346
+ screensEventObserver = RNScreensEventObserver().apply {
347
+ delegate = this@TrueSheetView
348
+
349
+ // For stacked sheets on the same screen, inherit parent's presenter screen tag.
350
+ // If parent was hidden by screen navigation, this sheet is on a different screen.
351
+ val parentScreenTag = viewController.parentSheetView?.screensEventObserver?.presenterScreenTag ?: 0
352
+ val parentHiddenByScreen = viewController.parentSheetView?.viewController?.wasHiddenByScreen == true
353
+ if (parentScreenTag != 0 && !parentHiddenByScreen) {
354
+ presenterScreenTag = parentScreenTag
355
+ } else {
356
+ capturePresenterScreenFromView(this@TrueSheetView)
357
+ }
358
+ startObserving(eventDispatcher)
359
+ }
327
360
  }
328
361
 
362
+ private fun cleanupScreenEventObserver() {
363
+ screensEventObserver?.stopObserving()
364
+ screensEventObserver = null
365
+ }
366
+
367
+ // ==================== State Management ====================
368
+
329
369
  /**
330
- * Presents the sheet at the given detent index.
331
- *
332
- * @param detentIndex The detent index to present at
333
- * @param animated Whether to animate the presentation
334
- * @param promiseCallback Callback invoked when presentation completes
370
+ * Updates the Fabric state with container dimensions for Yoga layout.
371
+ * Converts pixel values to density-independent pixels (dp).
335
372
  */
373
+ fun updateState(width: Int, height: Int) {
374
+ if (width == lastContainerWidth && height == lastContainerHeight) return
375
+
376
+ lastContainerWidth = width
377
+ lastContainerHeight = height
378
+
379
+ stateWrapper?.let { TrueSheetStateUpdater.updateContainerSize(it, width, height) }
380
+ }
381
+
382
+ // ==================== Sheet Actions ====================
383
+
336
384
  @UiThread
337
385
  fun present(detentIndex: Int, animated: Boolean = true, promiseCallback: () -> Unit) {
386
+ if (viewController.isPresented) {
387
+ RNLog.w(reactContext, "TrueSheet: sheet is already presented. Use resize() to change detent.")
388
+ promiseCallback()
389
+ return
390
+ }
391
+
392
+ viewController.createSheet()
393
+ setupScrollable()
394
+
395
+ // Dismiss keyboard if focused view is within a sheet or if target detent will be dimmed
396
+ val parentSheet = TrueSheetStackManager.getTopmostSheet()
397
+ val isFocusedViewWithinSheet = parentSheet?.viewController?.isFocusedViewWithinSheet() == true
398
+ val shouldDismissKeyboard = isFocusedViewWithinSheet || viewController.isDimmedAtDetentIndex(detentIndex)
399
+ if (KeyboardUtils.isKeyboardVisible(reactContext) && shouldDismissKeyboard) {
400
+ viewController.saveFocusedView()
401
+ KeyboardUtils.dismiss(this) {
402
+ post { present(detentIndex, animated, promiseCallback) }
403
+ }
404
+ return
405
+ }
406
+
407
+ // Attach coordinator to the root container
408
+ rootContainerView = findRootContainerView()
409
+ viewController.coordinatorLayout?.let { rootContainerView?.addView(it) }
410
+
411
+ // Register with observer to track sheet stack hierarchy
412
+ viewController.parentSheetView = TrueSheetStackManager.registerSheet(this)
413
+
338
414
  viewController.presentPromise = promiseCallback
339
415
  viewController.present(detentIndex, animated)
340
416
  }
341
417
 
342
- /**
343
- * Dismisses the sheet.
344
- *
345
- * @param promiseCallback Callback invoked when dismissal completes
346
- */
347
418
  @UiThread
348
- fun dismiss(promiseCallback: () -> Unit) {
419
+ fun handleBackPress() {
420
+ viewController.handleBackPress()
421
+ }
422
+
423
+ @UiThread
424
+ fun dismiss(animated: Boolean = true, promiseCallback: () -> Unit) {
425
+ if (viewController.isBeingDismissed || !viewController.isPresented) {
426
+ RNLog.w(reactContext, "TrueSheet: sheet is already dismissed. No need to dismiss it again.")
427
+ promiseCallback()
428
+ return
429
+ }
430
+
431
+ // Dismiss all sheets above first
432
+ dismissStack(animated) {}
433
+
434
+ // Then dismiss itself
349
435
  viewController.dismissPromise = promiseCallback
350
- viewController.dismiss()
436
+ viewController.dismiss(animated)
351
437
  }
352
438
 
353
- override fun viewControllerDidChangeSize(width: Int, height: Int) {
354
- // Dispatch size change event to JS
355
- val surfaceId = UIManagerHelper.getSurfaceId(this)
356
- eventDispatcher?.dispatchEvent(
357
- SizeChangeEvent(surfaceId, id, width, height)
439
+ @UiThread
440
+ fun dismissStack(animated: Boolean = true, promiseCallback: () -> Unit) {
441
+ if (viewController.isBeingDismissed || !viewController.isPresented) {
442
+ RNLog.w(reactContext, "TrueSheet: sheet is already dismissed. No need to dismiss it again.")
443
+ promiseCallback()
444
+ return
445
+ }
446
+
447
+ val sheetsAbove = TrueSheetStackManager.getSheetsAbove(this)
448
+ // Create snapshot only for topmost sheet (first in reversed list)
449
+ sheetsAbove.firstOrNull()?.viewController?.createSheetSnapshot()
450
+
451
+ for (sheet in sheetsAbove) {
452
+ sheet.viewController.dismiss(animated)
453
+ }
454
+
455
+ promiseCallback()
456
+ }
457
+
458
+ @UiThread
459
+ fun resize(detentIndex: Int, promiseCallback: () -> Unit) {
460
+ if (!viewController.isPresented) {
461
+ RNLog.w(reactContext, "TrueSheet: Cannot resize. Sheet is not presented.")
462
+ promiseCallback()
463
+ return
464
+ }
465
+
466
+ viewController.resizePromise = promiseCallback
467
+ viewController.resize(detentIndex)
468
+ }
469
+
470
+ /**
471
+ * Debounced sheet update to handle rapid content/header size changes.
472
+ * Uses post() to ensure all layout passes complete before reconfiguring.
473
+ */
474
+ fun updateSheetIfNeeded() {
475
+ if (!viewController.isPresented || isSheetUpdatePending) return
476
+
477
+ isSheetUpdatePending = true
478
+ viewController.post {
479
+ isSheetUpdatePending = false
480
+ if (viewController.containerView == null) return@post
481
+
482
+ viewController.setupSheetDetentsForSizeChange()
483
+ // While settling, onSlide drives the parent translation in realtime —
484
+ // an animated update here would race it frame-by-frame, staggering the
485
+ // emitted position. Keyboard-driven resizes leave the parent alone (like
486
+ // iOS); keyboardDidHide resizes again once the detents are keyboard-free.
487
+ if (!viewController.isSettling && !viewController.isKeyboardActive) {
488
+ TrueSheetStackManager.updateParentTranslation(this)
489
+ }
490
+ }
491
+ }
492
+
493
+ // ==================== Sheet Stack Translation ====================
494
+
495
+ /**
496
+ * Updates this sheet's translation and disables dragging when a child sheet is presented.
497
+ * Parent sheets slide down to create a stacked appearance.
498
+ * Propagates additional translation to parent so the entire stack stays visually consistent.
499
+ */
500
+ fun updateTranslationForChild(childSheetTop: Int) {
501
+ if (!viewController.isSheetVisible || viewController.isExpanded) return
502
+
503
+ viewController.sheetView?.behavior?.isDraggable = false
504
+
505
+ val mySheetTop = viewController.detentCalculator.getSheetTopForDetentIndex(viewController.currentDetentIndex)
506
+ val newTranslation = maxOf(0, childSheetTop - mySheetTop)
507
+ val additionalTranslation = newTranslation - viewController.currentTranslationY
508
+
509
+ viewController.translateSheet(newTranslation)
510
+
511
+ // Propagate any additional translation up the stack
512
+ if (additionalTranslation > 0) {
513
+ TrueSheetStackManager.getParentSheet(this)?.addTranslation(additionalTranslation)
514
+ }
515
+ }
516
+
517
+ /**
518
+ * Realtime counterpart of updateTranslationForChild, driven by the child's
519
+ * onSlide frames so stacked sheets move in lockstep instead of on
520
+ * independently-timed animations.
521
+ */
522
+ fun syncTranslationForChild(childSheetTop: Int, childMinSheetTop: Int) {
523
+ if (!viewController.isSheetVisible || viewController.isExpanded) return
524
+
525
+ val mySheetTop = viewController.detentCalculator.getSheetTopForDetentIndex(viewController.currentDetentIndex)
526
+ val targetTranslation = maxOf(0, childMinSheetTop - mySheetTop)
527
+ val actualTranslation = maxOf(0, childSheetTop - mySheetTop)
528
+ val currentTranslation = viewController.currentTranslationY
529
+
530
+ // Ride the child's actual position, but only between the current
531
+ // translation and the settled target — tracks the child frame-by-frame
532
+ // when the alignment changes (auto detent resize) while staying put when
533
+ // the child moves between detents above its minimum. Returning early on
534
+ // no-ops avoids cancelling an in-flight realign animation.
535
+ val newTranslation = actualTranslation.coerceIn(
536
+ minOf(currentTranslation, targetTranslation),
537
+ maxOf(currentTranslation, targetTranslation)
358
538
  )
539
+ if (newTranslation == currentTranslation) return
540
+
541
+ viewController.translateSheet(newTranslation, animated = false)
542
+
543
+ val additionalTranslation = newTranslation - currentTranslation
544
+ if (additionalTranslation > 0) {
545
+ TrueSheetStackManager.getParentSheet(this)?.addTranslation(additionalTranslation, animated = false)
546
+ }
359
547
  }
360
548
 
361
- // ==================== TrueSheetContainerViewDelegate Implementation ====================
549
+ /**
550
+ * Recursively adds translation to this sheet and all parent sheets.
551
+ */
552
+ private fun addTranslation(amount: Int, animated: Boolean = true) {
553
+ if (viewController.isExpanded) return
362
554
 
363
- override fun containerViewContentDidChangeSize(width: Int, height: Int) {
364
- // Clamp content height to container height to prevent unbounded growth with scrollable content
365
- val containerHeight = viewController.maxScreenHeight
366
- val contentHeight = if (containerHeight > 0) minOf(height, containerHeight) else height
555
+ viewController.translateSheet(viewController.currentTranslationY + amount, animated)
556
+ TrueSheetStackManager.getParentSheet(this)?.addTranslation(amount, animated)
557
+ }
558
+
559
+ /**
560
+ * Resets this sheet's translation and restores dragging when it becomes topmost.
561
+ * Parent recalculates its translation based on this sheet's position.
562
+ */
563
+ fun resetTranslation(onTranslateEnd: (() -> Unit)? = null) {
564
+ viewController.sheetView?.behavior?.isDraggable = viewController.draggable
565
+ viewController.translateSheet(0, onEnd = onTranslateEnd)
566
+
567
+ // Parent should recalculate its translation based on this sheet's position
568
+ val mySheetTop = viewController.detentCalculator.getSheetTopForDetentIndex(viewController.currentDetentIndex)
569
+ TrueSheetStackManager.getParentSheet(this)?.updateTranslationForChild(mySheetTop)
570
+ }
367
571
 
368
- viewController.contentHeight = contentHeight
572
+ // ==================== TrueSheetViewControllerDelegate ====================
369
573
 
370
- // Update detents if sheet is already presented
371
- if (viewController.isPresented) {
372
- // Reconfigure sheet detents with new content height
373
- viewController.setupSheetDetents()
574
+ override fun viewControllerWillPresent(index: Int, position: Float, detent: Float) {
575
+ // Update parent sheet translation now that content is measured
576
+ TrueSheetStackManager.updateParentTranslation(this)
374
577
 
375
- // Use post to ensure layout is complete before positioning footer
376
- viewController.post {
377
- viewController.positionFooter()
578
+ val surfaceId = UIManagerHelper.getSurfaceId(this)
579
+ eventDispatcher?.dispatchEvent(WillPresentEvent(surfaceId, id, index, position, detent))
580
+ }
581
+
582
+ override fun viewControllerDidPresent(index: Int, position: Float, detent: Float) {
583
+ setupScreenEventObserver()
584
+
585
+ val surfaceId = UIManagerHelper.getSurfaceId(this)
586
+ eventDispatcher?.dispatchEvent(DidPresentEvent(surfaceId, id, index, position, detent))
587
+ }
588
+
589
+ override fun viewControllerWillDismiss() {
590
+ val surfaceId = UIManagerHelper.getSurfaceId(this)
591
+ eventDispatcher?.dispatchEvent(WillDismissEvent(surfaceId, id))
592
+ }
593
+
594
+ override fun viewControllerDidAttemptDismiss() {
595
+ val surfaceId = UIManagerHelper.getSurfaceId(this)
596
+ eventDispatcher?.dispatchEvent(DismissAttemptEvent(surfaceId, id))
597
+ }
598
+
599
+ override fun viewControllerDidDismiss(parent: TrueSheetView?) {
600
+ // Detach coordinator from the root container view
601
+ viewController.coordinatorLayout?.let { rootContainerView?.removeView(it) }
602
+ rootContainerView = null
603
+
604
+ cleanupScreenEventObserver()
605
+
606
+ val surfaceId = UIManagerHelper.getSurfaceId(this)
607
+ eventDispatcher?.dispatchEvent(DidDismissEvent(surfaceId, id))
608
+
609
+ TrueSheetStackManager.unregisterSheet(this)
610
+
611
+ parent?.resetTranslation {
612
+ val parentController = parent.viewController
613
+ if (parentController.isPresented && !parentController.isBeingDismissed) {
614
+ parent.viewControllerDidFocus()
378
615
  }
379
616
  }
380
617
  }
381
618
 
619
+ override fun viewControllerDidChangeDetent(index: Int, position: Float, detent: Float) {
620
+ val surfaceId = UIManagerHelper.getSurfaceId(this)
621
+ eventDispatcher?.dispatchEvent(DetentChangeEvent(surfaceId, id, index, position, detent))
622
+ }
623
+
624
+ override fun viewControllerDidDragBegin(index: Int, position: Float, detent: Float) {
625
+ val surfaceId = UIManagerHelper.getSurfaceId(this)
626
+ eventDispatcher?.dispatchEvent(DragBeginEvent(surfaceId, id, index, position, detent))
627
+ }
628
+
629
+ override fun viewControllerDidDragChange(index: Int, position: Float, detent: Float) {
630
+ val surfaceId = UIManagerHelper.getSurfaceId(this)
631
+ eventDispatcher?.dispatchEvent(DragChangeEvent(surfaceId, id, index, position, detent))
632
+ }
633
+
634
+ override fun viewControllerDidDragEnd(index: Int, position: Float, detent: Float) {
635
+ val surfaceId = UIManagerHelper.getSurfaceId(this)
636
+ eventDispatcher?.dispatchEvent(DragEndEvent(surfaceId, id, index, position, detent))
637
+ }
638
+
639
+ override fun viewControllerDidChangePosition(index: Float, position: Float, detent: Float, realtime: Boolean) {
640
+ val surfaceId = UIManagerHelper.getSurfaceId(this)
641
+ eventDispatcher?.dispatchEvent(PositionChangeEvent(surfaceId, id, index, position, detent, realtime))
642
+ }
643
+
644
+ override fun viewControllerDidChangeSize(width: Int, height: Int) {
645
+ updateState(width, height)
646
+ }
647
+
648
+ override fun viewControllerWillFocus() {
649
+ val surfaceId = UIManagerHelper.getSurfaceId(this)
650
+ eventDispatcher?.dispatchEvent(WillFocusEvent(surfaceId, id))
651
+ }
652
+
653
+ override fun viewControllerDidFocus() {
654
+ val surfaceId = UIManagerHelper.getSurfaceId(this)
655
+ eventDispatcher?.dispatchEvent(FocusEvent(surfaceId, id))
656
+ }
657
+
658
+ override fun viewControllerWillBlur() {
659
+ val surfaceId = UIManagerHelper.getSurfaceId(this)
660
+ eventDispatcher?.dispatchEvent(WillBlurEvent(surfaceId, id))
661
+ }
662
+
663
+ override fun viewControllerDidBlur() {
664
+ val surfaceId = UIManagerHelper.getSurfaceId(this)
665
+ eventDispatcher?.dispatchEvent(BlurEvent(surfaceId, id))
666
+ }
667
+
668
+ override fun viewControllerDidChangeVisibility(visible: Boolean) {
669
+ val surfaceId = UIManagerHelper.getSurfaceId(this)
670
+ eventDispatcher?.dispatchEvent(VisibilityChangeEvent(surfaceId, id, visible))
671
+ }
672
+
673
+ // ==================== TrueSheetContainerViewDelegate ====================
674
+
675
+ override fun containerViewContentDidChangeSize(width: Int, height: Int) {
676
+ updateSheetIfNeeded()
677
+ }
678
+
679
+ override fun containerViewContentDidScroll() {
680
+ viewController.commitKeyboardDetent()
681
+ }
682
+
683
+ // When the ScrollView changes (e.g. conditional remount), re-detect the new ScrollView
684
+ // and request layout so BottomSheetBehavior re-discovers the nested scrolling child.
685
+ override fun containerViewScrollViewDidChange() {
686
+ setupScrollable()
687
+ viewController.sheetView?.requestLayout()
688
+ }
689
+
690
+ override fun containerViewHeaderDidChangeSize(width: Int, height: Int) {
691
+ updateSheetIfNeeded()
692
+ }
693
+
382
694
  override fun containerViewFooterDidChangeSize(width: Int, height: Int) {
383
- // Reposition footer when its size changes
384
- if (viewController.isPresented) {
385
- viewController.positionFooter()
695
+ // Footer height affects peek detents
696
+ updateSheetIfNeeded()
697
+ viewController.positionFooter()
698
+ }
699
+
700
+ override fun containerViewPeekDidChangeSize(width: Int, height: Int) {
701
+ // Peek content height affects peek detents
702
+ updateSheetIfNeeded()
703
+ }
704
+
705
+ // ==================== RNScreensEventObserverDelegate ====================
706
+
707
+ override fun presenterScreenWillDisappear() {
708
+ if (viewController.isPresented && viewController.isSheetVisible) {
709
+ KeyboardUtils.dismiss(this) {}
710
+ viewController.post { viewController.hideForScreen() }
386
711
  }
387
712
  }
388
713
 
389
- companion object {
390
- const val TAG_NAME = "TrueSheet"
714
+ override fun presenterScreenWillAppear() {
715
+ if (viewController.isPresented && viewController.wasHiddenByScreen) {
716
+ viewController.wasHiddenByScreen = false
717
+ viewController.showAfterScreen()
718
+ }
391
719
  }
720
+
721
+ // ==================== Private Helpers ====================
722
+
723
+ /**
724
+ * Find the root container view for presenting the sheet.
725
+ * This traverses up the view hierarchy to find the content view (android.R.id.content)
726
+ * of whichever window this view is in - whether that's the activity's window or a
727
+ * Modal's dialog window.
728
+ */
729
+ override fun findRootContainerView(): ViewGroup? = findRootContainerView(reactContext)
392
730
  }