UNPKG

@carbon/react

Version:

React components for the Carbon Design System

192 lines (190 loc) 8.38 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_Text = require("../Text/Text.js"); const require_deprecate = require("../../prop-types/deprecate.js"); const require_utils = require("../../internal/utils.js"); const require_useNormalizedInputProps = require("../../internal/useNormalizedInputProps.js"); const require_index = require("../AILabel/index.js"); const require_events = require("../../tools/events.js"); const require_FormContext = require("../FluidForm/FormContext.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"); let _carbon_icons_react = require("@carbon/icons-react"); //#region src/components/Select/Select.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. */ const Select = (0, react.forwardRef)(({ className, decorator, id, inline = false, labelText = "Select", disabled = false, children, noLabel = false, hideLabel = false, invalid = false, invalidText = "", helperText, light = false, readOnly, size, warn = false, warnText, onChange, slug, ...other }, ref) => { const prefix = require_usePrefix.usePrefix(); const { isFluid } = (0, react.useContext)(require_FormContext.FormContext); const [isFocused, setIsFocused] = (0, react.useState)(false); const validChildren = react.default.Children.toArray(children).filter((child) => react.default.isValidElement(child)); const selectedValue = other?.value || other?.defaultValue; const selectedOption = validChildren.find((child) => child.props?.value === selectedValue); const [title, setTitle] = (0, react.useState)(other?.title || selectedOption?.props?.text || validChildren[0]?.props?.text || ""); const normalizedProps = require_useNormalizedInputProps.useNormalizedInputProps({ id, disabled, readOnly, invalid, invalidText, warn, warnText }); const selectClasses = (0, classnames.default)({ [`${prefix}--select`]: true, [`${prefix}--select--inline`]: inline, [`${prefix}--select--light`]: light, [`${prefix}--select--invalid`]: normalizedProps.invalid, [`${prefix}--select--disabled`]: normalizedProps.disabled, [`${prefix}--select--readonly`]: readOnly, [`${prefix}--select--warning`]: normalizedProps.warn, [`${prefix}--select--fluid--invalid`]: isFluid && normalizedProps.invalid, [`${prefix}--select--fluid--focus`]: isFluid && isFocused, [`${prefix}--select--slug`]: slug, [`${prefix}--select--decorator`]: decorator }); const labelClasses = (0, classnames.default)(`${prefix}--label`, { [`${prefix}--visually-hidden`]: hideLabel, [`${prefix}--label--disabled`]: normalizedProps.disabled }); const inputClasses = (0, classnames.default)({ [`${prefix}--select-input`]: true, [`${prefix}--select-input--${size}`]: size }); const error = normalizedProps.validation; const helperTextClasses = (0, classnames.default)(`${prefix}--form__helper-text`, { [`${prefix}--form__helper-text--disabled`]: normalizedProps.disabled }); const helper = typeof helperText !== "undefined" && helperText !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Text.Text, { as: "div", id: normalizedProps.helperId, className: helperTextClasses, children: helperText }) : null; const ariaProps = {}; if (normalizedProps.invalid) ariaProps["aria-describedby"] = normalizedProps.invalidId; else if (!inline && !isFluid) ariaProps["aria-describedby"] = helper ? normalizedProps.helperId : void 0; const handleFocus = (evt) => { setIsFocused(evt.type === "focus"); }; const handleChange = (evt) => { const selectedOption = evt?.target?.options[evt.target.selectedIndex]; setTitle(selectedOption?.text); }; const readOnlyEventHandlers = { onMouseDown: (evt) => { if (readOnly) { evt.preventDefault(); evt.target.focus(); } }, onKeyDown: (evt) => { if (readOnly && [ "ArrowDown", "ArrowUp", " " ].includes(evt.key)) evt.preventDefault(); } }; const candidate = slug ?? decorator; const normalizedDecorator = require_utils.isComponentElement(candidate, require_index.AILabel) ? (0, react.cloneElement)(candidate, { size: "mini" }) : candidate; const input = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", { ...other, ...ariaProps, id, className: inputClasses, disabled: normalizedProps.disabled || void 0, "aria-invalid": normalizedProps.invalid || void 0, "aria-readonly": readOnly || void 0, title, onChange: require_events.composeEventHandlers([onChange, handleChange]), ...readOnlyEventHandlers, ref, children }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_carbon_icons_react.ChevronDown, { className: `${prefix}--select__arrow` }), normalizedProps.invalid && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_carbon_icons_react.WarningFilled, { className: `${prefix}--select__invalid-icon` }), !normalizedProps.invalid && normalizedProps.warn && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_carbon_icons_react.WarningAltFilled, { className: `${prefix}--select__invalid-icon ${prefix}--select__invalid-icon--warning` }) ] }); return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: (0, classnames.default)(`${prefix}--form-item`, className), children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { className: selectClasses, children: [ !noLabel && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Text.Text, { as: "label", htmlFor: id, className: labelClasses, children: labelText }), inline && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { className: `${prefix}--select-input--inline__wrapper`, children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: `${prefix}--select-input__wrapper`, "data-invalid": normalizedProps.invalid || null, children: input }), error] }), !inline && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { className: `${prefix}--select-input__wrapper`, "data-invalid": normalizedProps.invalid || null, onFocus: handleFocus, onBlur: handleFocus, children: [ input, slug ? normalizedDecorator : decorator ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: `${prefix}--select__inner-wrapper--decorator`, children: normalizedDecorator }) : "", isFluid && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("hr", { className: `${prefix}--select__divider` }), isFluid && error ? error : null ] }), !inline && !isFluid && error ? error : helper ] }) }); }); Select.displayName = "Select"; Select.propTypes = { children: prop_types.default.node, className: prop_types.default.string, decorator: prop_types.default.node, defaultValue: prop_types.default.any, disabled: prop_types.default.bool, helperText: prop_types.default.node, hideLabel: prop_types.default.bool, id: prop_types.default.string.isRequired, inline: prop_types.default.bool, invalid: prop_types.default.bool, invalidText: prop_types.default.node, labelText: prop_types.default.node, light: require_deprecate.deprecate(prop_types.default.bool, "The `light` prop for `Select` is no longer needed and has been deprecated in v11 in favor of the new `Layer` component. It will be moved in the next major release."), noLabel: prop_types.default.bool, onChange: prop_types.default.func, readOnly: prop_types.default.bool, size: prop_types.default.oneOf([ "sm", "md", "lg" ]), slug: require_deprecate.deprecate(prop_types.default.node, "The `slug` prop has been deprecated and will be removed in the next major version. Use the decorator prop instead."), warn: prop_types.default.bool, warnText: prop_types.default.node }; //#endregion exports.default = Select;