import React, { useRef, useEffect, useLayoutEffect } from "react"; import { KEYS } from "@excalidraw/common"; import { ArrowRightIcon, stop as StopIcon } from "../../icons"; import { InlineIcon } from "../../InlineIcon"; import { t } from "../../../i18n"; import { TTDWelcomeMessage } from "../TTDWelcomeMessage"; import { ChatMessage } from "./ChatMessage"; import type { TChat, TTTDDialog } from "../types"; import type { FormEventHandler } from "react"; export const ChatInterface = ({ chatId, messages, currentPrompt, onPromptChange, onGenerate, isGenerating, rateLimits, onAbort, onMermaidTabClick, onAiRepairClick, onDeleteMessage, onInsertMessage, onRetry, renderWelcomeScreen, renderWarning, }: { chatId: string; messages: TChat.ChatMessage[]; currentPrompt: string; onPromptChange: (prompt: string) => void; onGenerate: TTTDDialog.OnGenerate; isGenerating: boolean; rateLimits?: { rateLimit: number; rateLimitRemaining: number; } | null; onViewAsMermaid?: () => void; generatedResponse?: string | null; onAbort?: () => void; onMermaidTabClick?: (message: TChat.ChatMessage) => void; onAiRepairClick?: (message: TChat.ChatMessage) => void; onDeleteMessage?: (messageId: string) => void; onInsertMessage?: (message: TChat.ChatMessage) => void; onRetry?: (message: TChat.ChatMessage) => void; renderWelcomeScreen?: TTTDDialog.renderWelcomeScreen; renderWarning?: TTTDDialog.renderWarning; }) => { const messagesEndRef = useRef(null); const textareaRef = useRef(null); useLayoutEffect(() => { messagesEndRef.current?.scrollIntoView(); }, [messages]); useEffect(() => { if (textareaRef.current) { textareaRef.current.focus(); } }, [chatId]); const handleInputChange = (event: React.ChangeEvent) => { const value = event.target.value; onPromptChange(value); }; const handleSubmit = () => { if (isGenerating && onAbort) { onAbort(); return; } const trimmedPrompt = currentPrompt.trim(); if (!trimmedPrompt) { return; } onGenerate({ prompt: trimmedPrompt }); onPromptChange(""); }; const handleKeyDown = (event: React.KeyboardEvent) => { if (event.key === KEYS.ENTER && !event.shiftKey) { event.preventDefault(); if (!isGenerating) { handleSubmit(); } } }; const canSend = currentPrompt.trim().length > 3 && !isGenerating && (rateLimits?.rateLimitRemaining ?? 1) > 0; const canStop = isGenerating && !!onAbort; const onInput: FormEventHandler = (ev) => { const target = ev.target as HTMLTextAreaElement; target.style.height = "auto"; target.style.height = `${Math.min(target.scrollHeight, 120)}px`; }; return (
{messages.length === 0 ? (
{renderWelcomeScreen ? ( renderWelcomeScreen({ rateLimits: rateLimits ?? null }) ) : ( )}
) : ( messages.map((message, index) => ( )) )}