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.
Files changed (56) hide show
  1. package/Common/cpp/SharedItems/MutableValue.cpp +22 -18
  2. package/Common/cpp/SharedItems/ShareableValue.cpp +1 -1
  3. package/Common/cpp/Tools/JSIStoreValueUser.cpp +28 -15
  4. package/Common/cpp/Tools/RuntimeDecorator.cpp +20 -14
  5. package/Common/cpp/headers/Tools/JSIStoreValueUser.h +8 -3
  6. package/Common/cpp/headers/Tools/RuntimeDecorator.h +10 -0
  7. package/README.md +3 -4
  8. package/RNReanimated.podspec +6 -6
  9. package/android/build.gradle +78 -2
  10. package/android/react-native-reanimated-63-hermes.aar +0 -0
  11. package/android/react-native-reanimated-63-jsc.aar +0 -0
  12. package/android/react-native-reanimated-64-hermes.aar +0 -0
  13. package/android/react-native-reanimated-64-jsc.aar +0 -0
  14. package/android/react-native-reanimated-65-hermes.aar +0 -0
  15. package/android/react-native-reanimated-65-jsc.aar +0 -0
  16. package/android/react-native-reanimated-66-hermes.aar +0 -0
  17. package/android/react-native-reanimated-66-jsc.aar +0 -0
  18. package/ios/REANodesManager.m +3 -0
  19. package/ios/native/NativeMethods.mm +2 -2
  20. package/ios/native/NativeProxy.mm +6 -2
  21. package/ios/native/REAInitializer.h +32 -0
  22. package/ios/native/REAInitializer.mm +54 -0
  23. package/ios/native/UIResponder+Reanimated.mm +8 -48
  24. package/lib/Animated.js +0 -3
  25. package/lib/createAnimatedComponent.js +8 -4
  26. package/lib/index.js +0 -3
  27. package/lib/reanimated1/animations/decay.js +4 -2
  28. package/lib/reanimated1/animations/spring.js +4 -3
  29. package/lib/reanimated1/animations/timing.js +1 -1
  30. package/lib/reanimated1/core/Core.test.js +30 -0
  31. package/lib/reanimated2/animations.js +33 -17
  32. package/lib/reanimated2/core.js +1 -1
  33. package/lib/reanimated2/jestUtils.js +55 -21
  34. package/lib/reanimated2/js-reanimated/JSReanimated.js +7 -4
  35. package/libSo/fbjni/jni/arm64-v8a/libfbjni.so +0 -0
  36. package/libSo/fbjni/jni/armeabi-v7a/libfbjni.so +0 -0
  37. package/libSo/fbjni/jni/x86/libfbjni.so +0 -0
  38. package/libSo/fbjni/jni/x86_64/libfbjni.so +0 -0
  39. package/mock.js +1 -1
  40. package/package.json +4 -3
  41. package/plugin.js +8 -0
  42. package/react-native-reanimated.d.ts +8 -2
  43. package/src/Animated.js +0 -3
  44. package/src/createAnimatedComponent.js +8 -4
  45. package/src/reanimated1/animations/decay.js +4 -2
  46. package/src/reanimated1/animations/spring.js +4 -3
  47. package/src/reanimated1/animations/timing.js +1 -1
  48. package/src/reanimated1/core/Core.test.js +30 -0
  49. package/src/reanimated2/animations.ts +48 -22
  50. package/src/reanimated2/core.ts +1 -1
  51. package/src/reanimated2/jestUtils.ts +63 -24
  52. package/src/reanimated2/js-reanimated/JSReanimated.ts +6 -4
  53. package/android/react-native-reanimated-62.aar +0 -0
  54. package/android/react-native-reanimated-63.aar +0 -0
  55. package/android/react-native-reanimated-64.aar +0 -0
  56. 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 = 5;
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 { lastTimestamp, initialVelocity, current, velocity } = animation;
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
- animation.lastTimestamp = now;
371
-
372
- const kv = Math.pow(config.deceleration, deltaTime);
373
- const kx = (config.deceleration * (1 - kv)) / (1 - config.deceleration);
374
-
375
- const v0 = velocity / 1000;
376
- const v = v0 * kv * 1000;
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
- let toValueIsReached = null;
383
-
384
- if (Array.isArray(config.clamp)) {
389
+ if (config.clamp) {
385
390
  if (initialVelocity < 0 && animation.current <= config.clamp[0]) {
386
- toValueIsReached = config.clamp[0];
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
- toValueIsReached = config.clamp[1];
397
+ animation.current = config.clamp[1];
398
+ return true;
392
399
  }
393
400
  }
394
401
 
395
- if (Math.abs(v) < VELOCITY_EPS || toValueIsReached !== null) {
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 {
@@ -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 checkValidation = (received) => {
10
- let message = [];
11
- let isValid = true;
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
- return { isValid, message };
13
+ const getAnimatedStyleFromObject = (style) => {
14
+ return style.animatedStyle.current.value;
23
15
  };
24
16
 
25
17
  const getCurrentStyle = (received) => {
26
- return {
27
- ...received.props.style,
28
- ...received.props.animatedStyle.value,
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] !== expect[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
- const { isValid, message } = checkValidation(received);
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 ${diff.expect}, but is ${diff.current}`
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 < Math.ceil(time / frameTime); 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 < count; 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 = null;
13
+ timeProvider = {};
14
14
 
15
15
  constructor() {
16
- this.timeProvider = process.env.JEST_WORKER_ID
17
- ? { now: () => Date.now() }
18
- : window.performance;
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