react-native-reanimated 3.13.0-rc.2 → 3.13.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 (153) hide show
  1. package/Common/cpp/LayoutAnimations/LayoutAnimationsManager.cpp +8 -2
  2. package/Common/cpp/LayoutAnimations/LayoutAnimationsManager.h +3 -1
  3. package/Common/cpp/LayoutAnimations/LayoutAnimationsProxy.cpp +58 -33
  4. package/Common/cpp/LayoutAnimations/LayoutAnimationsProxy.h +19 -9
  5. package/Common/cpp/LayoutAnimations/LayoutAnimationsUtils.cpp +11 -7
  6. package/Common/cpp/LayoutAnimations/LayoutAnimationsUtils.h +14 -6
  7. package/Common/cpp/NativeModules/NativeReanimatedModule.cpp +1 -1
  8. package/Common/cpp/NativeModules/NativeReanimatedModule.h +1 -1
  9. package/Common/cpp/ReanimatedRuntime/WorkletRuntime.cpp +1 -1
  10. package/Common/cpp/ReanimatedRuntime/WorkletRuntime.h +1 -1
  11. package/Common/cpp/ReanimatedRuntime/WorkletRuntimeDecorator.cpp +6 -6
  12. package/Common/cpp/SharedItems/Shareables.cpp +25 -8
  13. package/Common/cpp/SharedItems/Shareables.h +12 -7
  14. package/android/CMakeLists.txt +1 -1
  15. package/android/src/main/cpp/LayoutAnimations.cpp +14 -0
  16. package/android/src/main/cpp/LayoutAnimations.h +5 -0
  17. package/android/src/main/cpp/NativeProxy.cpp +10 -0
  18. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/AnimationsManager.java +10 -2
  19. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/LayoutAnimations.java +2 -0
  20. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/NativeMethodsHolder.java +2 -0
  21. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/ReanimatedNativeHierarchyManager.java +10 -0
  22. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/ScreensHelper.java +83 -0
  23. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/SharedTransitionManager.java +130 -31
  24. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/Snapshot.java +36 -0
  25. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/TabNavigatorObserver.java +128 -0
  26. package/android/src/paper/java/com/swmansion/reanimated/NativeProxy.java +8 -0
  27. package/android/src/reactNativeVersionPatch/RuntimeExecutor/73/com/swmansion/reanimated/NativeProxy.java +6 -0
  28. package/android/src/reactNativeVersionPatch/RuntimeExecutor/latest/com/swmansion/reanimated/NativeProxy.java +6 -0
  29. package/apple/LayoutReanimation/REAAnimationsManager.h +2 -0
  30. package/apple/LayoutReanimation/REAAnimationsManager.m +5 -0
  31. package/apple/LayoutReanimation/REAScreensHelper.h +6 -0
  32. package/apple/LayoutReanimation/REAScreensHelper.m +92 -4
  33. package/apple/LayoutReanimation/REASharedTransitionManager.h +1 -0
  34. package/apple/LayoutReanimation/REASharedTransitionManager.m +254 -55
  35. package/apple/native/NativeProxy.mm +12 -0
  36. package/lib/module/Colors.js +5 -2
  37. package/lib/module/Colors.js.map +1 -1
  38. package/lib/module/UpdateProps.js +8 -8
  39. package/lib/module/UpdateProps.js.map +1 -1
  40. package/lib/module/ViewDescriptorsSet.js +0 -27
  41. package/lib/module/ViewDescriptorsSet.js.map +1 -1
  42. package/lib/module/createAnimatedComponent/InlinePropManager.js +1 -7
  43. package/lib/module/createAnimatedComponent/InlinePropManager.js.map +1 -1
  44. package/lib/module/createAnimatedComponent/PropsFilter.js +1 -6
  45. package/lib/module/createAnimatedComponent/PropsFilter.js.map +1 -1
  46. package/lib/module/createAnimatedComponent/commonTypes.js.map +1 -1
  47. package/lib/module/createAnimatedComponent/createAnimatedComponent.js +1 -5
  48. package/lib/module/createAnimatedComponent/createAnimatedComponent.js.map +1 -1
  49. package/lib/module/hook/commonTypes.js.map +1 -1
  50. package/lib/module/hook/useAnimatedStyle.js +12 -15
  51. package/lib/module/hook/useAnimatedStyle.js.map +1 -1
  52. package/lib/module/hook/useFrameCallback.js +2 -2
  53. package/lib/module/hook/useFrameCallback.js.map +1 -1
  54. package/lib/module/hook/useWorkletCallback.js +1 -1
  55. package/lib/module/hook/useWorkletCallback.js.map +1 -1
  56. package/lib/module/js-reanimated/index.js +3 -28
  57. package/lib/module/js-reanimated/index.js.map +1 -1
  58. package/lib/module/js-reanimated/webUtils.js +9 -0
  59. package/lib/module/js-reanimated/webUtils.js.map +1 -0
  60. package/lib/module/js-reanimated/webUtils.web.js +25 -0
  61. package/lib/module/js-reanimated/webUtils.web.js.map +1 -0
  62. package/lib/module/layoutReanimation/defaultTransitions/CurvedTransition.js +1 -0
  63. package/lib/module/layoutReanimation/defaultTransitions/CurvedTransition.js.map +1 -1
  64. package/lib/module/layoutReanimation/defaultTransitions/EntryExitTransition.js +1 -0
  65. package/lib/module/layoutReanimation/defaultTransitions/EntryExitTransition.js.map +1 -1
  66. package/lib/module/layoutReanimation/defaultTransitions/FadingTransition.js +11 -10
  67. package/lib/module/layoutReanimation/defaultTransitions/FadingTransition.js.map +1 -1
  68. package/lib/module/layoutReanimation/defaultTransitions/JumpingTransition.js +1 -0
  69. package/lib/module/layoutReanimation/defaultTransitions/JumpingTransition.js.map +1 -1
  70. package/lib/module/layoutReanimation/defaultTransitions/LinearTransition.js +1 -0
  71. package/lib/module/layoutReanimation/defaultTransitions/LinearTransition.js.map +1 -1
  72. package/lib/module/layoutReanimation/defaultTransitions/SequencedTransition.js +1 -0
  73. package/lib/module/layoutReanimation/defaultTransitions/SequencedTransition.js.map +1 -1
  74. package/lib/module/layoutReanimation/web/Easing.web.js +14 -0
  75. package/lib/module/layoutReanimation/web/Easing.web.js.map +1 -0
  76. package/lib/module/layoutReanimation/web/animationParser.js +16 -1
  77. package/lib/module/layoutReanimation/web/animationParser.js.map +1 -1
  78. package/lib/module/layoutReanimation/web/animationsManager.js +25 -8
  79. package/lib/module/layoutReanimation/web/animationsManager.js.map +1 -1
  80. package/lib/module/layoutReanimation/web/componentStyle.js +12 -16
  81. package/lib/module/layoutReanimation/web/componentStyle.js.map +1 -1
  82. package/lib/module/layoutReanimation/web/componentUtils.js +53 -18
  83. package/lib/module/layoutReanimation/web/componentUtils.js.map +1 -1
  84. package/lib/module/layoutReanimation/web/config.js +1 -12
  85. package/lib/module/layoutReanimation/web/config.js.map +1 -1
  86. package/lib/module/layoutReanimation/web/createAnimation.js +21 -2
  87. package/lib/module/layoutReanimation/web/createAnimation.js.map +1 -1
  88. package/lib/module/layoutReanimation/web/domUtils.js +6 -5
  89. package/lib/module/layoutReanimation/web/domUtils.js.map +1 -1
  90. package/lib/module/layoutReanimation/web/transition/Jumping.web.js +43 -0
  91. package/lib/module/layoutReanimation/web/transition/Jumping.web.js.map +1 -0
  92. package/lib/module/platform-specific/RNRenderer.web.js +1 -1
  93. package/lib/module/platform-specific/RNRenderer.web.js.map +1 -1
  94. package/lib/module/platform-specific/jsVersion.js +1 -1
  95. package/lib/module/platform-specific/jsVersion.js.map +1 -1
  96. package/lib/module/platformFunctions/setNativeProps.web.js +1 -3
  97. package/lib/module/platformFunctions/setNativeProps.web.js.map +1 -1
  98. package/lib/typescript/UpdateProps.d.ts +2 -3
  99. package/lib/typescript/ViewDescriptorsSet.d.ts +0 -9
  100. package/lib/typescript/createAnimatedComponent/commonTypes.d.ts +1 -2
  101. package/lib/typescript/hook/commonTypes.d.ts +3 -6
  102. package/lib/typescript/hook/useWorkletCallback.d.ts +1 -1
  103. package/lib/typescript/js-reanimated/index.d.ts +2 -4
  104. package/lib/typescript/js-reanimated/webUtils.d.ts +3 -0
  105. package/lib/typescript/js-reanimated/webUtils.web.d.ts +3 -0
  106. package/lib/typescript/layoutReanimation/defaultTransitions/CurvedTransition.d.ts +1 -0
  107. package/lib/typescript/layoutReanimation/defaultTransitions/EntryExitTransition.d.ts +1 -0
  108. package/lib/typescript/layoutReanimation/defaultTransitions/FadingTransition.d.ts +1 -0
  109. package/lib/typescript/layoutReanimation/defaultTransitions/JumpingTransition.d.ts +1 -0
  110. package/lib/typescript/layoutReanimation/defaultTransitions/LinearTransition.d.ts +1 -0
  111. package/lib/typescript/layoutReanimation/defaultTransitions/SequencedTransition.d.ts +1 -0
  112. package/lib/typescript/layoutReanimation/web/Easing.web.d.ts +10 -0
  113. package/lib/typescript/layoutReanimation/web/animationParser.d.ts +1 -2
  114. package/lib/typescript/layoutReanimation/web/componentStyle.d.ts +1 -1
  115. package/lib/typescript/layoutReanimation/web/componentUtils.d.ts +4 -3
  116. package/lib/typescript/layoutReanimation/web/config.d.ts +5 -12
  117. package/lib/typescript/layoutReanimation/web/createAnimation.d.ts +2 -0
  118. package/lib/typescript/layoutReanimation/web/domUtils.d.ts +1 -1
  119. package/lib/typescript/layoutReanimation/web/transition/Jumping.web.d.ts +29 -0
  120. package/lib/typescript/platform-specific/jsVersion.d.ts +1 -1
  121. package/package.json +4 -3
  122. package/src/Colors.ts +5 -2
  123. package/src/UpdateProps.ts +8 -11
  124. package/src/ViewDescriptorsSet.ts +0 -42
  125. package/src/createAnimatedComponent/InlinePropManager.ts +2 -8
  126. package/src/createAnimatedComponent/PropsFilter.tsx +0 -4
  127. package/src/createAnimatedComponent/commonTypes.ts +1 -2
  128. package/src/createAnimatedComponent/createAnimatedComponent.tsx +1 -5
  129. package/src/hook/commonTypes.ts +3 -6
  130. package/src/hook/useAnimatedStyle.ts +9 -26
  131. package/src/hook/useFrameCallback.ts +2 -2
  132. package/src/hook/useWorkletCallback.ts +1 -1
  133. package/src/js-reanimated/index.ts +11 -37
  134. package/src/js-reanimated/webUtils.ts +8 -0
  135. package/src/js-reanimated/webUtils.web.ts +27 -0
  136. package/src/layoutReanimation/defaultTransitions/CurvedTransition.ts +2 -0
  137. package/src/layoutReanimation/defaultTransitions/EntryExitTransition.ts +2 -0
  138. package/src/layoutReanimation/defaultTransitions/FadingTransition.ts +12 -10
  139. package/src/layoutReanimation/defaultTransitions/JumpingTransition.ts +2 -0
  140. package/src/layoutReanimation/defaultTransitions/LinearTransition.ts +2 -0
  141. package/src/layoutReanimation/defaultTransitions/SequencedTransition.ts +2 -0
  142. package/src/layoutReanimation/web/Easing.web.ts +15 -0
  143. package/src/layoutReanimation/web/animationParser.ts +30 -2
  144. package/src/layoutReanimation/web/animationsManager.ts +45 -12
  145. package/src/layoutReanimation/web/componentStyle.ts +13 -16
  146. package/src/layoutReanimation/web/componentUtils.ts +68 -25
  147. package/src/layoutReanimation/web/config.ts +5 -14
  148. package/src/layoutReanimation/web/createAnimation.ts +38 -4
  149. package/src/layoutReanimation/web/domUtils.ts +15 -5
  150. package/src/layoutReanimation/web/transition/Jumping.web.ts +44 -0
  151. package/src/platform-specific/RNRenderer.web.ts +1 -1
  152. package/src/platform-specific/jsVersion.ts +1 -1
  153. package/src/platformFunctions/setNativeProps.web.ts +1 -1
