react-native-reanimated 2.3.0-beta.3 → 2.3.0-beta.4

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 (67) hide show
  1. package/Common/cpp/NativeModules/NativeReanimatedModule.cpp +9 -0
  2. package/Common/cpp/NativeModules/NativeReanimatedModuleSpec.cpp +13 -0
  3. package/Common/cpp/Tools/FeaturesConfig.cpp +5 -0
  4. package/Common/cpp/Tools/RuntimeDecorator.cpp +21 -2
  5. package/Common/cpp/headers/NativeModules/NativeReanimatedModule.h +3 -0
  6. package/Common/cpp/headers/NativeModules/NativeReanimatedModuleSpec.h +5 -0
  7. package/Common/cpp/headers/Tools/FeaturesConfig.h +19 -0
  8. package/Common/cpp/headers/Tools/PlatformDepMethodsHolder.h +2 -0
  9. package/Common/cpp/headers/Tools/RuntimeDecorator.h +8 -7
  10. package/RNReanimated.podspec +20 -3
  11. package/android/build.gradle +29 -5
  12. package/android/react-native-reanimated-63-hermes.aar +0 -0
  13. package/android/react-native-reanimated-63-jsc.aar +0 -0
  14. package/android/react-native-reanimated-64-hermes.aar +0 -0
  15. package/android/react-native-reanimated-64-jsc.aar +0 -0
  16. package/android/react-native-reanimated-65-hermes.aar +0 -0
  17. package/android/react-native-reanimated-65-jsc.aar +0 -0
  18. package/android/react-native-reanimated-66-hermes.aar +0 -0
  19. package/android/react-native-reanimated-66-jsc.aar +0 -0
  20. package/android/react-native-reanimated-67-hermes.aar +0 -0
  21. package/android/react-native-reanimated-67-jsc.aar +0 -0
  22. package/ios/LayoutReanimation/REAUIManager.mm +56 -12
  23. package/ios/REAEventDispatcher.m +1 -1
  24. package/ios/REAModule.h +0 -2
  25. package/ios/REAModule.m +0 -3
  26. package/ios/REANodesManager.m +1 -0
  27. package/ios/RNGestureHandlerStateManager.h +5 -0
  28. package/ios/native/NativeMethods.h +5 -0
  29. package/ios/native/NativeMethods.mm +8 -1
  30. package/ios/native/NativeProxy.h +1 -0
  31. package/ios/native/NativeProxy.mm +10 -2
  32. package/ios/native/REAInitializer.mm +8 -3
  33. package/lib/Animated.js +9 -1
  34. package/lib/createAnimatedComponent.js +53 -37
  35. package/lib/index.js +9 -1
  36. package/lib/reanimated2/NativeMethods.js +7 -0
  37. package/lib/reanimated2/NativeReanimated/NativeReanimated.js +3 -0
  38. package/lib/reanimated2/UpdateProps.js +1 -1
  39. package/lib/reanimated2/ViewDescriptorsSet.js +4 -2
  40. package/lib/reanimated2/animation/styleAnimation.js +5 -0
  41. package/lib/reanimated2/core.js +18 -0
  42. package/lib/reanimated2/globals.d.ts +2 -0
  43. package/lib/reanimated2/js-reanimated/JSReanimated.js +3 -0
  44. package/lib/reanimated2/js-reanimated/Mapper.js +4 -1
  45. package/lib/reanimated2/js-reanimated/index.js +3 -0
  46. package/lib/reanimated2/layoutReanimation/LayoutAnimationRepository.js +14 -5
  47. package/lib/reanimated2/layoutReanimation/defaultAnimations/Slide.js +1 -1
  48. package/lib/reanimated2/layoutReanimation/defaultTransitions/EntryExitTransition.js +2 -2
  49. package/mock.js +1 -1
  50. package/package.json +2 -2
  51. package/plugin.js +9 -3
  52. package/react-native-reanimated.d.ts +1 -0
  53. package/src/Animated.js +9 -1
  54. package/src/createAnimatedComponent.tsx +76 -41
  55. package/src/reanimated2/NativeMethods.ts +13 -1
  56. package/src/reanimated2/NativeReanimated/NativeReanimated.ts +4 -0
  57. package/src/reanimated2/UpdateProps.ts +1 -1
  58. package/src/reanimated2/ViewDescriptorsSet.ts +6 -2
  59. package/src/reanimated2/animation/styleAnimation.ts +9 -0
  60. package/src/reanimated2/core.ts +29 -0
  61. package/src/reanimated2/globals.d.ts +2 -0
  62. package/src/reanimated2/js-reanimated/JSReanimated.ts +6 -0
  63. package/src/reanimated2/js-reanimated/Mapper.ts +3 -1
  64. package/src/reanimated2/js-reanimated/index.ts +5 -0
  65. package/src/reanimated2/layoutReanimation/LayoutAnimationRepository.ts +18 -5
  66. package/src/reanimated2/layoutReanimation/defaultAnimations/Slide.ts +1 -1
  67. package/src/reanimated2/layoutReanimation/defaultTransitions/EntryExitTransition.ts +5 -5
