fix(chat): Smoothen scrolling animation on message reply click

This commit is contained in:
João Victor 2024-10-18 10:14:39 -03:00
parent 719d2e6296
commit 8d37029c85

View File

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