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
@@ -1,20 +1,28 @@
1
1
  'use strict';
2
2
 
3
- import type { AnimationConfig, AnimationNames, CustomConfig } from './config';
3
+ import type {
4
+ AnimationConfig,
5
+ AnimationNames,
6
+ CustomConfig,
7
+ KeyframeDefinitions,
8
+ } from './config';
4
9
  import { Animations } from './config';
5
10
  import type {
6
11
  AnimatedComponentProps,
7
12
  LayoutAnimationStaticContext,
8
13
  } from '../../createAnimatedComponent/commonTypes';
9
14
  import { LayoutAnimationType } from '../animationBuilder/commonTypes';
15
+ import { createCustomKeyFrameAnimation } from './createAnimation';
10
16
  import {
11
17
  getProcessedConfig,
12
18
  handleExitingAnimation,
13
19
  handleLayoutTransition,
20
+ maybeModifyStyleForKeyframe,
14
21
  setElementAnimation,
15
22
  } from './componentUtils';
16
23
  import { areDOMRectsEqual } from './domUtils';
17
24
  import type { TransitionData } from './animationParser';
25
+ import { Keyframe } from '../animationBuilder';
18
26
  import { makeElementVisible } from './componentStyle';
19
27
 
20
28
  function chooseConfig<ComponentProps extends Record<string, unknown>>(
@@ -35,11 +43,11 @@ function chooseConfig<ComponentProps extends Record<string, unknown>>(
35
43
 
36
44
  function checkUndefinedAnimationFail(
37
45
  initialAnimationName: string,
38
- isLayoutTransition: boolean
46
+ needsCustomization: boolean
39
47
  ) {
40
48
  // This prevents crashes if we try to set animations that are not defined.
41
- // We don't care about layout transitions since they're created dynamically
42
- if (initialAnimationName in Animations || isLayoutTransition) {
49
+ // We don't care about layout transitions or custom keyframes since they're created dynamically
50
+ if (initialAnimationName in Animations || needsCustomization) {
43
51
  return false;
44
52
  }
45
53
 
@@ -86,7 +94,7 @@ function chooseAction(
86
94
  ) {
87
95
  switch (animationType) {
88
96
  case LayoutAnimationType.ENTERING:
89
- setElementAnimation(element, animationConfig);
97
+ setElementAnimation(element, animationConfig, true);
90
98
  break;
91
99
  case LayoutAnimationType.LAYOUT:
92
100
  transitionData.reversed = animationConfig.reversed;
@@ -111,25 +119,48 @@ function tryGetAnimationConfig<ComponentProps extends Record<string, unknown>>(
111
119
  typeof config.constructor;
112
120
 
113
121
  const isLayoutTransition = animationType === LayoutAnimationType.LAYOUT;
114
- const animationName =
115
- typeof config === 'function'
116
- ? config.presetName
117
- : (config.constructor as ConstructorWithStaticContext).presetName;
122
+ const isCustomKeyframe = config instanceof Keyframe;
123
+
124
+ let animationName;
125
+
126
+ if (isCustomKeyframe) {
127
+ animationName = createCustomKeyFrameAnimation(
128
+ (config as CustomConfig).definitions as KeyframeDefinitions
129
+ );
130
+ } else if (typeof config === 'function') {
131
+ animationName = config.presetName;
132
+ } else {
133
+ animationName = (config.constructor as ConstructorWithStaticContext)
134
+ .presetName;
135
+ }
118
136
 
119
137
  const shouldFail = checkUndefinedAnimationFail(
120
138
  animationName,
121
- isLayoutTransition
139
+ isLayoutTransition || isCustomKeyframe
122
140
  );
123
141
 
124
142
  if (shouldFail) {
125
143
  return null;
126
144
  }
127
145
 
146
+ if (isCustomKeyframe) {
147
+ const keyframeTimestamps = Object.keys(
148
+ (config as CustomConfig).definitions as KeyframeDefinitions
149
+ );
150
+
151
+ if (
152
+ !(keyframeTimestamps.includes('100') || keyframeTimestamps.includes('to'))
153
+ ) {
154
+ console.warn(
155
+ `[Reanimated] Neither '100' nor 'to' was specified in Keyframe definition. This may result in wrong final position of your component. One possible solution is to duplicate last timestamp in definition as '100' (or 'to')`
156
+ );
157
+ }
158
+ }
159
+
128
160
  const animationConfig = getProcessedConfig(
129
161
  animationName,
130
162
  animationType,
131
- config as CustomConfig,
132
- animationName as AnimationNames
163
+ config as CustomConfig
133
164
  );
134
165
 
135
166
  return animationConfig;
@@ -145,6 +176,8 @@ export function startWebLayoutAnimation<
145
176
  ) {
146
177
  const animationConfig = tryGetAnimationConfig(props, animationType);
147
178
 
179
+ maybeModifyStyleForKeyframe(element, props.entering as CustomConfig);
180
+
148
181
  if ((animationConfig?.animationName as AnimationNames) in Animations) {
149
182
  maybeReportOverwrittenProperties(
150
183
  Animations[animationConfig?.animationName as AnimationNames].style,
@@ -20,15 +20,12 @@ export const snapshots = new WeakMap<HTMLElement, ReanimatedSnapshot>();
20
20
 
21
21
  export function makeElementVisible(element: HTMLElement, delay: number) {
22
22
  if (delay === 0) {
23
- _updatePropsJS(
24
- { visibility: 'initial' },
25
- { _component: element as ReanimatedHTMLElement }
26
- );
23
+ _updatePropsJS({ visibility: 'initial' }, element as ReanimatedHTMLElement);
27
24
  } else {
28
25
  setTimeout(() => {
29
26
  _updatePropsJS(
30
27
  { visibility: 'initial' },
31
- { _component: element as ReanimatedHTMLElement }
28
+ element as ReanimatedHTMLElement
32
29
  );
33
30
  }, delay * 1000);
34
31
  }
@@ -66,19 +63,19 @@ function fixElementPosition(
66
63
  }
67
64
  }
68
65
 
69
- export function setDummyPosition(
70
- dummy: HTMLElement,
66
+ export function setElementPosition(
67
+ element: HTMLElement,
71
68
  snapshot: ReanimatedSnapshot
72
69
  ) {
73
- dummy.style.transform = '';
74
- dummy.style.position = 'absolute';
75
- dummy.style.top = `${snapshot.top}px`;
76
- dummy.style.left = `${snapshot.left}px`;
77
- dummy.style.width = `${snapshot.width}px`;
78
- dummy.style.height = `${snapshot.height}px`;
79
- dummy.style.margin = '0px'; // tmpElement has absolute position, so margin is not necessary
70
+ element.style.transform = '';
71
+ element.style.position = 'absolute';
72
+ element.style.top = `${snapshot.top}px`;
73
+ element.style.left = `${snapshot.left}px`;
74
+ element.style.width = `${snapshot.width}px`;
75
+ element.style.height = `${snapshot.height}px`;
76
+ element.style.margin = '0px'; // tmpElement has absolute position, so margin is not necessary
80
77
 
81
- if (dummy.parentElement) {
82
- fixElementPosition(dummy, dummy.parentElement, snapshot);
78
+ if (element.parentElement) {
79
+ fixElementPosition(element, element.parentElement, snapshot);
83
80
  }
84
81
  }
@@ -1,13 +1,15 @@
1
1
  'use strict';
2
2
 
3
- import { Animations, TransitionType, WebEasings } from './config';
3
+ import { Animations, TransitionType } from './config';
4
4
  import type {
5
5
  AnimationCallback,
6
6
  AnimationConfig,
7
7
  AnimationNames,
8
8
  CustomConfig,
9
- WebEasingsNames,
9
+ KeyframeDefinitions,
10
10
  } from './config';
11
+ import { WebEasings } from './Easing.web';
12
+ import type { WebEasingsNames } from './Easing.web';
11
13
  import type { TransitionData } from './animationParser';
12
14
  import { TransitionGenerator } from './createAnimation';
13
15
  import { scheduleAnimationCleanup } from './domUtils';
@@ -17,7 +19,8 @@ import { ReduceMotion } from '../../commonTypes';
17
19
  import { isReducedMotion } from '../../PlatformChecker';
18
20
  import { LayoutAnimationType } from '../animationBuilder/commonTypes';
19
21
  import type { ReanimatedSnapshot, ScrollOffsets } from './componentStyle';
20
- import { setDummyPosition, snapshots } from './componentStyle';
22
+ import { setElementPosition, snapshots } from './componentStyle';
23
+ import { Keyframe } from '../animationBuilder';
21
24
 
22
25
  function getEasingFromConfig(config: CustomConfig): string {
23
26
  const easingName =
@@ -63,12 +66,15 @@ export function getReducedMotionFromConfig(config: CustomConfig) {
63
66
 
64
67
  function getDurationFromConfig(
65
68
  config: CustomConfig,
66
- isLayoutTransition: boolean,
67
- animationName: AnimationNames
69
+ animationName: string
68
70
  ): number {
69
- const defaultDuration = isLayoutTransition
70
- ? 0.3
71
- : Animations[animationName].duration;
71
+ // Duration in keyframe has to be in seconds. However, when using `.duration()` modifier we pass it in miliseconds.
72
+ // If `duration` was specified in config, we have to divide it by `1000`, otherwise we return value that is already in seconds.
73
+
74
+ const defaultDuration =
75
+ animationName in Animations
76
+ ? Animations[animationName as AnimationNames].duration
77
+ : 0.3;
72
78
 
73
79
  return config.durationV !== undefined
74
80
  ? config.durationV / 1000
@@ -86,17 +92,12 @@ function getReversedFromConfig(config: CustomConfig) {
86
92
  export function getProcessedConfig(
87
93
  animationName: string,
88
94
  animationType: LayoutAnimationType,
89
- config: CustomConfig,
90
- initialAnimationName: AnimationNames
95
+ config: CustomConfig
91
96
  ): AnimationConfig {
92
97
  return {
93
98
  animationName,
94
99
  animationType,
95
- duration: getDurationFromConfig(
96
- config,
97
- animationType === LayoutAnimationType.LAYOUT,
98
- initialAnimationName
99
- ),
100
+ duration: getDurationFromConfig(config, animationName),
100
101
  delay: getDelayFromConfig(config),
101
102
  easing: getEasingFromConfig(config),
102
103
  callback: getCallbackFromConfig(config),
@@ -104,6 +105,28 @@ export function getProcessedConfig(
104
105
  };
105
106
  }
106
107
 
108
+ export function maybeModifyStyleForKeyframe(
109
+ element: HTMLElement,
110
+ config: CustomConfig
111
+ ) {
112
+ if (!(config instanceof Keyframe)) {
113
+ return;
114
+ }
115
+
116
+ // We need to set `animationFillMode` to `forwards`, otherwise component will go back to its position.
117
+ // This will result in wrong snapshot
118
+ element.style.animationFillMode = 'forwards';
119
+
120
+ for (const timestampRules of Object.values(
121
+ config.definitions as KeyframeDefinitions
122
+ )) {
123
+ if ('originX' in timestampRules || 'originY' in timestampRules) {
124
+ element.style.position = 'absolute';
125
+ return;
126
+ }
127
+ }
128
+ }
129
+
107
130
  export function saveSnapshot(element: HTMLElement) {
108
131
  const rect = element.getBoundingClientRect();
109
132
 
@@ -120,16 +143,31 @@ export function saveSnapshot(element: HTMLElement) {
120
143
 
121
144
  export function setElementAnimation(
122
145
  element: HTMLElement,
123
- animationConfig: AnimationConfig
146
+ animationConfig: AnimationConfig,
147
+ shouldSavePosition = false
124
148
  ) {
125
149
  const { animationName, duration, delay, easing } = animationConfig;
126
150
 
127
- element.style.animationName = animationName;
128
- element.style.animationDuration = `${duration}s`;
129
- element.style.animationDelay = `${delay}s`;
130
- element.style.animationTimingFunction = easing;
151
+ const configureAnimation = () => {
152
+ element.style.animationName = animationName;
153
+ element.style.animationDuration = `${duration}s`;
154
+ element.style.animationDelay = `${delay}s`;
155
+ element.style.animationTimingFunction = easing;
156
+ };
157
+
158
+ if (animationConfig.animationType === LayoutAnimationType.ENTERING) {
159
+ // On chrome sometimes entering animations flicker. This is most likely caused by animation being interrupted
160
+ // by already started tasks. To avoid flickering, we use `requestAnimationFrame`, which will run callback right before repaint.
161
+ requestAnimationFrame(configureAnimation);
162
+ } else {
163
+ configureAnimation();
164
+ }
131
165
 
132
166
  element.onanimationend = () => {
167
+ if (shouldSavePosition) {
168
+ saveSnapshot(element);
169
+ }
170
+
133
171
  animationConfig.callback?.(true);
134
172
  element.removeEventListener('animationcancel', animationCancelHandler);
135
173
  };
@@ -144,7 +182,7 @@ export function setElementAnimation(
144
182
  if (animationConfig.animationType === LayoutAnimationType.ENTERING) {
145
183
  _updatePropsJS(
146
184
  { visibility: 'initial' },
147
- { _component: element as ReanimatedHTMLElement }
185
+ element as ReanimatedHTMLElement
148
186
  );
149
187
  }
150
188
 
@@ -152,7 +190,11 @@ export function setElementAnimation(
152
190
  };
153
191
 
154
192
  if (!(animationName in Animations)) {
155
- scheduleAnimationCleanup(animationName, duration + delay);
193
+ scheduleAnimationCleanup(animationName, duration + delay, () => {
194
+ if (shouldSavePosition) {
195
+ setElementPosition(element, snapshots.get(element)!);
196
+ }
197
+ });
156
198
  }
157
199
  }
158
200
 
@@ -175,6 +217,9 @@ export function handleLayoutTransition(
175
217
  case 'FadingTransition':
176
218
  animationType = TransitionType.FADING;
177
219
  break;
220
+ case 'JumpingTransition':
221
+ animationType = TransitionType.JUMPING;
222
+ break;
178
223
  default:
179
224
  animationType = TransitionType.LINEAR;
180
225
  break;
@@ -220,8 +265,6 @@ export function handleExitingAnimation(
220
265
  dummy.reanimatedDummy = true;
221
266
 
222
267
  element.style.animationName = '';
223
- // We hide current element so only its copy with proper animation will be displayed
224
- element.style.visibility = 'hidden';
225
268
 
226
269
  // After cloning the element, we want to move all children from original element to its clone. This is because original element
227
270
  // will be unmounted, therefore when this code executes in child component, parent will be either empty or removed soon.
@@ -260,7 +303,7 @@ export function handleExitingAnimation(
260
303
 
261
304
  snapshots.set(dummy, snapshot);
262
305
 
263
- setDummyPosition(dummy, snapshot);
306
+ setElementPosition(dummy, snapshot);
264
307
 
265
308
  const originalOnAnimationEnd = dummy.onanimationend;
266
309
 
@@ -37,10 +37,12 @@ import {
37
37
  } from './animation/Stretch.web';
38
38
  import { ZoomIn, ZoomInData, ZoomOut, ZoomOutData } from './animation/Zoom.web';
39
39
 
40
- import type { AnimationData } from './animationParser';
40
+ import type { AnimationData, AnimationStyle } from './animationParser';
41
41
 
42
42
  export type AnimationCallback = ((finished: boolean) => void) | null;
43
43
 
44
+ export type KeyframeDefinitions = Record<number, AnimationStyle>;
45
+
44
46
  export interface AnimationConfig {
45
47
  animationName: string;
46
48
  animationType: LayoutAnimationType;
@@ -59,12 +61,14 @@ export interface CustomConfig {
59
61
  reduceMotionV?: ReduceMotion;
60
62
  callbackV?: AnimationCallback;
61
63
  reversed?: boolean;
64
+ definitions?: KeyframeDefinitions;
62
65
  }
63
66
 
64
67
  export enum TransitionType {
65
68
  LINEAR,
66
69
  SEQUENCED,
67
70
  FADING,
71
+ JUMPING,
68
72
  }
69
73
 
70
74
  export const AnimationsData: Record<string, AnimationData> = {
@@ -111,18 +115,5 @@ export const Animations = {
111
115
  ...RollOut,
112
116
  };
113
117
 
114
- // Those are the easings that can be implemented using Bezier curves.
115
- // Others should be done as CSS animations
116
- export const WebEasings = {
117
- linear: [0, 0, 1, 1],
118
- ease: [0.42, 0, 1, 1],
119
- quad: [0.11, 0, 0.5, 0],
120
- cubic: [0.32, 0, 0.67, 0],
121
- sin: [0.12, 0, 0.39, 0],
122
- circle: [0.55, 0, 1, 0.45],
123
- exp: [0.7, 0, 0.84, 0],
124
- };
125
-
126
118
  export type AnimationNames = keyof typeof Animations;
127
119
  export type LayoutTransitionsNames = keyof typeof AnimationsData;
128
- export type WebEasingsNames = keyof typeof WebEasings;
@@ -1,8 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  import { TransitionType } from './config';
4
+ import type { KeyframeDefinitions } from './config';
4
5
  import { convertAnimationObjectToKeyframes } from './animationParser';
5
6
  import type {
7
+ AnimationData,
6
8
  ReanimatedWebTransformProperties,
7
9
  TransitionData,
8
10
  } from './animationParser';
@@ -10,16 +12,17 @@ import type { TransformsStyle } from 'react-native';
10
12
  import { LinearTransition } from './transition/Linear.web';
11
13
  import { SequencedTransition } from './transition/Sequenced.web';
12
14
  import { FadingTransition } from './transition/Fading.web';
15
+ import { JumpingTransition } from './transition/Jumping.web';
13
16
  import { insertWebAnimation } from './domUtils';
14
17
 
18
+ type TransformType = NonNullable<TransformsStyle['transform']>;
19
+
15
20
  // Translate values are passed as numbers. However, if `translate` property receives number, it will not automatically
16
21
  // convert it to `px`. Therefore if we want to keep transform we have to add 'px' suffix to each of translate values
17
22
  // that are present inside transform.
18
23
  //
19
24
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
20
- function addPxToTranslate(
21
- transform: NonNullable<TransformsStyle['transform']>
22
- ) {
25
+ function addPxToTranslate(transform: TransformType) {
23
26
  type RNTransformProp = (typeof transform)[number];
24
27
 
25
28
  // @ts-ignore `existingTransform` cannot be string because in that case
@@ -27,7 +30,7 @@ function addPxToTranslate(
27
30
  const newTransform = transform.map((transformProp: RNTransformProp) => {
28
31
  const newTransformProp: ReanimatedWebTransformProperties = {};
29
32
  for (const [key, value] of Object.entries(transformProp)) {
30
- if (key.includes('translate')) {
33
+ if (key.includes('translate') && typeof value === 'number') {
31
34
  // @ts-ignore After many trials we decided to ignore this error - it says that we cannot use 'key' to index this object.
32
35
  // Sadly it doesn't go away after using cast `key as keyof TransformProperties`.
33
36
  newTransformProp[key] = `${value}px`;
@@ -42,6 +45,30 @@ function addPxToTranslate(
42
45
  return newTransform;
43
46
  }
44
47
 
48
+ export function createCustomKeyFrameAnimation(
49
+ keyframeDefinitions: KeyframeDefinitions
50
+ ) {
51
+ for (const value of Object.values(keyframeDefinitions)) {
52
+ if (value.transform) {
53
+ value.transform = addPxToTranslate(value.transform as TransformType);
54
+ }
55
+ }
56
+
57
+ const animationData: AnimationData = {
58
+ name: '',
59
+ style: keyframeDefinitions,
60
+ duration: -1,
61
+ };
62
+
63
+ animationData.name = generateNextCustomKeyframeName();
64
+
65
+ const parsedKeyframe = convertAnimationObjectToKeyframes(animationData);
66
+
67
+ insertWebAnimation(animationData.name, parsedKeyframe);
68
+
69
+ return animationData.name;
70
+ }
71
+
45
72
  let customKeyframeCounter = 0;
46
73
 
47
74
  function generateNextCustomKeyframeName() {
@@ -81,6 +108,13 @@ export function TransitionGenerator(
81
108
  transitionData
82
109
  );
83
110
  break;
111
+
112
+ case TransitionType.JUMPING:
113
+ transitionObject = JumpingTransition(
114
+ transitionKeyframeName,
115
+ transitionData
116
+ );
117
+ break;
84
118
  }
85
119
 
86
120
  const transitionKeyframe =
@@ -2,7 +2,7 @@
2
2
 
3
3
  import type { ReanimatedHTMLElement } from '../../js-reanimated';
4
4
  import { isWindowAvailable } from '../../PlatformChecker';
5
- import { setDummyPosition, snapshots } from './componentStyle';
5
+ import { setElementPosition, snapshots } from './componentStyle';
6
6
  import { Animations } from './config';
7
7
  import type { AnimationNames } from './config';
8
8
 
@@ -85,7 +85,10 @@ export function insertWebAnimation(animationName: string, keyframe: string) {
85
85
  }
86
86
  }
87
87
 
88
- function removeWebAnimation(animationName: string) {
88
+ function removeWebAnimation(
89
+ animationName: string,
90
+ animationRemoveCallback: () => void
91
+ ) {
89
92
  // Without this check SSR crashes because document is undefined (NextExample on CI)
90
93
  if (!isWindowAvailable()) {
91
94
  return;
@@ -101,7 +104,10 @@ function removeWebAnimation(animationName: string) {
101
104
  throw new Error('[Reanimated] Failed to obtain animation index.');
102
105
  }
103
106
 
107
+ animationRemoveCallback();
108
+
104
109
  styleTag.sheet?.deleteRule(currentAnimationIndex);
110
+
105
111
  animationNameList.splice(currentAnimationIndex, 1);
106
112
  animationNameToIndex.delete(animationName);
107
113
 
@@ -123,7 +129,8 @@ const minimumFrames = 10;
123
129
 
124
130
  export function scheduleAnimationCleanup(
125
131
  animationName: string,
126
- animationDuration: number
132
+ animationDuration: number,
133
+ animationRemoveCallback: () => void
127
134
  ) {
128
135
  // If duration is very short, we want to keep remove delay to at least 10 frames
129
136
  // In our case it is exactly 160/1099 s, which is approximately 0.15s
@@ -132,7 +139,10 @@ export function scheduleAnimationCleanup(
132
139
  animationDuration + frameDurationMs * minimumFrames
133
140
  );
134
141
 
135
- setTimeout(() => removeWebAnimation(animationName), timeoutValue);
142
+ setTimeout(
143
+ () => removeWebAnimation(animationName, animationRemoveCallback),
144
+ timeoutValue
145
+ );
136
146
  }
137
147
 
138
148
  function reattachElementToAncestor(child: ReanimatedHTMLElement, parent: Node) {
@@ -147,7 +157,7 @@ function reattachElementToAncestor(child: ReanimatedHTMLElement, parent: Node) {
147
157
  child.removedAfterAnimation = true;
148
158
  parent.appendChild(child);
149
159
 
150
- setDummyPosition(child, childSnapshot);
160
+ setElementPosition(child, childSnapshot);
151
161
 
152
162
  const originalOnAnimationEnd = child.onanimationend;
153
163
 
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+ import type { TransitionData } from '../animationParser';
3
+ import { Easing } from '../../../Easing';
4
+
5
+ export function JumpingTransition(
6
+ name: string,
7
+ transitionData: TransitionData
8
+ ) {
9
+ const { translateX, translateY, scaleX, scaleY } = transitionData;
10
+
11
+ const d = Math.max(Math.abs(translateX), Math.abs(translateY)) / 2;
12
+ const peakTranslateY = translateY <= 0 ? translateY - d : -translateY + d;
13
+
14
+ const jumpingTransition = {
15
+ name,
16
+ style: {
17
+ 0: {
18
+ transform: [
19
+ {
20
+ translateX: `${translateX}px`,
21
+ translateY: `${translateY}px`,
22
+ scale: `${scaleX},${scaleY}`,
23
+ },
24
+ ],
25
+ easing: Easing.exp,
26
+ },
27
+ 50: {
28
+ transform: [
29
+ {
30
+ translateX: `${translateX / 2}px`,
31
+ translateY: `${peakTranslateY}px`,
32
+ scale: `${scaleX},${scaleY}`,
33
+ },
34
+ ],
35
+ },
36
+ 100: {
37
+ transform: [{ translateX: '0px', translateY: '0px', scale: '1,1' }],
38
+ },
39
+ },
40
+ duration: 300,
41
+ };
42
+
43
+ return jumpingTransition;
44
+ }
@@ -1,3 +1,3 @@
1
1
  'use strict';
2
2
  // RNRender is not used for web. An export is still defined to eliminate warnings from bundlers such as esbuild.
3
- module.exports = null;
3
+ export {};
@@ -4,4 +4,4 @@
4
4
  * with the version used to build the native part of the library in runtime.
5
5
  * Remember to keep this in sync with the version declared in `package.json`
6
6
  */
7
- export const jsVersion = '3.13.0-rc.2';
7
+ export const jsVersion = '3.13.0';
@@ -10,5 +10,5 @@ export function setNativeProps<T extends Component>(
10
10
  updates: StyleProps
11
11
  ) {
12
12
  const component = animatedRef() as ReanimatedHTMLElement;
13
- _updatePropsJS(updates, { _component: component });
13
+ _updatePropsJS(updates, component);
14
14
  }