'use client'; import { useEffect, useMemo, useRef, useState } from 'react'; import type { ModelInfo } from '@/lib/types'; interface ChatInputProps { onSend: (content: string, options?: { modelId?: string }) => void; onStop?: () => void; isStreaming?: boolean; models: ModelInfo[]; selectedModelId: string; onModelChange: (modelId: string) => void; onRequestEditLastMessage?: () => string | null; } const MAX_HEIGHT = 220; export function ChatInput({ onSend, onStop, isStreaming = false, models, selectedModelId, onModelChange, onRequestEditLastMessage, }: ChatInputProps): React.ReactElement { const [value, setValue] = useState(''); const textareaRef = useRef(null); const selectedModel = useMemo( () => models.find((model) => model.id === selectedModelId) ?? models[0], [models, selectedModelId], ); useEffect(() => { const textarea = textareaRef.current; if (!textarea) return; textarea.style.height = 'auto'; textarea.style.height = `${Math.min(textarea.scrollHeight, MAX_HEIGHT)}px`; }, [value]); useEffect(() => { function handleGlobalFocus(event: KeyboardEvent): void { if ( (event.metaKey || event.ctrlKey) && (event.key === '/' || event.key.toLowerCase() === 'k') ) { const target = event.target as HTMLElement | null; if (target?.closest('input, textarea, [contenteditable="true"]')) return; event.preventDefault(); textareaRef.current?.focus(); } } document.addEventListener('keydown', handleGlobalFocus); return () => document.removeEventListener('keydown', handleGlobalFocus); }, []); function handleSubmit(event: React.FormEvent): void { event.preventDefault(); const trimmed = value.trim(); if (!trimmed || isStreaming) return; onSend(trimmed, { modelId: selectedModel?.id }); setValue(''); textareaRef.current?.focus(); } function handleKeyDown(event: React.KeyboardEvent): void { if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) { event.preventDefault(); handleSubmit(event); return; } if (event.key === 'ArrowUp' && value.length === 0 && onRequestEditLastMessage) { const lastMessage = onRequestEditLastMessage(); if (lastMessage) { event.preventDefault(); setValue(lastMessage); } } } const charCount = value.length; const tokenEstimate = Math.ceil(charCount / 4); return (
⌘/ focus ⌘K focus ⌘↵ send