import { getClassNames } from '@websolutespa/bom-core'; import { useRealSize } from '@websolutespa/bom-mixer-hooks'; import React, { CSSProperties, useEffect, useRef, useState } from 'react'; import styled from 'styled-components'; export type ExpandProps = { isExpanded?: boolean; delay?: number; }; const StyledExpand = styled.div<{ delay: number, height: CSSProperties['height'] }>` padding: 0; margin: 0; height: 0; overflow: hidden; visibility: hidden; transition: height ${props => props.delay}ms ease; &.visible { visibility: visible; } &.expanded { height: ${props => props.height}; visibility: visible; } `; export const Expand: React.FC> = ({ isExpanded = false, delay = 200, children, }: React.PropsWithChildren) => { const [height, setHeight] = useState(isExpanded ? 'auto' : '0'); const [selfExpanded, setSelfExpanded] = useState(isExpanded); const [visible, setVisible] = useState(isExpanded); const contentRef = useRef(null); const entryTimer = useRef(undefined); const leaveTimer = useRef(undefined); const resetTimer = useRef(undefined); const [size, updateSize] = useRealSize(contentRef); useEffect(() => setHeight(`${size.height}px`), [size.height]); useEffect(() => { // show element or reset height. // force an update once manually, even if the element does not change. // (the height of the element might be "auto") if (isExpanded) { setVisible(isExpanded); } else { updateSize(); setHeight(`${size.height}px`); } // show expand animation entryTimer.current = window.setTimeout(() => { setSelfExpanded(isExpanded); clearTimeout(entryTimer.current); }, 30); // Reset height after animation 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]); const classNames = getClassNames('container', { expanded: selfExpanded, visible }); return (
{children}
); }; Expand.displayName = 'Expand';