@carbon/react
Version:
React components for the Carbon Design System
204 lines (200 loc) • 6.92 kB
JavaScript
/**
* 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 PropTypes from 'prop-types';
import React, { cloneElement } from 'react';
import cx from 'classnames';
import '../Text/index.js';
import { deprecate } from '../../prop-types/deprecate.js';
import { usePrefix } from '../../internal/usePrefix.js';
import { WarningFilled, WarningAltFilled } from '@carbon/icons-react';
import { useId } from '../../internal/useId.js';
import { noopFn } from '../../internal/noopFn.js';
import { AILabel } from '../AILabel/index.js';
import { isComponentElement } from '../../internal/utils.js';
import { Text } from '../Text/Text.js';
const Checkbox = /*#__PURE__*/React.forwardRef(({
className,
decorator,
helperText,
id,
labelText,
onChange = noopFn,
onClick,
indeterminate = false,
invalid,
invalidText,
hideLabel,
readOnly,
title = '',
warn,
warnText,
slug,
...other
}, ref) => {
const prefix = usePrefix();
const showWarning = !readOnly && !invalid && warn;
const showHelper = !invalid && !warn;
const checkboxGroupInstanceId = useId();
const helperId = !helperText ? undefined : `checkbox-helper-text-${checkboxGroupInstanceId}`;
const helper = helperText ? /*#__PURE__*/React.createElement("div", {
id: helperId,
className: `${prefix}--form__helper-text`
}, helperText) : null;
const wrapperClasses = cx(`${prefix}--form-item`, `${prefix}--checkbox-wrapper`, className, {
[`${prefix}--checkbox-wrapper--readonly`]: readOnly,
[`${prefix}--checkbox-wrapper--invalid`]: !readOnly && invalid,
[`${prefix}--checkbox-wrapper--warning`]: showWarning,
[`${prefix}--checkbox-wrapper--slug`]: slug,
[`${prefix}--checkbox-wrapper--decorator`]: decorator
});
const innerLabelClasses = cx(`${prefix}--checkbox-label-text`, {
[`${prefix}--visually-hidden`]: hideLabel
});
const candidate = slug ?? decorator;
const candidateIsAILabel = isComponentElement(candidate, AILabel);
const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/cloneElement(candidate, {
size: candidate.props.kind === 'inline' ? 'md' : 'mini'
}) : null;
return /*#__PURE__*/React.createElement("div", {
className: wrapperClasses
}, /*#__PURE__*/React.createElement("input", _extends({}, other, {
type: "checkbox",
"data-invalid": invalid ? true : undefined,
onChange: evt => {
if (!readOnly && onChange) {
onChange(evt, {
checked: evt.target.checked,
id
});
}
},
className: `${prefix}--checkbox`,
id: id,
ref: el => {
if (el) {
el.indeterminate = indeterminate ?? false;
}
if (typeof ref === 'function') {
ref(el);
} else if (ref && 'current' in ref) {
ref.current = el;
}
}
// readonly attribute not applicable to type="checkbox"
// see - https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox
,
"aria-readonly": readOnly,
onClick: evt => {
if (readOnly) {
// prevent default stops the checkbox being updated
evt.preventDefault();
}
// pass onClick event on to the user even if readonly
if (onClick) {
onClick(evt);
}
}
})), /*#__PURE__*/React.createElement("label", {
htmlFor: id,
className: `${prefix}--checkbox-label`,
title: title
}, /*#__PURE__*/React.createElement(Text, {
className: innerLabelClasses
}, labelText, slug ? normalizedDecorator : decorator ? /*#__PURE__*/React.createElement("div", {
className: `${prefix}--checkbox-wrapper-inner--decorator`
}, normalizedDecorator) : '')), /*#__PURE__*/React.createElement("div", {
className: `${prefix}--checkbox__validation-msg`
}, !readOnly && invalid && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(WarningFilled, {
className: `${prefix}--checkbox__invalid-icon`
}), /*#__PURE__*/React.createElement("div", {
className: `${prefix}--form-requirement`
}, invalidText)), showWarning && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(WarningAltFilled, {
className: `${prefix}--checkbox__invalid-icon ${prefix}--checkbox__invalid-icon--warning`
}), /*#__PURE__*/React.createElement("div", {
className: `${prefix}--form-requirement`
}, warnText))), showHelper && helper);
});
Checkbox.propTypes = {
/**
* Specify whether the underlying input should be checked
*/
checked: PropTypes.bool,
/**
* Specify an optional className to be applied to the <label> node
*/
className: PropTypes.string,
/**
* **Experimental**: Provide a decorator component to be rendered inside the `Checkbox` component
*/
decorator: PropTypes.node,
/**
* Specify whether the underlying input should be checked by default
*/
defaultChecked: PropTypes.bool,
/**
* Specify whether the Checkbox should be disabled
*/
disabled: PropTypes.bool,
/**
* Provide text for the form group for additional help
*/
helperText: PropTypes.node,
/**
* Specify whether the label should be hidden, or not
*/
hideLabel: PropTypes.bool,
/**
* Provide an `id` to uniquely identify the Checkbox input
*/
id: PropTypes.string.isRequired,
/**
* Specify whether the Checkbox is in an indeterminate state
*/
indeterminate: PropTypes.bool,
/**
* Specify whether the Checkbox is currently invalid
*/
invalid: PropTypes.bool,
/**
* Provide the text that is displayed when the Checkbox is in an invalid state
*/
invalidText: PropTypes.node,
/**
* Provide a label to provide a description of the Checkbox input that you are
* exposing to the user
*/
labelText: PropTypes.node.isRequired,
/**
* Provide an optional handler that is called when the internal state of
* Checkbox changes. This handler is called with event and state info.
* `(event, { checked, id }) => void`
*/
onChange: PropTypes.func,
/**
* Specify whether the Checkbox is read-only
*/
readOnly: PropTypes.bool,
/**
* **Experimental**: Provide a `Slug` component to be rendered inside the `Checkbox` component
*/
slug: deprecate(PropTypes.node, 'The `slug` prop has been deprecated and will be removed in the next major version. Use the decorator prop instead.'),
/**
* Specify a title for the <label> node for the Checkbox
*/
title: PropTypes.string,
/**
* Specify whether the Checkbox is currently in warning state
*/
warn: PropTypes.bool,
/**
* Provide the text that is displayed when the Checkbox is in warning state
*/
warnText: PropTypes.node
};
Checkbox.displayName = 'Checkbox';
export { Checkbox as default };