From aa02c0d243f9ada13c5d22a27d74f74361ae10a9 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 7 Nov 2024 09:14:29 +0100 Subject: [PATCH] use ref height for accordion expand animation --- site/src/common/blocks/AccordionItemBlock.tsx | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/site/src/common/blocks/AccordionItemBlock.tsx b/site/src/common/blocks/AccordionItemBlock.tsx index ddeee0ec4..64fcf4083 100644 --- a/site/src/common/blocks/AccordionItemBlock.tsx +++ b/site/src/common/blocks/AccordionItemBlock.tsx @@ -5,9 +5,9 @@ import { SpaceBlock } from "@src/common/blocks/SpaceBlock"; import { StandaloneCallToActionListBlock } from "@src/common/blocks/StandaloneCallToActionListBlock"; import { StandaloneHeadingBlock } from "@src/common/blocks/StandaloneHeadingBlock"; import { SvgUse } from "@src/common/helpers/SvgUse"; -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { useIntl } from "react-intl"; -import styled, { css } from "styled-components"; +import styled from "styled-components"; import { Typography } from "../components/Typography"; @@ -30,12 +30,26 @@ type AccordionItemBlockProps = PropsWithData; export const AccordionItemBlock = withPreview( ({ data: { title, content, openByDefault } }: AccordionItemBlockProps) => { const intl = useIntl(); + const innerContentRef = useRef(null); const [isExpanded, setIsExpanded] = useState(openByDefault); + const [elementHeight, setElementHeight] = useState(0); const ariaLabelText = isExpanded ? intl.formatMessage({ id: "accordionBlock.ariaLabel.expanded", defaultMessage: "Collapse accordion item" }) : intl.formatMessage({ id: "accordionBlock.ariaLabel.collapsed", defaultMessage: "Expand accordion item" }); + useEffect(() => { + const updateElementHeight = () => { + const height = isExpanded && innerContentRef.current ? innerContentRef.current.clientHeight : 0; + setElementHeight(height); + }; + + updateElementHeight(); + + window.addEventListener("resize", updateElementHeight); + return () => window.removeEventListener("resize", updateElementHeight); + }, [isExpanded]); + return ( <> setIsExpanded(!isExpanded)} aria-label={ariaLabelText}> @@ -44,8 +58,8 @@ export const AccordionItemBlock = withPreview( - - + + @@ -83,21 +97,17 @@ const AnimatedChevron = styled(SvgUse)<{ $isExpanded: boolean }>` transition: transform 0.4s ease; `; -const ContentWrapper = styled.div` +const ContentWrapper = styled.div<{ $isExpanded: boolean; $height: number }>` overflow: hidden; + height: ${({ $height }) => $height}px; + transition: height 300ms, margin-bottom 300ms; `; -const ContentWrapperInner = styled.div<{ $isExpanded: boolean }>` - padding-bottom: ${({ theme }) => theme.spacing.S300}; - margin-top: -100%; - opacity: 0; - transition: margin-top 0.8s ease-out 0.3s, opacity 0.3s linear; - - ${({ $isExpanded }) => - $isExpanded && - css` - margin-top: 0; - opacity: 1; - transition: margin-top 0.5s ease-out, opacity 0.3s linear 0.4s; - `} +const ContentWrapperInner = styled.div` + padding: ${({ theme }) => theme.spacing.S500} 0; + border-top: 1px solid ${({ theme }) => theme.palette.gray["300"]}; + + > *:last-child { + margin-bottom: 0; + } `;