joyent-portal/packages/ui-toolkit/src/slider/react-input-range/input-range/track.jsx

211 lines
4.6 KiB
JavaScript
Executable File

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import remcalc from 'remcalc';
import theme from '../../../theme';
export const TrackStyled = styled.div`
background: ${theme.grey};
cursor: pointer;
display: block;
height: ${remcalc(4)};
position: relative;
`;
const ActiveTrack = styled.div`
background: ${theme.blue};
height: 100%;
position: absolute;
`;
/**
* @ignore
*/
export default class Track extends Component {
/**
* @override
* @return {Object}
* @property {Function} children
* @property {Function} classNames
* @property {Boolean} draggableTrack
* @property {Function} onTrackDrag
* @property {Function} onTrackMouseDown
* @property {Function} percentages
*/
static get propTypes() {
return {
children: PropTypes.node.isRequired,
classNames: PropTypes.objectOf(PropTypes.string).isRequired,
draggableTrack: PropTypes.bool,
onTrackDrag: PropTypes.func,
onTrackMouseDown: PropTypes.func.isRequired,
percentages: PropTypes.objectOf(PropTypes.number).isRequired
};
}
/**
* @param {Object} props
* @param {InputRangeClassNames} props.classNames
* @param {Boolean} props.draggableTrack
* @param {Function} props.onTrackDrag
* @param {Function} props.onTrackMouseDown
* @param {number} props.percentages
*/
constructor(props) {
super(props);
/**
* @private
* @type {?Component}
*/
this.node = null;
this.trackDragEvent = null;
this.handleMouseMove = this.handleMouseMove.bind(this);
this.handleMouseUp = this.handleMouseUp.bind(this);
this.handleMouseDown = this.handleMouseDown.bind(this);
this.handleTouchStart = this.handleTouchStart.bind(this);
}
/**
* @private
* @return {ClientRect}
*/
getClientRect() {
return this.node.getBoundingClientRect();
}
/**
* @private
* @return {Object} CSS styles
*/
getActiveTrackStyle() {
const width = `${(this.props.percentages.max - this.props.percentages.min) *
100}%`;
const left = `${this.props.percentages.min * 100}%`;
return { left, width };
}
/**
* Listen to mousemove event
* @private
* @return {void}
*/
addDocumentMouseMoveListener() {
this.removeDocumentMouseMoveListener();
this.node.ownerDocument.addEventListener('mousemove', this.handleMouseMove);
}
/**
* Listen to mouseup event
* @private
* @return {void}
*/
addDocumentMouseUpListener() {
this.removeDocumentMouseUpListener();
this.node.ownerDocument.addEventListener('mouseup', this.handleMouseUp);
}
/**
* @private
* @return {void}
*/
removeDocumentMouseMoveListener() {
this.node.ownerDocument.removeEventListener(
'mousemove',
this.handleMouseMove
);
}
/**
* @private
* @return {void}
*/
removeDocumentMouseUpListener() {
this.node.ownerDocument.removeEventListener('mouseup', this.handleMouseUp);
}
/**
* @private
* @param {SyntheticEvent} event
* @return {void}
*/
handleMouseMove(event) {
if (!this.props.draggableTrack) {
return;
}
if (this.trackDragEvent !== null) {
this.props.onTrackDrag(event, this.trackDragEvent);
}
this.trackDragEvent = event;
}
/**
* @private
* @return {void}
*/
handleMouseUp() {
if (!this.props.draggableTrack) {
return;
}
this.removeDocumentMouseMoveListener();
this.removeDocumentMouseUpListener();
this.trackDragEvent = null;
}
/**
* @private
* @param {SyntheticEvent} event - User event
*/
handleMouseDown(event) {
const clientX = event.touches ? event.touches[0].clientX : event.clientX;
const trackClientRect = this.getClientRect();
const position = {
x: clientX - trackClientRect.left,
y: 0
};
this.props.onTrackMouseDown(event, position);
if (this.props.draggableTrack) {
this.addDocumentMouseMoveListener();
this.addDocumentMouseUpListener();
}
}
/**
* @private
* @param {SyntheticEvent} event - User event
*/
handleTouchStart(event) {
event.preventDefault();
this.handleMouseDown(event);
}
/**
* @override
* @return {JSX.Element}
*/
render() {
const activeTrackStyle = this.getActiveTrackStyle();
return (
<TrackStyled
onMouseDown={this.handleMouseDown}
onTouchStart={this.handleTouchStart}
innerRef={node => {
this.node = node;
}}
>
<ActiveTrack style={activeTrackStyle} />
{this.props.children}
</TrackStyled>
);
}
}