|
| 1 | +import PropTypes from 'prop-types'; |
| 2 | +import React from 'react'; |
| 3 | +import { findDOMNode } from 'react-dom' |
| 4 | +import TransitionGroup from './TransitionGroup'; |
| 5 | + |
| 6 | +const propTypes = { |
| 7 | + in: PropTypes.bool.isRequired, |
| 8 | + children(props, propName) { |
| 9 | + if (React.Children.count(props[propName]) !== 2) |
| 10 | + return new Error(`"${propName}" must be exactly two transition components.`) |
| 11 | + |
| 12 | + return null; |
| 13 | + }, |
| 14 | +}; |
| 15 | + |
| 16 | +/** |
| 17 | + * The `<ReplaceTransition>` component is a specialized `Transition` component |
| 18 | + * that animates between two children. |
| 19 | + * |
| 20 | + * ```jsx |
| 21 | + * <ReplaceTransition in> |
| 22 | + * <Fade><div>I appear first</div></Fade> |
| 23 | + * <Fade><div>I replace the above</div></Fade> |
| 24 | + * </ReplaceTransition> |
| 25 | + * ``` |
| 26 | + */ |
| 27 | +class ReplaceTransition extends React.Component { |
| 28 | + handleEnter = (...args) => this.handleLifecycle('onEnter', 0, args) |
| 29 | + handleEntering = (...args) => this.handleLifecycle('onEntering', 0, args) |
| 30 | + handleEntered = (...args) => this.handleLifecycle('onEntered', 0, args) |
| 31 | + |
| 32 | + handleExit = (...args) => this.handleLifecycle('onExit', 1, args) |
| 33 | + handleExiting = (...args) => this.handleLifecycle('onExiting', 1, args) |
| 34 | + handleExited = (...args) => this.handleLifecycle('onExited', 1, args) |
| 35 | + |
| 36 | + handleLifecycle(handler, idx, originalArgs) { |
| 37 | + const { children } = this.props; |
| 38 | + const child = React.Children.toArray(children)[idx]; |
| 39 | + |
| 40 | + if (child.props[handler]) child.props[handler](...originalArgs) |
| 41 | + if (this.props[handler]) this.props[handler](findDOMNode(this)) |
| 42 | + } |
| 43 | + |
| 44 | + render() { |
| 45 | + const { |
| 46 | + children, |
| 47 | + in: inProp, |
| 48 | + ...props |
| 49 | + } = this.props; |
| 50 | + const [first, second] = React.Children.toArray(children); |
| 51 | + |
| 52 | + delete props.onEnter; |
| 53 | + delete props.onEntering; |
| 54 | + delete props.onEntered; |
| 55 | + delete props.onExit; |
| 56 | + delete props.onExiting; |
| 57 | + delete props.onExited; |
| 58 | + |
| 59 | + return ( |
| 60 | + <TransitionGroup {...props}> |
| 61 | + {inProp ? |
| 62 | + React.cloneElement(first, { |
| 63 | + key: 'first', |
| 64 | + onEnter: this.handleEnter, |
| 65 | + onEntering: this.handleEntering, |
| 66 | + onEntered: this.handleEntered, |
| 67 | + |
| 68 | + }) : |
| 69 | + React.cloneElement(second, { |
| 70 | + key: 'second', |
| 71 | + onEnter: this.handleExit, |
| 72 | + onEntering: this.handleExiting, |
| 73 | + onEntered: this.handleExited, |
| 74 | + }) |
| 75 | + } |
| 76 | + </TransitionGroup> |
| 77 | + ); |
| 78 | + } |
| 79 | +} |
| 80 | + |
| 81 | +ReplaceTransition.propTypes = propTypes; |
| 82 | + |
| 83 | +export default ReplaceTransition; |
0 commit comments