UNPKG

@navinc/base-react-components

Version:
54 lines (45 loc) 1.55 kB
import React, { useState, useRef, useMemo, useEffect } from 'react' import debounce from 'lodash.debounce' import styled from 'styled-components' export const AnimateHeightContainer = styled.div` overflow: hidden; height: ${({ height }) => (height === 'auto' ? 'auto' : `${Math.ceil(height)}px`)}; transition: height 0.4s ease-in-out; will-change: height; ` AnimateHeightContainer.displayName = 'AnimateHeightContainer' export const AnimateHeight = ({ children, ...props }) => { const [contentHeight, setContentHeight] = useState('auto') const contentRef = useRef(null) const setHeight = useMemo( () => debounce(() => { window.requestAnimationFrame(() => { setContentHeight(contentRef?.current?.getBoundingClientRect().height ?? 'auto') }) }, 100), [] ) useEffect(() => { window.addEventListener('resize', setHeight) // ResizeObserver is not available in older browsers like Safari v12 const observer = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(setHeight) : undefined if (observer) { observer.observe(contentRef.current) } return () => { setHeight.cancel() window.removeEventListener('resize', setHeight) if (observer) { observer.disconnect() } } // eslint-disable-next-line react-hooks/exhaustive-deps }, []) return ( <AnimateHeightContainer {...props} height={contentHeight}> <div ref={contentRef}>{children}</div> </AnimateHeightContainer> ) } export default AnimateHeight