UNPKG

@carbon/react

Version:

React components for the Carbon Design System

216 lines (207 loc) 6.94 kB
/** * Copyright IBM Corp. 2016, 2023 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _rollupPluginBabelHelpers = require('../../_virtual/_rollupPluginBabelHelpers.js'); var React = require('react'); var PropTypes = require('prop-types'); var cx = require('classnames'); var keys = require('../../internal/keyboard/keys.js'); var match = require('../../internal/keyboard/match.js'); var useId = require('../../internal/useId.js'); var usePrefix = require('../../internal/usePrefix.js'); var events = require('../../tools/events.js'); var deprecate = require('../../prop-types/deprecate.js'); var noopFn = require('../../internal/noopFn.js'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var React__default = /*#__PURE__*/_interopDefaultLegacy(React); var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes); var cx__default = /*#__PURE__*/_interopDefaultLegacy(cx); function FileUploaderDropContainer({ accept = [], className, id, disabled, labelText = 'Add file', multiple = false, name, onAddFiles = noopFn.noopFn, onClick, pattern = '.[0-9a-z]+$', // eslint-disable-next-line react/prop-types innerRef, ...rest }) { const prefix = usePrefix.usePrefix(); const inputRef = React.useRef(null); const { current: uid } = React.useRef(id || useId.useId()); const [isActive, setActive] = React.useState(false); const dropareaClasses = cx__default["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 restrictions */ function validateFiles(transferredFiles) { if (!accept.length) { return 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 (fileExtension === undefined) { return acc; } if (acceptedTypes.has(mimeType) || acceptedTypes.has(fileExtension.toLowerCase())) { return acc.concat([curr]); } curr.invalidFileType = true; return acc.concat([curr]); }, []); } function handleChange(event) { const files = [...(event.target.files ?? [])]; const filesToValidate = multiple ? files : [files[0]]; const addedFiles = validateFiles(filesToValidate); return onAddFiles(event, { addedFiles }); } function handleDrop(event) { const files = [...event.dataTransfer.files]; const filesToValidate = multiple ? files : [files[0]]; const addedFiles = validateFiles(filesToValidate); return onAddFiles(event, { addedFiles }); } const handleClick = () => { if (!disabled) { inputRef.current?.click(); } }; return /*#__PURE__*/React__default["default"].createElement("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); } }, /*#__PURE__*/React__default["default"].createElement("button", _rollupPluginBabelHelpers["extends"]({ type: "button", className: dropareaClasses, ref: innerRef, onKeyDown: evt => { if (match.matches(evt, [keys.Enter, keys.Space])) { evt.preventDefault(); inputRef.current?.click(); } }, onClick: events.composeEventHandlers([onClick, handleClick]) }, rest), labelText), /*#__PURE__*/React__default["default"].createElement("label", { htmlFor: uid, className: `${prefix}--visually-hidden` }, labelText), /*#__PURE__*/React__default["default"].createElement("input", { type: "file", id: uid, className: `${prefix}--file-input`, ref: inputRef, tabIndex: -1, disabled: disabled, accept: accept.join(','), name: name, multiple: multiple, onChange: handleChange, onClick: evt => { evt.target.value = ''; } })); } FileUploaderDropContainer.propTypes = { /** * Specify the types of files that this input should be able to receive */ accept: PropTypes__default["default"].arrayOf(PropTypes__default["default"].string), /** * Provide a custom className to be applied to the container node */ className: PropTypes__default["default"].string, /** * Specify whether file input is disabled */ disabled: PropTypes__default["default"].bool, /** * Provide a unique id for the underlying `<input>` node */ id: PropTypes__default["default"].string, /** * Provide the label text to be read by screen readers when interacting with * this control */ labelText: PropTypes__default["default"].string.isRequired, /** * Specify if the component should accept multiple files to upload */ multiple: PropTypes__default["default"].bool, /** * Provide a name for the underlying `<input>` node */ name: PropTypes__default["default"].string, /** * Event handler that is called after files are added to the uploader * The event handler signature looks like `onAddFiles(evt, { addedFiles })` */ onAddFiles: PropTypes__default["default"].func, /** * Provide an optional function to be called when the button element * is clicked */ onClick: PropTypes__default["default"].func, /** * Provide a custom regex pattern for the acceptedTypes */ pattern: PropTypes__default["default"].string, /** * Provide an accessibility role for the `<FileUploaderButton>` */ role: deprecate["default"](PropTypes__default["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.'), /** * Provide a custom tabIndex value for the `<FileUploaderButton>` */ tabIndex: deprecate["default"](PropTypes__default["default"].number, 'The `tabIndex` prop for `FileUploaderButton` has ' + 'been deprecated since it now renders a button element by default.') }; exports["default"] = FileUploaderDropContainer;