diff --git a/src/components/middle/ActionMessage.tsx b/src/components/middle/ActionMessage.tsx index fbf199a53..0fc926b67 100644 --- a/src/components/middle/ActionMessage.tsx +++ b/src/components/middle/ActionMessage.tsx @@ -40,6 +40,7 @@ import useFlag from '../../hooks/useFlag'; import { useIsIntersecting, useOnIntersect } from '../../hooks/useIntersectionObserver'; import useLang from '../../hooks/useLang'; import useOldLang from '../../hooks/useOldLang'; +import useMessageResizeObserver from '../../hooks/useResizeMessageObserver'; import useShowTransitionDeprecated from '../../hooks/useShowTransitionDeprecated'; import useFocusMessage from './message/hooks/useFocusMessage'; @@ -171,6 +172,8 @@ const ActionMessage: FC = ({ const withServiceReactions = Boolean(message.areReactionsPossible && message?.reactions); + useMessageResizeObserver(ref, isLastInList); + useEffect(() => { if (noAppearanceAnimation) { return; diff --git a/src/components/middle/message/Message.tsx b/src/components/middle/message/Message.tsx index 305499339..f980b77f5 100644 --- a/src/components/middle/message/Message.tsx +++ b/src/components/middle/message/Message.tsx @@ -1,6 +1,5 @@ import type { FC } from '../../../lib/teact/teact'; import React, { - beginHeavyAnimation, memo, useCallback, useEffect, @@ -111,17 +110,12 @@ import { selectUploadProgress, selectUser, } from '../../../global/selectors'; -import { isAnimatingScroll } from '../../../util/animateScroll'; import buildClassName from '../../../util/buildClassName'; import { isElementInViewport } from '../../../util/isElementInViewport'; import { getMessageKey } from '../../../util/keys/messageKey'; import stopEvent from '../../../util/stopEvent'; import { IS_ANDROID, IS_ELECTRON, IS_TRANSLATION_SUPPORTED } from '../../../util/windowEnvironment'; -import { - calculateDimensionsForMessageMedia, - getStickerDimensions, - REM, -} from '../../common/helpers/mediaDimensions'; +import { calculateDimensionsForMessageMedia, getStickerDimensions, REM } from '../../common/helpers/mediaDimensions'; import { getPeerColorClass } from '../../common/helpers/peerColor'; import renderText from '../../common/helpers/renderText'; import { getCustomEmojiSize } from '../composer/helpers/customEmoji'; @@ -139,10 +133,9 @@ import { useOnIntersect } from '../../../hooks/useIntersectionObserver'; import useLastCallback from '../../../hooks/useLastCallback'; import useOldLang from '../../../hooks/useOldLang'; import usePreviousDeprecated from '../../../hooks/usePreviousDeprecated'; -import useResizeObserver from '../../../hooks/useResizeObserver'; +import useMessageResizeObserver from '../../../hooks/useResizeMessageObserver'; import useShowTransition from '../../../hooks/useShowTransition'; import useTextLanguage from '../../../hooks/useTextLanguage'; -import useThrottledCallback from '../../../hooks/useThrottledCallback'; import useDetectChatLanguage from './hooks/useDetectChatLanguage'; import useFocusMessage from './hooks/useFocusMessage'; import useInnerHandlers from './hooks/useInnerHandlers'; @@ -322,9 +315,6 @@ const APPEARANCE_DELAY = 10; const NO_MEDIA_CORNERS_THRESHOLD = 18; const QUICK_REACTION_SIZE = 1.75 * REM; const EXTRA_SPACE_FOR_REACTIONS = 2.25 * REM; -const BOTTOM_FOCUS_SCROLL_THRESHOLD = 5; -const THROTTLE_MS = 300; -const RESIZE_ANIMATION_DURATION = 400; const Message: FC = ({ message, @@ -442,8 +432,6 @@ const Message: FC = ({ // eslint-disable-next-line no-null/no-null const quickReactionRef = useRef(null); - const messageHeightRef = useRef(0); - const lang = useOldLang(); const [isTranscriptionHidden, setTranscriptionHidden] = useState(false); @@ -850,34 +838,7 @@ const Message: FC = ({ || ((asForwarded || isChatWithSelf) && forwardInfo?.postAuthorTitle) || undefined; - const shouldFocusOnResize = isLastInList; - - const handleResize = useLastCallback((entry: ResizeObserverEntry) => { - const lastHeight = messageHeightRef.current; - - const newHeight = entry.contentRect.height; - messageHeightRef.current = newHeight; - - if (isAnimatingScroll() || !lastHeight || newHeight <= lastHeight) return; - - const container = entry.target.closest('.MessageList'); - if (!container) return; - - beginHeavyAnimation(RESIZE_ANIMATION_DURATION); - - const resizeDiff = newHeight - lastHeight; - const { offsetHeight, scrollHeight, scrollTop } = container; - const currentScrollBottom = Math.round(scrollHeight - scrollTop - offsetHeight); - const previousScrollBottom = currentScrollBottom - resizeDiff; - - if (previousScrollBottom <= BOTTOM_FOCUS_SCROLL_THRESHOLD) { - focusLastMessage(); - } - }); - - const throttledResize = useThrottledCallback(handleResize, [handleResize], THROTTLE_MS, false); - - useResizeObserver(ref, throttledResize, !shouldFocusOnResize); + useMessageResizeObserver(ref, isLastInList); useEffect(() => { const bottomMarker = bottomMarkerRef.current; diff --git a/src/hooks/useResizeMessageObserver.ts b/src/hooks/useResizeMessageObserver.ts new file mode 100644 index 000000000..55370d8f6 --- /dev/null +++ b/src/hooks/useResizeMessageObserver.ts @@ -0,0 +1,52 @@ +import { beginHeavyAnimation, useRef } from '../lib/teact/teact'; +import { getActions } from '../global'; + +import { isAnimatingScroll } from '../util/animateScroll'; +import useLastCallback from './useLastCallback'; +import useResizeObserver from './useResizeObserver'; +import useThrottledCallback from './useThrottledCallback'; + +const BOTTOM_FOCUS_SCROLL_THRESHOLD = 5; +const THROTTLE_MS = 300; +const RESIZE_ANIMATION_DURATION = 400; + +function useMessageResizeObserver( + ref: React.RefObject | undefined, + shouldFocusOnResize = false, +) { + const { + focusLastMessage, + } = getActions(); + const messageHeightRef = useRef(0); + + const handleResize = useLastCallback( + (entry) => { + const lastHeight = messageHeightRef.current; + + const newHeight = entry.contentRect.height; + messageHeightRef.current = newHeight; + + if (isAnimatingScroll() || !lastHeight || newHeight <= lastHeight) return; + + const container = entry.target.closest('.MessageList'); + if (!container) return; + + beginHeavyAnimation(RESIZE_ANIMATION_DURATION); + + const resizeDiff = newHeight - lastHeight; + const { offsetHeight, scrollHeight, scrollTop } = container; + const currentScrollBottom = Math.round(scrollHeight - scrollTop - offsetHeight); + const previousScrollBottom = currentScrollBottom - resizeDiff; + + if (previousScrollBottom <= BOTTOM_FOCUS_SCROLL_THRESHOLD) { + focusLastMessage(); + } + }, + ); + + const throttledResize = useThrottledCallback(handleResize, [handleResize], THROTTLE_MS, false); + + useResizeObserver(ref, throttledResize, !shouldFocusOnResize); +} + +export default useMessageResizeObserver;