63 lines
2.1 KiB
TypeScript
63 lines
2.1 KiB
TypeScript
import React from "react";
|
|
|
|
type FileDropZoneProps = {
|
|
disabled?: boolean;
|
|
multiple?: boolean;
|
|
selectedFiles: FileList | null;
|
|
label: string;
|
|
hint: string;
|
|
onFiles: (files: FileList | null) => void;
|
|
};
|
|
|
|
export default function FileDropZone({ disabled = false, multiple = false, selectedFiles, label, hint, onFiles }: FileDropZoneProps) {
|
|
const [isDragOver, setIsDragOver] = React.useState(false);
|
|
const fileInputRef = React.useRef<HTMLInputElement | null>(null);
|
|
const fileCount = selectedFiles?.length ?? 0;
|
|
const fileNames = selectedFiles ? Array.from(selectedFiles).map((file) => file.name) : [];
|
|
const selectedLabel =
|
|
fileCount > 1 ? `${fileCount} souborů vybráno` : selectedFiles && fileCount === 1 ? selectedFiles[0]?.name : label;
|
|
const selectedHint =
|
|
fileCount > 1 ? `Vybráno: ${fileNames.slice(0, 3).join(", ")}${fileCount > 3 ? ", ..." : ""}` : hint;
|
|
|
|
return (
|
|
<>
|
|
<input
|
|
ref={fileInputRef}
|
|
type="file"
|
|
multiple={multiple}
|
|
onChange={(e) => onFiles(e.target.files)}
|
|
aria-label={label}
|
|
className="sr-only"
|
|
disabled={disabled}
|
|
/>
|
|
<div
|
|
onClick={() => !disabled && fileInputRef.current?.click()}
|
|
onDragOver={(e) => {
|
|
if (disabled) return;
|
|
e.preventDefault();
|
|
setIsDragOver(true);
|
|
}}
|
|
onDragLeave={(e) => {
|
|
if (disabled) return;
|
|
e.preventDefault();
|
|
setIsDragOver(false);
|
|
}}
|
|
onDrop={(e) => {
|
|
if (disabled) return;
|
|
e.preventDefault();
|
|
setIsDragOver(false);
|
|
onFiles(e.dataTransfer.files);
|
|
}}
|
|
className={`flex-1 min-w-[240px] cursor-pointer rounded border-2 border-dashed p-4 ${
|
|
isDragOver ? "border-primary bg-green-50" : "border-default-300 bg-green-50"
|
|
} ${disabled ? "opacity-60 cursor-not-allowed" : ""}`}
|
|
>
|
|
<div className="flex flex-col items-start gap-1 text-sm">
|
|
<span className="font-semibold">{selectedLabel}</span>
|
|
<span className="text-foreground-500">{selectedHint}</span>
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|