react-native-screens 4.0.0-beta.8 → 4.0.0

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 (271) hide show
  1. package/README.md +9 -2
  2. package/android/CMakeLists.txt +28 -19
  3. package/android/src/main/java/com/swmansion/rnscreens/CustomToolbar.kt +13 -3
  4. package/android/src/main/java/com/swmansion/rnscreens/InsetsObserverProxy.kt +2 -4
  5. package/android/src/main/java/com/swmansion/rnscreens/NativeDismissalObserver.kt +12 -0
  6. package/android/src/main/java/com/swmansion/rnscreens/Screen.kt +11 -4
  7. package/android/src/main/java/com/swmansion/rnscreens/ScreenStack.kt +24 -6
  8. package/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt +64 -68
  9. package/android/src/main/java/com/swmansion/rnscreens/ScreenWindowTraits.kt +1 -0
  10. package/android/src/main/java/com/swmansion/rnscreens/bottomsheet/BottomSheetBehaviorExt.kt +42 -0
  11. package/android/src/main/java/com/swmansion/rnscreens/bottomsheet/DimmingFragment.kt +24 -19
  12. package/android/src/main/java/com/swmansion/rnscreens/bottomsheet/SheetUtils.kt +8 -0
  13. package/android/src/main/java/com/swmansion/rnscreens/ext/ViewExt.kt +24 -0
  14. package/android/src/main/jni/CMakeLists.txt +28 -19
  15. package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenManagerDelegate.java +2 -2
  16. package/ios/RNSConvert.h +13 -4
  17. package/ios/RNSConvert.mm +50 -28
  18. package/ios/RNSEnums.h +47 -0
  19. package/ios/RNSPercentDrivenInteractiveTransition.h +12 -0
  20. package/ios/RNSPercentDrivenInteractiveTransition.mm +69 -0
  21. package/ios/RNSScreen.h +14 -0
  22. package/ios/RNSScreen.mm +30 -5
  23. package/ios/RNSScreenStack.mm +74 -9
  24. package/ios/RNSScreenStackAnimator.h +13 -1
  25. package/ios/RNSScreenStackAnimator.mm +233 -130
  26. package/ios/RNSScreenStackHeaderConfig.h +1 -1
  27. package/ios/RNSScreenStackHeaderConfig.mm +39 -29
  28. package/lib/commonjs/components/DebugContainer.js +40 -0
  29. package/lib/commonjs/components/DebugContainer.js.map +1 -0
  30. package/lib/commonjs/components/DebugContainer.web.js +15 -0
  31. package/lib/commonjs/components/DebugContainer.web.js.map +1 -0
  32. package/lib/commonjs/components/FullWindowOverlay.js +8 -5
  33. package/lib/commonjs/components/FullWindowOverlay.js.map +1 -1
  34. package/lib/commonjs/components/Screen.js +35 -10
  35. package/lib/commonjs/components/Screen.js.map +1 -1
  36. package/lib/commonjs/components/ScreenContainer.js +3 -5
  37. package/lib/commonjs/components/ScreenContainer.js.map +1 -1
  38. package/lib/commonjs/components/ScreenContainer.web.js +3 -4
  39. package/lib/commonjs/components/ScreenContainer.web.js.map +1 -1
  40. package/lib/commonjs/components/ScreenContentWrapper.js +2 -4
  41. package/lib/commonjs/components/ScreenContentWrapper.js.map +1 -1
  42. package/lib/commonjs/components/ScreenContentWrapper.web.js +1 -2
  43. package/lib/commonjs/components/ScreenContentWrapper.web.js.map +1 -1
  44. package/lib/commonjs/components/ScreenFooter.js +2 -8
  45. package/lib/commonjs/components/ScreenFooter.js.map +1 -1
  46. package/lib/commonjs/components/ScreenFooter.web.js +1 -2
  47. package/lib/commonjs/components/ScreenFooter.web.js.map +1 -1
  48. package/lib/commonjs/components/ScreenStack.js +47 -9
  49. package/lib/commonjs/components/ScreenStack.js.map +1 -1
  50. package/lib/commonjs/components/ScreenStack.web.js +2 -1
  51. package/lib/commonjs/components/ScreenStack.web.js.map +1 -1
  52. package/lib/commonjs/components/ScreenStackHeaderConfig.js +14 -10
  53. package/lib/commonjs/components/ScreenStackHeaderConfig.js.map +1 -1
  54. package/lib/commonjs/components/ScreenStackItem.js +99 -0
  55. package/lib/commonjs/components/ScreenStackItem.js.map +1 -0
  56. package/lib/commonjs/components/SearchBar.js +5 -5
  57. package/lib/commonjs/components/SearchBar.js.map +1 -1
  58. package/lib/commonjs/components/SearchBar.web.js +3 -4
  59. package/lib/commonjs/components/SearchBar.web.js.map +1 -1
  60. package/lib/commonjs/components/helpers/usePrevious.js +15 -0
  61. package/lib/commonjs/components/helpers/usePrevious.js.map +1 -0
  62. package/lib/commonjs/contexts.js +11 -0
  63. package/lib/commonjs/contexts.js.map +1 -0
  64. package/lib/commonjs/core.js +0 -3
  65. package/lib/commonjs/core.js.map +1 -1
  66. package/lib/commonjs/fabric/ModalScreenNativeComponent.js.map +1 -1
  67. package/lib/commonjs/fabric/ScreenStackHeaderConfigNativeComponent.js.map +1 -1
  68. package/lib/commonjs/gesture-handler/GestureDetectorProvider.js +2 -2
  69. package/lib/commonjs/gesture-handler/GestureDetectorProvider.js.map +1 -1
  70. package/lib/commonjs/gesture-handler/ScreenGestureDetector.js +3 -3
  71. package/lib/commonjs/gesture-handler/ScreenGestureDetector.js.map +1 -1
  72. package/lib/commonjs/gesture-handler/fabricUtils.js +54 -18
  73. package/lib/commonjs/gesture-handler/fabricUtils.js.map +1 -1
  74. package/lib/commonjs/index.js +23 -86
  75. package/lib/commonjs/index.js.map +1 -1
  76. package/lib/commonjs/native-stack/navigators/createNativeStackNavigator.js +4 -0
  77. package/lib/commonjs/native-stack/navigators/createNativeStackNavigator.js.map +1 -1
  78. package/lib/commonjs/native-stack/views/FooterComponent.js +2 -2
  79. package/lib/commonjs/native-stack/views/FooterComponent.js.map +1 -1
  80. package/lib/commonjs/native-stack/views/HeaderConfig.js +10 -8
  81. package/lib/commonjs/native-stack/views/HeaderConfig.js.map +1 -1
  82. package/lib/commonjs/native-stack/views/NativeStackView.js +34 -39
  83. package/lib/commonjs/native-stack/views/NativeStackView.js.map +1 -1
  84. package/lib/commonjs/reanimated/ReanimatedNativeStackScreen.js +2 -2
  85. package/lib/commonjs/reanimated/ReanimatedNativeStackScreen.js.map +1 -1
  86. package/lib/commonjs/reanimated/ReanimatedScreen.js +2 -2
  87. package/lib/commonjs/reanimated/ReanimatedScreen.js.map +1 -1
  88. package/lib/commonjs/reanimated/ReanimatedScreenProvider.js +2 -2
  89. package/lib/commonjs/reanimated/ReanimatedScreenProvider.js.map +1 -1
  90. package/lib/commonjs/utils.js +28 -6
  91. package/lib/commonjs/utils.js.map +1 -1
  92. package/lib/module/components/DebugContainer.js +31 -0
  93. package/lib/module/components/DebugContainer.js.map +1 -0
  94. package/lib/module/components/DebugContainer.web.js +6 -0
  95. package/lib/module/components/DebugContainer.web.js.map +1 -0
  96. package/lib/module/components/FullWindowOverlay.js +9 -6
  97. package/lib/module/components/FullWindowOverlay.js.map +1 -1
  98. package/lib/module/components/Screen.js +34 -9
  99. package/lib/module/components/Screen.js.map +1 -1
  100. package/lib/module/components/ScreenContainer.js +2 -4
  101. package/lib/module/components/ScreenContainer.js.map +1 -1
  102. package/lib/module/components/ScreenContainer.web.js +2 -3
  103. package/lib/module/components/ScreenContainer.web.js.map +1 -1
  104. package/lib/module/components/ScreenContentWrapper.js +1 -3
  105. package/lib/module/components/ScreenContentWrapper.js.map +1 -1
  106. package/lib/module/components/ScreenContentWrapper.web.js +0 -1
  107. package/lib/module/components/ScreenContentWrapper.web.js.map +1 -1
  108. package/lib/module/components/ScreenFooter.js +1 -7
  109. package/lib/module/components/ScreenFooter.js.map +1 -1
  110. package/lib/module/components/ScreenFooter.web.js +0 -1
  111. package/lib/module/components/ScreenFooter.web.js.map +1 -1
  112. package/lib/module/components/ScreenStack.js +46 -8
  113. package/lib/module/components/ScreenStack.js.map +1 -1
  114. package/lib/module/components/ScreenStack.web.js +2 -1
  115. package/lib/module/components/ScreenStack.web.js.map +1 -1
  116. package/lib/module/components/ScreenStackHeaderConfig.js +14 -8
  117. package/lib/module/components/ScreenStackHeaderConfig.js.map +1 -1
  118. package/lib/module/components/ScreenStackItem.js +90 -0
  119. package/lib/module/components/ScreenStackItem.js.map +1 -0
  120. package/lib/module/components/SearchBar.js +3 -3
  121. package/lib/module/components/SearchBar.js.map +1 -1
  122. package/lib/module/components/SearchBar.web.js +2 -3
  123. package/lib/module/components/SearchBar.web.js.map +1 -1
  124. package/lib/module/components/helpers/usePrevious.js +9 -0
  125. package/lib/module/components/helpers/usePrevious.js.map +1 -0
  126. package/lib/module/contexts.js +4 -0
  127. package/lib/module/contexts.js.map +1 -0
  128. package/lib/module/core.js +0 -3
  129. package/lib/module/core.js.map +1 -1
  130. package/lib/module/fabric/ModalScreenNativeComponent.js.map +1 -1
  131. package/lib/module/fabric/ScreenStackHeaderConfigNativeComponent.js.map +1 -1
  132. package/lib/module/gesture-handler/GestureDetectorProvider.js +1 -1
  133. package/lib/module/gesture-handler/GestureDetectorProvider.js.map +1 -1
  134. package/lib/module/gesture-handler/ScreenGestureDetector.js +3 -3
  135. package/lib/module/gesture-handler/ScreenGestureDetector.js.map +1 -1
  136. package/lib/module/gesture-handler/fabricUtils.js +55 -17
  137. package/lib/module/gesture-handler/fabricUtils.js.map +1 -1
  138. package/lib/module/index.js +12 -18
  139. package/lib/module/index.js.map +1 -1
  140. package/lib/module/native-stack/navigators/createNativeStackNavigator.js +4 -0
  141. package/lib/module/native-stack/navigators/createNativeStackNavigator.js.map +1 -1
  142. package/lib/module/native-stack/views/FooterComponent.js +1 -1
  143. package/lib/module/native-stack/views/FooterComponent.js.map +1 -1
  144. package/lib/module/native-stack/views/HeaderConfig.js +3 -1
  145. package/lib/module/native-stack/views/HeaderConfig.js.map +1 -1
  146. package/lib/module/native-stack/views/NativeStackView.js +28 -33
  147. package/lib/module/native-stack/views/NativeStackView.js.map +1 -1
  148. package/lib/module/reanimated/ReanimatedNativeStackScreen.js +1 -2
  149. package/lib/module/reanimated/ReanimatedNativeStackScreen.js.map +1 -1
  150. package/lib/module/reanimated/ReanimatedScreen.js +1 -2
  151. package/lib/module/reanimated/ReanimatedScreen.js.map +1 -1
  152. package/lib/module/reanimated/ReanimatedScreenProvider.js +1 -1
  153. package/lib/module/reanimated/ReanimatedScreenProvider.js.map +1 -1
  154. package/lib/module/utils.js +26 -5
  155. package/lib/module/utils.js.map +1 -1
  156. package/lib/typescript/components/DebugContainer.d.ts +15 -0
  157. package/lib/typescript/components/DebugContainer.d.ts.map +1 -0
  158. package/lib/typescript/components/DebugContainer.web.d.ts +4 -0
  159. package/lib/typescript/components/DebugContainer.web.d.ts.map +1 -0
  160. package/lib/typescript/components/FullWindowOverlay.d.ts.map +1 -1
  161. package/lib/typescript/components/Screen.d.ts +2 -7
  162. package/lib/typescript/components/Screen.d.ts.map +1 -1
  163. package/lib/typescript/components/Screen.web.d.ts +1 -1
  164. package/lib/typescript/components/Screen.web.d.ts.map +1 -1
  165. package/lib/typescript/components/ScreenContainer.d.ts +1 -3
  166. package/lib/typescript/components/ScreenContainer.d.ts.map +1 -1
  167. package/lib/typescript/components/ScreenContainer.web.d.ts +2 -3
  168. package/lib/typescript/components/ScreenContainer.web.d.ts.map +1 -1
  169. package/lib/typescript/components/ScreenContentWrapper.d.ts +0 -1
  170. package/lib/typescript/components/ScreenContentWrapper.d.ts.map +1 -1
  171. package/lib/typescript/components/ScreenContentWrapper.web.d.ts +0 -1
  172. package/lib/typescript/components/ScreenContentWrapper.web.d.ts.map +1 -1
  173. package/lib/typescript/components/ScreenFooter.d.ts +0 -4
  174. package/lib/typescript/components/ScreenFooter.d.ts.map +1 -1
  175. package/lib/typescript/components/ScreenFooter.web.d.ts +0 -1
  176. package/lib/typescript/components/ScreenFooter.web.d.ts.map +1 -1
  177. package/lib/typescript/components/ScreenStack.d.ts +1 -1
  178. package/lib/typescript/components/ScreenStack.d.ts.map +1 -1
  179. package/lib/typescript/components/ScreenStack.web.d.ts +2 -1
  180. package/lib/typescript/components/ScreenStack.web.d.ts.map +1 -1
  181. package/lib/typescript/components/ScreenStackHeaderConfig.d.ts +3 -3
  182. package/lib/typescript/components/ScreenStackHeaderConfig.d.ts.map +1 -1
  183. package/lib/typescript/components/ScreenStackHeaderConfig.web.d.ts +1 -1
  184. package/lib/typescript/components/ScreenStackHeaderConfig.web.d.ts.map +1 -1
  185. package/lib/typescript/components/ScreenStackItem.d.ts +11 -0
  186. package/lib/typescript/components/ScreenStackItem.d.ts.map +1 -0
  187. package/lib/typescript/components/SearchBar.d.ts +1 -15
  188. package/lib/typescript/components/SearchBar.d.ts.map +1 -1
  189. package/lib/typescript/components/SearchBar.web.d.ts +2 -3
  190. package/lib/typescript/components/SearchBar.web.d.ts.map +1 -1
  191. package/lib/typescript/components/helpers/usePrevious.d.ts +2 -0
  192. package/lib/typescript/components/helpers/usePrevious.d.ts.map +1 -0
  193. package/lib/typescript/contexts.d.ts +5 -0
  194. package/lib/typescript/contexts.d.ts.map +1 -0
  195. package/lib/typescript/core.d.ts +0 -1
  196. package/lib/typescript/core.d.ts.map +1 -1
  197. package/lib/typescript/fabric/ModalScreenNativeComponent.d.ts +9 -3
  198. package/lib/typescript/fabric/ModalScreenNativeComponent.d.ts.map +1 -1
  199. package/lib/typescript/fabric/ScreenNativeComponent.d.ts +2 -2
  200. package/lib/typescript/fabric/ScreenNativeComponent.d.ts.map +1 -1
  201. package/lib/typescript/fabric/ScreenStackHeaderConfigNativeComponent.d.ts +2 -2
  202. package/lib/typescript/fabric/ScreenStackHeaderConfigNativeComponent.d.ts.map +1 -1
  203. package/lib/typescript/fabric/ScreenStackNativeComponent.d.ts +1 -1
  204. package/lib/typescript/fabric/ScreenStackNativeComponent.d.ts.map +1 -1
  205. package/lib/typescript/gesture-handler/ScreenGestureDetector.d.ts +2 -2
  206. package/lib/typescript/gesture-handler/ScreenGestureDetector.d.ts.map +1 -1
  207. package/lib/typescript/gesture-handler/fabricUtils.d.ts +7 -5
  208. package/lib/typescript/gesture-handler/fabricUtils.d.ts.map +1 -1
  209. package/lib/typescript/index.d.ts +10 -16
  210. package/lib/typescript/index.d.ts.map +1 -1
  211. package/lib/typescript/native-stack/navigators/createNativeStackNavigator.d.ts +3 -0
  212. package/lib/typescript/native-stack/navigators/createNativeStackNavigator.d.ts.map +1 -1
  213. package/lib/typescript/native-stack/types.d.ts +58 -12
  214. package/lib/typescript/native-stack/types.d.ts.map +1 -1
  215. package/lib/typescript/native-stack/utils/getDefaultHeaderHeight.d.ts +1 -1
  216. package/lib/typescript/native-stack/utils/getDefaultHeaderHeight.d.ts.map +1 -1
  217. package/lib/typescript/native-stack/views/HeaderConfig.d.ts.map +1 -1
  218. package/lib/typescript/native-stack/views/NativeStackView.d.ts.map +1 -1
  219. package/lib/typescript/reanimated/ReanimatedNativeStackScreen.d.ts +1 -1
  220. package/lib/typescript/reanimated/ReanimatedNativeStackScreen.d.ts.map +1 -1
  221. package/lib/typescript/reanimated/ReanimatedScreen.d.ts +1 -1
  222. package/lib/typescript/reanimated/ReanimatedScreen.d.ts.map +1 -1
  223. package/lib/typescript/reanimated/ReanimatedScreenProvider.d.ts.map +1 -1
  224. package/lib/typescript/types.d.ts +52 -16
  225. package/lib/typescript/types.d.ts.map +1 -1
  226. package/lib/typescript/utils.d.ts +26 -1
  227. package/lib/typescript/utils.d.ts.map +1 -1
  228. package/native-stack/README.md +5 -4
  229. package/native-stack/package.json +4 -4
  230. package/package.json +1 -1
  231. package/react-native.config.js +16 -28
  232. package/src/components/DebugContainer.tsx +47 -0
  233. package/src/components/DebugContainer.web.tsx +7 -0
  234. package/src/components/FullWindowOverlay.tsx +10 -2
  235. package/src/components/Screen.tsx +52 -24
  236. package/src/components/Screen.web.tsx +1 -1
  237. package/src/components/ScreenContainer.tsx +4 -11
  238. package/src/components/ScreenContainer.web.tsx +2 -3
  239. package/src/components/ScreenContentWrapper.tsx +2 -5
  240. package/src/components/ScreenContentWrapper.web.tsx +1 -2
  241. package/src/components/ScreenFooter.tsx +2 -8
  242. package/src/components/ScreenFooter.web.tsx +1 -2
  243. package/src/components/ScreenStack.tsx +99 -12
  244. package/src/components/ScreenStack.web.tsx +3 -1
  245. package/src/components/ScreenStackHeaderConfig.tsx +28 -13
  246. package/src/components/ScreenStackHeaderConfig.web.tsx +1 -1
  247. package/src/components/ScreenStackItem.tsx +162 -0
  248. package/src/components/SearchBar.tsx +4 -7
  249. package/src/components/SearchBar.web.tsx +2 -3
  250. package/src/components/helpers/usePrevious.tsx +11 -0
  251. package/src/contexts.tsx +9 -0
  252. package/src/core.ts +0 -3
  253. package/src/fabric/ModalScreenNativeComponent.ts +11 -3
  254. package/src/fabric/ScreenNativeComponent.ts +2 -2
  255. package/src/fabric/ScreenStackHeaderConfigNativeComponent.ts +2 -1
  256. package/src/fabric/ScreenStackNativeComponent.ts +1 -1
  257. package/src/gesture-handler/GestureDetectorProvider.tsx +2 -2
  258. package/src/gesture-handler/ScreenGestureDetector.tsx +4 -4
  259. package/src/gesture-handler/fabricUtils.ts +74 -27
  260. package/src/index.tsx +11 -37
  261. package/src/native-stack/navigators/createNativeStackNavigator.tsx +3 -0
  262. package/src/native-stack/types.tsx +60 -17
  263. package/src/native-stack/utils/getDefaultHeaderHeight.tsx +1 -1
  264. package/src/native-stack/views/FooterComponent.tsx +1 -1
  265. package/src/native-stack/views/HeaderConfig.tsx +7 -5
  266. package/src/native-stack/views/NativeStackView.tsx +48 -67
  267. package/src/reanimated/ReanimatedNativeStackScreen.tsx +2 -2
  268. package/src/reanimated/ReanimatedScreen.tsx +2 -1
  269. package/src/reanimated/ReanimatedScreenProvider.tsx +2 -1
  270. package/src/types.tsx +72 -15
  271. package/src/utils.ts +27 -5
