diff --git a/packages/react-native/Libraries/Animated/__tests__/Animated-test.js b/packages/react-native/Libraries/Animated/__tests__/Animated-test.js index 7796168b195..eca451af1ba 100644 --- a/packages/react-native/Libraries/Animated/__tests__/Animated-test.js +++ b/packages/react-native/Libraries/Animated/__tests__/Animated-test.js @@ -78,8 +78,7 @@ describe('Animated tests', () => { node.__attach(); - // Children: [AnimatedStyle, AnimatedTransform, AnimatedInterpolation, AnimatedObject, AnimatedObject] - expect(anim.__getChildren().length).toBe(5); + expect(anim.__getChildren().length).toBe(3); 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 e393454b9e4..2fccade525c 100644 --- a/packages/react-native/Libraries/Animated/__tests__/Animated-web-test.js +++ b/packages/react-native/Libraries/Animated/__tests__/Animated-web-test.js @@ -84,8 +84,7 @@ describe('Animated tests', () => { node.__attach(); - // Children: [AnimatedStyle, AnimatedTransform, AnimatedInterpolation, AnimatedObject, AnimatedObject] - expect(anim.__getChildren().length).toBe(5); + expect(anim.__getChildren().length).toBe(3); 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 333f147ab68..d6ebbb02e3b 100644 --- a/packages/react-native/Libraries/Animated/nodes/AnimatedProps.js +++ b/packages/react-native/Libraries/Animated/nodes/AnimatedProps.js @@ -16,27 +16,9 @@ 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; @@ -44,7 +26,13 @@ export default class AnimatedProps extends AnimatedNode { constructor(props: Object, callback: () => void) { super(); - this._props = createAnimatedProps(props); + if (props.style) { + props = { + ...props, + style: new AnimatedStyle(props.style), + }; + } + this._props = 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 86a100f485e..e851b6031de 100644 --- a/packages/react-native/Libraries/Animated/nodes/AnimatedStyle.js +++ b/packages/react-native/Libraries/Animated/nodes/AnimatedStyle.js @@ -16,14 +16,10 @@ 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, - keepUnanimatedValues: boolean, -): Object { +function createAnimatedStyle(inputStyle: any): Object { // $FlowFixMe[underconstrained-implicit-instantiation] const style = flattenStyle(inputStyle); const animatedStyles: any = {}; @@ -33,48 +29,82 @@ function createAnimatedStyle( animatedStyles[key] = new AnimatedTransform(value); } else if (value instanceof AnimatedNode) { animatedStyles[key] = value; - } else if (hasAnimatedNode(value)) { - animatedStyles[key] = new AnimatedObject(value); - } else if (keepUnanimatedValues) { - animatedStyles[key] = value; + } else if (value && !Array.isArray(value) && typeof value === 'object') { + animatedStyles[key] = createAnimatedStyle(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(); - this._inputStyle = style; - this._style = createAnimatedStyle(style, Platform.OS !== 'web'); + if (Platform.OS === 'web') { + this._inputStyle = style; + this._style = createAnimatedStyle(style); + } else { + this._style = createStyleWithAnimatedTransform(style); + } + } + + // 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]; + 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); + } else { + updatedStyle[key] = value; + } + } + return updatedStyle; } __getValue(): Object | Array { - const result: {[string]: any} = {}; - for (const key in this._style) { - const value = this._style[key]; - if (value instanceof AnimatedNode) { - result[key] = value.__getValue(); - } else { - result[key] = value; - } + if (Platform.OS === 'web') { + return [this._inputStyle, this._walkStyleAndGetValues(this._style)]; } - return Platform.OS === 'web' ? [this._inputStyle, result] : result; + return this._walkStyleAndGetValues(this._style); + } + + // 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]; + 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); + } + } + return updatedStyle; } __getAnimatedValue(): Object { - const result: {[string]: any} = {}; - for (const key in this._style) { - const value = this._style[key]; - if (value instanceof AnimatedNode) { - result[key] = value.__getAnimatedValue(); - } - } - return result; + return this._walkStyleAndGetAnimatedValues(this._style); } __attach(): void {