@@ -111,6 +111,12 @@ public class NativeProxy extends NativeProxyCommon {
111
111
  public void checkDuplicateSharedTag(int viewTag, int screenTag) {
112
112
  // NOT IMPLEMENTED
113
113
  }
114
+
115
+ @Override
116
+ public int[] getSharedGroup(int viewTag) {
117
+ // NOT IMPLEMENTED
118
+ return new int[]{};
119
+ }
114
120
  };
115
121
  }
116
122
  }
@@ -138,6 +138,12 @@ public class NativeProxy extends NativeProxyCommon {
138
138
  public void checkDuplicateSharedTag(int viewTag, int screenTag) {
139
139
  // NOT IMPLEMENTED
140
140
  }
141
+
142
+ @Override
143
+ public int[] getSharedGroup(int viewTag) {
144
+ // NOT IMPLEMENTED
145
+ return new int[]{};
146
+ }
141
147
  };
142
148
  }
143
149
  }
@@ -26,6 +26,7 @@ typedef void (^REACheckDuplicateSharedTagBlock)(REAUIView *view, NSNumber *_Nonn
26
26
  #endif
27
27
  typedef void (^REACancelAnimationBlock)(NSNumber *_Nonnull tag);
28
28
  typedef NSNumber *_Nullable (^REAFindPrecedingViewTagForTransitionBlock)(NSNumber *_Nonnull tag);
29
+ typedef NSArray<NSNumber *> *_Nullable (^REAGetSharedGroupBlock)(NSNumber *_Nonnull tag);
29
30
  typedef int (^REATreeVisitor)(id<RCTComponent>);
30
31
  BOOL REANodeFind(id<RCTComponent> view, int (^block)(id<RCTComponent>));
31
32
 
@@ -45,6 +46,7 @@ BOOL REANodeFind(id<RCTComponent> view, int (^block)(id<RCTComponent>));
45
46
  isSharedTransition:(BOOL)isSharedTransition;
46
47
  - (void)setFindPrecedingViewTagForTransitionBlock:
47
48
  (REAFindPrecedingViewTagForTransitionBlock)findPrecedingViewTagForTransition;
49
+ - (void)setGetSharedGroupBlock:(REAGetSharedGroupBlock)getSharedGroupBlock;
48
50
  - (void)setCancelAnimationBlock:(REACancelAnimationBlock)animationCancellingBlock;
49
51
  - (void)endLayoutAnimationForTag:(NSNumber *_Nonnull)tag removeView:(BOOL)removeView;
50
52
  - (void)endAnimationsRecursive:(REAUIView *)view;
@@ -600,6 +600,11 @@ BOOL REANodeFind(id<RCTComponent> view, int (^block)(id<RCTComponent>))
600
600
  [_sharedTransitionManager setFindPrecedingViewTagForTransitionBlock:findPrecedingViewTagForTransition];
601
601
  }
