feat(chat): 优化聊天面板交互体验 — 推理折叠/智能滚动/工具中文名/代码块按钮

This commit is contained in:
2026-06-02 08:43:26 +08:00
parent 628b592577
commit 9c9afbd108
10 changed files with 408 additions and 8 deletions

View File

@@ -0,0 +1,55 @@
import type { UIMessage } from "ai";
import { useCallback, useEffect, useState } from "react";
const NEAR_BOTTOM_THRESHOLD = 80;
interface UseChatScrollOptions {
messages: UIMessage[];
scrollRef: React.RefObject<HTMLDivElement | null>;
status: string;
}
export function useChatScroll({ messages, scrollRef, status }: UseChatScrollOptions) {
const [isAtBottom, setIsAtBottom] = useState(true);
const isStreaming = status === "streaming";
const checkNearBottom = useCallback(() => {
const el = scrollRef.current;
if (!el) return true;
return el.scrollHeight - el.scrollTop - el.clientHeight < NEAR_BOTTOM_THRESHOLD;
}, [scrollRef]);
useEffect(() => {
const el = scrollRef.current;
if (!el) return;
setIsAtBottom(checkNearBottom());
const handleScroll = () => {
setIsAtBottom(checkNearBottom());
};
el.addEventListener("scroll", handleScroll, { passive: true });
return () => el.removeEventListener("scroll", handleScroll);
}, [scrollRef, checkNearBottom]);
useEffect(() => {
const el = scrollRef.current;
if (!el || !isAtBottom) return;
el.scrollTo({
behavior: isStreaming ? "instant" : "smooth",
top: el.scrollHeight,
});
}, [messages, isStreaming, isAtBottom, scrollRef]);
const scrollToBottom = useCallback(() => {
const el = scrollRef.current;
if (!el) return;
el.scrollTo({ behavior: "smooth", top: el.scrollHeight });
setIsAtBottom(true);
}, [scrollRef]);
return { isAtBottom, scrollToBottom };
}