diff --git a/src/components/expandable.jsx b/src/components/expandable.jsx index eb5098481..fa1da42e5 100644 --- a/src/components/expandable.jsx +++ b/src/components/expandable.jsx @@ -1,4 +1,4 @@ -import { useLayoutEffect, useRef, useState } from 'react'; +import { useEffect, useLayoutEffect, useRef, useState } from 'react'; import cn from 'classnames'; import { faChevronDown } from '@fortawesome/free-solid-svg-icons'; import { useEvent } from 'react-use-event-hook'; @@ -30,24 +30,37 @@ export function Expandable({ const [expanded, setExpanded] = useState(givenExpanded); const expand = useEvent(() => setExpanded(true)); - useLayoutEffect(() => { - if (expanded) { - return; + // Update the maxHeight when the content dimensions changes + const update = useEvent(({ width, height }) => { + if (width * height < scaledMaxUnfoldedArea) { + setNeedExpand(false); + setMaxHeight(null); + } else { + let targetHeight = scaledFoldedArea / width; + targetHeight = align(content.current, targetHeight); + setNeedExpand(true); + setMaxHeight(`${targetHeight}px`); } + }); - return observeResizeOf(content.current, ({ target, contentRect }) => { - const { width, height } = contentRect; - if (width * height < scaledMaxUnfoldedArea) { - setNeedExpand(false); - setMaxHeight(null); - } else { - let targetHeight = scaledFoldedArea / width; - targetHeight = align(target, targetHeight); - setNeedExpand(true); - setMaxHeight(`${targetHeight}px`); + // We use the layout effect just once, to set the initial height without + // flickering. + useLayoutEffect( + () => { + if (!expanded) { + update(content.current.getBoundingClientRect()); } - }); - }, [expanded, scaledFoldedArea, scaledMaxUnfoldedArea]); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [], + ); + + // Update the maxHeight when the content resizes + useEffect(() => { + if (!expanded) { + return observeResizeOf(content.current, ({ contentRect }) => update(contentRect)); + } + }, [expanded, update]); return ( <>