2021-06-07 07:08:14 -04:00
|
|
|
import { useState } from "react";
|
2021-06-06 05:27:01 -04:00
|
|
|
import { useToasts } from "react-toast-notifications";
|
|
|
|
|
2021-06-07 07:08:14 -04:00
|
|
|
import Vector2 from "../helpers/Vector2";
|
2020-05-19 02:21:01 -04:00
|
|
|
|
2021-07-09 03:19:00 -04:00
|
|
|
export type ImageDropEvent = {
|
|
|
|
files: File[];
|
|
|
|
dropPosition: Vector2;
|
|
|
|
};
|
|
|
|
|
2021-06-07 07:08:14 -04:00
|
|
|
function useImageDrop(
|
2021-07-09 03:19:00 -04:00
|
|
|
onImageDrop: (event: ImageDropEvent) => void,
|
2021-06-07 07:08:14 -04:00
|
|
|
supportFileTypes = ["image/jpeg", "image/gif", "image/png", "image/webp"]
|
|
|
|
) {
|
2021-06-06 05:27:01 -04:00
|
|
|
const { addToast } = useToasts();
|
|
|
|
|
2020-05-19 02:21:01 -04:00
|
|
|
const [dragging, setDragging] = useState(false);
|
2021-07-09 03:19:00 -04:00
|
|
|
function onDragEnter(event: React.DragEvent<HTMLDivElement>) {
|
2020-05-19 02:21:01 -04:00
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
setDragging(true);
|
|
|
|
}
|
|
|
|
|
2021-07-09 03:19:00 -04:00
|
|
|
function onDragLeave(event: React.DragEvent<HTMLDivElement>) {
|
2020-05-19 02:21:01 -04:00
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
setDragging(false);
|
|
|
|
}
|
|
|
|
|
2021-07-09 03:19:00 -04:00
|
|
|
function onDragOver(event: React.DragEvent<HTMLDivElement>) {
|
2021-06-07 07:08:14 -04:00
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
2021-07-09 03:19:00 -04:00
|
|
|
if (event.dataTransfer) {
|
|
|
|
event.dataTransfer.dropEffect = "copy";
|
|
|
|
}
|
2021-06-07 07:08:14 -04:00
|
|
|
}
|
|
|
|
|
2021-07-09 03:19:00 -04:00
|
|
|
async function onDrop(event: React.DragEvent<HTMLDivElement>) {
|
2020-05-19 02:21:01 -04:00
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
2020-05-30 20:53:33 -04:00
|
|
|
let imageFiles = [];
|
2020-12-11 00:36:27 -05:00
|
|
|
|
|
|
|
// Check if the dropped image is from a URL
|
2021-07-09 03:19:00 -04:00
|
|
|
const html = event.dataTransfer?.getData("text/html");
|
2020-12-11 00:36:27 -05:00
|
|
|
if (html) {
|
|
|
|
try {
|
|
|
|
const urlMatch = html.match(/src="?([^"\s]+)"?\s*/);
|
2021-07-09 03:19:00 -04:00
|
|
|
if (!urlMatch) {
|
|
|
|
throw new Error("Unable to find image source");
|
|
|
|
}
|
2021-01-19 02:40:22 -05:00
|
|
|
const url = urlMatch[1].replace("&", "&"); // Reverse html encoding of url parameters
|
2020-12-11 00:36:27 -05:00
|
|
|
let name = "";
|
|
|
|
const altMatch = html.match(/alt="?([^"]+)"?\s*/);
|
|
|
|
if (altMatch && altMatch.length > 1) {
|
|
|
|
name = altMatch[1];
|
|
|
|
}
|
|
|
|
const response = await fetch(url);
|
|
|
|
if (response.ok) {
|
2021-07-09 03:19:00 -04:00
|
|
|
const file = new File([await response.blob()], name);
|
2021-06-06 05:27:01 -04:00
|
|
|
if (supportFileTypes.includes(file.type)) {
|
|
|
|
imageFiles.push(file);
|
|
|
|
} else {
|
|
|
|
addToast(`Unsupported file type for ${file.name}`);
|
|
|
|
}
|
2020-12-11 00:36:27 -05:00
|
|
|
}
|
2021-06-06 05:27:01 -04:00
|
|
|
} catch (e) {
|
|
|
|
if (e.message === "Failed to fetch") {
|
|
|
|
addToast("Unable to import image: failed to fetch");
|
|
|
|
} else {
|
|
|
|
addToast("Unable to import image");
|
|
|
|
}
|
|
|
|
}
|
2020-12-11 00:36:27 -05:00
|
|
|
}
|
|
|
|
|
2021-07-09 03:19:00 -04:00
|
|
|
const files = event.dataTransfer?.files || [];
|
2020-05-30 20:53:33 -04:00
|
|
|
for (let file of files) {
|
2021-06-06 05:27:01 -04:00
|
|
|
if (supportFileTypes.includes(file.type)) {
|
2020-05-30 20:53:33 -04:00
|
|
|
imageFiles.push(file);
|
2021-06-06 05:27:01 -04:00
|
|
|
} else {
|
|
|
|
addToast(`Unsupported file type for ${file.name}`);
|
2020-05-30 20:53:33 -04:00
|
|
|
}
|
2020-05-19 02:21:01 -04:00
|
|
|
}
|
2021-06-07 07:08:14 -04:00
|
|
|
const dropPosition = new Vector2(event.clientX, event.clientY);
|
2021-07-09 03:19:00 -04:00
|
|
|
onImageDrop({ files: imageFiles, dropPosition });
|
2020-05-19 02:21:01 -04:00
|
|
|
setDragging(false);
|
|
|
|
}
|
|
|
|
|
2021-06-07 07:08:14 -04:00
|
|
|
const containerListeners = { onDragEnter };
|
|
|
|
const overlayListeners = { onDragLeave, onDragOver, onDrop };
|
|
|
|
|
|
|
|
return { dragging, containerListeners, overlayListeners };
|
2020-05-19 02:21:01 -04:00
|
|
|
}
|
|
|
|
|
2021-06-07 07:08:14 -04:00
|
|
|
export default useImageDrop;
|