tfrere's picture
tfrere HF Staff
feat(editor): embed studio with data files and agent-aware editing
8fc8501
Raw
History Blame Contribute Delete
2.03 kB
import { useRef, useState, type DragEvent } from "react";
import { Upload } from "lucide-react";
import { ACCEPTED_DATA_EXTS, MAX_DATA_FILE_SIZE } from "../utils/data-files";
interface UploadZoneProps {
onFiles: (files: FileList | File[]) => void | Promise<void>;
disabled?: boolean;
compact?: boolean;
}
const ACCEPT_ATTR = ACCEPTED_DATA_EXTS.map((e) => `.${e}`).join(",");
const MAX_MB = (MAX_DATA_FILE_SIZE / (1024 * 1024)).toFixed(0);
export function UploadZone({ onFiles, disabled, compact }: UploadZoneProps) {
const inputRef = useRef<HTMLInputElement>(null);
const [isDragging, setIsDragging] = useState(false);
const handleDrop = (e: DragEvent<HTMLDivElement>) => {
e.preventDefault();
setIsDragging(false);
if (disabled) return;
if (e.dataTransfer.files?.length) void onFiles(e.dataTransfer.files);
};
const handleDragOver = (e: DragEvent<HTMLDivElement>) => {
e.preventDefault();
if (!disabled) setIsDragging(true);
};
const handleDragLeave = () => setIsDragging(false);
return (
<div
className={`es-upload-zone ${isDragging ? "es-upload-zone--active" : ""} ${compact ? "es-upload-zone--compact" : ""}`}
onDrop={handleDrop}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onClick={() => !disabled && inputRef.current?.click()}
role="button"
tabIndex={disabled ? -1 : 0}
aria-label="Upload data file"
>
<input
ref={inputRef}
type="file"
accept={ACCEPT_ATTR}
multiple
onChange={(e) => {
if (e.target.files?.length) void onFiles(e.target.files);
e.target.value = "";
}}
style={{ display: "none" }}
/>
<Upload size={compact ? 14 : 18} />
{compact ? (
<span>Add data file</span>
) : (
<div className="es-upload-zone__text">
<strong>Drop a data file</strong>
<span>CSV, TSV, JSON, NDJSON, TXT - up to {MAX_MB} MB</span>
</div>
)}
</div>
);
}