@@ -3,30 +3,48 @@
3
3
 
4
4
  #import "RNSScreen.h"
5
5
 
6
- // proportions to default transition duration
7
- static const float RNSSlideOpenTransitionDurationProportion = 1;
8
- static const float RNSFadeOpenTransitionDurationProportion = 0.2 / 0.35;
9
- static const float RNSSlideCloseTransitionDurationProportion = 0.25 / 0.35;
10
- static const float RNSFadeCloseTransitionDurationProportion = 0.15 / 0.35;
11
- static const float RNSFadeCloseDelayTransitionDurationProportion = 0.1 / 0.35;
12
- // same value is used in other projects using similar approach for transistions
6
+ #pragma mark - Constants
7
+
8
+ // Default duration for transitions in seconds. Note, that this enforces the default
9
+ // only on Paper. On Fabric the transition duration coming from JS layer
10
+ // is never null, thus it defaults to the value set in component codegen spec.
11
+ static constexpr NSTimeInterval RNSDefaultTransitionDuration = 0.5;
12
+
13
+ // Proportions for diffrent phases of more complex animations.
14
+ // The reference duration differs from default transition duration,
15
+ // because we've changed the default duration & we want to keep proportions
16
+ // in tact. Unit = seconds.
17
+ static constexpr NSTimeInterval RNSTransitionDurationForProportion = 0.35;
18
+
19
+ static constexpr float RNSSlideOpenTransitionDurationProportion = 1;
20
+ static constexpr float RNSFadeOpenTransitionDurationProportion = 0.2 / RNSTransitionDurationForProportion;
21
+ static constexpr float RNSSlideCloseTransitionDurationProportion = 0.25 / RNSTransitionDurationForProportion;
22
+ static constexpr float RNSFadeCloseTransitionDurationProportion = 0.15 / RNSTransitionDurationForProportion;
23
+ static constexpr float RNSFadeCloseDelayTransitionDurationProportion = 0.1 / RNSTransitionDurationForProportion;
24
+
25
+ // Value used for dimming view attached for tranistion time.
26
+ // Same value is used in other projects using similar approach for transistions
13
27
  // and it looks the most similar to the value used by Apple
