2020-05-19 16:21:01 +10:00
|
|
|
import React, { useState } from "react";
|
|
|
|
|
import { Box, Flex, Text } from "theme-ui";
|
2021-06-06 19:27:01 +10:00
|
|
|
import { useToasts } from "react-toast-notifications";
|
|
|
|
|
|
|
|
|
|
const supportFileTypes = ["image/jpeg", "image/gif", "image/png", "image/webp"];
|
2020-05-19 16:21:01 +10:00
|
|
|
|
|
|
|
|
function ImageDrop({ onDrop, dropText, children }) {
|
2021-06-06 19:27:01 +10:00
|
|
|
const { addToast } = useToasts();
|
|
|
|
|
|
2020-05-19 16:21:01 +10:00
|
|
|
const [dragging, setDragging] = useState(false);
|
|
|
|
|
function handleImageDragEnter(event) {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
event.stopPropagation();
|
|
|
|
|
setDragging(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleImageDragLeave(event) {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
event.stopPropagation();
|
|
|
|
|
setDragging(false);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-11 16:36:27 +11:00
|
|
|
async function handleImageDrop(event) {
|
2020-05-19 16:21:01 +10:00
|
|
|
event.preventDefault();
|
|
|
|
|
event.stopPropagation();
|
2020-05-31 10:53:33 +10:00
|
|
|
let imageFiles = [];
|
2020-12-11 16:36:27 +11:00
|
|
|
|
|
|
|
|
// Check if the dropped image is from a URL
|
|
|
|
|
const html = event.dataTransfer.getData("text/html");
|
|
|
|
|
if (html) {
|
|
|
|
|
try {
|
|
|
|
|
const urlMatch = html.match(/src="?([^"\s]+)"?\s*/);
|
2021-01-19 18:40:22 +11:00
|
|
|
const url = urlMatch[1].replace("&", "&"); // Reverse html encoding of url parameters
|
2020-12-11 16:36:27 +11: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) {
|
|
|
|
|
const file = await response.blob();
|
|
|
|
|
file.name = name;
|
2021-06-06 19:27:01 +10:00
|
|
|
if (supportFileTypes.includes(file.type)) {
|
|
|
|
|
imageFiles.push(file);
|
|
|
|
|
} else {
|
|
|
|
|
addToast(`Unsupported file type for ${file.name}`);
|
|
|
|
|
}
|
2020-12-11 16:36:27 +11:00
|
|
|
}
|
2021-06-06 19:27:01 +10: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 16:36:27 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const files = event.dataTransfer.files;
|
2020-05-31 10:53:33 +10:00
|
|
|
for (let file of files) {
|
2021-06-06 19:27:01 +10:00
|
|
|
if (supportFileTypes.includes(file.type)) {
|
2020-05-31 10:53:33 +10:00
|
|
|
imageFiles.push(file);
|
2021-06-06 19:27:01 +10:00
|
|
|
} else {
|
|
|
|
|
addToast(`Unsupported file type for ${file.name}`);
|
2020-05-31 10:53:33 +10:00
|
|
|
}
|
2020-05-19 16:21:01 +10:00
|
|
|
}
|
2020-05-31 10:53:33 +10:00
|
|
|
onDrop(imageFiles);
|
2020-05-19 16:21:01 +10:00
|
|
|
setDragging(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
2021-06-06 21:04:46 +10:00
|
|
|
<Box onDragEnter={handleImageDragEnter} sx={{ height: "100%" }}>
|
2020-05-19 16:21:01 +10:00
|
|
|
{children}
|
|
|
|
|
{dragging && (
|
|
|
|
|
<Flex
|
|
|
|
|
bg="overlay"
|
|
|
|
|
sx={{
|
|
|
|
|
position: "absolute",
|
|
|
|
|
top: 0,
|
|
|
|
|
right: 0,
|
|
|
|
|
left: 0,
|
|
|
|
|
bottom: 0,
|
|
|
|
|
justifyContent: "center",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
cursor: "copy",
|
|
|
|
|
}}
|
|
|
|
|
onDragLeave={handleImageDragLeave}
|
|
|
|
|
onDragOver={(e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
e.dataTransfer.dropEffect = "copy";
|
|
|
|
|
}}
|
|
|
|
|
onDrop={handleImageDrop}
|
|
|
|
|
>
|
|
|
|
|
<Text sx={{ pointerEvents: "none" }}>
|
2021-06-06 19:27:01 +10:00
|
|
|
{dropText || "Drop image to import"}
|
2020-05-19 16:21:01 +10:00
|
|
|
</Text>
|
|
|
|
|
</Flex>
|
|
|
|
|
)}
|
|
|
|
|
</Box>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default ImageDrop;
|