@amazon-devices/react-native-screens 2.0.1758683737

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 (381) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +223 -0
  3. package/RNScreens.podspec +53 -0
  4. package/SystemBundles/8f5a820b958535e533acb38dbc0c72c1837721b9db075f4a1740e42b9fee3910.bundle +33668 -0
  5. package/SystemBundles/8f5a820b958535e533acb38dbc0c72c1837721b9db075f4a1740e42b9fee3910.map +1 -0
  6. package/SystemModules/amzn__react-native-screens.modules.txt +101 -0
  7. package/SystemModules/amzn__react-native-screens.private.modules.txt +244 -0
  8. package/SystemModules/keplerscript-system-bundle-config.json +7 -0
  9. package/THIRD_PARTY_NOTICES.txt +707 -0
  10. package/android/build.gradle +133 -0
  11. package/android/src/fabric/java/com/swmansion/rnscreens/FabricEnabledViewGroup.kt +49 -0
  12. package/android/src/main/AndroidManifest.xml +5 -0
  13. package/android/src/main/java/com/swmansion/rnscreens/CustomSearchView.kt +77 -0
  14. package/android/src/main/java/com/swmansion/rnscreens/CustomToolbar.kt +7 -0
  15. package/android/src/main/java/com/swmansion/rnscreens/FragmentBackPressOverrider.kt +29 -0
  16. package/android/src/main/java/com/swmansion/rnscreens/FragmentHolder.kt +7 -0
  17. package/android/src/main/java/com/swmansion/rnscreens/RNScreensPackage.kt +21 -0
  18. package/android/src/main/java/com/swmansion/rnscreens/Screen.kt +289 -0
  19. package/android/src/main/java/com/swmansion/rnscreens/ScreenContainer.kt +372 -0
  20. package/android/src/main/java/com/swmansion/rnscreens/ScreenContainerViewManager.kt +40 -0
  21. package/android/src/main/java/com/swmansion/rnscreens/ScreenEventDispatcher.kt +21 -0
  22. package/android/src/main/java/com/swmansion/rnscreens/ScreenFragment.kt +331 -0
  23. package/android/src/main/java/com/swmansion/rnscreens/ScreenFragmentWrapper.kt +22 -0
  24. package/android/src/main/java/com/swmansion/rnscreens/ScreenStack.kt +336 -0
  25. package/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt +282 -0
  26. package/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragmentWrapper.kt +15 -0
  27. package/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.kt +398 -0
  28. package/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.kt +204 -0
  29. package/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubview.kt +38 -0
  30. package/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubviewManager.kt +41 -0
  31. package/android/src/main/java/com/swmansion/rnscreens/ScreenStackViewManager.kt +75 -0
  32. package/android/src/main/java/com/swmansion/rnscreens/ScreenViewManager.kt +186 -0
  33. package/android/src/main/java/com/swmansion/rnscreens/ScreenWindowTraits.kt +296 -0
  34. package/android/src/main/java/com/swmansion/rnscreens/ScreensShadowNode.kt +19 -0
  35. package/android/src/main/java/com/swmansion/rnscreens/SearchBarManager.kt +133 -0
  36. package/android/src/main/java/com/swmansion/rnscreens/SearchBarView.kt +178 -0
  37. package/android/src/main/java/com/swmansion/rnscreens/SearchViewFormatter.kt +67 -0
  38. package/android/src/main/java/com/swmansion/rnscreens/events/HeaderAttachedEvent.kt +22 -0
  39. package/android/src/main/java/com/swmansion/rnscreens/events/HeaderBackButtonClickedEvent.kt +22 -0
  40. package/android/src/main/java/com/swmansion/rnscreens/events/HeaderDetachedEvent.kt +22 -0
  41. package/android/src/main/java/com/swmansion/rnscreens/events/HeaderHeightChangeEvent.kt +26 -0
  42. package/android/src/main/java/com/swmansion/rnscreens/events/ScreenAppearEvent.kt +18 -0
  43. package/android/src/main/java/com/swmansion/rnscreens/events/ScreenDisappearEvent.kt +18 -0
  44. package/android/src/main/java/com/swmansion/rnscreens/events/ScreenDismissedEvent.kt +20 -0
  45. package/android/src/main/java/com/swmansion/rnscreens/events/ScreenTransitionProgressEvent.kt +32 -0
  46. package/android/src/main/java/com/swmansion/rnscreens/events/ScreenWillAppearEvent.kt +18 -0
  47. package/android/src/main/java/com/swmansion/rnscreens/events/ScreenWillDisappearEvent.kt +18 -0
  48. package/android/src/main/java/com/swmansion/rnscreens/events/SearchBarBlurEvent.kt +22 -0
  49. package/android/src/main/java/com/swmansion/rnscreens/events/SearchBarChangeTextEvent.kt +28 -0
  50. package/android/src/main/java/com/swmansion/rnscreens/events/SearchBarCloseEvent.kt +22 -0
  51. package/android/src/main/java/com/swmansion/rnscreens/events/SearchBarFocusEvent.kt +22 -0
  52. package/android/src/main/java/com/swmansion/rnscreens/events/SearchBarOpenEvent.kt +22 -0
  53. package/android/src/main/java/com/swmansion/rnscreens/events/SearchBarSearchButtonPressEvent.kt +24 -0
  54. package/android/src/main/java/com/swmansion/rnscreens/events/StackFinishTransitioningEvent.kt +18 -0
  55. package/android/src/main/java/com/swmansion/rnscreens/utils/DeviceUtils.kt +12 -0
  56. package/android/src/main/jni/CMakeLists.txt +72 -0
  57. package/android/src/main/jni/rnscreens.cpp +16 -0
  58. package/android/src/main/jni/rnscreens.h +28 -0
  59. package/android/src/main/res/base/anim/rns_default_enter_in.xml +18 -0
  60. package/android/src/main/res/base/anim/rns_default_enter_out.xml +19 -0
  61. package/android/src/main/res/base/anim/rns_default_exit_in.xml +17 -0
  62. package/android/src/main/res/base/anim/rns_default_exit_out.xml +18 -0
  63. package/android/src/main/res/base/anim/rns_fade_from_bottom.xml +14 -0
  64. package/android/src/main/res/base/anim/rns_fade_in.xml +7 -0
  65. package/android/src/main/res/base/anim/rns_fade_out.xml +7 -0
  66. package/android/src/main/res/base/anim/rns_fade_to_bottom.xml +15 -0
  67. package/android/src/main/res/base/anim/rns_no_animation_20.xml +6 -0
  68. package/android/src/main/res/base/anim/rns_no_animation_250.xml +7 -0
  69. package/android/src/main/res/base/anim/rns_no_animation_350.xml +6 -0
  70. package/android/src/main/res/base/anim/rns_no_animation_medium.xml +7 -0
  71. package/android/src/main/res/base/anim/rns_slide_in_from_bottom.xml +7 -0
  72. package/android/src/main/res/base/anim/rns_slide_in_from_left.xml +5 -0
  73. package/android/src/main/res/base/anim/rns_slide_in_from_right.xml +5 -0
  74. package/android/src/main/res/base/anim/rns_slide_out_to_bottom.xml +7 -0
  75. package/android/src/main/res/base/anim/rns_slide_out_to_left.xml +5 -0
  76. package/android/src/main/res/base/anim/rns_slide_out_to_right.xml +5 -0
  77. package/android/src/main/res/base/anim/rns_standard_accelerate_interpolator.xml +6 -0
  78. package/android/src/main/res/v33/anim-v33/rns_default_enter_in.xml +38 -0
  79. package/android/src/main/res/v33/anim-v33/rns_default_enter_out.xml +38 -0
  80. package/android/src/main/res/v33/anim-v33/rns_default_exit_in.xml +38 -0
  81. package/android/src/main/res/v33/anim-v33/rns_default_exit_out.xml +38 -0
  82. package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenManagerDelegate.java +111 -0
  83. package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenManagerInterface.java +44 -0
  84. package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderConfigManagerDelegate.java +107 -0
  85. package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderConfigManagerInterface.java +42 -0
  86. package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderSubviewManagerDelegate.java +31 -0
  87. package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderSubviewManagerInterface.java +17 -0
  88. package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackManagerDelegate.java +25 -0
  89. package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackManagerInterface.java +16 -0
  90. package/android/src/paper/java/com/swmansion/rnscreens/FabricEnabledViewGroup.kt +10 -0
  91. package/common/cpp/react/renderer/components/rnscreens/RNSScreenComponentDescriptor.h +41 -0
  92. package/common/cpp/react/renderer/components/rnscreens/RNSScreenShadowNode.cpp +9 -0
  93. package/common/cpp/react/renderer/components/rnscreens/RNSScreenShadowNode.h +30 -0
  94. package/common/cpp/react/renderer/components/rnscreens/RNSScreenState.cpp +14 -0
  95. package/common/cpp/react/renderer/components/rnscreens/RNSScreenState.h +45 -0
  96. package/ios/RCTImageComponentView+RNSScreenStackHeaderConfig.h +11 -0
  97. package/ios/RCTImageComponentView+RNSScreenStackHeaderConfig.mm +14 -0
  98. package/ios/RNSConvert.h +36 -0
  99. package/ios/RNSConvert.mm +154 -0
  100. package/ios/RNSEnums.h +71 -0
  101. package/ios/RNSFullWindowOverlay.h +34 -0
  102. package/ios/RNSFullWindowOverlay.mm +241 -0
  103. package/ios/RNSScreen.h +144 -0
  104. package/ios/RNSScreen.mm +1599 -0
  105. package/ios/RNSScreenContainer.h +45 -0
  106. package/ios/RNSScreenContainer.mm +343 -0
  107. package/ios/RNSScreenNavigationContainer.h +16 -0
  108. package/ios/RNSScreenNavigationContainer.mm +66 -0
  109. package/ios/RNSScreenStack.h +37 -0
  110. package/ios/RNSScreenStack.mm +1111 -0
  111. package/ios/RNSScreenStackAnimator.h +8 -0
  112. package/ios/RNSScreenStackAnimator.mm +320 -0
  113. package/ios/RNSScreenStackHeaderConfig.h +74 -0
  114. package/ios/RNSScreenStackHeaderConfig.mm +967 -0
  115. package/ios/RNSScreenStackHeaderSubview.h +44 -0
  116. package/ios/RNSScreenStackHeaderSubview.mm +147 -0
  117. package/ios/RNSScreenWindowTraits.h +26 -0
  118. package/ios/RNSScreenWindowTraits.mm +266 -0
  119. package/ios/RNSSearchBar.h +43 -0
  120. package/ios/RNSSearchBar.mm +465 -0
  121. package/ios/RNScreens.xcodeproj/project.pbxproj +461 -0
  122. package/ios/UIViewController+RNScreens.h +9 -0
  123. package/ios/UIViewController+RNScreens.mm +78 -0
  124. package/ios/UIWindow+RNScreens.h +9 -0
  125. package/ios/UIWindow+RNScreens.mm +17 -0
  126. package/ios/events/RNSHeaderHeightChangeEvent.h +8 -0
  127. package/ios/events/RNSHeaderHeightChangeEvent.mm +44 -0
  128. package/ios/events/RNSScreenViewEvent.h +12 -0
  129. package/ios/events/RNSScreenViewEvent.mm +59 -0
  130. package/ios/utils/RNSUIBarButtonItem.h +5 -0
  131. package/ios/utils/RNSUIBarButtonItem.mm +22 -0
  132. package/kepler-compatibility.json +8 -0
  133. package/kepler-transformed-package-info.json +3 -0
  134. package/lib/commonjs/TransitionProgressContext.js +11 -0
  135. package/lib/commonjs/TransitionProgressContext.js.map +1 -0
  136. package/lib/commonjs/fabric/FullWindowOverlayNativeComponent.js +11 -0
  137. package/lib/commonjs/fabric/FullWindowOverlayNativeComponent.js.map +1 -0
  138. package/lib/commonjs/fabric/ScreenContainerNativeComponent.js +33 -0
  139. package/lib/commonjs/fabric/ScreenContainerNativeComponent.js.map +1 -0
  140. package/lib/commonjs/fabric/ScreenNativeComponent.js +70 -0
  141. package/lib/commonjs/fabric/ScreenNativeComponent.js.map +1 -0
  142. package/lib/commonjs/fabric/ScreenNavigationContainerNativeComponent.js +11 -0
  143. package/lib/commonjs/fabric/ScreenNavigationContainerNativeComponent.js.map +1 -0
  144. package/lib/commonjs/fabric/ScreenStackHeaderConfigNativeComponent.js +31 -0
  145. package/lib/commonjs/fabric/ScreenStackHeaderConfigNativeComponent.js.map +1 -0
  146. package/lib/commonjs/fabric/ScreenStackHeaderSubviewNativeComponent.js +12 -0
  147. package/lib/commonjs/fabric/ScreenStackHeaderSubviewNativeComponent.js.map +1 -0
  148. package/lib/commonjs/fabric/ScreenStackNativeComponent.js +35 -0
  149. package/lib/commonjs/fabric/ScreenStackNativeComponent.js.map +1 -0
  150. package/lib/commonjs/fabric/SearchBarNativeComponent.js +19 -0
  151. package/lib/commonjs/fabric/SearchBarNativeComponent.js.map +1 -0
  152. package/lib/commonjs/index.js +147 -0
  153. package/lib/commonjs/index.js.map +1 -0
  154. package/lib/commonjs/index.native.js +407 -0
  155. package/lib/commonjs/index.native.js.map +1 -0
  156. package/lib/commonjs/native-stack/index.js +49 -0
  157. package/lib/commonjs/native-stack/index.js.map +1 -0
  158. package/lib/commonjs/native-stack/navigators/createNativeStackNavigator.js +75 -0
  159. package/lib/commonjs/native-stack/navigators/createNativeStackNavigator.js.map +1 -0
  160. package/lib/commonjs/native-stack/types.js +6 -0
  161. package/lib/commonjs/native-stack/types.js.map +1 -0
  162. package/lib/commonjs/native-stack/utils/AnimatedHeaderHeightContext.js +12 -0
  163. package/lib/commonjs/native-stack/utils/AnimatedHeaderHeightContext.js.map +1 -0
  164. package/lib/commonjs/native-stack/utils/HeaderHeightContext.js +12 -0
  165. package/lib/commonjs/native-stack/utils/HeaderHeightContext.js.map +1 -0
  166. package/lib/commonjs/native-stack/utils/SafeAreaProviderCompat.js +75 -0
  167. package/lib/commonjs/native-stack/utils/SafeAreaProviderCompat.js.map +1 -0
  168. package/lib/commonjs/native-stack/utils/getDefaultHeaderHeight.js +35 -0
  169. package/lib/commonjs/native-stack/utils/getDefaultHeaderHeight.js.map +1 -0
  170. package/lib/commonjs/native-stack/utils/useAnimatedHeaderHeight.js +19 -0
  171. package/lib/commonjs/native-stack/utils/useAnimatedHeaderHeight.js.map +1 -0
  172. package/lib/commonjs/native-stack/utils/useBackPressSubscription.js +54 -0
  173. package/lib/commonjs/native-stack/utils/useBackPressSubscription.js.map +1 -0
  174. package/lib/commonjs/native-stack/utils/useHeaderHeight.js +19 -0
  175. package/lib/commonjs/native-stack/utils/useHeaderHeight.js.map +1 -0
  176. package/lib/commonjs/native-stack/views/FontProcessor.js +21 -0
  177. package/lib/commonjs/native-stack/views/FontProcessor.js.map +1 -0
  178. package/lib/commonjs/native-stack/views/HeaderConfig.js +141 -0
  179. package/lib/commonjs/native-stack/views/HeaderConfig.js.map +1 -0
  180. package/lib/commonjs/native-stack/views/NativeStackView.js +354 -0
  181. package/lib/commonjs/native-stack/views/NativeStackView.js.map +1 -0
  182. package/lib/commonjs/reanimated/ReanimatedHeaderHeightContext.js +12 -0
  183. package/lib/commonjs/reanimated/ReanimatedHeaderHeightContext.js.map +1 -0
  184. package/lib/commonjs/reanimated/ReanimatedNativeStackScreen.js +101 -0
  185. package/lib/commonjs/reanimated/ReanimatedNativeStackScreen.js.map +1 -0
  186. package/lib/commonjs/reanimated/ReanimatedScreen.js +22 -0
  187. package/lib/commonjs/reanimated/ReanimatedScreen.js.map +1 -0
  188. package/lib/commonjs/reanimated/ReanimatedScreenProvider.js +47 -0
  189. package/lib/commonjs/reanimated/ReanimatedScreenProvider.js.map +1 -0
  190. package/lib/commonjs/reanimated/ReanimatedTransitionProgressContext.js +12 -0
  191. package/lib/commonjs/reanimated/ReanimatedTransitionProgressContext.js.map +1 -0
  192. package/lib/commonjs/reanimated/index.js +28 -0
  193. package/lib/commonjs/reanimated/index.js.map +1 -0
  194. package/lib/commonjs/reanimated/useReanimatedHeaderHeight.js +19 -0
  195. package/lib/commonjs/reanimated/useReanimatedHeaderHeight.js.map +1 -0
  196. package/lib/commonjs/reanimated/useReanimatedTransitionProgress.js +19 -0
  197. package/lib/commonjs/reanimated/useReanimatedTransitionProgress.js.map +1 -0
  198. package/lib/commonjs/types.js +6 -0
  199. package/lib/commonjs/types.js.map +1 -0
  200. package/lib/commonjs/useTransitionProgress.js +19 -0
  201. package/lib/commonjs/useTransitionProgress.js.map +1 -0
  202. package/lib/commonjs/utils.js +21 -0
  203. package/lib/commonjs/utils.js.map +1 -0
  204. package/lib/module/TransitionProgressContext.js +3 -0
  205. package/lib/module/TransitionProgressContext.js.map +1 -0
  206. package/lib/module/fabric/FullWindowOverlayNativeComponent.js +4 -0
  207. package/lib/module/fabric/FullWindowOverlayNativeComponent.js.map +1 -0
  208. package/lib/module/fabric/ScreenContainerNativeComponent.js +25 -0
  209. package/lib/module/fabric/ScreenContainerNativeComponent.js.map +1 -0
  210. package/lib/module/fabric/ScreenNativeComponent.js +63 -0
  211. package/lib/module/fabric/ScreenNativeComponent.js.map +1 -0
  212. package/lib/module/fabric/ScreenNavigationContainerNativeComponent.js +4 -0
  213. package/lib/module/fabric/ScreenNavigationContainerNativeComponent.js.map +1 -0
  214. package/lib/module/fabric/ScreenStackHeaderConfigNativeComponent.js +23 -0
  215. package/lib/module/fabric/ScreenStackHeaderConfigNativeComponent.js.map +1 -0
  216. package/lib/module/fabric/ScreenStackHeaderSubviewNativeComponent.js +7 -0
  217. package/lib/module/fabric/ScreenStackHeaderSubviewNativeComponent.js.map +1 -0
  218. package/lib/module/fabric/ScreenStackNativeComponent.js +28 -0
  219. package/lib/module/fabric/ScreenStackNativeComponent.js.map +1 -0
  220. package/lib/module/fabric/SearchBarNativeComponent.js +10 -0
  221. package/lib/module/fabric/SearchBarNativeComponent.js.map +1 -0
  222. package/lib/module/index.js +67 -0
  223. package/lib/module/index.js.map +1 -0
  224. package/lib/module/index.native.js +410 -0
  225. package/lib/module/index.native.js.map +1 -0
  226. package/lib/module/native-stack/index.js +22 -0
  227. package/lib/module/native-stack/index.js.map +1 -0
  228. package/lib/module/native-stack/navigators/createNativeStackNavigator.js +72 -0
  229. package/lib/module/native-stack/navigators/createNativeStackNavigator.js.map +1 -0
  230. package/lib/module/native-stack/types.js +2 -0
  231. package/lib/module/native-stack/types.js.map +1 -0
  232. package/lib/module/native-stack/utils/AnimatedHeaderHeightContext.js +4 -0
  233. package/lib/module/native-stack/utils/AnimatedHeaderHeightContext.js.map +1 -0
  234. package/lib/module/native-stack/utils/HeaderHeightContext.js +4 -0
  235. package/lib/module/native-stack/utils/HeaderHeightContext.js.map +1 -0
  236. package/lib/module/native-stack/utils/SafeAreaProviderCompat.js +68 -0
  237. package/lib/module/native-stack/utils/SafeAreaProviderCompat.js.map +1 -0
  238. package/lib/module/native-stack/utils/getDefaultHeaderHeight.js +29 -0
  239. package/lib/module/native-stack/utils/getDefaultHeaderHeight.js.map +1 -0
  240. package/lib/module/native-stack/utils/useAnimatedHeaderHeight.js +10 -0
  241. package/lib/module/native-stack/utils/useAnimatedHeaderHeight.js.map +1 -0
  242. package/lib/module/native-stack/utils/useBackPressSubscription.js +47 -0
  243. package/lib/module/native-stack/utils/useBackPressSubscription.js.map +1 -0
  244. package/lib/module/native-stack/utils/useHeaderHeight.js +10 -0
  245. package/lib/module/native-stack/utils/useHeaderHeight.js.map +1 -0
  246. package/lib/module/native-stack/views/FontProcessor.js +13 -0
  247. package/lib/module/native-stack/views/FontProcessor.js.map +1 -0
  248. package/lib/module/native-stack/views/HeaderConfig.js +132 -0
  249. package/lib/module/native-stack/views/HeaderConfig.js.map +1 -0
  250. package/lib/module/native-stack/views/NativeStackView.js +355 -0
  251. package/lib/module/native-stack/views/NativeStackView.js.map +1 -0
  252. package/lib/module/reanimated/ReanimatedHeaderHeightContext.js +5 -0
  253. package/lib/module/reanimated/ReanimatedHeaderHeightContext.js.map +1 -0
  254. package/lib/module/reanimated/ReanimatedNativeStackScreen.js +97 -0
  255. package/lib/module/reanimated/ReanimatedNativeStackScreen.js.map +1 -0
  256. package/lib/module/reanimated/ReanimatedScreen.js +17 -0
  257. package/lib/module/reanimated/ReanimatedScreen.js.map +1 -0
  258. package/lib/module/reanimated/ReanimatedScreenProvider.js +40 -0
  259. package/lib/module/reanimated/ReanimatedScreenProvider.js.map +1 -0
  260. package/lib/module/reanimated/ReanimatedTransitionProgressContext.js +5 -0
  261. package/lib/module/reanimated/ReanimatedTransitionProgressContext.js.map +1 -0
  262. package/lib/module/reanimated/index.js +4 -0
  263. package/lib/module/reanimated/index.js.map +1 -0
  264. package/lib/module/reanimated/useReanimatedHeaderHeight.js +10 -0
  265. package/lib/module/reanimated/useReanimatedHeaderHeight.js.map +1 -0
  266. package/lib/module/reanimated/useReanimatedTransitionProgress.js +10 -0
  267. package/lib/module/reanimated/useReanimatedTransitionProgress.js.map +1 -0
  268. package/lib/module/types.js +2 -0
  269. package/lib/module/types.js.map +1 -0
  270. package/lib/module/useTransitionProgress.js +10 -0
  271. package/lib/module/useTransitionProgress.js.map +1 -0
  272. package/lib/module/utils.js +14 -0
  273. package/lib/module/utils.js.map +1 -0
  274. package/lib/typescript/TransitionProgressContext.d.ts +9 -0
  275. package/lib/typescript/fabric/FullWindowOverlayNativeComponent.d.ts +7 -0
  276. package/lib/typescript/fabric/ScreenContainerNativeComponent.d.ts +5 -0
  277. package/lib/typescript/fabric/ScreenNativeComponent.d.ts +66 -0
  278. package/lib/typescript/fabric/ScreenNavigationContainerNativeComponent.d.ts +7 -0
  279. package/lib/typescript/fabric/ScreenStackHeaderConfigNativeComponent.d.ts +33 -0
  280. package/lib/typescript/fabric/ScreenStackHeaderSubviewNativeComponent.d.ts +10 -0
  281. package/lib/typescript/fabric/ScreenStackNativeComponent.d.ts +8 -0
  282. package/lib/typescript/fabric/SearchBarNativeComponent.d.ts +49 -0
  283. package/lib/typescript/index.d.ts +33 -0
  284. package/lib/typescript/index.native.d.ts +2 -0
  285. package/lib/typescript/native-stack/index.d.ts +19 -0
  286. package/lib/typescript/native-stack/navigators/createNativeStackNavigator.d.ts +6 -0
  287. package/lib/typescript/native-stack/types.d.ts +438 -0
  288. package/lib/typescript/native-stack/utils/AnimatedHeaderHeightContext.d.ts +4 -0
  289. package/lib/typescript/native-stack/utils/HeaderHeightContext.d.ts +3 -0
  290. package/lib/typescript/native-stack/utils/SafeAreaProviderCompat.d.ts +11 -0
  291. package/lib/typescript/native-stack/utils/getDefaultHeaderHeight.d.ts +7 -0
  292. package/lib/typescript/native-stack/utils/useAnimatedHeaderHeight.d.ts +1 -0
  293. package/lib/typescript/native-stack/utils/useBackPressSubscription.d.ts +16 -0
  294. package/lib/typescript/native-stack/utils/useHeaderHeight.d.ts +1 -0
  295. package/lib/typescript/native-stack/views/FontProcessor.d.ts +1 -0
  296. package/lib/typescript/native-stack/views/HeaderConfig.d.ts +8 -0
  297. package/lib/typescript/native-stack/views/NativeStackView.d.ts +10 -0
  298. package/lib/typescript/reanimated/ReanimatedHeaderHeightContext.d.ts +4 -0
  299. package/lib/typescript/reanimated/ReanimatedNativeStackScreen.d.ts +5 -0
  300. package/lib/typescript/reanimated/ReanimatedScreen.d.ts +5 -0
  301. package/lib/typescript/reanimated/ReanimatedScreenProvider.d.ts +2 -0
  302. package/lib/typescript/reanimated/ReanimatedTransitionProgressContext.d.ts +9 -0
  303. package/lib/typescript/reanimated/index.d.ts +3 -0
  304. package/lib/typescript/reanimated/useReanimatedHeaderHeight.d.ts +3 -0
  305. package/lib/typescript/reanimated/useReanimatedTransitionProgress.d.ts +11 -0
  306. package/lib/typescript/types.d.ts +612 -0
  307. package/lib/typescript/useTransitionProgress.d.ts +5 -0
  308. package/lib/typescript/utils.d.ts +3 -0
  309. package/native-stack/README.md +814 -0
  310. package/native-stack/package.json +6 -0
  311. package/package.json +1 -0
  312. package/react-native.config.js +42 -0
  313. package/reanimated/package.json +6 -0
  314. package/src/TransitionProgressContext.tsx +12 -0
  315. package/src/fabric/FullWindowOverlayNativeComponent.ts +7 -0
  316. package/src/fabric/ScreenContainerNativeComponent.ts +28 -0
  317. package/src/fabric/ScreenNativeComponent.ts +158 -0
  318. package/src/fabric/ScreenNavigationContainerNativeComponent.ts +10 -0
  319. package/src/fabric/ScreenStackHeaderConfigNativeComponent.ts +61 -0
  320. package/src/fabric/ScreenStackHeaderSubviewNativeComponent.ts +22 -0
  321. package/src/fabric/ScreenStackNativeComponent.ts +33 -0
  322. package/src/fabric/SearchBarNativeComponent.ts +79 -0
  323. package/src/index.native.tsx +599 -0
  324. package/src/index.tsx +119 -0
  325. package/src/native-stack/index.tsx +27 -0
  326. package/src/native-stack/navigators/createNativeStackNavigator.tsx +107 -0
  327. package/src/native-stack/types.tsx +486 -0
  328. package/src/native-stack/utils/AnimatedHeaderHeightContext.tsx +8 -0
  329. package/src/native-stack/utils/HeaderHeightContext.tsx +5 -0
  330. package/src/native-stack/utils/SafeAreaProviderCompat.tsx +78 -0
  331. package/src/native-stack/utils/getDefaultHeaderHeight.tsx +41 -0
  332. package/src/native-stack/utils/useAnimatedHeaderHeight.tsx +15 -0
  333. package/src/native-stack/utils/useBackPressSubscription.tsx +66 -0
  334. package/src/native-stack/utils/useHeaderHeight.tsx +15 -0
  335. package/src/native-stack/views/FontProcessor.tsx +14 -0
  336. package/src/native-stack/views/HeaderConfig.tsx +187 -0
  337. package/src/native-stack/views/NativeStackView.tsx +466 -0
  338. package/src/reanimated/ReanimatedHeaderHeightContext.tsx +7 -0
  339. package/src/reanimated/ReanimatedNativeStackScreen.tsx +130 -0
  340. package/src/reanimated/ReanimatedScreen.tsx +25 -0
  341. package/src/reanimated/ReanimatedScreenProvider.tsx +42 -0
  342. package/src/reanimated/ReanimatedTransitionProgressContext.tsx +13 -0
  343. package/src/reanimated/index.tsx +3 -0
  344. package/src/reanimated/useReanimatedHeaderHeight.tsx +14 -0
  345. package/src/reanimated/useReanimatedTransitionProgress.tsx +14 -0
  346. package/src/types.tsx +699 -0
  347. package/src/useTransitionProgress.tsx +15 -0
  348. package/src/utils.ts +18 -0
  349. package/windows/README.md +25 -0
  350. package/windows/RNScreens/PropertySheet.props +16 -0
  351. package/windows/RNScreens/RNScreens.cpp +66 -0
  352. package/windows/RNScreens/RNScreens.def +3 -0
  353. package/windows/RNScreens/RNScreens.h +41 -0
  354. package/windows/RNScreens/RNScreens.idl +8 -0
  355. package/windows/RNScreens/RNScreens.vcxproj +187 -0
  356. package/windows/RNScreens/RNScreens.vcxproj.filters +52 -0
  357. package/windows/RNScreens/ReactPackageProvider.cpp +30 -0
  358. package/windows/RNScreens/ReactPackageProvider.h +17 -0
  359. package/windows/RNScreens/ReactPackageProvider.idl +9 -0
  360. package/windows/RNScreens/Screen.cpp +122 -0
  361. package/windows/RNScreens/Screen.h +64 -0
  362. package/windows/RNScreens/ScreenContainer.cpp +49 -0
  363. package/windows/RNScreens/ScreenContainer.h +23 -0
  364. package/windows/RNScreens/ScreenContainerViewManager.cpp +133 -0
  365. package/windows/RNScreens/ScreenContainerViewManager.h +78 -0
  366. package/windows/RNScreens/ScreenStack.cpp +65 -0
  367. package/windows/RNScreens/ScreenStack.h +23 -0
  368. package/windows/RNScreens/ScreenStackHeaderConfig.cpp +19 -0
  369. package/windows/RNScreens/ScreenStackHeaderConfig.h +14 -0
  370. package/windows/RNScreens/ScreenStackHeaderConfigViewManager.cpp +89 -0
  371. package/windows/RNScreens/ScreenStackHeaderConfigViewManager.h +62 -0
  372. package/windows/RNScreens/ScreenStackViewManager.cpp +132 -0
  373. package/windows/RNScreens/ScreenStackViewManager.h +78 -0
  374. package/windows/RNScreens/ScreenViewManager.cpp +154 -0
  375. package/windows/RNScreens/ScreenViewManager.h +78 -0
  376. package/windows/RNScreens/packages.config +4 -0
  377. package/windows/RNScreens/pch.cpp +1 -0
  378. package/windows/RNScreens/pch.h +9 -0
  379. package/windows/RNScreens62.sln +254 -0
  380. package/windows/RNScreens63.sln +225 -0
  381. package/windows/RNScreens65.sln +144 -0
