react-native-reanimated 2.3.0-beta.2 → 2.3.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 (168) hide show
  1. package/Common/cpp/NativeModules/NativeReanimatedModule.cpp +12 -3
  2. package/Common/cpp/NativeModules/NativeReanimatedModuleSpec.cpp +13 -0
  3. package/Common/cpp/Registries/EventHandlerRegistry.cpp +2 -2
  4. package/Common/cpp/Registries/MapperRegistry.cpp +5 -5
  5. package/Common/cpp/SharedItems/FrozenObject.cpp +1 -3
  6. package/Common/cpp/SharedItems/ShareableValue.cpp +8 -10
  7. package/Common/cpp/Tools/FeaturesConfig.cpp +5 -0
  8. package/Common/cpp/Tools/JSIStoreValueUser.cpp +8 -8
  9. package/Common/cpp/Tools/Mapper.cpp +1 -1
  10. package/Common/cpp/Tools/RuntimeDecorator.cpp +40 -4
  11. package/Common/cpp/Tools/WorkletEventHandler.cpp +3 -1
  12. package/Common/cpp/headers/NativeModules/NativeReanimatedModule.h +5 -0
  13. package/Common/cpp/headers/NativeModules/NativeReanimatedModuleSpec.h +6 -1
  14. package/Common/cpp/headers/Registries/EventHandlerRegistry.h +1 -0
  15. package/Common/cpp/headers/Registries/MapperRegistry.h +1 -0
  16. package/Common/cpp/headers/SharedItems/FrozenObject.h +4 -0
  17. package/Common/cpp/headers/SharedItems/HostFunctionHandler.h +2 -0
  18. package/Common/cpp/headers/SharedItems/MutableValue.h +2 -0
  19. package/Common/cpp/headers/SharedItems/MutableValueSetterProxy.h +3 -1
  20. package/Common/cpp/headers/SharedItems/RemoteObject.h +4 -1
  21. package/Common/cpp/headers/SharedItems/ShareableValue.h +2 -0
  22. package/Common/cpp/headers/SharedItems/SharedParent.h +9 -9
  23. package/Common/cpp/headers/SharedItems/ValueWrapper.h +32 -28
  24. package/Common/cpp/headers/SpecTools/ErrorHandler.h +1 -0
  25. package/Common/cpp/headers/Tools/FeaturesConfig.h +19 -0
  26. package/Common/cpp/headers/Tools/JSIStoreValueUser.h +2 -5
  27. package/Common/cpp/headers/Tools/Mapper.h +2 -0
  28. package/Common/cpp/headers/Tools/PlatformDepMethodsHolder.h +5 -0
  29. package/Common/cpp/headers/Tools/ReanimatedHiddenHeaders.h +1 -5
  30. package/Common/cpp/headers/Tools/RuntimeDecorator.h +10 -7
  31. package/Common/cpp/headers/Tools/Scheduler.h +2 -0
  32. package/Common/cpp/headers/Tools/WorkletEventHandler.h +2 -1
  33. package/Common/cpp/hidden_headers/Logger.h +2 -2
  34. package/Common/cpp/hidden_headers/LoggerInterface.h +1 -1
  35. package/README.md +1 -1
  36. package/RNReanimated.podspec +21 -3
  37. package/android/build.gradle +33 -13
  38. package/android/expo/linking.gradle +46 -0
  39. package/android/expo/src/main/java/com/swmansion/reanimated/EXReanimatedAdapter.java +12 -0
  40. package/android/expo/src/main/java/expo/modules/adapters/reanimated/EXReanimatedPackage.java +26 -0
  41. package/android/react-native-reanimated-63-hermes.aar +0 -0
  42. package/android/react-native-reanimated-63-jsc.aar +0 -0
  43. package/android/react-native-reanimated-64-hermes.aar +0 -0
  44. package/android/react-native-reanimated-64-jsc.aar +0 -0
  45. package/android/react-native-reanimated-65-hermes.aar +0 -0
  46. package/android/react-native-reanimated-65-jsc.aar +0 -0
  47. package/android/react-native-reanimated-66-hermes.aar +0 -0
  48. package/android/react-native-reanimated-66-jsc.aar +0 -0
  49. package/android/react-native-reanimated-67-hermes.aar +0 -0
  50. package/android/react-native-reanimated-67-jsc.aar +0 -0
  51. package/expo-module.config.json +3 -0
  52. package/ios/LayoutReanimation/REAAnimationsManager.m +65 -19
  53. package/ios/LayoutReanimation/REAUIManager.mm +101 -61
  54. package/ios/Nodes/REAPropsNode.m +1 -1
  55. package/ios/REAEventDispatcher.m +1 -1
  56. package/ios/REAModule.h +0 -2
  57. package/ios/REAModule.m +0 -3
  58. package/ios/REANodesManager.m +1 -0
  59. package/ios/RNGestureHandlerStateManager.h +5 -0
  60. package/ios/native/NativeMethods.h +5 -0
  61. package/ios/native/NativeMethods.mm +14 -6
  62. package/ios/native/NativeProxy.h +1 -0
  63. package/ios/native/NativeProxy.mm +84 -63
  64. package/ios/native/REAIOSErrorHandler.mm +19 -15
  65. package/ios/native/REAIOSLogger.mm +10 -6
  66. package/ios/native/REAIOSScheduler.mm +17 -10
  67. package/ios/native/REAInitializer.mm +39 -37
  68. package/ios/native/UIResponder+Reanimated.mm +2 -2
  69. package/lib/Animated.js +11 -5
  70. package/lib/ConfigHelper.js +121 -138
  71. package/lib/ReanimatedEventEmitter.js +0 -1
  72. package/lib/ReanimatedModule.js +0 -1
  73. package/lib/ReanimatedModule.macos.js +0 -1
  74. package/lib/ReanimatedModule.native.js +5 -6
  75. package/lib/ReanimatedModule.windows.js +0 -1
  76. package/lib/ReanimatedModuleCompat.js +64 -35
  77. package/lib/createAnimatedComponent.js +469 -499
  78. package/lib/index.js +11 -5
  79. package/lib/reanimated1/core/Core.test.js +1 -1
  80. package/lib/reanimated2/NativeMethods.js +7 -0
  81. package/lib/reanimated2/NativeReanimated/NativeReanimated.js +3 -0
  82. package/lib/reanimated2/PropAdapters.js +0 -1
  83. package/lib/reanimated2/UpdateProps.js +1 -1
  84. package/lib/reanimated2/ViewDescriptorsSet.js +4 -2
  85. package/lib/reanimated2/animation/spring.js +2 -0
  86. package/lib/reanimated2/animation/styleAnimation.js +5 -1
  87. package/lib/reanimated2/animation/util.js +23 -0
  88. package/lib/reanimated2/component/FlatList.js +30 -0
  89. package/lib/reanimated2/component/WrappedComponents.js +9 -0
  90. package/lib/reanimated2/component/index.js +4 -0
  91. package/lib/reanimated2/core.js +34 -6
  92. package/lib/reanimated2/globals.d.ts +8 -0
  93. package/lib/reanimated2/js-reanimated/JSReanimated.js +4 -0
  94. package/lib/reanimated2/js-reanimated/Mapper.js +4 -3
  95. package/lib/reanimated2/js-reanimated/MapperRegistry.js +3 -6
  96. package/lib/reanimated2/js-reanimated/MutableValue.js +0 -2
  97. package/lib/reanimated2/js-reanimated/index.js +10 -8
  98. package/lib/reanimated2/layoutReanimation/LayoutAnimationRepository.js +14 -5
  99. package/lib/reanimated2/layoutReanimation/defaultAnimations/Default.js +14 -14
  100. package/lib/reanimated2/layoutReanimation/defaultAnimations/Flip.js +8 -8
  101. package/lib/reanimated2/layoutReanimation/defaultAnimations/Rotate.js +16 -16
  102. package/lib/reanimated2/layoutReanimation/defaultAnimations/Slide.js +16 -16
  103. package/lib/reanimated2/layoutReanimation/defaultAnimations/Zoom.js +4 -4
  104. package/lib/reanimated2/layoutReanimation/defaultTransitions/CurvedTransition.js +20 -8
  105. package/lib/reanimated2/layoutReanimation/defaultTransitions/EntryExitTransition.js +3 -3
  106. package/lib/reanimated2/layoutReanimation/defaultTransitions/FadingTransition.js +8 -8
  107. package/lib/reanimated2/layoutReanimation/defaultTransitions/JumpingTransition.js +10 -10
  108. package/lib/reanimated2/layoutReanimation/defaultTransitions/LinearTransition.js +8 -8
  109. package/lib/reanimated2/layoutReanimation/defaultTransitions/SequencedTransition.js +8 -8
  110. package/lib/reanimated2/mock.js +3 -1
  111. package/lib/setAndForwardRef.js +14 -48
  112. package/mock.js +1 -1
  113. package/package.json +27 -23
  114. package/plugin.js +111 -110
  115. package/react-native-reanimated.d.ts +56 -27
  116. package/src/Animated.js +11 -5
  117. package/src/{ConfigHelper.js → ConfigHelper.ts} +15 -7
  118. package/src/{ReanimatedEventEmitter.js → ReanimatedEventEmitter.ts} +0 -0
  119. package/src/{ReanimatedModule.js → ReanimatedModule.macos.ts} +0 -0
  120. package/src/{ReanimatedModule.native.js → ReanimatedModule.native.ts} +0 -0
  121. package/src/{ReanimatedModule.macos.js → ReanimatedModule.ts} +0 -0
  122. package/src/{ReanimatedModule.windows.js → ReanimatedModule.windows.ts} +0 -0
  123. package/src/ReanimatedModuleCompat.ts +51 -0
  124. package/src/{createAnimatedComponent.js → createAnimatedComponent.tsx} +278 -124
  125. package/src/reanimated1/core/Core.test.js +1 -1
  126. package/src/reanimated2/NativeMethods.ts +13 -1
  127. package/src/reanimated2/NativeReanimated/NativeReanimated.ts +5 -11
  128. package/src/reanimated2/PropAdapters.ts +0 -1
  129. package/src/reanimated2/UpdateProps.ts +1 -1
  130. package/src/reanimated2/ViewDescriptorsSet.ts +6 -2
  131. package/src/reanimated2/animation/commonTypes.ts +4 -4
  132. package/src/reanimated2/animation/decay.ts +2 -2
  133. package/src/reanimated2/animation/delay.ts +3 -3
  134. package/src/reanimated2/animation/index.ts +7 -7
  135. package/src/reanimated2/animation/repeat.ts +4 -4
  136. package/src/reanimated2/animation/sequence.ts +2 -2
  137. package/src/reanimated2/animation/spring.ts +6 -5
  138. package/src/reanimated2/animation/styleAnimation.ts +24 -12
  139. package/src/reanimated2/animation/timing.ts +5 -5
  140. package/src/reanimated2/animation/util.ts +45 -6
  141. package/src/reanimated2/component/FlatList.tsx +44 -0
  142. package/src/reanimated2/component/WrappedComponents.ts +11 -0
  143. package/src/reanimated2/component/index.ts +9 -0
  144. package/src/reanimated2/core.ts +62 -17
  145. package/src/reanimated2/globals.d.ts +8 -0
  146. package/src/reanimated2/hook/useAnimatedStyle.ts +2 -2
  147. package/src/reanimated2/js-reanimated/JSReanimated.ts +15 -26
  148. package/src/reanimated2/js-reanimated/Mapper.ts +22 -9
  149. package/src/reanimated2/js-reanimated/MapperRegistry.ts +22 -19
  150. package/src/reanimated2/js-reanimated/MutableValue.ts +11 -11
  151. package/src/reanimated2/js-reanimated/index.ts +31 -14
  152. package/src/reanimated2/layoutReanimation/{LayoutAnimationRepository.tsx → LayoutAnimationRepository.ts} +18 -5
  153. package/src/reanimated2/layoutReanimation/animationBuilder/commonTypes.ts +39 -20
  154. package/src/reanimated2/layoutReanimation/animationBuilder/index.ts +5 -1
  155. package/src/reanimated2/layoutReanimation/defaultAnimations/Default.ts +21 -15
  156. package/src/reanimated2/layoutReanimation/defaultAnimations/Flip.ts +29 -24
  157. package/src/reanimated2/layoutReanimation/defaultAnimations/Rotate.ts +61 -34
  158. package/src/reanimated2/layoutReanimation/defaultAnimations/Slide.ts +49 -34
  159. package/src/reanimated2/layoutReanimation/defaultAnimations/Zoom.ts +17 -12
  160. package/src/reanimated2/layoutReanimation/defaultTransitions/CurvedTransition.ts +20 -8
  161. package/src/reanimated2/layoutReanimation/defaultTransitions/EntryExitTransition.ts +9 -9
  162. package/src/reanimated2/layoutReanimation/defaultTransitions/FadingTransition.ts +8 -8
  163. package/src/reanimated2/layoutReanimation/defaultTransitions/JumpingTransition.ts +20 -14
  164. package/src/reanimated2/layoutReanimation/defaultTransitions/LinearTransition.ts +14 -8
  165. package/src/reanimated2/layoutReanimation/defaultTransitions/SequencedTransition.ts +24 -12
  166. package/src/reanimated2/mock.ts +3 -1
  167. package/src/{setAndForwardRef.js → setAndForwardRef.ts} +12 -2
  168. package/src/ReanimatedModuleCompat.js +0 -37
