Files
OpenCut/apps/web/src/hooks/use-file-upload.ts
T

102 lines
2.2 KiB
TypeScript
Raw Normal View History

2026-01-31 00:20:04 +01:00
import { useState, useRef } from "react";
import { hasDragData } from "@/lib/drag-data";
interface UseFileUploadOptions {
accept?: string;
multiple?: boolean;
onFilesSelected?: (files: File[]) => void;
2026-01-31 00:20:04 +01:00
}
function containsFiles(dataTransfer: DataTransfer): boolean {
return !hasDragData({ dataTransfer }) && dataTransfer.types.includes("Files");
}
export function useFileUpload({
accept,
multiple,
onFilesSelected,
}: UseFileUploadOptions = {}) {
const [isDragOver, setIsDragOver] = useState(false);
const dragCounterRef = useRef(0);
const inputRef = useRef<HTMLInputElement>(null);
function openFilePicker() {
if (!inputRef.current) return;
inputRef.current.accept = accept || "*";
inputRef.current.multiple = multiple || false;
inputRef.current.click();
}
function handleFileChange(event: React.ChangeEvent<HTMLInputElement>) {
const files = Array.from(event.target.files ?? []);
if (files.length > 0 && onFilesSelected) {
2026-01-31 00:20:04 +01:00
onFilesSelected(files);
}
if (event.target) {
event.target.value = "";
}
}
function handleDragEnter(e: React.DragEvent) {
e.preventDefault();
if (!containsFiles(e.dataTransfer)) return;
dragCounterRef.current += 1;
setIsDragOver(true);
}
function handleDragOver(e: React.DragEvent) {
e.preventDefault();
if (!containsFiles(e.dataTransfer)) return;
}
function handleDragLeave(e: React.DragEvent) {
e.preventDefault();
if (!containsFiles(e.dataTransfer)) return;
dragCounterRef.current -= 1;
if (dragCounterRef.current === 0) {
setIsDragOver(false);
}
}
function handleDrop(e: React.DragEvent) {
e.preventDefault();
setIsDragOver(false);
dragCounterRef.current = 0;
if (onFilesSelected && containsFiles(e.dataTransfer)) {
const files = Array.from(e.dataTransfer.files);
2026-01-31 00:20:04 +01:00
const shouldUseMultiple = multiple ?? false;
if (shouldUseMultiple) {
onFilesSelected(files);
} else if (files.length > 0) {
onFilesSelected([files[0]]);
2026-01-31 00:20:04 +01:00
}
}
}
return {
isDragOver,
openFilePicker,
fileInputProps: {
ref: inputRef,
type: "file",
style: { display: "none" },
onChange: handleFileChange,
},
dragProps: {
onDragEnter: handleDragEnter,
onDragOver: handleDragOver,
onDragLeave: handleDragLeave,
onDrop: handleDrop,
},
};
}