fix: resolve scroll flickering on message send and improve thinking state animation (#1333)

This commit is contained in:
josh 2025-11-29 13:02:24 +00:00 committed by GitHub
parent d0b6f37aee
commit a3802348fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 225 additions and 174 deletions

View file

@ -1,13 +1,11 @@
import type { UseChatHelpers } from "@ai-sdk/react";
import equal from "fast-deep-equal";
import { AnimatePresence } from "framer-motion";
import { ArrowDownIcon } from "lucide-react";
import { memo, useEffect } from "react";
import { memo } from "react";
import { useMessages } from "@/hooks/use-messages";
import type { Vote } from "@/lib/db/schema";
import type { ChatMessage } from "@/lib/types";
import { useDataStream } from "./data-stream-provider";
import { Conversation, ConversationContent } from "./elements/conversation";
import { Greeting } from "./greeting";
import { PreviewMessage, ThinkingMessage } from "./message";
@ -31,7 +29,7 @@ function PureMessages({
setMessages,
regenerate,
isReadonly,
selectedModelId,
selectedModelId: _selectedModelId,
}: MessagesProps) {
const {
containerRef: messagesContainerRef,
@ -45,62 +43,41 @@ function PureMessages({
useDataStream();
useEffect(() => {
if (status === "submitted") {
requestAnimationFrame(() => {
const container = messagesContainerRef.current;
if (container) {
container.scrollTo({
top: container.scrollHeight,
behavior: "smooth",
});
}
});
}
}, [status, messagesContainerRef]);
return (
<div
className="overscroll-behavior-contain -webkit-overflow-scrolling-touch flex-1 touch-pan-y overflow-y-scroll"
className="relative flex-1 touch-pan-y overflow-y-auto"
ref={messagesContainerRef}
style={{ overflowAnchor: "none" }}
>
<Conversation className="mx-auto flex min-w-0 max-w-4xl flex-col gap-4 md:gap-6">
<ConversationContent className="flex flex-col gap-4 px-2 py-4 md:gap-6 md:px-4">
{messages.length === 0 && <Greeting />}
<div className="mx-auto flex min-w-0 max-w-4xl flex-col gap-4 px-2 py-4 md:gap-6 md:px-4">
{messages.length === 0 && <Greeting />}
{messages.map((message, index) => (
<PreviewMessage
chatId={chatId}
isLoading={
status === "streaming" && messages.length - 1 === index
}
isReadonly={isReadonly}
key={message.id}
message={message}
regenerate={regenerate}
requiresScrollPadding={
hasSentMessage && index === messages.length - 1
}
setMessages={setMessages}
vote={
votes
? votes.find((vote) => vote.messageId === message.id)
: undefined
}
/>
))}
<AnimatePresence mode="wait">
{status === "submitted" && <ThinkingMessage key="thinking" />}
</AnimatePresence>
<div
className="min-h-[24px] min-w-[24px] shrink-0"
ref={messagesEndRef}
{messages.map((message, index) => (
<PreviewMessage
chatId={chatId}
isLoading={status === "streaming" && messages.length - 1 === index}
isReadonly={isReadonly}
key={message.id}
message={message}
regenerate={regenerate}
requiresScrollPadding={
hasSentMessage && index === messages.length - 1
}
setMessages={setMessages}
vote={
votes
? votes.find((vote) => vote.messageId === message.id)
: undefined
}
/>
</ConversationContent>
</Conversation>
))}
{status === "submitted" && <ThinkingMessage />}
<div
className="min-h-[24px] min-w-[24px] shrink-0"
ref={messagesEndRef}
/>
</div>
{!isAtBottom && (
<button