// 输入表单组件 - MD3 风格 import { useCallback, useEffect, useRef, useState } from 'react'; import type { OutputMode, Quality, ReferenceImage } from '../types/api'; import { loadSettings } from '../lib/settings'; import { FormToolbar } from './input-form/form-toolbar'; import { ReferenceImageList } from './input-form/reference-image-list'; import { useReferenceImages } from './input-form/use-reference-images'; import { useI18n } from '../i18n'; interface InputFormProps { onSubmit: (data: { concept: string; quality: Quality; outputMode: OutputMode; referenceImages?: ReferenceImage[]; }) => void; loading: boolean; } export function InputForm({ onSubmit, loading }: InputFormProps) { const { t } = useI18n(); const [concept, setConcept] = useState(''); const [error, setError] = useState(null); const [quality, setQuality] = useState(loadSettings().video.quality); const [outputMode, setOutputMode] = useState('video'); const textareaRef = useRef(null); const { images, imageError, isDragging, fileInputRef, addImages, removeImage, handleDrop, handleDragOver, handleDragEnter, handleDragLeave, } = useReferenceImages(); const handleSubmit = useCallback(() => { if (concept.trim().length < 5) { setError(t('form.error.minLength')); textareaRef.current?.focus(); return; } setError(null); onSubmit({ concept: concept.trim(), quality, outputMode, referenceImages: images.length > 0 ? images : undefined, }); }, [concept, quality, outputMode, images, onSubmit, t]); useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.ctrlKey && e.key === 'Enter' && !loading) { e.preventDefault(); handleSubmit(); } }; document.addEventListener('keydown', handleKeyDown); return () => document.removeEventListener('keydown', handleKeyDown); }, [loading, handleSubmit]); useEffect(() => { if (concept.length > 0 && concept.length < 5) { setError(t('form.error.minLengthShort')); } else { setError(null); } }, [concept, t]); const handleFormSubmit = (e: React.FormEvent) => { e.preventDefault(); handleSubmit(); }; return (