"use client"; import React, { useCallback, useRef, useEffect, useState } from "react"; import { Button } from "@/components/ui/button"; import { Textarea } from "@/components/ui/textarea"; import { Loader2, Send, RotateCcw, Image as ImageIcon, X, History, } from "lucide-react"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import Image from "next/image"; import { useDiagram } from "@/contexts/diagram-context"; import { HistoryDialog } from "@/components/history-dialog"; interface ChatInputProps { input: string; status: "submitted" | "streaming" | "ready" | "error"; onSubmit: (e: React.FormEvent) => void; onChange: (e: React.ChangeEvent) => void; setMessages: (messages: any[]) => void; files?: FileList; onFileChange?: (files: FileList | undefined) => void; showHistory?: boolean; setShowHistory?: (show: boolean) => void; } export function ChatInput({ input, status, onSubmit, onChange, setMessages, files, onFileChange, showHistory = false, setShowHistory = () => {}, }: ChatInputProps) { const { loadDiagram: onDisplayChart, diagramHistory } = useDiagram(); const textareaRef = useRef(null); const fileInputRef = useRef(null); const [isDragging, setIsDragging] = useState(false); const [showClearDialog, setShowClearDialog] = useState(false); // Auto-resize textarea based on content const adjustTextareaHeight = useCallback(() => { const textarea = textareaRef.current; if (textarea) { textarea.style.height = "auto"; textarea.style.height = `${Math.min(textarea.scrollHeight, 200)}px`; } }, []); useEffect(() => { adjustTextareaHeight(); }, [input, adjustTextareaHeight]); // Handle keyboard shortcuts const handleKeyDown = (e: React.KeyboardEvent) => { if ((e.metaKey || e.ctrlKey) && e.key === "Enter") { e.preventDefault(); const form = e.currentTarget.closest("form"); if (form && input.trim() && status !== "streaming") { form.requestSubmit(); } } }; // Handle file changes const handleFileChange = (e: React.ChangeEvent) => { if (onFileChange) { onFileChange(e.target.files || undefined); } }; // Clear file selection const clearFiles = () => { if (fileInputRef.current) { fileInputRef.current.value = ""; } if (onFileChange) { onFileChange(undefined); } }; // Trigger file input click const triggerFileInput = () => { fileInputRef.current?.click(); }; // Handle drag events const handleDragOver = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); setIsDragging(true); }; const handleDragLeave = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); setIsDragging(false); }; const handleDrop = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); setIsDragging(false); if (status === "streaming") return; const droppedFiles = e.dataTransfer.files; // Only process image files if (droppedFiles.length > 0) { const imageFiles = Array.from(droppedFiles).filter((file) => file.type.startsWith("image/") ); if (imageFiles.length > 0 && onFileChange) { // Create a new FileList-like object with only image files const dt = new DataTransfer(); imageFiles.forEach((file) => dt.items.add(file)); onFileChange(dt.files); } } }; // Handle clearing conversation and diagram const handleClear = () => { setMessages([]); onDisplayChart(` `); setShowClearDialog(false); }; return (
{/* File preview area */} {files && files.length > 0 && (
{Array.from(files).map((file, index) => (
{file.type.startsWith("image/") ? ( {file.name} ) : (
{file.name}
)}
))}
)}