14
28
  static constexpr float RNSShadowViewMaxAlpha = 0.1;
15
29
 
16
30
  @implementation RNSScreenStackAnimator {
17
31
  UINavigationControllerOperation _operation;
18
32
  NSTimeInterval _transitionDuration;
33
+ UIViewPropertyAnimator *_Nullable _inFlightAnimator;
19
34
  }
20
35
 
21
36
  - (instancetype)initWithOperation:(UINavigationControllerOperation)operation
22
37
  {
23
38
  if (self = [super init]) {
24
39
  _operation = operation;
25
- _transitionDuration = 0.35; // default duration in seconds
40
+ _transitionDuration = RNSDefaultTransitionDuration; // default duration in seconds
41
+ _inFlightAnimator = nil;
26
42
  }
27
43
  return self;
28
44
  }
29
45
 
46
+ #pragma mark - UIViewControllerAnimatedTransitioning
47
+
30
48
  - (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
31
49
  {
32
50
  RNSScreenView *screen;
@@ -52,6 +70,12 @@ static constexpr float RNSShadowViewMaxAlpha = 0.1;
52
70
  return _transitionDuration;
53
71
  }
54
72
 
73
+ - (id<UIViewImplicitlyAnimating>)interruptibleAnimatorForTransition:
74
+ (id<UIViewControllerContextTransitioning>)transitionContext
75
+ {
76
+ return _inFlightAnimator;
77
+ }
78
+
55
79
  - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
56
80
  {
57
81
  UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
@@ -97,6 +121,13 @@ static constexpr float RNSShadowViewMaxAlpha = 0.1;
97
121
  }
98
122
  }
