react-native-reanimated 4.2.0 → 4.2.1

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 (59) hide show
  1. package/lib/module/common/style/config.js +10 -1
  2. package/lib/module/common/style/config.js.map +1 -1
  3. package/lib/module/common/web/index.js +1 -0
  4. package/lib/module/common/web/index.js.map +1 -1
  5. package/lib/module/common/web/utils/dom.js +16 -0
  6. package/lib/module/common/web/utils/dom.js.map +1 -0
  7. package/lib/module/common/web/utils/index.js +1 -0
  8. package/lib/module/common/web/utils/index.js.map +1 -1
  9. package/lib/module/createAnimatedComponent/AnimatedComponent.js +2 -2
  10. package/lib/module/createAnimatedComponent/AnimatedComponent.js.map +1 -1
  11. package/lib/module/css/native/managers/CSSAnimationsManager.js +3 -3
  12. package/lib/module/css/native/managers/CSSAnimationsManager.js.map +1 -1
  13. package/lib/module/css/web/managers/CSSAnimationsManager.js +2 -6
  14. package/lib/module/css/web/managers/CSSAnimationsManager.js.map +1 -1
  15. package/lib/module/layoutReanimation/web/animationsManager.js +2 -2
  16. package/lib/module/layoutReanimation/web/animationsManager.js.map +1 -1
  17. package/lib/module/layoutReanimation/web/componentUtils.js +39 -3
  18. package/lib/module/layoutReanimation/web/componentUtils.js.map +1 -1
  19. package/lib/module/layoutReanimation/web/createAnimation.js +44 -38
  20. package/lib/module/layoutReanimation/web/createAnimation.js.map +1 -1
  21. package/lib/module/platform-specific/jsVersion.js +1 -1
  22. package/lib/module/updateProps/updateProps.js +2 -2
  23. package/lib/module/updateProps/updateProps.js.map +1 -1
  24. package/lib/typescript/common/style/config.d.ts.map +1 -1
  25. package/lib/typescript/common/web/index.d.ts +1 -0
  26. package/lib/typescript/common/web/index.d.ts.map +1 -1
  27. package/lib/typescript/common/web/utils/dom.d.ts +2 -0
  28. package/lib/typescript/common/web/utils/dom.d.ts.map +1 -0
  29. package/lib/typescript/common/web/utils/index.d.ts +1 -0
  30. package/lib/typescript/common/web/utils/index.d.ts.map +1 -1
  31. package/lib/typescript/createAnimatedComponent/commonTypes.d.ts +1 -1
  32. package/lib/typescript/createAnimatedComponent/commonTypes.d.ts.map +1 -1
  33. package/lib/typescript/css/native/types/animation.d.ts +2 -2
  34. package/lib/typescript/css/web/managers/CSSAnimationsManager.d.ts.map +1 -1
  35. package/lib/typescript/helperTypes.d.ts +4 -4
  36. package/lib/typescript/helperTypes.d.ts.map +1 -1
  37. package/lib/typescript/layoutReanimation/web/animationsManager.d.ts.map +1 -1
  38. package/lib/typescript/layoutReanimation/web/componentUtils.d.ts.map +1 -1
  39. package/lib/typescript/layoutReanimation/web/createAnimation.d.ts +3 -2
  40. package/lib/typescript/layoutReanimation/web/createAnimation.d.ts.map +1 -1
  41. package/lib/typescript/platform-specific/jsVersion.d.ts +1 -1
  42. package/lib/typescript/updateProps/updateProps.d.ts.map +1 -1
  43. package/package.json +1 -1
  44. package/src/common/style/config.ts +8 -1
  45. package/src/common/web/index.ts +1 -0
  46. package/src/common/web/utils/dom.ts +16 -0
  47. package/src/common/web/utils/index.ts +1 -0
  48. package/src/createAnimatedComponent/AnimatedComponent.tsx +2 -2
  49. package/src/createAnimatedComponent/commonTypes.ts +1 -1
  50. package/src/createAnimatedComponent/createAnimatedComponent.tsx +1 -1
  51. package/src/css/native/managers/CSSAnimationsManager.ts +4 -4
  52. package/src/css/native/types/animation.ts +2 -2
  53. package/src/css/web/managers/CSSAnimationsManager.ts +2 -6
  54. package/src/helperTypes.ts +10 -9
  55. package/src/layoutReanimation/web/animationsManager.ts +4 -2
  56. package/src/layoutReanimation/web/componentUtils.ts +52 -3
  57. package/src/layoutReanimation/web/createAnimation.ts +58 -40
  58. package/src/platform-specific/jsVersion.ts +1 -1
  59. package/src/updateProps/updateProps.ts +2 -5
