fix: scroll issue padding not re render correctly (#6639)
This commit is contained in:
parent
75dee86375
commit
f2a3861410
@ -3,7 +3,8 @@ import { useAppState } from './useAppState'
|
||||
import { useMessages } from './useMessages'
|
||||
|
||||
const VIEWPORT_PADDING = 40 // Offset from viewport bottom for user message positioning
|
||||
const MAX_DOM_RETRY_ATTEMPTS = 3 // Maximum attempts to find DOM elements before giving up
|
||||
const MAX_DOM_RETRY_ATTEMPTS = 5 // Maximum attempts to find DOM elements before giving up
|
||||
const DOM_RETRY_DELAY = 100 // Delay in ms between DOM element retry attempts
|
||||
|
||||
export const useThreadScrolling = (
|
||||
threadId: string,
|
||||
@ -16,6 +17,7 @@ export const useThreadScrolling = (
|
||||
const [isAtBottom, setIsAtBottom] = useState(true)
|
||||
const [hasScrollbar, setHasScrollbar] = useState(false)
|
||||
const lastScrollTopRef = useRef(0)
|
||||
const lastAssistantMessageRef = useRef<HTMLElement | null>(null)
|
||||
|
||||
const messageCount = useMessages((state) => state.messages[threadId]?.length ?? 0)
|
||||
const lastMessageRole = useMessages((state) => {
|
||||
@ -33,13 +35,12 @@ export const useThreadScrolling = (
|
||||
|
||||
const userMessages = scrollContainer.querySelectorAll('[data-message-author-role="user"]')
|
||||
const assistantMessages = scrollContainer.querySelectorAll('[data-message-author-role="assistant"]')
|
||||
|
||||
return {
|
||||
scrollContainer,
|
||||
lastUserMessage: userMessages[userMessages.length - 1] as HTMLElement,
|
||||
lastAssistantMessage: assistantMessages[assistantMessages.length - 1] as HTMLElement,
|
||||
}
|
||||
}, [])
|
||||
}, [scrollContainerRef])
|
||||
|
||||
|
||||
const showScrollToBottomBtn = !isAtBottom && hasScrollbar
|
||||
@ -121,6 +122,7 @@ export const useThreadScrolling = (
|
||||
setPaddingHeight(calculatedPadding)
|
||||
originalPaddingRef.current = calculatedPadding
|
||||
|
||||
// Scroll after padding is applied to the DOM
|
||||
requestAnimationFrame(() => {
|
||||
elements.scrollContainer.scrollTo({
|
||||
top: elements.scrollContainer.scrollHeight,
|
||||
@ -136,11 +138,11 @@ export const useThreadScrolling = (
|
||||
calculatePadding()
|
||||
} else if (retryCount < MAX_DOM_RETRY_ATTEMPTS) {
|
||||
retryCount++
|
||||
requestAnimationFrame(tryCalculatePadding)
|
||||
setTimeout(tryCalculatePadding, DOM_RETRY_DELAY)
|
||||
}
|
||||
}
|
||||
|
||||
requestAnimationFrame(tryCalculatePadding)
|
||||
tryCalculatePadding()
|
||||
}
|
||||
|
||||
prevCountRef.current = messageCount
|
||||
@ -150,23 +152,48 @@ export const useThreadScrolling = (
|
||||
const previouslyStreaming = wasStreamingRef.current
|
||||
const currentlyStreaming = !!streamingContent && streamingContent.thread_id === threadId
|
||||
|
||||
const streamingStarted = !previouslyStreaming && currentlyStreaming
|
||||
const streamingEnded = previouslyStreaming && !currentlyStreaming
|
||||
const hasPaddingToAdjust = originalPaddingRef.current > 0
|
||||
|
||||
if (streamingEnded && hasPaddingToAdjust) {
|
||||
requestAnimationFrame(() => {
|
||||
// Store the current assistant message when streaming starts
|
||||
if (streamingStarted) {
|
||||
const elements = getDOMElements()
|
||||
if (!elements?.lastAssistantMessage || !elements?.lastUserMessage) return
|
||||
lastAssistantMessageRef.current = elements?.lastAssistantMessage || null
|
||||
}
|
||||
|
||||
if (streamingEnded && hasPaddingToAdjust) {
|
||||
let retryCount = 0
|
||||
|
||||
const adjustPaddingWhenReady = () => {
|
||||
const elements = getDOMElements()
|
||||
const currentAssistantMessage = elements?.lastAssistantMessage
|
||||
|
||||
// Check if a new assistant message has appeared (different from the one before streaming)
|
||||
const hasNewAssistantMessage = currentAssistantMessage &&
|
||||
currentAssistantMessage !== lastAssistantMessageRef.current
|
||||
|
||||
if (hasNewAssistantMessage && elements?.lastUserMessage) {
|
||||
const userRect = elements.lastUserMessage.getBoundingClientRect()
|
||||
const assistantRect = elements.lastAssistantMessage.getBoundingClientRect()
|
||||
const assistantRect = currentAssistantMessage.getBoundingClientRect()
|
||||
const actualSpacing = assistantRect.top - userRect.bottom
|
||||
const totalAssistantHeight = elements.lastAssistantMessage.offsetHeight + actualSpacing
|
||||
const totalAssistantHeight = currentAssistantMessage.offsetHeight + actualSpacing
|
||||
const newPadding = Math.max(0, originalPaddingRef.current - totalAssistantHeight)
|
||||
|
||||
setPaddingHeight(newPadding)
|
||||
originalPaddingRef.current = newPadding
|
||||
})
|
||||
lastAssistantMessageRef.current = currentAssistantMessage
|
||||
} else if (retryCount < MAX_DOM_RETRY_ATTEMPTS) {
|
||||
retryCount++
|
||||
setTimeout(adjustPaddingWhenReady, DOM_RETRY_DELAY)
|
||||
} else {
|
||||
// Max retries hit - remove padding as fallback
|
||||
setPaddingHeight(0)
|
||||
originalPaddingRef.current = 0
|
||||
}
|
||||
}
|
||||
|
||||
adjustPaddingWhenReady()
|
||||
}
|
||||
|
||||
wasStreamingRef.current = currentlyStreaming
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user