fix: sticky action scroll to bottom when edit message (#5169)
This commit is contained in:
parent
d56686fd21
commit
b0d3d485cf
@ -27,6 +27,7 @@ function ThreadDetail() {
|
|||||||
const { threadId } = useParams({ from: Route.id })
|
const { threadId } = useParams({ from: Route.id })
|
||||||
const [isUserScrolling, setIsUserScrolling] = useState(false)
|
const [isUserScrolling, setIsUserScrolling] = useState(false)
|
||||||
const [isAtBottom, setIsAtBottom] = useState(true)
|
const [isAtBottom, setIsAtBottom] = useState(true)
|
||||||
|
const [hasScrollbar, setHasScrollbar] = useState(false)
|
||||||
const lastScrollTopRef = useRef(0)
|
const lastScrollTopRef = useRef(0)
|
||||||
const { currentThreadId, setCurrentThreadId } = useThreads()
|
const { currentThreadId, setCurrentThreadId } = useThreads()
|
||||||
const { setCurrentAssistant, assistants } = useAssistant()
|
const { setCurrentAssistant, assistants } = useAssistant()
|
||||||
@ -45,6 +46,19 @@ function ThreadDetail() {
|
|||||||
const isFirstRender = useRef(true)
|
const isFirstRender = useRef(true)
|
||||||
const messagesCount = useMemo(() => messages?.length ?? 0, [messages])
|
const messagesCount = useMemo(() => messages?.length ?? 0, [messages])
|
||||||
|
|
||||||
|
// Function to check scroll position and scrollbar presence
|
||||||
|
const checkScrollState = () => {
|
||||||
|
const scrollContainer = scrollContainerRef.current
|
||||||
|
if (!scrollContainer) return
|
||||||
|
|
||||||
|
const { scrollTop, scrollHeight, clientHeight } = scrollContainer
|
||||||
|
const isBottom = Math.abs(scrollHeight - scrollTop - clientHeight) < 10
|
||||||
|
const hasScroll = scrollHeight > clientHeight
|
||||||
|
|
||||||
|
setIsAtBottom(isBottom)
|
||||||
|
setHasScrollbar(hasScroll)
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentThreadId !== threadId) {
|
if (currentThreadId !== threadId) {
|
||||||
setCurrentThreadId(threadId)
|
setCurrentThreadId(threadId)
|
||||||
@ -86,6 +100,7 @@ function ThreadDetail() {
|
|||||||
scrollToBottom()
|
scrollToBottom()
|
||||||
setIsAtBottom(true)
|
setIsAtBottom(true)
|
||||||
setIsUserScrolling(false)
|
setIsUserScrolling(false)
|
||||||
|
checkScrollState()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
@ -96,6 +111,7 @@ function ThreadDetail() {
|
|||||||
scrollToBottom()
|
scrollToBottom()
|
||||||
setIsAtBottom(true)
|
setIsAtBottom(true)
|
||||||
setIsUserScrolling(false)
|
setIsUserScrolling(false)
|
||||||
|
checkScrollState()
|
||||||
}, [threadId])
|
}, [threadId])
|
||||||
|
|
||||||
// Single useEffect for all auto-scrolling logic
|
// Single useEffect for all auto-scrolling logic
|
||||||
@ -109,6 +125,13 @@ function ThreadDetail() {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [streamingContent, isUserScrolling, messagesCount])
|
}, [streamingContent, isUserScrolling, messagesCount])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (streamingContent) {
|
||||||
|
const interval = setInterval(checkScrollState, 100)
|
||||||
|
return () => clearInterval(interval)
|
||||||
|
}
|
||||||
|
}, [streamingContent])
|
||||||
|
|
||||||
const scrollToBottom = (smooth = false) => {
|
const scrollToBottom = (smooth = false) => {
|
||||||
if (scrollContainerRef.current) {
|
if (scrollContainerRef.current) {
|
||||||
scrollContainerRef.current.scrollTo({
|
scrollContainerRef.current.scrollTo({
|
||||||
@ -123,12 +146,14 @@ function ThreadDetail() {
|
|||||||
const { scrollTop, scrollHeight, clientHeight } = target
|
const { scrollTop, scrollHeight, clientHeight } = target
|
||||||
// Use a small tolerance to better detect when we're at the bottom
|
// Use a small tolerance to better detect when we're at the bottom
|
||||||
const isBottom = Math.abs(scrollHeight - scrollTop - clientHeight) < 10
|
const isBottom = Math.abs(scrollHeight - scrollTop - clientHeight) < 10
|
||||||
|
const hasScroll = scrollHeight > clientHeight
|
||||||
|
|
||||||
// Detect if this is a user-initiated scroll
|
// Detect if this is a user-initiated scroll
|
||||||
if (Math.abs(scrollTop - lastScrollTopRef.current) > 10) {
|
if (Math.abs(scrollTop - lastScrollTopRef.current) > 10) {
|
||||||
setIsUserScrolling(!isBottom)
|
setIsUserScrolling(!isBottom)
|
||||||
}
|
}
|
||||||
setIsAtBottom(isBottom)
|
setIsAtBottom(isBottom)
|
||||||
|
setHasScrollbar(hasScroll)
|
||||||
lastScrollTopRef.current = scrollTop
|
lastScrollTopRef.current = scrollTop
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,12 +163,14 @@ function ThreadDetail() {
|
|||||||
const { scrollTop, scrollHeight, clientHeight } = target
|
const { scrollTop, scrollHeight, clientHeight } = target
|
||||||
// Use a small tolerance to better detect when we're at the bottom
|
// Use a small tolerance to better detect when we're at the bottom
|
||||||
const isBottom = Math.abs(scrollHeight - scrollTop - clientHeight) < 10
|
const isBottom = Math.abs(scrollHeight - scrollTop - clientHeight) < 10
|
||||||
|
const hasScroll = scrollHeight > clientHeight
|
||||||
|
|
||||||
// Detect if this is a user-initiated scroll
|
// Detect if this is a user-initiated scroll
|
||||||
if (Math.abs(scrollTop - lastScrollTopRef.current) > 10) {
|
if (Math.abs(scrollTop - lastScrollTopRef.current) > 10) {
|
||||||
setIsUserScrolling(!isBottom)
|
setIsUserScrolling(!isBottom)
|
||||||
}
|
}
|
||||||
setIsAtBottom(isBottom)
|
setIsAtBottom(isBottom)
|
||||||
|
setHasScrollbar(hasScroll)
|
||||||
lastScrollTopRef.current = scrollTop
|
lastScrollTopRef.current = scrollTop
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +242,7 @@ function ThreadDetail() {
|
|||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'from-main-view/20 bg-gradient-to-b to-main-view absolute z-0 -top-6 h-8 py-1 flex w-full justify-center backdrop-blur pointer-events-none opacity-0 visibility-hidden',
|
'from-main-view/20 bg-gradient-to-b to-main-view absolute z-0 -top-6 h-8 py-1 flex w-full justify-center backdrop-blur pointer-events-none opacity-0 visibility-hidden',
|
||||||
!isAtBottom && 'visibility-visible opacity-100'
|
!isAtBottom && hasScrollbar && 'visibility-visible opacity-100'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user