UNPKG

@carbon/react

Version:

React components for the Carbon Design System

176 lines (171 loc) 5.35 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. */ import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js'; import cx from 'classnames'; import PropTypes from 'prop-types'; import React, { useState, useRef } from 'react'; import { Enter, Space } from '../../internal/keyboard/keys.js'; import { matches } from '../../internal/keyboard/match.js'; import { useId } from '../../internal/useId.js'; import { usePrefix } from '../../internal/usePrefix.js'; import { deprecate } from '../../prop-types/deprecate.js'; import { noopFn } from '../../internal/noopFn.js'; import { ButtonKinds } from '../Button/Button.js'; import '../Button/Button.Skeleton.js'; function FileUploaderButton({ accept, buttonKind = 'primary', className, disabled = false, disableLabelChanges = false, id, labelText: ownerLabelText = 'Add file', multiple = false, onChange = noopFn, name, size = 'md', // eslint-disable-next-line react/prop-types innerRef, ...other }) { const prefix = usePrefix(); const [labelText, setLabelText] = useState(ownerLabelText); const [prevOwnerLabelText, setPrevOwnerLabelText] = useState(ownerLabelText); const { current: inputId } = useRef(id || useId()); const inputNode = useRef(null); const classes = cx(`${prefix}--btn`, className, { [`${prefix}--btn--${buttonKind}`]: buttonKind, [`${prefix}--btn--disabled`]: disabled, // V11: remove field, small [`${prefix}--btn--md`]: size === 'field' || size === 'md', [`${prefix}--btn--sm`]: size === 'small' || size === 'sm', [`${prefix}--layout--size-${size}`]: size }); // Adjust label text state based on changes to the labelText prop if (ownerLabelText !== prevOwnerLabelText) { setLabelText(ownerLabelText); setPrevOwnerLabelText(ownerLabelText); } function onClick(event) { event.target.value = null; if (inputNode.current) { inputNode.current.value = ''; inputNode.current.click(); } } function onKeyDown(event) { if (matches(event, [Enter, Space])) { event.preventDefault(); if (inputNode.current) { inputNode.current.value = ''; inputNode.current.click(); } } } function handleOnChange(event) { const files = event.target.files; const length = event.target.files?.length || 0; if (files && !disableLabelChanges) { if (length > 1) { setLabelText(`${length} files`); } else if (length === 1) { setLabelText(files[0].name); } } onChange(event); } return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("button", _extends({ type: "button", disabled: disabled, className: classes, onClick: onClick, onKeyDown: onKeyDown }, other, { tabIndex: other.tabIndex !== undefined ? parseInt(other.tabIndex) : undefined }), labelText), /*#__PURE__*/React.createElement("label", { className: `${prefix}--visually-hidden`, ref: innerRef, htmlFor: inputId }, /*#__PURE__*/React.createElement("span", null, labelText)), /*#__PURE__*/React.createElement("input", { className: `${prefix}--visually-hidden`, ref: inputNode, id: inputId, disabled: disabled, type: "file", tabIndex: -1, multiple: multiple, accept: accept?.toString(), name: name, onChange: handleOnChange })); } FileUploaderButton.propTypes = { /** * Specify the types of files that this input should be able to receive */ accept: PropTypes.arrayOf(PropTypes.string), /** * Specify the type of underlying button */ buttonKind: PropTypes.oneOf(ButtonKinds), /** * Provide a custom className to be applied to the container node */ className: PropTypes.string, /** * Specify whether you want to disable any updates to the FileUploaderButton * label */ disableLabelChanges: PropTypes.bool, /** * Specify whether file input is disabled */ disabled: PropTypes.bool, /** * Provide a unique id for the underlying `<input>` node */ id: PropTypes.string, /** * Provide the label text to be read by screen readers when interacting with * this control */ labelText: PropTypes.node, /** * Specify if the component should accept multiple files to upload */ multiple: PropTypes.bool, /** * Provide a name for the underlying `<input>` node */ name: PropTypes.string, /** * Provide an optional `onChange` hook that is called each time the `<input>` * value changes */ onChange: PropTypes.func, /** * Provide an optional `onClick` hook that is called each time the button is * clicked */ onClick: PropTypes.func, /** * Provide an accessibility role for the `<FileUploaderButton>` */ role: PropTypes.string, /** * Specify the size of the FileUploaderButton, from a list of available * sizes. */ size: PropTypes.oneOf(['sm', 'md', 'lg']), /** * Provide a custom tabIndex value for the `<FileUploaderButton>` */ tabIndex: deprecate(PropTypes.number, 'The `tabIndex` prop for `FileUploaderButton` has ' + 'been deprecated since it now renders a button element by default.') }; export { FileUploaderButton as default };