react-native-reanimated 2.1.0 → 2.2.3
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/Common/cpp/SharedItems/MutableValue.cpp +22 -18
- package/Common/cpp/SharedItems/ShareableValue.cpp +1 -1
- package/Common/cpp/Tools/JSIStoreValueUser.cpp +28 -15
- package/Common/cpp/Tools/RuntimeDecorator.cpp +20 -14
- package/Common/cpp/headers/Tools/JSIStoreValueUser.h +8 -3
- package/Common/cpp/headers/Tools/RuntimeDecorator.h +10 -0
- package/README.md +3 -4
- package/RNReanimated.podspec +6 -6
- package/android/build.gradle +78 -2
- package/android/react-native-reanimated-63-hermes.aar +0 -0
- package/android/react-native-reanimated-63-jsc.aar +0 -0
- package/android/react-native-reanimated-64-hermes.aar +0 -0
- package/android/react-native-reanimated-64-jsc.aar +0 -0
- package/android/react-native-reanimated-65-hermes.aar +0 -0
- package/android/react-native-reanimated-65-jsc.aar +0 -0
- package/android/react-native-reanimated-66-hermes.aar +0 -0
- package/android/react-native-reanimated-66-jsc.aar +0 -0
- package/ios/REANodesManager.m +3 -0
- package/ios/native/NativeMethods.mm +2 -2
- package/ios/native/NativeProxy.mm +6 -2
- package/ios/native/REAInitializer.h +32 -0
- package/ios/native/REAInitializer.mm +54 -0
- package/ios/native/UIResponder+Reanimated.mm +8 -48
- package/lib/Animated.js +0 -3
- package/lib/createAnimatedComponent.js +8 -4
- package/lib/index.js +0 -3
- package/lib/reanimated1/animations/decay.js +4 -2
- package/lib/reanimated1/animations/spring.js +4 -3
- package/lib/reanimated1/animations/timing.js +1 -1
- package/lib/reanimated1/core/Core.test.js +30 -0
- package/lib/reanimated2/animations.js +33 -17
- package/lib/reanimated2/core.js +1 -1
- package/lib/reanimated2/jestUtils.js +55 -21
- package/lib/reanimated2/js-reanimated/JSReanimated.js +7 -4
- package/libSo/fbjni/jni/arm64-v8a/libfbjni.so +0 -0
- package/libSo/fbjni/jni/armeabi-v7a/libfbjni.so +0 -0
- package/libSo/fbjni/jni/x86/libfbjni.so +0 -0
- package/libSo/fbjni/jni/x86_64/libfbjni.so +0 -0
- package/mock.js +1 -1
- package/package.json +4 -3
- package/plugin.js +8 -0
- package/react-native-reanimated.d.ts +8 -2
- package/src/Animated.js +0 -3
- package/src/createAnimatedComponent.js +8 -4
- package/src/reanimated1/animations/decay.js +4 -2
- package/src/reanimated1/animations/spring.js +4 -3
- package/src/reanimated1/animations/timing.js +1 -1
- package/src/reanimated1/core/Core.test.js +30 -0
- package/src/reanimated2/animations.ts +48 -22
- package/src/reanimated2/core.ts +1 -1
- package/src/reanimated2/jestUtils.ts +63 -24
- package/src/reanimated2/js-reanimated/JSReanimated.ts +6 -4
- package/android/react-native-reanimated-62.aar +0 -0
- package/android/react-native-reanimated-63.aar +0 -0
- package/android/react-native-reanimated-64.aar +0 -0
- package/android/react-native-reanimated.aar +0 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Animated from '../../Animated';
|
|
3
|
+
|
|
4
|
+
import renderer from 'react-test-renderer';
|
|
5
|
+
|
|
6
|
+
jest.mock('../../ReanimatedEventEmitter');
|
|
7
|
+
jest.mock('../../ReanimatedModule');
|
|
8
|
+
jest.mock('../../reanimated2/NativeReanimated');
|
|
9
|
+
|
|
10
|
+
describe('Core Animated components', () => {
|
|
11
|
+
xit('fails if something other then a node or function that returns a node is passed to Animated.Code exec prop', () => {
|
|
12
|
+
console.error = jest.fn();
|
|
13
|
+
|
|
14
|
+
expect(() =>
|
|
15
|
+
renderer.create(<Animated.Code exec="not a node" />)
|
|
16
|
+
).toThrowError(
|
|
17
|
+
"<Animated.Code /> expects the 'exec' prop or children to be an animated node or a function returning an animated node."
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
xit('fails if something other then a node or function that returns a node is passed to Animated.Code children', () => {
|
|
22
|
+
console.error = jest.fn();
|
|
23
|
+
|
|
24
|
+
expect(() =>
|
|
25
|
+
renderer.create(<Animated.Code>not a node</Animated.Code>)
|
|
26
|
+
).toThrowError(
|
|
27
|
+
"<Animated.Code /> expects the 'exec' prop or children to be an animated node or a function returning an animated node."
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { Easing } from './Easing';
|
|
5
5
|
import { isColor, convertToHSVA, toRGBA } from './Colors';
|
|
6
6
|
import NativeReanimated from './NativeReanimated';
|
|
7
|
+
import { Platform } from 'react-native';
|
|
7
8
|
|
|
8
9
|
let IN_STYLE_UPDATER = false;
|
|
9
10
|
|
|
@@ -356,55 +357,80 @@ export function withDecay(userConfig, callback) {
|
|
|
356
357
|
'worklet';
|
|
357
358
|
const config = {
|
|
358
359
|
deceleration: 0.998,
|
|
360
|
+
velocityFactor: Platform.OS !== 'web' ? 1 : 1000,
|
|
359
361
|
};
|
|
360
362
|
if (userConfig) {
|
|
361
363
|
Object.keys(userConfig).forEach((key) => (config[key] = userConfig[key]));
|
|
362
364
|
}
|
|
363
365
|
|
|
364
|
-
const VELOCITY_EPS =
|
|
366
|
+
const VELOCITY_EPS = Platform.OS !== 'web' ? 1 : 1 / 20;
|
|
367
|
+
const SLOPE_FACTOR = 0.1;
|
|
365
368
|
|
|
366
369
|
function decay(animation, now) {
|
|
367
|
-
const {
|
|
370
|
+
const {
|
|
371
|
+
lastTimestamp,
|
|
372
|
+
startTimestamp,
|
|
373
|
+
initialVelocity,
|
|
374
|
+
current,
|
|
375
|
+
velocity,
|
|
376
|
+
} = animation;
|
|
368
377
|
|
|
369
378
|
const deltaTime = Math.min(now - lastTimestamp, 64);
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
const x = current + v0 * kx;
|
|
378
|
-
|
|
379
|
-
animation.current = x;
|
|
379
|
+
const v =
|
|
380
|
+
velocity *
|
|
381
|
+
Math.exp(
|
|
382
|
+
-(1 - config.deceleration) * (now - startTimestamp) * SLOPE_FACTOR
|
|
383
|
+
);
|
|
384
|
+
animation.current =
|
|
385
|
+
current + (v * config.velocityFactor * deltaTime) / 1000; // /1000 because time is in ms not in s
|
|
380
386
|
animation.velocity = v;
|
|
387
|
+
animation.lastTimestamp = now;
|
|
381
388
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
if (Array.isArray(config.clamp)) {
|
|
389
|
+
if (config.clamp) {
|
|
385
390
|
if (initialVelocity < 0 && animation.current <= config.clamp[0]) {
|
|
386
|
-
|
|
391
|
+
animation.current = config.clamp[0];
|
|
392
|
+
return true;
|
|
387
393
|
} else if (
|
|
388
394
|
initialVelocity > 0 &&
|
|
389
395
|
animation.current >= config.clamp[1]
|
|
390
396
|
) {
|
|
391
|
-
|
|
397
|
+
animation.current = config.clamp[1];
|
|
398
|
+
return true;
|
|
392
399
|
}
|
|
393
400
|
}
|
|
394
401
|
|
|
395
|
-
if (Math.abs(v) < VELOCITY_EPS
|
|
396
|
-
if (toValueIsReached !== null) {
|
|
397
|
-
animation.current = toValueIsReached;
|
|
398
|
-
}
|
|
399
|
-
|
|
402
|
+
if (Math.abs(v) < VELOCITY_EPS) {
|
|
400
403
|
return true;
|
|
401
404
|
}
|
|
402
405
|
}
|
|
403
406
|
|
|
407
|
+
function validateConfig() {
|
|
408
|
+
if (config.clamp) {
|
|
409
|
+
if (Array.isArray(config.clamp)) {
|
|
410
|
+
if (config.clamp.length !== 2) {
|
|
411
|
+
console.error(
|
|
412
|
+
`clamp array must contain 2 items but is given ${config.clamp.length}`
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
} else {
|
|
416
|
+
console.error(
|
|
417
|
+
`config.clamp must be an array but is ${typeof config.clamp}`
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
if (config.velocityFactor <= 0) {
|
|
422
|
+
console.error(
|
|
423
|
+
`config.velocityFactor must be greather then 0 but is ${config.velocityFactor}`
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
404
428
|
function onStart(animation, value, now) {
|
|
405
429
|
animation.current = value;
|
|
406
430
|
animation.lastTimestamp = now;
|
|
431
|
+
animation.startTimestamp = now;
|
|
407
432
|
animation.initialVelocity = config.velocity;
|
|
433
|
+
validateConfig();
|
|
408
434
|
}
|
|
409
435
|
|
|
410
436
|
return {
|
package/src/reanimated2/core.ts
CHANGED
|
@@ -39,7 +39,7 @@ export const isConfigured = (throwError = false) => {
|
|
|
39
39
|
export const isConfiguredCheck = () => {
|
|
40
40
|
if (!isConfigured(true)) {
|
|
41
41
|
throw new Error(
|
|
42
|
-
'If you want to use Reanimated 2 then go through our installation steps https://docs.swmansion.com/react-native-reanimated/docs/installation'
|
|
42
|
+
'If you want to use Reanimated 2 then go through our installation steps https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation'
|
|
43
43
|
);
|
|
44
44
|
}
|
|
45
45
|
};
|
|
@@ -6,34 +6,69 @@ let config = {
|
|
|
6
6
|
fps: 60,
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (!received.props.style) {
|
|
13
|
-
isValid = false;
|
|
14
|
-
message.push("Component not contains 'style' property");
|
|
15
|
-
}
|
|
16
|
-
if (!received.props.animatedStyle?.value) {
|
|
17
|
-
isValid = false;
|
|
18
|
-
message.push("Component not contains 'animatedStyle' property");
|
|
19
|
-
}
|
|
20
|
-
message = message.join('\n');
|
|
9
|
+
const isAnimatedStyle = (style) => {
|
|
10
|
+
return !!style.animatedStyle;
|
|
11
|
+
};
|
|
21
12
|
|
|
22
|
-
|
|
13
|
+
const getAnimatedStyleFromObject = (style) => {
|
|
14
|
+
return style.animatedStyle.current.value;
|
|
23
15
|
};
|
|
24
16
|
|
|
25
17
|
const getCurrentStyle = (received) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
const styleObject = received.props.style;
|
|
19
|
+
let currentStyle = {};
|
|
20
|
+
if (Array.isArray(styleObject)) {
|
|
21
|
+
received.props.style.forEach((style) => {
|
|
22
|
+
if (isAnimatedStyle(style)) {
|
|
23
|
+
currentStyle = {
|
|
24
|
+
...currentStyle,
|
|
25
|
+
...getAnimatedStyleFromObject(style),
|
|
26
|
+
};
|
|
27
|
+
} else {
|
|
28
|
+
currentStyle = {
|
|
29
|
+
...currentStyle,
|
|
30
|
+
...style,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
} else {
|
|
35
|
+
if (isAnimatedStyle(styleObject)) {
|
|
36
|
+
currentStyle = getAnimatedStyleFromObject(styleObject);
|
|
37
|
+
} else {
|
|
38
|
+
currentStyle = {
|
|
39
|
+
...styleObject,
|
|
40
|
+
...received.props.animatedStyle.value,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return currentStyle;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const checkEqual = (currentStyle, expectStyle) => {
|
|
48
|
+
if (Array.isArray(expectStyle)) {
|
|
49
|
+
if (expectStyle.length !== currentStyle.length) return false;
|
|
50
|
+
for (let i = 0; i < currentStyle.length; i++) {
|
|
51
|
+
if (!checkEqual(currentStyle[i], expectStyle[i])) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
} else if (typeof currentStyle === 'object' && currentStyle) {
|
|
56
|
+
for (const property in expectStyle) {
|
|
57
|
+
if (!checkEqual(currentStyle[property], expectStyle[property])) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
return currentStyle === expectStyle;
|
|
63
|
+
}
|
|
64
|
+
return true;
|
|
30
65
|
};
|
|
31
66
|
|
|
32
67
|
const findStyleDiff = (current, expect, requireAllMatch) => {
|
|
33
68
|
const diffs = [];
|
|
34
69
|
let isEqual = true;
|
|
35
70
|
for (const property in expect) {
|
|
36
|
-
if (current[property]
|
|
71
|
+
if (!checkEqual(current[property], expect[property])) {
|
|
37
72
|
isEqual = false;
|
|
38
73
|
diffs.push({
|
|
39
74
|
property: property,
|
|
@@ -42,6 +77,7 @@ const findStyleDiff = (current, expect, requireAllMatch) => {
|
|
|
42
77
|
});
|
|
43
78
|
}
|
|
44
79
|
}
|
|
80
|
+
|
|
45
81
|
if (
|
|
46
82
|
requireAllMatch &&
|
|
47
83
|
Object.keys(current).length !== Object.keys(expect).length
|
|
@@ -62,8 +98,7 @@ const findStyleDiff = (current, expect, requireAllMatch) => {
|
|
|
62
98
|
};
|
|
63
99
|
|
|
64
100
|
const compareStyle = (received, expectedStyle, config) => {
|
|
65
|
-
|
|
66
|
-
if (!isValid) {
|
|
101
|
+
if (!received.props.style) {
|
|
67
102
|
return { message: () => message, pass: false };
|
|
68
103
|
}
|
|
69
104
|
const { exact } = config;
|
|
@@ -79,7 +114,9 @@ const compareStyle = (received, expectedStyle, config) => {
|
|
|
79
114
|
const differences = diffs
|
|
80
115
|
.map(
|
|
81
116
|
(diff) =>
|
|
82
|
-
`- '${diff.property}' should be ${
|
|
117
|
+
`- '${diff.property}' should be ${JSON.stringify(
|
|
118
|
+
diff.expect
|
|
119
|
+
)}, but is ${JSON.stringify(diff.current)}`
|
|
83
120
|
)
|
|
84
121
|
.join('\n');
|
|
85
122
|
|
|
@@ -122,20 +159,22 @@ export const withReanimatedTimer = (animatonTest) => {
|
|
|
122
159
|
};
|
|
123
160
|
|
|
124
161
|
export const advanceAnimationByTime = (time = frameTime) => {
|
|
125
|
-
for (let i = 0; i
|
|
162
|
+
for (let i = 0; i <= Math.ceil(time / frameTime); i++) {
|
|
126
163
|
tickTravel();
|
|
127
164
|
}
|
|
165
|
+
jest.advanceTimersByTime(frameTime);
|
|
128
166
|
};
|
|
129
167
|
|
|
130
168
|
export const advanceAnimationByFrame = (count) => {
|
|
131
|
-
for (let i = 0; i
|
|
169
|
+
for (let i = 0; i <= count; i++) {
|
|
132
170
|
tickTravel();
|
|
133
171
|
}
|
|
172
|
+
jest.advanceTimersByTime(frameTime);
|
|
134
173
|
};
|
|
135
174
|
|
|
136
175
|
export const setUpTests = (userConfig = {}) => {
|
|
137
176
|
const expect = require('expect');
|
|
138
|
-
frameTime = 1000 / config.fps;
|
|
177
|
+
frameTime = Math.round(1000 / config.fps);
|
|
139
178
|
|
|
140
179
|
config = {
|
|
141
180
|
...config,
|
|
@@ -10,12 +10,14 @@ export default class JSReanimated {
|
|
|
10
10
|
_renderRequested = false;
|
|
11
11
|
_mapperRegistry = new MapperRegistry(this);
|
|
12
12
|
_frames = [];
|
|
13
|
-
timeProvider =
|
|
13
|
+
timeProvider = {};
|
|
14
14
|
|
|
15
15
|
constructor() {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
if (process.env.JEST_WORKER_ID) {
|
|
17
|
+
this.timeProvider.now = () => Date.now();
|
|
18
|
+
} else {
|
|
19
|
+
this.timeProvider.now = () => window.performance.now();
|
|
20
|
+
}
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
pushFrame(frame) {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|