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.
- package/lib/module/common/style/config.js +10 -1
- package/lib/module/common/style/config.js.map +1 -1
- package/lib/module/common/web/index.js +1 -0
- package/lib/module/common/web/index.js.map +1 -1
- package/lib/module/common/web/utils/dom.js +16 -0
- package/lib/module/common/web/utils/dom.js.map +1 -0
- package/lib/module/common/web/utils/index.js +1 -0
- package/lib/module/common/web/utils/index.js.map +1 -1
- package/lib/module/createAnimatedComponent/AnimatedComponent.js +2 -2
- package/lib/module/createAnimatedComponent/AnimatedComponent.js.map +1 -1
- package/lib/module/css/native/managers/CSSAnimationsManager.js +3 -3
- package/lib/module/css/native/managers/CSSAnimationsManager.js.map +1 -1
- package/lib/module/css/web/managers/CSSAnimationsManager.js +2 -6
- package/lib/module/css/web/managers/CSSAnimationsManager.js.map +1 -1
- package/lib/module/layoutReanimation/web/animationsManager.js +2 -2
- package/lib/module/layoutReanimation/web/animationsManager.js.map +1 -1
- package/lib/module/layoutReanimation/web/componentUtils.js +39 -3
- package/lib/module/layoutReanimation/web/componentUtils.js.map +1 -1
- package/lib/module/layoutReanimation/web/createAnimation.js +44 -38
- package/lib/module/layoutReanimation/web/createAnimation.js.map +1 -1
- package/lib/module/platform-specific/jsVersion.js +1 -1
- package/lib/module/updateProps/updateProps.js +2 -2
- package/lib/module/updateProps/updateProps.js.map +1 -1
- package/lib/typescript/common/style/config.d.ts.map +1 -1
- package/lib/typescript/common/web/index.d.ts +1 -0
- package/lib/typescript/common/web/index.d.ts.map +1 -1
- package/lib/typescript/common/web/utils/dom.d.ts +2 -0
- package/lib/typescript/common/web/utils/dom.d.ts.map +1 -0
- package/lib/typescript/common/web/utils/index.d.ts +1 -0
- package/lib/typescript/common/web/utils/index.d.ts.map +1 -1
- package/lib/typescript/createAnimatedComponent/commonTypes.d.ts +1 -1
- package/lib/typescript/createAnimatedComponent/commonTypes.d.ts.map +1 -1
- package/lib/typescript/css/native/types/animation.d.ts +2 -2
- package/lib/typescript/css/web/managers/CSSAnimationsManager.d.ts.map +1 -1
- package/lib/typescript/helperTypes.d.ts +4 -4
- package/lib/typescript/helperTypes.d.ts.map +1 -1
- package/lib/typescript/layoutReanimation/web/animationsManager.d.ts.map +1 -1
- package/lib/typescript/layoutReanimation/web/componentUtils.d.ts.map +1 -1
- package/lib/typescript/layoutReanimation/web/createAnimation.d.ts +3 -2
- package/lib/typescript/layoutReanimation/web/createAnimation.d.ts.map +1 -1
- package/lib/typescript/platform-specific/jsVersion.d.ts +1 -1
- package/lib/typescript/updateProps/updateProps.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/common/style/config.ts +8 -1
- package/src/common/web/index.ts +1 -0
- package/src/common/web/utils/dom.ts +16 -0
- package/src/common/web/utils/index.ts +1 -0
- package/src/createAnimatedComponent/AnimatedComponent.tsx +2 -2
- package/src/createAnimatedComponent/commonTypes.ts +1 -1
- package/src/createAnimatedComponent/createAnimatedComponent.tsx +1 -1
- package/src/css/native/managers/CSSAnimationsManager.ts +4 -4
- package/src/css/native/types/animation.ts +2 -2
- package/src/css/web/managers/CSSAnimationsManager.ts +2 -6
- package/src/helperTypes.ts +10 -9
- package/src/layoutReanimation/web/animationsManager.ts +4 -2
- package/src/layoutReanimation/web/componentUtils.ts +52 -3
- package/src/layoutReanimation/web/createAnimation.ts +58 -40
- package/src/platform-specific/jsVersion.ts +1 -1
- package/src/updateProps/updateProps.ts +2 -5
package/src/helperTypes.ts
CHANGED
|
@@ -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
|
|
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?:
|
|
110
|
-
|
|
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,
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
transformStyle.set(property, value);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
129
|
+
if (originX !== undefined) {
|
|
130
|
+
transformStyle.set('translateX', maybeAddSuffix(originX, 'px'));
|
|
131
|
+
}
|
|
126
132
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
|
|
161
|
-
|
|
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,
|
|
@@ -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,
|