602
602
 
603
+ - (void)setGetSharedGroupBlock:(REAGetSharedGroupBlock)getSharedGroupBlock
604
+ {
605
+ [_sharedTransitionManager setGetSharedGroupBlock:getSharedGroupBlock];
606
+ }
607
+
603
608
  - (void)setCancelAnimationBlock:(REACancelAnimationBlock)animationCancellingBlock
604
609
  {
605
610
  [_sharedTransitionManager setCancelAnimationBlock:animationCancellingBlock];
@@ -3,7 +3,9 @@
3
3
  || (RCT_NEW_ARCH_ENABLED && __has_include(<RNScreens/RNSScreen.h>) && __cplusplus))
4
4
 
5
5
  #if LOAD_SCREENS_HEADERS
6
+ #import <RNScreens/RNSEnums.h>
6
7
  #import <RNScreens/RNSScreen.h>
8
+ #import <RNScreens/RNSScreenNavigationContainer.h>
7
9
  #import <RNScreens/RNSScreenStack.h>
8
10
  #endif
9
11
 
@@ -17,5 +19,9 @@
17
19
  + (REAUIView *)getScreenWrapper:(REAUIView *)view;
18
20
  + (int)getScreenType:(REAUIView *)screen;
19
21
  + (bool)isRNSScreenType:(REAUIView *)screen;
22
+ + (REAUIView *)findTopScreenInChildren:(REAUIView *)screen;
23
+ + (REAUIView *)getActiveTabForTabNavigator:(REAUIView *)tabNavigator;
24
+ + (bool)isView:(REAUIView *)view DescendantOfScreen:(REAUIView *)screen;
25
+ + (bool)isViewOnTopOfScreenStack:(REAUIView *)view;
20
26
 
21
27
  @end
@@ -18,6 +18,9 @@
18
18
 
19
19
  + (REAUIView *)getStackForView:(REAUIView *)view
