diff --git a/packages/babel-plugin-react-native-web/src/moduleMap.js b/packages/babel-plugin-react-native-web/src/moduleMap.js index 4c0b0a93..fb9b6188 100644 --- a/packages/babel-plugin-react-native-web/src/moduleMap.js +++ b/packages/babel-plugin-react-native-web/src/moduleMap.js @@ -23,6 +23,7 @@ module.exports = { InteractionManager: true, Keyboard: true, KeyboardAvoidingView: true, + LayoutAnimation: true, Linking: true, ListView: true, Modal: true, diff --git a/packages/react-native-web/src/exports/LayoutAnimation/index.js b/packages/react-native-web/src/exports/LayoutAnimation/index.js new file mode 100644 index 00000000..312ca877 --- /dev/null +++ b/packages/react-native-web/src/exports/LayoutAnimation/index.js @@ -0,0 +1,11 @@ +/** + * Copyright (c) 2016-present, Nicolas Gallagher. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import LayoutAnimation from '../../vendor/react-native/LayoutAnimation'; +export default LayoutAnimation; diff --git a/packages/react-native-web/src/exports/UIManager/index.js b/packages/react-native-web/src/exports/UIManager/index.js index b15574f4..8e8ed6fa 100644 --- a/packages/react-native-web/src/exports/UIManager/index.js +++ b/packages/react-native-web/src/exports/UIManager/index.js @@ -89,6 +89,10 @@ const UIManager = { node.setAttribute(prop, value); } } + }, + + configureNextLayoutAnimation(config, onAnimationDidEnd) { + onAnimationDidEnd(); } }; diff --git a/packages/react-native-web/src/index.js b/packages/react-native-web/src/index.js index e2f509f2..6167e586 100644 --- a/packages/react-native-web/src/index.js +++ b/packages/react-native-web/src/index.js @@ -21,6 +21,7 @@ import Easing from './exports/Easing'; import I18nManager from './exports/I18nManager'; import Keyboard from './exports/Keyboard'; import InteractionManager from './exports/InteractionManager'; +import LayoutAnimation from './exports/LayoutAnimation'; import Linking from './exports/Linking'; import NetInfo from './exports/NetInfo'; import PanResponder from './exports/PanResponder'; @@ -90,6 +91,7 @@ export { I18nManager, InteractionManager, Keyboard, + LayoutAnimation, Linking, NetInfo, PanResponder, @@ -158,6 +160,7 @@ const ReactNative = { I18nManager, InteractionManager, Keyboard, + LayoutAnimation, Linking, NetInfo, PanResponder, diff --git a/packages/react-native-web/src/vendor/react-native/LayoutAnimation/index.js b/packages/react-native-web/src/vendor/react-native/LayoutAnimation/index.js new file mode 100644 index 00000000..21484ed9 --- /dev/null +++ b/packages/react-native-web/src/vendor/react-native/LayoutAnimation/index.js @@ -0,0 +1,161 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @noflow + * @format + */ + +import PropTypes from 'prop-types'; +import UIManager from '../../../exports/UIManager'; + +const __DEV__ = process.env.NODE !== 'production'; +const { checkPropTypes } = PropTypes; + +const Types = { + spring: 'spring', + linear: 'linear', + easeInEaseOut: 'easeInEaseOut', + easeIn: 'easeIn', + easeOut: 'easeOut', + keyboard: 'keyboard' +}; + +const Properties = { + opacity: 'opacity', + scaleX: 'scaleX', + scaleY: 'scaleY', + scaleXY: 'scaleXY' +}; + +const animType = PropTypes.shape({ + duration: PropTypes.number, + delay: PropTypes.number, + springDamping: PropTypes.number, + initialVelocity: PropTypes.number, + type: PropTypes.oneOf(Object.keys(Types)).isRequired, + property: PropTypes.oneOf( + // Only applies to create/delete + Object.keys(Properties), + ), +}); + +type Anim = { + duration?: number, + delay?: number, + springDamping?: number, + initialVelocity?: number, + type?: $Enum, + property?: $Enum, +}; + +const configType = PropTypes.shape({ + duration: PropTypes.number.isRequired, + create: animType, + update: animType, + delete: animType, +}); + +type Config = { + duration: number, + create?: Anim, + update?: Anim, + delete?: Anim, +}; + +function checkConfig(config: Config, location: string, name: string) { + checkPropTypes({config: configType}, {config}, location, name); +} + +function configureNext(config: Config, onAnimationDidEnd?: Function) { + if (__DEV__) { + checkConfig(config, 'config', 'LayoutAnimation.configureNext'); + } + UIManager.configureNextLayoutAnimation( + config, + onAnimationDidEnd || function() {}, + function() { + /* unused */ + }, + ); +} + +function create(duration: number, type, creationProp): Config { + return { + duration, + create: { + type, + property: creationProp, + }, + update: { + type, + }, + delete: { + type, + property: creationProp, + }, + }; +} + +const Presets = { + easeInEaseOut: create(300, Types.easeInEaseOut, Properties.opacity), + linear: create(500, Types.linear, Properties.opacity), + spring: { + duration: 700, + create: { + type: Types.linear, + property: Properties.opacity, + }, + update: { + type: Types.spring, + springDamping: 0.4, + }, + delete: { + type: Types.linear, + property: Properties.opacity, + }, + }, +}; + +/** + * Automatically animates views to their new positions when the + * next layout happens. + * + * A common way to use this API is to call it before calling `setState`. + * + * Note that in order to get this to work on **Android** you need to set the following flags via `UIManager`: + * + * UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true); + */ +const LayoutAnimation = { + /** + * Schedules an animation to happen on the next layout. + * + * @param config Specifies animation properties: + * + * - `duration` in milliseconds + * - `create`, config for animating in new views (see `Anim` type) + * - `update`, config for animating views that have been updated + * (see `Anim` type) + * + * @param onAnimationDidEnd Called when the animation finished. + * Only supported on iOS. + * @param onError Called on error. Only supported on iOS. + */ + configureNext, + /** + * Helper for creating a config for `configureNext`. + */ + create, + Types, + Properties, + checkConfig, + Presets, + easeInEaseOut: configureNext.bind(null, Presets.easeInEaseOut), + linear: configureNext.bind(null, Presets.linear), + spring: configureNext.bind(null, Presets.spring), +}; + +export default LayoutAnimation;