@@ -0,0 +1,1599 @@
1
+ #import <UIKit/UIKit.h>
2
+
3
+ #import "RNSScreen.h"
4
+ #import "RNSScreenContainer.h"
5
+ #import "RNSScreenWindowTraits.h"
6
+
7
+ #ifdef RCT_NEW_ARCH_ENABLED
8
+ #import <React/RCTConversions.h>
9
+ #import <React/RCTFabricComponentsPlugins.h>
10
+ #import <React/RCTRootComponentView.h>
11
+ #import <React/RCTSurfaceTouchHandler.h>
12
+ #import <react/renderer/components/rnscreens/EventEmitters.h>
13
+ #import <react/renderer/components/rnscreens/Props.h>
14
+ #import <react/renderer/components/rnscreens/RCTComponentViewHelpers.h>
15
+ #import <rnscreens/RNSScreenComponentDescriptor.h>
16
+ #import "RNSConvert.h"
17
+ #import "RNSHeaderHeightChangeEvent.h"
18
+ #import "RNSScreenViewEvent.h"
19
+ #else
20
+ #import <React/RCTTouchHandler.h>
21
+ #endif
22
+
23
+ #import <React/RCTShadowView.h>
24
+ #import <React/RCTUIManager.h>
25
+ #import "RNSScreenStack.h"
26
+ #import "RNSScreenStackHeaderConfig.h"
27
+
28
+ #ifdef RCT_NEW_ARCH_ENABLED
29
+ namespace react = facebook::react;
30
+ #endif // RCT_NEW_ARCH_ENABLED
31
+
32
+ @interface RNSScreenView ()
33
+ #ifdef RCT_NEW_ARCH_ENABLED
34
+ <RCTRNSScreenViewProtocol, UIAdaptivePresentationControllerDelegate>
35
+ #else
36
+ <UIAdaptivePresentationControllerDelegate, RCTInvalidating>
37
+ #endif
38
+ @end
39
+
40
+ @implementation RNSScreenView {
41
+ __weak RCTBridge *_bridge;
42
+ #ifdef RCT_NEW_ARCH_ENABLED
43
+ RCTSurfaceTouchHandler *_touchHandler;
44
+ react::RNSScreenShadowNode::ConcreteState::Shared _state;
45
+ // on fabric, they are not available by default so we need them exposed here too
46
+ NSMutableArray<UIView *> *_reactSubviews;
47
+ #else
48
+ RCTTouchHandler *_touchHandler;
49
+ CGRect _reactFrame;
50
+ #endif
51
+ }
52
+
53
+ #ifdef RCT_NEW_ARCH_ENABLED
54
+ - (instancetype)initWithFrame:(CGRect)frame
55
+ {
56
+ if (self = [super initWithFrame:frame]) {
57
+ static const auto defaultProps = std::make_shared<const react::RNSScreenProps>();
58
+ _props = defaultProps;
59
+ _reactSubviews = [NSMutableArray new];
60
+ [self initCommonProps];
61
+ }
62
+ return self;
63
+ }
64
+ #endif // RCT_NEW_ARCH_ENABLED
65
+
66
+ - (instancetype)initWithBridge:(RCTBridge *)bridge
67
+ {
68
+ if (self = [super init]) {
69
+ _bridge = bridge;
70
+ [self initCommonProps];
71
+ }
72
+
73
+ return self;
74
+ }
75
+
76
+ - (void)initCommonProps
77
+ {
78
+ _controller = [[RNSScreen alloc] initWithView:self];
79
+ _stackPresentation = RNSScreenStackPresentationPush;
80
+ _stackAnimation = RNSScreenStackAnimationDefault;
81
+ _gestureEnabled = YES;
82
+ _replaceAnimation = RNSScreenReplaceAnimationPop;
83
+ _dismissed = NO;
84
+ _hasStatusBarStyleSet = NO;
85
+ _hasStatusBarAnimationSet = NO;
86
+ _hasStatusBarHiddenSet = NO;
87
+ _hasOrientationSet = NO;
88
+ _hasHomeIndicatorHiddenSet = NO;
89
+ #if !TARGET_OS_TV
90
+ _sheetExpandsWhenScrolledToEdge = YES;
91
+ #endif // !TARGET_OS_TV
92
+ }
93
+
94
+ - (UIViewController *)reactViewController
95
+ {
96
+ return _controller;
97
+ }
98
+
99
+ #ifdef RCT_NEW_ARCH_ENABLED
100
+ - (NSArray<UIView *> *)reactSubviews
101
+ {
102
+ return _reactSubviews;
103
+ }
104
+ #endif
105
+
106
+ - (void)updateBounds
107
+ {
108
+ #ifdef RCT_NEW_ARCH_ENABLED
109
+ if (_state != nullptr) {
110
+ auto newState = react::RNSScreenState{RCTSizeFromCGSize(self.bounds.size)};
111
+ _state->updateState(std::move(newState));
112
+ UINavigationController *navctr = _controller.navigationController;
113
+ [navctr.view setNeedsLayout];
114
+ }
115
+ #else
116
+ [_bridge.uiManager setSize:self.bounds.size forView:self];
117
+ #endif
118
+ }
119
+
120
+ - (void)setStackPresentation:(RNSScreenStackPresentation)stackPresentation
121
+ {
122
+ switch (stackPresentation) {
123
+ case RNSScreenStackPresentationModal:
124
+ #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
125
+ __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
126
+ if (@available(iOS 13.0, tvOS 13.0, *)) {
127
+ _controller.modalPresentationStyle = UIModalPresentationAutomatic;
128
+ } else {
129
+ _controller.modalPresentationStyle = UIModalPresentationFullScreen;
130
+ }
131
+ #else
132
+ _controller.modalPresentationStyle = UIModalPresentationFullScreen;
133
+ #endif
134
+ break;
135
+ case RNSScreenStackPresentationFullScreenModal:
136
+ _controller.modalPresentationStyle = UIModalPresentationFullScreen;
137
+ break;
138
+ #if !TARGET_OS_TV
139
+ case RNSScreenStackPresentationFormSheet:
140
+ _controller.modalPresentationStyle = UIModalPresentationFormSheet;
141
+ break;
142
+ #endif
143
+ case RNSScreenStackPresentationTransparentModal:
144
+ _controller.modalPresentationStyle = UIModalPresentationOverFullScreen;
145
+ break;
146
+ case RNSScreenStackPresentationContainedModal:
147
+ _controller.modalPresentationStyle = UIModalPresentationCurrentContext;
148
+ break;
149
+ case RNSScreenStackPresentationContainedTransparentModal:
150
+ _controller.modalPresentationStyle = UIModalPresentationOverCurrentContext;
151
+ break;
152
+ case RNSScreenStackPresentationPush:
153
+ // ignored, we only need to keep in mind not to set presentation delegate
154
+ break;
155
+ }
156
+
157
+ // There is a bug in UIKit which causes retain loop when presentationController is accessed for a
158
+ // controller that is not going to be presented modally. We therefore need to avoid setting the
159
+ // delegate for screens presented using push. This also means that when controller is updated from
160
+ // modal to push type, this may cause memory leak, we warn about that as well.
161
+ if (stackPresentation != RNSScreenStackPresentationPush) {
162
+ // `modalPresentationStyle` must be set before accessing `presentationController`
163
+ // otherwise a default controller will be created and cannot be changed after.
164
+ // Documented here:
165
+ // https://developer.apple.com/documentation/uikit/uiviewcontroller/1621426-presentationcontroller?language=objc
166
+ _controller.presentationController.delegate = self;
167
+ } else if (_stackPresentation != RNSScreenStackPresentationPush) {
168
+ #ifdef RCT_NEW_ARCH_ENABLED
169
+ // TODO: on Fabric, same controllers can be used as modals and then recycled and used a push which would result in
170
+ // this error. It would be good to check if it doesn't leak in such case.
171
+ #else
172
+ RCTLogError(
173
+ @"Screen presentation updated from modal to push, this may likely result in a screen object leakage. If you need to change presentation style create a new screen object instead");
174
+ #endif
175
+ }
176
+ _stackPresentation = stackPresentation;
177
+ }
178
+
179
+ - (void)setStackAnimation:(RNSScreenStackAnimation)stackAnimation
180
+ {
181
+ _stackAnimation = stackAnimation;
182
+
183
+ switch (stackAnimation) {
184
+ case RNSScreenStackAnimationFade:
185
+ _controller.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
186
+ break;
187
+ #if !TARGET_OS_TV
188
+ case RNSScreenStackAnimationFlip:
189
+ _controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
190
+ break;
191
+ #endif
192
+ case RNSScreenStackAnimationNone:
193
+ case RNSScreenStackAnimationDefault:
194
+ case RNSScreenStackAnimationSimplePush:
195
+ case RNSScreenStackAnimationSlideFromBottom:
196
+ case RNSScreenStackAnimationFadeFromBottom:
197
+ // Default
198
+ break;
199
+ }
200
+ }
201
+
202
+ - (void)setGestureEnabled:(BOOL)gestureEnabled
203
+ {
204
+ #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
205
+ __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
206
+ if (@available(iOS 13.0, tvOS 13.0, *)) {
207
+ _controller.modalInPresentation = !gestureEnabled;
208
+ }
209
+ #endif
210
+
211
+ _gestureEnabled = gestureEnabled;
212
+ }
213
+
214
+ - (void)setReplaceAnimation:(RNSScreenReplaceAnimation)replaceAnimation
215
+ {
216
+ _replaceAnimation = replaceAnimation;
217
+ }
218
+
219
+ // Nil will be provided when activityState is set as an animated value and we change
220
+ // it from JS to be a plain value (non animated).
221
+ // In case when nil is received, we want to ignore such value and not make
222
+ // any updates as the actual non-nil value will follow immediately.
223
+ - (void)setActivityStateOrNil:(NSNumber *)activityStateOrNil
224
+ {
225
+ int activityState = [activityStateOrNil intValue];
226
+ if (activityStateOrNil != nil && activityState != -1 && activityState != _activityState) {
227
+ _activityState = activityState;
228
+ [_reactSuperview markChildUpdated];
229
+ }
230
+ }
231
+
232
+ #if !TARGET_OS_TV
233
+ - (void)setStatusBarStyle:(RNSStatusBarStyle)statusBarStyle
234
+ {
235
+ _hasStatusBarStyleSet = YES;
236
+ _statusBarStyle = statusBarStyle;
237
+ [RNSScreenWindowTraits assertViewControllerBasedStatusBarAppearenceSet];
238
+ [RNSScreenWindowTraits updateStatusBarAppearance];
239
+ }
240
+
241
+ - (void)setStatusBarAnimation:(UIStatusBarAnimation)statusBarAnimation
242
+ {
243
+ _hasStatusBarAnimationSet = YES;
244
+ _statusBarAnimation = statusBarAnimation;
245
+ [RNSScreenWindowTraits assertViewControllerBasedStatusBarAppearenceSet];
246
+ }
247
+
248
+ - (void)setStatusBarHidden:(BOOL)statusBarHidden
249
+ {
250
+ _hasStatusBarHiddenSet = YES;
251
+ _statusBarHidden = statusBarHidden;
252
+ [RNSScreenWindowTraits assertViewControllerBasedStatusBarAppearenceSet];
253
+ [RNSScreenWindowTraits updateStatusBarAppearance];
254
+ }
255
+
256
+ - (void)setScreenOrientation:(UIInterfaceOrientationMask)screenOrientation
257
+ {
258
+ _hasOrientationSet = YES;
259
+ _screenOrientation = screenOrientation;
260
+ [RNSScreenWindowTraits enforceDesiredDeviceOrientation];
261
+ }
262
+
263
+ - (void)setHomeIndicatorHidden:(BOOL)homeIndicatorHidden
264
+ {
265
+ _hasHomeIndicatorHiddenSet = YES;
266
+ _homeIndicatorHidden = homeIndicatorHidden;
267
+ [RNSScreenWindowTraits updateHomeIndicatorAutoHidden];
268
+ }
269
+ #endif
270
+
271
+ - (UIView *)reactSuperview
272
+ {
273
+ return _reactSuperview;
274
+ }
275
+
276
+ - (void)addSubview:(UIView *)view
277
+ {
278
+ if (![view isKindOfClass:[RNSScreenStackHeaderConfig class]]) {
279
+ [super addSubview:view];
280
+ } else {
281
+ ((RNSScreenStackHeaderConfig *)view).screenView = self;
282
+ }
283
+ }
284
+
285
+ - (void)notifyDismissedWithCount:(int)dismissCount
286
+ {
287
+ #ifdef RCT_NEW_ARCH_ENABLED
288
+ // If screen is already unmounted then there will be no event emitter
289
+ // it will be cleaned in prepareForRecycle
290
+ if (_eventEmitter != nullptr) {
291
+ std::dynamic_pointer_cast<const react::RNSScreenEventEmitter>(_eventEmitter)
292
+ ->onDismissed(react::RNSScreenEventEmitter::OnDismissed{.dismissCount = dismissCount});
293
+ }
294
+ #else
295
+ // TODO: hopefully problems connected to dismissed prop are only the case on paper
296
+ _dismissed = YES;
297
+ if (self.onDismissed) {
298
+ dispatch_async(dispatch_get_main_queue(), ^{
299
+ if (self.onDismissed) {
300
+ self.onDismissed(@{@"dismissCount" : @(dismissCount)});
301
+ }
302
+ });
303
+ }
304
+ #endif
305
+ }
306
+
307
+ - (void)notifyDismissCancelledWithDismissCount:(int)dismissCount
308
+ {
309
+ #ifdef RCT_NEW_ARCH_ENABLED
310
+ // If screen is already unmounted then there will be no event emitter
311
+ // it will be cleaned in prepareForRecycle
312
+ if (_eventEmitter != nullptr) {
313
+ std::dynamic_pointer_cast<const react::RNSScreenEventEmitter>(_eventEmitter)
314
+ ->onNativeDismissCancelled(
315
+ react::RNSScreenEventEmitter::OnNativeDismissCancelled{.dismissCount = dismissCount});
316
+ }
317
+ #else
318
+ if (self.onNativeDismissCancelled) {
319
+ self.onNativeDismissCancelled(@{@"dismissCount" : @(dismissCount)});
320
+ }
321
+ #endif
322
+ }
323
+
324
+ - (void)notifyWillAppear
325
+ {
326
+ #ifdef RCT_NEW_ARCH_ENABLED
327
+ // If screen is already unmounted then there will be no event emitter
328
+ // it will be cleaned in prepareForRecycle
329
+ if (_eventEmitter != nullptr) {
330
+ std::dynamic_pointer_cast<const react::RNSScreenEventEmitter>(_eventEmitter)
331
+ ->onWillAppear(react::RNSScreenEventEmitter::OnWillAppear{});
332
+ }
333
+ [self updateLayoutMetrics:_newLayoutMetrics oldLayoutMetrics:_oldLayoutMetrics];
334
+ #else
335
+ if (self.onWillAppear) {
336
+ self.onWillAppear(nil);
337
+ }
338
+ // we do it here too because at this moment the `parentViewController` is already not nil,
339
+ // so if the parent is not UINavCtr, the frame will be updated to the correct one.
340
+ [self reactSetFrame:_reactFrame];
341
+ #endif
342
+ }
343
+
344
+ - (void)notifyWillDisappear
345
+ {
346
+ if (_hideKeyboardOnSwipe) {
347
+ [self endEditing:YES];
348
+ }
349
+ #ifdef RCT_NEW_ARCH_ENABLED
350
+ // If screen is already unmounted then there will be no event emitter
351
+ // it will be cleaned in prepareForRecycle
352
+ if (_eventEmitter != nullptr) {
353
+ std::dynamic_pointer_cast<const react::RNSScreenEventEmitter>(_eventEmitter)
354
+ ->onWillDisappear(react::RNSScreenEventEmitter::OnWillDisappear{});
355
+ }
356
+ #else
357
+ if (self.onWillDisappear) {
358
+ self.onWillDisappear(nil);
359
+ }
360
+ #endif
361
+ }
362
+
363
+ - (void)notifyAppear
364
+ {
365
+ #ifdef RCT_NEW_ARCH_ENABLED
366
+ // If screen is already unmounted then there will be no event emitter
367
+ // it will be cleaned in prepareForRecycle
368
+ if (_eventEmitter != nullptr) {
369
+ std::dynamic_pointer_cast<const react::RNSScreenEventEmitter>(_eventEmitter)
370
+ ->onAppear(react::RNSScreenEventEmitter::OnAppear{});
371
+ }
372
+ #else
373
+ if (self.onAppear) {
374
+ dispatch_async(dispatch_get_main_queue(), ^{
375
+ if (self.onAppear) {
376
+ self.onAppear(nil);
377
+ }
378
+ });
379
+ }
380
+ #endif
381
+ }
382
+
383
+ - (void)notifyDisappear
384
+ {
385
+ #ifdef RCT_NEW_ARCH_ENABLED
386
+ // If screen is already unmounted then there will be no event emitter
387
+ // it will be cleaned in prepareForRecycle
388
+ if (_eventEmitter != nullptr) {
389
+ std::dynamic_pointer_cast<const react::RNSScreenEventEmitter>(_eventEmitter)
390
+ ->onDisappear(react::RNSScreenEventEmitter::OnDisappear{});
391
+ }
392
+ #else
393
+ if (self.onDisappear) {
394
+ self.onDisappear(nil);
395
+ }
396
+ #endif
397
+ }
398
+
399
+ - (void)notifyHeaderHeightChange:(double)headerHeight
400
+ {
401
+ #ifdef RCT_NEW_ARCH_ENABLED
402
+ if (_eventEmitter != nullptr) {
403
+ std::dynamic_pointer_cast<const facebook::react::RNSScreenEventEmitter>(_eventEmitter)
404
+ ->onHeaderHeightChange(
405
+ facebook::react::RNSScreenEventEmitter::OnHeaderHeightChange{.headerHeight = headerHeight});
406
+ }
407
+
408
+ RNSHeaderHeightChangeEvent *event =
409
+ [[RNSHeaderHeightChangeEvent alloc] initWithEventName:@"onHeaderHeightChange"
410
+ reactTag:[NSNumber numberWithInt:self.tag]
411
+ headerHeight:headerHeight];
412
+ [[RCTBridge currentBridge].eventDispatcher sendEvent:event];
413
+ #else
414
+ if (self.onHeaderHeightChange) {
415
+ self.onHeaderHeightChange(@{
416
+ @"headerHeight" : @(headerHeight),
417
+ });
418
+ }
419
+ #endif
420
+ }
421
+
422
+ - (void)notifyGestureCancel
423
+ {
424
+ #ifdef RCT_NEW_ARCH_ENABLED
425
+ if (_eventEmitter != nullptr) {
426
+ std::dynamic_pointer_cast<const react::RNSScreenEventEmitter>(_eventEmitter)
427
+ ->onGestureCancel(react::RNSScreenEventEmitter::OnGestureCancel{});
428
+ }
429
+ #else
430
+ if (self.onGestureCancel) {
431
+ self.onGestureCancel(nil);
432
+ }
433
+ #endif
434
+ }
435
+
436
+ - (BOOL)isMountedUnderScreenOrReactRoot
437
+ {
438
+ #ifdef RCT_NEW_ARCH_ENABLED
439
+ #define RNS_EXPECTED_VIEW RCTRootComponentView
440
+ #else
441
+ #define RNS_EXPECTED_VIEW RCTRootView
442
+ #endif
443
+ for (UIView *parent = self.superview; parent != nil; parent = parent.superview) {
444
+ if ([parent isKindOfClass:[RNS_EXPECTED_VIEW class]] || [parent isKindOfClass:[RNSScreenView class]]) {
445
+ return YES;
446
+ }
447
+ }
448
+ return NO;
449
+ #undef RNS_EXPECTED_VIEW
450
+ }
451
+
452
+ - (void)didMoveToWindow
453
+ {
454
+ // For RN touches to work we need to instantiate and connect RCTTouchHandler. This only applies
455
+ // for screens that aren't mounted under RCTRootView e.g., modals that are mounted directly to
456
+ // root application window.
457
+ if (self.window != nil && ![self isMountedUnderScreenOrReactRoot]) {
458
+ if (_touchHandler == nil) {
459
+ #ifdef RCT_NEW_ARCH_ENABLED
460
+ _touchHandler = [RCTSurfaceTouchHandler new];
461
+ #else
462
+ _touchHandler = [[RCTTouchHandler alloc] initWithBridge:_bridge];
463
+ #endif
464
+ }
465
+ [_touchHandler attachToView:self];
466
+ } else {
467
+ [_touchHandler detachFromView:self];
468
+ }
469
+ }
470
+
471
+ #ifdef RCT_NEW_ARCH_ENABLED
472
+ - (RCTSurfaceTouchHandler *)touchHandler
473
+ #else
474
+ - (RCTTouchHandler *)touchHandler
475
+ #endif
476
+ {
477
+ if (_touchHandler != nil) {
478
+ return _touchHandler;
479
+ }
480
+ UIView *parent = [self superview];
481
+ while (parent != nil && ![parent respondsToSelector:@selector(touchHandler)])
482
+ parent = parent.superview;
483
+ if (parent != nil) {
484
+ return [parent performSelector:@selector(touchHandler)];
485
+ }
486
+ return nil;
487
+ }
488
+
489
+ - (void)notifyFinishTransitioning
490
+ {
491
+ [_controller notifyFinishTransitioning];
492
+ }
493
+
494
+ - (void)notifyTransitionProgress:(double)progress closing:(BOOL)closing goingForward:(BOOL)goingForward
495
+ {
496
+ #ifdef RCT_NEW_ARCH_ENABLED
497
+ if (_eventEmitter != nullptr) {
498
+ std::dynamic_pointer_cast<const react::RNSScreenEventEmitter>(_eventEmitter)
499
+ ->onTransitionProgress(react::RNSScreenEventEmitter::OnTransitionProgress{
500
+ .progress = progress, .closing = closing ? 1 : 0, .goingForward = goingForward ? 1 : 0});
501
+ }
502
+ RNSScreenViewEvent *event = [[RNSScreenViewEvent alloc] initWithEventName:@"onTransitionProgress"
503
+ reactTag:[NSNumber numberWithInt:self.tag]
504
+ progress:progress
505
+ closing:closing
506
+ goingForward:goingForward];
507
+ [[RCTBridge currentBridge].eventDispatcher sendEvent:event];
508
+ #else
509
+ if (self.onTransitionProgress) {
510
+ self.onTransitionProgress(@{
511
+ @"progress" : @(progress),
512
+ @"closing" : @(closing ? 1 : 0),
513
+ @"goingForward" : @(goingForward ? 1 : 0),
514
+ });
515
+ }
516
+ #endif
517
+ }
518
+
519
+ - (void)presentationControllerWillDismiss:(UIPresentationController *)presentationController
520
+ {
521
+ // We need to call both "cancel" and "reset" here because RN's gesture recognizer
522
+ // does not handle the scenario when it gets cancelled by other top
523
+ // level gesture recognizer. In this case by the modal dismiss gesture.
524
+ // Because of that, at the moment when this method gets called the React's
525
+ // gesture recognizer is already in FAILED state but cancel events never gets
526
+ // send to JS. Calling "reset" forces RCTTouchHanler to dispatch cancel event.
527
+ // To test this behavior one need to open a dismissable modal and start
528
+ // pulling down starting at some touchable item. Without "reset" the touchable
529
+ // will never go back from highlighted state even when the modal start sliding
530
+ // down.
531
+ #ifdef RCT_NEW_ARCH_ENABLED
532
+ [_touchHandler setEnabled:NO];
533
+ [_touchHandler setEnabled:YES];
534
+ #else
535
+ [_touchHandler cancel];
536
+ #endif
537
+ [_touchHandler reset];
538
+ }
539
+
540
+ - (BOOL)presentationControllerShouldDismiss:(UIPresentationController *)presentationController
541
+ {
542
+ if (_preventNativeDismiss) {
543
+ [self notifyDismissCancelledWithDismissCount:1];
544
+ return NO;
545
+ }
546
+ return _gestureEnabled;
547
+ }
548
+
549
+ - (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController
550
+ {
551
+ if ([_reactSuperview respondsToSelector:@selector(presentationControllerDidDismiss:)]) {
552
+ [_reactSuperview performSelector:@selector(presentationControllerDidDismiss:) withObject:presentationController];
553
+ }
554
+ }
555
+
556
+ - (RNSScreenStackHeaderConfig *_Nullable)findHeaderConfig
557
+ {
558
+ for (UIView *view in self.reactSubviews) {
559
+ if ([view isKindOfClass:RNSScreenStackHeaderConfig.class]) {
560
+ return (RNSScreenStackHeaderConfig *)view;
561
+ }
562
+ }
563
+ return nil;
564
+ }
565
+
566
+ - (BOOL)isModal
567
+ {
568
+ return self.stackPresentation != RNSScreenStackPresentationPush;
569
+ }
570
+
571
+ - (BOOL)isPresentedAsNativeModal
572
+ {
573
+ return self.controller.parentViewController == nil && self.controller.presentingViewController != nil;
574
+ }
575
+
576
+ - (BOOL)isFullscreenModal
577
+ {
578
+ switch (self.controller.modalPresentationStyle) {
579
+ case UIModalPresentationFullScreen:
580
+ case UIModalPresentationCurrentContext:
581
+ case UIModalPresentationOverCurrentContext:
582
+ return YES;
583
+ default:
584
+ return NO;
585
+ }
586
+ }
587
+
588
+ - (BOOL)isTransparentModal
589
+ {
590
+ return self.controller.modalPresentationStyle == UIModalPresentationOverFullScreen ||
591
+ self.controller.modalPresentationStyle == UIModalPresentationOverCurrentContext;
592
+ }
593
+
594
+ #if !TARGET_OS_TV
595
+ /**
596
+ * Updates settings for sheet presentation controller.
597
+ * Note that this method should not be called inside `stackPresentation` setter, because on Paper we don't have
598
+ * guarantee that values of all related props had been updated earlier.
599
+ */
600
+ - (void)updatePresentationStyle
601
+ {
602
+ #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_15_0) && \
603
+ __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_15_0
604
+ if (@available(iOS 15.0, *)) {
605
+ UISheetPresentationController *sheet = _controller.sheetPresentationController;
606
+ if (_stackPresentation == RNSScreenStackPresentationFormSheet && sheet != nil) {
607
+ sheet.prefersScrollingExpandsWhenScrolledToEdge = _sheetExpandsWhenScrolledToEdge;
608
+ sheet.prefersGrabberVisible = _sheetGrabberVisible;
609
+ sheet.preferredCornerRadius =
610
+ _sheetCornerRadius < 0 ? UISheetPresentationControllerAutomaticDimension : _sheetCornerRadius;
611
+
612
+ if (_sheetLargestUndimmedDetent == RNSScreenDetentTypeMedium) {
613
+ sheet.largestUndimmedDetentIdentifier = UISheetPresentationControllerDetentIdentifierMedium;
614
+ } else if (_sheetLargestUndimmedDetent == RNSScreenDetentTypeLarge) {
615
+ sheet.largestUndimmedDetentIdentifier = UISheetPresentationControllerDetentIdentifierLarge;
616
+ } else if (_sheetLargestUndimmedDetent == RNSScreenDetentTypeAll) {
617
+ sheet.largestUndimmedDetentIdentifier = nil;
618
+ } else {
619
+ RCTLogError(@"Unhandled value of sheetLargestUndimmedDetent passed");
620
+ }
621
+
622
+ if (_sheetAllowedDetents == RNSScreenDetentTypeMedium) {
623
+ sheet.detents = @[ UISheetPresentationControllerDetent.mediumDetent ];
624
+ if (sheet.selectedDetentIdentifier != UISheetPresentationControllerDetentIdentifierMedium) {
625
+ [sheet animateChanges:^{
626
+ sheet.selectedDetentIdentifier = UISheetPresentationControllerDetentIdentifierMedium;
627
+ }];
628
+ }
629
+ } else if (_sheetAllowedDetents == RNSScreenDetentTypeLarge) {
630
+ sheet.detents = @[ UISheetPresentationControllerDetent.largeDetent ];
631
+ if (sheet.selectedDetentIdentifier != UISheetPresentationControllerDetentIdentifierLarge) {
632
+ [sheet animateChanges:^{
633
+ sheet.selectedDetentIdentifier = UISheetPresentationControllerDetentIdentifierLarge;
634
+ }];
635
+ }
636
+ } else if (_sheetAllowedDetents == RNSScreenDetentTypeAll) {
637
+ sheet.detents =
638
+ @[ UISheetPresentationControllerDetent.mediumDetent, UISheetPresentationControllerDetent.largeDetent ];
639
+ } else {
640
+ RCTLogError(@"Unhandled value of sheetAllowedDetents passed");
641
+ }
642
+ }
643
+ }
644
+ #endif // Check for max allowed iOS version
645
+ }
646
+ #endif // !TARGET_OS_TV
647
+
648
+ #pragma mark - Fabric specific
649
+ #ifdef RCT_NEW_ARCH_ENABLED
650
+
651
+ - (BOOL)hasHeaderConfig
652
+ {
653
+ return _config != nil;
654
+ }
655
+
656
+ + (react::ComponentDescriptorProvider)componentDescriptorProvider
657
+ {
658
+ return react::concreteComponentDescriptorProvider<react::RNSScreenComponentDescriptor>();
659
+ }
660
+
661
+ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
662
+ {
663
+ if ([childComponentView isKindOfClass:[RNSScreenStackHeaderConfig class]]) {
664
+ _config = (RNSScreenStackHeaderConfig *)childComponentView;
665
+ _config.screenView = self;
666
+ }
667
+ [_reactSubviews insertObject:childComponentView atIndex:index];
668
+ [super mountChildComponentView:childComponentView index:index];
669
+ }
670
+
671
+ - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
672
+ {
673
+ if ([childComponentView isKindOfClass:[RNSScreenStackHeaderConfig class]]) {
674
+ _config = nil;
675
+ }
676
+ [_reactSubviews removeObject:childComponentView];
677
+ [super unmountChildComponentView:childComponentView index:index];
678
+ }
679
+
680
+ #pragma mark - RCTComponentViewProtocol
681
+
682
+ - (void)prepareForRecycle
683
+ {
684
+ [super prepareForRecycle];
685
+ // TODO: Make sure that there is no edge case when this should be uncommented
686
+ // _controller=nil;
687
+ _dismissed = NO;
688
+ _state.reset();
689
+ _touchHandler = nil;
690
+
691
+ // We set this prop to default value here to workaround view-recycling.
692
+ // Let's assume the view has had _stackPresentation == <some modal stack presentation> set
693
+ // before below line was executed. Then, when instantiated again (with the same modal presentation)
694
+ // updateProps:oldProps: method would be called and setter for stack presentation would not be called.
695
+ // This is crucial as in that setter we register `self.controller` as a delegate
696
+ // (UIAdaptivePresentationControllerDelegate) to presentation controller and this leads to buggy modal behaviour as we
697
+ // rely on UIAdaptivePresentationControllerDelegate callbacks. Restoring the default value and then comparing against
698
+ // it in updateProps:oldProps: allows for setter to be called, however if there was some additional logic to execute
699
+ // when stackPresentation is set to "push" the setter would not be triggered.
700
+ _stackPresentation = RNSScreenStackPresentationPush;
701
+ }
702
+
703
+ - (void)updateProps:(react::Props::Shared const &)props oldProps:(react::Props::Shared const &)oldProps
704
+ {
705
+ const auto &oldScreenProps = *std::static_pointer_cast<const react::RNSScreenProps>(_props);
706
+ const auto &newScreenProps = *std::static_pointer_cast<const react::RNSScreenProps>(props);
707
+
708
+ [self setFullScreenSwipeEnabled:newScreenProps.fullScreenSwipeEnabled];
709
+
710
+ [self setGestureEnabled:newScreenProps.gestureEnabled];
711
+
712
+ [self setTransitionDuration:[NSNumber numberWithInt:newScreenProps.transitionDuration]];
713
+
714
+ [self setHideKeyboardOnSwipe:newScreenProps.hideKeyboardOnSwipe];
715
+
716
+ [self setCustomAnimationOnSwipe:newScreenProps.customAnimationOnSwipe];
717
+
718
+ [self
719
+ setGestureResponseDistance:[RNSConvert
720
+ gestureResponseDistanceDictFromCppStruct:newScreenProps.gestureResponseDistance]];
721
+
722
+ [self setPreventNativeDismiss:newScreenProps.preventNativeDismiss];
723
+
724
+ [self setActivityStateOrNil:[NSNumber numberWithFloat:newScreenProps.activityState]];
725
+
726
+ [self setSwipeDirection:[RNSConvert RNSScreenSwipeDirectionFromCppEquivalent:newScreenProps.swipeDirection]];
727
+
728
+ #if !TARGET_OS_TV
729
+ if (newScreenProps.statusBarHidden != oldScreenProps.statusBarHidden) {
730
+ [self setStatusBarHidden:newScreenProps.statusBarHidden];
731
+ }
732
+
733
+ if (newScreenProps.statusBarStyle != oldScreenProps.statusBarStyle) {
734
+ [self setStatusBarStyle:[RCTConvert
735
+ RNSStatusBarStyle:RCTNSStringFromStringNilIfEmpty(newScreenProps.statusBarStyle)]];
736
+ }
737
+
738
+ if (newScreenProps.statusBarAnimation != oldScreenProps.statusBarAnimation) {
739
+ [self setStatusBarAnimation:[RCTConvert UIStatusBarAnimation:RCTNSStringFromStringNilIfEmpty(
740
+ newScreenProps.statusBarAnimation)]];
741
+ }
742
+
743
+ if (newScreenProps.screenOrientation != oldScreenProps.screenOrientation) {
744
+ [self setScreenOrientation:[RCTConvert UIInterfaceOrientationMask:RCTNSStringFromStringNilIfEmpty(
745
+ newScreenProps.screenOrientation)]];
746
+ }
747
+
748
+ if (newScreenProps.homeIndicatorHidden != oldScreenProps.homeIndicatorHidden) {
749
+ [self setHomeIndicatorHidden:newScreenProps.homeIndicatorHidden];
750
+ }
751
+
752
+ [self setSheetGrabberVisible:newScreenProps.sheetGrabberVisible];
753
+ [self setSheetCornerRadius:newScreenProps.sheetCornerRadius];
754
+ [self setSheetExpandsWhenScrolledToEdge:newScreenProps.sheetExpandsWhenScrolledToEdge];
755
+
756
+ if (newScreenProps.sheetAllowedDetents != oldScreenProps.sheetAllowedDetents) {
757
+ [self setSheetAllowedDetents:[RNSConvert RNSScreenDetentTypeFromAllowedDetents:newScreenProps.sheetAllowedDetents]];
758
+ }
759
+
760
+ if (newScreenProps.sheetLargestUndimmedDetent != oldScreenProps.sheetLargestUndimmedDetent) {
761
+ [self setSheetLargestUndimmedDetent:
762
+ [RNSConvert RNSScreenDetentTypeFromLargestUndimmedDetent:newScreenProps.sheetLargestUndimmedDetent]];
763
+ }
764
+ #endif // !TARGET_OS_TV
765
+
766
+ // Notice that we compare against _stackPresentation, not oldScreenProps.stackPresentation.
767
+ // See comment in prepareForRecycle method for explanation.
768
+ RNSScreenStackPresentation newStackPresentation =
769
+ [RNSConvert RNSScreenStackPresentationFromCppEquivalent:newScreenProps.stackPresentation];
770
+ if (newStackPresentation != _stackPresentation) {
771
+ [self setStackPresentation:newStackPresentation];
772
+ }
773
+
774
+ if (newScreenProps.stackAnimation != oldScreenProps.stackAnimation) {
775
+ [self setStackAnimation:[RNSConvert RNSScreenStackAnimationFromCppEquivalent:newScreenProps.stackAnimation]];
776
+ }
777
+
778
+ if (newScreenProps.replaceAnimation != oldScreenProps.replaceAnimation) {
779
+ [self setReplaceAnimation:[RNSConvert RNSScreenReplaceAnimationFromCppEquivalent:newScreenProps.replaceAnimation]];
780
+ }
781
+
782
+ [super updateProps:props oldProps:oldProps];
783
+ }
784
+
785
+ - (void)updateState:(react::State::Shared const &)state oldState:(react::State::Shared const &)oldState
786
+ {
787
+ _state = std::static_pointer_cast<const react::RNSScreenShadowNode::ConcreteState>(state);
788
+ }
789
+
790
+ - (void)updateLayoutMetrics:(const react::LayoutMetrics &)layoutMetrics
791
+ oldLayoutMetrics:(const react::LayoutMetrics &)oldLayoutMetrics
792
+ {
793
+ _newLayoutMetrics = layoutMetrics;
794
+ _oldLayoutMetrics = oldLayoutMetrics;
795
+ UIViewController *parentVC = self.reactViewController.parentViewController;
796
+ if (parentVC != nil && ![parentVC isKindOfClass:[RNSNavigationController class]]) {
797
+ [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
798
+ }
799
+ // when screen is mounted under RNSNavigationController it's size is controller
800
+ // by the navigation controller itself. That is, it is set to fill space of
801
+ // the controller. In that case we ignore react layout system from managing
802
+ // the screen dimensions and we wait for the screen VC to update and then we
803
+ // pass the dimensions to ui view manager to take into account when laying out
804
+ // subviews
805
+ // Explanation taken from `reactSetFrame`, which is old arch equivalent of this code.
806
+ }
807
+
808
+ - (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask
809
+ {
810
+ [super finalizeUpdates:updateMask];
811
+ #if !TARGET_OS_TV
812
+ [self updatePresentationStyle];
813
+ #endif // !TARGET_OS_TV
814
+ }
815
+
816
+ #pragma mark - Paper specific
817
+ #else
818
+
819
+ - (void)didSetProps:(NSArray<NSString *> *)changedProps
820
+ {
821
+ [super didSetProps:changedProps];
822
+ #if !TARGET_OS_TV
823
+ [self updatePresentationStyle];
824
+ #endif // !TARGET_OS_TV
825
+ }
826
+
827
+ - (void)setPointerEvents:(RCTPointerEvents)pointerEvents
828
+ {
829
+ // pointer events settings are managed by the parent screen container, we ignore
830
+ // any attempt of setting that via React props
831
+ }
832
+
833
+ - (void)reactSetFrame:(CGRect)frame
834
+ {
835
+ _reactFrame = frame;
836
+ UIViewController *parentVC = self.reactViewController.parentViewController;
837
+ if (parentVC != nil && ![parentVC isKindOfClass:[RNSNavigationController class]]) {
838
+ [super reactSetFrame:frame];
839
+ }
840
+ // when screen is mounted under RNSNavigationController it's size is controller
841
+ // by the navigation controller itself. That is, it is set to fill space of
842
+ // the controller. In that case we ignore react layout system from managing
843
+ // the screen dimensions and we wait for the screen VC to update and then we
844
+ // pass the dimensions to ui view manager to take into account when laying out
845
+ // subviews
846
+ }
847
+
848
+ - (void)invalidate
849
+ {
850
+ _controller = nil;
851
+ }
852
+ #endif
853
+
854
+ @end
855
+
856
+ #ifdef RCT_NEW_ARCH_ENABLED
857
+ Class<RCTComponentViewProtocol> RNSScreenCls(void)
858
+ {
859
+ return RNSScreenView.class;
860
+ }
861
+ #endif
862
+
863
+ #pragma mark - RNSScreen
864
+
865
+ @implementation RNSScreen {
866
+ __weak id _previousFirstResponder;
867
+ CGRect _lastViewFrame;
868
+ RNSScreenView *_initialView;
869
+ UIView *_fakeView;
870
+ CADisplayLink *_animationTimer;
871
+ CGFloat _currentAlpha;
872
+ BOOL _closing;
873
+ BOOL _goingForward;
874
+ int _dismissCount;
875
+ BOOL _isSwiping;
876
+ BOOL _shouldNotify;
877
+ }
878
+
879
+ #pragma mark - Common
880
+
881
+ - (instancetype)initWithView:(UIView *)view
882
+ {
883
+ if (self = [super init]) {
884
+ self.view = view;
885
+ _fakeView = [UIView new];
886
+ _shouldNotify = YES;
887
+ #ifdef RCT_NEW_ARCH_ENABLED
888
+ _initialView = (RNSScreenView *)view;
889
+ #endif
890
+ }
891
+ return self;
892
+ }
893
+
894
+ // TODO: Find out why this is executed when screen is going out
895
+ - (void)viewWillAppear:(BOOL)animated
896
+ {
897
+ [super viewWillAppear:animated];
898
+ if (!_isSwiping) {
899
+ [self.screenView notifyWillAppear];
900
+ if (self.transitionCoordinator.isInteractive) {
901
+ // we started dismissing with swipe gesture
902
+ _isSwiping = YES;
903
+ }
904
+ } else {
905
+ // this event is also triggered if we cancelled the swipe.
906
+ // The _isSwiping is still true, but we don't want to notify then
907
+ _shouldNotify = NO;
908
+ }
909
+
910
+ [self hideHeaderIfNecessary];
911
+ // as per documentation of these methods
912
+ _goingForward = [self isBeingPresented] || [self isMovingToParentViewController];
913
+
914
+ [RNSScreenWindowTraits updateWindowTraits];
915
+ if (_shouldNotify) {
916
+ _closing = NO;
917
+ [self notifyTransitionProgress:0.0 closing:_closing goingForward:_goingForward];
918
+ [self setupProgressNotification];
919
+ }
920
+ }
921
+
922
+ - (void)viewWillDisappear:(BOOL)animated
923
+ {
924
+ [super viewWillDisappear:animated];
925
+ // self.navigationController might be null when we are dismissing a modal
926
+ if (!self.transitionCoordinator.isInteractive && self.navigationController != nil) {
927
+ // user might have long pressed ios 14 back button item,
928
+ // so he can go back more than one screen and we need to dismiss more screens in JS stack then.
929
+ // We check it by calculating the difference between the index of currently displayed screen
930
+ // and the index of the target screen, which is the view of topViewController at this point.
931
+ // If the value is lower than 1, it means we are dismissing a modal, or navigating forward, or going back with JS.
932
+ int selfIndex = [self getIndexOfView:self.screenView];
933
+ int targetIndex = [self getIndexOfView:self.navigationController.topViewController.view];
934
+ _dismissCount = selfIndex - targetIndex > 0 ? selfIndex - targetIndex : 1;
935
+ } else {
936
+ _dismissCount = 1;
937
+ }
938
+
939
+ // same flow as in viewWillAppear
940
+ if (!_isSwiping) {
941
+ [self.screenView notifyWillDisappear];
942
+ if (self.transitionCoordinator.isInteractive) {
943
+ _isSwiping = YES;
944
+ }
945
+ } else {
946
+ _shouldNotify = NO;
947
+ }
948
+
949
+ // as per documentation of these methods
950
+ _goingForward = !([self isBeingDismissed] || [self isMovingFromParentViewController]);
951
+
952
+ if (_shouldNotify) {
953
+ _closing = YES;
954
+ [self notifyTransitionProgress:0.0 closing:_closing goingForward:_goingForward];
955
+ [self setupProgressNotification];
956
+ }
957
+ }
958
+
959
+ - (void)viewDidAppear:(BOOL)animated
960
+ {
961
+ [super viewDidAppear:animated];
962
+ if (!_isSwiping || _shouldNotify) {
963
+ // we are going forward or dismissing without swipe
964
+ // or successfully swiped back
965
+ [self.screenView notifyAppear];
966
+ [self notifyTransitionProgress:1.0 closing:NO goingForward:_goingForward];
967
+ } else {
968
+ [self.screenView notifyGestureCancel];
969
+ }
970
+
971
+ _isSwiping = NO;
972
+ _shouldNotify = YES;
973
+ }
974
+
975
+ - (void)viewDidDisappear:(BOOL)animated
976
+ {
977
+ [super viewDidDisappear:animated];
978
+ #ifdef RCT_NEW_ARCH_ENABLED
979
+ [self resetViewToScreen];
980
+ #endif
981
+ if (self.parentViewController == nil && self.presentingViewController == nil) {
982
+ if (self.screenView.preventNativeDismiss) {
983
+ // if we want to prevent the native dismiss, we do not send dismissal event,
984
+ // but instead call `updateContainer`, which restores the JS navigation stack
985
+ [self.screenView.reactSuperview updateContainer];
986
+ [self.screenView notifyDismissCancelledWithDismissCount:_dismissCount];
987
+ } else {
988
+ // screen dismissed, send event
989
+ [self.screenView notifyDismissedWithCount:_dismissCount];
990
+ }
991
+ }
992
+ // same flow as in viewDidAppear
993
+ if (!_isSwiping || _shouldNotify) {
994
+ [self.screenView notifyDisappear];
995
+ [self notifyTransitionProgress:1.0 closing:YES goingForward:_goingForward];
996
+ }
997
+
998
+ _isSwiping = NO;
999
+ _shouldNotify = YES;
1000
+ #ifdef RCT_NEW_ARCH_ENABLED
1001
+ #else
1002
+ [self traverseForScrollView:self.screenView];
1003
+ #endif
1004
+ }
1005
+
1006
+ - (void)viewDidLayoutSubviews
1007
+ {
1008
+ [super viewDidLayoutSubviews];
1009
+
1010
+ // The below code makes the screen view adapt dimensions provided by the system. We take these
1011
+ // into account only when the view is mounted under RNSNavigationController in which case system
1012
+ // provides additional padding to account for possible header, and in the case when screen is
1013
+ // shown as a native modal, as the final dimensions of the modal on iOS 12+ are shorter than the
1014
+ // screen size
1015
+ BOOL isDisplayedWithinUINavController = [self.parentViewController isKindOfClass:[RNSNavigationController class]];
1016
+
1017
+ // Calculate header height on modal open
1018
+ if (self.screenView.isPresentedAsNativeModal) {
1019
+ [self calculateAndNotifyHeaderHeightChangeIsModal:YES];
1020
+ }
1021
+
1022
+ if (isDisplayedWithinUINavController || self.screenView.isPresentedAsNativeModal) {
1023
+ #ifdef RCT_NEW_ARCH_ENABLED
1024
+ [self.screenView updateBounds];
1025
+ #else
1026
+ if (!CGRectEqualToRect(_lastViewFrame, self.screenView.frame)) {
1027
+ _lastViewFrame = self.screenView.frame;
1028
+ [((RNSScreenView *)self.viewIfLoaded) updateBounds];
1029
+ }
1030
+ #endif
1031
+ }
1032
+ }
1033
+
1034
+ // Checks whether this screen has any child view controllers of type RNSNavigationController.
1035
+ // Useful for checking if this screen has nested stack or is displayed at the top.
1036
+ - (BOOL)hasNestedStack
1037
+ {
1038
+ for (UIViewController *vc in self.childViewControllers) {
1039
+ if ([vc isKindOfClass:[RNSNavigationController class]]) {
1040
+ return YES;
1041
+ }
1042
+ }
1043
+
1044
+ return NO;
1045
+ }
1046
+
1047
+ - (CGFloat)getCalculatedHeaderHeightIsModal:(BOOL)isModal
1048
+ {
1049
+ CGFloat navbarHeight = self.navigationController.navigationBar.frame.size.height;
1050
+
1051
+ // In case where screen is a modal, we want to calculate just its childViewController's height
1052
+ if (isModal && self.childViewControllers.count > 0 &&
1053
+ [self.childViewControllers[0] isKindOfClass:UINavigationController.class]) {
1054
+ UINavigationController *childNavCtr = self.childViewControllers[0];
1055
+ navbarHeight = childNavCtr.navigationBar.frame.size.height;
1056
+ }
1057
+
1058
+ return navbarHeight;
1059
+ }
1060
+
1061
+ - (CGSize)getCalculatedStatusBarHeightIsModal:(BOOL)isModal
1062
+ {
1063
+ #if !TARGET_OS_TV
1064
+ BOOL isDraggableModal = isModal && ![self.screenView isFullscreenModal];
1065
+ BOOL isDraggableModalWithChildViewCtr =
1066
+ isDraggableModal && self.childViewControllers.count > 0 && self.childViewControllers[0] != nil;
1067
+
1068
+ // When modal is floating (we can grab its header), we don't want to calculate status bar in it.
1069
+ // Thus, we return '0' as a height of status bar.
1070
+ if (isDraggableModalWithChildViewCtr || self.screenView.isTransparentModal) {
1071
+ return CGSizeMake(0, 0);
1072
+ }
1073
+
1074
+ CGSize fallbackStatusBarSize = [[UIApplication sharedApplication] statusBarFrame].size;
1075
+
1076
+ #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
1077
+ __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
1078
+ if (@available(iOS 13.0, *)) {
1079
+ CGSize primaryStatusBarSize = self.view.window.windowScene.statusBarManager.statusBarFrame.size;
1080
+ if (primaryStatusBarSize.height == 0 || primaryStatusBarSize.width == 0)
1081
+ return fallbackStatusBarSize;
1082
+
1083
+ return primaryStatusBarSize;
1084
+ } else {
1085
+ return fallbackStatusBarSize;
1086
+ }
1087
+ #endif /* Check for iOS 13.0 */
1088
+
1089
+ #else
1090
+ // On TVOS, status bar doesn't exist
1091
+ return CGSizeMake(0, 0);
1092
+ #endif // !TARGET_OS_TV
1093
+ }
1094
+
1095
+ - (CGFloat)calculateHeaderHeightIsModal:(BOOL)isModal
1096
+ {
1097
+ CGFloat navbarHeight = [self getCalculatedHeaderHeightIsModal:isModal];
1098
+ CGSize statusBarSize = [self getCalculatedStatusBarHeightIsModal:isModal];
1099
+
1100
+ // Unfortunately, UIKit doesn't care about switching width and height options on screen rotation.
1101
+ // We should check if user has rotated its screen, so we're choosing the minimum value between the
1102
+ // width and height.
1103
+ CGFloat statusBarHeight = MIN(statusBarSize.width, statusBarSize.height);
1104
+ return navbarHeight + statusBarHeight;
1105
+ }
1106
+
1107
+ - (void)calculateAndNotifyHeaderHeightChangeIsModal:(BOOL)isModal
1108
+ {
1109
+ CGFloat totalHeight = [self calculateHeaderHeightIsModal:isModal];
1110
+ [self.screenView notifyHeaderHeightChange:totalHeight];
1111
+ }
1112
+
1113
+ - (void)notifyFinishTransitioning
1114
+ {
1115
+ [_previousFirstResponder becomeFirstResponder];
1116
+ _previousFirstResponder = nil;
1117
+ // the correct Screen for appearance is set after the transition, same for orientation.
1118
+ [RNSScreenWindowTraits updateWindowTraits];
1119
+ }
1120
+
1121
+ - (void)willMoveToParentViewController:(UIViewController *)parent
1122
+ {
1123
+ [super willMoveToParentViewController:parent];
1124
+ if (parent == nil) {
1125
+ id responder = [self findFirstResponder:self.screenView];
1126
+ if (responder != nil) {
1127
+ _previousFirstResponder = responder;
1128
+ }
1129
+ }
1130
+ }
1131
+
1132
+ - (id)findFirstResponder:(UIView *)parent
1133
+ {
1134
+ if (parent.isFirstResponder) {
1135
+ return parent;
1136
+ }
1137
+ for (UIView *subView in parent.subviews) {
1138
+ id responder = [self findFirstResponder:subView];
1139
+ if (responder != nil) {
1140
+ return responder;
1141
+ }
1142
+ }
1143
+ return nil;
1144
+ }
1145
+
1146
+ #pragma mark - transition progress related methods
1147
+
1148
+ - (void)setupProgressNotification
1149
+ {
1150
+ if (self.transitionCoordinator != nil) {
1151
+ _fakeView.alpha = 0.0;
1152
+ [self.transitionCoordinator
1153
+ animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
1154
+ [[context containerView] addSubview:self->_fakeView];
1155
+ self->_fakeView.alpha = 1.0;
1156
+ self->_animationTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleAnimation)];
1157
+ [self->_animationTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
1158
+ }
1159
+ completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
1160
+ [self->_animationTimer setPaused:YES];
1161
+ [self->_animationTimer invalidate];
1162
+ [self->_fakeView removeFromSuperview];
1163
+ }];
1164
+ }
1165
+ }
1166
+
1167
+ - (void)handleAnimation
1168
+ {
1169
+ if ([[_fakeView layer] presentationLayer] != nil) {
1170
+ CGFloat fakeViewAlpha = _fakeView.layer.presentationLayer.opacity;
1171
+ if (_currentAlpha != fakeViewAlpha) {
1172
+ _currentAlpha = fmax(0.0, fmin(1.0, fakeViewAlpha));
1173
+ [self notifyTransitionProgress:_currentAlpha closing:_closing goingForward:_goingForward];
1174
+ }
1175
+ }
1176
+ }
1177
+
1178
+ - (void)notifyTransitionProgress:(double)progress closing:(BOOL)closing goingForward:(BOOL)goingForward
1179
+ {
1180
+ if ([self.view isKindOfClass:[RNSScreenView class]]) {
1181
+ // if the view is already snapshot, there is not sense in sending progress since on JS side
1182
+ // the component is already not present
1183
+ [(RNSScreenView *)self.view notifyTransitionProgress:progress closing:closing goingForward:goingForward];
1184
+ }
1185
+ }
1186
+
1187
+ #if !TARGET_OS_TV
1188
+ // if the returned vc is a child, it means that it can provide config;
1189
+ // if the returned vc is self, it means that there is no child for config and self has config to provide,
1190
+ // so we return self which results in asking self for preferredStatusBarStyle/Animation etc.;
1191
+ // if the returned vc is nil, it means none of children could provide config and self does not have config either,
1192
+ // so if it was asked by parent, it will fallback to parent's option, or use default option if it is the top Screen
1193
+ - (UIViewController *)findChildVCForConfigAndTrait:(RNSWindowTrait)trait includingModals:(BOOL)includingModals
1194
+ {
1195
+ UIViewController *lastViewController = [[self childViewControllers] lastObject];
1196
+ if ([self.presentedViewController isKindOfClass:[RNSScreen class]]) {
1197
+ lastViewController = self.presentedViewController;
1198
+ // we don't want to allow controlling of status bar appearance when we present non-fullScreen modal
1199
+ // and it is not possible if `modalPresentationCapturesStatusBarAppearance` is not set to YES, so even
1200
+ // if we went into a modal here and ask it, it wouldn't take any effect. For fullScreen modals, the system
1201
+ // asks them by itself, so we can stop traversing here.
1202
+ // for screen orientation, we need to start the search again from that modal
1203
+ return !includingModals
1204
+ ? nil
1205
+ : [(RNSScreen *)lastViewController findChildVCForConfigAndTrait:trait includingModals:includingModals]
1206
+ ?: lastViewController;
1207
+ }
1208
+
1209
+ UIViewController *selfOrNil = [self hasTraitSet:trait] ? self : nil;
1210
+ if (lastViewController == nil) {
1211
+ return selfOrNil;
1212
+ } else {
1213
+ if ([lastViewController conformsToProtocol:@protocol(RNSViewControllerDelegate)]) {
1214
+ // If there is a child (should be VC of ScreenContainer or ScreenStack), that has a child that could provide the
1215
+ // trait, we recursively go into its findChildVCForConfig, and if one of the children has the trait set, we return
1216
+ // it, otherwise we return self if this VC has config, and nil if it doesn't we use
1217
+ // `childViewControllerForStatusBarStyle` for all options since the behavior is the same for all of them
1218
+ UIViewController *childScreen = [lastViewController childViewControllerForStatusBarStyle];
1219
+ if ([childScreen isKindOfClass:[RNSScreen class]]) {
1220
+ return [(RNSScreen *)childScreen findChildVCForConfigAndTrait:trait includingModals:includingModals]
1221
+ ?: selfOrNil;
1222
+ } else {
1223
+ return selfOrNil;
1224
+ }
1225
+ } else {
1226
+ // child vc is not from this library, so we don't ask it
1227
+ return selfOrNil;
1228
+ }
1229
+ }
1230
+ }
1231
+
1232
+ - (BOOL)hasTraitSet:(RNSWindowTrait)trait
1233
+ {
1234
+ switch (trait) {
1235
+ case RNSWindowTraitStyle: {
1236
+ return self.screenView.hasStatusBarStyleSet;
1237
+ }
1238
+ case RNSWindowTraitAnimation: {
1239
+ return self.screenView.hasStatusBarAnimationSet;
1240
+ }
1241
+ case RNSWindowTraitHidden: {
1242
+ return self.screenView.hasStatusBarHiddenSet;
1243
+ }
1244
+ case RNSWindowTraitOrientation: {
1245
+ return self.screenView.hasOrientationSet;
1246
+ }
1247
+ case RNSWindowTraitHomeIndicatorHidden: {
1248
+ return self.screenView.hasHomeIndicatorHiddenSet;
1249
+ }
1250
+ default: {
1251
+ RCTLogError(@"Unknown trait passed: %d", (int)trait);
1252
+ }
1253
+ }
1254
+ return NO;
1255
+ }
1256
+
1257
+ - (UIViewController *)childViewControllerForStatusBarHidden
1258
+ {
1259
+ UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitHidden includingModals:NO];
1260
+ return vc == self ? nil : vc;
1261
+ }
1262
+
1263
+ - (BOOL)prefersStatusBarHidden
1264
+ {
1265
+ return self.screenView.statusBarHidden;
1266
+ }
1267
+
1268
+ - (UIViewController *)childViewControllerForStatusBarStyle
1269
+ {
1270
+ UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitStyle includingModals:NO];
1271
+ return vc == self ? nil : vc;
1272
+ }
1273
+
1274
+ - (UIStatusBarStyle)preferredStatusBarStyle
1275
+ {
1276
+ return [RNSScreenWindowTraits statusBarStyleForRNSStatusBarStyle:self.screenView.statusBarStyle];
1277
+ }
1278
+
1279
+ - (UIStatusBarAnimation)preferredStatusBarUpdateAnimation
1280
+ {
1281
+ UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitAnimation includingModals:NO];
1282
+
1283
+ if ([vc isKindOfClass:[RNSScreen class]]) {
1284
+ return ((RNSScreen *)vc).screenView.statusBarAnimation;
1285
+ }
1286
+ return UIStatusBarAnimationFade;
1287
+ }
1288
+
1289
+ - (UIInterfaceOrientationMask)supportedInterfaceOrientations
1290
+ {
1291
+ UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitOrientation includingModals:YES];
1292
+
1293
+ if ([vc isKindOfClass:[RNSScreen class]]) {
1294
+ return ((RNSScreen *)vc).screenView.screenOrientation;
1295
+ }
1296
+ return UIInterfaceOrientationMaskAllButUpsideDown;
1297
+ }
1298
+
1299
+ - (UIViewController *)childViewControllerForHomeIndicatorAutoHidden
1300
+ {
1301
+ UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitHomeIndicatorHidden includingModals:YES];
1302
+ return vc == self ? nil : vc;
1303
+ }
1304
+
1305
+ - (BOOL)prefersHomeIndicatorAutoHidden
1306
+ {
1307
+ return self.screenView.homeIndicatorHidden;
1308
+ }
1309
+ - (int)getParentChildrenCount
1310
+ {
1311
+ return (int)[[self.screenView.reactSuperview reactSubviews] count];
1312
+ }
1313
+ #endif
1314
+
1315
+ - (int)getIndexOfView:(UIView *)view
1316
+ {
1317
+ return (int)[[self.screenView.reactSuperview reactSubviews] indexOfObject:view];
1318
+ }
1319
+
1320
+ // since on Fabric the view of controller can be a snapshot of type `UIView`,
1321
+ // when we want to check props of ScreenView, we need to get them from _initialView
1322
+ - (RNSScreenView *)screenView
1323
+ {
1324
+ #ifdef RCT_NEW_ARCH_ENABLED
1325
+ return _initialView;
1326
+ #else
1327
+ return (RNSScreenView *)self.view;
1328
+ #endif
1329
+ }
1330
+
1331
+ - (void)hideHeaderIfNecessary
1332
+ {
1333
+ #if !TARGET_OS_TV
1334
+ // On iOS >=13, there is a bug when user transitions from screen with active search bar to screen without header
1335
+ // In that case default iOS header will be shown. To fix this we hide header when the screens that appears has header
1336
+ // hidden and search bar was active on previous screen. We need to do it asynchronously, because default header is
1337
+ // added after viewWillAppear.
1338
+ if (@available(iOS 13.0, *)) {
1339
+ NSUInteger currentIndex = [self.navigationController.viewControllers indexOfObject:self];
1340
+
1341
+ // we need to check whether reactSubviews array is empty, because on Fabric child nodes are unmounted first ->
1342
+ // reactSubviews array may be empty
1343
+ RNSScreenStackHeaderConfig *config = [self.screenView findHeaderConfig];
1344
+ if (currentIndex > 0 && config != nil) {
1345
+ UINavigationItem *prevNavigationItem =
1346
+ [self.navigationController.viewControllers objectAtIndex:currentIndex - 1].navigationItem;
1347
+ BOOL wasSearchBarActive = prevNavigationItem.searchController.active;
1348
+
1349
+ #ifdef RCT_NEW_ARCH_ENABLED
1350
+ BOOL shouldHideHeader = !config.show;
1351
+ #else
1352
+ BOOL shouldHideHeader = config.hide;
1353
+ #endif
1354
+
1355
+ if (wasSearchBarActive && shouldHideHeader) {
1356
+ dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 0);
1357
+ dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
1358
+ [self.navigationController setNavigationBarHidden:YES animated:NO];
1359
+ });
1360
+ }
1361
+ }
1362
+ }
1363
+ #endif
1364
+ }
1365
+
1366
+ #ifdef RCT_NEW_ARCH_ENABLED
1367
+ #pragma mark - Fabric specific
1368
+
1369
+ - (void)setViewToSnapshot:(UIView *)snapshot
1370
+ {
1371
+ // modals of native stack seem not to support
1372
+ // changing their view by just setting the view
1373
+ if (_initialView.stackPresentation != RNSScreenStackPresentationPush) {
1374
+ UIView *superView = self.view.superview;
1375
+ [self.view removeFromSuperview];
1376
+ self.view = snapshot;
1377
+ [superView addSubview:self.view];
1378
+ } else {
1379
+ [self.view removeFromSuperview];
1380
+ self.view = snapshot;
1381
+ }
1382
+ }
1383
+
1384
+ - (void)resetViewToScreen
1385
+ {
1386
+ if (self.view != _initialView) {
1387
+ [self.view removeFromSuperview];
1388
+ self.view = _initialView;
1389
+ }
1390
+ }
1391
+
1392
+ #else
1393
+ #pragma mark - Paper specific
1394
+
1395
+ - (void)traverseForScrollView:(UIView *)view
1396
+ {
1397
+ if (![[self.view valueForKey:@"_bridge"] valueForKey:@"_jsThread"]) {
1398
+ // we don't want to send `scrollViewDidEndDecelerating` event to JS before the JS thread is ready
1399
+ return;
1400
+ }
1401
+ if ([view isKindOfClass:[UIScrollView class]] &&
1402
+ ([[(UIScrollView *)view delegate] respondsToSelector:@selector(scrollViewDidEndDecelerating:)])) {
1403
+ [[(UIScrollView *)view delegate] scrollViewDidEndDecelerating:(id)view];
1404
+ }
1405
+ [view.subviews enumerateObjectsUsingBlock:^(__kindof UIView *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
1406
+ [self traverseForScrollView:obj];
1407
+ }];
1408
+ }
1409
+ #endif
1410
+
1411
+ @end
1412
+
1413
+ @implementation RNSScreenManager
1414
+
1415
+ RCT_EXPORT_MODULE()
1416
+
1417
+ // we want to handle the case when activityState is nil
1418
+ RCT_REMAP_VIEW_PROPERTY(activityState, activityStateOrNil, NSNumber)
1419
+ RCT_EXPORT_VIEW_PROPERTY(customAnimationOnSwipe, BOOL);
1420
+ RCT_EXPORT_VIEW_PROPERTY(fullScreenSwipeEnabled, BOOL);
1421
+ RCT_EXPORT_VIEW_PROPERTY(gestureEnabled, BOOL)
1422
+ RCT_EXPORT_VIEW_PROPERTY(gestureResponseDistance, NSDictionary)
1423
+ RCT_EXPORT_VIEW_PROPERTY(hideKeyboardOnSwipe, BOOL)
1424
+ RCT_EXPORT_VIEW_PROPERTY(preventNativeDismiss, BOOL)
1425
+ RCT_EXPORT_VIEW_PROPERTY(replaceAnimation, RNSScreenReplaceAnimation)
1426
+ RCT_EXPORT_VIEW_PROPERTY(stackPresentation, RNSScreenStackPresentation)
1427
+ RCT_EXPORT_VIEW_PROPERTY(stackAnimation, RNSScreenStackAnimation)
1428
+ RCT_EXPORT_VIEW_PROPERTY(swipeDirection, RNSScreenSwipeDirection)
1429
+ RCT_EXPORT_VIEW_PROPERTY(transitionDuration, NSNumber)
1430
+
1431
+ RCT_EXPORT_VIEW_PROPERTY(onAppear, RCTDirectEventBlock);
1432
+ RCT_EXPORT_VIEW_PROPERTY(onDisappear, RCTDirectEventBlock);
1433
+ RCT_EXPORT_VIEW_PROPERTY(onHeaderHeightChange, RCTDirectEventBlock);
1434
+ RCT_EXPORT_VIEW_PROPERTY(onDismissed, RCTDirectEventBlock);
1435
+ RCT_EXPORT_VIEW_PROPERTY(onNativeDismissCancelled, RCTDirectEventBlock);
1436
+ RCT_EXPORT_VIEW_PROPERTY(onTransitionProgress, RCTDirectEventBlock);
1437
+ RCT_EXPORT_VIEW_PROPERTY(onWillAppear, RCTDirectEventBlock);
1438
+ RCT_EXPORT_VIEW_PROPERTY(onWillDisappear, RCTDirectEventBlock);
1439
+ RCT_EXPORT_VIEW_PROPERTY(onGestureCancel, RCTDirectEventBlock);
1440
+
1441
+ #if !TARGET_OS_TV
1442
+ RCT_EXPORT_VIEW_PROPERTY(screenOrientation, UIInterfaceOrientationMask)
1443
+ RCT_EXPORT_VIEW_PROPERTY(statusBarAnimation, UIStatusBarAnimation)
1444
+ RCT_EXPORT_VIEW_PROPERTY(statusBarHidden, BOOL)
1445
+ RCT_EXPORT_VIEW_PROPERTY(statusBarStyle, RNSStatusBarStyle)
1446
+ RCT_EXPORT_VIEW_PROPERTY(homeIndicatorHidden, BOOL)
1447
+
1448
+ RCT_EXPORT_VIEW_PROPERTY(sheetAllowedDetents, RNSScreenDetentType);
1449
+ RCT_EXPORT_VIEW_PROPERTY(sheetLargestUndimmedDetent, RNSScreenDetentType);
1450
+ RCT_EXPORT_VIEW_PROPERTY(sheetGrabberVisible, BOOL);
1451
+ RCT_EXPORT_VIEW_PROPERTY(sheetCornerRadius, CGFloat);
1452
+ RCT_EXPORT_VIEW_PROPERTY(sheetExpandsWhenScrolledToEdge, BOOL);
1453
+ #endif
1454
+
1455
+ #if !TARGET_OS_TV
1456
+ // See:
1457
+ // 1. https://github.com/software-mansion/react-native-screens/pull/1543
1458
+ // 2. https://github.com/software-mansion/react-native-screens/pull/1596
1459
+ // This class is instatiated from React Native's internals during application startup
1460
+ - (instancetype)init
1461
+ {
1462
+ if (self = [super init]) {
1463
+ dispatch_async(dispatch_get_main_queue(), ^{
1464
+ [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
1465
+ });
1466
+ }
1467
+ return self;
1468
+ }
1469
+
1470
+ - (void)dealloc
1471
+ {
1472
+ dispatch_sync(dispatch_get_main_queue(), ^{
1473
+ [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
1474
+ });
1475
+ }
1476
+ #endif // !TARGET_OS_TV
1477
+
1478
+ - (UIView *)view
1479
+ {
1480
+ return [[RNSScreenView alloc] initWithBridge:self.bridge];
1481
+ }
1482
+
1483
+ + (BOOL)requiresMainQueueSetup
1484
+ {
1485
+ // Returning NO here despite the fact some initialization in -init method dispatches tasks
1486
+ // on main queue, because the comments in RN source code states that modules which return YES
1487
+ // here will be constructed ahead-of-time -- and this is not required in our case.
1488
+ return NO;
1489
+ }
1490
+
1491
+ @end
1492
+
1493
+ @implementation RCTConvert (RNSScreen)
1494
+
1495
+ RCT_ENUM_CONVERTER(
1496
+ RNSScreenStackPresentation,
1497
+ (@{
1498
+ @"push" : @(RNSScreenStackPresentationPush),
1499
+ @"modal" : @(RNSScreenStackPresentationModal),
1500
+ @"fullScreenModal" : @(RNSScreenStackPresentationFullScreenModal),
1501
+ @"formSheet" : @(RNSScreenStackPresentationFormSheet),
1502
+ @"containedModal" : @(RNSScreenStackPresentationContainedModal),
1503
+ @"transparentModal" : @(RNSScreenStackPresentationTransparentModal),
1504
+ @"containedTransparentModal" : @(RNSScreenStackPresentationContainedTransparentModal)
1505
+ }),
1506
+ RNSScreenStackPresentationPush,
1507
+ integerValue)
1508
+
1509
+ RCT_ENUM_CONVERTER(
1510
+ RNSScreenStackAnimation,
1511
+ (@{
1512
+ @"default" : @(RNSScreenStackAnimationDefault),
1513
+ @"none" : @(RNSScreenStackAnimationNone),
1514
+ @"fade" : @(RNSScreenStackAnimationFade),
1515
+ @"fade_from_bottom" : @(RNSScreenStackAnimationFadeFromBottom),
1516
+ @"flip" : @(RNSScreenStackAnimationFlip),
1517
+ @"simple_push" : @(RNSScreenStackAnimationSimplePush),
1518
+ @"slide_from_bottom" : @(RNSScreenStackAnimationSlideFromBottom),
1519
+ @"slide_from_right" : @(RNSScreenStackAnimationDefault),
1520
+ @"slide_from_left" : @(RNSScreenStackAnimationDefault),
1521
+ }),
1522
+ RNSScreenStackAnimationDefault,
1523
+ integerValue)
1524
+
1525
+ RCT_ENUM_CONVERTER(
1526
+ RNSScreenReplaceAnimation,
1527
+ (@{
1528
+ @"push" : @(RNSScreenReplaceAnimationPush),
1529
+ @"pop" : @(RNSScreenReplaceAnimationPop),
1530
+ }),
1531
+ RNSScreenReplaceAnimationPop,
1532
+ integerValue)
1533
+
1534
+ RCT_ENUM_CONVERTER(
1535
+ RNSScreenSwipeDirection,
1536
+ (@{
1537
+ @"vertical" : @(RNSScreenSwipeDirectionVertical),
1538
+ @"horizontal" : @(RNSScreenSwipeDirectionHorizontal),
1539
+ }),
1540
+ RNSScreenSwipeDirectionHorizontal,
1541
+ integerValue)
1542
+
1543
+ #if !TARGET_OS_TV
1544
+ RCT_ENUM_CONVERTER(
1545
+ UIStatusBarAnimation,
1546
+ (@{
1547
+ @"none" : @(UIStatusBarAnimationNone),
1548
+ @"fade" : @(UIStatusBarAnimationFade),
1549
+ @"slide" : @(UIStatusBarAnimationSlide)
1550
+ }),
1551
+ UIStatusBarAnimationNone,
1552
+ integerValue)
1553
+
1554
+ RCT_ENUM_CONVERTER(
1555
+ RNSStatusBarStyle,
1556
+ (@{
1557
+ @"auto" : @(RNSStatusBarStyleAuto),
1558
+ @"inverted" : @(RNSStatusBarStyleInverted),
1559
+ @"light" : @(RNSStatusBarStyleLight),
1560
+ @"dark" : @(RNSStatusBarStyleDark),
1561
+ }),
1562
+ RNSStatusBarStyleAuto,
1563
+ integerValue)
1564
+
1565
+ RCT_ENUM_CONVERTER(
1566
+ RNSScreenDetentType,
1567
+ (@{
1568
+ @"large" : @(RNSScreenDetentTypeLarge),
1569
+ @"medium" : @(RNSScreenDetentTypeMedium),
1570
+ @"all" : @(RNSScreenDetentTypeAll),
1571
+ }),
1572
+ RNSScreenDetentTypeAll,
1573
+ integerValue)
1574
+
1575
+ + (UIInterfaceOrientationMask)UIInterfaceOrientationMask:(id)json
1576
+ {
1577
+ json = [self NSString:json];
1578
+ if ([json isEqualToString:@"default"]) {
1579
+ return UIInterfaceOrientationMaskAllButUpsideDown;
1580
+ } else if ([json isEqualToString:@"all"]) {
1581
+ return UIInterfaceOrientationMaskAll;
1582
+ } else if ([json isEqualToString:@"portrait"]) {
1583
+ return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
1584
+ } else if ([json isEqualToString:@"portrait_up"]) {
1585
+ return UIInterfaceOrientationMaskPortrait;
1586
+ } else if ([json isEqualToString:@"portrait_down"]) {
1587
+ return UIInterfaceOrientationMaskPortraitUpsideDown;
1588
+ } else if ([json isEqualToString:@"landscape"]) {
1589
+ return UIInterfaceOrientationMaskLandscape;
1590
+ } else if ([json isEqualToString:@"landscape_left"]) {
1591
+ return UIInterfaceOrientationMaskLandscapeLeft;
1592
+ } else if ([json isEqualToString:@"landscape_right"]) {
1593
+ return UIInterfaceOrientationMaskLandscapeRight;
1594
+ }
1595
+ return UIInterfaceOrientationMaskAllButUpsideDown;
1596
+ }
1597
+ #endif
1598
+
1599
+ @end