react-ios-switch
Version:
React switch component
338 lines (296 loc) • 11.1 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
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 _popmotion = require('popmotion');
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _normalizeColor = require('./normalizeColor');
var _normalizeColor2 = _interopRequireDefault(_normalizeColor);
var _prefixStyle = require('./prefixStyle');
var _prefixStyle2 = _interopRequireDefault(_prefixStyle);
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 = {
isDragging: false,
offset: null
};
_this.handleChange = _this.handleChange.bind(_this);
_this.handleClick = _this.handleClick.bind(_this);
_this.handleHandleClick = _this.handleHandleClick.bind(_this);
_this.handleMouseDown = _this.handleMouseDown.bind(_this);
_this.handleMouseUp = _this.handleMouseUp.bind(_this);
_this.setRef = _this.setRef.bind(_this);
return _this;
}
_createClass(Switch, [{
key: 'clickChange',
value: function clickChange(checked) {
if (this.ref.parentNode && this.ref.parentNode.tagName.toLowerCase() === 'label') {
// if the parent is a label, we don't need to emit the change event ourselves
return;
}
this.props.onChange(checked);
}
}, {
key: 'componentDidMount',
value: function componentDidMount() {
window.addEventListener('mouseup', this.handleMouseUp);
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
window.removeEventListener('mouseup', this.handleMouseUp);
}
}, {
key: 'getHandleColor',
value: function getHandleColor() {
return (0, _normalizeColor2.default)(this.props.handleColor);
}
}, {
key: 'getHandleCursor',
value: function getHandleCursor() {
if (this.isDisabled()) {
return 'default';
}
return this.state.isDragging ? 'grabbing' : 'grab';
}
}, {
key: 'getHandleLength',
value: function getHandleLength() {
return this.getHeight() - 2;
}
}, {
key: 'getHeight',
value: function getHeight() {
return 30;
}
}, {
key: 'getOffColor',
value: function getOffColor() {
return (0, _normalizeColor2.default)(this.props.offColor);
}
}, {
key: 'getOffset',
value: function getOffset() {
if (this.state.isDragging) {
return this.state.offset;
}
return this.props.checked ? this.getOffsetWidth() : 0;
}
}, {
key: 'getOffsetProgress',
value: function getOffsetProgress() {
return this.getOffset() / this.getOffsetWidth();
}
}, {
key: 'getOffsetWidth',
value: function getOffsetWidth(props) {
return this.getWidth() - this.getHandleLength() - 2;
}
}, {
key: 'getOnColor',
value: function getOnColor() {
return (0, _normalizeColor2.default)(this.props.onColor);
}
}, {
key: 'getPendingColor',
value: function getPendingColor(_ref) {
var color = _ref.color,
pendingColor = _ref.pendingColor;
if (!pendingColor) {
return color === 'white' ?
// default pending color for white color
'#dfdfdf' : (0, _normalizeColor2.default)(color);
}
return (0, _normalizeColor2.default)(pendingColor);
}
}, {
key: 'getPendingOffColor',
value: function getPendingOffColor() {
return this.getPendingColor({
color: this.props.offColor,
pendingColor: this.props.pendingOffColor
});
}
}, {
key: 'getPendingOnColor',
value: function getPendingOnColor() {
return this.getPendingColor({
color: this.props.onColor,
pendingColor: this.props.pendingOnColor
});
}
}, {
key: 'getWidth',
value: function getWidth() {
return 50;
}
}, {
key: 'handleChange',
value: function handleChange(e) {
this.props.onChange(e.target.checked);
}
}, {
key: 'handleClick',
value: function handleClick(e) {
if (this.isDisabled()) {
return;
}
// handle case when the switch is clicked
this.clickChange(!this.props.checked);
}
}, {
key: 'handleHandleClick',
value: function handleHandleClick(e) {
e.stopPropagation();
}
}, {
key: 'handleMouseDown',
value: function handleMouseDown(e) {
var _this2 = this;
if (this.isDisabled()) {
return;
}
this.pointerTracker = (0, _popmotion.pointer)(e).start();
this.offsetTracker = (0, _popmotion.trackOffset)(this.pointerTracker.x, {
from: this.getOffset(),
onUpdate: _popmotion.transform.pipe(_popmotion.transform.clamp(0, this.getOffsetWidth()), function (offset) {
return _this2.setState({ offset: offset });
})
}).start();
this.setState({
isDragging: true,
offset: this.getOffset()
});
}
}, {
key: 'handleMouseUp',
value: function handleMouseUp() {
if (!this.state.isDragging) {
return;
}
this.pointerTracker.stop();
this.offsetTracker.stop();
var prevOffset = this.props.checked ? this.getOffsetWidth() : 0;
var checked = this.state.offset === prevOffset ?
// handle case when the handle is clicked
!this.props.checked :
// handle case when the handle is dragged
this.getOffsetProgress() >= 0.5;
this.setState({
isDragging: false,
offset: null
});
this.clickChange(checked);
}
}, {
key: 'isDisabled',
value: function isDisabled() {
return this.props.disabled || this.props.readOnly;
}
}, {
key: 'render',
value: function render() {
var _props = this.props,
checked = _props.checked,
className = _props.className,
disabled = _props.disabled,
name = _props.name,
onChange = _props.onChange,
readOnly = _props.readOnly,
style = _props.style;
var isDragging = this.state.isDragging;
var color = _popmotion.transform.pipe(_popmotion.easing.createExpoIn(2), _popmotion.transform.blendColor(this.getOffColor(), this.getOnColor()), _popmotion.transform.rgba)(this.getOffsetProgress());
var borderColor = _popmotion.transform.pipe(_popmotion.easing.createExpoIn(1), _popmotion.transform.blendColor(this.getPendingOffColor(), this.getPendingOnColor()), _popmotion.transform.rgba)(this.getOffsetProgress());
return _react2.default.createElement(
'span',
{
className: className,
onClick: this.handleClick,
ref: this.setRef,
style: _extends({}, (0, _prefixStyle2.default)({
backgroundColor: color,
border: '1px solid ' + borderColor,
borderRadius: this.getHeight() / 2,
boxShadow: 'inset 0 0 0 ' + this.getOffset() + 'px ' + borderColor,
boxSizing: 'border-box',
display: 'inline-block',
height: this.getHeight(),
opacity: this.isDisabled() ? 0.5 : 1,
position: 'relative',
transition: isDragging ? null : '0.2s',
userSelect: 'none',
width: this.getWidth()
}), style)
},
_react2.default.createElement('span', {
onClick: this.handleHandleClick,
onMouseDown: this.handleMouseDown,
style: (0, _prefixStyle2.default)({
backgroundColor: this.getHandleColor(),
borderRadius: '100%',
boxShadow: '0 1px 3px rgba(0, 0, 0, 0.4)',
cursor: this.getHandleCursor(),
display: 'inline-block',
height: this.getHandleLength(),
left: this.getOffset(),
position: 'absolute',
top: 0,
transition: isDragging ? null : '0.2s',
width: this.getHandleLength()
})
}),
_react2.default.createElement('input', {
checked: checked,
disabled: disabled,
name: name,
onChange: this.handleChange,
readOnly: readOnly,
style: {
display: 'none'
},
type: 'checkbox'
})
);
}
}, {
key: 'setRef',
value: function setRef(ref) {
this.ref = ref;
}
}]);
return Switch;
}(_react2.default.Component);
Switch.propTypes = {
checked: _propTypes2.default.bool,
className: _propTypes2.default.string,
disabled: _propTypes2.default.bool,
handleColor: _propTypes2.default.string,
name: _propTypes2.default.string,
offColor: _propTypes2.default.string,
onChange: _propTypes2.default.func,
onColor: _propTypes2.default.string,
pendingOffColor: _propTypes2.default.string,
pendingOnColor: _propTypes2.default.string,
readOnly: _propTypes2.default.bool,
style: _propTypes2.default.object
};
Switch.defaultProps = {
handleColor: 'white',
offColor: 'white',
onChange: function onChange() {},
onColor: 'rgb(76, 217, 100)'
};
exports.default = Switch;