Files
cinny/src/app/hooks/useFileDrop.ts
T

74 lines
2.2 KiB
TypeScript
Raw Normal View History

2023-06-12 21:15:23 +10:00
import { useCallback, DragEventHandler, RefObject, useState, useEffect, useRef } from 'react';
import { getDataTransferFiles } from '../utils/dom';
export const useFileDropHandler = (onDrop: (file: File[]) => void): DragEventHandler =>
useCallback(
(evt) => {
const files = getDataTransferFiles(evt.dataTransfer);
if (files) onDrop(files);
},
[onDrop],
2023-06-12 21:15:23 +10:00
);
export const useFileDropZone = (
zoneRef: RefObject<HTMLElement>,
onDrop: (file: File[]) => void,
2023-06-12 21:15:23 +10:00
): boolean => {
const dragCounterRef = useRef(0);
2023-06-12 21:15:23 +10:00
const [active, setActive] = useState(false);
useEffect(() => {
const target = zoneRef.current;
const handleDrop = (evt: DragEvent) => {
evt.preventDefault();
dragCounterRef.current = 0;
2023-06-12 21:15:23 +10:00
setActive(false);
if (!evt.dataTransfer) return;
const files = getDataTransferFiles(evt.dataTransfer);
if (files) onDrop(files);
};
target?.addEventListener('drop', handleDrop);
return () => {
target?.removeEventListener('drop', handleDrop);
};
}, [zoneRef, onDrop]);
useEffect(() => {
const target = zoneRef.current;
const handleDragEnter = (evt: DragEvent) => {
if (evt.dataTransfer?.types.includes('Files')) {
dragCounterRef.current += 1;
2023-06-12 21:15:23 +10:00
setActive(true);
}
};
const handleDragLeave = (evt: DragEvent) => {
if (evt.relatedTarget === null) {
// Mouse left the browser window — reset unconditionally
dragCounterRef.current = 0;
setActive(false);
return;
}
dragCounterRef.current -= 1;
if (dragCounterRef.current <= 0) {
dragCounterRef.current = 0;
setActive(false);
}
2023-06-12 21:15:23 +10:00
};
const handleDragOver = (evt: DragEvent) => {
evt.preventDefault();
};
target?.addEventListener('dragenter', handleDragEnter);
target?.addEventListener('dragleave', handleDragLeave);
target?.addEventListener('dragover', handleDragOver);
return () => {
target?.removeEventListener('dragenter', handleDragEnter);
target?.removeEventListener('dragleave', handleDragLeave);
target?.removeEventListener('dragover', handleDragOver);
};
}, [zoneRef]);
return active;
};