پرش به مطلب اصلی

File Upload

کامپوننت FileUpload برای انتخاب و مدیریت فایل استفاده می‌شود؛ مثل آپلود عکس پروفایل یا اسناد. انتخاب فایل با کلیک یا کشیدن و رها کردن (drag & drop) انجام می‌شود و اعتبارسنجی نوع، حجم و تعداد فایل به‌صورت داخلی پشتیبانی می‌شود.

Import​

import { FileUpload } from "fara-ui";

اگر هنوز FaraUI را نصب و راه‌اندازی نکرده‌ای، ابتدا صفحه‌ی شروع به کار را ببین.

Basic Usage​

import { useState } from "react";
import { FileUpload } from "fara-ui";

export function DocumentUpload() {
const [files, setFiles] = useState([]);

return (
<FileUpload
files={files}
accept=".pdf,.docx"
maxSize={5 * 1024 * 1024}
label="فایل مدرک را انتخاب کنید"
hint="PDF یا DOCX، حداکثر ۵ مگابایت"
onFilesSelected={(selected) => setFiles((current) => [...current, ...selected])}
onRemoveFile={(id) => setFiles((current) => current.filter((file) => file.id !== id))}
/>
);
}

کامپوننت state داخلی برای لیست فایل‌ها ندارد؛ files و onFilesSelected/onRemoveFile را خودت کنترل کن.

onFilesSelected آبجکت‌های UploadedFile را برمی‌گرداند. فایل اصلی در file قرار دارد و url یک object URL برای preview است:

function handleFilesSelected(selected) {
for (const uploadedFile of selected) {
console.log(uploadedFile.name);
console.log(uploadedFile.file);
console.log(uploadedFile.url);
}
}

Playground​

فایل را بکشید و رها کنید یا کلیک کنیدحداکثر ۲ مگابایت
<FileUpload
label="فایل را بکشید و رها کنید یا کلیک کنید"
hint="حداکثر ۲ مگابایت"
onFilesSelected={...}
/>

Validation​

سه محدودیت داخلی وجود دارد که فایل‌های رد‌شده را با پیام فارسی زیر dropzone نمایش می‌دهند:

  • accept — مثل "image/*" یا ".pdf,.docx"؛ فایل با نوع غیرمجاز رد می‌شود.
  • maxSize — حداکثر حجم هر فایل به بایت.
  • maxFiles — حداکثر تعداد فایل (در حالت multiple).

برای قوانین سفارشی، validate را پاس بده؛ اگر رشته‌ای برگرداند، فایل با آن پیام رد می‌شود. لیست رد‌شده‌ها را می‌توانی با onRejected دریافت کنی.

<FileUpload
accept="image/*"
maxSize={2 * 1024 * 1024}
maxFiles={3}
validate={(file) => (file.name.includes(" ") ? "نام فایل نباید فاصله داشته باشد" : null)}
onRejected={(rejected) => console.log(rejected)}
onFilesSelected={(selected) => console.log(selected)}
/>

Upload Status​

هر آیتم در آرایه‌ی files یک status دارد که حالت آن را در کارت فایل نشان می‌دهد:

  • "idle" — هنوز آپلود نشده
  • "uploading" — در حال آپلود؛ اگر progress (عدد ۰ تا ۱۰۰) بدهی، درصد روی کارت نمایش داده می‌شود
  • "success" / "error" — آیکون وضعیت؛ در حالت خطا، errorMessage زیر نام فایل نمایش داده می‌شود

این مقادیر را پس از پیشرفت آپلود واقعی در state خودت به‌روز کن.

نمونه‌ی ساده‌ی شبیه‌سازی آپلود:

async function uploadSelectedFile(selectedFile, setFiles) {
setFiles((current) =>
current.map((file) =>
file.id === selectedFile.id ? { ...file, status: "uploading", progress: 0 } : file,
),
);

try {
await new Promise((resolve) => setTimeout(resolve, 1000));

setFiles((current) =>
current.map((file) =>
file.id === selectedFile.id ? { ...file, status: "success", progress: 100 } : file,
),
);
} catch {
setFiles((current) =>
current.map((file) =>
file.id === selectedFile.id
? { ...file, status: "error", errorMessage: "آپلود ناموفق بود" }
: file,
),
);
}
}

Preview Mode​

