material-ui-number-input
Version:
The better TextField for number inputs.
305 lines (304 loc) • 13.1 kB
JavaScript
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
var React = require("react");
var PropTypes = require("prop-types");
var TextField_1 = require("material-ui/TextField");
var ObjectAssign = require("object-assign");
var bind_decorator_1 = require("bind-decorator");
var errorNames;
(function (errorNames) {
errorNames.none = 'none';
errorNames.invalidSymbol = 'invalidSymbol';
errorNames.incompleteNumber = 'incompleteNumber';
errorNames.singleMinus = 'singleMinus';
errorNames.singleFloatingPoint = 'singleFloatingPoint';
errorNames.singleZero = 'singleZero';
errorNames.min = 'min';
errorNames.max = 'max';
errorNames.required = 'required';
errorNames.clean = 'clean';
errorNames.allow = 'allow';
errorNames.limit = 'limit';
})(errorNames || (errorNames = {}));
var strategies;
(function (strategies) {
strategies.ignore = 'ignore';
strategies.warn = 'warn';
strategies.allow = 'allow';
})(strategies || (strategies = {}));
var typeofs;
(function (typeofs) {
typeofs.stringType = 'string';
typeofs.numberType = 'number';
})(typeofs || (typeofs = {}));
var constants;
(function (constants) {
constants.emptyString = '';
constants.dash = '-';
constants.dot = '.';
constants.zero = 0;
constants.one = 1;
constants.text = 'text';
constants.zeroString = '0';
constants.minusOne = -1;
constants.boolTrue = true;
constants.boolFalse = false;
})(constants || (constants = {}));
var NumberInput = (function (_super) {
__extends(NumberInput, _super);
function NumberInput(props) {
var _this = _super.call(this, props) || this;
_this.constProps = {
type: constants.text,
onChange: _this.onChange,
onBlur: _this.onBlur,
ref: _this.refTextField
};
return _this;
}
NumberInput.getValidValue = function (value) {
var match = value.match(NumberInput.allowed);
return match !== null ? (match.index === constants.zero ? match[constants.zero] : match.join(constants.emptyString)) : constants.emptyString;
};
NumberInput.deleteOwnProps = function (props) {
var prop;
for (var index = 0; index < NumberInput.deleteProps.length; ++index) {
prop = NumberInput.deleteProps[index];
if (props.hasOwnProperty(prop)) {
delete props[prop];
}
}
};
NumberInput.validateNumberValue = function (value, props) {
var max = props.max, min = props.min;
if ((typeof max === typeofs.numberType) && (value > max)) {
return constants.one;
}
if ((typeof min === typeofs.numberType) && (value < min)) {
return constants.minusOne;
}
return constants.zero;
};
NumberInput.validateValue = function (value, props) {
var required = props.required, strategy = props.strategy, min = props.min;
if (value === constants.emptyString) {
return required ? errorNames.required : errorNames.clean;
}
else {
if (value.match(NumberInput.validSymbols)) {
if (value.match(NumberInput.stricAllowed)) {
if (value.match(NumberInput.validNumber)) {
var numberValue = Number(value);
var floatingPoint = value.indexOf(constants.dot);
var decimal = floatingPoint > constants.minusOne;
var whole = decimal ? Number(value.substring(constants.zero, floatingPoint)) : min;
switch (NumberInput.validateNumberValue(numberValue, props)) {
case constants.one: return errorNames.max;
case constants.minusOne: return ((strategy !== strategies.allow) && (min > constants.zero) && (numberValue > constants.zero) && (!decimal || (decimal && (whole > min)))) ? errorNames.allow : errorNames.min;
default: return errorNames.none;
}
}
else {
return (strategy !== strategies.allow) && (value === constants.dash) && (min >= constants.zero)
? errorNames.limit : (min < 0 ? errorNames.allow : errorNames.incompleteNumber);
}
}
else {
switch (value[value.length - constants.one]) {
case constants.dash: return errorNames.singleMinus;
case constants.dot: return errorNames.singleFloatingPoint;
case constants.zeroString: return errorNames.singleZero;
default: return errorNames.invalidSymbol;
}
}
}
else {
return errorNames.invalidSymbol;
}
}
};
NumberInput.overrideRequestedValue = function (error, value, props) {
switch (error) {
case errorNames.min: return String(props.min);
case errorNames.max: return String(props.max);
default: return props.strategy !== strategies.allow && value === constants.dash && props.min >= 0 ? constants.emptyString : value;
}
};
NumberInput.overrideError = function (error, props) {
switch (error) {
case errorNames.allow: return errorNames.none;
case errorNames.limit: return props.required ? errorNames.required : errorNames.clean;
default: return error;
}
};
NumberInput.revertAllowToMin = function (error) {
return error === errorNames.allow ? errorNames.min : error;
};
NumberInput.emitValid = function (error, overridenError) {
return (error !== errorNames.allow) && (overridenError === errorNames.none);
};
NumberInput.prototype.emitEvents = function (nextError, value, valid, props) {
var onError = props.onError, onValid = props.onValid;
if ((this.error !== nextError) && (props.strategy !== strategies.ignore)) {
if (onError) {
onError(nextError);
}
this.error = nextError;
}
if (onValid && valid && (this.lastValid !== value)) {
onValid(Number(value));
this.lastValid = value;
}
};
NumberInput.prototype.takeActionForValue = function (value, props) {
var strategy = props.strategy, onRequestValue = props.onRequestValue, propsValue = props.value;
var error = NumberInput.validateValue(value, props);
var valid = NumberInput.overrideRequestedValue(error, NumberInput.getValidValue(value), props);
var overridenError = NumberInput.overrideError(error, props);
var emitValid = NumberInput.emitValid(error, overridenError);
this.emitEvents(overridenError, valid, emitValid, props);
if ((strategy !== strategies.allow) && (valid !== value)) {
if (typeof propsValue !== typeofs.stringType) {
this.getInputNode().value = valid;
}
else if (onRequestValue) {
onRequestValue(valid);
}
}
};
NumberInput.prototype.shouldTakeActionForValue = function (props) {
var _a = this.props, min = _a.min, max = _a.max, required = _a.required, strategy = _a.strategy;
return (min !== props.min) || (max !== props.max) || (required !== props.required) || (strategy !== props.strategy);
};
NumberInput.prototype.refTextField = function (textField) {
this.textField = textField;
};
NumberInput.prototype.onChange = function (event) {
var value = event.currentTarget.value;
var onChange = this.props.onChange;
if (onChange) {
onChange(event, value);
}
if (typeof this.props.value !== typeofs.stringType) {
this.takeActionForValue(value, this.props);
}
};
NumberInput.prototype.onBlur = function (event) {
var value = event.currentTarget.value;
var props = this.props;
var onBlur = props.onBlur;
var error = NumberInput.overrideError(NumberInput.revertAllowToMin(NumberInput.validateValue(value, props)), props);
this.emitEvents(error, value, constants.boolFalse, props);
if (onBlur) {
onBlur(event);
}
};
NumberInput.prototype.getInputNode = function () {
return this.textField.getInputNode();
};
NumberInput.prototype.getTextField = function () {
return this.textField;
};
NumberInput.prototype.componentDidMount = function () {
var props = this.props;
var value = props.value;
this.takeActionForValue(typeof value === typeofs.stringType ? value : this.getInputNode().value, props);
};
NumberInput.prototype.componentWillReceiveProps = function (props) {
var value = props.value;
if ((value !== this.props.value) || this.shouldTakeActionForValue(props)) {
this.takeActionForValue(value, props);
}
};
NumberInput.prototype.render = function () {
var _a = this, props = _a.props, constProps = _a.constProps;
var value = props.value, defaultValue = props.defaultValue;
var inputProps = ObjectAssign({}, props, constProps, {
defaultValue: typeof defaultValue === typeofs.numberType ? String(defaultValue) : undefined,
value: value,
});
if (typeof inputProps.value !== typeofs.stringType) {
delete inputProps.value;
}
if (inputProps.defaultValue === undefined) {
delete inputProps.defaultValue;
}
NumberInput.deleteOwnProps(inputProps);
return React.createElement(TextField_1.default, inputProps);
};
NumberInput.validSymbols = /(\-|\.|\d)+/;
NumberInput.stricAllowed = /^-?((0|([1-9]\d{0,}))(\.\d{0,})?)?$/;
NumberInput.validNumber = /^-?((0(\.\d+)?)|([1-9]\d{0,}(\.\d+)?))$/;
NumberInput.allowed = /-?((0|([1-9]\d{0,}))(\.\d{0,})?)?/;
NumberInput.deleteProps = ['strategy', 'onError', 'onValid', 'onRequestValue'];
NumberInput.propTypes = {
className: PropTypes.string,
disabled: PropTypes.bool,
errorStyle: PropTypes.object,
errorText: PropTypes.node,
floatingLabelFixed: PropTypes.bool,
floatingLabelFocusStyle: PropTypes.object,
floatingLabelStyle: PropTypes.object,
floatingLabelText: PropTypes.node,
fullWidth: PropTypes.bool,
hintStyle: PropTypes.object,
hintText: PropTypes.node,
id: PropTypes.string,
inputStyle: PropTypes.object,
name: PropTypes.string,
onBlur: PropTypes.func,
onChange: PropTypes.func,
onFocus: PropTypes.func,
onValid: PropTypes.func,
onError: PropTypes.func,
onRequestValue: PropTypes.func,
onKeyDown: PropTypes.func,
style: PropTypes.object,
underlineDisabledStyle: PropTypes.object,
underlineFocusStyle: PropTypes.object,
underlineShow: PropTypes.bool,
underlineStyle: PropTypes.object,
defaultValue: PropTypes.number,
min: PropTypes.number,
max: PropTypes.number,
required: PropTypes.bool,
strategy: PropTypes.oneOf([
strategies.ignore,
strategies.warn,
strategies.allow
]),
value: PropTypes.string
};
NumberInput.defaultProps = {
required: constants.boolFalse,
strategy: strategies.allow
};
__decorate([
bind_decorator_1.default
], NumberInput.prototype, "refTextField", null);
__decorate([
bind_decorator_1.default
], NumberInput.prototype, "onChange", null);
__decorate([
bind_decorator_1.default
], NumberInput.prototype, "onBlur", null);
return NumberInput;
}(React.Component));
exports.NumberInput = NumberInput;
exports.default = NumberInput;
;