import React, { useContext, useEffect, useRef } from 'react'; import { CSSTransition as ReactCSSTransition } from 'react-transition-group'; interface CSSTransitionProps { show?: boolean; enter?: string; enterFrom?: string; enterTo?: string; leave?: string; leaveFrom?: string; leaveTo?: string; appear?: boolean; children?: React.ReactNode; } const TransitionContext = React.createContext<{ parent: { show?: boolean; isInitialRender?: boolean; appear?: boolean }; }>({ parent: {}, }); function useIsInitialRender() { const isInitialRender = useRef(true); useEffect(() => { isInitialRender.current = false; }, []); return isInitialRender.current; } const CSSTransition = ({ show, enter = '', enterFrom = '', enterTo = '', leave = '', leaveFrom = '', leaveTo = '', appear, children, }: CSSTransitionProps) => { const enterClasses = enter.split(' ').filter((s) => s.length); const enterFromClasses = enterFrom.split(' ').filter((s) => s.length); const enterToClasses = enterTo.split(' ').filter((s) => s.length); const leaveClasses = leave.split(' ').filter((s) => s.length); const leaveFromClasses = leaveFrom.split(' ').filter((s) => s.length); const leaveToClasses = leaveTo.split(' ').filter((s) => s.length); const addClasses = (node: HTMLElement, classes: string[]) => { classes.length && node.classList.add(...classes); }; const removeClasses = (node: HTMLElement, classes: string[]) => { classes.length && node.classList.remove(...classes); }; return ( { node.addEventListener('transitionend', done, false); }} onEnter={(node: HTMLElement) => { addClasses(node, [...enterClasses, ...enterFromClasses]); }} onEntering={(node: HTMLElement) => { removeClasses(node, enterFromClasses); addClasses(node, enterToClasses); }} onEntered={(node: HTMLElement) => { removeClasses(node, [...enterToClasses, ...enterClasses]); }} onExit={(node) => { addClasses(node, [...leaveClasses, ...leaveFromClasses]); }} onExiting={(node) => { removeClasses(node, leaveFromClasses); addClasses(node, leaveToClasses); }} onExited={(node) => { removeClasses(node, [...leaveToClasses, ...leaveClasses]); }} > {children} ); }; const Transition = ({ show, appear, ...rest }: CSSTransitionProps) => { const { parent } = useContext(TransitionContext); const isInitialRender = useIsInitialRender(); const isChild = show === undefined; if (isChild) { return ( ); } return ( ); }; export default Transition;