import { useRef, useState, useCallback, ReactNode, forwardRef, useImperativeHandle } from "react"; import { Button } from "./Button"; import uploadAreaStyles from "~/styles/components/upload-area.css?url"; interface UploadAreaProps { onFilesSelected: (files: FileList) => void; className?: string; accept?: string; multiple?: boolean; icon?: string; buttonText?: string; mainText?: string; tipText?: ReactNode; disabled?: boolean; shouldPreventFileSelect?: boolean; } export interface UploadAreaRef { resetFileInput: () => void; } export function links() { return [{ rel: "stylesheet", href: uploadAreaStyles }]; } export const UploadArea = forwardRef(({ onFilesSelected, className = "", accept = "", multiple = false, icon = "ri-upload-cloud-2-line", buttonText = "选择文件", mainText = "点击或拖拽文件到此区域上传", tipText = "", disabled = false, shouldPreventFileSelect = false }, ref) => { const fileInputRef = useRef(null); const [isDragOver, setIsDragOver] = useState(false); const resetFileInput = useCallback(() => { if (fileInputRef.current) { fileInputRef.current.value = ''; } }, []); // 暴露resetFileInput方法给父组件 useImperativeHandle(ref, () => ({ resetFileInput })); const handleClick = useCallback(() => { if (disabled) return; if (shouldPreventFileSelect) { // 如果应该阻止文件选择,则触发表单提交 const form = fileInputRef.current?.closest('form'); if (form) { form.requestSubmit(); } } else if (fileInputRef.current) { fileInputRef.current.click(); } }, [disabled, shouldPreventFileSelect]); const handleFileChange = useCallback(() => { if (fileInputRef.current?.files?.length) { onFilesSelected(fileInputRef.current.files); } }, [onFilesSelected]); const handleDragOver = useCallback((e: React.DragEvent) => { e.preventDefault(); if (!disabled && !shouldPreventFileSelect) { setIsDragOver(true); } }, [disabled, shouldPreventFileSelect]); const handleDragLeave = useCallback(() => { setIsDragOver(false); }, []); const handleDrop = useCallback((e: React.DragEvent) => { e.preventDefault(); setIsDragOver(false); if (disabled) return; if (shouldPreventFileSelect) { // 如果应该阻止文件选择,则触发表单提交 const form = e.currentTarget.closest('form'); if (form) { form.requestSubmit(); } } else if (e.dataTransfer.files.length > 0) { onFilesSelected(e.dataTransfer.files); } }, [disabled, shouldPreventFileSelect, onFilesSelected]); const handleKeyDown = useCallback((e: React.KeyboardEvent) => { if ((e.key === 'Enter' || e.key === ' ') && !disabled && !shouldPreventFileSelect) { e.preventDefault(); handleClick(); } }, [handleClick, disabled, shouldPreventFileSelect]); return (
{mainText}
{tipText &&

{tipText}

}
); }); UploadArea.displayName = "UploadArea";