Spaces:
Runtime error
Runtime error
File size: 2,647 Bytes
b5c0df4 2befd58 b5c0df4 2befd58 b5c0df4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | /**
* ChatThread — renders the scrollable list of chat messages with auto-scroll.
*
* - Renders each message as a <MessageBubble /> with appropriate props
* - Renders an in-flight streaming bubble when streaming is active
* - Auto-scrolls to bottom on new messages or streaming content updates
*
* Requirements: 4.3
*/
import { useEffect, useRef } from "react";
import { MessageBubble } from "./MessageBubble";
import type { Message, QueryResult } from "../types";
export interface ChatThreadProps {
messages: Message[];
results: Record<string, QueryResult>;
streamingContent: string;
streamingIndex: number | null;
isStreaming: boolean;
conversationId: string;
isSaved: (index: number) => boolean;
onSave: (index: number) => void;
onExport: (index: number) => void;
}
/**
* Renders the chat message thread with auto-scroll behaviour.
*
* Each message in the `messages` array is rendered as a <MessageBubble />.
* When `isStreaming` is true and `streamingIndex` is not null, an additional
* assistant bubble is rendered with the current `streamingContent` (flushed
* by the rAF loop in useStream).
*
* Auto-scroll fires whenever messages change or streaming content updates,
* keeping the latest content visible without manual scrolling.
*/
export function ChatThread({
messages,
results,
streamingContent,
streamingIndex,
isStreaming,
conversationId,
isSaved,
onSave,
onExport,
}: ChatThreadProps) {
const bottomRef = useRef<HTMLDivElement>(null);
// Auto-scroll to bottom when messages change or streaming content updates
useEffect(() => {
bottomRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages, streamingContent]);
return (
<div className="flex-1 overflow-y-auto px-4 py-6">
<div className="max-w-3xl mx-auto">
{messages.map((message, index) => (
<MessageBubble
key={`${conversationId}-${index}`}
message={message}
index={index}
conversationId={conversationId}
result={results[String(index)]}
isSaved={isSaved(index)}
onSave={onSave}
onExport={onExport}
/>
))}
{/* In-flight streaming bubble */}
{streamingIndex !== null && isStreaming && (
<MessageBubble
key={`${conversationId}-streaming`}
message={{ role: "assistant", content: streamingContent }}
index={streamingIndex}
conversationId={conversationId}
isStreaming={true}
/>
)}
{/* Scroll anchor */}
<div ref={bottomRef} />
</div>
</div>
);
}
export default ChatThread;
|