20
20
  {
21
+ if (view == nil) {
22
+ return nil;
23
+ }
21
24
  if ([view isKindOfClass:[RNSScreenView class]]) {
22
25
  if (view.reactSuperview != nil) {
23
26
  if ([view.reactSuperview isKindOfClass:[RNSScreenStackView class]]) {
@@ -25,11 +28,19 @@
25
28
  }
26
29
  }
27
30
  }
28
- while (view != nil && ![view isKindOfClass:[RNSScreenStackView class]] && view.superview != nil) {
29
- view = view.superview;
31
+ REAUIView *currentView = view;
32
+ while (currentView.reactSuperview != nil) {
33
+ if ([currentView isKindOfClass:[RNSScreenStackView class]]) {
34
+ return currentView;
35
+ }
36
+ currentView = currentView.reactSuperview;
30
37
  }
31
- if ([view isKindOfClass:[RNSScreenStackView class]]) {
32
- return view;
38
+ currentView = view;
39
+ while (currentView.superview != nil) {
40
+ if ([currentView isKindOfClass:[RNSScreenStackView class]]) {
41
+ return currentView;
42
+ }
43
+ currentView = currentView.superview;
33
44
  }
34
45
  return nil;
35
46
  }
@@ -69,6 +80,83 @@
69
80
  return [view isKindOfClass:[RNSScreen class]] == YES;
70
81
  }
71
82
 
83
+ + (REAUIView *)getActiveTabForTabNavigator:(REAUIView *)tabNavigator
84
+ {
85
+ NSArray<REAUIView *> *screenTabs = tabNavigator.reactSubviews;
86
+ for (RNSScreenView *tab in screenTabs) {
87
+ if (tab.activityState == RNSActivityStateOnTop) {
88
+ return tab;
89
+ }
90
+ }
91
+ return nil;
92
+ }
93
+
94
+ + (REAUIView *)findTopScreenInChildren:(REAUIView *)view
95
+ {
96
+ for (REAUIView *child in view.reactSubviews) {
97
+ if ([child isKindOfClass:[RNSScreenStackView class]]) {
98
+ int screenCount = [child.reactSubviews count];
99
+ if (screenCount != 0) {
100
+ REAUIView *topScreen = child.reactSubviews[[child.reactSubviews count] - 1];
101
+ REAUIView *maybeChildScreen = [REAScreensHelper findTopScreenInChildren:topScreen];
102
+ if (maybeChildScreen) {
103
+ return maybeChildScreen;
104
+ }
105
+ if (topScreen) {
106
+ return topScreen;
107
+ }
108
+ }
109
+ }
110
+ REAUIView *topScreen = [REAScreensHelper findTopScreenInChildren:child];
111
+ if (topScreen != nil) {
112
+ return topScreen;
113
+ }
114
+ }
115
+ if ([view isKindOfClass:[RNSScreenView class]]) {
116
+ return view;
117
+ }
118
+ return nil;
119
+ }
120
+
121
+ + (bool)isView:(REAUIView *)view DescendantOfScreen:(REAUIView *)screen
122
+ {
123
+ REAUIView *currentView = view;
124
+ while (currentView.reactSuperview) {
125
+ if (currentView == screen) {
126
+ return true;
127
+ }
128
+ currentView = currentView.reactSuperview;
129
+ }
130
+ return false;
131
+ }
132
+
133
+ + (bool)isViewOnTopOfScreenStack:(REAUIView *)view
134
+ {
135
+ NSMutableArray<REAUIView *> *screens = [NSMutableArray new];
136
+ REAUIView *currentView = view;
137
+ while (currentView.reactSuperview != nil) {
138
+ if ([currentView isKindOfClass:[RNSScreenView class]]) {
139
+ [screens addObject:currentView];
140
+ }
141
+ currentView = currentView.reactSuperview;
142
+ }
143
+ for (int i = 0; i < [screens count]; i++) {
144
+ REAUIView *screen = screens[i];
145
+ REAUIView *container = screen.reactSuperview;
146
+ if ([container isKindOfClass:[RNSScreenStackView class]]) {
147
+ if (screen.reactSuperview.reactSubviews.lastObject != screen) {
148
+ return false;
149
+ }
150
+ }
151
+ if ([container isKindOfClass:[RNSScreenNavigationContainerView class]]) {
152
+ if ([REAScreensHelper getActiveTabForTabNavigator:container] != screen) {
153
+ return false;
154
+ }
155
+ }
156
+ }
157
+ return true;
158
+ }
159
+
72
160
  #else
73
161
 
74
162
  + (REAUIView *)getScreenForView:(REAUIView *)view
@@ -10,6 +10,7 @@
10
10
  - (void)setFindPrecedingViewTagForTransitionBlock:
11
11
  (REAFindPrecedingViewTagForTransitionBlock)findPrecedingViewTagForTransition;
12
12
  - (void)setCancelAnimationBlock:(REACancelAnimationBlock)cancelAnimationBlock;
13
+ - (void)setGetSharedGroupBlock:(REAGetSharedGroupBlock)getSharedGroupBlock;
13
14
  - (instancetype)initWithAnimationsManager:(REAAnimationsManager *)animationManager;
14
15
  - (REAUIView *)getTransitioningView:(NSNumber *)tag;
15
16
  - (NSDictionary *)prepareDataForWorklet:(NSMutableDictionary *)currentValues
@@ -11,6 +11,7 @@
11
11
  NSMutableDictionary<NSNumber *, REAUIView *> *_currentSharedTransitionViews;
12
12
  REAFindPrecedingViewTagForTransitionBlock _findPrecedingViewTagForTransition;
13
13
  REACancelAnimationBlock _cancelLayoutAnimation;
14
+ REAGetSharedGroupBlock _getSharedGroupBlock;
14
15
  REAUIView *_transitionContainer;
15
16
  NSMutableArray<REAUIView *> *_addedSharedViews;
16
17
  BOOL _isSharedTransitionActive;
@@ -29,7 +30,8 @@
29
30
  BOOL _isAsyncSharedTransitionConfigured;
30
31
  BOOL _clearScreen;
31
32
  BOOL _isInteractive;
32
- REAUIView *_disappearingScreen;
33
+ NSMutableArray<REAUIView *> *_disappearingScreens;
34
+ BOOL _isTabNavigator;
33
35
  }
