UNPKG

react-widgets

Version:

An à la carte set of polished, extensible, and accessible inputs built for React

340 lines (277 loc) 10.7 kB
'use strict'; var babelHelpers = require('./util/babelHelpers.js'); exports.__esModule = true; var _react = require('react'); var _react2 = babelHelpers.interopRequireDefault(_react); var _classnames = require('classnames'); var _classnames2 = babelHelpers.interopRequireDefault(_classnames); var _util_ = require('./util/_'); var _util_2 = babelHelpers.interopRequireDefault(_util_); var _utilCompat = require('./util/compat'); var _utilCompat2 = babelHelpers.interopRequireDefault(_utilCompat); var _utilPropTypes = require('./util/propTypes'); var _utilPropTypes2 = babelHelpers.interopRequireDefault(_utilPropTypes); var _uncontrollable = require('uncontrollable'); var _uncontrollable2 = babelHelpers.interopRequireDefault(_uncontrollable); var _utilConstants = require('./util/constants'); var _utilConstants2 = babelHelpers.interopRequireDefault(_utilConstants); var _utilRepeater = require('./util/repeater'); var _utilRepeater2 = babelHelpers.interopRequireDefault(_utilRepeater); var _utilLocalizers = require('./util/localizers'); var _NumberInput = require('./NumberInput'); var _NumberInput2 = babelHelpers.interopRequireDefault(_NumberInput); var _WidgetButton = require('./WidgetButton'); var _WidgetButton2 = babelHelpers.interopRequireDefault(_WidgetButton); var _utilInteraction = require('./util/interaction'); var _utilWidgetHelpers = require('./util/widgetHelpers'); var directions = _utilConstants2['default'].directions; var format = function format(props) { return _utilLocalizers.number.getFormat('default', props.format); }; var propTypes = { // -- controlled props ----------- value: _react2['default'].PropTypes.number, onChange: _react2['default'].PropTypes.func, //------------------------------------ min: _react2['default'].PropTypes.number, max: _react2['default'].PropTypes.number, step: _react2['default'].PropTypes.number, precision: _react2['default'].PropTypes.number, culture: _react2['default'].PropTypes.string, format: _utilPropTypes2['default'].numberFormat, name: _react2['default'].PropTypes.string, parse: _react2['default'].PropTypes.func, autoFocus: _react2['default'].PropTypes.bool, disabled: _utilPropTypes2['default'].disabled, readOnly: _utilPropTypes2['default'].readOnly, messages: _react2['default'].PropTypes.shape({ increment: _react2['default'].PropTypes.string, decrement: _react2['default'].PropTypes.string }), placeholder: _react2['default'].PropTypes.string }; var NumberPicker = _react2['default'].createClass(babelHelpers.createDecoratedObject([{ key: 'displayName', initializer: function initializer() { return 'NumberPicker'; } }, { key: 'mixins', initializer: function initializer() { return [require('./mixins/TimeoutMixin'), require('./mixins/PureRenderMixin'), require('./mixins/RtlParentContextMixin')]; } }, { key: 'propTypes', initializer: function initializer() { return propTypes; } }, { key: 'getDefaultProps', value: function getDefaultProps() { return { value: null, open: false, min: -Infinity, max: Infinity, step: 1, messages: { increment: 'increment value', decrement: 'decrement value' } }; } }, { key: 'getInitialState', value: function getInitialState() { return { focused: false, active: false }; } }, { key: 'render', value: function render() { var _$omit = _util_2['default'].omit(this.props, Object.keys(propTypes)); var className = _$omit.className; var onKeyPress = _$omit.onKeyPress; var onKeyUp = _$omit.onKeyUp; var autoFocus = _$omit.autoFocus; var props = babelHelpers.objectWithoutProperties(_$omit, ['className', 'onKeyPress', 'onKeyUp', 'autoFocus']); var val = this.constrainValue(this.props.value); return _react2['default'].createElement( 'div', babelHelpers._extends({}, props, { ref: 'element', onKeyDown: this._keyDown, onFocus: this._focus.bind(null, true), onBlur: this._focus.bind(null, false), tabIndex: '-1', className: _classnames2['default'](className, 'rw-numberpicker', 'rw-widget', { 'rw-state-focus': this.state.focused, 'rw-state-disabled': this.props.disabled, 'rw-state-readonly': this.props.readOnly, 'rw-rtl': this.isRtl() }) }), _react2['default'].createElement( 'span', { className: 'rw-select' }, _react2['default'].createElement( _WidgetButton2['default'], { tabIndex: '-1', className: _classnames2['default']({ 'rw-state-active': this.state.active === directions.UP }), onMouseDown: this._mouseDown.bind(null, directions.UP), onMouseUp: this._mouseUp.bind(null, directions.UP), onMouseLeave: this._mouseUp.bind(null, directions.UP), onClick: this._focus.bind(null, true), disabled: val === this.props.max || this.props.disabled, 'aria-disabled': val === this.props.max || this.props.disabled }, _react2['default'].createElement( 'i', { className: 'rw-i rw-i-caret-up' }, _react2['default'].createElement( 'span', { className: 'rw-sr' }, this.props.messages.increment ) ) ), _react2['default'].createElement( _WidgetButton2['default'], { tabIndex: '-1', className: _classnames2['default']({ 'rw-state-active': this.state.active === directions.DOWN }), onMouseDown: this._mouseDown.bind(null, directions.DOWN), onMouseUp: this._mouseUp.bind(null, directions.DOWN), onMouseLeave: this._mouseUp.bind(null, directions.DOWN), onClick: this._focus.bind(null, true), disabled: val === this.props.min || this.props.disabled, 'aria-disabled': val === this.props.min || this.props.disabled }, _react2['default'].createElement( 'i', { className: 'rw-i rw-i-caret-down' }, _react2['default'].createElement( 'span', { className: 'rw-sr' }, this.props.messages.decrement ) ) ) ), _react2['default'].createElement(_NumberInput2['default'], { ref: 'input', tabIndex: props.tabIndex, placeholder: this.props.placeholder, value: val, autoFocus: autoFocus, editing: this.state.focused, format: this.props.format, parse: this.props.parse, name: this.props.name, role: 'spinbutton', min: this.props.min, 'aria-valuenow': val, 'aria-valuemin': isFinite(this.props.min) ? this.props.min : null, 'aria-valuemax': isFinite(this.props.max) ? this.props.max : null, 'aria-disabled': this.props.disabled, 'aria-readonly': this.props.readonly, disabled: this.props.disabled, readOnly: this.props.readOnly, onChange: this.change, onKeyPress: onKeyPress, onKeyUp: onKeyUp }) ); } }, { key: '_mouseDown', decorators: [_utilInteraction.widgetEditable], value: function _mouseDown(dir) { var method = dir === directions.UP ? this.increment : this.decrement; this.setState({ active: dir }); var val = method.call(this); if (!(dir === directions.UP && val === this.props.max || dir === directions.DOWN && val === this.props.min)) { if (!this._cancelRepeater) this._cancelRepeater = _utilRepeater2['default'](this._mouseDown.bind(null, dir)); } else this._mouseUp(); } }, { key: '_mouseUp', decorators: [_utilInteraction.widgetEditable], value: function _mouseUp() { this.setState({ active: false }); this._cancelRepeater && this._cancelRepeater(); this._cancelRepeater = null; } }, { key: '_focus', decorators: [_utilInteraction.widgetEnabled], value: function _focus(focused, e) { var _this = this; focused && _utilCompat2['default'].findDOMNode(this.refs.input).focus(); this.setTimeout('focus', function () { if (focused !== _this.state.focused) { _utilWidgetHelpers.notify(_this.props[focused ? 'onFocus' : 'onBlur'], e); _this.setState({ focused: focused }); } }, 0); } }, { key: '_keyDown', decorators: [_utilInteraction.widgetEditable], value: function _keyDown(e) { var key = e.key; _utilWidgetHelpers.notify(this.props.onKeyDown, [e]); if (e.defaultPrevented) return; if (key === 'End' && isFinite(this.props.max)) this.change(this.props.max);else if (key === 'Home' && isFinite(this.props.min)) this.change(this.props.min);else if (key === 'ArrowDown') { e.preventDefault(); this.decrement(); } else if (key === 'ArrowUp') { e.preventDefault(); this.increment(); } } }, { key: 'increment', value: function increment() { return this.step(this.props.step); } }, { key: 'decrement', value: function decrement() { return this.step(-this.props.step); } }, { key: 'step', value: function step(amount) { var value = (this.props.value || 0) + amount; var decimals = this.props.precision != null ? this.props.precision : _utilLocalizers.number.precision(format(this.props)); this.change(decimals != null ? round(value, decimals) : value); return value; } }, { key: 'change', value: function change(val) { val = this.constrainValue(val); if (this.props.value !== val) _utilWidgetHelpers.notify(this.props.onChange, val); } }, { key: 'constrainValue', value: function constrainValue(value) { var max = this.props.max == null ? Infinity : this.props.max, min = this.props.min == null ? -Infinity : this.props.min; if (value == null || value === '') return null; return Math.max(Math.min(value, max), min); } }])); exports['default'] = _uncontrollable2['default'](NumberPicker, { value: 'onChange' }); // thank you kendo ui core // https://github.com/telerik/kendo-ui-core/blob/master/src/kendo.core.js#L1036 function round(value, precision) { precision = precision || 0; value = ('' + value).split('e'); value = Math.round(+(value[0] + 'e' + (value[1] ? +value[1] + precision : precision))); value = ('' + value).split('e'); value = +(value[0] + 'e' + (value[1] ? +value[1] - precision : -precision)); return value.toFixed(precision); } module.exports = exports['default']; //allow for styling, focus stealing keeping me from the normal what have you