From 09bfc0549ec14f4de2b2bb87cf1381108841e312 Mon Sep 17 00:00:00 2001 From: Faisal Amir Date: Tue, 10 Dec 2024 13:34:59 +0800 Subject: [PATCH] fix: auto scrolling to bottom (#4256) --- .../ThreadCenterPanel/ChatBody/index.tsx | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/web/screens/Thread/ThreadCenterPanel/ChatBody/index.tsx b/web/screens/Thread/ThreadCenterPanel/ChatBody/index.tsx index 9077a351ac..de99ee4138 100644 --- a/web/screens/Thread/ThreadCenterPanel/ChatBody/index.tsx +++ b/web/screens/Thread/ThreadCenterPanel/ChatBody/index.tsx @@ -1,4 +1,4 @@ -import { memo, useEffect, useMemo, useRef, useState } from 'react' +import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { ThreadMessage } from '@janhq/core' import { useVirtualizer } from '@tanstack/react-virtual' @@ -58,6 +58,8 @@ const ChatBody = memo( }) => { // The scrollable element for your list const parentRef = useRef(null) + const prevScrollTop = useRef(0) + const isUserManuallyScrollingUp = useRef(false) const count = useMemo( () => (messages?.length ?? 0) + (loadModelError ? 1 : 0), @@ -72,27 +74,61 @@ const ChatBody = memo( overscan: 5, }) useEffect(() => { + if (isUserManuallyScrollingUp.current === true || !parentRef.current) + return + if (count > 0 && messages && virtualizer) { virtualizer.scrollToIndex(count - 1) } - }, [count, virtualizer, messages, loadModelError]) + }, [ + count, + virtualizer, + messages, + loadModelError, + isUserManuallyScrollingUp, + ]) const items = virtualizer.getVirtualItems() + virtualizer.shouldAdjustScrollPositionOnItemSizeChange = ( item, _, instance ) => { + if (isUserManuallyScrollingUp.current === true) return false return ( // item.start < (instance.scrollOffset ?? 0) && instance.scrollDirection !== 'backward' ) } + const handleScroll = useCallback((event: React.UIEvent) => { + const currentScrollTop = event.currentTarget.scrollTop + + if (prevScrollTop.current > currentScrollTop) { + isUserManuallyScrollingUp.current = true + } else { + const currentScrollTop = event.currentTarget.scrollTop + const scrollHeight = event.currentTarget.scrollHeight + const clientHeight = event.currentTarget.clientHeight + + if (currentScrollTop + clientHeight >= scrollHeight) { + isUserManuallyScrollingUp.current = false + } + } + + if (isUserManuallyScrollingUp.current === true) { + event.preventDefault() + event.stopPropagation() + } + prevScrollTop.current = currentScrollTop + }, []) + return (