MCPcopy Index your code
hub / github.com/enowdev/enowX-Coder / ChatPanel

Function ChatPanel

src/components/chat/ChatPanel.tsx:23–143  ·  view source on GitHub ↗
({ onChipClick })

Source from the content-addressed store, hash-verified

21];
22
23export const ChatPanel: React.FC<ChatPanelProps> = ({ onChipClick }) => {
24 const { messages, isStreaming, streamingText } = useChatStore();
25 const { agentRuns } = useAgentStore();
26 const bottomRef = useRef<HTMLDivElement>(null);
27 const scrollRef = useRef<HTMLDivElement>(null);
28 const userScrolledUp = useRef(false);
29 const isAutoScrolling = useRef(false);
30
31 const scrollToBottom = useCallback(() => {
32 const el = scrollRef.current;
33 if (!el) return;
34 isAutoScrolling.current = true;
35 requestAnimationFrame(() => {
36 if (!el) return;
37 el.scrollTop = el.scrollHeight;
38 // Reset flag after browser has applied the scroll
39 requestAnimationFrame(() => { isAutoScrolling.current = false; });
40 });
41 }, []);
42
43 // Track user scroll intent — ignore scroll events caused by our own scrollToBottom
44 const handleScroll = useCallback(() => {
45 if (isAutoScrolling.current) return;
46 const el = scrollRef.current;
47 if (!el) return;
48 const distFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
49 userScrolledUp.current = distFromBottom > 150;
50 }, []);
51
52 // Auto-scroll only when genuinely new messages are added
53 const prevMsgCount = useRef(messages.length);
54
55 useEffect(() => {
56 const newMsg = messages.length > prevMsgCount.current;
57 prevMsgCount.current = messages.length;
58
59 if (newMsg && !userScrolledUp.current) {
60 scrollToBottom();
61 }
62 }, [messages.length, scrollToBottom]);
63
64 // During active streaming only, follow new tokens (throttled)
65 const streamScrollTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
66
67 useEffect(() => {
68 if (!isStreaming || userScrolledUp.current) return;
69 if (streamScrollTimer.current) return; // throttle
70 streamScrollTimer.current = setTimeout(() => {
71 streamScrollTimer.current = null;
72 if (!userScrolledUp.current) scrollToBottom();
73 }, 80);
74 }, [streamingText, isStreaming, scrollToBottom]);
75
76 const isEmpty = messages.length === 0 && agentRuns.length === 0 && !isStreaming;
77
78 if (isEmpty) {
79 return (
80 <div className="flex-1 flex flex-col items-center pt-[12vh] text-center p-8">

Callers

nothing calls this directly

Calls 1

cnFunction · 0.90

Tested by

no test coverage detected