@salesforce/design-system-react
Version:
Salesforce Lightning Design System for React
205 lines (190 loc) • 5.71 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 */
import React from 'react';
import PropTypes from 'prop-types';
import shortid from 'shortid';
import classNames from 'classnames';
import KEYS from '../../utilities/key-code';
import { RADIO } from '../../utilities/constants';
import getDataProps from '../../utilities/get-data-props';
import Swatch from '../../components/color-picker/private/swatch';
const propTypes = {
/**
* The ID of an element that describes this radio input. Often used for error messages.
*/
'aria-describedby': PropTypes.string,
/**
* This is a controlled component. This radio is checked according to this value.
*/
checked: PropTypes.bool,
/**
* Class name to be passed to radio input wrapper ( `span` element)
*/
className: PropTypes.oneOfType([
PropTypes.array,
PropTypes.object,
PropTypes.string,
]) /**
* This is the initial value of an uncontrolled form element and is present only to provide compatibility
* with hybrid framework applications that are not entirely React. It should only be used in an application
* without centralized state (Redux, Flux). "Controlled components" with centralized state is highly recommended.
* See [Code Overview](https://github.com/salesforce/design-system-react/blob/master/docs/codebase-overview.md#controlled-and-uncontrolled-components) for more information.
*/,
defaultChecked: PropTypes.bool,
/**
* Disable this radio input.
*/
disabled: PropTypes.bool,
/**
* A unique ID that is used to associating a label to the `input` element. This ID is added to the `input` element.
*/
id: PropTypes.string,
/**
* The string or element that is shown as both the title and the label for this radio input.
*/
label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
/**
* The name of the radio input group.
*/
name: PropTypes.string,
/**
* This event fires when the radio selection changes. Passes in `event, { checked }`.
*/
onChange: PropTypes.func,
/**
* The value of this radio input.
*/
value: PropTypes.string,
/**
* Variant of the Radio button. Base is the default and button-group makes the radio button look like a normal button (should be a child of <RadioButtonGroup>).
*/
variant: PropTypes.oneOf(['base', 'button-group', 'swatch']),
/**
* Ref callback that will pass in the radio's `input` tag
*/
refs: PropTypes.shape({
input: PropTypes.func,
}),
};
const defaultProps = {
variant: 'base',
};
/**
* A radio input that can have a single input checked at any one time. Radios should be wrapped with
* a [RadioGroup](/components/radio-group) or [RadioButtonGroup](/components/radio-button-group)
*/
class Radio extends React.Component {
constructor(props) {
super(props);
this.generatedId = shortid.generate();
this.preventDuplicateChangeEvent = false;
}
getId() {
return this.props.id || this.generatedId;
}
handleChange = (event, preventDuplicateChangeEvent) => {
if (!this.preventDuplicateChangeEvent) {
this.preventDuplicateChangeEvent = Boolean(preventDuplicateChangeEvent);
if (this.props.onChange) {
this.props.onChange(event, {
checked: !this.props.checked,
});
}
} else {
this.preventDuplicateChangeEvent = false;
}
};
render() {
const dataProps = getDataProps(this.props);
let radio;
if (this.props.variant === 'swatch') {
radio = (
<label
style={{ border: '1px' }}
className="slds-radio_button__label"
htmlFor={this.getId()}
>
<span>
<Swatch
label={this.props.label}
style={this.props.style}
color={this.props.value}
/>
</span>
</label>
);
} else if (this.props.variant === 'button-group')
radio = (
<label className="slds-radio_button__label" htmlFor={this.getId()}>
<span className="slds-radio_faux">{this.props.label}</span>
</label>
);
else {
radio = (
<label className="slds-radio__label" htmlFor={this.getId()}>
<span className="slds-radio_faux" />
<span className="slds-form-element__label">{this.props.label}</span>
</label>
);
}
return (
<span
className={classNames(
{
'slds-radio':
this.props.variant === 'base' || this.props.variant === 'swatch',
'slds-button slds-radio_button':
this.props.variant === 'button-group',
},
this.props.className
)}
>
<input
type="radio"
id={this.getId()}
name={this.props.name}
value={this.props.value}
checked={this.props.checked}
defaultChecked={this.props.defaultChecked}
onChange={(event) => {
this.handleChange(event);
}}
onClick={(event) => {
if (this.props.checked && this.props.deselectable) {
this.handleChange(event);
}
}}
onKeyPress={(event) => {
const charCode = event.charCode;
if (
charCode === KEYS.SPACE &&
this.props.checked &&
this.props.deselectable
) {
this.handleChange(event, true);
} else if (
(charCode === KEYS.ENTER &&
(this.props.checked && this.props.deselectable)) ||
!this.props.checked
) {
this.handleChange(event);
}
}}
aria-describedby={this.props['aria-describedby']}
disabled={this.props.disabled}
{...dataProps}
ref={(input) => {
if (this.props.refs && this.props.refs.input) {
this.props.refs.input(input);
}
}}
/>
{radio}
</span>
);
}
}
Radio.displayName = RADIO;
Radio.propTypes = propTypes;
Radio.defaultProps = defaultProps;
export default Radio;