@@ -1,10 +1,14 @@
1
- import React from 'react';
1
+ import React, { Component, ComponentType, MutableRefObject, Ref } from 'react';
2
2
  import { findNodeHandle, Platform, StyleSheet } from 'react-native';
3
3
  import ReanimatedEventEmitter from './ReanimatedEventEmitter';
4
4
 
5
+ // @ts-ignore JS file
5
6
  import AnimatedEvent from './reanimated1/core/AnimatedEvent';
7
+ // @ts-ignore JS file
6
8
  import AnimatedNode from './reanimated1/core/AnimatedNode';
9
+ // @ts-ignore JS file
7
10
  import AnimatedValue from './reanimated1/core/AnimatedValue';
11
+ // @ts-ignore JS file
8
12
  import { createOrReusePropsNode } from './reanimated1/core/AnimatedProps';
9
13
  import WorkletEventHandler from './reanimated2/WorkletEventHandler';
10
14
  import setAndForwardRef from './setAndForwardRef';
@@ -13,18 +17,41 @@ import './reanimated2/layoutReanimation/LayoutAnimationRepository';
13
17
  import invariant from 'invariant';
14
18
  import { adaptViewConfig } from './ConfigHelper';
15
19
  import { RNRenderer } from './reanimated2/platform-specific/RNRenderer';
