UNPKG

@hitachivantara/uikit-react-core

Version:

Core React components for the NEXT Design System.

195 lines (194 loc) 7.01 kB
import { jsxs, Fragment, jsx } from "react/jsx-runtime"; import { useContext, useState, useRef } from "react"; import { useDefaultProps } from "@hitachivantara/uikit-react-utils"; import { HvLabelContainer } from "../../FormElement/LabelContainer.js"; import { useLabels } from "../../hooks/useLabels.js"; import { useUniqueId } from "../../hooks/useUniqueId.js"; import { HvIcon } from "../../icons.js"; import { uniqueId } from "../../utils/helpers.js"; import { setId } from "../../utils/setId.js"; import { convertUnits } from "../utils.js"; import { useClasses } from "./DropZone.styles.js"; import { staticClasses } from "./DropZone.styles.js"; import { HvFormElementContext } from "../../FormElement/context.js"; const DEFAULT_LABELS = { /** Extensions of the accepted file types */ acceptedFiles: "", /** Dropzone area label. @deprecated use `label` prop instead */ dropzone: "Label", /** Size file warning label. */ sizeWarning: "Max. file size:", /** Size file warning label. */ drag: "Drop files here or", /** Size file warning label. */ selectFiles: "click to upload", /** Theming sheet used to style components */ dropFiles: "Drop files here", /** Message to display when file size is greater than allowed */ fileSizeError: "The file exceeds the maximum upload size", /** Message to display when file type is greater than allowed */ fileTypeError: "File type not allowed for upload", removeFileButtonLabel: "Remove File" }; function validateAccept(file, acceptAttr) { if (!file || !acceptAttr) return true; const acceptEntries = acceptAttr.split(","); const fileName = file.name || ""; const mimeType = (file.type || "").toLowerCase(); const baseMimeType = mimeType.replace(/\/.*$/, ""); return acceptEntries.some((type) => { const validType = type.trim().toLowerCase(); if (validType.charAt(0) === ".") { return fileName.toLowerCase().endsWith(validType); } if (validType.endsWith("/*")) { return baseMimeType === validType.replace(/\/.*$/, ""); } return mimeType === validType; }); } const HvDropZone = (props) => { const { id: idProp, classes: classesProp, label, labels: labelsProp, accept, maxFileSize, inputProps, hideLabels, multiple = true, onFilesAdded } = useDefaultProps("HvDropZone", props); const id = useUniqueId(idProp); const labels = useLabels(DEFAULT_LABELS, labelsProp); const { classes, cx } = useClasses(classesProp); const { disabled } = useContext(HvFormElementContext); const [dragState, setDragState] = useState(false); const inputRef = useRef(null); const handleDragLeave = () => { setDragState(false); }; const handleDragEnter = (event) => { if (disabled) return; event.stopPropagation(); event.preventDefault(); setDragState(true); }; const onChangeHandler = (filesList) => { const filesToProcess = Object.values(filesList); const newFiles = filesToProcess.map((file) => { const newFile = new File([file], file.name, { type: file.type, lastModified: file.lastModified }); newFile.id = uniqueId("uploaded-file-data-"); const isSizeAllowed = file.size <= maxFileSize; const isFileAccepted = !accept || accept.includes(file.type?.split("/")[1]) || // TODO: remove in v6 validateAccept(file, accept); if (!isFileAccepted) { newFile.errorMessage = labels?.fileTypeError; newFile.status = "fail"; } else if (!isSizeAllowed) { newFile.errorMessage = labels?.fileSizeError; newFile.status = "fail"; } return newFile; }); onFilesAdded?.(newFiles); }; const description = /* @__PURE__ */ jsxs(Fragment, { children: [ Number.isInteger(maxFileSize) && `${labels.sizeWarning} ${convertUnits(maxFileSize)}`, labels.acceptedFiles || accept && ` (${accept?.replaceAll(",", ", ")})` ] }); return /* @__PURE__ */ jsxs(Fragment, { children: [ !hideLabels && /* @__PURE__ */ jsx( HvLabelContainer, { id, label: label ?? labels.dropzone, description, inputId: setId(id, "input-file"), labelId: setId(id, "input-file-label"), descriptionId: setId(id, "description"), classes: { root: classes.dropZoneLabelsGroup, label: classes.dropZoneLabel } } ), /* @__PURE__ */ jsxs( "div", { id: setId(id, "input-file-container"), className: cx(classes.dropZoneContainer, { [classes.dragAction]: dragState, [classes.dropZoneContainerDisabled]: disabled }), children: [ /* @__PURE__ */ jsx( "input", { id: setId(id, "input-file"), className: classes.inputArea, type: "file", multiple, disabled, title: !disabled ? `${labels?.drag} ${labels?.selectFiles}` : "", onClick: () => { if (inputRef.current) { inputRef.current.value = ""; } }, onChange: () => { if (!disabled && inputRef.current?.files) { onChangeHandler(inputRef.current.files); } }, onDragEnter: handleDragEnter, onDragOver: handleDragEnter, onDragLeave: handleDragLeave, onDropCapture: handleDragLeave, onDrop: (event) => { if (disabled) return; const { files } = event.dataTransfer; if (multiple === true || files.length === 1) { event.stopPropagation(); event.preventDefault(); onChangeHandler(files); } }, ref: inputRef, accept, ...inputProps } ), /* @__PURE__ */ jsx("div", { className: classes?.dropArea, children: dragState ? /* @__PURE__ */ jsx("div", { className: classes.dropZoneAreaLabels, children: /* @__PURE__ */ jsx("div", { className: classes.dragText, children: labels?.dropFiles }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx( HvIcon, { name: "Doc", size: "md", className: classes.dropZoneAreaIcon } ), /* @__PURE__ */ jsx("div", { className: classes.dropZoneAreaLabels, children: /* @__PURE__ */ jsxs("div", { className: classes.dragText, children: [ labels?.drag, /* @__PURE__ */ jsx( "span", { className: classes.selectFilesText, children: ` ${labels?.selectFiles}` } ) ] }) }) ] }) }) ] } ) ] }); }; export { HvDropZone, staticClasses as dropZoneClasses };