fix(files): make dropped-file handling explicit

This commit is contained in:
2026-07-20 16:57:29 +02:00
parent 78b4afdec4
commit b5cfba666c
6 changed files with 345 additions and 6 deletions
+32 -6
View File
@@ -1,5 +1,8 @@
import { i18nMessage } from "../i18n/LanguageContext";import { useRef, useState, type CSSProperties, type ReactNode } from "react";
import { i18nMessage } from "../i18n/LanguageContext";import { useRef, useState, type CSSProperties, type DragEvent as ReactDragEvent, type ReactNode } from "react";
import { UploadCloud } from "lucide-react";
import { resolveDroppedFiles } from "./resolveDroppedFiles";
type RejectedDropReason = "disabled" | "empty" | "unreadable";
export type FileDropZoneProps = {
accept?: string;
@@ -14,6 +17,7 @@ export type FileDropZoneProps = {
note?: ReactNode;
className?: string;
inputLabel?: string;
onRejectedDrop?: (reason: RejectedDropReason) => void;
onFiles: (files: File[]) => void | Promise<void>;
};
@@ -30,6 +34,7 @@ export default function FileDropZone({
note,
className = "",
inputLabel = "i18n:govoplan-core.drop_files_here_or_click_to_select_files.7eda8608",
onRejectedDrop,
onFiles
}: FileDropZoneProps) {
const inputRef = useRef<HTMLInputElement | null>(null);
@@ -52,6 +57,13 @@ export default function FileDropZone({
}
}
function prepareFileDrag(event: ReactDragEvent<HTMLDivElement>) {
event.preventDefault();
event.stopPropagation();
event.dataTransfer.dropEffect = interactionDisabled ? "none" : "copy";
if (!interactionDisabled) setDragActive(true);
}
return (
<>
<div
@@ -70,15 +82,29 @@ export default function FileDropZone({
inputRef.current?.click();
}
}}
onDragOver={(event) => {
onDragEnter={prepareFileDrag}
onDragOver={prepareFileDrag}
onDragLeave={(event) => {
event.preventDefault();
if (!interactionDisabled) setDragActive(true);
event.stopPropagation();
if (event.relatedTarget instanceof Node && event.currentTarget.contains(event.relatedTarget)) return;
setDragActive(false);
}}
onDragLeave={() => setDragActive(false)}
onDrop={(event) => {
event.preventDefault();
event.stopPropagation();
setDragActive(false);
if (!interactionDisabled) void handleFiles(event.dataTransfer.files);
if (interactionDisabled) {
onRejectedDrop?.("disabled");
return;
}
void resolveDroppedFiles(event.dataTransfer).then((files) => {
if (files.length === 0) {
onRejectedDrop?.("empty");
return;
}
void handleFiles(files);
}).catch(() => onRejectedDrop?.("unreadable"));
}}>
{showProgress ?
@@ -110,4 +136,4 @@ export default function FileDropZone({
</>);
}
}