@@ -15,8 +15,8 @@ import type {
15
15
  LayoutAnimationFunction,
16
16
  SharedValue,
17
17
  } from './commonTypes';
18
+ import type { NestedArray } from './createAnimatedComponent/commonTypes';
18
19
  import type { CSSStyle } from './css';
19
- import type { AddArrayPropertyType } from './css/types';
20
20
  import type { BaseAnimationBuilder } from './layoutReanimation/animationBuilder/BaseAnimationBuilder';
21
21
  import type { ReanimatedKeyframe } from './layoutReanimation/animationBuilder/Keyframe';
22
22
  import type { SharedTransition } from './layoutReanimation/SharedTransition';
@@ -47,8 +47,13 @@ type AnimatedStyleProps<Props extends object> = {
47
47
  };
48
48
 
49
49
  /** Component props that are not specially handled by us. */
50
+ type ComponentPropsWithoutStyle<Props extends object> = Omit<
51
+ Props,
52
+ keyof PickStyleProps<Props> | 'style'
53
+ >;
54
+
50
55
  type RestProps<Props extends object> = {
51
- [K in keyof Omit<Props, keyof PickStyleProps<Props> | 'style'>]:
56
+ [K in keyof ComponentPropsWithoutStyle<Props>]:
52
57
  | Props[K]
53
58
  | SharedValue<Props[K]>;
54
59
  };
@@ -94,10 +99,6 @@ type SharedTransitionProps = {
94
99
  sharedTransitionStyle?: SharedTransition;
95
100
  };
96
101
 
97
- type AnimatedPropsProp<Props extends object> = RestProps<Props> &
98
- AnimatedStyleProps<Props> &
99
- LayoutProps;
100
-
101
102
  export type AnimatedProps<Props extends object> = RestProps<Props> &
102
103
  AnimatedStyleProps<Props> &
103
104
  LayoutProps & {
@@ -106,9 +107,9 @@ export type AnimatedProps<Props extends object> = RestProps<Props> &
106
107
  *
107
108
  * @see https://docs.swmansion.com/react-native-reanimated/docs/core/useAnimatedProps
108
109
  */
109
- animatedProps?: AddArrayPropertyType<
110
- Partial<AnimatedPropsProp<Props>> | CSSStyle<Props>
111
- >;
110
+ animatedProps?: NestedArray<
111
+ CSSStyle<ComponentPropsWithoutStyle<Partial<Props>>>
112
+ >; // TODO - improve type once useAnimatedProps is typed properly. For now it is typed in the same way as the normal style prop, so it is assignable to the CSSStyle type
112
113
  } & SharedTransitionProps;
113
114
 
114
115
  // THE LAND OF THE DEPRECATED
