import React , { useEffect , useRef , useState } from "react" ; import withDefaults from "./withDefaults" ; import useRealShape from "./useRealShape" ; interface Props { isExpanded ? : boolean ; delay ? : number ; } const defaultProps = { isExpanded : false , delay : 200 , } ; export type ExpandProps = Props & typeof defaultProps ; const Expand = ( { isExpanded , delay , children , } ) => { const [ height , setHeight ] = useState < string > ( isExpanded ? "auto" : "0" ) ; const [ selfExpanded , setSelfExpanded ] = useState < boolean > ( isExpanded ) ; const [ visible , setVisible ] = useState < boolean > ( isExpanded ) ; const contentRef = useRef < HTMLDivElement > ( null ) ; const entryTimer = useRef < number > ( ) ; const leaveTimer = useRef < number > ( ) ; const resetTimer = useRef < number > ( ) ; const [ state , updateShape ] = useRealShape < HTMLDivElement > ( contentRef ) ; useEffect ( ( ) => setHeight ( `${ state . height }px` ) , [ state . height ] ) ; useEffect ( ( ) => { if ( isExpanded ) { setVisible ( isExpanded ) ; } else { updateShape ( ) ; setHeight ( `${ state . height }px` ) ; } entryTimer . current = window . setTimeout ( ( ) => { setSelfExpanded ( isExpanded ) ; clearTimeout ( entryTimer . current ) ; } , 30 ) ; if ( isExpanded ) { resetTimer . current = window . setTimeout ( ( ) => { setHeight ( "auto" ) ; clearTimeout ( resetTimer . current ) ; } , delay ) ; } else { leaveTimer . current = window . setTimeout ( ( ) => { setVisible ( isExpanded ) ; clearTimeout ( leaveTimer . current ) ; } , delay / 2 ) ; } return ( ) => { clearTimeout ( entryTimer . current ) ; clearTimeout ( leaveTimer . current ) ; clearTimeout ( resetTimer . current ) ; } ; } , [ isExpanded ] ) ; return ( < div className = { `container ${ selfExpanded ? "expanded" : "" }` } > < div ref = { contentRef } className = "content" > { children } < /div> < style jsx > { `
        .container {
          padding: 0;
          margin: 0;
          height: 0;
          overflow: hidden;
          visibility: ${ visible ? "visible" : "hidden" };
          transition: height ${ delay }ms ease;
        }
        .expanded {
          height: ${ height };
          visibility: visible;
        }
      ` } < /style> < /div>); } ; export default withDefaults ( Expand , defaultProps ) ;