import * as React from 'react' import Transition, { TransitionStatus } from 'react-transition-group/Transition' export const getDuration = (timeout: TimeoutType | number): TimeoutType => { if (typeof timeout === 'object') { return timeout as TimeoutType } return { enter: timeout, exit: timeout } } export const STATES = { ENTERED: 'entered', ENTERING: 'entering', EXITING: 'exiting', EXITED: 'exited', } export const isEntered = (state: string) => state === STATES.ENTERED export const isEntering = (state: string) => state === STATES.ENTERING export const isExiting = (state: string) => state === STATES.EXITING export const isExited = (state: string) => state === STATES.EXITED export type TimeoutType = { enter: number exit: number } export type AnimationProps = { timeout: TimeoutType | number in?: boolean children: (props: TransitionProps) => React.ReactNode } type AnimationState = { enter: number exit: number } export type TransitionProps = { entering: boolean entered: boolean duration: number exiting: boolean exited: boolean state: TransitionStatus } /* Animation component which behaves as state machine for * animating entering and exiting behaviours in nice and easy way * usually used to change props on children that trigger CSS rules * changes with different kinds of transitions */ export class Animation extends React.PureComponent { state = getDuration(this.props.timeout) static defaultProps = { timeout: 500, in: false, } static getDerivedStateFromProps(nextProps: AnimationProps) { return getDuration(nextProps.timeout) } render() { const { in: inProp, children, timeout, ...rest } = this.props return ( {state => { if (isEntering(state)) { return children({ entering: true, entered: false, duration: this.state.enter, exiting: false, exited: false, state, }) } if (isEntered(state)) { return children({ entered: true, entering: false, duration: this.state.enter, exiting: false, exited: false, state, }) } if (isExiting(state)) { children({ entered: false, entering: false, duration: this.state.exit, exiting: true, exited: false, state, }) } if (isExited(state)) { children({ entered: false, entering: false, duration: this.state.enter, exiting: false, exited: true, state, }) } return children({ entered: false, entering: false, duration: this.state.enter, exiting: false, exited: true, state, }) }} ) } }