@@ -17,13 +17,21 @@ import './reanimated2/layoutReanimation/LayoutAnimationRepository';
17
17
  import invariant from 'invariant';
18
18
  import { adaptViewConfig } from './ConfigHelper';
19
19
  import { RNRenderer } from './reanimated2/platform-specific/RNRenderer';
20
- import { makeMutable, runOnUI } from './reanimated2/core';
20
+ import {
21
+ makeMutable,
22
+ runOnUI,
23
+ enableLayoutAnimations,
24
+ } from './reanimated2/core';
21
25
  import {
22
26
  DefaultEntering,
23
27
  DefaultExiting,
24
28
  DefaultLayout,
25
29
  } from './reanimated2/layoutReanimation/defaultAnimations/Default';
26
- import { isJest, isChromeDebugger } from './reanimated2/PlatformChecker';
30
+ import {
31
+ isJest,
32
+ isChromeDebugger,
33
+ shouldBeUseWeb,
34
+ } from './reanimated2/PlatformChecker';
27
35
  import { initialUpdaterRun } from './reanimated2/animation';
28
36
  import {
29
37
  BaseAnimationBuilder,
@@ -88,6 +96,16 @@ function flattenArray<T>(array: NestedArray<T>): T[] {
88
96
  return resultArr;
89
97
  }
90
98
 
99
+ function onlyAnimatedStyles(styles: StyleProps[]) {
100
+ return styles.filter((style) => style?.viewDescriptors);
101
+ }
102
+
103
+ function isSameAnimatedStyle(style1: StyleProps, style2: StyleProps): boolean {
104
+ // We cannot use equality check to compare useAnimatedStyle outputs directly.
105
+ // Instead, we can compare its viewsRefs.
106
+ return style1.viewsRef === style2.viewsRef;
107
+ }
108
+
91
109
  const has = <K extends string>(
92
110
  key: K,
93
111
  x: unknown
@@ -167,6 +185,7 @@ export default function createAnimatedComponent(
167
185
  > {
168
186
  _invokeAnimatedPropsCallbackOnMount = false;
169
187
  _styles: StyleProps[] | null = null;
188
+ _animatedProps?: Partial<AnimatedComponentProps<AnimatedProps>>;
170
189
  _viewTag = -1;
171
190
  _isFirstRender = true;
172
191
  animatedStyle: { value: StyleProps } = { value: {} };
@@ -255,9 +274,7 @@ export default function createAnimatedComponent(
255
274
  }
256
275
  } else if (this._viewTag !== -1 && this._styles !== null) {
257
276
  for (const style of this._styles) {
258
- if (style?.viewDescriptors) {
259
- style.viewDescriptors.remove(this._viewTag);
260
- }
277
+ style.viewDescriptors.remove(this._viewTag);
261
278
  }
262
279
  if (this.props.animatedProps?.viewDescriptors) {
263
280
  this.props.animatedProps.viewDescriptors.remove(this._viewTag);
@@ -387,8 +404,15 @@ export default function createAnimatedComponent(
387
404
  }
388
405
 
389
406
  _attachAnimatedStyles() {
390
- const styles = flattenArray<StyleProps>(this.props.style ?? []);
407
+ const styles = this.props.style
408
+ ? onlyAnimatedStyles(flattenArray<StyleProps>(this.props.style))
409
+ : [];
410
+ const prevStyles = this._styles;
391
411
  this._styles = styles;
412
+
413
+ const prevAnimatedProps = this._animatedProps;
414
+ this._animatedProps = this.props.animatedProps;
415
+
392
416
  let viewTag: number | null;
393
417
  let viewName: string | null;
394
418
  if (Platform.OS === 'web') {
@@ -410,34 +434,57 @@ export default function createAnimatedComponent(
410
434
  */
411
435
  viewName = hostInstance?.viewConfig?.uiViewClassName;
412
436
  // update UI props whitelist for this view
413
- if (
414
- hostInstance &&
415
- this._hasReanimated2Props(styles) &&
416
- hostInstance.viewConfig
417
- ) {
437
+ const hasReanimated2Props =
438
+ this.props.animatedProps?.viewDescriptors || styles.length;
439
+ if (hasReanimated2Props && hostInstance?.viewConfig) {
418
440
  adaptViewConfig(hostInstance.viewConfig);
419
441
  }
420
442
  }
421
443
  this._viewTag = viewTag as number;
422
444
 
423
- styles.forEach((style) => {
424
- if (style?.viewDescriptors) {
425
- style.viewDescriptors.add({ tag: viewTag, name: viewName });
426
- if (isJest()) {
427
- /**
428
- * We need to connect Jest's TestObject instance whose contains just props object
429
- * with the updateProps() function where we update the properties of the component.
430
- * We can't update props object directly because TestObject contains a copy of props - look at render function:
431
- * const props = this._filterNonAnimatedProps(this.props);
432
- */
433
- this.animatedStyle.value = {
434
- ...this.animatedStyle.value,
435
- ...style.initial.value,
436
- };
437
- style.animatedStyle.current = this.animatedStyle;
445
+ // remove old styles
446
+ if (prevStyles) {
447
+ // in most of the cases, views have only a single animated style and it remains unchanged
448
+ const hasOneSameStyle =
449
+ styles.length === 1 &&
450
+ prevStyles.length === 1 &&
451
+ isSameAnimatedStyle(styles[0], prevStyles[0]);
452
+
453
+ if (!hasOneSameStyle) {
454
+ // otherwise, remove each style that is not present in new styles
455
+ for (const prevStyle of prevStyles) {
456
+ const isPresent = styles.some((style) =>
457
+ isSameAnimatedStyle(style, prevStyle)
458
+ );
459
+ if (!isPresent) {
460
+ prevStyle.viewDescriptors.remove(viewTag);
461
+ }
438
462
  }
439
463
  }
464
+ }
465
+
466
+ styles.forEach((style) => {
467
+ style.viewDescriptors.add({ tag: viewTag, name: viewName });
468
+ if (isJest()) {
469
+ /**
470
+ * We need to connect Jest's TestObject instance whose contains just props object
471
+ * with the updateProps() function where we update the properties of the component.
472
+ * We can't update props object directly because TestObject contains a copy of props - look at render function:
473
+ * const props = this._filterNonAnimatedProps(this.props);
474
+ */
475
+ this.animatedStyle.value = {
476
+ ...this.animatedStyle.value,
477
+ ...style.initial.value,
478
+ };
479
+ style.animatedStyle.current = this.animatedStyle;
480
+ }
440
481
  });
482
+
483
+ // detach old animatedProps
484
+ if (prevAnimatedProps && prevAnimatedProps !== this.props.animatedProps) {
485
+ prevAnimatedProps.viewDescriptors!.remove(viewTag as number);
486
+ }
487
+
441
488
  // attach animatedProps property
442
489
  if (this.props.animatedProps?.viewDescriptors) {
443
490
  this.props.animatedProps.viewDescriptors.add({
@@ -449,21 +496,6 @@ export default function createAnimatedComponent(
449
496
  }
450
497
  }
451
498
 
452
- _hasReanimated2Props(flattenStyles: StyleProps[]) {
453
- if (this.props.animatedProps?.viewDescriptors) {
454
- return true;
455
- }
456
- if (this.props.style) {
457
- for (const style of flattenStyles) {
458
- // eslint-disable-next-line no-prototype-builtins
459
- if (style?.hasOwnProperty('viewDescriptors')) {
460
- return true;
461
- }
462
- }
463
- }
464
- return false;
465
- }
466
-
467
499
  _detachPropUpdater() {
468
500
  const viewTag = findNodeHandle(this);
469
501
  NODE_MAPPING.delete(viewTag);
@@ -496,6 +528,9 @@ export default function createAnimatedComponent(
496
528
  (this.props.layout || this.props.entering || this.props.exiting) &&
497
529
  tag != null
498
530
  ) {
531
+ if (!shouldBeUseWeb()) {
532
+ enableLayoutAnimations(true, false);
533
+ }
499
534
  let layout = this.props.layout ? this.props.layout : DefaultLayout;
500
535
  let entering = this.props.entering
501
536
  ? this.props.entering
@@ -1,4 +1,6 @@
1
- /* global _WORKLET _measure _scrollTo */
1
+ /* global _WORKLET _measure _scrollTo _setGestureState */
2
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
3
+ // @ts-nocheck
2
4
  import { Component } from 'react';
3
5
  import { findNodeHandle } from 'react-native';
4
6
  import { RefObjectFunction } from './hook/useAnimatedRef';
@@ -47,3 +49,13 @@ export function scrollTo(
47
49
  const viewTag = animatedRef();
48
50
  _scrollTo(viewTag, x, y, animated);
49
51
  }
52
+
53
+ export function setGestureState(handlerTag: number, newState: number): void {
54
+ 'worklet';
55
+ if (!_WORKLET && !isChromeDebugger()) {
56
+ console.warn(
57
+ '[Reanimated] You can not use setGestureState in non-worklet function.'
58
+ );
59
+ }
60
+ _setGestureState(handlerTag, newState);
61
+ }
@@ -65,4 +65,8 @@ export class NativeReanimated {
65
65
  ): Promise<T> {
66
66
  return InnerNativeModule.getViewProp(viewTag, propName, callback);
67
67
  }
68
+
69
+ enableLayoutAnimations(flag: boolean): void {
70
+ InnerNativeModule.enableLayoutAnimations(flag);
71
+ }
68
72
  }
@@ -26,7 +26,7 @@ export const colorProps = [
26
26
  'overlayColor',
27
27
  ];
28
28
 
29
- const ColorProperties = !isConfigured() ? [] : makeShareable(colorProps);
29
+ export const ColorProperties = !isConfigured() ? [] : makeShareable(colorProps);
30
30
 
31
31
  let updatePropsByPlatform;
32
32
  if (shouldBeUseWeb()) {
@@ -2,6 +2,7 @@ import { useRef } from 'react';
2
2
  import { makeMutable } from './core';
3
3
  import { SharedValue } from './commonTypes';
4
4
  import { Descriptor } from './hook/commonTypes';
5
+ import { Platform } from 'react-native';
5
6
 
6
7
  export interface ViewRefSet<T> {
7
8
  items: Set<T>;
@@ -23,6 +24,9 @@ export interface ViewDescriptorsSet {
23
24
  ) => void;
24
25
  }
25
26
 
27
+ const scheduleUpdates =
28
+ Platform.OS === 'web' ? requestAnimationFrame : setImmediate;
29
+
26
30
  export function makeViewDescriptorsSet(): ViewDescriptorsSet {
27
31
  const ref = useRef<ViewDescriptorsSet | null>(null);
28
32
  if (ref.current === null) {
@@ -44,7 +48,7 @@ export function makeViewDescriptorsSet(): ViewDescriptorsSet {
44
48
  if (!data.waitForInsertSync) {
45
49
  data.waitForInsertSync = true;
46
50
 
47
- setImmediate(() => {
51
+ scheduleUpdates(() => {
48
52
  data.sharableViewDescriptors.value = data.items;
49
53
  data.waitForInsertSync = false;
50
54
  });
@@ -57,7 +61,7 @@ export function makeViewDescriptorsSet(): ViewDescriptorsSet {
57
61
  if (!data.waitForRemoveSync) {
58
62
  data.waitForRemoveSync = true;
59
63
 
60
- setImmediate(() => {
64
+ scheduleUpdates(() => {
61
65
  const items = [];
62
66
  for (const item of data.items) {
63
67
  if (data.batchToRemove.has(item.tag)) {
@@ -14,6 +14,8 @@ import {
14
14
  StyleProps,
15
15
  } from '../commonTypes';
16
16
  import { withTiming } from './timing';
17
+ import { ColorProperties } from '../UpdateProps';
18
+ import { processColor } from '../Colors';
17
19
 
18
20
  export interface StyleLayoutAnimation extends HigherOrderAnimation {
19
21
  current: StyleProps;
@@ -134,6 +136,13 @@ export function withStyleAnimation(
134
136
  } else {
135
137
  stillGoing = true;
136
138
  }
139
+
140
+ if (ColorProperties.includes(currentEntry.path[0] as string)) {
141
+ currentStyleAnimation.current = processColor(
142
+ currentStyleAnimation.current
143
+ ) as number;
144
+ }
145
+
137
146
  setPath(
138
147
  animation.current,
139
148
  currentEntry.path,
@@ -385,3 +385,32 @@ if (!NativeReanimatedModule.useOnlyV1) {
385
385
  _setGlobalConsole(console);
386
386
  })();
387
387
  }
388
+
389
+ type FeaturesConfig = {
390
+ enableLayoutAnimations: boolean;
391
+ setByUser: boolean;
392
+ };
393
+
394
+ let featuresConfig: FeaturesConfig = {
395
+ enableLayoutAnimations: false,
396
+ setByUser: false,
397
+ };
398
+
399
+ export function enableLayoutAnimations(
400
+ flag: boolean,
401
+ isCallByUser = true
402
+ ): void {
403
+ if (isCallByUser) {
404
+ featuresConfig = {
405
+ enableLayoutAnimations: flag,
406
+ setByUser: true,
407
+ };
408
+ NativeReanimatedModule.enableLayoutAnimations(flag);
409
+ } else if (
410
+ !featuresConfig.setByUser &&
411
+ featuresConfig.enableLayoutAnimations !== flag
412
+ ) {
413
+ featuresConfig.enableLayoutAnimations = flag;
414
+ NativeReanimatedModule.enableLayoutAnimations(flag);
415
+ }
416
+ }
@@ -13,6 +13,7 @@ declare global {
13
13
  tag: number,
14
14
  flag: { value: boolean; _value: boolean }
15
15
  ) => void;
16
+ const _setGestureState: (handlerTag: number, newState: number) => void;
16
17
  const _updateProps: (
17
18
  tag: number,
18
19
  name: string,
@@ -30,6 +31,7 @@ declare global {
30
31
  __reanimatedWorkletInit: (worklet: WorkletFunction) => void;
31
32
  _setGlobalConsole: (console?: ReanimatedConsole) => void;
32
33
  _log: (s: string) => void;
34
+ _setGestureState: () => void;
33
35
  _WORKLET: boolean;
34
36
  __reanimatedModuleProxy: NativeReanimated;
35
37
  _frameTimestamp: number | null;
@@ -98,4 +98,10 @@ export default class JSReanimated extends NativeReanimated {
98
98
  unregisterEventHandler(_: string): void {
99
99
  // noop
100
100
  }
101
+
102
+ enableLayoutAnimations() {
103
+ console.warn(
104
+ '[Reanimated] enableLayoutAnimations is not available for WEB yet'
105
+ );
106
+ }
101
107
  }
@@ -43,7 +43,9 @@ export default class Mapper<T> {
43
43
  const res: MutableValue<T>[] = [];
44
44
 
45
45
  function extractMutables(value: NestedObjectValues<MutableValue<T>>) {
46
- if (value instanceof MutableValue) {
46
+ if (value == null) {
47
+ // return;
48
+ } else if (value instanceof MutableValue) {
47
49
  res.push(value);
48
50
  } else if (Array.isArray(value)) {
49
51
  value.forEach((v) => extractMutables(v));
@@ -36,6 +36,11 @@ if (shouldBeUseWeb()) {
36
36
  "[Reanimated] You can't use 'scrollTo' method with Chrome Debugger or with web version"
37
37
  );
38
38
  };
39
+ global._setGestureState = () => {
40
+ console.warn(
41
+ "[Reanimated] You can't use 'setGestureState' method with Chrome Debugger or with web version"
42
+ );
43
+ };
39
44
  }
40
45
 
41
46
  export const _updatePropsJS = (
@@ -1,6 +1,8 @@
1
1
  /* global _stopObservingProgress, _startObservingProgress */
2
2
  import { runOnUI } from '../core';
3
3
  import { withStyleAnimation } from '../animation/styleAnimation';
4
+ import { ColorProperties } from '../UpdateProps';
5
+ import { processColor } from '../Colors';
4
6
 
5
7
  runOnUI(() => {
6
8
  'worklet';
@@ -36,13 +38,22 @@ runOnUI(() => {
36
38
  for (const key in layoutAnimation) {
37
39
  currentAnimation[key] = layoutAnimation[key];
38
40
  }
39
- enteringAnimationForTag[tag] = null;
40
41
  }
41
42
 
42
43
  const sv: { value: boolean; _value: boolean } = configs[tag].sv;
43
44
  _stopObservingProgress(tag, false);
44
45
  _startObservingProgress(tag, sv);
45
- sv._value = Object.assign({}, sv._value, style.initialValues);
46
+
47
+ const backupColor: Record<string, string> = {};
48
+ for (const key in style.initialValues) {
49
+ if (ColorProperties.includes(key)) {
50
+ const value = style.initialValues[key];
51
+ backupColor[key] = value;
52
+ style.initialValues[key] = processColor(value);
53
+ }
54
+ }
55
+
56
+ sv.value = Object.assign({}, sv._value, style.initialValues);
46
57
  _stopObservingProgress(tag, false);
47
58
  const animation = withStyleAnimation(currentAnimation);
48
59
 
@@ -51,10 +62,12 @@ runOnUI(() => {
51
62
  _stopObservingProgress(tag, finished);
52
63
  }
53
64
  style.callback && style.callback(finished);
54
- if (type === 'entering') {
55
- enteringAnimationForTag[tag] = null;
56
- }
57
65
  };
66
+
67
+ if (backupColor) {
68
+ configs[tag].sv._value = { ...configs[tag].sv.value, ...backupColor };
69
+ }
70
+
58
71
  configs[tag].sv.value = animation;
59
72
  _startObservingProgress(tag, sv);
60
73
  },
@@ -145,7 +145,7 @@ export class SlideInUp
145
145
  originY: delayFunction(delay, animation(values.originY, config)),
146
146
  },
147
147
  initialValues: {
148
- originY: height,
148
+ originY: -height,
149
149
  },
150
150
  callback: callback,
151
151
  };
@@ -122,7 +122,7 @@ export class EntryExitTransition
122
122
  transformProp as keyof TransformProperty
123
123
  ]
124
124
  : 0,
125
- { duration: 0 }
125
+ { duration: exitingDuration }
126
126
  ),
127
127
  value[transformProp as keyof TransformProperty]
128
128
  )
@@ -183,19 +183,19 @@ export class EntryExitTransition
183
183
  animations: {
184
184
  originX: delayFunction(
185
185
  delay + exitingDuration,
186
- withTiming(values.originX, { duration: 0 })
186
+ withTiming(values.originX, { duration: exitingDuration })
187
187
  ),
188
188
  originY: delayFunction(
189
189
  delay + exitingDuration,
190
- withTiming(values.originY, { duration: 0 })
190
+ withTiming(values.originY, { duration: exitingDuration })
191
191
  ),
192
192
  width: delayFunction(
193
193
  delay + exitingDuration,
194
- withTiming(values.width, { duration: 0 })
194
+ withTiming(values.width, { duration: exitingDuration })
195
195
  ),
196
196
  height: delayFunction(
197
197
  delay + exitingDuration,
198
- withTiming(values.height, { duration: 0 })
198
+ withTiming(values.height, { duration: exitingDuration })
199
199
  ),
200
200
  ...animations,
201
201
  },