@carbon/react
Version:
React components for the Carbon Design System
120 lines (118 loc) • 3.88 kB
JavaScript
/**
* 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.
*/
import { usePrefix } from "../../internal/usePrefix.js";
import { Enter, Space } from "../../internal/keyboard/keys.js";
import { matches } from "../../internal/keyboard/match.js";
import { useId } from "../../internal/useId.js";
import { noopFn } from "../../internal/noopFn.js";
import { deprecate } from "../../prop-types/deprecate.js";
import { ButtonKinds } from "../Button/Button.js";
import classNames from "classnames";
import { useEffect, useRef, useState } from "react";
import PropTypes from "prop-types";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
//#region src/components/FileUploader/FileUploaderButton.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 FileUploaderButton({ accept, buttonKind = "primary", className, disabled = false, disableLabelChanges = false, id, labelText: ownerLabelText = "Add file", multiple = false, onChange = noopFn, name, size = "md", innerRef, ...other }) {
const prefix = usePrefix();
const [labelText, setLabelText] = useState(ownerLabelText);
const generatedId = useId();
const { current: inputId } = useRef(id || generatedId);
const inputNode = useRef(null);
const classes = classNames(`${prefix}--btn`, className, {
[`${prefix}--btn--${buttonKind}`]: buttonKind,
[`${prefix}--btn--disabled`]: disabled,
[`${prefix}--btn--md`]: size === "field" || size === "md",
[`${prefix}--btn--sm`]: size === "small" || size === "sm",
[`${prefix}--layout--size-${size}`]: size
});
useEffect(() => {
setLabelText(ownerLabelText);
}, [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__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx("button", {
type: "button",
disabled,
className: classes,
onClick,
onKeyDown,
...other,
tabIndex: other.tabIndex !== void 0 ? parseInt(other.tabIndex) : void 0,
children: labelText
}),
/* @__PURE__ */ jsx("label", {
className: `${prefix}--visually-hidden`,
ref: innerRef,
htmlFor: inputId,
children: /* @__PURE__ */ jsx("span", { children: labelText })
}),
/* @__PURE__ */ jsx("input", {
className: `${prefix}--visually-hidden`,
ref: inputNode,
id: inputId,
disabled,
type: "file",
tabIndex: -1,
multiple,
accept: accept?.toString(),
name,
onChange: handleOnChange
})
] });
}
FileUploaderButton.propTypes = {
accept: PropTypes.arrayOf(PropTypes.string),
buttonKind: PropTypes.oneOf(ButtonKinds),
className: PropTypes.string,
disableLabelChanges: PropTypes.bool,
disabled: PropTypes.bool,
id: PropTypes.string,
labelText: PropTypes.node,
multiple: PropTypes.bool,
name: PropTypes.string,
onChange: PropTypes.func,
onClick: PropTypes.func,
role: PropTypes.string,
size: PropTypes.oneOf([
"sm",
"md",
"lg"
]),
tabIndex: deprecate(PropTypes.number, "The `tabIndex` prop for `FileUploaderButton` has been deprecated since it now renders a button element by default.")
};
//#endregion
export { FileUploaderButton as default };