UNPKG

@foo-software/react-toolbox

Version:

A set of React components implementing Google's Material Design specification with the power of CSS Modules.

430 lines (380 loc) 16.2 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.Slider = exports.sliderFactory = undefined; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _reactDom = require('react-dom'); var _reactDom2 = _interopRequireDefault(_reactDom); var _classnames2 = require('classnames'); var _classnames3 = _interopRequireDefault(_classnames2); var _reactStyleProptype = require('react-style-proptype'); var _reactStyleProptype2 = _interopRequireDefault(_reactStyleProptype); var _reactCssThemr = require('react-css-themr'); var _utils = require('../utils/utils'); var _identifiers = require('../identifiers'); var _events = require('../utils/events'); var _events2 = _interopRequireDefault(_events); var _ProgressBar = require('../progress_bar/ProgressBar'); var _ProgressBar2 = _interopRequireDefault(_ProgressBar); var _Input = require('../input/Input'); var _Input2 = _interopRequireDefault(_Input); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var KEYS = { ENTER: 'Enter', ESC: 'Escape', ARROW_UP: 'ArrowUp', ARROW_DOWN: 'ArrowDown' }; var factory = function factory(ProgressBar, Input) { var Slider = function (_Component) { _inherits(Slider, _Component); function Slider() { var _ref; var _temp, _this, _ret; _classCallCheck(this, Slider); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Slider.__proto__ || Object.getPrototypeOf(Slider)).call.apply(_ref, [this].concat(args))), _this), _this.state = { inputFocused: false, inputValue: null, sliderLength: 0, sliderStart: 0 }, _this.handleInputFocus = function () { _this.setState({ inputFocused: true, inputValue: _this.valueForInput(_this.props.value) }); }, _this.handleInputChange = function (value) { _this.setState({ inputValue: value }); }, _this.handleInputBlur = function (event) { var value = _this.state.inputValue || 0; _this.setState({ inputFocused: false, inputValue: null }, function () { _this.props.onChange(_this.trimValue(value), event); }); }, _this.handleKeyDown = function (event) { var _this$props = _this.props, disabled = _this$props.disabled, step = _this$props.step; var ARROW_DOWN = KEYS.ARROW_DOWN, ARROW_UP = KEYS.ARROW_UP, ENTER = KEYS.ENTER, ESC = KEYS.ESC; if (disabled) return; if ([ENTER, ESC].includes(event.code)) _this.inputNode.blur(); if (event.code === ARROW_UP) _this.addToValue(step); if (event.code === ARROW_DOWN) _this.addToValue(-step); }, _this.handleMouseDown = function (event) { if (_this.state.inputFocused) _this.inputNode.blur(); _events2.default.addEventsToDocument(_this.getMouseEventMap()); _this.start(_events2.default.getMousePosition(event)); _events2.default.pauseEvent(event); }, _this.handleMouseMove = function (event) { _events2.default.pauseEvent(event); _this.move(_events2.default.getMousePosition(event)); }, _this.handleMouseUp = function () { _this.end(_this.getMouseEventMap()); }, _this.handleResize = function (event, callback) { var _ReactDOM$findDOMNode = _reactDom2.default.findDOMNode(_this.progressbarNode).getBoundingClientRect(), left = _ReactDOM$findDOMNode.left, right = _ReactDOM$findDOMNode.right; var cb = callback || function () {}; _this.setState({ sliderStart: left, sliderLength: right - left }, cb); }, _this.handleSliderBlur = function () { _events2.default.removeEventsFromDocument(_this.getKeyboardEvents()); }, _this.handleSliderFocus = function () { _events2.default.addEventsToDocument(_this.getKeyboardEvents()); }, _this.handleTouchEnd = function () { _this.end(_this.getTouchEventMap()); }, _this.handleTouchMove = function (event) { _this.move(_events2.default.getTouchPosition(event)); }, _this.handleTouchStart = function (event) { if (_this.state.inputFocused) _this.inputNode.blur(); _this.start(_events2.default.getTouchPosition(event)); _events2.default.addEventsToDocument(_this.getTouchEventMap()); _events2.default.pauseEvent(event); }, _temp), _possibleConstructorReturn(_this, _ret); } _createClass(Slider, [{ key: 'componentDidMount', value: function componentDidMount() { window.addEventListener('resize', this.handleResize); this.handleResize(); } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { if (this.state.inputFocused && this.props.value !== nextProps.value) { this.setState({ inputValue: this.valueForInput(nextProps.value) }); } } }, { key: 'shouldComponentUpdate', value: function shouldComponentUpdate(nextProps, nextState) { return this.state.inputFocused || !nextState.inputFocused; } }, { key: 'componentWillUpdate', value: function componentWillUpdate(nextProps, nextState) { if (nextState.pressed !== this.state.pressed) { if (nextState.pressed) { this.props.onDragStart(); } else { this.props.onDragStop(); } } } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { window.removeEventListener('resize', this.handleResize); _events2.default.removeEventsFromDocument(this.getMouseEventMap()); _events2.default.removeEventsFromDocument(this.getTouchEventMap()); _events2.default.removeEventsFromDocument(this.getKeyboardEvents()); } }, { key: 'getKeyboardEvents', value: function getKeyboardEvents() { return { keydown: this.handleKeyDown }; } }, { key: 'getMouseEventMap', value: function getMouseEventMap() { return { mousemove: this.handleMouseMove, mouseup: this.handleMouseUp }; } }, { key: 'getTouchEventMap', value: function getTouchEventMap() { return { touchmove: this.handleTouchMove, touchend: this.handleTouchEnd }; } }, { key: 'addToValue', value: function addToValue(increment) { var value = this.state.inputFocused ? parseFloat(this.state.inputValue) : this.props.value; value = this.trimValue(value + increment); if (value !== this.props.value) this.props.onChange(value); } }, { key: 'end', value: function end(revents) { _events2.default.removeEventsFromDocument(revents); this.setState({ pressed: false }); } }, { key: 'knobOffset', value: function knobOffset() { var _props = this.props, max = _props.max, min = _props.min, value = _props.value; return 100 * ((value - min) / (max - min)); } }, { key: 'move', value: function move(position) { var newValue = this.positionToValue(position); if (newValue !== this.props.value) this.props.onChange(newValue); } }, { key: 'positionToValue', value: function positionToValue(position) { var _state = this.state, start = _state.sliderStart, length = _state.sliderLength; var _props2 = this.props, max = _props2.max, min = _props2.min, step = _props2.step; var pos = (position.x - start) / length * (max - min); return this.trimValue(Math.round(pos / step) * step + min); } }, { key: 'start', value: function start(position) { var _this2 = this; this.handleResize(null, function () { _this2.setState({ pressed: true }); _this2.props.onChange(_this2.positionToValue(position)); }); } }, { key: 'stepDecimals', value: function stepDecimals() { return (this.props.step.toString().split('.')[1] || []).length; } }, { key: 'trimValue', value: function trimValue(value) { if (value < this.props.min) return this.props.min; if (value > this.props.max) return this.props.max; return (0, _utils.round)(value, this.stepDecimals()); } }, { key: 'valueForInput', value: function valueForInput(value) { var decimals = this.stepDecimals(); return decimals > 0 ? value.toFixed(decimals) : value.toString(); } }, { key: 'renderSnaps', value: function renderSnaps() { var _this3 = this; if (!this.props.snaps) return undefined; return _react2.default.createElement( 'div', { className: this.props.theme.snaps }, (0, _utils.range)(0, (this.props.max - this.props.min) / this.props.step).map(function (i) { return _react2.default.createElement('div', { key: 'span-' + i, className: _this3.props.theme.snap }); }) ); } }, { key: 'renderInput', value: function renderInput() { var _this4 = this; if (!this.props.editable) return undefined; return _react2.default.createElement(Input, { innerRef: function innerRef(node) { _this4.inputNode = node; }, className: this.props.theme.input, disabled: this.props.disabled, onFocus: this.handleInputFocus, onChange: this.handleInputChange, onBlur: this.handleInputBlur, value: this.state.inputFocused ? this.state.inputValue : this.valueForInput(this.props.value) }); } }, { key: 'render', value: function render() { var _classnames, _this5 = this; var theme = this.props.theme; var knobStyles = { left: this.knobOffset() + '%' }; var className = (0, _classnames3.default)(theme.slider, (_classnames = {}, _defineProperty(_classnames, theme.editable, this.props.editable), _defineProperty(_classnames, theme.disabled, this.props.disabled), _defineProperty(_classnames, theme.pinned, this.props.pinned), _defineProperty(_classnames, theme.pressed, this.state.pressed), _defineProperty(_classnames, theme.ring, this.props.value === this.props.min), _classnames), this.props.className); return _react2.default.createElement( 'div', { className: className, disabled: this.props.disabled, 'data-react-toolbox': 'slider', onBlur: this.handleSliderBlur, onFocus: this.handleSliderFocus, style: this.props.style, tabIndex: '0' }, _react2.default.createElement( 'div', { ref: function ref(node) { _this5.sliderNode = node; }, className: theme.container, onMouseDown: this.handleMouseDown, onTouchStart: this.handleTouchStart }, _react2.default.createElement( 'div', { ref: function ref(node) { _this5.knobNode = node; }, className: theme.knob, onMouseDown: this.handleMouseDown, onTouchStart: this.handleTouchStart, style: knobStyles }, _react2.default.createElement('div', { className: theme.innerknob, 'data-value': parseInt(this.props.value, 10) }) ), _react2.default.createElement( 'div', { className: theme.progress }, _react2.default.createElement(ProgressBar, { disabled: this.props.disabled, ref: function ref(node) { _this5.progressbarNode = node; }, className: theme.innerprogress, max: this.props.max, min: this.props.min, mode: 'determinate', value: this.props.value, buffer: this.props.buffer }), this.renderSnaps() ) ), this.renderInput() ); } }]); return Slider; }(_react.Component); Slider.propTypes = { buffer: _propTypes2.default.number, className: _propTypes2.default.string, disabled: _propTypes2.default.bool, editable: _propTypes2.default.bool, max: _propTypes2.default.number, min: _propTypes2.default.number, onChange: _propTypes2.default.func, onDragStart: _propTypes2.default.func, onDragStop: _propTypes2.default.func, pinned: _propTypes2.default.bool, snaps: _propTypes2.default.bool, step: _propTypes2.default.number, style: _reactStyleProptype2.default, theme: _propTypes2.default.shape({ container: _propTypes2.default.string, editable: _propTypes2.default.string, innerknob: _propTypes2.default.string, innerprogress: _propTypes2.default.string, input: _propTypes2.default.string, knob: _propTypes2.default.string, pinned: _propTypes2.default.string, pressed: _propTypes2.default.string, progress: _propTypes2.default.string, ring: _propTypes2.default.string, slider: _propTypes2.default.string, snap: _propTypes2.default.string, snaps: _propTypes2.default.string }), value: _propTypes2.default.number }; Slider.defaultProps = { buffer: 0, className: '', editable: false, max: 100, min: 0, onDragStart: function onDragStart() {}, onDragStop: function onDragStop() {}, pinned: false, snaps: false, step: 0.01, value: 0 }; return Slider; }; var Slider = factory(_ProgressBar2.default, _Input2.default); exports.default = (0, _reactCssThemr.themr)(_identifiers.SLIDER)(Slider); exports.sliderFactory = factory; exports.Slider = Slider;