ファイルアップローダーFileUploaderExperimental

ドラッグ&ドロップ対応のファイルアップロードです。

プレビュー

状態とバリエーション

標準

ドロップゾーン全体でクリック選択とドラッグ&ドロップを受け付けます。

ファイルを選択 またはドラッグ&ドロップ

最大 5MB

画像のみ

画像だけを受け付けるアップローダーとして使えます。

ファイルを選択 またはドラッグ&ドロップ

最大 10MB

アップロード中

アップロード処理は利用側で管理し、内部リストには fileProgress を渡すか showFileList=false で独自リストを描画します。

ファイルを選択 またはドラッグ&ドロップ

最大 5MB

アップロード中68%

成功

アップロード後は成功状態を明示し、追加された件数を伝えます。

ファイルを選択 またはドラッグ&ドロップ

最大 5MB

失敗

失敗時は警告表示で、何が失敗したかを明確にします。

ファイルを選択 またはドラッグ&ドロップ

最大 5MB

無効化

アップロードできない状態では操作を無効化し、ツールチップで理由を補足します。

ファイルを選択 またはドラッグ&ドロップ

最大 5MB

プロパティ

表は横にスクロールできます
プロパティ初期値説明
valueFile[]-選択済みファイルを親で管理する controlled 値です。
onValueChange(files: File[]) => void-選択、ドロップ、削除後の累積ファイル配列で呼ばれます。
maxFilesnumber1選択できる最大ファイル数です。
maxSizenumber5242880 (5MB)1ファイルあたりの最大サイズをバイト数で指定します。
acceptRecord<string, string[]>-受け付けるファイル形式です。種類ごとに拡張子を指定します。
disabledbooleanfalseアップロード操作を無効化します。
showFileListbooleantrue内部ファイル一覧を表示するかを指定します。外部リストや独自進捗を描画する場合は false にします。
fileProgressRecord<string, FileUploaderFileProgress> | (file, index) => FileUploaderFileProgress-利用側が管理するファイルごとの進捗、状態、エラーを内部リストに表示します。
labels{ browse?: ReactNode; drop?: ReactNode; maxSize?: (sizeMb: number) => ReactNode; removeFile?: string; fileTooLarge?: string; fileTypeNotAccepted?: string; progress?: (fileName: string) => string; status?: Partial<Record<FileUploaderFileStatus, ReactNode>> }-ドロップゾーン、削除ボタン、検証、進捗表示の文言を差し替えます。

使い方

import { FileUploader, FormControl, FormGroup, FormLabel, Progress } from "@gunjo/ui";
import { useState } from "react";

export function ImageUploader() {
  const [files, setFiles] = useState<File[]>([]);
  const progressByName: Record<string, number> = {};

  return (
    <FormGroup className="w-full max-w-md">
      <FormLabel>画像</FormLabel>
      <FormControl>
        <FileUploader
          value={files}
          onValueChange={setFiles}
          showFileList={false}
          maxFiles={5}
          maxSize={10 * 1024 * 1024}
          accept={{
            "image/*": [".png", ".jpg", ".jpeg", ".webp"],
          }}
        />
      </FormControl>
      {files.length > 0 && (
        <div className="grid gap-2">
          {files.map((file) => (
            <div key={file.name} className="grid gap-1 rounded-md border p-2 text-xs">
              <div className="flex justify-between gap-3">
                <span className="truncate font-medium">{file.name}</span>
                <span className="text-muted-foreground">
                  {progressByName[file.name] ?? 0}%
                </span>
              </div>
              <Progress value={progressByName[file.name] ?? 0} className="h-2" />
            </div>
          ))}
        </div>
      )}
    </FormGroup>
  );
}