diff --git a/README.md b/README.md index 3842d94..c562a3d 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,11 @@ resolve: { ``` If you are using [Expo](https://docs.expo.dev/guides/customizing-webpack/), you can simply do + ```js const createExpoWebpackConfigAsync = require('@expo/webpack-config'); -module.exports = async function(env, argv) { +module.exports = async function (env, argv) { const config = await createExpoWebpackConfigAsync(env, argv); config.resolve.alias['lottie-react-native'] = 'react-native-web-lottie'; diff --git a/package.json b/package.json index 9a5a6a4..23cabb9 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "1.4.4", "description": "React Native for Web implementation of Lottie", "main": "dist/index.js", + "types": "src/index.d.ts", "main-es": "src/index.js", "repository": { "type": "git", @@ -14,29 +15,17 @@ "url": "https://github.com/Minishlink" }, "license": "MIT", - "keywords": [ - "react-native", - "react-native-web", - "lottie-react-native" - ], + "keywords": ["react-native", "react-native-web", "lottie-react-native"], "scripts": { "prepublish": "yarn build", "build": "mkdir -p dist && babel src --out-dir dist --copy-files", "test": "prettier --check ." }, "babel": { - "presets": [ - "module:metro-react-native-babel-preset" - ], - "plugins": [ - "react-native-web" - ] + "presets": ["module:metro-react-native-babel-preset"], + "plugins": ["react-native-web"] }, - "files": [ - "src", - "dist", - "yarn.lock" - ], + "files": ["src", "dist", "yarn.lock"], "devDependencies": { "@babel/cli": "^7.2.3", "@babel/core": "^7.2.2", diff --git a/src/index.d.ts b/src/index.d.ts new file mode 100644 index 0000000..2c5d57c --- /dev/null +++ b/src/index.d.ts @@ -0,0 +1,102 @@ +declare module 'react-native-web-lottie' { + import { Animated, StyleProp, ViewStyle } from 'react-native'; + /** + * Serialized animation as generated from After Effects + */ + export interface AnimationObject { + v: string; + fr: number; + ip: number; + op: number; + w: number; + h: number; + nm?: string; + ddd?: number; + assets: any[]; + layers: any[]; + markers?: any[]; + } + + export interface BaseRendererConfig { + imagePreserveAspectRatio?: string; + className?: string; + } + + export interface FilterSizeConfig { + width: string; + height: string; + x: string; + y: string; + } + + export interface SVGRendererConfig extends BaseRendererConfig { + title?: string; + description?: string; + preserveAspectRatio?: string; + progressiveLoad?: boolean; + hideOnTransparent?: boolean; + viewBoxOnly?: boolean; + viewBoxSize?: string; + focusable?: boolean; + filterSize?: FilterSizeConfig; + } + + export interface AnimatedLottieViewProps { + /** + * The source of animation. Can be referenced as a local asset by a string, or remotely + * with an object with a `uri` property, or it can be an actual JS object of an + * animation, obtained (for example) with something like + * `require('../path/to/animation.json')` + */ + source: string | AnimationObject | { uri: string }; + + progress?: Animated.Value; + + /** + * A boolean flag indicating whether or not the animation should loop. + */ + loop?: boolean; + + /** + * Style attributes for the view, as expected in a standard `View`: + * http://facebook.github.io/react-native/releases/0.39/docs/view.html#style + * CAVEAT: border styling is not supported. + */ + style?: StyleProp; + + /** + * A boolean flag indicating whether or not the animation should start automatically when + * mounted. This only affects the imperative API. + */ + autoPlay?: boolean; + + /** + * The speed the animation will progress. This only affects the imperative API. The + * default value is 1. + */ + speed?: number; + + /** + * Check out lottie docs : https://airbnb.io/lottie/#/web?id=other-loading-options + */ + rendererSettings?: SVGRendererConfig; + + /** + * A callback function which will be called when animation is finished. Note that this + * callback will be called only when `loop` is set to false. + */ + onAnimationFinish?: (isCancelled: boolean) => void; + + /** + * A string to identify the component during testing + */ + testID?: string; + } + + class AnimatedLottieView extends React.Component { + play(startFrame?: number, endFrame?: number): void; + reset(): void; + } + + export default AnimatedLottieView; +} diff --git a/src/index.js b/src/index.js index da0e363..c3e581b 100644 --- a/src/index.js +++ b/src/index.js @@ -25,9 +25,16 @@ class Animation extends PureComponent { } UNSAFE_componentWillReceiveProps(nextProps) { - if (this.props.source && nextProps.source && this.props.source.nm !== nextProps.source.nm) { + if ( + this.props.source && + nextProps.source && + (this.props.source.nm !== nextProps.source.nm || this.props.source.uri !== nextProps.source.uri) + ) { this.loadAnimation(nextProps); } + if (this.props.speed !== nextProps.speed) { + this.anim.setSpeed(nextProps.speed); + } } loadAnimation = (props) => { @@ -37,13 +44,19 @@ class Animation extends PureComponent { this.anim = lottie.loadAnimation({ container: this.animationDOMNode, - animationData: props.source, renderer: 'svg', loop: props.loop || false, autoplay: props.autoPlay, rendererSettings: props.rendererSettings || {}, + ...(props.source.uri && typeof props.source.uri === 'string' + ? { path: props.source.uri } + : { animationData: props.source }), }); + if (props.speed !== undefined) { + this.anim.setSpeed(props.speed); + } + if (props.onAnimationFinish) { this.anim.addEventListener('complete', props.onAnimationFinish); }