@@ -132,7 +132,8 @@ function tryGetAnimationConfig<ComponentProps extends Record<string, unknown>>(
132
132
 
133
133
  if (isCustomKeyframe) {
134
134
  animationName = createCustomKeyFrameAnimation(
135
- (config as CustomConfig).definitions as KeyframeDefinitions
135
+ (config as CustomConfig).definitions as KeyframeDefinitions,
136
+ animationType
136
137
  );
137
138
  } else if (typeof config === 'function') {
138
139
  animationName = config.presetName;
@@ -144,7 +145,8 @@ function tryGetAnimationConfig<ComponentProps extends Record<string, unknown>>(
144
145
  if (hasInitialValues) {
145
146
  animationName = createAnimationWithInitialValues(
146
147
  animationName,
147
- (config as CustomConfig).initialValues as InitialValuesStyleProps
148
+ (config as CustomConfig).initialValues as InitialValuesStyleProps,
149
+ animationType
148
150
  );
149
151
  }
150
152
 
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
+
2
3
  import { logger } from '../../common';
4
+ import { removeElementAnimation } from '../../common/web';
3
5
  import { LayoutAnimationType, ReduceMotion } from '../../commonTypes';
4
6
  import type { EasingFunctionFactory } from '../../Easing';
5
7
  import { EasingNameSymbol } from '../../Easing';
@@ -29,6 +31,28 @@ import {
29
31
  } from './Easing.web';
30
32
  import { prepareCurvedTransition } from './transition/Curved.web';
31
33
 
34
+ function getSnapshotForElement(element: HTMLElement): ReanimatedSnapshot {
35
+ const existingSnapshot = snapshots.get(element);
36
+
37
+ if (existingSnapshot) {
38
+ return existingSnapshot;
39
+ }
40
+
41
+ const rect = element.getBoundingClientRect();
42
+
43
+ const fallbackSnapshot: ReanimatedSnapshot = {
44
+ top: rect.top,
45
+ left: rect.left,
46
+ width: rect.width,
47
+ height: rect.height,
48
+ scrollOffsets: getElementScrollValue(element),
49
+ };
50
+
51
+ snapshots.set(element, fallbackSnapshot);
52
+
53
+ return fallbackSnapshot;
54
+ }
55
+
32
56
  function getEasingFromConfig(config: CustomConfig): string {
33
57
  if (!config.easingV) {
34
58
  return getEasingByName('linear');
@@ -175,10 +199,16 @@ export function setElementAnimation(
175
199
 
176
200
  const configureAnimation = () => {
177
201
  element.style.animationName = animationName;
178
- element.style.animationFillMode = 'backwards';
179
202
  element.style.animationDuration = `${duration}s`;
180
203
  element.style.animationDelay = `${delay}s`;
181
204
  element.style.animationTimingFunction = easing;
205
+
206
+ if (
207
+ animationConfig.animationType === LayoutAnimationType.ENTERING &&
208
+ delay > 0
209
+ ) {
210
+ element.style.animationFillMode = 'backwards';
211
+ }
182
212
  };
183
213
 
184
214
  if (animationConfig.animationType === LayoutAnimationType.ENTERING) {
@@ -234,7 +264,7 @@ export function setElementAnimation(
234
264
  if (!(animationName in Animations)) {
235
265
  scheduleAnimationCleanup(animationName, duration + delay, () => {
236
266
  if (shouldSavePosition) {
237
- setElementPosition(element, snapshots.get(element)!);
267
+ setElementPosition(element, getSnapshotForElement(element));
238
268
  }
239
269
 
240
270
  maybeRemoveElement();
@@ -317,6 +347,21 @@ function getElementScrollValue(element: HTMLElement): ScrollOffsets {
317
347
  return scrollOffsets;
318
348
  }
319
349
 
350
+ function cleanupEnteringAnimations(element: HTMLElement) {
351
+ const animationName = element.style.animationName;
352
+
353
+ // Check if the animation name indicates it's an entering animation
354
+ if (animationName && animationName.startsWith('REA-ENTERING-')) {
355
+ removeElementAnimation(element);
356
+ }
357
+
358
+ for (const child of Array.from(element.children)) {
359
+ if (child instanceof HTMLElement) {
360
+ cleanupEnteringAnimations(child);
361
+ }
362
+ }
363
+ }
364
+
320
365
  export function handleExitingAnimation(
321
366
  element: ReanimatedHTMLElement,
322
367
  animationConfig: AnimationConfig
@@ -344,6 +389,10 @@ export function handleExitingAnimation(
344
389
  };
345
390
  saveScrollPosition(element);
346
391
 
392
+ // Clean up entering animations on all descendants before moving them to the dummy.
393
+ // This prevents entering animations from restarting when elements are moved to a new parent.
394
+ cleanupEnteringAnimations(element);
395
+
347
396
  // After cloning the element, we want to move all children from original element to its clone. This is because original element
348
397
  // will be unmounted, therefore when this code executes in child component, parent will be either empty or removed soon.
349
398
  // Using element.cloneNode(true) doesn't solve the problem, because it creates copy of children and we won't be able to set their animations
@@ -367,7 +416,7 @@ export function handleExitingAnimation(
367
416
  };
368
417
  restoreScrollPosition(dummy);
369
418
 
370
- const snapshot = snapshots.get(element)!;
419
+ const snapshot = getSnapshotForElement(element);
371
420
 
372
421
  const scrollOffsets = getElementScrollValue(element);
373
422
 
@@ -2,6 +2,8 @@
2
2
 
3
3
  import type { TransformsStyle } from 'react-native';
4
4
 
5
+ import { maybeAddSuffix } from '../../common';
6
+ import { LayoutAnimationType } from '../../commonTypes';
5
7
  import type {
6
8
  AnimationData,
7
9
  ReanimatedWebTransformProperties,
@@ -19,12 +21,27 @@ import { LinearTransition } from './transition/Linear.web';
19
21
  import { SequencedTransition } from './transition/Sequenced.web';
20
22
 
21
23
  type TransformType = NonNullable<TransformsStyle['transform']>;
24
+ type TransformValue = string | number;
25
+
26
+ function assignTransformRules(
27
+ map: Map<string, TransformValue>,
28
+ transform?: ReanimatedWebTransformProperties[]
29
+ ) {
30
+ if (!transform) {
31
+ return;
32
+ }
33
+
34
+ for (const rule of transform) {
35
+ for (const [property, value] of Object.entries(rule)) {
36
+ map.set(property, value as TransformValue);
37
+ }
38
+ }
39
+ }
22
40
 
23
41
  // Translate values are passed as numbers. However, if `translate` property receives number, it will not automatically
24
42
  // convert it to `px`. Therefore if we want to keep transform we have to add 'px' suffix to each of translate values
25
43
  // that are present inside transform.
26
44
  //
27
-
28
45
  function addPxToTransform(transform: TransformType) {
29
46
  type RNTransformProp = NonNullable<(typeof transform)[number]>;
30
47
 
@@ -52,7 +69,8 @@ function addPxToTransform(transform: TransformType) {
52
69
  }
53
70
 
54
71
  export function createCustomKeyFrameAnimation(
55
- keyframeDefinitions: KeyframeDefinitions
72
+ keyframeDefinitions: KeyframeDefinitions,
73
+ animationType: LayoutAnimationType
56
74
  ) {
57
75
  for (const value of Object.values(keyframeDefinitions)) {
58
76
  if (value.transform) {
@@ -66,7 +84,7 @@ export function createCustomKeyFrameAnimation(
66
84
  duration: -1,
67
85
  };
68
86
 
69
- animationData.name = generateNextCustomKeyframeName();
87
+ animationData.name = generateNextCustomKeyframeName(animationType);
70
88
 
71
89
  // Move keyframe easings one keyframe up (our LA Keyframe definition is different
72
90
  // from the CSS keyframes and expects easing to be present in the keyframe to which
@@ -92,46 +110,36 @@ export function createCustomKeyFrameAnimation(
92
110
 
93
111
  export function createAnimationWithInitialValues(
94
112
  animationName: string,
95
- initialValues: InitialValuesStyleProps
113
+ initialValues: InitialValuesStyleProps,
114
+ animationType: LayoutAnimationType
96
115
  ) {
97
116
  const animationStyle = structuredClone(AnimationsData[animationName].style);
98
117
  const firstAnimationStep = animationStyle['0'];
99
118
 
100
- const { transform, ...rest } = initialValues;
101
- const transformWithPx = addPxToTransform(transform as TransformType);
119
+ const { transform, originX, originY, ...rest } = initialValues;
120
+
121
+ const transformStyle = new Map<string, TransformValue>();
122
+ assignTransformRules(transformStyle, firstAnimationStep.transform);
102
123
 
103
124
  if (transform) {
104
- // If there was no predefined transform, we can simply assign transform from `initialValues`.
105
- if (!firstAnimationStep.transform) {
106
- firstAnimationStep.transform = transformWithPx;
107
- } else {
108
- // Othwerwise we have to merge predefined transform with the one provided in `initialValues`.
109
- // To do that, we create `Map` that will contain final transform.
110
- const transformStyle = new Map<string, any>();
111
-
112
- // First we assign all of the predefined rules
113
- for (const rule of firstAnimationStep.transform) {
114
- // In most cases there will be just one iteration
115
- for (const [property, value] of Object.entries(rule)) {
116
- transformStyle.set(property, value);
117
- }
118
- }
125
+ const transformWithPx = addPxToTransform(transform as TransformType);
126
+ assignTransformRules(transformStyle, transformWithPx);
127
+ }
119
128
 
120
- // Then we either add new rule, or override one that already exists.
121
- for (const rule of transformWithPx) {
122
- for (const [property, value] of Object.entries(rule)) {
123
- transformStyle.set(property, value);
124
- }
125
- }
129
+ if (originX !== undefined) {
130
+ transformStyle.set('translateX', maybeAddSuffix(originX, 'px'));
131
+ }
126
132
 
127
- // Finally, we convert `Map` with final transform back into array of objects.
128
- firstAnimationStep.transform = Array.from(
129
- transformStyle,
130
- ([property, value]) => ({
131
- [property]: value,
132
- })
133
- );
134
- }
133
+ if (originY !== undefined) {
134
+ transformStyle.set('translateY', maybeAddSuffix(originY, 'px'));
135
+ }
136
+
137
+ const mergedTransform = Array.from(transformStyle, ([property, value]) => ({
138
+ [property]: value,
139
+ }));
140
+
141
+ if (transformStyle.size) {
142
+ firstAnimationStep.transform = mergedTransform;
135
143
  }
136
144
 
137
145
  animationStyle['0'] = {
@@ -140,7 +148,7 @@ export function createAnimationWithInitialValues(
140
148
  };
141
149
 
142
150
  // TODO: Maybe we can extract the logic below into separate function
143
- const keyframeName = generateNextCustomKeyframeName();
151
+ const keyframeName = generateNextCustomKeyframeName(animationType);
144
152
 
145
153
  const animationObject: AnimationData = {
146
154
  name: keyframeName,
@@ -157,8 +165,14 @@ export function createAnimationWithInitialValues(
157
165
 
158
166
  let customKeyframeCounter = 0;
159
167
 
160
- function generateNextCustomKeyframeName() {
161
- return `REA${customKeyframeCounter++}`;
168
+ const ANIMATION_TYPE_STRINGS: Partial<Record<LayoutAnimationType, string>> = {
169
+ [LayoutAnimationType.ENTERING]: 'ENTERING',
170
+ [LayoutAnimationType.EXITING]: 'EXITING',
171
+ [LayoutAnimationType.LAYOUT]: 'LAYOUT',
172
+ };
173
+
174
+ function generateNextCustomKeyframeName(animationType: LayoutAnimationType) {
175
+ return `REA-${ANIMATION_TYPE_STRINGS[animationType] ?? ''}-${customKeyframeCounter++}`;
162
176
  }
163
177
 
164
178
  /**
@@ -174,7 +188,9 @@ export function TransitionGenerator(
174
188
  transitionType: TransitionType,
175
189
  transitionData: TransitionData
176
190
  ) {
177
- const transitionKeyframeName = generateNextCustomKeyframeName();
191
+ const transitionKeyframeName = generateNextCustomKeyframeName(
192
+ LayoutAnimationType.LAYOUT
193
+ );
178
194
  let dummyTransitionKeyframeName;
179
195
 
180
196
  let transitionObject;
@@ -207,7 +223,9 @@ export function TransitionGenerator(
207
223
 
208
224
  // Here code block with {} is necessary because of eslint
209
225
  case TransitionType.CURVED: {
210
- dummyTransitionKeyframeName = generateNextCustomKeyframeName();
226
+ dummyTransitionKeyframeName = generateNextCustomKeyframeName(
227
+ LayoutAnimationType.LAYOUT
228
+ );
211
229
 
212
230
  const { firstKeyframeObj, secondKeyframeObj } = CurvedTransition(
213
231
  transitionKeyframeName,
@@ -4,4 +4,4 @@
4
4
  * version used to build the native part of the library in runtime. Remember to
5
5
  * keep this in sync with the version declared in `package.json`
6
6
  */
7
- export const jsVersion = '4.2.0';
7
+ export const jsVersion = '4.2.1';
@@ -10,14 +10,11 @@ import {
10
10
  processColorsInProps,
11
11
  processFilter,
12
12
  processTransform,
13
+ processTransformOrigin,
13
14
  ReanimatedError,
14
15
  SHOULD_BE_USE_WEB,
15
16
  } from '../common';
16
- import {
17
- processBoxShadowWeb,
18
- processFilterWeb,
19
- processTransformOrigin,
20
- } from '../common/web';
17
+ import { processBoxShadowWeb, processFilterWeb } from '../common/web';
21
18
  import type {
22
19
  AnimatedStyle,
23
20
  ShadowNodeWrapper,