UNPKG

react-bootstrap-switch

Version:

Turn checkboxes and radio buttons into toggle switches.

571 lines (455 loc) 16.5 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); 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 _reactDom = require('react-dom'); var _reactDom2 = _interopRequireDefault(_reactDom); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: 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 Switch = function (_React$Component) { _inherits(Switch, _React$Component); function Switch(props) { _classCallCheck(this, Switch); var _this = _possibleConstructorReturn(this, (Switch.__proto__ || Object.getPrototypeOf(Switch)).call(this, props)); _this.state = { offset: 0, skipAnimation: true, dragStart: false, focus: false, value: props.value != undefined ? props.value : props.defaultValue, labelWidth: props.labelWidth, handleWidth: props.handleWidth }; return _this; } _createClass(Switch, [{ key: 'componentDidMount', value: function componentDidMount() { this._recalculateWidth(); } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { var _this2 = this; var newValue = nextProps.value !== undefined ? nextProps.value : this.state.value; var oldValue = this.state.value; // ensure width is updated this.setState({ labelWidth: nextProps.labelWidth, handleWidth: nextProps.handleWidth, value: newValue }, function () { _this2._recalculateWidth(newValue == oldValue); }); } }, { key: '_getValue', value: function _getValue() { if (this.props.value !== undefined) return this.props.value; return this.state.value; } }, { key: 'value', value: function value(val) { if (val === undefined) return this.state.value; var newVal = val === null ? null : !!val; this._setValue(newVal); return newVal; } }, { key: '_wrapperClasses', value: function _wrapperClasses() { var _props = this.props, baseClass = _props.baseClass, wrapperClass = _props.wrapperClass, bsSize = _props.bsSize, disabled = _props.disabled, readonly = _props.readonly, inverse = _props.inverse, tristate = _props.tristate, animate = _props.animate, id = _props.id; var _state = this.state, skipAnimation = _state.skipAnimation, focus = _state.focus, dragStart = _state.dragStart; var value = this._getValue(); var classes = [baseClass, wrapperClass]; classes.push(baseClass + (value ? "-on" : "-off")); if (bsSize) classes.push(baseClass + "-" + bsSize); if (disabled) classes.push(baseClass + "-disabled"); if (readonly) classes.push(baseClass + "-readonly"); if (value === null) classes.push(baseClass + "-indeterminate"); if (inverse) classes.push(baseClass + "-inverse"); if (tristate) classes.push(baseClass + "-tristate"); if (id) classes.push(baseClass + "-" + id); if (animate && !dragStart && !skipAnimation) classes.push(baseClass + "-animate"); if (focus) classes.push(baseClass + "-focused"); return classes.join(" "); } }, { key: '_recalculateWidth', value: function _recalculateWidth(animate) { var _this3 = this; var onHandle = _reactDom2.default.findDOMNode(this.elmOnHandle); var offHandle = _reactDom2.default.findDOMNode(this.elmOffHandle); var label = _reactDom2.default.findDOMNode(this.elmLabel); // assuming that if the elms need to be resized, the size will be cleared elsewhere first var _props2 = this.props, handleWidth = _props2.handleWidth, labelWidth = _props2.labelWidth; var newHandleWidth = handleWidth == "auto" ? Math.max(onHandle.offsetWidth, offHandle.offsetWidth) : handleWidth; var newLabelWidth = labelWidth == "auto" ? Math.max(newHandleWidth, label.offsetWidth) : labelWidth; return this.setState({ handleWidth: newHandleWidth, labelWidth: newLabelWidth }, function () { _this3._updateContainerPosition(!animate); }); } }, { key: '_updateContainerPosition', value: function _updateContainerPosition(noAnimate) { var _state2 = this.state, handleWidth = _state2.handleWidth, offset = _state2.offset; var inverse = this.props.inverse; var value = this._getValue(); // skip animating if no offset yet var skipAnimation = noAnimate || offset == null; var newOffset = offset; if (handleWidth === 'auto') { newOffset = 0; } else if (value === null) { newOffset = -(handleWidth / 2); } else if (value) { newOffset = inverse ? -handleWidth : 0; } else { newOffset = inverse ? 0 : -handleWidth; } return this.setState({ skipAnimation: skipAnimation, offset: newOffset }); } }, { key: '_disableUserInput', value: function _disableUserInput() { var _props3 = this.props, disabled = _props3.disabled, readonly = _props3.readonly; return disabled || readonly; } }, { key: '_handleOnClick', value: function _handleOnClick() { if (this._disableUserInput()) return; this._setValue(this.props.tristate ? this._getValue() == null : false); this._setFocus(); } }, { key: '_handleOffClick', value: function _handleOffClick() { if (this._disableUserInput()) return; this._setValue(this.props.tristate ? this._getValue() != null : true); this._setFocus(); } }, { key: '_handleKeyPress', value: function _handleKeyPress(e) { if (!e.which || this._disableUserInput()) return; var inverse = this.props.inverse; switch (e.which) { case 37: return this._setValue(inverse); case 39: return this._setValue(!inverse); } } }, { key: '_handleLabelMouseDown', value: function _handleLabelMouseDown(e) { if (this.state.dragStart || this._disableUserInput()) return; this.setState({ dragStart: (e.pageX || e.touches[0].pageX) - this.state.offset }); this._setFocus(); } }, { key: '_handleLabelMouseMove', value: function _handleLabelMouseMove(e) { var _state3 = this.state, dragStart = _state3.dragStart, handleWidth = _state3.handleWidth; if (dragStart === undefined || dragStart === null || dragStart === false) return; var difference = (e.pageX || e.touches[0].pageX) - dragStart; if (difference < -handleWidth || difference > 0) return; this.setState({ skipAnimation: false, offset: difference, dragged: true }); } }, { key: '_handleLabelTouchEnd', value: function _handleLabelTouchEnd() { var _this4 = this; var _state4 = this.state, dragStart = _state4.dragStart, dragged = _state4.dragged, offset = _state4.offset, handleWidth = _state4.handleWidth; if (dragStart === undefined || dragStart === null || dragStart === false) return; // If the touch ended without motion, then either a mousedown event should fire, or it was a long press and should do nothing if (!dragged || dragged === undefined || dragged === null) { this.setState({ dragStart: false, dragged: false }); return; } var inverse = this.props.inverse; var val = offset > -(handleWidth / 2); val = inverse ? !val : val; this.setState({ dragStart: false, dragged: false, value: val }, function () { _this4._updateContainerPosition(); _this4._fireStateChange(val); }); } }, { key: '_handleLabelMouseUp', value: function _handleLabelMouseUp() { var _this5 = this; var _state5 = this.state, dragStart = _state5.dragStart, dragged = _state5.dragged, offset = _state5.offset, handleWidth = _state5.handleWidth; var value = this._getValue(); if (dragStart === undefined || dragStart === null || dragStart === false) return; var _props4 = this.props, inverse = _props4.inverse, tristate = _props4.tristate; var val = void 0; if (dragged) { val = offset > -(handleWidth / 2); val = inverse ? !val : val; } else if (tristate) { val = value === null ? true : null; } else { val = !value; } this.setState({ dragStart: false, dragged: false, value: val }, function () { _this5._updateContainerPosition(); _this5._fireStateChange(val); }); } }, { key: '_setFocus', value: function _setFocus() { this.setState({ focus: true }); } }, { key: '_setBlur', value: function _setBlur() { this.setState({ focus: false }); } }, { key: '_setValue', value: function _setValue(val) { var _this6 = this; var value = this._getValue(); if (val === value) return; var newValue = val === undefined ? !value : val; this.setState({ value: newValue }, function () { _this6._updateContainerPosition(); _this6._fireStateChange(newValue); }); } }, { key: '_fireStateChange', value: function _fireStateChange(newValue) { var _this7 = this; var onChange = this.props.onChange; if (typeof onChange != "function") return; setTimeout(function () { return onChange(_this7, newValue); }, 0); } }, { key: 'render', value: function render() { var _props5 = this.props, baseClass = _props5.baseClass, inverse = _props5.inverse; var _state6 = this.state, handleWidth = _state6.handleWidth, labelWidth = _state6.labelWidth, offset = _state6.offset; var onHandle = this._renderOnHandle(); var offHandle = this._renderOffHandle(); var containerWidth = labelWidth + handleWidth * 2; var wrapperWidth = labelWidth + handleWidth; if (containerWidth == wrapperWidth || handleWidth == "auto" || labelWidth == "auto") containerWidth = wrapperWidth = "auto"; var wrapperParams = { className: this._wrapperClasses(), style: { width: wrapperWidth }, tabIndex: "0", onKeyDown: this._handleKeyPress.bind(this), onFocus: this._setFocus.bind(this), onBlur: this._setBlur.bind(this) }; var containerParams = { className: baseClass + '-container', style: { width: containerWidth, marginLeft: offset } }; return _react2.default.createElement( 'div', wrapperParams, _react2.default.createElement( 'div', containerParams, inverse ? offHandle : onHandle, this._renderLabel(), inverse ? onHandle : offHandle ) ); } }, { key: '_renderOnHandle', value: function _renderOnHandle() { var _this8 = this; var _props6 = this.props, baseClass = _props6.baseClass, onColor = _props6.onColor, onText = _props6.onText; var handleWidth = this.state.handleWidth; var params = { ref: function ref(e) { return _this8.elmOnHandle = e; }, style: { width: handleWidth }, className: baseClass + '-handle-on ' + baseClass + '-' + onColor, onClick: this._handleOnClick.bind(this) }; return _react2.default.createElement( 'span', params, onText ); } }, { key: '_renderOffHandle', value: function _renderOffHandle() { var _this9 = this; var _props7 = this.props, baseClass = _props7.baseClass, offColor = _props7.offColor, offText = _props7.offText; var handleWidth = this.state.handleWidth; var params = { ref: function ref(e) { return _this9.elmOffHandle = e; }, style: { width: handleWidth }, className: baseClass + '-handle-off ' + baseClass + '-' + offColor, onClick: this._handleOffClick.bind(this) }; return _react2.default.createElement( 'span', params, offText ); } }, { key: '_renderLabel', value: function _renderLabel() { var _this10 = this; var _props8 = this.props, baseClass = _props8.baseClass, labelText = _props8.labelText; var labelWidth = this.state.labelWidth; var params = { ref: function ref(e) { return _this10.elmLabel = e; }, style: { width: labelWidth }, className: baseClass + '-label', onTouchStart: this._handleLabelMouseDown.bind(this), onTouchMove: this._handleLabelMouseMove.bind(this), onTouchEnd: this._handleLabelTouchEnd.bind(this), onMouseDown: this._handleLabelMouseDown.bind(this), onMouseMove: this._handleLabelMouseMove.bind(this), onMouseUp: this._handleLabelMouseUp.bind(this), onMouseLeave: this._handleLabelMouseUp.bind(this) }; return _react2.default.createElement( 'span', params, labelText ); } }]); return Switch; }(_react2.default.Component); exports.default = Switch; Switch.defaultProps = { baseClass: 'bootstrap-switch', wrapperClass: 'wrapper', bsSize: null, handleWidth: 'auto', labelWidth: 'auto', onColor: 'primary', offColor: 'default', onText: 'ON', offText: 'OFF', labelText: ' ', inverse: false, animate: true, disabled: false, readonly: false, tristate: false, defaultValue: true, value: undefined }; Switch.propTypes = { baseClass: _propTypes2.default.string, wrapperClass: _propTypes2.default.string, bsSize: _propTypes2.default.string, handleWidth: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.number]), labelWidth: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.number]), onColor: _propTypes2.default.string, offColor: _propTypes2.default.string, onText: _propTypes2.default.node, offText: _propTypes2.default.node, labelText: _propTypes2.default.node, inverse: _propTypes2.default.bool, animate: _propTypes2.default.bool, disabled: _propTypes2.default.bool, readonly: _propTypes2.default.bool, tristate: _propTypes2.default.bool, defaultValue: _propTypes2.default.bool, value: _propTypes2.default.bool, onChange: _propTypes2.default.func };