@salesforce/design-system-react
Version:
Salesforce Lightning Design System for React
159 lines (142 loc) • 4.06 kB
JSX
/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */
// Implements the [Radio Button Group design pattern](https://lightningdesignsystem.com/components/radio-button-group/) in React.
// Based on SLDS v2.5.0
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import shortid from 'shortid';
import assign from 'lodash.assign';
import { RADIO_BUTTON_GROUP } from '../../utilities/constants';
const propTypes = {
/**
* **Assistive text for accessibility**
* * `label`: This label appears in the legend.
*/
assistiveText: PropTypes.shape({
label: PropTypes.string,
}),
/**
* Children are expected to be Radio components.
*/
children: PropTypes.node.isRequired,
/**
* Custom CSS classes added to `slds-radio_button-group` node.
*/
className: PropTypes.oneOfType([
PropTypes.array,
PropTypes.object,
PropTypes.string,
]),
/**
* **Text labels for internationalization**
* This object is merged with the default props object on every render.
* * `error`: Message to display when any of Checkboxes are in an error state.
* * `label`: This label appears above the button group.
*/
labels: PropTypes.shape({
error: PropTypes.string,
label: PropTypes.string,
}),
/**
* This event fires when the radio selection changes.
*/
onChange: PropTypes.func,
/**
* Disable all radio inputs.
*/
disabled: PropTypes.bool,
/**
* Adds an indicator that this field is required.
*/
required: PropTypes.bool,
/**
* The name of this radio group.
*/
name: PropTypes.string,
/**
* The ID of the error message, for linking to radio inputs with aria-describedby.
*/
errorId: PropTypes.string,
};
const defaultProps = { labels: {}, assistiveText: {} };
/**
* A styled select list that can have a single entry checked at any one time.
* The RadioButtonGroup component wraps [Radio](/components/radios) components, which should be used as children.
*/
class RadioButtonGroup extends React.Component {
constructor(props) {
super(props);
// Merge objects of strings with their default object
this.labels = this.props.labels
? assign({}, defaultProps.labels, this.props.labels)
: defaultProps.labels;
this.generatedName = shortid.generate();
this.generatedErrorId = this.labels.error ? shortid.generate() : null;
}
getErrorId() {
if (this.hasError()) {
return this.props.errorId || this.generatedErrorId;
}
return undefined;
}
getName() {
return this.props.name || this.generatedName;
}
hasError() {
return !!this.labels.error;
}
render() {
const children = React.Children.map(this.props.children, (child) =>
React.cloneElement(child, {
name: this.getName(),
onChange: this.props.onChange,
'aria-describedby': this.getErrorId(),
disabled: this.props.disabled,
})
);
return (
<fieldset
className={classNames('slds-form-element', {
'slds-has-error': this.labels.error,
})}
>
<legend
className={classNames(
'slds-form-element__legend',
'slds-form-element__label',
this.props.assistiveText.label ? 'slds-assistive-text' : ''
)}
>
{this.props.required ? (
<abbr className="slds-required" title="required">
*
</abbr>
) : null}
{this.props.assistiveText.label
? this.props.assistiveText.label
: this.labels.label}
</legend>
<div
className={classNames(
'slds-form-element__control',
this.props.className
)}
>
<div style={this.props.style} className="slds-radio_button-group">
{children}
</div>
{this.labels.error ? (
<div id={this.getErrorId()} className="slds-form-element__help">
{this.labels.error}
</div>
) : null}
</div>
</fieldset>
);
}
}
RadioButtonGroup.displayName = RADIO_BUTTON_GROUP;
RadioButtonGroup.propTypes = propTypes;
RadioButtonGroup.defaultProps = defaultProps;
export default RadioButtonGroup;