diff --git a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/component.tsx b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/component.tsx index 141cedf723..6e16abd64d 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/component.tsx +++ b/bigbluebutton-html5/imports/ui/components/chat/chat-graphql/chat-message-list/page/chat-message/component.tsx @@ -105,6 +105,7 @@ function isInViewport(el: HTMLDivElement) { const messageRef = React.createRef(); const ANIMATION_DURATION = 2000; +const SCROLL_ANIMATION_DURATION = 500; const ChatMesssage: React.FC = ({ previousMessage, @@ -144,6 +145,8 @@ const ChatMesssage: React.FC = ({ const chatFocusMessageRequest = useStorageKey(ChatEvents.CHAT_FOCUS_MESSAGE_REQUEST, STORAGES.IN_MEMORY); const containerRef = React.useRef(null); const animationInitialTimestamp = React.useRef(0); + const animationInitialScrollPosition = React.useRef(0); + const animationScrollPositionDiff = React.useRef(0); const [chatSendReaction] = useMutation(CHAT_SEND_REACTION_MUTATION); const [chatDeleteReaction] = useMutation(CHAT_DELETE_REACTION_MUTATION); @@ -197,12 +200,16 @@ const ChatMesssage: React.FC = ({ ].some((config) => config); const startScrollAnimation = (timestamp: number) => { - if (scrollRef.current && containerRef.current) { - // eslint-disable-next-line no-param-reassign - scrollRef.current.scrollTop = containerRef.current.offsetTop; - } + animationInitialScrollPosition.current = scrollRef.current?.scrollTop || 0; + animationScrollPositionDiff.current = (scrollRef.current?.scrollTop || 0) + - ((containerRef.current?.offsetTop || 0) - ((scrollRef.current?.offsetHeight || 0) / 2)); animationInitialTimestamp.current = timestamp; - requestAnimationFrame(animate); + requestAnimationFrame(animateScrollPosition); + }; + + const startBackgroundAnimation = (timestamp: number) => { + animationInitialTimestamp.current = timestamp; + requestAnimationFrame(animateBackgroundColor); }; useEffect(() => { @@ -210,6 +217,7 @@ const ChatMesssage: React.FC = ({ if (e instanceof CustomEvent) { if (e.detail.sequence === message.messageSequence) { requestAnimationFrame(startScrollAnimation); + requestAnimationFrame(startBackgroundAnimation); } } }; @@ -244,12 +252,25 @@ const ChatMesssage: React.FC = ({ } }, []); - const animate = useCallback((timestamp: number) => { + const animateScrollPosition = useCallback((timestamp: number) => { + const value = (timestamp - animationInitialTimestamp.current) / SCROLL_ANIMATION_DURATION; + const { current: scrollContainer } = scrollRef; + const { current: messageContainer } = containerRef; + if (!scrollContainer || !messageContainer) return; + if (value <= 1) { + // eslint-disable-next-line no-param-reassign + scrollContainer.scrollTop = animationInitialScrollPosition.current + - (value * animationScrollPositionDiff.current); + requestAnimationFrame(animateScrollPosition); + } + }, []); + + const animateBackgroundColor = useCallback((timestamp: number) => { if (!messageContentRef.current) return; const value = (timestamp - animationInitialTimestamp.current) / ANIMATION_DURATION; if (value < 1) { messageContentRef.current.style.backgroundColor = `rgb(${colorBlueLightestChannel} / ${1 - value})`; - requestAnimationFrame(animate); + requestAnimationFrame(animateBackgroundColor); } else { messageContentRef.current.style.backgroundColor = '#f4f6fa'; }