From a75fc9be51b363d2f6830d48f84548af9e2206e9 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Tue, 12 Dec 2023 12:34:48 +0100 Subject: [PATCH] Story: Fix long caption blinking (#4099) --- src/components/story/StoryCaption.tsx | 68 +++++++++++++++------------ 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/src/components/story/StoryCaption.tsx b/src/components/story/StoryCaption.tsx index b0d2f51b2..7bb62edc0 100644 --- a/src/components/story/StoryCaption.tsx +++ b/src/components/story/StoryCaption.tsx @@ -1,13 +1,12 @@ import React, { - memo, useEffect, useRef, useState, + memo, useEffect, useLayoutEffect, useRef, useState, } from '../../lib/teact/teact'; import { addExtraClass, removeExtraClass } from '../../lib/teact/teact-dom'; import type { ApiStory } from '../../api/types'; -import { requestMutation } from '../../lib/fasterdom/fasterdom'; +import { requestForcedReflow, requestMeasure, requestMutation } from '../../lib/fasterdom/fasterdom'; import buildClassName from '../../util/buildClassName'; -import { REM } from '../common/helpers/mediaDimensions'; import useLang from '../../hooks/useLang'; import usePrevDuringAnimation from '../../hooks/usePrevDuringAnimation'; @@ -27,7 +26,6 @@ interface OwnProps { } const EXPAND_ANIMATION_DURATION_MS = 400; -const OVERFLOW_THRESHOLD_PX = 5.75 * REM; const LINES_TO_SHOW = 3; function StoryCaption({ @@ -49,15 +47,6 @@ function StoryCaption({ const prevIsExpanded = usePrevDuringAnimation(isExpanded || undefined, EXPAND_ANIMATION_DURATION_MS); const isInExpandedState = isExpanded || prevIsExpanded; - useEffect(() => { - if (!ref.current) { - return; - } - - const { clientHeight } = ref.current; - setHasOverflow(clientHeight > OVERFLOW_THRESHOLD_PX); - }, [caption]); - useEffect(() => { requestMutation(() => { if (!contentRef.current) { @@ -77,26 +66,46 @@ function StoryCaption({ canExpand, undefined, true, 'slow', true, ); - useEffect(() => { - if (!showMoreButtonRef.current || !contentRef.current || !textRef.current) { - return; - } + useLayoutEffect(() => { + requestMeasure(() => { + if (!showMoreButtonRef.current) { + return; + } - const container = contentRef.current; - const textContainer = textRef.current; + const button = showMoreButtonRef.current; - const textOffsetTop = textContainer.offsetTop; - const lineHeight = parseInt(getComputedStyle(textContainer).lineHeight, 10); - const overflowShift = textOffsetTop + lineHeight * LINES_TO_SHOW; + const { offsetWidth } = button; - const button = showMoreButtonRef.current; - - const { offsetWidth } = button; - requestMutation(() => { - container.style.setProperty('--_overflow-shift', `${overflowShift}px`); - container.style.setProperty('--expand-button-width', `${offsetWidth}px`); + requestMutation(() => { + button.style.setProperty('--expand-button-width', `${offsetWidth}px`); + }); }); - }, [canExpand]); + }, []); + + useLayoutEffect(() => { + requestForcedReflow(() => { + if (!contentRef.current || !textRef.current) { + return undefined; + } + + const container = contentRef.current; + const textContainer = textRef.current; + + const textOffsetTop = textContainer.offsetTop; + const lineHeight = parseInt(getComputedStyle(textContainer).lineHeight, 10); + const isOverflowing = textContainer.clientHeight > lineHeight * LINES_TO_SHOW; + const overflowShift = textOffsetTop + lineHeight * LINES_TO_SHOW; + + return () => { + if (isOverflowing) { + addExtraClass(container, styles.hasOverflow); + setHasOverflow(true); + } + + container.style.setProperty('--_overflow-shift', `${overflowShift}px`); + }; + }); + }, [caption]); useEffect(() => { if (!isExpanded) { @@ -106,7 +115,6 @@ function StoryCaption({ const fullClassName = buildClassName( styles.captionContent, - hasOverflow && !isExpanded && styles.hasOverflow, isInExpandedState && styles.expanded, shouldRenderShowMore && styles.withShowMore, );