@rpldy/upload-drop-zone
Version:
drop zone (container) component to initiate file and folder content uploads
96 lines • 3.89 kB
JavaScript
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
import React, { forwardRef, useCallback, useImperativeHandle, useRef, useLayoutEffect } from "react";
import { getFilesFromDragEvent } from "html-dir-content";
import { isEmpty, isFunction } from "@rpldy/shared";
import { useUploadyContext, markAsUploadOptionsComponent } from "@rpldy/shared-ui";
const getShouldHandleDrag = (e, shouldHandle) => isEmpty(shouldHandle) || shouldHandle === true || isFunction(shouldHandle) && shouldHandle(e);
const isOnTarget = (e, containerElm, allowContains) => {
const target = e.type === "dragleave" ? e.relatedTarget : e.target;
return target === containerElm || allowContains && containerElm && target && containerElm.contains(target);
};
const UploadDropZone = /*#__PURE__*/forwardRef(({
className,
id,
children,
onDragOverClassName,
dropHandler,
htmlDirContentParams,
shouldRemoveDragOver,
shouldHandleDrag,
enableOnContains = true,
noContainCheckForDrag = false,
extraProps,
...uploadOptions
}, ref) => {
const {
upload
} = useUploadyContext();
const containerRef = useRef(null);
const dragLeaveTrackerRef = useRef(false);
useImperativeHandle(ref, () => containerRef.current, []);
const uploadOptionsRef = useRef();
useLayoutEffect(() => {
uploadOptionsRef.current = uploadOptions;
}, [uploadOptions]);
const handleEnd = useCallback(() => {
dragLeaveTrackerRef.current = false;
if (containerRef.current && onDragOverClassName) {
containerRef.current.classList.remove(onDragOverClassName);
}
}, [onDragOverClassName, containerRef]);
const dropFileHandler = useCallback(e => {
const getFiles = () => getFilesFromDragEvent(e, htmlDirContentParams || {});
return dropHandler ? Promise.resolve(dropHandler(e, getFiles)) : getFiles();
}, [dropHandler, htmlDirContentParams]);
const handleDropUpload = useCallback(e => {
dropFileHandler(e).then(files => {
upload(files, uploadOptionsRef.current);
});
}, [upload, dropFileHandler, uploadOptionsRef]);
const onDragEnter = useCallback(e => {
const isHandling = getShouldHandleDrag(e, shouldHandleDrag) && isOnTarget(e, containerRef.current, enableOnContains) || noContainCheckForDrag;
if (isHandling) {
dragLeaveTrackerRef.current = true;
if (containerRef.current && onDragOverClassName) {
containerRef.current.classList.add(onDragOverClassName);
}
}
}, [onDragOverClassName, containerRef, shouldHandleDrag, enableOnContains, noContainCheckForDrag]);
const onDragOver = useCallback(e => {
if (dragLeaveTrackerRef.current) {
e.preventDefault();
}
}, []);
const onDrop = useCallback(e => {
if (dragLeaveTrackerRef.current) {
e.preventDefault();
e.persist();
handleEnd();
handleDropUpload(e);
}
}, [handleEnd, handleDropUpload]);
const onDragLeave = useCallback(e => {
if (dragLeaveTrackerRef.current && !isOnTarget(e, containerRef.current, enableOnContains) || shouldRemoveDragOver?.(e)) {
handleEnd();
}
}, [handleEnd, containerRef, shouldRemoveDragOver, enableOnContains]);
const onDragEnd = useCallback(e => {
if (dragLeaveTrackerRef.current) {
e.preventDefault();
e.stopPropagation();
handleEnd();
}
}, [handleEnd]);
return /*#__PURE__*/React.createElement("div", _extends({
id: id,
className: className,
ref: containerRef,
onDragOver: onDragOver,
onDragEnter: onDragEnter,
onDrop: onDrop,
onDragLeave: onDragLeave,
onDragEnd: onDragEnd
}, extraProps), children);
});
markAsUploadOptionsComponent(UploadDropZone);
export default UploadDropZone;