99
123
 
124
+ - (void)animationEnded:(BOOL)transitionCompleted
125
+ {
126
+ _inFlightAnimator = nil;
127
+ }
128
+
129
+ #pragma mark - Animation implementations
130
+
100
131
  - (void)animateSimplePushWithShadowEnabled:(BOOL)shadowEnabled
101
132
  transitionContext:(id<UIViewControllerContextTransitioning>)transitionContext
102
133
  toVC:(UIViewController *)toViewController
@@ -128,22 +159,28 @@ static constexpr float RNSShadowViewMaxAlpha = 0.1;
128
159
  shadowView.alpha = 0.0;
129
160
  }
130
161
 
131
- [UIView animateWithDuration:[self transitionDuration:transitionContext]
132
- animations:^{
133
- fromViewController.view.transform = leftTransform;
134
- toViewController.view.transform = CGAffineTransformIdentity;
135
- if (shadowView) {
136
- shadowView.alpha = RNSShadowViewMaxAlpha;
137
- }
138
- }
139
- completion:^(BOOL finished) {
140
- if (shadowView) {
141
- [shadowView removeFromSuperview];
142
- }
143
- fromViewController.view.transform = CGAffineTransformIdentity;
144
- toViewController.view.transform = CGAffineTransformIdentity;
145
- [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
146
- }];
162
+ UIViewPropertyAnimator *animator =
163
+ [[UIViewPropertyAnimator alloc] initWithDuration:[self transitionDuration:transitionContext]
164
+ timingParameters:[RNSScreenStackAnimator defaultSpringTimingParametersApprox]];
165
+
166
+ [animator addAnimations:^{
167
+ fromViewController.view.transform = leftTransform;
168
+ toViewController.view.transform = CGAffineTransformIdentity;
169
+ if (shadowView) {
170
+ shadowView.alpha = RNSShadowViewMaxAlpha;
171
+ }
172
+ }];
173
+
174
+ [animator addCompletion:^(UIViewAnimatingPosition finalPosition) {
175
+ if (shadowView) {
176
+ [shadowView removeFromSuperview];
177
+ }
178
+ fromViewController.view.transform = CGAffineTransformIdentity;
179
+ toViewController.view.transform = CGAffineTransformIdentity;
180
+ [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
181
+ }];
182
+ _inFlightAnimator = animator;
183
+ [animator startAnimation];
147
184
  } else if (_operation == UINavigationControllerOperationPop) {
148
185
  toViewController.view.transform = leftTransform;
149
186
  [[transitionContext containerView] insertSubview:toViewController.view belowSubview:fromViewController.view];
@@ -159,7 +196,8 @@ static constexpr float RNSShadowViewMaxAlpha = 0.1;
159
196
  shadowView.alpha = 0.0;
160
197
  }
161
198
  };
162
- void (^completionBlock)(BOOL) = ^(BOOL finished) {
199
+
200
+ void (^completionBlock)(UIViewAnimatingPosition) = ^(UIViewAnimatingPosition finalPosition) {
163
201
  if (shadowView) {
164
202
  [shadowView removeFromSuperview];
165
203
  }
@@ -169,16 +207,24 @@ static constexpr float RNSShadowViewMaxAlpha = 0.1;
169
207
  };
170
208
 
171
209
  if (!transitionContext.isInteractive) {
172
- [UIView animateWithDuration:[self transitionDuration:transitionContext]
173
- animations:animationBlock
174
- completion:completionBlock];
210
+ UIViewPropertyAnimator *animator = [[UIViewPropertyAnimator alloc]
211
+ initWithDuration:[self transitionDuration:transitionContext]
212
+ timingParameters:[RNSScreenStackAnimator defaultSpringTimingParametersApprox]];
213
+
214
+ [animator addAnimations:animationBlock];
215
+ [animator addCompletion:completionBlock];
216
+ _inFlightAnimator = animator;
217
+ [animator startAnimation];
175
218
  } else {
176
219
  // we don't want the EaseInOut option when swiping to dismiss the view, it is the same in default animation option
177
- [UIView animateWithDuration:[self transitionDuration:transitionContext]
178
- delay:0.0
179
- options:UIViewAnimationOptionCurveLinear
180
- animations:animationBlock
181
- completion:completionBlock];
220
+ UIViewPropertyAnimator *animator =
221
+ [[UIViewPropertyAnimator alloc] initWithDuration:[self transitionDuration:transitionContext]
222
+ curve:UIViewAnimationCurveLinear
223
+ animations:animationBlock];
224
+
225
+ [animator addCompletion:completionBlock];
226
+ [animator setUserInteractionEnabled:YES];
227
+ _inFlightAnimator = animator;
182
228
  }
183
229
  }