16
- import { makeMutable, runOnUI } from './reanimated2/core';
20
+ import {
21
+ makeMutable,
22
+ runOnUI,
23
+ enableLayoutAnimations,
24
+ } from './reanimated2/core';
17
25
  import {
18
26
  DefaultEntering,
19
27
  DefaultExiting,
20
28
  DefaultLayout,
21
29
  } from './reanimated2/layoutReanimation/defaultAnimations/Default';
22
- import { isJest, isChromeDebugger } from './reanimated2/PlatformChecker';
30
+ import {
31
+ isJest,
32
+ isChromeDebugger,
33
+ shouldBeUseWeb,
34
+ } from './reanimated2/PlatformChecker';
23
35
  import { initialUpdaterRun } from './reanimated2/animation';
36
+ import {
37
+ BaseAnimationBuilder,
38
+ EntryExitAnimationFunction,
39
+ ILayoutAnimationBuilder,
40
+ } from './reanimated2/layoutReanimation';
41
+ import { SharedValue, StyleProps } from './reanimated2/commonTypes';
42
+ import {
43
+ ViewDescriptorsSet,
44
+ ViewRefSet,
45
+ } from './reanimated2/ViewDescriptorsSet';
24
46
 
25
47
  const NODE_MAPPING = new Map();
26
48
 
