/**
* @module InputRange/Slider
*/
import React from 'react';
import Label from './Label';
import { autobind } from './util';
/**
* Get the owner document of slider
* @private
* @param {Slider} slider - React component
* @return {Document} Document
*/
function getDocument(slider) {
const { slider: { ownerDocument } } = slider.refs;
return ownerDocument;
}
/**
* Get the style of slider based on its props
* @private
* @param {Slider} slider - React component
* @return {Object} CSS styles
*/
function getStyle(slider) {
const perc = (slider.props.percentage || 0) * 100;
const style = {
position: 'absolute',
left: `${perc}%`,
};
return style;
}
/**
* Slider React component
* @class
* @extends React.Component
* @param {Object} props - React component props
*/
export default class Slider extends React.Component {
constructor(props) {
super(props);
// Auto-bind
autobind([
'handleClick',
'handleMouseDown',
'handleMouseUp',
'handleMouseMove',
'handleTouchStart',
'handleTouchEnd',
'handleTouchMove',
'handleKeyDown',
], this);
}
/**
* Handle any click event received by the component
* @param {SyntheticEvent} event - User event
*/
handleClick(event) {
event.preventDefault();
}
/**
* Handle any mousedown event received by the component
* @param {SyntheticEvent} event - User event
*/
handleMouseDown() {
const document = getDocument(this);
// Event
document.addEventListener('mousemove', this.handleMouseMove);
document.addEventListener('mouseup', this.handleMouseUp);
}
/**
* Handle any mouseup event received by the component
* @param {SyntheticEvent} event - User event
*/
handleMouseUp() {
const document = getDocument(this);
// Event
document.removeEventListener('mousemove', this.handleMouseMove);
document.removeEventListener('mouseup', this.handleMouseUp);
}
/**
* Handle any mousemove event received by the component
* @param {SyntheticEvent} event - User event
*/
handleMouseMove(event) {
this.props.onSliderMouseMove(event, this);
}
/**
* Handle any touchstart event received by the component
* @param {SyntheticEvent} event - User event
*/
handleTouchStart(event) {
const document = getDocument(this);
event.preventDefault();
document.addEventListener('touchmove', this.handleTouchMove);
document.addEventListener('touchend', this.handleTouchEnd);
}
/**
* Handle any touchmove event received by the component
* @param {SyntheticEvent} event - User event
*/
handleTouchMove(event) {
this.props.onSliderMouseMove(event, this);
}
/**
* Handle any touchend event received by the component
* @param {SyntheticEvent} event - User event
*/
handleTouchEnd() {
const document = getDocument(this);
event.preventDefault();
document.removeEventListener('touchmove', this.handleTouchMove);
document.removeEventListener('touchend', this.handleTouchEnd);
}
/**
* Handle any keydown event received by the component
* @param {SyntheticEvent} event - User event
*/
handleKeyDown(event) {
this.props.onSliderKeyDown(event, this);
}
/**
* Render method of the component
* @return {string} Component JSX
*/
render() {
const classNames = this.props.classNames;
const style = getStyle(this);
return (
<span
className={ classNames.sliderContainer }
ref="slider"
style={ style }>
<Label
className={ classNames.labelValue }
containerClassName={ classNames.labelContainer }>
{ this.props.value }
</Label>
<a
aria-labelledby={ this.props.ariaLabelledby }
aria-valuemax={ this.props.maxValue }
aria-valuemin={ this.props.minValue }
aria-valuenow={ this.props.value }
className={ classNames.slider }
draggable="false"
href="#"
onClick={ this.handleClick }
onKeyDown={ this.handleKeyDown }
onMouseDown={ this.handleMouseDown }
onTouchStart={ this.handleTouchStart }
role="slider">
</a>
</span>
);
}
}
/**
* Accepted propTypes of Slider
* @static {Object}
* @property {Function} ariaLabelledby
* @property {Function} className
* @property {Function} maxValue
* @property {Function} minValue
* @property {Function} onSliderKeyDown
* @property {Function} onSliderMouseMove
* @property {Function} percentage
* @property {Function} type
* @property {Function} value
*/
Slider.propTypes = {
ariaLabelledby: React.PropTypes.string,
classNames: React.PropTypes.objectOf(React.PropTypes.string),
maxValue: React.PropTypes.number,
minValue: React.PropTypes.number,
onSliderKeyDown: React.PropTypes.func.isRequired,
onSliderMouseMove: React.PropTypes.func.isRequired,
percentage: React.PropTypes.number.isRequired,
type: React.PropTypes.string.isRequired,
value: React.PropTypes.number.isRequired,
};