diff --git a/src/component.js b/src/component.js new file mode 100644 index 0000000..1deeaa1 --- /dev/null +++ b/src/component.js @@ -0,0 +1,200 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +export default class Lottie extends React.Component { + componentDidMount() { + const { + lottie, + options, + eventListeners, + } = this.props; + + const { + loop, + autoplay, + animationData, + rendererSettings, + segments, + } = options; + + this.options = { + container: this.el, + renderer: 'svg', + loop: loop !== false, + autoplay: autoplay !== false, + segments: segments !== false, + animationData, + rendererSettings, + }; + + this.options = { ...this.options, ...options }; + + this.anim = lottie.loadAnimation(this.options); + this.registerEvents(eventListeners); + } + + componentWillUpdate(nextProps /* , nextState */) { + /* Recreate the animation handle if the data is changed */ + if (this.options.animationData !== nextProps.options.animationData) { + this.deRegisterEvents(this.props.eventListeners); + this.destroy(); + this.options = { ...this.options, ...nextProps.options }; + this.anim = this.props.lottie.loadAnimation(this.options); + this.registerEvents(nextProps.eventListeners); + } + } + + componentDidUpdate() { + if (this.props.isStopped) { + this.stop(); + } else if (this.props.segments) { + this.playSegments(); + } else { + this.play(); + } + + this.pause(); + this.setSpeed(); + this.setDirection(); + } + + componentWillUnmount() { + this.deRegisterEvents(this.props.eventListeners); + this.destroy(); + this.options.animationData = null; + this.anim = null; + } + + setSpeed() { + this.anim.setSpeed(this.props.speed); + } + + setDirection() { + this.anim.setDirection(this.props.direction); + } + + play() { + this.anim.play(); + } + + playSegments() { + this.anim.playSegments(this.props.segments); + } + + stop() { + this.anim.stop(); + } + + pause() { + if (this.props.isPaused && !this.anim.isPaused) { + this.anim.pause(); + } else if (!this.props.isPaused && this.anim.isPaused) { + this.anim.pause(); + } + } + + destroy() { + this.anim.destroy(); + } + + registerEvents(eventListeners) { + eventListeners.forEach((eventListener) => { + this.anim.addEventListener(eventListener.eventName, eventListener.callback); + }); + } + + deRegisterEvents(eventListeners) { + eventListeners.forEach((eventListener) => { + this.anim.removeEventListener(eventListener.eventName, eventListener.callback); + }); + } + + handleClickToPause = () => { + // The pause() method is for handling pausing by passing a prop isPaused + // This method is for handling the ability to pause by clicking on the animation + if (this.anim.isPaused) { + this.anim.play(); + } else { + this.anim.pause(); + } + } + + render() { + const { + width, + height, + ariaRole, + ariaLabel, + isClickToPauseDisabled, + title, + } = this.props; + + const getSize = (initial) => { + let size; + + if (typeof initial === 'number') { + size = `${initial}px`; + } else { + size = initial || '100%'; + } + + return size; + }; + + const lottieStyles = { + width: getSize(width), + height: getSize(height), + overflow: 'hidden', + margin: '0 auto', + outline: 'none', + ...this.props.style, + }; + + const onClickHandler = isClickToPauseDisabled ? () => null : this.handleClickToPause; + + return ( + // Bug with eslint rules https://github.com/airbnb/javascript/issues/1374 + // eslint-disable-next-line jsx-a11y/no-static-element-interactions +
{ + this.el = c; + }} + style={lottieStyles} + onClick={onClickHandler} + title={title} + role={ariaRole} + aria-label={ariaLabel} + tabIndex="0" + /> + ); + } +} + +Lottie.propTypes = { + eventListeners: PropTypes.arrayOf(PropTypes.object), + options: PropTypes.object.isRequired, + lottie: PropTypes.object.isRequired, + height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + isStopped: PropTypes.bool, + isPaused: PropTypes.bool, + speed: PropTypes.number, + segments: PropTypes.arrayOf(PropTypes.number), + direction: PropTypes.number, + ariaRole: PropTypes.string, + ariaLabel: PropTypes.string, + isClickToPauseDisabled: PropTypes.bool, + title: PropTypes.string, + style: PropTypes.string, +}; + +Lottie.defaultProps = { + eventListeners: [], + isStopped: false, + isPaused: false, + speed: 1, + ariaRole: 'button', + ariaLabel: 'animation', + isClickToPauseDisabled: false, + title: '', +}; diff --git a/src/index.js b/src/index.js index bbc4364..96a59d1 100644 --- a/src/index.js +++ b/src/index.js @@ -1,199 +1,7 @@ import React from 'react'; -import PropTypes from 'prop-types'; import lottie from 'lottie-web'; +import Component from './component'; -export default class Lottie extends React.Component { - componentDidMount() { - const { - options, - eventListeners, - } = this.props; - - const { - loop, - autoplay, - animationData, - rendererSettings, - segments, - } = options; - - this.options = { - container: this.el, - renderer: 'svg', - loop: loop !== false, - autoplay: autoplay !== false, - segments: segments !== false, - animationData, - rendererSettings, - }; - - this.options = { ...this.options, ...options }; - - this.anim = lottie.loadAnimation(this.options); - this.registerEvents(eventListeners); - } - - componentWillUpdate(nextProps /* , nextState */) { - /* Recreate the animation handle if the data is changed */ - if (this.options.animationData !== nextProps.options.animationData) { - this.deRegisterEvents(this.props.eventListeners); - this.destroy(); - this.options = {...this.options, ...nextProps.options}; - this.anim = lottie.loadAnimation(this.options); - this.registerEvents(nextProps.eventListeners); - } - } - - componentDidUpdate() { - if (this.props.isStopped) { - this.stop(); - } else if (this.props.segments) { - this.playSegments(); - } else { - this.play(); - } - - this.pause(); - this.setSpeed(); - this.setDirection(); - } - - componentWillUnmount() { - this.deRegisterEvents(this.props.eventListeners); - this.destroy(); - this.options.animationData = null; - this.anim = null; - } - - setSpeed() { - this.anim.setSpeed(this.props.speed); - } - - setDirection() { - this.anim.setDirection(this.props.direction); - } - - play() { - this.anim.play(); - } - - playSegments() { - this.anim.playSegments(this.props.segments); - } - - stop() { - this.anim.stop(); - } - - pause() { - if (this.props.isPaused && !this.anim.isPaused) { - this.anim.pause(); - } else if (!this.props.isPaused && this.anim.isPaused) { - this.anim.pause(); - } - } - - destroy() { - this.anim.destroy(); - } - - registerEvents(eventListeners) { - eventListeners.forEach((eventListener) => { - this.anim.addEventListener(eventListener.eventName, eventListener.callback); - }); - } - - deRegisterEvents(eventListeners) { - eventListeners.forEach((eventListener) => { - this.anim.removeEventListener(eventListener.eventName, eventListener.callback); - }); - } - - handleClickToPause = () => { - // The pause() method is for handling pausing by passing a prop isPaused - // This method is for handling the ability to pause by clicking on the animation - if (this.anim.isPaused) { - this.anim.play(); - } else { - this.anim.pause(); - } - } - - render() { - const { - width, - height, - ariaRole, - ariaLabel, - isClickToPauseDisabled, - title, - } = this.props; - - const getSize = (initial) => { - let size; - - if (typeof initial === 'number') { - size = `${initial}px`; - } else { - size = initial || '100%'; - } - - return size; - }; - - const lottieStyles = { - width: getSize(width), - height: getSize(height), - overflow: 'hidden', - margin: '0 auto', - outline: 'none', - ...this.props.style, - }; - - const onClickHandler = isClickToPauseDisabled ? () => null : this.handleClickToPause; - - return ( - // Bug with eslint rules https://github.com/airbnb/javascript/issues/1374 - // eslint-disable-next-line jsx-a11y/no-static-element-interactions -
{ - this.el = c; - }} - style={lottieStyles} - onClick={onClickHandler} - title={title} - role={ariaRole} - aria-label={ariaLabel} - tabIndex="0" - /> - ); - } +export default function (props) { + return ; } - -Lottie.propTypes = { - eventListeners: PropTypes.arrayOf(PropTypes.object), - options: PropTypes.object.isRequired, - height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - isStopped: PropTypes.bool, - isPaused: PropTypes.bool, - speed: PropTypes.number, - segments: PropTypes.arrayOf(PropTypes.number), - direction: PropTypes.number, - ariaRole: PropTypes.string, - ariaLabel: PropTypes.string, - isClickToPauseDisabled: PropTypes.bool, - title: PropTypes.string, - style: PropTypes.string, -}; - -Lottie.defaultProps = { - eventListeners: [], - isStopped: false, - isPaused: false, - speed: 1, - ariaRole: 'button', - ariaLabel: 'animation', - isClickToPauseDisabled: false, - title: '', -}; diff --git a/src/light.js b/src/light.js new file mode 100644 index 0000000..19bdabf --- /dev/null +++ b/src/light.js @@ -0,0 +1,7 @@ +import React from 'react'; +import lottieLight from 'lottie-web/build/player/lottie_light'; +import Component from './component'; + +export default function (props) { + return ; +} diff --git a/src/tests/index.js b/src/tests/index.js index e84bd42..c176cae 100644 --- a/src/tests/index.js +++ b/src/tests/index.js @@ -2,7 +2,8 @@ import React from 'react'; import { shallow, mount } from 'enzyme'; import { expect } from 'chai'; import sinon from 'sinon'; -import ReactLottie from '../index'; +import lottie from 'lottie-web'; +import ReactLottie from '../component'; import pinjump from '../stories/pinjump.json'; import beatingHeart from '../stories/beating-heart.json'; @@ -20,7 +21,7 @@ describe('react-lottie', () => { describe('props', () => { describe('isClickToPauseDisabled', () => { it('should prevent handleClickToPause from being called when true', () => { - const component = mount(); + const component = mount(); const spy = sinon.stub(); component.instance().handleClickToPause = spy; @@ -61,6 +62,7 @@ describe('react-lottie', () => { options={defaultOptions} height={199} width={188} + lottie={lottie} /> ); @@ -72,7 +74,7 @@ describe('react-lottie', () => { describe('when props change', () => { it('should change the animation that is being played', () => { - const component = mount(); + const component = mount(); expect(component.instance().anim.animationData).to.equal(pinjump); @@ -91,7 +93,7 @@ describe('react-lottie', () => { describe('componentDidMount', () => { it('should register events', () => { const registerEventsSpy = sinon.stub(); - const component = mount(); + const component = mount(); component.instance().registerEvents = registerEventsSpy; component.update(); @@ -102,7 +104,7 @@ describe('react-lottie', () => { }); it('should load the animation', () => { - const component = mount(); + const component = mount(); const animation = component.instance().anim; expect(animation.animationData).to.equal(pinjump); @@ -112,7 +114,7 @@ describe('react-lottie', () => { describe('componentWillUpdate', () => { it('should register events when animationData changes', () => { const registerEventsSpy = sinon.stub(); - const component = mount(); + const component = mount(); component.instance().registerEvents = registerEventsSpy; component.update(); @@ -131,7 +133,7 @@ describe('react-lottie', () => { describe('componentDidUnmount', () => { it('should de-register events', () => { const spy = sinon.stub(); - const component = mount(); + const component = mount(); component.instance().deRegisterEvents = spy; component.update(); @@ -142,7 +144,7 @@ describe('react-lottie', () => { it('should destroy the animation', () => { const spy = sinon.stub(); - const component = mount(); + const component = mount(); component.instance().anim = { destroy: spy,