src/components/Slider/index.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { uniqueId } from '../../libs/utils';
import RenderIf from '../RenderIf';
import StyledContainer from './styled/container';
import StyledLabel from './styled/label';
import StyledSlider from './styled/slider';
import StyledInputRange from './styled/inputRange';
import StyledValue from './styled/value';
import ErrorText from '../Input/styled/errorText';
import withReduxForm from '../../libs/hocs/withReduxForm';
/**
* An input range slider lets the user specify a numeric value which must be between
* two specified values.
* @category Form
*/
class Slider extends Component {
constructor(props) {
super(props);
this.sliderId = uniqueId('slider-id');
this.errorMessageId = uniqueId('error-message');
this.sliderRef = React.createRef();
}
getAriaDescribedBy() {
const { error } = this.props;
if (error) {
return this.errorMessageId;
}
return undefined;
}
/**
* Sets click on the element.
* @public
*/
click() {
this.sliderRef.current.click();
}
/**
* Sets focus on the element.
* @public
*/
focus() {
this.sliderRef.current.focus();
}
/**
* Sets blur on the element.
* @public
*/
blur() {
this.sliderRef.current.blur();
}
render() {
const {
label,
value,
name,
min,
max,
step,
error,
disabled,
onBlur,
onChange,
onClick,
onFocus,
style,
className,
labelAlignment,
hideLabel,
required,
} = this.props;
const valueWidth = Math.max(`${max}`.length, `${min}`.length) + 1;
return (
<StyledContainer className={className} style={style}>
<RenderIf isTrue={label}>
<StyledLabel
label={label}
labelAlignment={labelAlignment}
hideLabel={hideLabel}
inputId={this.sliderId}
required={required}
/>
</RenderIf>
<StyledSlider>
<StyledInputRange
id={this.sliderId}
type="range"
name={name}
value={value}
min={min}
max={max}
step={step}
aria-describedby={this.getAriaDescribedBy()}
disabled={disabled}
required={required}
onClick={onClick}
onChange={onChange}
onBlur={onBlur}
onFocus={onFocus}
ref={this.sliderRef}
/>
<StyledValue width={valueWidth} aria-hidden>
{value}
</StyledValue>
</StyledSlider>
<RenderIf isTrue={error}>
<ErrorText id={this.errorMessageId}>{error}</ErrorText>
</RenderIf>
</StyledContainer>
);
}
}
Slider.propTypes = {
/** The text label for the slider. Provide your own label to describe the slider.
* Otherwise, no label is displayed. */
label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
/** Describes the position of the Slider label. Options include left, center and right.
* This value defaults to center. */
labelAlignment: PropTypes.oneOf(['left', 'center', 'right']),
/** A boolean to hide the Slider label */
hideLabel: PropTypes.bool,
/** The numerical value of the slider. This value defaults to 0. */
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
/** The name of the Slider. */
name: PropTypes.string,
/** The min value of the slider. This value defaults to 0. */
min: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
/** The max value of the slider. This value defaults to 100. */
max: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
/** The step increment value of the slider. Example steps include 0.1, 1, or 10.
* This value defaults to 1. */
step: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
/** Specifies that the slider element must have a value selected before submitting the form. */
error: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
/** Specifies that the slider element should be disabled. This value defaults to false. */
disabled: PropTypes.bool,
/** Specifies that an input field must be filled out before submitting the form.
* This value defaults to false. */
required: PropTypes.bool,
/** The action triggered when a value attribute changes. */
onChange: PropTypes.func,
/** The action triggered when the element is clicked. */
onClick: PropTypes.func,
/** The action triggered when the element receives focus. */
onFocus: PropTypes.func,
/** The action triggered when the element releases focus. */
onBlur: PropTypes.func,
/** A CSS class for the outer element, in addition to the component's base classes. */
className: PropTypes.string,
/** An object with custom style applied to the outer element. */
style: PropTypes.object,
};
Slider.defaultProps = {
label: null,
value: undefined,
name: undefined,
min: 0,
max: 100,
step: 1,
error: undefined,
disabled: false,
required: false,
onChange: () => {},
onClick: () => {},
onFocus: () => {},
onBlur: () => {},
className: undefined,
style: null,
labelAlignment: 'center',
hideLabel: false,
};
export default withReduxForm(Slider);