11import React from 'react' ;
2- import { CSSTransition } from 'react-transition-group' ;
3- import { CSSTransitionProps } from 'react-transition-group/CSSTransition' ;
2+ import useTransition , { TransitionState } from './use-transition' ;
43
54export type AnimationName =
65 | 'zoom-center-top'
@@ -23,42 +22,112 @@ export type AnimationName =
2322 | 'slide-down' ;
2423
2524export type TransitionProps = {
25+ in ?: boolean ;
26+ timeout ?: number | { enter : number ; exit : number } ;
27+ appear ?: boolean ;
28+ unmountOnExit ?: boolean ;
29+ mountOnEnter ?: boolean ;
30+
2631 /** Animation prefix */
2732 prefix ?: string ;
2833
2934 /** Preset animation name */
3035 animation ?: AnimationName ;
3136
37+ /** Custom class name base (overrides prefix + animation) */
38+ classNames ?: string ;
39+
3240 /** Prevent the transition conflict with the inner component */
3341 wrapper ?: boolean ;
42+
43+ nodeRef ?: React . RefObject < HTMLElement | null > ;
44+
45+ onEnter ?: ( ) => void ;
46+ onEntering ?: ( ) => void ;
47+ onEntered ?: ( ) => void ;
48+ onExit ?: ( ) => void ;
49+ onExiting ?: ( ) => void ;
50+ onExited ?: ( ) => void ;
51+
3452 children ?: React . ReactNode ;
35- } & Partial < CSSTransitionProps < HTMLElement > > ;
53+ } ;
54+
55+ function getTransitionClasses ( base : string , state : TransitionState ) : string {
56+ switch ( state ) {
57+ case 'enter' :
58+ return `${ base } -enter` ;
59+ case 'entering' :
60+ return `${ base } -enter ${ base } -enter-active` ;
61+ case 'entered' :
62+ return `${ base } -enter-done` ;
63+ case 'exit' :
64+ return `${ base } -exit` ;
65+ case 'exiting' :
66+ return `${ base } -exit ${ base } -exit-active` ;
67+ case 'exited' :
68+ return `${ base } -exit-done` ;
69+ default :
70+ return '' ;
71+ }
72+ }
3673
37- const Transition = ( props : TransitionProps ) : React . ReactElement => {
74+ const Transition = ( props : TransitionProps ) : React . ReactElement | null => {
3875 const {
76+ in : inProp = false ,
3977 timeout = 300 ,
4078 unmountOnExit = true ,
79+ mountOnEnter,
4180 appear = true ,
4281 prefix = 'ty' ,
4382 animation,
44- classNames,
83+ classNames : classNamesProp ,
4584 nodeRef,
4685 children,
4786 wrapper,
48- ...otherProps
87+ onEnter,
88+ onEntering,
89+ onEntered,
90+ onExit,
91+ onExiting,
92+ onExited,
4993 } = props ;
5094
51- return (
52- < CSSTransition
53- { ...( otherProps as CSSTransitionProps < HTMLElement > ) }
54- timeout = { timeout }
55- appear = { appear }
56- unmountOnExit = { unmountOnExit }
57- nodeRef = { nodeRef }
58- classNames = { classNames ? classNames : `${ prefix } -${ animation } ` } >
59- { wrapper ? < div > { children } </ div > : ( children as React . ReactElement ) }
60- </ CSSTransition >
61- ) ;
95+ const { state, shouldMount } = useTransition ( {
96+ in : inProp ,
97+ timeout,
98+ appear,
99+ unmountOnExit,
100+ mountOnEnter,
101+ onEnter,
102+ onEntering,
103+ onEntered,
104+ onExit,
105+ onExiting,
106+ onExited,
107+ nodeRef,
108+ } ) ;
109+
110+ if ( ! shouldMount ) {
111+ return null ;
112+ }
113+
114+ const base = classNamesProp ? classNamesProp : `${ prefix } -${ animation } ` ;
115+ const transitionClasses = getTransitionClasses ( base , state ) ;
116+
117+ const child = wrapper ? < div > { children } </ div > : children ;
118+
119+ if ( React . isValidElement ( child ) ) {
120+ const existingClassName = ( child . props as { className ?: string } ) . className || '' ;
121+ const mergedClassName = existingClassName
122+ ? `${ existingClassName } ${ transitionClasses } ` . trim ( )
123+ : transitionClasses ;
124+
125+ return React . cloneElement ( child as React . ReactElement < { className ?: string } > , {
126+ className : mergedClassName || undefined ,
127+ } ) ;
128+ }
129+
130+ return child as React . ReactElement ;
62131} ;
63132
64133Transition . displayName = 'Transition' ;
0 commit comments