با variant="preview" کل dropzone به یک پیش‌نمایش تصویر تبدیل می‌شود؛ مناسب آپلود تکی عکس مثل عکس پروفایل. تصویر انتخاب‌شده داخل خود dropzone نمایش داده می‌شود و دکمه‌ی حذف روی آن قرار می‌گیرد.

Image Preview in a Modal​

در حالت پیش‌فرض، کلیک روی کارت یک عکس، آن را در یک مودال بزرگ‌نمایی می‌کند (قابل غیرفعال‌سازی با enablePreviewModal={false}). کلیک روی کارت فایل غیرعکسی، فایل را در تب جدید باز می‌کند.

Data Attributes and Customize CSS​

FileUpload hookهای پایدار مختلفی برای dropzone، خطاها، لیست فایل و وضعیت آپلود دارد:

Attributeکاربرد
data-fara-file-uploadریشه‌ی کامپوننت
data-fara-file-upload-dropzoneناحیه‌ی انتخاب و drag & drop
data-fara-file-upload-inputinput داخلی فایل
data-fara-file-upload-labelمتن اصلی dropzone
data-fara-file-upload-hintمتن راهنما
data-fara-file-upload-rejectionsفهرست فایل‌های ردشده
data-fara-file-upload-itemکارت هر فایل
data-fara-file-upload-item-progressنوار پیشرفت
data-fara-file-upload-item-removeدکمه‌ی حذف فایل

روی dropzone stateهایی مثل data-variant, data-drag-active, data-error و data-disabled قرار می‌گیرد و روی آیتم فایل data-status قرار دارد:

[data-fara-file-upload-dropzone][data-drag-active] {
border-color: #7c3aed;
background: #f5f3ff;
}

[data-fara-file-upload-item][data-status="uploading"] {
opacity: 0.75;
}

[data-fara-file-upload-item][data-status="error"] {
border-color: #dc2626;
}

برای layout یک نمونه‌ی خاص از className استفاده کن:

<FileUpload className="avatar-upload" onFilesSelected={handleFilesSelected} />
.avatar-upload {
max-width: 420px;
}

Accessibility​

  • dropzone با role="button" و tabIndex قابل دسترسی با صفحه‌کلید است.
  • وقتی کامپوننت فعال باشد، کلیدهای Enter و Space پنجره‌ی انتخاب فایل را باز می‌کنند.
  • در حالت disabled، dropzone با aria-disabled علامت‌گذاری می‌شود.
  • برای توضیح محدودیت‌ها، از hint استفاده کن؛ پیام فایل‌های ردشده نیز داخل کامپوننت نمایش داده می‌شود.

SSR Note​

FileUpload با SSR و Next.js سازگار است؛ APIهای File، FileList و URL.createObjectURL فقط هنگام تعامل کاربر در مرورگر استفاده می‌شوند. نیازی به غیرفعال‌کردن SSR نیست.

Props​

PropTypeDefaultDescription
onFilesSelected(files: UploadedFile[]) => void-فایل‌های پذیرفته‌شده (الزامی)
filesUploadedFile[]-لیست فایل‌های فعلی (برای نمایش کارت‌ها)
onRemoveFile(id: string) => void-با پاس‌دادن آن، دکمه‌ی حذف نمایش داده می‌شود
acceptstring-محدودیت نوع فایل (مثل "image/*")
multiplebooleanfalseاجازه‌ی انتخاب چند فایل
maxSizenumber-حداکثر حجم هر فایل به بایت
maxFilesnumber-حداکثر تعداد فایل‌ها
validate(file: File) => string | null-قانون اعتبارسنجی سفارشی
onRejected(rejected: RejectedFile[]) => void-فایل‌های رد‌شده و دلیل آن‌ها
enablePreviewModalbooleantrueپیش‌نمایش عکس‌ها در مودال
variant"default" | "preview""default"حالت نمایش
labelstring«فایل را بکشید و ...»متن داخل dropzone
hintstring-متن کمکی زیر label
disabledbooleanfalseغیرفعال کردن dropzone
classNamestring-کلاس CSS اضافی برای سفارشی‌سازی
type FileStatus = "idle" | "uploading" | "success" | "error";

interface UploadedFile {
id: string;
name: string;
url: string;
size?: number;
file?: File;
status?: FileStatus;
progress?: number; // 0-100، در حالت uploading نمایش داده می‌شود
errorMessage?: string;
}

interface RejectedFile {
name: string;
reason: "type" | "size" | "count";
message: string;
}