184
230
  }
@@ -202,16 +248,22 @@ static constexpr float RNSShadowViewMaxAlpha = 0.1;
202
248
  if (_operation == UINavigationControllerOperationPush) {
203
249
  toViewController.view.transform = rightTransform;
204
250
  [[transitionContext containerView] addSubview:toViewController.view];
205
- [UIView animateWithDuration:[self transitionDuration:transitionContext]
206
- animations:^{
207
- fromViewController.view.transform = leftTransform;
208
- toViewController.view.transform = CGAffineTransformIdentity;
209
- }
210
- completion:^(BOOL finished) {
211
- fromViewController.view.transform = CGAffineTransformIdentity;
212
- toViewController.view.transform = CGAffineTransformIdentity;
213
- [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
214
- }];
251
+
252
+ UIViewPropertyAnimator *animator =
253
+ [[UIViewPropertyAnimator alloc] initWithDuration:[self transitionDuration:transitionContext]
254
+ timingParameters:[RNSScreenStackAnimator defaultSpringTimingParametersApprox]];
255
+
256
+ [animator addAnimations:^{
257
+ fromViewController.view.transform = leftTransform;
258
+ toViewController.view.transform = CGAffineTransformIdentity;
259
+ }];
260
+ [animator addCompletion:^(UIViewAnimatingPosition finalPosition) {
261
+ fromViewController.view.transform = CGAffineTransformIdentity;
262
+ toViewController.view.transform = CGAffineTransformIdentity;
263
+ [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
264
+ }];
265
+ _inFlightAnimator = animator;
266
+ [animator startAnimation];
215
267
  } else if (_operation == UINavigationControllerOperationPop) {
216
268
  toViewController.view.transform = leftTransform;
217
269
  [[transitionContext containerView] insertSubview:toViewController.view belowSubview:fromViewController.view];
@@ -220,23 +272,30 @@ static constexpr float RNSShadowViewMaxAlpha = 0.1;
220
272
  toViewController.view.transform = CGAffineTransformIdentity;
221
273
  fromViewController.view.transform = rightTransform;
222
274
  };
223
- void (^completionBlock)(BOOL) = ^(BOOL finished) {
275
+ void (^completionBlock)(UIViewAnimatingPosition) = ^(UIViewAnimatingPosition finalPosition) {
224
276
  fromViewController.view.transform = CGAffineTransformIdentity;
225
277
  toViewController.view.transform = CGAffineTransformIdentity;
226
278
  [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
227
279
  };
228
280
 
229
281
  if (!transitionContext.isInteractive) {
230
- [UIView animateWithDuration:[self transitionDuration:transitionContext]
231
- animations:animationBlock
232
- completion:completionBlock];
282
+ UIViewPropertyAnimator *animator = [[UIViewPropertyAnimator alloc]
283
+ initWithDuration:[self transitionDuration:transitionContext]
284
+ timingParameters:[RNSScreenStackAnimator defaultSpringTimingParametersApprox]];
285
+
286
+ [animator addAnimations:animationBlock];
287
+ [animator addCompletion:completionBlock];
288
+ _inFlightAnimator = animator;
289
+ [animator startAnimation];
233
290
  } else {
234
291
  // we don't want the EaseInOut option when swiping to dismiss the view, it is the same in default animation option
235
- [UIView animateWithDuration:[self transitionDuration:transitionContext]
236
- delay:0.0
237
- options:UIViewAnimationOptionCurveLinear
238
- animations:animationBlock
239
- completion:completionBlock];
292
+ UIViewPropertyAnimator *animator =
293
+ [[UIViewPropertyAnimator alloc] initWithDuration:[self transitionDuration:transitionContext]
294
+ curve:UIViewAnimationCurveLinear
295
+ animations:animationBlock];
296
+ [animator addCompletion:completionBlock];
297
+ [animator setUserInteractionEnabled:YES];
298
+ _inFlightAnimator = animator;
240
299
  }
241
300
  }
242
301
  }
@@ -250,26 +309,30 @@ static constexpr float RNSShadowViewMaxAlpha = 0.1;
250
309
  if (_operation == UINavigationControllerOperationPush) {
251
310
  [[transitionContext containerView] addSubview:toViewController.view];
252
311
  toViewController.view.alpha = 0.0;
253
- [UIView animateWithDuration:[self transitionDuration:transitionContext]
254
- animations:^{
255
- toViewController.view.alpha = 1.0;
256
- }
257
- completion:^(BOOL finished) {
258
- toViewController.view.alpha = 1.0;
259
- [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
260
- }];
312
+ auto animator = [[UIViewPropertyAnimator alloc] initWithDuration:[self transitionDuration:transitionContext]
313
+ curve:UIViewAnimationCurveEaseInOut
314
+ animations:^{
315
+ toViewController.view.alpha = 1.0;
316
+ }];
317
+ [animator addCompletion:^(UIViewAnimatingPosition finalPosition) {
318
+ toViewController.view.alpha = 1.0;
319
+ [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
320
+ }];
321
+ _inFlightAnimator = animator;
322
+ [animator startAnimation];
261
323
  } else if (_operation == UINavigationControllerOperationPop) {
262
324
  [[transitionContext containerView] insertSubview:toViewController.view belowSubview:fromViewController.view];
263
-
264
- [UIView animateWithDuration:[self transitionDuration:transitionContext]
265
- animations:^{
266
- fromViewController.view.alpha = 0.0;
267
- }
268
- completion:^(BOOL finished) {
269
- fromViewController.view.alpha = 1.0;
270
-
271
- [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
272
- }];
325
+ auto animator = [[UIViewPropertyAnimator alloc] initWithDuration:[self transitionDuration:transitionContext]
326
+ curve:UIViewAnimationCurveEaseInOut
327
+ animations:^{
328
+ fromViewController.view.alpha = 0.0;
329
+ }];
330
+ [animator addCompletion:^(UIViewAnimatingPosition finalPosition) {
331
+ fromViewController.view.alpha = 1.0;
332
+ [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
333
+ }];
334
+ _inFlightAnimator = animator;
335
+ [animator startAnimation];
273
336
  }
274
337
  }
275
338
 
@@ -283,16 +346,21 @@ static constexpr float RNSShadowViewMaxAlpha = 0.1;
283
346
  if (_operation == UINavigationControllerOperationPush) {
284
347
  toViewController.view.transform = topBottomTransform;
285
348
  [[transitionContext containerView] addSubview:toViewController.view];
286
- [UIView animateWithDuration:[self transitionDuration:transitionContext]
287
- animations:^{
288
- fromViewController.view.transform = CGAffineTransformIdentity;
289
- toViewController.view.transform = CGAffineTransformIdentity;
290
- }
291
- completion:^(BOOL finished) {
292
- fromViewController.view.transform = CGAffineTransformIdentity;
293
- toViewController.view.transform = CGAffineTransformIdentity;
294
- [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
295
- }];
349
+
350
+ auto animator = [[UIViewPropertyAnimator alloc] initWithDuration:[self transitionDuration:transitionContext]
351
+ curve:UIViewAnimationCurveEaseInOut
352
+ animations:^{
353
+ fromViewController.view.transform =
354
+ CGAffineTransformIdentity;
355
+ toViewController.view.transform = CGAffineTransformIdentity;
356
+ }];
357
+ [animator addCompletion:^(UIViewAnimatingPosition finalPosition) {
358
+ fromViewController.view.transform = CGAffineTransformIdentity;
359
+ toViewController.view.transform = CGAffineTransformIdentity;
360
+ [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
361
+ }];
362
+ _inFlightAnimator = animator;
363
+ [animator startAnimation];
296
364
  } else if (_operation == UINavigationControllerOperationPop) {
297
365
  toViewController.view.transform = CGAffineTransformIdentity;
298
366
  [[transitionContext containerView] insertSubview:toViewController.view belowSubview:fromViewController.view];
@@ -301,23 +369,26 @@ static constexpr float RNSShadowViewMaxAlpha = 0.1;
301
369
  toViewController.view.transform = CGAffineTransformIdentity;
302
370
  fromViewController.view.transform = topBottomTransform;
303
371
  };
304
- void (^completionBlock)(BOOL) = ^(BOOL finished) {
372
+ void (^completionBlock)(UIViewAnimatingPosition) = ^(UIViewAnimatingPosition finalPosition) {
305
373
  fromViewController.view.transform = CGAffineTransformIdentity;
306
374
  toViewController.view.transform = CGAffineTransformIdentity;
307
375
  [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
308
376
  };
309
377
 
310
378
  if (!transitionContext.isInteractive) {
311
- [UIView animateWithDuration:[self transitionDuration:transitionContext]
312
- animations:animationBlock
313
- completion:completionBlock];
379
+ auto animator = [[UIViewPropertyAnimator alloc] initWithDuration:[self transitionDuration:transitionContext]
380
+ curve:UIViewAnimationCurveEaseInOut
381
+ animations:animationBlock];
382
+ [animator addCompletion:completionBlock];
383
+ _inFlightAnimator = animator;
384
+ [animator startAnimation];
314
385
  } else {
315
386
  // we don't want the EaseInOut option when swiping to dismiss the view, it is the same in default animation option
316
- [UIView animateWithDuration:[self transitionDuration:transitionContext]
317
- delay:0.0
318
- options:UIViewAnimationOptionCurveLinear
319
- animations:animationBlock
320
- completion:completionBlock];
387
+ auto animator = [[UIViewPropertyAnimator alloc] initWithDuration:[self transitionDuration:transitionContext]
388
+ curve:UIViewAnimationCurveLinear
389
+ animations:animationBlock];
390
+ [animator addCompletion:completionBlock];
391
+ _inFlightAnimator = animator;
321
392
  }
322
393
  }
323
394
  }
@@ -329,7 +400,7 @@ static constexpr float RNSShadowViewMaxAlpha = 0.1;
329
400
  CGAffineTransform topBottomTransform =
330
401
  CGAffineTransformMakeTranslation(0, 0.08 * transitionContext.containerView.bounds.size.height);
331
402
 
332
- const float transitionDuration = [self transitionDuration:transitionContext];
403
+ const float baseTransitionDuration = [self transitionDuration:transitionContext];
333
404
 
334
405
  if (_operation == UINavigationControllerOperationPush) {
335
406
  toViewController.view.transform = topBottomTransform;
@@ -338,52 +409,59 @@ static constexpr float RNSShadowViewMaxAlpha = 0.1;
338
409
 
339
410
  // Android Nougat open animation
340
411
  // http://aosp.opersys.com/xref/android-7.1.2_r37/xref/frameworks/base/core/res/res/anim/activity_open_enter.xml
341
- [UIView animateWithDuration:transitionDuration * RNSSlideOpenTransitionDurationProportion // defaults to 0.35 s
342
- delay:0
343
- options:UIViewAnimationOptionCurveEaseOut
344
- animations:^{
345
- fromViewController.view.transform = CGAffineTransformIdentity;
346
- toViewController.view.transform = CGAffineTransformIdentity;
347
- }
348
- completion:^(BOOL finished) {
349
- fromViewController.view.transform = CGAffineTransformIdentity;
350
- [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
351
- }];
352
- [UIView animateWithDuration:transitionDuration * RNSFadeOpenTransitionDurationProportion // defaults to 0.2 s
353
- delay:0
354
- options:UIViewAnimationOptionCurveEaseOut
355
- animations:^{
356
- toViewController.view.alpha = 1.0;
357
- }
358
- completion:nil];
359
-
412
+ auto slideAnimator = [[UIViewPropertyAnimator alloc]
413
+ initWithDuration:baseTransitionDuration * RNSSlideOpenTransitionDurationProportion
414
+ curve:UIViewAnimationCurveEaseOut
415
+ animations:^{
416
+ fromViewController.view.transform = CGAffineTransformIdentity;
417
+ toViewController.view.transform = CGAffineTransformIdentity;
418
+ }];
419
+ [slideAnimator addCompletion:^(UIViewAnimatingPosition finalPosition) {
420
+ fromViewController.view.transform = CGAffineTransformIdentity;
421
+ [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
422
+ }];
423
+
424
+ auto fadeAnimator = [[UIViewPropertyAnimator alloc]
425
+ initWithDuration:baseTransitionDuration * RNSFadeOpenTransitionDurationProportion
426
+ curve:UIViewAnimationCurveEaseOut
427
+ animations:^{
428
+ toViewController.view.alpha = 1.0;
429
+ }];
430
+
431
+ _inFlightAnimator = slideAnimator;
432
+ [slideAnimator startAnimation];
433
+ [fadeAnimator startAnimation];
360
434
  } else if (_operation == UINavigationControllerOperationPop) {
361
435
  toViewController.view.transform = CGAffineTransformIdentity;
362
436
  [[transitionContext containerView] insertSubview:toViewController.view belowSubview:fromViewController.view];
363
437
 
364
438
  // Android Nougat exit animation
365
439
  // http://aosp.opersys.com/xref/android-7.1.2_r37/xref/frameworks/base/core/res/res/anim/activity_close_exit.xml
366
- [UIView animateWithDuration:transitionDuration * RNSSlideCloseTransitionDurationProportion // defaults to 0.25 s
367
- delay:0
368
- options:UIViewAnimationOptionCurveEaseIn
369
- animations:^{
370
- toViewController.view.transform = CGAffineTransformIdentity;
371
- fromViewController.view.transform = topBottomTransform;
372
- }
373
- completion:^(BOOL finished) {
374
- fromViewController.view.transform = CGAffineTransformIdentity;
375
- toViewController.view.transform = CGAffineTransformIdentity;
376
- fromViewController.view.alpha = 1.0;
377
- toViewController.view.alpha = 1.0;
378
- [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
379
- }];
380
- [UIView animateWithDuration:transitionDuration * RNSFadeCloseTransitionDurationProportion // defaults to 0.15 s
381
- delay:transitionDuration * RNSFadeCloseDelayTransitionDurationProportion // defaults to 0.1 s
382
- options:UIViewAnimationOptionCurveLinear
383
- animations:^{
384
- fromViewController.view.alpha = 0.0;
385
- }
386
- completion:nil];
440
+ auto slideAnimator = [[UIViewPropertyAnimator alloc]
441
+ initWithDuration:baseTransitionDuration * RNSSlideCloseTransitionDurationProportion
442
+ curve:UIViewAnimationCurveEaseIn
443
+ animations:^{
444
+ toViewController.view.transform = CGAffineTransformIdentity;
445
+ fromViewController.view.transform = topBottomTransform;
446
+ }];
447
+ [slideAnimator addCompletion:^(UIViewAnimatingPosition finalPosition) {
448
+ fromViewController.view.transform = CGAffineTransformIdentity;
449
+ toViewController.view.transform = CGAffineTransformIdentity;
450
+ fromViewController.view.alpha = 1.0;
451
+ toViewController.view.alpha = 1.0;
452
+ [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
453
+ }];
454
+
455
+ auto fadeAnimator = [[UIViewPropertyAnimator alloc]
456
+ initWithDuration:baseTransitionDuration * RNSFadeCloseTransitionDurationProportion
457
+ curve:UIViewAnimationCurveLinear
458
+ animations:^{
459
+ fromViewController.view.alpha = 0.0;
460
+ }];
461
+
462
+ _inFlightAnimator = slideAnimator;
463
+ [slideAnimator startAnimation];
464
+ [fadeAnimator startAnimationAfterDelay:baseTransitionDuration * RNSFadeCloseDelayTransitionDurationProportion];
387
465
  }
388
466
  }
389
467
 
@@ -411,11 +489,20 @@ static constexpr float RNSShadowViewMaxAlpha = 0.1;
411
489
  }
412
490
  }
413
491
 
492
+ #pragma mark - Public API
493
+
494
+ - (nullable id<UITimingCurveProvider>)timingParamsForAnimationCompletion
495
+ {
496
+ return [RNSScreenStackAnimator defaultSpringTimingParametersApprox];
497
+ }
498
+
414
499
  + (BOOL)isCustomAnimation:(RNSScreenStackAnimation)animation
415
500
  {
416
501
  return (animation != RNSScreenStackAnimationFlip && animation != RNSScreenStackAnimationDefault);
417
502
  }
418
503
 
504
+ #pragma mark - Helpers
505
+
419
506
  - (void)animateTransitionWithStackAnimation:(RNSScreenStackAnimation)animation
420
507
  shadowEnabled:(BOOL)shadowEnabled
421
508
  transitionContext:(id<UIViewControllerContextTransitioning>)transitionContext
@@ -442,4 +529,20 @@ static constexpr float RNSShadowViewMaxAlpha = 0.1;
442
529
  [self animateSimplePushWithShadowEnabled:shadowEnabled transitionContext:transitionContext toVC:toVC fromVC:fromVC];
443
530
  }
444
531
 
532
+ + (UISpringTimingParameters *)defaultSpringTimingParametersApprox
533
+ {
534
+ // Default curve provider is as defined below, however spring timing defined this way
535
+ // ignores the requested duration of the animation, effectively impairing our `animationDuration` prop.
536
+ // We want to keep `animationDuration` functional.
537
+ // id<UITimingCurveProvider> timingCurveProvider = [[UISpringTimingParameters alloc] init];
538
+
539
+ // According to "Programming iOS 14" by Matt Neuburg, the params for the default spring are as follows:
540
+ // mass = 3, stiffness = 1000, damping = 500. Damping ratio is computed using formula
541
+ // ratio = damping / (2 * sqrt(stiffness * mass)) ==> default damping ratio should be ~= 4,56.
542
+ // I've found afterwards that this is even indicated here:
543
+ // https://developer.apple.com/documentation/uikit/uispringtimingparameters/1649802-init?language=objc
544
+
545
+ return [[UISpringTimingParameters alloc] initWithDampingRatio:4.56];
546
+ }
547
+
445
548
  @end
@@ -56,7 +56,7 @@
56
56
  @property (nonatomic) BOOL backButtonInCustomView;
57
57
  @property (nonatomic) UISemanticContentAttribute direction;
58
58
  @property (nonatomic) UINavigationItemBackButtonDisplayMode backButtonDisplayMode;
59
- @property (nonatomic) UIBlurEffectStyle blurEffect;
59
+ @property (nonatomic) RNSBlurEffectStyle blurEffect;
60
60
 
61
61
  + (void)willShowViewController:(UIViewController *)vc
62
62
  animated:(BOOL)animated
@@ -110,6 +110,7 @@ namespace react = facebook::react;
110
110
  self.hidden = YES;
111
111
  _reactSubviews = [NSMutableArray new];
112
112
  _backTitleVisible = YES;
113
+ _blurEffect = RNSBlurEffectStyleNone;
113
114
  }
114
115
 
115
116
  - (UIView *)reactSuperview
@@ -449,8 +450,11 @@ namespace react = facebook::react;
449
450
  appearance.backgroundColor = config.backgroundColor;
450
451
  }
451
452
 
452
- if (config.blurEffect) {
453
- appearance.backgroundEffect = [UIBlurEffect effectWithStyle:config.blurEffect];
453
+ if (config.blurEffect != RNSBlurEffectStyleNone) {
454
+ appearance.backgroundEffect =
455
+ [UIBlurEffect effectWithStyle:[RNSConvert tryConvertRNSBlurEffectStyleToUIBlurEffectStyle:config.blurEffect]];
456
+ } else {
457
+ appearance.backgroundEffect = nil;
454
458
  }
455
459
 
456
460
  if (config.hideShadow) {
@@ -823,12 +827,17 @@ namespace react = facebook::react;
823
827
 
824
828
  - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
825
829
  {
826
- // For explanation of why we can make a snapshot here despite the fact that our children are already
827
- // unmounted see https://github.com/software-mansion/react-native-screens/pull/2261
828
- [self replaceNavigationBarViewsWithSnapshotOfSubview:(RNSScreenStackHeaderSubview *)childComponentView];
830
+ BOOL isGoingToBeRemoved = _screenView.isMarkedForUnmountInCurrentTransaction;
831
+ if (isGoingToBeRemoved) {
832
+ // For explanation of why we can make a snapshot here despite the fact that our children are already
833
+ // unmounted see https://github.com/software-mansion/react-native-screens/pull/2261
834
+ [self replaceNavigationBarViewsWithSnapshotOfSubview:(RNSScreenStackHeaderSubview *)childComponentView];
835
+ }
829
836
  [_reactSubviews removeObject:(RNSScreenStackHeaderSubview *)childComponentView];
830
837
  [childComponentView removeFromSuperview];
831
- [self updateViewControllerIfNeeded];
838
+ if (!isGoingToBeRemoved) {
839
+ [self updateViewControllerIfNeeded];
840
+ }
832
841
  }
833
842
 
834
843
  - (void)replaceNavigationBarViewsWithSnapshotOfSubview:(RNSScreenStackHeaderSubview *)childComponentView
@@ -972,7 +981,7 @@ static RCTResizeMode resizeModeFromCppEquiv(react::ImageResizeMode resizeMode)
972
981
  _backgroundColor = RCTUIColorFromSharedColor(newScreenProps.backgroundColor);
973
982
 
974
983
  if (newScreenProps.blurEffect != oldScreenProps.blurEffect) {
975
- _blurEffect = [RNSConvert UIBlurEffectStyleFromCppEquivalent:newScreenProps.blurEffect];
984
+ _blurEffect = [RNSConvert RNSBlurEffectStyleFromCppEquivalent:newScreenProps.blurEffect];
976
985
  }
977
986
 
978
987
  [self updateViewControllerIfNeeded];
@@ -1056,7 +1065,7 @@ RCT_EXPORT_VIEW_PROPERTY(backTitleFontFamily, NSString)
1056
1065
  RCT_EXPORT_VIEW_PROPERTY(backTitleFontSize, NSNumber)
1057
1066
  RCT_EXPORT_VIEW_PROPERTY(backgroundColor, UIColor)
1058
1067
  RCT_EXPORT_VIEW_PROPERTY(backTitleVisible, BOOL)
1059
- RCT_EXPORT_VIEW_PROPERTY(blurEffect, UIBlurEffectStyle)
1068
+ RCT_EXPORT_VIEW_PROPERTY(blurEffect, RNSBlurEffectStyle)
1060
1069
  RCT_EXPORT_VIEW_PROPERTY(color, UIColor)
1061
1070
  RCT_EXPORT_VIEW_PROPERTY(direction, UISemanticContentAttribute)
1062
1071
  RCT_EXPORT_VIEW_PROPERTY(largeTitle, BOOL)
@@ -1122,36 +1131,37 @@ RCT_EXPORT_VIEW_PROPERTY(translucent, BOOL)
1122
1131
  {
1123
1132
  NSMutableDictionary *blurEffects = [NSMutableDictionary new];
1124
1133
  [blurEffects addEntriesFromDictionary:@{
1125
- @"extraLight" : @(UIBlurEffectStyleExtraLight),
1126
- @"light" : @(UIBlurEffectStyleLight),
1127
- @"dark" : @(UIBlurEffectStyleDark),
1134
+ @"none" : @(RNSBlurEffectStyleNone),
1135
+ @"extraLight" : @(RNSBlurEffectStyleExtraLight),
1136
+ @"light" : @(RNSBlurEffectStyleLight),
1137
+ @"dark" : @(RNSBlurEffectStyleDark),
1128
1138
  }];
1129
1139
 
1130
1140
  if (@available(iOS 10.0, *)) {
1131
1141
  [blurEffects addEntriesFromDictionary:@{
1132
- @"regular" : @(UIBlurEffectStyleRegular),
1133
- @"prominent" : @(UIBlurEffectStyleProminent),
1142
+ @"regular" : @(RNSBlurEffectStyleRegular),
1143
+ @"prominent" : @(RNSBlurEffectStyleProminent),
1134
1144
  }];
1135
1145
  }
1136
1146
  #if !TARGET_OS_TV && defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
1137
1147
  __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
1138
1148
  if (@available(iOS 13.0, *)) {
1139
1149
  [blurEffects addEntriesFromDictionary:@{
1140
- @"systemUltraThinMaterial" : @(UIBlurEffectStyleSystemUltraThinMaterial),
1141
- @"systemThinMaterial" : @(UIBlurEffectStyleSystemThinMaterial),
1142
- @"systemMaterial" : @(UIBlurEffectStyleSystemMaterial),
1143
- @"systemThickMaterial" : @(UIBlurEffectStyleSystemThickMaterial),
1144
- @"systemChromeMaterial" : @(UIBlurEffectStyleSystemChromeMaterial),
1145
- @"systemUltraThinMaterialLight" : @(UIBlurEffectStyleSystemUltraThinMaterialLight),
1146
- @"systemThinMaterialLight" : @(UIBlurEffectStyleSystemThinMaterialLight),
1147
- @"systemMaterialLight" : @(UIBlurEffectStyleSystemMaterialLight),
1148
- @"systemThickMaterialLight" : @(UIBlurEffectStyleSystemThickMaterialLight),
1149
- @"systemChromeMaterialLight" : @(UIBlurEffectStyleSystemChromeMaterialLight),
1150
- @"systemUltraThinMaterialDark" : @(UIBlurEffectStyleSystemUltraThinMaterialDark),
1151
- @"systemThinMaterialDark" : @(UIBlurEffectStyleSystemThinMaterialDark),
1152
- @"systemMaterialDark" : @(UIBlurEffectStyleSystemMaterialDark),
1153
- @"systemThickMaterialDark" : @(UIBlurEffectStyleSystemThickMaterialDark),
1154
- @"systemChromeMaterialDark" : @(UIBlurEffectStyleSystemChromeMaterialDark),
1150
+ @"systemUltraThinMaterial" : @(RNSBlurEffectStyleSystemUltraThinMaterial),
1151
+ @"systemThinMaterial" : @(RNSBlurEffectStyleSystemThinMaterial),
1152
+ @"systemMaterial" : @(RNSBlurEffectStyleSystemMaterial),
1153
+ @"systemThickMaterial" : @(RNSBlurEffectStyleSystemThickMaterial),
1154
+ @"systemChromeMaterial" : @(RNSBlurEffectStyleSystemChromeMaterial),
1155
+ @"systemUltraThinMaterialLight" : @(RNSBlurEffectStyleSystemUltraThinMaterialLight),
1156
+ @"systemThinMaterialLight" : @(RNSBlurEffectStyleSystemThinMaterialLight),
1157
+ @"systemMaterialLight" : @(RNSBlurEffectStyleSystemMaterialLight),
1158
+ @"systemThickMaterialLight" : @(RNSBlurEffectStyleSystemThickMaterialLight),
1159
+ @"systemChromeMaterialLight" : @(RNSBlurEffectStyleSystemChromeMaterialLight),
1160
+ @"systemUltraThinMaterialDark" : @(RNSBlurEffectStyleSystemUltraThinMaterialDark),
1161
+ @"systemThinMaterialDark" : @(RNSBlurEffectStyleSystemThinMaterialDark),
1162
+ @"systemMaterialDark" : @(RNSBlurEffectStyleSystemMaterialDark),
1163
+ @"systemThickMaterialDark" : @(RNSBlurEffectStyleSystemThickMaterialDark),
1164
+ @"systemChromeMaterialDark" : @(RNSBlurEffectStyleSystemChromeMaterialDark),
1155
1165
  }];
1156
1166
  }
1157
1167
  #endif
@@ -1177,6 +1187,6 @@ RCT_ENUM_CONVERTER(
1177
1187
  UINavigationItemBackButtonDisplayModeDefault,
1178
1188
  integerValue)
1179
1189
 
1180
- RCT_ENUM_CONVERTER(UIBlurEffectStyle, ([self blurEffectsForIOSVersion]), UIBlurEffectStyleExtraLight, integerValue)
1190
+ RCT_ENUM_CONVERTER(RNSBlurEffectStyle, ([self blurEffectsForIOSVersion]), RNSBlurEffectStyleNone, integerValue)
1181
1191
 
1182
1192
  @end