FileUpload
Chọn tệp bằng một vùng thả: kéo tệp vào, hoặc nhấp hay nhấn Enter trên nó để mở hộp chọn tệp. Tệp quá lớn hoặc sai loại bị từ chối kèm lý do. Các tệp đã chọn hiện bên dưới với tiến độ tải lên, dấu đã tải lên hoặc lỗi với nút thử lại, và nút gỡ mang tên từng tệp.
Xem trước
import { FileUpload } from "@/components/ui/file-upload"
<FileUpload labels={{ prompt: "Thả tệp vào đây hoặc {browse}", browse: "Chọn tệp", list: "Tệp", remove: "Gỡ {name}", retry: "Thử lại {name}", uploading: "Đang tải lên {name}", done: "Đã tải lên", tooLarge: "Lớn hơn {size}", wrongType: "Loại tệp không được chấp nhận", tooMany: "Bạn có thể thêm tối đa {max} tệp", rejected: "{name}, {error}" }} hint="PNG, JPG hoặc PDF, tối đa 25 MB" defaultValue={sampleUploads} onRetry={retryUpload} />Cách dùng
Khi nào dùng
- Cho người dùng thêm tệp vào form, ticket hoặc dự án, bằng cách kéo vào hoặc chọn.
- Hiện tiến độ tải lên từng tệp, và cho thử lại hoặc gỡ lần tải lên thất bại.
Khi nào không dùng
- Đính kèm tệp vào tin nhắn chat. Dùng Composer với AttachmentPreview.
- Hiện tệp đã gửi, dưới dạng liên kết. Dùng AttachmentPreview với href.
- Chọn một ảnh đại diện cần được xem lớn. Hiện ảnh với một Button đổi.
Biến thể
size
Khoảng đệm, icon và chữ của vùng thả: sm cho bảng bên, lg cho trang chủ yếu là tải lên.
import { FileUpload } from "@/components/ui/file-upload"
<FileUpload size="sm" labels={{ prompt: "Thả tệp vào đây hoặc {browse}", browse: "Chọn tệp", list: "Tệp", remove: "Gỡ {name}", retry: "Thử lại {name}", uploading: "Đang tải lên {name}", done: "Đã tải lên", tooLarge: "Lớn hơn {size}", wrongType: "Loại tệp không được chấp nhận", tooMany: "Bạn có thể thêm tối đa {max} tệp", rejected: "{name}, {error}" }} hint="PNG, JPG hoặc PDF, tối đa 25 MB" defaultValue={sampleUploads} onRetry={retryUpload} />
<FileUpload labels={{ prompt: "Thả tệp vào đây hoặc {browse}", browse: "Chọn tệp", list: "Tệp", remove: "Gỡ {name}", retry: "Thử lại {name}", uploading: "Đang tải lên {name}", done: "Đã tải lên", tooLarge: "Lớn hơn {size}", wrongType: "Loại tệp không được chấp nhận", tooMany: "Bạn có thể thêm tối đa {max} tệp", rejected: "{name}, {error}" }} hint="PNG, JPG hoặc PDF, tối đa 25 MB" defaultValue={sampleUploads} onRetry={retryUpload} />
<FileUpload size="lg" labels={{ prompt: "Thả tệp vào đây hoặc {browse}", browse: "Chọn tệp", list: "Tệp", remove: "Gỡ {name}", retry: "Thử lại {name}", uploading: "Đang tải lên {name}", done: "Đã tải lên", tooLarge: "Lớn hơn {size}", wrongType: "Loại tệp không được chấp nhận", tooMany: "Bạn có thể thêm tối đa {max} tệp", rejected: "{name}, {error}" }} hint="PNG, JPG hoặc PDF, tối đa 25 MB" defaultValue={sampleUploads} onRetry={retryUpload} />Ví dụ
Ảnh
accept và maxSize từ chối các tệp khác kèm lý do, và hint nói quy tắc từ trước.
import { FileUpload } from "@/components/ui/file-upload"
<FileUpload multiple accept="image/*" maxSize={5000000} hint="PNG, JPG or GIF, up to 5 MB" onFilesAdd={uploadFiles} />Tiến độ tải lên
Mỗi tệp hiện tiến độ, dấu đã tải lên, hoặc lỗi với nút thử lại.
import { FileUpload } from "@/components/ui/file-upload"
<FileUpload multiple defaultValue={sampleUploads} onRetry={retryUpload} hint="Up to 25 MB each" />Có nhãn
Đặt tên trường bằng Label và inputId. maxFiles 1 giữ một tệp.
import { FileUpload } from "@/components/ui/file-upload"
import { Label } from "@/components/ui/label"
<div className="flex w-full flex-col gap-xs">
<Label htmlFor="resume">Resume</Label>
<FileUpload inputId="resume" accept=".pdf,.doc,.docx" maxFiles={1} hint="PDF or Word, up to 10 MB" maxSize={10000000} />
</div>Không hợp lệ
invalid chuyển viền sang danger, và error nói lý do dưới vùng thả.
import { FileUpload } from "@/components/ui/file-upload"
<FileUpload invalid error="Add at least one receipt" hint="PDF or image" accept="application/pdf,image/*" />Vô hiệu
import { FileUpload } from "@/components/ui/file-upload"
<FileUpload disabled hint="Uploads open after the review" />Trong bảng bên
size sm giữ vùng thả thấp.
import { FileUpload } from "@/components/ui/file-upload"
<FileUpload size="sm" multiple defaultValue={sampleUploadsDone} hint="Up to 25 MB each" />Nên và không nên
Nên
- Nói loại tệp được nhận và giới hạn kích thước trong hint, để không ai phải thử sai mới biết.
- Bắt đầu tải lên trong onFilesAdd và hiện tiến độ từng tệp trong value.
- Giữ tệp lỗi trong danh sách kèm lý do, và truyền onRetry khi thử lại có thể thành công.
Không nên
- Đừng giấu input hay thay nó bằng div; input thật cho sẵn hộp chọn tệp, bàn phím và form.
- Đừng tự gỡ tệp lỗi; để người dùng gỡ.
- Đừng dùng nó cho một ảnh đại diện hay ảnh bìa cần được xem lớn; hiện ảnh và một nút đổi.
Props
| Tên | Kiểu | Giá trị | Mặc định | Mô tả |
|---|---|---|---|---|
| value | FileUploadItem[] | - | - | Các tệp, có kiểm soát. Mỗi mục có id, name, type, size, src, status (uploading, done hoặc error), progress và error. |
| defaultValue | FileUploadItem[] | - | - | Các tệp ban đầu, không kiểm soát. |
| onValueChange | (items: FileUploadItem[]) => void | - | - | Được gọi với cả danh sách sau khi tệp được thêm hoặc gỡ. |
| onFilesAdd | (items: FileUploadItem[]) => void | - | - | Được gọi với các tệp mới được chấp nhận, để bắt đầu tải lên. |
| onRemove | (item: FileUploadItem) => void | - | - | Được gọi khi nút gỡ được nhấn, trước khi danh sách đổi, để hủy lần tải lên. |
| onRetry | (item: FileUploadItem) => void | - | - | Hiện nút thử lại trên các lần tải lên thất bại và được gọi khi nút được nhấn. |
| accept | string | - | - | Loại tệp, như trên input, như image/*,.pdf. Tệp thả vào thuộc loại khác bị từ chối. |
| maxSize | number | - | - | Tệp lớn nhất tính bằng byte. Tệp lớn hơn được liệt kê kèm lỗi. |
| maxFiles | number | - | - | Số tệp tối đa trong danh sách. Tệp vượt quá không được thêm, và một thông báo nói điều đó. |
| multiple | boolean | - | false | Cho phép nhiều hơn một tệp. Không có nó, tệp mới thế chỗ tệp cũ. |
| disabled | boolean | - | false | Tắt vùng thả và các nút. |
| invalid | boolean | - | false | Đánh dấu trường không hợp lệ, với viền danger. Dùng kèm error. |
| error | React.ReactNode | - | - | Lý do trường không hợp lệ, hiện dưới vùng thả và được đọc cùng input. |
| hint | React.ReactNode | - | - | Một dòng dưới lời nhắc, như loại tệp và giới hạn kích thước. |
| size | enum | sm | md | lg | md | Khoảng đệm, icon và chữ của vùng thả: sm cho bảng bên, lg cho trang chủ yếu là tải lên. |
| name | string | - | - | Tên của input, để gửi form. |
| inputId | string | - | - | id của input, cho Label với htmlFor. |
| formatSize | (bytes: number) => string | - | - | Định dạng kích thước tệp và maxSize. Mặc định theo đơn vị thập phân, như 482 KB. |
| labels | FileUploadLabels | - | - | Các chữ: prompt ({browse} đánh dấu chỗ nút), browse, list, remove, retry, uploading ({name}), done, tooLarge ({name}, {size}), wrongType ({name}, {accept}), tooMany ({max}), rejected ({name}, {error}). Tiếng Việt gợi ý: Thả tệp vào đây hoặc {browse}, Chọn tệp, Tệp, Gỡ {name}, Thử lại {name}, Đang tải lên {name}, Đã tải lên, Lớn hơn {size}, Loại tệp không được chấp nhận, Bạn có thể thêm tối đa {max} tệp, {name}, {error}. |
Cấu tạo
| Phần | Mô tả |
|---|---|
| root | Cột: vùng thả, lỗi, rồi danh sách tệp. |
| dropzone | Vùng viền nét đứt nhận tệp thả vào và mở hộp chọn tệp, nền sunken, viền control. Hover thêm lớp phủ hover. |
| input | input type=file thật, ẩn đi về mặt hiển thị trong vùng thả. |
| icon | Icon tải lên 16px trong một vòng tròn raised. Vòng tròn cố định 32, 40 hoặc 48px, là hình minh họa, không theo cỡ control. |
| prompt | Lời nhắc và nút chọn tệp. |
| browse | Chọn tệp, vẽ như Button secondary. Là một phần của label, không phải điều khiển thứ hai. |
| hint | Loại tệp và giới hạn, bằng chữ secondary. |
| error | Lý do trường không hợp lệ, hoặc thông báo maxFiles, bằng màu danger. |
| list | Danh sách tệp đã chọn. |
| item | Một ô tệp bố cục như AttachmentPreview: ảnh thu nhỏ, tên trên kích thước, tiến độ hoặc lỗi, rồi dấu và các nút. |
| thumbnail | Ảnh hoặc icon loại tệp. |
| image | Ảnh thu nhỏ của tệp ảnh. |
| body | Tên ở trên kích thước, thanh tiến độ hoặc lỗi. |
| name | Tên tệp trên một dòng, cắt bằng dấu ba chấm. |
| meta | Kích thước tệp. |
| itemError | Lý do tải lên thất bại hoặc lý do tệp bị từ chối. |
| done | Dấu tích success của tệp đã tải lên. |
| retry | Button icon ghost để thử tải lên lại. Không hiện trên tệp bị từ chối. |
| remove | Button icon ghost để gỡ tệp. |
Khả năng truy cập
Role: generic
| Phím | Hành động |
|---|---|
| Tab | Chuyển tới input tệp trong vùng thả, rồi tới nút thử lại và nút gỡ của từng tệp. |
| Enter / Space | Trên vùng thả, mở hộp chọn tệp. Trên nút thử lại hoặc gỡ, thử lại hoặc gỡ tệp đó. |
- Vùng thả chứa một label bao quanh input type=file thật, nên hộp chọn tệp, accept và multiple là của trình duyệt, và trình đọc màn hình đặt tên input bằng lời nhắc và chữ chọn tệp. Hint nằm ngoài label nên chỉ được đọc một lần, như phần mô tả. Enter và Space đều mở hộp chọn tệp.
- Input được mô tả bằng hint, lỗi và danh sách tệp.
- invalid đặt aria-invalid trên input; error hiện dưới vùng thả bằng chữ, không chỉ bằng viền đỏ. Thông báo maxFiles được đọc như một alert. Mỗi tệp bị từ chối bởi accept hoặc maxSize được đọc trong một status ẩn, EN `brief.pdf, Larger than 5 MB`.
- Nút gỡ của mỗi tệp mang tên tệp, EN `Remove brief.pdf`; nút thử lại EN `Retry brief.pdf`. Cả hai được mô tả bằng lỗi của tệp.
- Tệp đang tải lên có thanh tiến độ tên EN `Uploading brief.pdf`. Tệp đã tải lên có dấu tích với chữ ẩn Uploaded.
- Sau khi gỡ một tệp, focus trở về input, để không bị mất.
Cài đặt
npx werewolf-ui add file-uploadChạy npx werewolf-ui init một lần trong app trước khi thêm component. Init cài token, thêm CSS import và luật cho agent. Add cài component này cùng các dependency và giữ nguyên theme của bạn. Xem Cài đặt để biết yêu cầu và cách cài qua registry.