diff --git a/src/components/middle/MessageList.tsx b/src/components/middle/MessageList.tsx index 53f3d4c6b..94ced632e 100644 --- a/src/components/middle/MessageList.tsx +++ b/src/components/middle/MessageList.tsx @@ -13,7 +13,7 @@ import { MESSAGE_LIST_SLICE, SERVICE_NOTIFICATIONS_USER_ID, } from '../../config'; -import { forceMeasure, requestForcedReflow, requestMeasure, requestMutation } from '../../lib/fasterdom/fasterdom'; +import { forceMeasure, requestMeasure, requestMutation } from '../../lib/fasterdom/fasterdom'; import { getIsSavedDialog, getMessageHtmlId, @@ -66,6 +66,7 @@ import { debounce, onTickEnd } from '../../util/schedulers'; import getOffsetToContainer from '../../util/visibility/getOffsetToContainer'; import { REM } from '../common/helpers/mediaDimensions'; import { groupMessages } from './helpers/groupMessages'; +import { requestMessageListReflow } from './helpers/messageListReflow'; import { preventMessageInputBlur } from './helpers/preventMessageInputBlur'; import useInterval from '../../hooks/schedulers/useInterval'; @@ -677,7 +678,7 @@ const MessageList = ({ }, MESSAGE_ANIMATION_DURATION); } - requestForcedReflow(() => { + requestMessageListReflow(() => { const { scrollTop, scrollHeight, offsetHeight } = container; const scrollOffset = scrollOffsetRef.current; diff --git a/src/components/middle/helpers/messageListReflow.ts b/src/components/middle/helpers/messageListReflow.ts new file mode 100644 index 000000000..ed5dd50a2 --- /dev/null +++ b/src/components/middle/helpers/messageListReflow.ts @@ -0,0 +1,24 @@ +import { requestForcedReflow } from '../../../lib/fasterdom/fasterdom'; + +type ReflowCallback = () => (NoneToVoidFunction | void); + +let afterReflowCallbacks: ReflowCallback[] = []; + +// For children effects that need to run after the message list reflow +export function requestAfterMessageListReflow(cb: ReflowCallback) { + afterReflowCallbacks.push(cb); +} + +export function requestMessageListReflow(cb: ReflowCallback) { + requestForcedReflow(() => { + const mutationFn = cb(); + + const callbacks = afterReflowCallbacks; + afterReflowCallbacks = []; + for (const afterCb of callbacks) { + requestForcedReflow(afterCb); + } + + return mutationFn; + }); +} diff --git a/src/components/middle/message/hooks/useFocusMessageListElement.ts b/src/components/middle/message/hooks/useFocusMessageListElement.ts index a28d9bfe9..5318bb6c8 100644 --- a/src/components/middle/message/hooks/useFocusMessageListElement.ts +++ b/src/components/middle/message/hooks/useFocusMessageListElement.ts @@ -1,5 +1,5 @@ import type { ElementRef } from '../../../../lib/teact/teact'; -import { useLayoutEffect } from '../../../../lib/teact/teact'; +import { useLayoutEffect, useRef } from '../../../../lib/teact/teact'; import { addExtraClass } from '../../../../lib/teact/teact-dom'; import type { FocusDirection, ScrollTargetPosition } from '../../../../types'; @@ -10,6 +10,7 @@ import { } from '../../../../lib/fasterdom/fasterdom'; import animateScroll from '../../../../util/animateScroll'; import { REM } from '../../../common/helpers/mediaDimensions'; +import { requestAfterMessageListReflow } from '../../helpers/messageListReflow'; // This is used when the viewport was replaced. const BOTTOM_FOCUS_OFFSET = 500; @@ -36,7 +37,12 @@ export default function useFocusMessageListElement({ isQuote?: boolean; scrollTargetPosition?: ScrollTargetPosition; }) { + const isRelocatedRef = useRef(!isJustAdded); + useLayoutEffect(() => { + const isRelocated = isRelocatedRef.current; + isRelocatedRef.current = false; + if (isFocused && elementRef.current) { const messagesContainer = elementRef.current.closest('.MessageList'); if (!messagesContainer) return; @@ -72,9 +78,14 @@ export default function useFocusMessageListElement({ return result; }; - requestMeasure(() => { - requestMutation(exec()!); - }); + if (isRelocated) { + // We need this to override scroll setting from Message List layout effect + requestAfterMessageListReflow(exec); + } else { + requestMeasure(() => { + requestMutation(exec()!); + }); + } } }, [ elementRef, isFocused, focusDirection, noFocusHighlight, isResizingContainer, isQuote, scrollTargetPosition,