UNPKG

react-reveal

Version:

Really simple way to add reveal on scroll animation to your React app.

175 lines (155 loc) 4.74 kB
/* * makeCarousel Higher Order Component For react-reveal * * Copyright © Roman Nosov 2017 * * This source code is licensed under the MIT license found in the * LICENSE.txt file in the root directory of this source tree. */ import React from 'react'; import { number, node, bool} from 'prop-types'; import swipedetect from './swipedetect'; function makeCarousel(WrappedComponent, config = {}) { //const { wait = 5000, maxTurns = 2, } = config; return class extends React.Component { static get propTypes() { return { children: node.isRequired, defaultWait: number, maxTurns: number, swipe: bool, }; } static get defaultProps() { return { defaultWait: config.defaultWait || 5000, maxTurns: config.maxTurns || 5, swipe: config.swipe || true, }; } constructor(props) { super(props); this.state = { //next: React.Children.count(this.props.children) - 1, current: 0, next: 1, backwards: false, swap: false, appear: false, }; this.turn = 0; this.stop = false; this.handleReveal = this.handleReveal.bind(this); this.handleSwipe = this.handleSwipe.bind(this); this.target = this.target.bind(this); } target({currentTarget}) { this.move(+currentTarget.getAttribute('data-position')); } handleReveal() { if (this.turn >= this.props.maxTurns) return; this.move(this.state.current + 1); } componentWillUnmount() { this.turn = -1; } move(newPos) { if (this.turn<0 || newPos === this.state.current) return; let pos = newPos; const count = React.Children.count(this.props.children); if (newPos >= count) { this.turn++ pos = 0; } else if (newPos < 0) pos = count -1; this.setState({ current: pos, next: this.state.current, backwards: newPos<this.state.current, swap: !this.state.swap, appear: true, }); } handleSwipe(dir) { if (!this.props.swipe) return; if (dir === 'left') this.move(this.state.current + 1); else if (dir === 'right') this.move(this.state.current - 1); } componentDidMount() { if (this.beforeNode && this.afterNode) { swipedetect(this.beforeNode, this.handleSwipe ); swipedetect(this.afterNode, this.handleSwipe ); } } render() { const { children } = this.props, arr = React.Children.toArray(children), count = arr.length; let { swap, next, current, backwards } = this.state; current %= count; next %= count; let before, after ; switch (count) { case 0: before = <div />; after = <div />; case 1: before = arr[0]; after = arr[0]; default: before = arr[swap ? next : current]; after = arr[swap ? current : next]; } if (typeof before !== 'object') before = <div>{before}</div>; if (typeof after !== 'object') after = <div>{after}</div>; return ( <WrappedComponent {...this.props} position={current} handleClick={this.target} total={count} children={[ <div ref={ node => this.beforeNode = node } key={1} style={{ position: 'absolute', left: 0, top: 0, width: '100%', height: '100%', zIndex: swap ? 1 : 2 }}> <before.type //disableObserver //force mountOnEnter unmountOnExit appear={this.state.appear} wait={this.props.defaultWait} {...before.props} opposite when={!swap} mirror={backwards} onReveal={!swap/*&&!this.stop*/ ? this.handleReveal : void 0} /> </div>, <div key={2} ref={ node => this.afterNode = node } style={{ position: 'absolute', left: 0, top: 0, width: '100%', height: '100%', zIndex: swap ? 2 : 1 }}> <after.type //disableObserver //force mountOnEnter unmountOnExit appear={this.state.appear} wait={this.props.defaultWait} {...after.props} opposite when={swap} mirror={backwards} onReveal={swap/*&&!this.stop*/ ? this.handleReveal : void 0} /> </div> ]} /> ); } }; } export default makeCarousel;