diff --git a/packages/react-native/Libraries/Animated/__tests__/Animated-test.js b/packages/react-native/Libraries/Animated/__tests__/Animated-test.js index eca451af1ba4dc..7796168b19502c 100644 --- a/packages/react-native/Libraries/Animated/__tests__/Animated-test.js +++ b/packages/react-native/Libraries/Animated/__tests__/Animated-test.js @@ -78,7 +78,8 @@ describe('Animated tests', () => { node.__attach(); - expect(anim.__getChildren().length).toBe(3); + // Children: [AnimatedStyle, AnimatedTransform, AnimatedInterpolation, AnimatedObject, AnimatedObject] + expect(anim.__getChildren().length).toBe(5); anim.setValue(0.5); diff --git a/packages/react-native/Libraries/Animated/__tests__/Animated-web-test.js b/packages/react-native/Libraries/Animated/__tests__/Animated-web-test.js index 2fccade525c107..e393454b9e43bb 100644 --- a/packages/react-native/Libraries/Animated/__tests__/Animated-web-test.js +++ b/packages/react-native/Libraries/Animated/__tests__/Animated-web-test.js @@ -84,7 +84,8 @@ describe('Animated tests', () => { node.__attach(); - expect(anim.__getChildren().length).toBe(3); + // Children: [AnimatedStyle, AnimatedTransform, AnimatedInterpolation, AnimatedObject, AnimatedObject] + expect(anim.__getChildren().length).toBe(5); anim.setValue(0.5); diff --git a/packages/react-native/Libraries/Animated/nodes/AnimatedProps.js b/packages/react-native/Libraries/Animated/nodes/AnimatedProps.js index d6ebbb02e3bfc5..333f147ab68cae 100644 --- a/packages/react-native/Libraries/Animated/nodes/AnimatedProps.js +++ b/packages/react-native/Libraries/Animated/nodes/AnimatedProps.js @@ -16,9 +16,27 @@ import {findNodeHandle} from '../../ReactNative/RendererProxy'; import {AnimatedEvent} from '../AnimatedEvent'; import NativeAnimatedHelper from '../NativeAnimatedHelper'; import AnimatedNode from './AnimatedNode'; +import AnimatedObject, {hasAnimatedNode} from './AnimatedObject'; import AnimatedStyle from './AnimatedStyle'; import invariant from 'invariant'; +function createAnimatedProps(inputProps: Object): Object { + const props: Object = {}; + for (const key in inputProps) { + const value = inputProps[key]; + if (key === 'style') { + props[key] = new AnimatedStyle(value); + } else if (value instanceof AnimatedNode) { + props[key] = value; + } else if (key !== 'children' && hasAnimatedNode(value)) { + props[key] = new AnimatedObject(value); + } else { + props[key] = value; + } + } + return props; +} + export default class AnimatedProps extends AnimatedNode { _props: Object; _animatedView: any; @@ -26,13 +44,7 @@ export default class AnimatedProps extends AnimatedNode { constructor(props: Object, callback: () => void) { super(); - if (props.style) { - props = { - ...props, - style: new AnimatedStyle(props.style), - }; - } - this._props = props; + this._props = createAnimatedProps(props); this._callback = callback; } diff --git a/packages/react-native/Libraries/Animated/nodes/AnimatedStyle.js b/packages/react-native/Libraries/Animated/nodes/AnimatedStyle.js index e851b6031de9bb..86a100f485e32e 100644 --- a/packages/react-native/Libraries/Animated/nodes/AnimatedStyle.js +++ b/packages/react-native/Libraries/Animated/nodes/AnimatedStyle.js @@ -16,10 +16,14 @@ import flattenStyle from '../../StyleSheet/flattenStyle'; import Platform from '../../Utilities/Platform'; import NativeAnimatedHelper from '../NativeAnimatedHelper'; import AnimatedNode from './AnimatedNode'; +import AnimatedObject, {hasAnimatedNode} from './AnimatedObject'; import AnimatedTransform from './AnimatedTransform'; import AnimatedWithChildren from './AnimatedWithChildren'; -function createAnimatedStyle(inputStyle: any): Object { +function createAnimatedStyle( + inputStyle: any, + keepUnanimatedValues: boolean, +): Object { // $FlowFixMe[underconstrained-implicit-instantiation] const style = flattenStyle(inputStyle); const animatedStyles: any = {}; @@ -29,82 +33,48 @@ function createAnimatedStyle(inputStyle: any): Object { animatedStyles[key] = new AnimatedTransform(value); } else if (value instanceof AnimatedNode) { animatedStyles[key] = value; - } else if (value && !Array.isArray(value) && typeof value === 'object') { - animatedStyles[key] = createAnimatedStyle(value); + } else if (hasAnimatedNode(value)) { + animatedStyles[key] = new AnimatedObject(value); + } else if (keepUnanimatedValues) { + animatedStyles[key] = value; } } return animatedStyles; } -function createStyleWithAnimatedTransform(inputStyle: any): Object { - // $FlowFixMe[underconstrained-implicit-instantiation] - let style = flattenStyle(inputStyle) || ({}: {[string]: any}); - - if (style.transform) { - style = { - ...style, - transform: new AnimatedTransform(style.transform), - }; - } - return style; -} - export default class AnimatedStyle extends AnimatedWithChildren { _inputStyle: any; _style: Object; constructor(style: any) { super(); - if (Platform.OS === 'web') { - this._inputStyle = style; - this._style = createAnimatedStyle(style); - } else { - this._style = createStyleWithAnimatedTransform(style); - } + this._inputStyle = style; + this._style = createAnimatedStyle(style, Platform.OS !== 'web'); } - // Recursively get values for nested styles (like iOS's shadowOffset) - _walkStyleAndGetValues(style: any): {[string]: any | {...}} { - const updatedStyle: {[string]: any | {...}} = {}; - for (const key in style) { - const value = style[key]; + __getValue(): Object | Array { + const result: {[string]: any} = {}; + for (const key in this._style) { + const value = this._style[key]; if (value instanceof AnimatedNode) { - updatedStyle[key] = value.__getValue(); - } else if (value && !Array.isArray(value) && typeof value === 'object') { - // Support animating nested values (for example: shadowOffset.height) - updatedStyle[key] = this._walkStyleAndGetValues(value); + result[key] = value.__getValue(); } else { - updatedStyle[key] = value; + result[key] = value; } } - return updatedStyle; - } - __getValue(): Object | Array { - if (Platform.OS === 'web') { - return [this._inputStyle, this._walkStyleAndGetValues(this._style)]; - } - - return this._walkStyleAndGetValues(this._style); + return Platform.OS === 'web' ? [this._inputStyle, result] : result; } - // Recursively get animated values for nested styles (like iOS's shadowOffset) - _walkStyleAndGetAnimatedValues(style: any): {[string]: any | {...}} { - const updatedStyle: {[string]: any | {...}} = {}; - for (const key in style) { - const value = style[key]; + __getAnimatedValue(): Object { + const result: {[string]: any} = {}; + for (const key in this._style) { + const value = this._style[key]; if (value instanceof AnimatedNode) { - updatedStyle[key] = value.__getAnimatedValue(); - } else if (value && !Array.isArray(value) && typeof value === 'object') { - // Support animating nested values (for example: shadowOffset.height) - updatedStyle[key] = this._walkStyleAndGetAnimatedValues(value); + result[key] = value.__getAnimatedValue(); } } - return updatedStyle; - } - - __getAnimatedValue(): Object { - return this._walkStyleAndGetAnimatedValues(this._style); + return result; } __attach(): void {