UNPKG

@carbon/react

Version:

React components for the Carbon Design System

158 lines (156 loc) 5.96 kB
/** * Copyright IBM Corp. 2016, 2026 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ const require_runtime = require("../../_virtual/_rolldown/runtime.js"); const require_usePrefix = require("../../internal/usePrefix.js"); const require_keys = require("../../internal/keyboard/keys.js"); const require_match = require("../../internal/keyboard/match.js"); const require_useId = require("../../internal/useId.js"); const require_noopFn = require("../../internal/noopFn.js"); const require_deprecate = require("../../prop-types/deprecate.js"); const require_events = require("../../tools/events.js"); let classnames = require("classnames"); classnames = require_runtime.__toESM(classnames); let react = require("react"); react = require_runtime.__toESM(react); let prop_types = require("prop-types"); prop_types = require_runtime.__toESM(prop_types); let react_jsx_runtime = require("react/jsx-runtime"); //#region src/components/FileUploader/FileUploaderDropContainer.tsx /** * Copyright IBM Corp. 2016, 2026 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ function FileUploaderDropContainer({ accept = [], className, id, disabled, labelText = "Add file", maxFileSize, multiple = false, name, onAddFiles = require_noopFn.noopFn, onClick, pattern = ".[0-9a-z]+$", innerRef, ...rest }) { const prefix = require_usePrefix.usePrefix(); const inputRef = (0, react.useRef)(null); const generatedId = require_useId.useId(); const { current: uid } = (0, react.useRef)(id || generatedId); const [isActive, setActive] = (0, react.useState)(false); const dropareaClasses = (0, classnames.default)(`${prefix}--file__drop-container`, `${prefix}--file-browse-btn`, { [`${prefix}--file__drop-container--drag-over`]: isActive, [`${prefix}--file-browse-btn--disabled`]: disabled }, className); /** * Filters the array of added files based on file type and size restrictions */ function validateFiles(transferredFiles) { const acceptedTypes = new Set(accept); return transferredFiles.reduce((acc, curr) => { const { name, type: mimeType = "" } = curr; const fileExtensionRegExp = new RegExp(pattern, "i"); const [fileExtension] = name.match(fileExtensionRegExp) ?? []; if (maxFileSize && curr.size > maxFileSize) { curr.invalidFileType = true; return acc.concat([curr]); } if (!accept.length) return acc.concat([curr]); if (fileExtension === void 0) return acc; if (acceptedTypes.has(mimeType) || acceptedTypes.has(fileExtension.toLowerCase())) return acc.concat([curr]); curr.invalidFileType = true; return acc.concat([curr]); }, []); } const handleFiles = (event, files) => { if (!files.length) return onAddFiles(event, { addedFiles: [] }); return onAddFiles(event, { addedFiles: validateFiles(multiple ? files : [files[0]]) }); }; const handleChange = (event) => { return handleFiles(event, [...event.target.files ?? []]); }; const handleDrop = (event) => { const items = [...event.dataTransfer.items ?? []]; return handleFiles(event, items.length ? items.reduce((acc, item) => { if (item.kind !== "file") return acc; if (item.webkitGetAsEntry()?.isDirectory) return acc; const file = item.getAsFile(); if (file) acc.push(file); return acc; }, []) : [...event.dataTransfer.files]); }; const handleClick = () => { if (!disabled) inputRef.current?.click(); }; return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { className: `${prefix}--file`, onDragOver: (evt) => { evt.stopPropagation(); evt.preventDefault(); if (disabled) return; setActive(true); evt.dataTransfer.dropEffect = "copy"; }, onDragLeave: (evt) => { evt.stopPropagation(); evt.preventDefault(); if (disabled) return; setActive(false); evt.dataTransfer.dropEffect = "move"; }, onDrop: (evt) => { evt.stopPropagation(); evt.preventDefault(); if (disabled) return; setActive(false); handleDrop(evt); }, children: [ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", { type: "button", className: dropareaClasses, ref: innerRef, onKeyDown: (evt) => { if (require_match.matches(evt, [require_keys.Enter, require_keys.Space])) { evt.preventDefault(); inputRef.current?.click(); } }, onClick: require_events.composeEventHandlers([onClick, handleClick]), ...rest, children: labelText }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", { htmlFor: uid, className: `${prefix}--visually-hidden`, children: labelText }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", { type: "file", id: uid, className: `${prefix}--file-input`, ref: inputRef, tabIndex: -1, disabled, accept: accept.join(","), name, multiple, onChange: handleChange, onClick: (evt) => { evt.target.value = ""; } }) ] }); } FileUploaderDropContainer.propTypes = { accept: prop_types.default.arrayOf(prop_types.default.string), className: prop_types.default.string, disabled: prop_types.default.bool, id: prop_types.default.string, labelText: prop_types.default.string.isRequired, maxFileSize: prop_types.default.number, multiple: prop_types.default.bool, name: prop_types.default.string, onAddFiles: prop_types.default.func, onClick: prop_types.default.func, pattern: prop_types.default.string, role: require_deprecate.deprecate(prop_types.default.number, "The `role` prop for `FileUploaderButton` has been deprecated since it now renders a button element by default, and has an implicit role of button."), tabIndex: require_deprecate.deprecate(prop_types.default.number, "The `tabIndex` prop for `FileUploaderButton` has been deprecated since it now renders a button element by default.") }; //#endregion exports.default = FileUploaderDropContainer;