27
- function listener(data) {
49
+ interface ListenerData {
50
+ viewTag: number;
51
+ props: StyleProps;
52
+ }
53
+
54
+ function listener(data: ListenerData) {
28
55
  const component = NODE_MAPPING.get(data.viewTag);
29
56
  component && component._updateFromNative(data.props);
30
57
  }
@@ -34,7 +61,7 @@ function dummyListener() {
34
61
  // event is used.
35
62
  }
36
63
 
37
- function hasAnimatedNodes(value) {
64
+ function hasAnimatedNodes(value: unknown): boolean {
38
65
  if (value instanceof AnimatedNode) {
39
66
  return true;
40
67
  }
@@ -42,18 +69,21 @@ function hasAnimatedNodes(value) {
42
69
  return value.some((item) => hasAnimatedNodes(item));
43
70
  }
44
71
  if (value && typeof value === 'object') {
45
- return Object.keys(value).some((key) => hasAnimatedNodes(value[key]));
72
+ return Object.keys(value).some((key) =>
73
+ hasAnimatedNodes((value as Record<string, unknown>)[key])
74
+ );
46
75
  }
47
76
  return false;
48
77
  }
49
78
 
50
- function flattenArray(array) {
79
+ type NestedArray<T> = T | NestedArray<T>[];
80
+ function flattenArray<T>(array: NestedArray<T>): T[] {
51
81
  if (!Array.isArray(array)) {
52
82
  return [array];
53
83
  }
54
- const resultArr = [];
84
+ const resultArr: T[] = [];
55
85
 
56
- const _flattenArray = (arr) => {
86
+ const _flattenArray = (arr: NestedArray<T>[]): void => {
57
87
  arr.forEach((item) => {
58
88
  if (Array.isArray(item)) {
59
89
  _flattenArray(item);
@@ -66,7 +96,88 @@ function flattenArray(array) {
66
96
  return resultArr;
67
97
  }
68
98
 
69
- export default function createAnimatedComponent(Component, options = {}) {
99
+ function onlyAnimatedStyles(styles: StyleProps[]) {
100
+ return styles.filter((style) => style?.viewDescriptors);
101
+ }
102
+
103
+ function isSameAnimatedStyle(
104
+ style1?: StyleProps,
105
+ style2?: StyleProps
106
+ ): boolean {
107
+ // We cannot use equality check to compare useAnimatedStyle outputs directly.
108
+ // Instead, we can compare its viewsRefs.
109
+ return style1?.viewsRef === style2?.viewsRef;
110
+ }
111
+
112
+ const isSameAnimatedProps = isSameAnimatedStyle;
113
+
114
+ const has = <K extends string>(
115
+ key: K,
116
+ x: unknown
117
+ ): x is { [key in K]: unknown } => {
118
+ if (typeof x === 'function' || typeof x === 'object') {
119
+ if (x === null || x === undefined) {
120
+ return false;
121
+ } else {
122
+ return key in x;
123
+ }
124
+ }
125
+ return false;
126
+ };
127
+
128
+ interface AnimatedProps extends Record<string, unknown> {
129
+ viewDescriptors?: ViewDescriptorsSet;
130
+ viewsRef?: ViewRefSet<unknown>;
131
+ initial?: SharedValue<StyleProps>;
132
+ }
133
+
134
+ export type AnimatedComponentProps<P extends Record<string, unknown>> = P & {
135
+ forwardedRef?: Ref<Component>;
136
+ style?: NestedArray<StyleProps>;
137
+ animatedProps?: Partial<AnimatedComponentProps<AnimatedProps>>;
138
+ animatedStyle?: StyleProps;
139
+ layout?:
140
+ | BaseAnimationBuilder
141
+ | ILayoutAnimationBuilder
142
+ | typeof BaseAnimationBuilder;
143
+ entering?:
144
+ | BaseAnimationBuilder
145
+ | typeof BaseAnimationBuilder
146
+ | EntryExitAnimationFunction
147
+ | Keyframe;
148
+ exiting?:
149
+ | BaseAnimationBuilder
150
+ | typeof BaseAnimationBuilder
151
+ | EntryExitAnimationFunction
152
+ | Keyframe;
153
+ };
154
+
155
+ type Options<P> = {
156
+ setNativeProps: (ref: ComponentRef, props: P) => void;
157
+ };
158
+
159
+ interface ComponentRef extends Component {
160
+ setNativeProps?: (props: Record<string, unknown>) => void;
161
+ getScrollableNode?: () => ComponentRef;
162
+ }
163
+
164
+ interface InitialComponentProps extends Record<string, unknown> {
165
+ ref?: Ref<Component>;
166
+ collapsable?: boolean;
167
+ }
168
+
169
+ interface PropsAnimated {
170
+ __onEvaluate: () => StyleProps;
171
+ __detach: () => void;
172
+ __getValue: () => StyleProps;
173
+ update: () => void;
174
+ setNativeView: (view: Component) => void;
175
+ }
176
+
177
+ export default function createAnimatedComponent(
178
+ Component: ComponentType<InitialComponentProps>,
179
+ options?: Options<InitialComponentProps>
180
+ ): ComponentType<AnimatedComponentProps<InitialComponentProps>> {
70
181
  invariant(
71
182
  typeof Component !== 'function' ||
72
183
  (Component.prototype && Component.prototype.isReactComponent),
@@ -74,13 +185,21 @@ export default function createAnimatedComponent(Component, options = {}) {
74
185
  'use a class component instead.'
75
186
  );
76
187
 
77
- class AnimatedComponent extends React.Component {
188
+ class AnimatedComponent extends React.Component<
189
+ AnimatedComponentProps<InitialComponentProps>
190
+ > {
78
191
  _invokeAnimatedPropsCallbackOnMount = false;
79
- _styles = null;
192
+ _styles: StyleProps[] | null = null;
193
+ _animatedProps?: Partial<AnimatedComponentProps<AnimatedProps>>;
80
194
  _viewTag = -1;
81
195
  _isFirstRender = true;
196
+ animatedStyle: { value: StyleProps } = { value: {} };
197
+ sv: SharedValue<null | Record<string, unknown>> | null;
198
+ _propsAnimated?: PropsAnimated;
199
+ _component: ComponentRef | null = null;
200
+ static displayName: string;
82
201
 
83
- constructor(props) {
202
+ constructor(props: AnimatedComponentProps<InitialComponentProps>) {
84
203
  super(props);
85
204
  this._attachProps(this.props);
86
205
  if (isJest()) {
@@ -103,7 +222,9 @@ export default function createAnimatedComponent(Component, options = {}) {
103
222
  this._animatedPropsCallback();
104
223
  }
105
224
 
106
- this._propsAnimated && this._propsAnimated.setNativeView(this._component);
225
+ this._propsAnimated &&
226
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
227
+ this._propsAnimated.setNativeView(this._component!);
107
228
  this._attachNativeEvents();
108
229
  this._attachPropUpdater();
109
230
  this._attachAnimatedStyles();
@@ -112,23 +233,23 @@ export default function createAnimatedComponent(Component, options = {}) {
112
233
  _getEventViewRef() {
113
234
  // Make sure to get the scrollable node for components that implement
114
235
  // `ScrollResponder.Mixin`.
115
- return this._component.getScrollableNode
236
+ return this._component?.getScrollableNode
116
237
  ? this._component.getScrollableNode()
117
238
  : this._component;
118
239
  }
119
240
 
120
241
  _attachNativeEvents() {
121
242
  const node = this._getEventViewRef();
122
- const viewTag = findNodeHandle(options.setNativeProps ? this : node);
243
+ const viewTag = findNodeHandle(options?.setNativeProps ? this : node);
123
244
  for (const key in this.props) {
124
245
  const prop = this.props[key];
125
246
  if (prop instanceof AnimatedEvent) {
126
- prop.attachEvent(node, key);
247
+ (prop as AnimatedEvent).attachEvent(node, key);
127
248
  } else if (
128
- prop?.current &&
249
+ has('current', prop) &&
129
250
  prop.current instanceof WorkletEventHandler
130
251
  ) {
131
- prop.current.registerForEvents(viewTag, key);
252
+ prop.current.registerForEvents(viewTag as number, key);
132
253
  }
133
254
  }
134
255
  }
@@ -139,9 +260,9 @@ export default function createAnimatedComponent(Component, options = {}) {
139
260
  for (const key in this.props) {
140
261
  const prop = this.props[key];
141
262
  if (prop instanceof AnimatedEvent) {
142
- prop.detachEvent(node, key);
263
+ (prop as AnimatedEvent).detachEvent(node, key);
143
264
  } else if (
144
- prop?.current &&
265
+ has('current', prop) &&
145
266
  prop.current instanceof WorkletEventHandler
146
267
  ) {
147
268
  prop.current.unregisterFromEvents();
@@ -150,17 +271,15 @@ export default function createAnimatedComponent(Component, options = {}) {
150
271
  }
151
272
 
152
273
  _detachStyles() {
153
- if (Platform.OS === 'web') {
274
+ if (Platform.OS === 'web' && this._styles !== null) {
154
275
  for (const style of this._styles) {
155
276
  if (style?.viewsRef) {
156
277
  style.viewsRef.remove(this);
157
278
  }
158
279
  }
159
- } else if (this._viewTag !== -1) {
280
+ } else if (this._viewTag !== -1 && this._styles !== null) {
160
281
  for (const style of this._styles) {
161
- if (style?.viewDescriptors) {
162
- style.viewDescriptors.remove(this._viewTag);
163
- }
282
+ style.viewDescriptors.remove(this._viewTag);
164
283
  }
165
284
  if (this.props.animatedProps?.viewDescriptors) {
166
285
  this.props.animatedProps.viewDescriptors.remove(this._viewTag);
@@ -168,18 +287,20 @@ export default function createAnimatedComponent(Component, options = {}) {
168
287
  }
169
288
  }
170
289
 
171
- _reattachNativeEvents(prevProps) {
290
+ _reattachNativeEvents(
291
+ prevProps: AnimatedComponentProps<InitialComponentProps>
292
+ ) {
172
293
  const node = this._getEventViewRef();
173
294
  const attached = new Set();
174
295
  const nextEvts = new Set();
175
- let viewTag;
296
+ let viewTag: number | undefined;
176
297
 
177
298
  for (const key in this.props) {
178
299
  const prop = this.props[key];
179
300
  if (prop instanceof AnimatedEvent) {
180
- nextEvts.add(prop.__nodeID);
301
+ nextEvts.add((prop as AnimatedEvent).__nodeID);
181
302
  } else if (
182
- prop?.current &&
303
+ has('current', prop) &&
183
304
  prop.current instanceof WorkletEventHandler
184
305
  ) {
185
306
  if (viewTag === undefined) {
@@ -190,15 +311,15 @@ export default function createAnimatedComponent(Component, options = {}) {
190
311
  for (const key in prevProps) {
191
312
  const prop = this.props[key];
192
313
  if (prop instanceof AnimatedEvent) {
193
- if (!nextEvts.has(prop.__nodeID)) {
314
+ if (!nextEvts.has((prop as AnimatedEvent).__nodeID)) {
194
315
  // event was in prev props but not in current props, we detach
195
- prop.detachEvent(node, key);
316
+ (prop as AnimatedEvent).detachEvent(node, key);
196
317
  } else {
197
318
  // event was in prev and is still in current props
198
- attached.add(prop.__nodeID);
319
+ attached.add((prop as AnimatedEvent).__nodeID);
199
320
  }
200
321
  } else if (
201
- prop?.current &&
322
+ has('current', prop) &&
202
323
  prop.current instanceof WorkletEventHandler &&
203
324
  prop.current.reattachNeeded
204
325
  ) {
@@ -208,15 +329,19 @@ export default function createAnimatedComponent(Component, options = {}) {
208
329
 
209
330
  for (const key in this.props) {
210
331
  const prop = this.props[key];
211
- if (prop instanceof AnimatedEvent && !attached.has(prop.__nodeID)) {
332
+ if (
333
+ prop instanceof AnimatedEvent &&
334
+ !attached.has((prop as AnimatedEvent).__nodeID)
335
+ ) {
212
336
  // not yet attached
213
- prop.attachEvent(node, key);
337
+ (prop as AnimatedEvent).attachEvent(node, key);
214
338
  } else if (
215
- prop?.current &&
339
+ has('current', prop) &&
216
340
  prop.current instanceof WorkletEventHandler &&
217
341
  prop.current.reattachNeeded
218
342
  ) {
219
- prop.current.registerForEvents(viewTag, key);
343
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
344
+ prop.current.registerForEvents(viewTag!, key);
220
345
  prop.current.reattachNeeded = false;
221
346
  }
222
347
  }
@@ -238,11 +363,12 @@ export default function createAnimatedComponent(Component, options = {}) {
238
363
  } else if (typeof this._component.setNativeProps !== 'function') {
239
364
  this.forceUpdate();
240
365
  } else {
241
- this._component.setNativeProps(this._propsAnimated.__getValue());
366
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
367
+ this._component.setNativeProps(this._propsAnimated!.__getValue());
242
368
  }
243
369
  };
244
370
 
245
- _attachProps(nextProps) {
371
+ _attachProps(nextProps: StyleProps) {
246
372
  const oldPropsAnimated = this._propsAnimated;
247
373
 
248
374
  this._propsAnimated = createOrReusePropsNode(
@@ -264,12 +390,13 @@ export default function createAnimatedComponent(Component, options = {}) {
264
390
  }
265
391
  }
266
392
 
267
- _updateFromNative(props) {
268
- if (options.setNativeProps) {
269
- options.setNativeProps(this._component, props);
393
+ _updateFromNative(props: StyleProps) {
394
+ if (options?.setNativeProps) {
395
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
396
+ options.setNativeProps(this._component!, props);
270
397
  } else {
271
398
  // eslint-disable-next-line no-unused-expressions
272
- this._component.setNativeProps?.(props);
399
+ this._component?.setNativeProps?.(props);
273
400
  }
274
401
  }
275
402
 
@@ -282,9 +409,17 @@ export default function createAnimatedComponent(Component, options = {}) {
282
409
  }
283
410
 
284
411
  _attachAnimatedStyles() {
285
- const styles = flattenArray(this.props.style);
412
+ const styles = this.props.style
413
+ ? onlyAnimatedStyles(flattenArray<StyleProps>(this.props.style))
414
+ : [];
415
+ const prevStyles = this._styles;
286
416
  this._styles = styles;
287
- let viewTag, viewName;
417
+
418
+ const prevAnimatedProps = this._animatedProps;
419
+ this._animatedProps = this.props.animatedProps;
420
+
421
+ let viewTag: number | null;
422
+ let viewName: string | null;
288
423
  if (Platform.OS === 'web') {
289
424
  viewTag = findNodeHandle(this);
290
425
  viewName = null;
@@ -304,58 +439,71 @@ export default function createAnimatedComponent(Component, options = {}) {
304
439
  */
305
440
  viewName = hostInstance?.viewConfig?.uiViewClassName;
306
441
  // update UI props whitelist for this view
307
- if (
308
- hostInstance &&
309
- this._hasReanimated2Props(styles) &&
310
- hostInstance.viewConfig
311
- ) {
442
+ const hasReanimated2Props =
443
+ this.props.animatedProps?.viewDescriptors || styles.length;
444
+ if (hasReanimated2Props && hostInstance?.viewConfig) {
312
445
  adaptViewConfig(hostInstance.viewConfig);
313
446
  }
314
447
  }
315
- this._viewTag = viewTag;
448
+ this._viewTag = viewTag as number;
449
+
450
+ // remove old styles
451
+ if (prevStyles) {
452
+ // in most of the cases, views have only a single animated style and it remains unchanged
453
+ const hasOneSameStyle =
454
+ styles.length === 1 &&
455
+ prevStyles.length === 1 &&
456
+ isSameAnimatedStyle(styles[0], prevStyles[0]);
457
+
458
+ if (!hasOneSameStyle) {
459
+ // otherwise, remove each style that is not present in new styles
460
+ for (const prevStyle of prevStyles) {
461
+ const isPresent = styles.some((style) =>
462
+ isSameAnimatedStyle(style, prevStyle)
463
+ );
464
+ if (!isPresent) {
465
+ prevStyle.viewDescriptors.remove(viewTag);
466
+ }
467
+ }
468
+ }
469
+ }
316
470
 
317
471
  styles.forEach((style) => {
318
- if (style?.viewDescriptors) {
319
- style.viewDescriptors.add({ tag: viewTag, name: viewName });
320
- if (isJest()) {
321
- /**
322
- * We need to connect Jest's TestObject instance whose contains just props object
323
- * with the updateProps() function where we update the properties of the component.
324
- * We can't update props object directly because TestObject contains a copy of props - look at render function:
325
- * const props = this._filterNonAnimatedProps(this.props);
326
- */
327
- this.animatedStyle.value = {
328
- ...this.animatedStyle.value,
329
- ...style.initial.value,
330
- };
331
- style.animatedStyle.current = this.animatedStyle;
332
- }
472
+ style.viewDescriptors.add({ tag: viewTag, name: viewName });
473
+ if (isJest()) {
474
+ /**
475
+ * We need to connect Jest's TestObject instance whose contains just props object
476
+ * with the updateProps() function where we update the properties of the component.
477
+ * We can't update props object directly because TestObject contains a copy of props - look at render function:
478
+ * const props = this._filterNonAnimatedProps(this.props);
479
+ */
480
+ this.animatedStyle.value = {
481
+ ...this.animatedStyle.value,
482
+ ...style.initial.value,
483
+ };
484
+ style.animatedStyle.current = this.animatedStyle;
333
485
  }
334
486
  });
487
+
488
+ // detach old animatedProps
489
+ if (
490
+ prevAnimatedProps &&
491
+ !isSameAnimatedProps(prevAnimatedProps, this.props.animatedProps)
492
+ ) {
493
+ prevAnimatedProps.viewDescriptors!.remove(viewTag as number);
494
+ }
495
+
335
496
  // attach animatedProps property
336
497
  if (this.props.animatedProps?.viewDescriptors) {
337
498
  this.props.animatedProps.viewDescriptors.add({
338
- tag: viewTag,
339
- name: viewName,
499
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
500
+ tag: viewTag!,
501
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
502
+ name: viewName!,
340
503
  });
341
504
  }
342
505
  }
343
506
 
344
- _hasReanimated2Props(flattenStyles) {
345
- if (this.props.animatedProps?.viewDescriptors) {
346
- return true;
347
- }
348
- if (this.props.style) {
349
- for (const style of flattenStyles) {
350
- // eslint-disable-next-line no-prototype-builtins
351
- if (style?.hasOwnProperty('viewDescriptors')) {
352
- return true;
353
- }
354
- }
355
- }
356
- return false;
357
- }
358
-
359
507
  _detachPropUpdater() {
360
508
  const viewTag = findNodeHandle(this);
361
509
  NODE_MAPPING.delete(viewTag);
@@ -364,16 +512,23 @@ export default function createAnimatedComponent(Component, options = {}) {
364
512
  }
365
513
  }
366
514
 
367
- componentDidUpdate(prevProps) {
515
+ componentDidUpdate(
516
+ prevProps: AnimatedComponentProps<InitialComponentProps>
517
+ ) {
368
518
  this._attachProps(this.props);
369
519
  this._reattachNativeEvents(prevProps);
370
520
 
371
- this._propsAnimated && this._propsAnimated.setNativeView(this._component);
521
+ this._propsAnimated &&
522
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
523
+ this._propsAnimated.setNativeView(this._component!);
372
524
  this._attachAnimatedStyles();
373
525
  }
374
526
 
375
- _setComponentRef = setAndForwardRef({
376
- getForwardedRef: () => this.props.forwardedRef,
527
+ _setComponentRef = setAndForwardRef<Component>({
528
+ getForwardedRef: () =>
529
+ this.props.forwardedRef as MutableRefObject<
530
+ Component<Record<string, unknown>, Record<string, unknown>, unknown>
531
+ >,
377
532
  setLocalRef: (ref) => {
378
533
  // TODO update config
379
534
  const tag = findNodeHandle(ref);
@@ -381,6 +536,9 @@ export default function createAnimatedComponent(Component, options = {}) {
381
536
  (this.props.layout || this.props.entering || this.props.exiting) &&
382
537
  tag != null
383
538
  ) {
539
+ if (!shouldBeUseWeb()) {
540
+ enableLayoutAnimations(true, false);
541
+ }
384
542
  let layout = this.props.layout ? this.props.layout : DefaultLayout;
385
543
  let entering = this.props.entering
386
544
  ? this.props.entering
@@ -389,16 +547,16 @@ export default function createAnimatedComponent(Component, options = {}) {
389
547
  ? this.props.exiting
390
548
  : DefaultExiting;
391
549
 
392
- if (layout.build) {
550
+ if (has('build', layout)) {
393
551
  layout = layout.build();
394
552
  }
395
553
 
396
- if (entering.build) {
397
- entering = entering.build();
554
+ if (has('build', entering)) {
555
+ entering = entering.build() as EntryExitAnimationFunction;
398
556
  }
399
557
 
400
- if (exiting.build) {
401
- exiting = exiting.build();
558
+ if (has('build', exiting)) {
559
+ exiting = exiting.build() as EntryExitAnimationFunction;
402
560
  }
403
561
 
404
562
  const config = {
@@ -416,25 +574,11 @@ export default function createAnimatedComponent(Component, options = {}) {
416
574
  if (ref !== this._component) {
417
575
  this._component = ref;
418
576
  }
419
-
420
- // TODO: Delete this after React Native also deletes this deprecation helper.
421
- if (ref != null && ref.getNode == null) {
422
- ref.getNode = () => {
423
- console.warn(
424
- '%s: Calling %s on the ref of an Animated component ' +
425
- 'is no longer necessary. You can now directly use the ref ' +
426
- 'instead. This method will be removed in a future release.',
427
- ref.constructor.name ?? '<<anonymous>>',
428
- 'getNode()'
429
- );
430
- return ref;
431
- };
432
- }
433
577
  },
434
578
  });
435
579
 
436
- _filterNonAnimatedStyle(inputStyle) {
437
- const style = {};
580
+ _filterNonAnimatedStyle(inputStyle: StyleProps) {
581
+ const style: StyleProps = {};
438
582
  for (const key in inputStyle) {
439
583
  const value = inputStyle[key];
440
584
  if (!hasAnimatedNodes(value)) {
@@ -448,20 +592,23 @@ export default function createAnimatedComponent(Component, options = {}) {
448
592
  return style;
449
593
  }
450
594
 
451
- _filterNonAnimatedProps(inputProps) {
452
- const props = {};
595
+ _filterNonAnimatedProps(
596
+ inputProps: AnimatedComponentProps<InitialComponentProps>
597
+ ): Record<string, unknown> {
598
+ const props: Record<string, unknown> = {};
453
599
  for (const key in inputProps) {
454
600
  const value = inputProps[key];
455
601
  if (key === 'style') {
456
- const styles = flattenArray(value);
457
- const processedStyle = styles.map((style) => {
602
+ const styleProp = inputProps.style;
603
+ const styles = flattenArray<StyleProps>(styleProp ?? []);
604
+ const processedStyle: StyleProps = styles.map((style) => {
458
605
  if (style && style.viewDescriptors) {
459
606
  // this is how we recognize styles returned by useAnimatedStyle
460
607
  style.viewsRef.add(this);
461
608
  if (this._isFirstRender) {
462
609
  return {
463
610
  ...style.initial.value,
464
- ...initialUpdaterRun(style.initial.updater),
611
+ ...initialUpdaterRun<StyleProps>(style.initial.updater),
465
612
  };
466
613
  } else {
467
614
  return style.initial.value;
@@ -474,10 +621,15 @@ export default function createAnimatedComponent(Component, options = {}) {
474
621
  StyleSheet.flatten(processedStyle)
475
622
  );
476
623
  } else if (key === 'animatedProps') {
477
- Object.keys(value.initial.value).forEach((key) => {
478
- props[key] = value.initial.value[key];
479
- value.viewsRef.add(this);
480
- });
624
+ const animatedProp = inputProps.animatedProps as Partial<
625
+ AnimatedComponentProps<AnimatedProps>
626
+ >;
627
+ if (animatedProp.initial !== undefined) {
628
+ Object.keys(animatedProp.initial.value).forEach((key) => {
629
+ props[key] = animatedProp.initial?.value[key];
630
+ animatedProp.viewsRef?.add(this);
631
+ });
632
+ }
481
633
  } else if (value instanceof AnimatedEvent) {
482
634
  // we cannot filter out event listeners completely as some components
483
635
  // rely on having a callback registered in order to generate events
@@ -485,13 +637,15 @@ export default function createAnimatedComponent(Component, options = {}) {
485
637
  // native event dispatcher to hijack events.
486
638
  props[key] = dummyListener;
487
639
  } else if (
488
- value?.current &&
640
+ has('current', value) &&
489
641
  value.current instanceof WorkletEventHandler
490
642
  ) {
491
643
  if (value.current.eventNames.length > 0) {
492
644
  value.current.eventNames.forEach((eventName) => {
493
- props[eventName] = value.current.listeners
494
- ? value.current.listeners[eventName]
645
+ props[eventName] = has('listeners', value.current)
646
+ ? (value.current.listeners as Record<string, unknown>)[
647
+ eventName
648
+ ]
495
649
  : dummyListener;
496
650
  });
497
651
  } else {
@@ -504,7 +658,7 @@ export default function createAnimatedComponent(Component, options = {}) {
504
658
  } else if (value instanceof AnimatedValue) {
505
659
  // if any prop in animated component is set directly to the `Value` we set those props to the first value of `Value` node in order
506
660
  // to avoid default values for a short moment when `Value` is being asynchrounously sent via bridge and initialized in the native side.
507
- props[key] = value._startingValue;
661
+ props[key] = (value as AnimatedValue)._startingValue;
508
662
  }
509
663
  }
510
664
  return props;
@@ -534,11 +688,11 @@ export default function createAnimatedComponent(Component, options = {}) {
534
688
  Component.displayName || Component.name || 'Component'
535
689
  })`;
536
690
 
537
- return React.forwardRef(function AnimatedComponentWrapper(props, ref) {
691
+ return React.forwardRef<Component>((props, ref) => {
538
692
  return (
539
693
  <AnimatedComponent
540
694
  {...props}
541
- {...(ref == null ? null : { forwardedRef: ref })}
695
+ {...(ref === null ? null : { forwardedRef: ref })}
542
696
  />
543
697
  );
544
698
  });