34
36
 
35
37
  /*
@@ -68,6 +70,21 @@ static BOOL _isConfigured = NO;
68
70
  _reattachedViews = [NSMutableSet new];
69
71
  _isAsyncSharedTransitionConfigured = NO;
70
72
  _isConfigured = NO;
73
+ _disappearingScreens = [NSMutableArray new];
74
+ _isTabNavigator = NO;
75
+ _findPrecedingViewTagForTransition = ^NSNumber *(NSNumber *tag)
76
+ {
77
+ // default implementation, this block will be replaced by a setter
78
+ return nil;
79
+ };
80
+ _cancelLayoutAnimation = ^(NSNumber *tag) {
81
+ // default implementation, this block will be replaced by a setter
82
+ };
83
+ _getSharedGroupBlock = ^NSArray<NSNumber *> *(NSNumber *tag)
84
+ {
85
+ // default implementation, this block will be replaced by a setter
86
+ return nil;
87
+ };
71
88
  [self swizzleScreensMethods];
72
89
  }
73
90
  return self;
@@ -240,6 +257,8 @@ static BOOL _isConfigured = NO;
240
257
  }
241
258
  } while (siblingView == nil && siblingViewTag != nil);
242
259
 
260
+ siblingView = [self maybeOverrideSiblingForTabNavigator:sharedView siblingView:siblingView];
261
+
243
262
  if (siblingView == nil) {
244
263
  // the sibling of shared view doesn't exist yet
245
264
  continue;
@@ -276,14 +295,18 @@ static BOOL _isConfigured = NO;
276
295
  // check valid target screen configuration
277
296
  int screensCount = [stack.reactSubviews count];
278
297
  if (addedNewScreen && !isModal) {
279
- // is under top
280
- if (screensCount < 2) {
281
- continue;
282
- }
283
- REAUIView *viewSourceParentScreen = [REAScreensHelper getScreenForView:viewSource];
284
- REAUIView *screenUnderStackTop = stack.reactSubviews[screensCount - 2];
285
- if (![screenUnderStackTop.reactTag isEqual:viewSourceParentScreen.reactTag] && !isInCurrentTransition) {
286
- continue;
298
+ REAUIView *sourceStack = [REAScreensHelper getStackForView:viewSource];
299
+ REAUIView *targetStack = [REAScreensHelper getStackForView:viewTarget];
300
+ if (sourceStack == targetStack) {
301
+ // is under top
302
+ if (screensCount < 2) {
303
+ continue;
304
+ }
305
+ REAUIView *viewSourceParentScreen = [REAScreensHelper getScreenForView:viewSource];
306
+ REAUIView *screenUnderStackTop = stack.reactSubviews[screensCount - 2];
307
+ if (![screenUnderStackTop.reactTag isEqual:viewSourceParentScreen.reactTag] && !isInCurrentTransition) {
308
+ continue;
309
+ }
287
310
  }
288
311
  } else if (!addedNewScreen && !isModal) {
289
312
  // is on top
@@ -358,6 +381,49 @@ static BOOL _isConfigured = NO;
358
381
  return newSharedElements;
359
382
  }
360
383
 
384
+ - (REAUIView *)maybeOverrideSiblingForTabNavigator:(REAUIView *)sharedView siblingView:(REAUIView *)siblingView
385
+ {
386
+ REAUIView *maybeTabNavigatorForSharedView = [self getTabNavigator:sharedView];
387
+ REAUIView *maybeTabNavigatorForSiblingView = [self getTabNavigator:siblingView];
388
+
389
+ if (!(maybeTabNavigatorForSharedView && maybeTabNavigatorForSiblingView) ||
390
+ maybeTabNavigatorForSharedView != maybeTabNavigatorForSiblingView) {
391
+ return siblingView;
392
+ }
393
+
394
+ NSArray<NSNumber *> *sharedGroup = _getSharedGroupBlock(sharedView.reactTag);
395
+ int siblingIndex = [sharedGroup indexOfObject:siblingView.reactTag];
396
+ REAUIView *activeTab = [REAScreensHelper getActiveTabForTabNavigator:maybeTabNavigatorForSharedView];
397
+ for (int i = siblingIndex; i >= 0; i--) {
398
+ NSNumber *viewTag = sharedGroup[i];
399
+ REAUIView *view = [_animationManager viewForTag:viewTag];
400
+ if ([REAScreensHelper isView:view DescendantOfScreen:activeTab]) {
401
+ return view;
402
+ }
403
+ }
404
+ return nil;
405
+ }
406
+
407
+ - (REAUIView *)getTabNavigator:(REAUIView *)view
408
+ {
409
+ REAUIView *currentView = view;
410
+ while (currentView.superview) {
411
+ if ([currentView isKindOfClass:NSClassFromString(@"RNSScreenNavigationContainerView")]) {
412
+ return currentView;
413
+ }
414
+ currentView = (REAUIView *)currentView.superview;
415
+ }
416
+
417
+ currentView = view;
418
+ while (currentView.reactSuperview) {
419
+ if ([currentView isKindOfClass:NSClassFromString(@"RNSScreenNavigationContainerView")]) {
420
+ return currentView;
421
+ }
422
+ currentView = (REAUIView *)currentView.reactSuperview;
423
+ }
424
+ return nil;
425
+ }
426
+
361
427
  /*
362
428
  Method swizzling is used to get notification from react-native-screens
363
429
  about push or pop screen from stack.
@@ -365,19 +431,19 @@ static BOOL _isConfigured = NO;
365
431
  - (void)swizzleScreensMethods
366
432
  {
367
433
  #if LOAD_SCREENS_HEADERS
368
- static dispatch_once_t onceToken;
369
- dispatch_once(&onceToken, ^{
370
- SEL viewDidLayoutSubviewsSelector = @selector(viewDidLayoutSubviews);
371
- SEL notifyWillDisappearSelector = @selector(notifyWillDisappear);
372
- SEL viewIsAppearingSelector = @selector(viewIsAppearing:);
373
- Class screenClass = [RNSScreen class];
374
- Class screenViewClass = [RNSScreenView class];
375
- BOOL allSelectorsAreAvailable = [RNSScreen instancesRespondToSelector:viewDidLayoutSubviewsSelector] &&
376
- [RNSScreenView instancesRespondToSelector:notifyWillDisappearSelector] &&
377
- [RNSScreen instancesRespondToSelector:viewIsAppearingSelector] &&
378
- [RNSScreenView instancesRespondToSelector:@selector(isModal)]; // used by REAScreenHelper
379
-
380
- if (allSelectorsAreAvailable) {
434
+ SEL viewDidLayoutSubviewsSelector = @selector(viewDidLayoutSubviews);
435
+ SEL notifyWillDisappearSelector = @selector(notifyWillDisappear);
436
+ SEL viewIsAppearingSelector = @selector(viewIsAppearing:);
437
+ Class screenClass = [RNSScreen class];
438
+ Class screenViewClass = [RNSScreenView class];
439
+ BOOL allSelectorsAreAvailable = [RNSScreen instancesRespondToSelector:viewDidLayoutSubviewsSelector] &&
440
+ [RNSScreenView instancesRespondToSelector:notifyWillDisappearSelector] &&
441
+ [RNSScreen instancesRespondToSelector:viewIsAppearingSelector] &&
442
+ [RNSScreenView instancesRespondToSelector:@selector(isModal)]; // used by REAScreenHelper
443
+
444
+ if (allSelectorsAreAvailable) {
445
+ static dispatch_once_t onceToken;
446
+ dispatch_once(&onceToken, ^{
381
447
  [REAUtils swizzleMethod:viewDidLayoutSubviewsSelector
382
448
  forClass:screenClass
383
449
  with:@selector(reanimated_viewDidLayoutSubviews)
@@ -390,21 +456,46 @@ static BOOL _isConfigured = NO;
390
456
  forClass:screenClass
391
457
  with:@selector(reanimated_viewIsAppearing:)
392
458
  fromClass:[self class]];
393
- _isConfigured = YES;
394
- }
395
- });
459
+ });
460
+ _isConfigured = YES;
461
+ }
396
462
  #endif
397
463
  }
398
464
 
399
465
  - (void)setDisappearingScreen:(REAUIView *)view
400
466
  {
401
- _disappearingScreen = view;
467
+ if (view == nil) {
468
+ [_disappearingScreens removeAllObjects];
469
+ } else {
470
+ [_disappearingScreens addObject:view];
471
+ }
402
472
  _isInteractive = [_sharedTransitionManager isInteractiveScreenChange:view];
403
473
  }
404
474
 
405
- - (REAUIView *)getDisappearingScreen
475
+ - (REAUIView *)getLastDisappearingScreen
406
476
  {
407
- return _disappearingScreen;
477
+ int count = [_disappearingScreens count];
478
+ if (count == 0) {
479
+ return nil;
480
+ } else {
481
+ return _disappearingScreens[count - 1];
482
+ }
483
+ }
484
+
485
+ - (NSMutableArray<REAUIView *> *)getDisappearingScreens
486
+ {
487
+ return _disappearingScreens;
488
+ }
489
+
490
+ - (void)dismissAsyncTransition
491
+ {
492
+ _isAsyncSharedTransitionConfigured = NO;
493
+ [_sharedElements removeAllObjects];
494
+ }
495
+
496
+ - (BOOL)isTabNavigator
497
+ {
498
+ return _isTabNavigator;
408
499
  }
409
500
 
410
501
  - (void)setIsInteractive:(BOOL)isInteractive
@@ -422,7 +513,12 @@ static BOOL _isConfigured = NO;
422
513
  // call original method from react-native-screens, self == RNScreen
423
514
  [self reanimated_viewDidLayoutSubviews];
424
515
  REAUIView *screen = [self valueForKey:@"screenView"];
425
- [_sharedTransitionManager screenAddedToStack:screen];
516
+ if ([_sharedTransitionManager isTabNavigator]) {
517
+ [_sharedTransitionManager dismissAsyncTransition];
518
+ [_sharedTransitionManager handleTabNavigatorChange:screen];
519
+ } else {
520
+ [_sharedTransitionManager screenAddedToStack:screen];
521
+ }
426
522
  }
427
523
 
428
524
  - (void)reanimated_notifyWillDisappear
@@ -443,20 +539,129 @@ static BOOL _isConfigured = NO;
443
539
  {
444
540
  // call original method from react-native-screens, self == RNSScreen
445
541
  [self reanimated_viewIsAppearing:animated];
446
- REAUIView *disappearingScreen = [_sharedTransitionManager getDisappearingScreen];
542
+ REAUIView *disappearingScreen = [_sharedTransitionManager getLastDisappearingScreen];
447
543
  REAUIView *targetScreen = [self valueForKey:@"screenView"];
448
- if (disappearingScreen != NULL) {
449
- [_sharedTransitionManager screenRemovedFromStack:disappearingScreen
450
- withOffsetX:-targetScreen.superview.frame.origin.x
451
- withOffsetY:-targetScreen.superview.frame.origin.y];
544
+
545
+ if (disappearingScreen == nil) {
546
+ [_sharedTransitionManager setDisappearingScreen:nil];
547
+ return;
452
548
  }
453
- [_sharedTransitionManager setDisappearingScreen:NULL];
549
+
550
+ NSArray *disappearingScreens = [_sharedTransitionManager getDisappearingScreens];
551
+ REAUIView *firstScreen = disappearingScreens[0];
552
+ if ([firstScreen.reactSuperview isKindOfClass:NSClassFromString(@"RNSScreenNavigationContainerView")]) {
553
+ [_sharedTransitionManager handleTabNavigatorChange:nil];
554
+ return;
555
+ }
556
+ float transitionViewOffsetX = 0;
557
+ if ([REAScreensHelper getStackForView:disappearingScreen] != [REAScreensHelper getStackForView:targetScreen]) {
558
+ transitionViewOffsetX = [_sharedTransitionManager getTransitionViewOffset:targetScreen];
559
+ }
560
+ [_sharedTransitionManager screenRemovedFromStack:disappearingScreen
561
+ withOffsetX:-(targetScreen.superview.frame.origin.x + transitionViewOffsetX)
562
+ withOffsetY:-(targetScreen.superview.frame.origin.y)];
563
+ [_sharedTransitionManager setDisappearingScreen:nil];
564
+ }
565
+
566
+ - (void)handleTabNavigatorChange:(REAUIView *)layoutedScreen
567
+ {
568
+ if (_isAsyncSharedTransitionConfigured) {
569
+ // this is a new screen, let wait until header will be attached to a screen to make a proper snapshots
570
+ _isTabNavigator = YES;
571
+ return;
572
+ }
573
+
574
+ REAUIView *navTabScreen = _disappearingScreens[0];
575
+ REAUIView *sourceScreen = _disappearingScreens[[_disappearingScreens count] - 1];
576
+ REAUIView *targetTabScreen = [REAScreensHelper getActiveTabForTabNavigator:navTabScreen.reactSuperview];
577
+ REAUIView *targetScreen = [REAScreensHelper findTopScreenInChildren:targetTabScreen];
578
+ if (!layoutedScreen && _isTabNavigator) {
579
+ // just wait for the next layout computation for your screen
580
+ return;
581
+ }
582
+
583
+ NSMutableArray<REAUIView *> *sharedViews = [NSMutableArray new];
584
+ REANodeFind(sourceScreen, ^int(id<RCTComponent> view) {
585
+ if ([self->_animationManager hasAnimationForTag:view.reactTag type:SHARED_ELEMENT_TRANSITION]) {
586
+ [sharedViews addObject:(REAUIView *)view];
587
+ }
588
+ return false;
589
+ });
590
+ sharedViews = (NSMutableArray<REAUIView *> *)[self sortViewsByTags:sharedViews];
591
+
592
+ for (REAUIView *sharedView in sharedViews) {
593
+ NSArray<NSNumber *> *groupTags = _getSharedGroupBlock(sharedView.reactTag);
594
+ if (![groupTags containsObject:sharedView.reactTag]) {
595
+ continue;
596
+ }
597
+ REAUIView *siblingView;
598
+ for (NSNumber *tag in groupTags) {
599
+ REAUIView *currentView = [_animationManager viewForTag:tag];
600
+ if ([REAScreensHelper isView:currentView DescendantOfScreen:targetScreen]) {
601
+ siblingView = currentView;
602
+ REAUIView *siblingScreen = [REAScreensHelper getScreenForView:siblingView];
603
+ if (layoutedScreen && siblingScreen != layoutedScreen) {
604
+ // just wait for the next layout computation for your screen
605
+ return;
606
+ }
607
+ break;
608
+ }
609
+ }
610
+
611
+ if (siblingView == nil) {
612
+ return;
613
+ }
614
+
615
+ REAUIView *viewSource = sharedView;
616
+ REAUIView *viewTarget = siblingView;
617
+ REASnapshot *sourceViewSnapshot = _snapshotRegistry[viewSource.reactTag];
618
+ if (navTabScreen.superview) {
619
+ sourceViewSnapshot = [[REASnapshot alloc] initWithAbsolutePosition:viewSource];
620
+ }
621
+ REASnapshot *targetViewSnapshot = [[REASnapshot alloc] initWithAbsolutePosition:viewTarget];
622
+ REASharedElement *sharedElement = [[REASharedElement alloc] initWithSourceView:viewSource
623
+ sourceViewSnapshot:sourceViewSnapshot
624
+ targetView:viewTarget
625
+ targetViewSnapshot:targetViewSnapshot];
626
+ sharedElement.animationType = SHARED_ELEMENT_TRANSITION;
627
+ [_sharedElements addObject:sharedElement];
628
+
629
+ _snapshotRegistry[viewSource.reactTag] = sourceViewSnapshot;
630
+ _snapshotRegistry[viewTarget.reactTag] = targetViewSnapshot;
631
+ _sharedElementsLookup[viewSource.reactTag] = sharedElement;
632
+ }
633
+
634
+ [self setDisappearingScreen:nil];
635
+ _isTabNavigator = NO;
636
+
637
+ if ([_sharedElements count] == 0) {
638
+ return;
639
+ }
640
+
641
+ [self configureTransitionContainer];
642
+ [self reparentSharedViewsForCurrentTransition:_sharedElements];
643
+ [self startSharedTransition:_sharedElements];
644
+ }
645
+
646
+ - (float)getTransitionViewOffset:(REAUIView *)screen
647
+ {
648
+ float x = 0;
649
+ REAUIView *currentView = screen;
650
+ while (currentView.superview != nil) {
651
+ REAUIView *maybeView = (REAUIView *)currentView.superview.superview;
652
+ if ([maybeView isKindOfClass:NSClassFromString(@"UINavigationTransitionView")]) {
653
+ CGPoint transitionViewOffset = currentView.frame.origin;
654
+ x += transitionViewOffset.x;
655
+ }
656
+ currentView = currentView.superview;
657
+ }
658
+ return x;
454
659
  }
455
660
 
456
661
  - (void)screenAddedToStack:(REAUIView *)screen
457
662
  {
458
663
  if (screen.superview != nil) {
459
- [self runAsyncSharedTransition];
664
+ [self runAsyncSharedTransition:screen];
460
665
  }
461
666
  }
462
667
 
@@ -469,9 +674,9 @@ static BOOL _isConfigured = NO;
469
674
  bool isInteractive = [self getIsInteractive];
470
675
  if ((stack != nil || isModal) && !isRemovedInParentStack) {
471
676
  // screen is removed from React tree (navigation.navigate(<screenName>))
472
- bool isScreenRemovedFromReactTree = [self isScreen:screen outsideStack:stack];
677
+ bool isScreenRemovedFromReactTree = screen.reactSuperview == nil;
473
678
  // click on button goBack on native header
474
- bool isTriggeredByGoBackButton = [self isScreen:screen onTopOfStack:stack];
679
+ bool isTriggeredByGoBackButton = [REAScreensHelper isViewOnTopOfScreenStack:screen];
475
680
  bool shouldRunTransition = (isScreenRemovedFromReactTree || isTriggeredByGoBackButton) &&
476
681
  !(isInteractive && [_currentSharedTransitionViews count] > 0);
477
682
  if (shouldRunTransition) {
@@ -526,22 +731,6 @@ static BOOL _isConfigured = NO;
526
731
  }
527
732
  }
528
733
 
529
- - (BOOL)isScreen:(REAUIView *)screen outsideStack:(REAUIView *)stack
530
- {
531
- for (REAUIView *child in stack.reactSubviews) {
532
- if ([child.reactTag isEqual:screen.reactTag]) {
533
- return NO;
534
- }
535
- }
536
- return YES;
537
- }
538
-
539
- - (BOOL)isScreen:(REAUIView *)screen onTopOfStack:(REAUIView *)stack
540
- {
541
- int screenCount = stack.reactSubviews.count;
542
- return screenCount > 0 && screen == stack.reactSubviews.lastObject;
543
- }
544
-
545
734
  - (BOOL)isRemovedFromHigherStack:(REAUIView *)screen
546
735
  {
547
736
  REAUIView *stack = screen.reactSuperview;
@@ -588,13 +777,18 @@ static BOOL _isConfigured = NO;
588
777
  }
589
778
  }
590
779
 
591
- - (void)runAsyncSharedTransition
780
+ - (void)runAsyncSharedTransition:(REAUIView *)screen
592
781
  {
593
782
  if ([_sharedElements count] == 0 || !_isAsyncSharedTransitionConfigured) {
594
783
  return;
595
784
  }
596
785
  for (REASharedElement *sharedElement in _sharedElements) {
597
786
  REAUIView *viewTarget = sharedElement.targetView;
787
+ REAUIView *viewScreen = [REAScreensHelper getScreenForView:viewTarget];
788
+ if (viewScreen != screen) {
789
+ // just wait for the next layout computation for your screen
790
+ return;
791
+ }
598
792
  REASnapshot *targetViewSnapshot = [[REASnapshot alloc] initWithAbsolutePosition:viewTarget];
599
793
  _snapshotRegistry[viewTarget.reactTag] = targetViewSnapshot;
600
794
  sharedElement.targetViewSnapshot = targetViewSnapshot;
@@ -743,6 +937,11 @@ static BOOL _isConfigured = NO;
743
937
  _cancelLayoutAnimation = cancelAnimationBlock;
744
938
  }
745
939
 
940
+ - (void)setGetSharedGroupBlock:(REAGetSharedGroupBlock)getSharedGroupBlock
941
+ {
942
+ _getSharedGroupBlock = getSharedGroupBlock;
943
+ }
944
+
746
945
  - (void)clearAllSharedConfigsForViewTag:(NSNumber *)viewTag
747
946
  {
748
947
  if (viewTag != nil) {
@@ -211,6 +211,18 @@ void setupLayoutAnimationCallbacks(
211
211
  }
212
212
  return nil;
213
213
  }];
214
+
215
+ [animationsManager setGetSharedGroupBlock:^NSArray<NSNumber *> *_Nullable(NSNumber *_Nonnull tag) {
216
+ if (auto nativeReanimatedModule = weakNativeReanimatedModule.lock()) {
217
+ const auto &results = nativeReanimatedModule->layoutAnimationsManager().getSharedGroup([tag intValue]);
218
+ NSMutableArray<NSNumber *> *convertedResult = [NSMutableArray new];
219
+ for (const int tag : results) {
220
+ [convertedResult addObject:@(tag)];
221
+ }
222
+ return convertedResult;
223
+ }
224
+ return nil;
225
+ }];
214
226
  #ifndef NDEBUG
215
227
  [animationsManager setCheckDuplicateSharedTagBlock:^(REAUIView *view, NSNumber *_Nonnull viewTag) {
216
228
  if (auto nativeReanimatedModule = weakNativeReanimatedModule.lock()) {
@@ -433,7 +433,9 @@ export const rgbaColor = (r, g, b, alpha = 1) => {
433
433
  'worklet';
434
434
 
435
435
  if (IS_WEB || !_WORKLET) {
436
- return `rgba(${r}, ${g}, ${b}, ${alpha})`;
436
+ // Replace tiny values like 1.234e-11 with 0:
437
+ const safeAlpha = alpha < 0.001 ? 0 : alpha;
438
+ return `rgba(${r}, ${g}, ${b}, ${safeAlpha})`;
437
439
  }
438
440
  const c = Math.round(alpha * 255) * (1 << 24) + Math.round(r) * (1 << 16) + Math.round(g) * (1 << 8) + Math.round(b);
439
441
  if (IS_ANDROID) {
@@ -599,7 +601,8 @@ export function convertToRGBA(color) {
599
601
  export function rgbaArrayToRGBAColor(RGBA) {
600
602
  'worklet';
601
603
 
602
- return `rgba(${Math.round(RGBA[0] * 255)}, ${Math.round(RGBA[1] * 255)}, ${Math.round(RGBA[2] * 255)}, ${RGBA[3]})`;
604
+ const alpha = RGBA[3] < 0.001 ? 0 : RGBA[3];
605
+ return `rgba(${Math.round(RGBA[0] * 255)}, ${Math.round(RGBA[1] * 255)}, ${Math.round(RGBA[2] * 255)}, ${alpha})`;
603
606
  }
604
607
  export function toLinearSpace(RGBA, gamma = 2.2) {
605
608
  'worklet';