@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,1111 @@
1
+ #ifdef RCT_NEW_ARCH_ENABLED
2
+ #import <React/RCTFabricComponentsPlugins.h>
3
+ #import <React/RCTMountingTransactionObserving.h>
4
+ #import <React/RCTSurfaceTouchHandler.h>
5
+ #import <React/UIView+React.h>
6
+ #import <react/renderer/components/rnscreens/ComponentDescriptors.h>
7
+ #import <react/renderer/components/rnscreens/EventEmitters.h>
8
+ #import <react/renderer/components/rnscreens/Props.h>
9
+ #import <react/renderer/components/rnscreens/RCTComponentViewHelpers.h>
10
+ #else
11
+ #import <React/RCTBridge.h>
12
+ #import <React/RCTRootContentView.h>
13
+ #import <React/RCTShadowView.h>
14
+ #import <React/RCTTouchHandler.h>
15
+ #import <React/RCTUIManager.h>
16
+ #import <React/RCTUIManagerUtils.h>
17
+ #endif // RCT_NEW_ARCH_ENABLED
18
+
19
+ #import "RNSScreen.h"
20
+ #import "RNSScreenStack.h"
21
+ #import "RNSScreenStackAnimator.h"
22
+ #import "RNSScreenStackHeaderConfig.h"
23
+ #import "RNSScreenWindowTraits.h"
24
+
25
+ #ifdef RCT_NEW_ARCH_ENABLED
26
+ namespace react = facebook::react;
27
+ #endif // RCT_NEW_ARCH_ENABLED
28
+
29
+ @interface RNSScreenStackView () <
30
+ UINavigationControllerDelegate,
31
+ UIAdaptivePresentationControllerDelegate,
32
+ UIGestureRecognizerDelegate,
33
+ UIViewControllerTransitioningDelegate
34
+ #ifdef RCT_NEW_ARCH_ENABLED
35
+ ,
36
+ RCTMountingTransactionObserving
37
+ #endif
38
+ >
39
+
40
+ @property (nonatomic) NSMutableArray<UIViewController *> *presentedModals;
41
+ @property (nonatomic) BOOL updatingModals;
42
+ @property (nonatomic) BOOL scheduleModalsUpdate;
43
+
44
+ @end
45
+
46
+ @implementation RNSNavigationController
47
+
48
+ #if !TARGET_OS_TV
49
+ - (UIViewController *)childViewControllerForStatusBarStyle
50
+ {
51
+ return [self topViewController];
52
+ }
53
+
54
+ - (UIStatusBarAnimation)preferredStatusBarUpdateAnimation
55
+ {
56
+ return [self topViewController].preferredStatusBarUpdateAnimation;
57
+ }
58
+
59
+ - (UIViewController *)childViewControllerForStatusBarHidden
60
+ {
61
+ return [self topViewController];
62
+ }
63
+
64
+ - (void)viewDidLayoutSubviews
65
+ {
66
+ [super viewDidLayoutSubviews];
67
+ if ([self.topViewController isKindOfClass:[RNSScreen class]]) {
68
+ RNSScreen *screenController = (RNSScreen *)self.topViewController;
69
+
70
+ // Calculate header height during simple transition from one screen to another.
71
+ // If RNSScreen includes a navigation controller of type RNSNavigationController, it should not calculate
72
+ // header height, as it could have nested stack.
73
+ if (![screenController hasNestedStack]) {
74
+ [(RNSScreen *)self.topViewController calculateAndNotifyHeaderHeightChangeIsModal:NO];
75
+ }
76
+ }
77
+ }
78
+
79
+ - (UIInterfaceOrientationMask)supportedInterfaceOrientations
80
+ {
81
+ return [self topViewController].supportedInterfaceOrientations;
82
+ }
83
+
84
+ - (UIViewController *)childViewControllerForHomeIndicatorAutoHidden
85
+ {
86
+ return [self topViewController];
87
+ }
88
+ #endif
89
+
90
+ @end
91
+
92
+ #if !TARGET_OS_TV
93
+ @interface RNSScreenEdgeGestureRecognizer : UIScreenEdgePanGestureRecognizer
94
+ @end
95
+
96
+ @implementation RNSScreenEdgeGestureRecognizer
97
+ @end
98
+
99
+ @interface RNSPanGestureRecognizer : UIPanGestureRecognizer
100
+ @end
101
+
102
+ @implementation RNSPanGestureRecognizer
103
+ @end
104
+ #endif
105
+
106
+ @implementation RNSScreenStackView {
107
+ UINavigationController *_controller;
108
+ NSMutableArray<RNSScreenView *> *_reactSubviews;
109
+ BOOL _invalidated;
110
+ BOOL _isFullWidthSwiping;
111
+ UIPercentDrivenInteractiveTransition *_interactionController;
112
+ BOOL _hasLayout;
113
+ __weak RNSScreenStackManager *_manager;
114
+ BOOL _updateScheduled;
115
+ #ifdef RCT_NEW_ARCH_ENABLED
116
+ UIView *_snapshot;
117
+ #endif
118
+ }
119
+
120
+ #ifdef RCT_NEW_ARCH_ENABLED
121
+ - (instancetype)initWithFrame:(CGRect)frame
122
+ {
123
+ if (self = [super initWithFrame:frame]) {
124
+ static const auto defaultProps = std::make_shared<const react::RNSScreenStackProps>();
125
+ _props = defaultProps;
126
+ [self initCommonProps];
127
+ }
128
+
129
+ return self;
130
+ }
131
+ #endif // RCT_NEW_ARCH_ENABLED
132
+
133
+ - (instancetype)initWithManager:(RNSScreenStackManager *)manager
134
+ {
135
+ if (self = [super init]) {
136
+ _hasLayout = NO;
137
+ _invalidated = NO;
138
+ _manager = manager;
139
+ [self initCommonProps];
140
+ }
141
+ return self;
142
+ }
143
+
144
+ - (void)initCommonProps
145
+ {
146
+ _reactSubviews = [NSMutableArray new];
147
+ _presentedModals = [NSMutableArray new];
148
+ _controller = [RNSNavigationController new];
149
+ _controller.delegate = self;
150
+ #if !TARGET_OS_TV
151
+ [self setupGestureHandlers];
152
+ #endif
153
+ // we have to initialize viewControllers with a non empty array for
154
+ // largeTitle header to render in the opened state. If it is empty
155
+ // the header will render in collapsed state which is perhaps a bug
156
+ // in UIKit but ¯\_(ツ)_/¯
157
+ [_controller setViewControllers:@[ [UIViewController new] ]];
158
+ }
159
+
160
+ #pragma mark - helper methods
161
+
162
+ - (BOOL)shouldCancelDismissFromView:(RNSScreenView *)fromView toView:(RNSScreenView *)toView
163
+ {
164
+ int fromIndex = (int)[_reactSubviews indexOfObject:fromView];
165
+ int toIndex = (int)[_reactSubviews indexOfObject:toView];
166
+ for (int i = fromIndex; i > toIndex; i--) {
167
+ if (_reactSubviews[i].preventNativeDismiss) {
168
+ return YES;
169
+ break;
170
+ }
171
+ }
172
+ return NO;
173
+ }
174
+
175
+ #pragma mark - Common
176
+
177
+ - (void)emitOnFinishTransitioningEvent
178
+ {
179
+ #ifdef RCT_NEW_ARCH_ENABLED
180
+ if (_eventEmitter != nullptr) {
181
+ std::dynamic_pointer_cast<const react::RNSScreenStackEventEmitter>(_eventEmitter)
182
+ ->onFinishTransitioning(react::RNSScreenStackEventEmitter::OnFinishTransitioning{});
183
+ }
184
+ #else
185
+ if (self.onFinishTransitioning) {
186
+ self.onFinishTransitioning(nil);
187
+ }
188
+ #endif
189
+ }
190
+
191
+ - (void)navigationController:(UINavigationController *)navigationController
192
+ willShowViewController:(UIViewController *)viewController
193
+ animated:(BOOL)animated
194
+ {
195
+ UIView *view = viewController.view;
196
+ #ifdef RCT_NEW_ARCH_ENABLED
197
+ if (![view isKindOfClass:[RNSScreenView class]]) {
198
+ // if the current view is a snapshot, config was already removed so we don't trigger the method
199
+ return;
200
+ }
201
+ #endif
202
+ RNSScreenStackHeaderConfig *config = nil;
203
+ for (UIView *subview in view.reactSubviews) {
204
+ if ([subview isKindOfClass:[RNSScreenStackHeaderConfig class]]) {
205
+ config = (RNSScreenStackHeaderConfig *)subview;
206
+ break;
207
+ }
208
+ }
209
+ [RNSScreenStackHeaderConfig willShowViewController:viewController animated:animated withConfig:config];
210
+ }
211
+
212
+ - (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController
213
+ {
214
+ // We don't directly set presentation delegate but instead rely on the ScreenView's delegate to
215
+ // forward certain calls to the container (Stack).
216
+ if ([presentationController.presentedViewController isKindOfClass:[RNSScreen class]]) {
217
+ // we trigger the update of status bar's appearance here because there is no other lifecycle method
218
+ // that can handle it when dismissing a modal, the same for orientation
219
+ [RNSScreenWindowTraits updateWindowTraits];
220
+ [_presentedModals removeObject:presentationController.presentedViewController];
221
+
222
+ _updatingModals = NO;
223
+ #ifdef RCT_NEW_ARCH_ENABLED
224
+ [self emitOnFinishTransitioningEvent];
225
+ #else
226
+ // we double check if there are no new controllers pending to be presented since someone could
227
+ // have tried to push another one during the transition.
228
+ // We don't do it on Fabric since update of container will be triggered from "unmount" method afterwards
229
+ [self updateContainer];
230
+ if (self.onFinishTransitioning) {
231
+ // instead of directly triggering onFinishTransitioning this time we enqueue the event on the
232
+ // main queue. We do that because onDismiss event is also enqueued and we want for the transition
233
+ // finish event to arrive later than onDismiss (see RNSScreen#notifyDismiss)
234
+ dispatch_async(dispatch_get_main_queue(), ^{
235
+ [self emitOnFinishTransitioningEvent];
236
+ });
237
+ }
238
+ #endif
239
+ }
240
+ }
241
+
242
+ - (NSArray<UIView *> *)reactSubviews
243
+ {
244
+ return _reactSubviews;
245
+ }
246
+
247
+ - (void)didMoveToWindow
248
+ {
249
+ [super didMoveToWindow];
250
+ #ifdef RCT_NEW_ARCH_ENABLED
251
+ // for handling nested stacks
252
+ [self maybeAddToParentAndUpdateContainer];
253
+ #else
254
+ if (!_invalidated) {
255
+ // We check whether the view has been invalidated before running side-effects in didMoveToWindow
256
+ // This is needed because when LayoutAnimations are used it is possible for view to be re-attached
257
+ // to a window despite the fact it has been removed from the React Native view hierarchy.
258
+ [self maybeAddToParentAndUpdateContainer];
259
+ }
260
+ #endif
261
+ }
262
+
263
+ - (void)maybeAddToParentAndUpdateContainer
264
+ {
265
+ BOOL wasScreenMounted = _controller.parentViewController != nil;
266
+ #ifdef RCT_NEW_ARCH_ENABLED
267
+ BOOL isScreenReadyForShowing = self.window;
268
+ #else
269
+ BOOL isScreenReadyForShowing = self.window && _hasLayout;
270
+ #endif
271
+ if (!isScreenReadyForShowing && !wasScreenMounted) {
272
+ // We wait with adding to parent controller until the stack is mounted and has its initial
273
+ // layout done.
274
+ // If we add it before layout, some of the items (specifically items from the navigation bar),
275
+ // won't be able to position properly. Also the position and size of such items, even if it
276
+ // happens to change, won't be properly updated (this is perhaps some internal issue of UIKit).
277
+ // If we add it when window is not attached, some of the view transitions will be bloced (i.e.
278
+ // modal transitions) and the internal view controler's state will get out of sync with what's
279
+ // on screen without us knowing.
280
+ return;
281
+ }
282
+ [self updateContainer];
283
+ if (!wasScreenMounted) {
284
+ // when stack hasn't been added to parent VC yet we do two things:
285
+ // 1) we run updateContainer (the one above) – we do this because we want push view controllers to
286
+ // be installed before the VC is mounted. If we do that after it is added to parent the push
287
+ // updates operations are going to be blocked by UIKit.
288
+ // 2) we add navigation VS to parent – this is needed for the VC lifecycle events to be dispatched
289
+ // properly
290
+ // 3) we again call updateContainer – this time we do this to open modal controllers. Modals
291
+ // won't open in (1) because they require navigator to be added to parent. We handle that case
292
+ // gracefully in setModalViewControllers and can retry opening at any point.
293
+ [self reactAddControllerToClosestParent:_controller];
294
+ [self updateContainer];
295
+ }
296
+ }
297
+
298
+ - (void)reactAddControllerToClosestParent:(UIViewController *)controller
299
+ {
300
+ if (!controller.parentViewController) {
301
+ UIView *parentView = (UIView *)self.reactSuperview;
302
+ while (parentView) {
303
+ if (parentView.reactViewController) {
304
+ [parentView.reactViewController addChildViewController:controller];
305
+ [self addSubview:controller.view];
306
+ #if !TARGET_OS_TV
307
+ _controller.interactivePopGestureRecognizer.delegate = self;
308
+ #endif
309
+ [controller didMoveToParentViewController:parentView.reactViewController];
310
+ // On iOS pre 12 we observed that `willShowViewController` delegate method does not always
311
+ // get triggered when the navigation controller is instantiated. As the only thing we do in
312
+ // that delegate method is ask nav header to update to the current state it does not hurt to
313
+ // trigger that logic from here too such that we can be sure the header is properly updated.
314
+ [self navigationController:_controller willShowViewController:_controller.topViewController animated:NO];
315
+ break;
316
+ }
317
+ parentView = (UIView *)parentView.reactSuperview;
318
+ }
319
+ return;
320
+ }
321
+ }
322
+
323
+ - (void)setModalViewControllers:(NSArray<UIViewController *> *)controllers
324
+ {
325
+ // prevent re-entry
326
+ if (_updatingModals) {
327
+ _scheduleModalsUpdate = YES;
328
+ return;
329
+ }
330
+
331
+ // when there is no change we return immediately. This check is important because sometime we may
332
+ // accidently trigger modal dismiss if we don't verify to run the below code only when an actual
333
+ // change in the list of presented modal was made.
334
+ if ([_presentedModals isEqualToArray:controllers]) {
335
+ return;
336
+ }
337
+
338
+ // if view controller is not yet attached to window we skip updates now and run them when view
339
+ // is attached
340
+ if (self.window == nil && _presentedModals.lastObject.view.window == nil) {
341
+ return;
342
+ }
343
+
344
+ _updatingModals = YES;
345
+
346
+ NSMutableArray<UIViewController *> *newControllers = [NSMutableArray arrayWithArray:controllers];
347
+ [newControllers removeObjectsInArray:_presentedModals];
348
+
349
+ // find bottom-most controller that should stay on the stack for the duration of transition
350
+ NSUInteger changeRootIndex = 0;
351
+ UIViewController *changeRootController = _controller;
352
+ for (NSUInteger i = 0; i < MIN(_presentedModals.count, controllers.count); i++) {
353
+ if (_presentedModals[i] == controllers[i]) {
354
+ changeRootController = controllers[i];
355
+ changeRootIndex = i + 1;
356
+ } else {
357
+ break;
358
+ }
359
+ }
360
+
361
+ // we verify that controllers added on top of changeRootIndex are all new. Unfortunately modal
362
+ // VCs cannot be reshuffled (there are some visual glitches when we try to dismiss then show as
363
+ // even non-animated dismissal has delay and updates the screen several times)
364
+ for (NSUInteger i = changeRootIndex; i < controllers.count; i++) {
365
+ if ([_presentedModals containsObject:controllers[i]]) {
366
+ RCTAssert(false, @"Modally presented controllers are being reshuffled, this is not allowed");
367
+ }
368
+ }
369
+
370
+ __weak RNSScreenStackView *weakSelf = self;
371
+
372
+ void (^afterTransitions)(void) = ^{
373
+ [weakSelf emitOnFinishTransitioningEvent];
374
+ weakSelf.updatingModals = NO;
375
+ if (weakSelf.scheduleModalsUpdate) {
376
+ // if modals update was requested during setModalViewControllers we set scheduleModalsUpdate
377
+ // flag in order to perform updates at a later point. Here we are done with all modals
378
+ // transitions and check this flag again. If it was set, we reset the flag and execute updates.
379
+ weakSelf.scheduleModalsUpdate = NO;
380
+ [weakSelf updateContainer];
381
+ }
382
+ // we trigger the update of orientation here because, when dismissing the modal from JS,
383
+ // neither `viewWillAppear` nor `presentationControllerDidDismiss` are called, same for status bar.
384
+ [RNSScreenWindowTraits updateWindowTraits];
385
+ };
386
+
387
+ void (^finish)(void) = ^{
388
+ NSUInteger oldCount = weakSelf.presentedModals.count;
389
+ if (changeRootIndex < oldCount) {
390
+ [weakSelf.presentedModals removeObjectsInRange:NSMakeRange(changeRootIndex, oldCount - changeRootIndex)];
391
+ }
392
+ BOOL isAttached =
393
+ changeRootController.parentViewController != nil || changeRootController.presentingViewController != nil;
394
+ if (!isAttached || changeRootIndex >= controllers.count) {
395
+ // if change controller view is not attached, presenting modals will silently fail on iOS.
396
+ // In such a case we trigger controllers update from didMoveToWindow.
397
+ // We also don't run any present transitions if changeRootIndex is greater or equal to the size
398
+ // of new controllers array. This means that no new controllers should be presented.
399
+ afterTransitions();
400
+ return;
401
+ } else {
402
+ UIViewController *previous = changeRootController;
403
+ for (NSUInteger i = changeRootIndex; i < controllers.count; i++) {
404
+ UIViewController *next = controllers[i];
405
+ BOOL lastModal = (i == controllers.count - 1);
406
+
407
+ #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
408
+ __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
409
+ if (@available(iOS 13.0, tvOS 13.0, *)) {
410
+ // Inherit UI style from its parent - solves an issue with incorrect style being applied to some UIKit views
411
+ // like date picker or segmented control.
412
+ next.overrideUserInterfaceStyle = self->_controller.overrideUserInterfaceStyle;
413
+ }
414
+ #endif
415
+
416
+ BOOL shouldAnimate = lastModal && [next isKindOfClass:[RNSScreen class]] &&
417
+ ((RNSScreen *)next).screenView.stackAnimation != RNSScreenStackAnimationNone;
418
+
419
+ // if you want to present another modal quick enough after dismissing the previous one,
420
+ // it will result in wrong changeRootController, see repro in
421
+ // https://github.com/software-mansion/react-native-screens/issues/1299 We call `updateContainer` again in
422
+ // `presentationControllerDidDismiss` to cover this case and present new controller
423
+ if (previous.beingDismissed) {
424
+ return;
425
+ }
426
+
427
+ [previous presentViewController:next
428
+ animated:shouldAnimate
429
+ completion:^{
430
+ [weakSelf.presentedModals addObject:next];
431
+ if (lastModal) {
432
+ afterTransitions();
433
+ };
434
+ }];
435
+ previous = next;
436
+ }
437
+ }
438
+ };
439
+
440
+ if (changeRootController.presentedViewController != nil &&
441
+ [_presentedModals containsObject:changeRootController.presentedViewController]) {
442
+ BOOL shouldAnimate = changeRootIndex == controllers.count &&
443
+ [changeRootController.presentedViewController isKindOfClass:[RNSScreen class]] &&
444
+ ((RNSScreen *)changeRootController.presentedViewController).screenView.stackAnimation !=
445
+ RNSScreenStackAnimationNone;
446
+ [changeRootController dismissViewControllerAnimated:shouldAnimate completion:finish];
447
+ } else {
448
+ finish();
449
+ }
450
+ }
451
+
452
+ - (void)setPushViewControllers:(NSArray<UIViewController *> *)controllers
453
+ {
454
+ // when there is no change we return immediately
455
+ if ([_controller.viewControllers isEqualToArray:controllers]) {
456
+ return;
457
+ }
458
+
459
+ // if view controller is not yet attached to window we skip updates now and run them when view
460
+ // is attached
461
+ if (self.window == nil) {
462
+ return;
463
+ }
464
+ // when transition is ongoing, any updates made to the controller will not be reflected until the
465
+ // transition is complete. In particular, when we push/pop view controllers we expect viewControllers
466
+ // property to be updated immediately. Based on that property we then calculate future updates.
467
+ // When the transition is ongoing the property won't be updated immediatly. We therefore avoid
468
+ // making any updated when transition is ongoing and schedule updates for when the transition
469
+ // is complete.
470
+ if (_controller.transitionCoordinator != nil) {
471
+ if (!_updateScheduled) {
472
+ _updateScheduled = YES;
473
+ __weak RNSScreenStackView *weakSelf = self;
474
+ [_controller.transitionCoordinator
475
+ animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
476
+ // do nothing here, we only want to be notified when transition is complete
477
+ }
478
+ completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
479
+ self->_updateScheduled = NO;
480
+ [weakSelf updateContainer];
481
+ }];
482
+ }
483
+ return;
484
+ }
485
+
486
+ UIViewController *top = controllers.lastObject;
487
+ #ifdef RCT_NEW_ARCH_ENABLED
488
+ UIViewController *previousTop = _controller.topViewController;
489
+ #else
490
+ UIViewController *previousTop = _controller.viewControllers.lastObject;
491
+ #endif
492
+
493
+ // At the start we set viewControllers to contain a single UIViewController
494
+ // instance. This is a workaround for header height adjustment bug (see comment
495
+ // in the init function). Here, we need to detect if the initial empty
496
+ // controller is still there
497
+ BOOL firstTimePush = ![previousTop isKindOfClass:[RNSScreen class]];
498
+
499
+ if (firstTimePush) {
500
+ // nothing pushed yet
501
+ [_controller setViewControllers:controllers animated:NO];
502
+ } else if (top != previousTop) {
503
+ if (![controllers containsObject:previousTop]) {
504
+ // if the previous top screen does not exist anymore and the new top was not on the stack before, probably replace
505
+ // was called, so we check the animation
506
+ if (![_controller.viewControllers containsObject:top] &&
507
+ ((RNSScreenView *)top.view).replaceAnimation == RNSScreenReplaceAnimationPush) {
508
+ // setting new controllers with animation does `push` animation by default
509
+ #ifdef RCT_NEW_ARCH_ENABLED
510
+ auto screenController = (RNSScreen *)top;
511
+ [screenController resetViewToScreen];
512
+ #endif
513
+ [_controller setViewControllers:controllers animated:YES];
514
+ } else {
515
+ // last top controller is no longer on stack
516
+ // in this case we set the controllers stack to the new list with
517
+ // added the last top element to it and perform (animated) pop
518
+ NSMutableArray *newControllers = [NSMutableArray arrayWithArray:controllers];
519
+ [newControllers addObject:previousTop];
520
+ [_controller setViewControllers:newControllers animated:NO];
521
+ [_controller popViewControllerAnimated:YES];
522
+ }
523
+ } else if (![_controller.viewControllers containsObject:top]) {
524
+ // new top controller is not on the stack
525
+ // in such case we update the stack except from the last element with
526
+ // no animation and do animated push of the last item
527
+ NSMutableArray *newControllers = [NSMutableArray arrayWithArray:controllers];
528
+ [newControllers removeLastObject];
529
+ [_controller setViewControllers:newControllers animated:NO];
530
+ #ifdef RCT_NEW_ARCH_ENABLED
531
+ auto screenController = (RNSScreen *)top;
532
+ [screenController resetViewToScreen];
533
+ #endif
534
+ [_controller pushViewController:top animated:YES];
535
+ } else {
536
+ // don't really know what this case could be, but may need to handle it
537
+ // somehow
538
+ [_controller setViewControllers:controllers animated:NO];
539
+ }
540
+ } else {
541
+ // change wasn't on the top of the stack. We don't need animation.
542
+ [_controller setViewControllers:controllers animated:NO];
543
+ }
544
+ }
545
+
546
+ - (void)updateContainer
547
+ {
548
+ NSMutableArray<UIViewController *> *pushControllers = [NSMutableArray new];
549
+ NSMutableArray<UIViewController *> *modalControllers = [NSMutableArray new];
550
+ for (RNSScreenView *screen in _reactSubviews) {
551
+ if (!screen.dismissed && screen.controller != nil) {
552
+ if (pushControllers.count == 0) {
553
+ // first screen on the list needs to be places as "push controller"
554
+ [pushControllers addObject:screen.controller];
555
+ } else {
556
+ if (screen.stackPresentation == RNSScreenStackPresentationPush) {
557
+ [pushControllers addObject:screen.controller];
558
+ } else {
559
+ [modalControllers addObject:screen.controller];
560
+ }
561
+ }
562
+ }
563
+ }
564
+
565
+ [self setPushViewControllers:pushControllers];
566
+ [self setModalViewControllers:modalControllers];
567
+ }
568
+
569
+ - (void)layoutSubviews
570
+ {
571
+ [super layoutSubviews];
572
+ _controller.view.frame = self.bounds;
573
+ }
574
+
575
+ - (void)dismissOnReload
576
+ {
577
+ #ifdef RCT_NEW_ARCH_ENABLED
578
+ if ([_controller.visibleViewController isKindOfClass:[RNSScreen class]]) {
579
+ [(RNSScreen *)_controller.visibleViewController resetViewToScreen];
580
+ }
581
+ #else
582
+ dispatch_async(dispatch_get_main_queue(), ^{
583
+ [self invalidate];
584
+ });
585
+ #endif
586
+ }
587
+
588
+ #pragma mark methods connected to transitioning
589
+
590
+ - (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
591
+ animationControllerForOperation:(UINavigationControllerOperation)operation
592
+ fromViewController:(UIViewController *)fromVC
593
+ toViewController:(UIViewController *)toVC
594
+ {
595
+ RNSScreenView *screen;
596
+ if (operation == UINavigationControllerOperationPush) {
597
+ screen = ((RNSScreen *)toVC).screenView;
598
+ } else if (operation == UINavigationControllerOperationPop) {
599
+ screen = ((RNSScreen *)fromVC).screenView;
600
+ }
601
+ BOOL shouldCancelDismiss = [self shouldCancelDismissFromView:(RNSScreenView *)fromVC.view
602
+ toView:(RNSScreenView *)toVC.view];
603
+ if (screen != nil &&
604
+ // when preventing the native dismiss with back button, we have to return the animator.
605
+ // Also, we need to return the animator when full width swiping even if the animation is not custom,
606
+ // otherwise the screen will be just popped immediately due to no animation
607
+ ((operation == UINavigationControllerOperationPop && shouldCancelDismiss) || _isFullWidthSwiping ||
608
+ [RNSScreenStackAnimator isCustomAnimation:screen.stackAnimation])) {
609
+ return [[RNSScreenStackAnimator alloc] initWithOperation:operation];
610
+ }
611
+ return nil;
612
+ }
613
+
614
+ - (void)cancelTouchesInParent
615
+ {
616
+ // cancel touches in parent, this is needed to cancel RN touch events. For example when Touchable
617
+ // item is close to an edge and we start pulling from edge we want the Touchable to be cancelled.
618
+ // Without the below code the Touchable will remain active (highlighted) for the duration of back
619
+ // gesture and onPress may fire when we release the finger.
620
+ UIView *parent = _controller.view;
621
+ while (parent != nil && ![parent respondsToSelector:@selector(touchHandler)])
622
+ parent = parent.superview;
623
+ if (parent != nil) {
624
+ #ifdef RCT_NEW_ARCH_ENABLED
625
+ RCTSurfaceTouchHandler *touchHandler = [parent performSelector:@selector(touchHandler)];
626
+ #else
627
+ RCTTouchHandler *touchHandler = [parent performSelector:@selector(touchHandler)];
628
+ #endif
629
+ [touchHandler setEnabled:NO];
630
+ [touchHandler setEnabled:YES];
631
+ [touchHandler reset];
632
+ }
633
+ }
634
+
635
+ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
636
+ {
637
+ RNSScreenView *topScreen = _reactSubviews.lastObject;
638
+
639
+ #if TARGET_OS_TV
640
+ [self cancelTouchesInParent];
641
+ return YES;
642
+ #else
643
+ // RNSPanGestureRecognizer will receive events iff topScreen.fullScreenSwipeEnabled == YES;
644
+ // Events are filtered in gestureRecognizer:shouldReceivePressOrTouchEvent: method
645
+ if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) {
646
+ if ([self isInGestureResponseDistance:gestureRecognizer topScreen:topScreen]) {
647
+ _isFullWidthSwiping = YES;
648
+ [self cancelTouchesInParent];
649
+ return YES;
650
+ }
651
+ return NO;
652
+ }
653
+
654
+ // Now we're dealing with RNSScreenEdgeGestureRecognizer (or _UIParallaxTransitionPanGestureRecognizer)
655
+ if (topScreen.customAnimationOnSwipe && [RNSScreenStackAnimator isCustomAnimation:topScreen.stackAnimation]) {
656
+ if ([gestureRecognizer isKindOfClass:[RNSScreenEdgeGestureRecognizer class]]) {
657
+ // if we do not set any explicit `semanticContentAttribute`, it is `UISemanticContentAttributeUnspecified` instead
658
+ // of `UISemanticContentAttributeForceLeftToRight`, so we just check if it is RTL or not
659
+ BOOL isCorrectEdge = (_controller.view.semanticContentAttribute == UISemanticContentAttributeForceRightToLeft &&
660
+ ((RNSScreenEdgeGestureRecognizer *)gestureRecognizer).edges == UIRectEdgeRight) ||
661
+ (_controller.view.semanticContentAttribute != UISemanticContentAttributeForceRightToLeft &&
662
+ ((RNSScreenEdgeGestureRecognizer *)gestureRecognizer).edges == UIRectEdgeLeft);
663
+ if (isCorrectEdge) {
664
+ [self cancelTouchesInParent];
665
+ return YES;
666
+ }
667
+ }
668
+ return NO;
669
+ } else {
670
+ if ([gestureRecognizer isKindOfClass:[RNSScreenEdgeGestureRecognizer class]]) {
671
+ // it should only recognize with `customAnimationOnSwipe` set
672
+ return NO;
673
+ }
674
+ // _UIParallaxTransitionPanGestureRecognizer (other...)
675
+ [self cancelTouchesInParent];
676
+ return YES;
677
+ }
678
+
679
+ #endif // TARGET_OS_TV
680
+ }
681
+
682
+ #if !TARGET_OS_TV
683
+ - (void)setupGestureHandlers
684
+ {
685
+ // gesture recognizers for custom stack animations
686
+ RNSScreenEdgeGestureRecognizer *leftEdgeSwipeGestureRecognizer =
687
+ [[RNSScreenEdgeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipe:)];
688
+ leftEdgeSwipeGestureRecognizer.edges = UIRectEdgeLeft;
689
+ leftEdgeSwipeGestureRecognizer.delegate = self;
690
+ [self addGestureRecognizer:leftEdgeSwipeGestureRecognizer];
691
+
692
+ RNSScreenEdgeGestureRecognizer *rightEdgeSwipeGestureRecognizer =
693
+ [[RNSScreenEdgeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipe:)];
694
+ rightEdgeSwipeGestureRecognizer.edges = UIRectEdgeRight;
695
+ rightEdgeSwipeGestureRecognizer.delegate = self;
696
+ [self addGestureRecognizer:rightEdgeSwipeGestureRecognizer];
697
+
698
+ // gesture recognizer for full width swipe gesture
699
+ RNSPanGestureRecognizer *panRecognizer = [[RNSPanGestureRecognizer alloc] initWithTarget:self
700
+ action:@selector(handleSwipe:)];
701
+ panRecognizer.delegate = self;
702
+ [self addGestureRecognizer:panRecognizer];
703
+ }
704
+
705
+ - (void)handleSwipe:(UIPanGestureRecognizer *)gestureRecognizer
706
+ {
707
+ RNSScreenView *topScreen = _reactSubviews.lastObject;
708
+ float translation;
709
+ float velocity;
710
+ float distance;
711
+ if (topScreen.swipeDirection == RNSScreenSwipeDirectionVertical) {
712
+ translation = [gestureRecognizer translationInView:gestureRecognizer.view].y;
713
+ velocity = [gestureRecognizer velocityInView:gestureRecognizer.view].y;
714
+ distance = gestureRecognizer.view.bounds.size.height;
715
+ } else {
716
+ translation = [gestureRecognizer translationInView:gestureRecognizer.view].x;
717
+ velocity = [gestureRecognizer velocityInView:gestureRecognizer.view].x;
718
+ distance = gestureRecognizer.view.bounds.size.width;
719
+ BOOL isRTL = _controller.view.semanticContentAttribute == UISemanticContentAttributeForceRightToLeft;
720
+ if (isRTL) {
721
+ translation = -translation;
722
+ velocity = -velocity;
723
+ }
724
+ }
725
+
726
+ float transitionProgress = (translation / distance);
727
+
728
+ switch (gestureRecognizer.state) {
729
+ case UIGestureRecognizerStateBegan: {
730
+ _interactionController = [UIPercentDrivenInteractiveTransition new];
731
+ [_controller popViewControllerAnimated:YES];
732
+ break;
733
+ }
734
+
735
+ case UIGestureRecognizerStateChanged: {
736
+ [_interactionController updateInteractiveTransition:transitionProgress];
737
+ break;
738
+ }
739
+
740
+ case UIGestureRecognizerStateCancelled: {
741
+ [_interactionController cancelInteractiveTransition];
742
+ break;
743
+ }
744
+
745
+ case UIGestureRecognizerStateEnded: {
746
+ // values taken from
747
+ // https://github.com/react-navigation/react-navigation/blob/54739828598d7072c1bf7b369659e3682db3edc5/packages/stack/src/views/Stack/Card.tsx#L316
748
+ BOOL shouldFinishTransition = (translation + velocity * 0.3) > (distance / 2);
749
+ if (shouldFinishTransition) {
750
+ [_interactionController finishInteractiveTransition];
751
+ } else {
752
+ [_interactionController cancelInteractiveTransition];
753
+ }
754
+ _interactionController = nil;
755
+ }
756
+ default: {
757
+ break;
758
+ }
759
+ }
760
+ }
761
+
762
+ - (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
763
+ interactionControllerForAnimationController:
764
+ (id<UIViewControllerAnimatedTransitioning>)animationController
765
+ {
766
+ RNSScreenView *fromView = [_controller.transitionCoordinator viewForKey:UITransitionContextFromViewKey];
767
+ RNSScreenView *toView = [_controller.transitionCoordinator viewForKey:UITransitionContextToViewKey];
768
+ // we can intercept clicking back button here, we check reactSuperview since this method also fires when
769
+ // navigating back from JS
770
+ if (_interactionController == nil && fromView.reactSuperview) {
771
+ BOOL shouldCancelDismiss = [self shouldCancelDismissFromView:fromView toView:toView];
772
+ if (shouldCancelDismiss) {
773
+ _interactionController = [UIPercentDrivenInteractiveTransition new];
774
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
775
+ [self->_interactionController cancelInteractiveTransition];
776
+ self->_interactionController = nil;
777
+ int fromIndex = (int)[self->_reactSubviews indexOfObject:fromView];
778
+ int toIndex = (int)[self->_reactSubviews indexOfObject:toView];
779
+ int indexDiff = fromIndex - toIndex;
780
+ int dismissCount = indexDiff > 0 ? indexDiff : 1;
781
+ [self updateContainer];
782
+ [fromView notifyDismissCancelledWithDismissCount:dismissCount];
783
+ });
784
+ }
785
+ }
786
+ return _interactionController;
787
+ }
788
+
789
+ - (id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:
790
+ (id<UIViewControllerAnimatedTransitioning>)animator
791
+ {
792
+ return _interactionController;
793
+ }
794
+
795
+ - (void)navigationController:(UINavigationController *)navigationController
796
+ didShowViewController:(UIViewController *)viewController
797
+ animated:(BOOL)animated
798
+ {
799
+ [self emitOnFinishTransitioningEvent];
800
+ [RNSScreenWindowTraits updateWindowTraits];
801
+ }
802
+ #endif
803
+
804
+ - (void)markChildUpdated
805
+ {
806
+ // do nothing
807
+ }
808
+
809
+ - (void)didUpdateChildren
810
+ {
811
+ // do nothing
812
+ }
813
+
814
+ - (UIViewController *)reactViewController
815
+ {
816
+ return _controller;
817
+ }
818
+
819
+ - (BOOL)isInGestureResponseDistance:(UIGestureRecognizer *)gestureRecognizer topScreen:(RNSScreenView *)topScreen
820
+ {
821
+ NSDictionary *gestureResponseDistanceValues = topScreen.gestureResponseDistance;
822
+ float x = [gestureRecognizer locationInView:gestureRecognizer.view].x;
823
+ float y = [gestureRecognizer locationInView:gestureRecognizer.view].y;
824
+ BOOL isRTL = _controller.view.semanticContentAttribute == UISemanticContentAttributeForceRightToLeft;
825
+ if (isRTL) {
826
+ x = _controller.view.frame.size.width - x;
827
+ }
828
+
829
+ // see:
830
+ // https://github.com/software-mansion/react-native-screens/pull/1442/commits/74d4bae321875d8305ad021b3d448ebf713e7d56
831
+ // this prop is always default initialized so we do not expect any nils
832
+ float start = [gestureResponseDistanceValues[@"start"] floatValue];
833
+ float end = [gestureResponseDistanceValues[@"end"] floatValue];
834
+ float top = [gestureResponseDistanceValues[@"top"] floatValue];
835
+ float bottom = [gestureResponseDistanceValues[@"bottom"] floatValue];
836
+
837
+ // we check if any of the constraints are violated and return NO if so
838
+ return !(
839
+ (start != -1 && x < start) || (end != -1 && x > end) || (top != -1 && y < top) || (bottom != -1 && y > bottom));
840
+ }
841
+
842
+ // By default, the header buttons that are not inside the native hit area
843
+ // cannot be clicked, so we check it by ourselves
844
+ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
845
+ {
846
+ if (CGRectContainsPoint(_controller.navigationBar.frame, point)) {
847
+ // headerConfig should be the first subview of the topmost screen
848
+ UIView *headerConfig = [[_reactSubviews.lastObject reactSubviews] firstObject];
849
+ if ([headerConfig isKindOfClass:[RNSScreenStackHeaderConfig class]]) {
850
+ UIView *headerHitTestResult = [headerConfig hitTest:point withEvent:event];
851
+ if (headerHitTestResult != nil) {
852
+ return headerHitTestResult;
853
+ }
854
+ }
855
+ }
856
+ return [super hitTest:point withEvent:event];
857
+ }
858
+
859
+ #if !TARGET_OS_TV
860
+
861
+ - (BOOL)isScrollViewPanGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
862
+ {
863
+ // NOTE: This hack is required to restore native behavior of edge swipe (interactive pop gesture)
864
+ // without this, on a screen with a scroll view, it's only possible to pop view by panning horizontally
865
+ // if even slightly diagonal (or if in motion), scroll view will scroll, and edge swipe will be cancelled
866
+ if (![[gestureRecognizer view] isKindOfClass:[UIScrollView class]]) {
867
+ return NO;
868
+ }
869
+ UIScrollView *scrollView = (UIScrollView *)gestureRecognizer.view;
870
+ return scrollView.panGestureRecognizer == gestureRecognizer;
871
+ }
872
+
873
+ // Custom method for compatibility with iOS < 13.4
874
+ // RNSScreenStackView is a UIGestureRecognizerDelegate for three types of gesture recognizers:
875
+ // RNSPanGestureRecognizer, RNSScreenEdgeGestureRecognizer, _UIParallaxTransitionPanGestureRecognizer
876
+ // Be careful when adding another type of gesture recognizer.
877
+ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceivePressOrTouchEvent:(NSObject *)event
878
+ {
879
+ RNSScreenView *topScreen = _reactSubviews.lastObject;
880
+
881
+ if (![topScreen isKindOfClass:[RNSScreenView class]] || !topScreen.gestureEnabled ||
882
+ _controller.viewControllers.count < 2 || [topScreen isModal]) {
883
+ return NO;
884
+ }
885
+
886
+ // We want to pass events to RNSPanGestureRecognizer iff full screen swipe is enabled.
887
+ if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) {
888
+ return topScreen.fullScreenSwipeEnabled;
889
+ }
890
+
891
+ // RNSScreenEdgeGestureRecognizer || _UIParallaxTransitionPanGestureRecognizer
892
+ return YES;
893
+ }
894
+
895
+ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceivePress:(UIPress *)press;
896
+ {
897
+ return [self gestureRecognizer:gestureRecognizer shouldReceivePressOrTouchEvent:press];
898
+ }
899
+
900
+ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
901
+ {
902
+ return [self gestureRecognizer:gestureRecognizer shouldReceivePressOrTouchEvent:touch];
903
+ }
904
+
905
+ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
906
+ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
907
+ {
908
+ if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]] &&
909
+ [self isScrollViewPanGestureRecognizer:otherGestureRecognizer]) {
910
+ RNSPanGestureRecognizer *panGestureRecognizer = (RNSPanGestureRecognizer *)gestureRecognizer;
911
+ BOOL isBackGesture = [panGestureRecognizer translationInView:panGestureRecognizer.view].x > 0 &&
912
+ _controller.viewControllers.count > 1;
913
+
914
+ if (gestureRecognizer.state == UIGestureRecognizerStateBegan || isBackGesture) {
915
+ return NO;
916
+ }
917
+
918
+ return YES;
919
+ }
920
+ return NO;
921
+ }
922
+
923
+ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
924
+ shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
925
+ {
926
+ return (
927
+ [gestureRecognizer isKindOfClass:[UIScreenEdgePanGestureRecognizer class]] &&
928
+ [self isScrollViewPanGestureRecognizer:otherGestureRecognizer]);
929
+ }
930
+
931
+ #endif // !TARGET_OS_TV
932
+
933
+ - (void)insertReactSubview:(RNSScreenView *)subview atIndex:(NSInteger)atIndex
934
+ {
935
+ if (![subview isKindOfClass:[RNSScreenView class]]) {
936
+ RCTLogError(@"ScreenStack only accepts children of type Screen");
937
+ return;
938
+ }
939
+ subview.reactSuperview = self;
940
+ [_reactSubviews insertObject:subview atIndex:atIndex];
941
+ }
942
+
943
+ - (void)removeReactSubview:(RNSScreenView *)subview
944
+ {
945
+ subview.reactSuperview = nil;
946
+ [_reactSubviews removeObject:subview];
947
+ }
948
+
949
+ - (void)didUpdateReactSubviews
950
+ {
951
+ // we need to wait until children have their layout set. At this point they don't have the layout
952
+ // set yet, however the layout call is already enqueued on ui thread. Enqueuing update call on the
953
+ // ui queue will guarantee that the update will run after layout.
954
+ dispatch_async(dispatch_get_main_queue(), ^{
955
+ self->_hasLayout = YES;
956
+ [self maybeAddToParentAndUpdateContainer];
957
+ });
958
+ }
959
+
960
+ #ifdef RCT_NEW_ARCH_ENABLED
961
+ #pragma mark - Fabric specific
962
+
963
+ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
964
+ {
965
+ if (![childComponentView isKindOfClass:[RNSScreenView class]]) {
966
+ RCTLogError(@"ScreenStack only accepts children of type Screen");
967
+ return;
968
+ }
969
+
970
+ RCTAssert(
971
+ childComponentView.reactSuperview == nil,
972
+ @"Attempt to mount already mounted component view. (parent: %@, child: %@, index: %@, existing parent: %@)",
973
+ self,
974
+ childComponentView,
975
+ @(index),
976
+ @([childComponentView.superview tag]));
977
+
978
+ [_reactSubviews insertObject:(RNSScreenView *)childComponentView atIndex:index];
979
+ ((RNSScreenView *)childComponentView).reactSuperview = self;
980
+ dispatch_async(dispatch_get_main_queue(), ^{
981
+ [self maybeAddToParentAndUpdateContainer];
982
+ });
983
+ }
984
+
985
+ - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
986
+ {
987
+ RNSScreenView *screenChildComponent = (RNSScreenView *)childComponentView;
988
+ // We should only do a snapshot of a screen that is on the top.
989
+ // We also check `_presentedModals` since if you push 2 modals, second one is not a "child" of _controller.
990
+ // Also, when dissmised with a gesture, the screen already is not under the window, so we don't need to apply
991
+ // snapshot.
992
+ if (screenChildComponent.window != nil &&
993
+ ((screenChildComponent == _controller.visibleViewController.view && _presentedModals.count < 2) ||
994
+ screenChildComponent == [_presentedModals.lastObject view])) {
995
+ [screenChildComponent.controller setViewToSnapshot:_snapshot];
996
+ }
997
+
998
+ RCTAssert(
999
+ screenChildComponent.reactSuperview == self,
1000
+ @"Attempt to unmount a view which is mounted inside different view. (parent: %@, child: %@, index: %@)",
1001
+ self,
1002
+ screenChildComponent,
1003
+ @(index));
1004
+ RCTAssert(
1005
+ (_reactSubviews.count > index) && [_reactSubviews objectAtIndex:index] == childComponentView,
1006
+ @"Attempt to unmount a view which has a different index. (parent: %@, child: %@, index: %@, actual index: %@, tag at index: %@)",
1007
+ self,
1008
+ screenChildComponent,
1009
+ @(index),
1010
+ @([_reactSubviews indexOfObject:screenChildComponent]),
1011
+ @([[_reactSubviews objectAtIndex:index] tag]));
1012
+ screenChildComponent.reactSuperview = nil;
1013
+ [_reactSubviews removeObject:screenChildComponent];
1014
+ [screenChildComponent removeFromSuperview];
1015
+ dispatch_async(dispatch_get_main_queue(), ^{
1016
+ [self maybeAddToParentAndUpdateContainer];
1017
+ });
1018
+ }
1019
+
1020
+ - (void)takeSnapshot
1021
+ {
1022
+ _snapshot = [_controller.visibleViewController.view snapshotViewAfterScreenUpdates:NO];
1023
+ }
1024
+
1025
+ - (void)mountingTransactionWillMount:(react::MountingTransaction const &)transaction
1026
+ withSurfaceTelemetry:(react::SurfaceTelemetry const &)surfaceTelemetry
1027
+ {
1028
+ for (auto &mutation : transaction.getMutations()) {
1029
+ if (mutation.type == react::ShadowViewMutation::Type::Remove && mutation.parentShadowView.componentName != nil &&
1030
+ strcmp(mutation.parentShadowView.componentName, "RNSScreenStack") == 0) {
1031
+ [self takeSnapshot];
1032
+ return;
1033
+ }
1034
+ }
1035
+ }
1036
+
1037
+ - (void)prepareForRecycle
1038
+ {
1039
+ [super prepareForRecycle];
1040
+ _reactSubviews = [NSMutableArray new];
1041
+
1042
+ for (UIViewController *controller in _presentedModals) {
1043
+ [controller dismissViewControllerAnimated:NO completion:nil];
1044
+ }
1045
+
1046
+ [_presentedModals removeAllObjects];
1047
+ [self dismissOnReload];
1048
+ [_controller willMoveToParentViewController:nil];
1049
+ [_controller removeFromParentViewController];
1050
+ [_controller setViewControllers:@[ [UIViewController new] ]];
1051
+ }
1052
+
1053
+ + (react::ComponentDescriptorProvider)componentDescriptorProvider
1054
+ {
1055
+ return react::concreteComponentDescriptorProvider<react::RNSScreenStackComponentDescriptor>();
1056
+ }
1057
+ #else
1058
+ #pragma mark - Paper specific
1059
+
1060
+ - (void)invalidate
1061
+ {
1062
+ _invalidated = YES;
1063
+ for (UIViewController *controller in _presentedModals) {
1064
+ [controller dismissViewControllerAnimated:NO completion:nil];
1065
+ }
1066
+ [_presentedModals removeAllObjects];
1067
+ [_controller willMoveToParentViewController:nil];
1068
+ [_controller removeFromParentViewController];
1069
+ }
1070
+
1071
+ #endif // RCT_NEW_ARCH_ENABLED
1072
+
1073
+ @end
1074
+
1075
+ #ifdef RCT_NEW_ARCH_ENABLED
1076
+ Class<RCTComponentViewProtocol> RNSScreenStackCls(void)
1077
+ {
1078
+ return RNSScreenStackView.class;
1079
+ }
1080
+ #endif
1081
+
1082
+ @implementation RNSScreenStackManager {
1083
+ NSPointerArray *_stacks;
1084
+ }
1085
+
1086
+ RCT_EXPORT_MODULE()
1087
+
1088
+ RCT_EXPORT_VIEW_PROPERTY(onFinishTransitioning, RCTDirectEventBlock);
1089
+
1090
+ #ifdef RCT_NEW_ARCH_ENABLED
1091
+ #else
1092
+ - (UIView *)view
1093
+ {
1094
+ RNSScreenStackView *view = [[RNSScreenStackView alloc] initWithManager:self];
1095
+ if (!_stacks) {
1096
+ _stacks = [NSPointerArray weakObjectsPointerArray];
1097
+ }
1098
+ [_stacks addPointer:(__bridge void *)view];
1099
+ return view;
1100
+ }
1101
+ #endif // RCT_NEW_ARCH_ENABLED
1102
+
1103
+ - (void)invalidate
1104
+ {
1105
+ for (RNSScreenStackView *stack in _stacks) {
1106
+ [stack dismissOnReload];
1107
+ }
1108
+ _stacks = nil;
1109
+ }
1110
+
1111
+ @end