tiny-mobx-form
Version:
Tiny (~2KB) tree-shakable MobX form library
415 lines (346 loc) • 12.2 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var tslib = require('tslib');
var mobx = require('mobx');
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);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _extends() {
_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;
};
return _extends.apply(this, arguments);
}
var error = function error(isError, message) {
if (message === void 0) {
message = '';
}
return isError ? message : undefined;
};
var MESSAGES = {
required: function required() {
return "This field is required.";
},
requiredIf: function requiredIf(dependentLabel, label) {
return "The " + dependentLabel + " field is required since the " + label + " field is filled out.";
},
length: function length(min, max) {
return "Must be at least " + min + " and no more than " + max + " characters";
},
match: function match(label, matchingLabel) {
return "The " + label + " and " + matchingLabel + " do not match.";
},
letters: function letters() {
return "Please enter letters only.";
},
email: function email() {
return "Please enter a valid email address.";
},
phone: function phone() {
return "Please enter a valid phone number.";
},
postal: function postal() {
return "Please enter a valid postal number.";
},
number: function number() {
return "Please enter a valid number.";
},
alpha: function alpha() {
return "Please do not use special characters.";
},
size: function size(min, max) {
return "Please enter a number between " + min + " and " + max + ".";
},
oneOf: function oneOf(pool) {
return "Please choose one of these choices: " + pool.join(', ');
}
};
var required = function required(field, message) {
return error(!field.value, message || MESSAGES.required());
};
var requiredIf = function requiredIf(field, message, dependentFieldName) {
return error(!(!!field.value && !!field.form.fields[dependentFieldName]), message || MESSAGES.requiredIf(field.form.fields[dependentFieldName].label, field.label));
};
var length = function length(field, message, min, max) {
if (min === void 0) {
min = 0;
}
if (max === void 0) {
max = Infinity;
}
return error(!(!!field.value && field.value.length >= Number(min) && field.value.length <= Number(max)), message || MESSAGES.length(min.toString(10), max.toString(10)));
};
var match = function match(field, message, matchingFieldName) {
return error(field.value !== field.form.fields[matchingFieldName].value, message || MESSAGES.match(field.label, field.form.fields[matchingFieldName].label));
};
var LETTERS = /^[a-zA-Z\s]*$/;
var letters = function letters(_ref, message) {
var value = _ref.value;
return error(!!value && !LETTERS.test(value), message || MESSAGES.letters());
};
var EMAIL = /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/;
var email = function email(_ref2, message) {
var value = _ref2.value;
return error(!!value && !EMAIL.test(value), message || MESSAGES.email());
};
var PHONE_NUMBER = /^(\()?[2-9]\d{2}(-|.|\))?\d{3}(-|.)?\d{4}$/;
var phone = function phone(_ref3, message) {
var value = _ref3.value;
return error(!!value && !PHONE_NUMBER.test(value), message || MESSAGES.phone());
};
var POSTAL = /^\d{5}-\d{4}|\d{5}|[A-Z]\d[A-Z] \d[A-Z]\d$/;
var postal = function postal(_ref4, message) {
var value = _ref4.value;
return error(!!value && !POSTAL.test(value), message || MESSAGES.postal());
};
var NUMBER = /^\d+$/;
var numbers = function numbers(_ref5, message) {
var value = _ref5.value;
return error(!!value && !NUMBER.test(value), message || MESSAGES.number());
};
var ALPHA = /^\w+$/;
var alpha = function alpha(_ref6, message) {
var value = _ref6.value;
return error(!!value && !ALPHA.test(value), message || MESSAGES.alpha());
};
var size = function size(_ref7, message, min, max) {
var value = _ref7.value;
if (min === void 0) {
min = 0;
}
if (max === void 0) {
max = Infinity;
}
return error(!!value && !(Number(value) >= min && Number(value) <= max), message || MESSAGES.size(min.toString(10), max.toString(10)));
};
var oneOf = function oneOf(_ref8, message) {
var value = _ref8.value;
for (var _len = arguments.length, pool = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
pool[_key - 2] = arguments[_key];
}
return error(!!value && !pool.includes(value), message || MESSAGES.oneOf(pool));
};
function validate(field, validatorMessages, validators) {
if (!field.validation) return [];
var validations = field.validation.split('|').filter(Boolean);
return validations.map(function (validation) {
var _validation$split = validation.split(':'),
validator = _validation$split[0],
argument = _validation$split[1];
var args = [];
if (argument) {
// Handle the arguments passed in
args = argument.split(',');
}
if (!(validator in validators)) {
throw new Error("There is no validator with the name of " + validator);
}
var message = validatorMessages && validator in validatorMessages ? validatorMessages[validator] : '';
return validators[validator].apply(validators, [field, message].concat(args));
}).filter(Boolean);
}
var validators = function validators(additionalValidators) {
if (additionalValidators === void 0) {
additionalValidators = {};
}
return _extends({
required: required,
'required-if': requiredIf,
length: length,
letters: letters,
email: email,
match: match,
numbers: numbers,
phone: phone,
postal: postal,
alpha: alpha,
size: size,
'one-of': oneOf
}, additionalValidators);
};
var Field =
/*#__PURE__*/
function () {
function Field(form, _ref, _ref2) {
var name = _ref.name,
_ref$label = _ref.label,
label = _ref$label === void 0 ? '' : _ref$label,
_ref$placeholder = _ref.placeholder,
placeholder = _ref$placeholder === void 0 ? '' : _ref$placeholder,
_ref$validation = _ref.validation,
validation = _ref$validation === void 0 ? '' : _ref$validation,
_ref$initialValue = _ref.initialValue,
initialValue = _ref$initialValue === void 0 ? '' : _ref$initialValue,
_ref$validationMessag = _ref.validationMessages,
validationMessages = _ref$validationMessag === void 0 ? {} : _ref$validationMessag;
var additionalValidators = _ref2.additionalValidators;
this.form = form;
this.isTouched = false;
this.isFocused = false;
this.name = name;
this.label = label;
this.placeholder = placeholder;
this.initialValue = initialValue;
this._value = initialValue;
this.validation = validation;
this.validators = additionalValidators;
this.validationMessages = validationMessages;
}
var _proto = Field.prototype;
_proto.reset = function reset() {
this._value = this.initialValue;
this.isTouched = false;
this.isFocused = false;
};
_createClass(Field, [{
key: "value",
get: function get() {
return this._value;
},
set: function set(value) {
this._value = value;
this.isTouched = true;
}
}, {
key: "isValid",
get: function get() {
return this.errors.length === 0;
}
}, {
key: "isDirty",
get: function get() {
return this.initialValue !== this.value;
}
}, {
key: "errors",
get: function get() {
return this.validators ? validate(this, this.validationMessages, this.validators) : [];
}
}, {
key: "hasErrors",
get: function get() {
return this.errors.length > 0;
}
}]);
return Field;
}();
tslib.__decorate([mobx.observable], Field.prototype, "initialValue", void 0);
tslib.__decorate([mobx.observable], Field.prototype, "isTouched", void 0);
tslib.__decorate([mobx.observable], Field.prototype, "isFocused", void 0);
tslib.__decorate([mobx.observable], Field.prototype, "validation", void 0);
tslib.__decorate([mobx.observable], Field.prototype, "_value", void 0);
tslib.__decorate([mobx.computed], Field.prototype, "value", null);
tslib.__decorate([mobx.computed], Field.prototype, "isValid", null);
tslib.__decorate([mobx.computed], Field.prototype, "isDirty", null);
tslib.__decorate([mobx.computed], Field.prototype, "errors", null);
tslib.__decorate([mobx.computed], Field.prototype, "hasErrors", null);
tslib.__decorate([mobx.action('TinyMobxForm | Field | reset')], Field.prototype, "reset", null);
var Form =
/*#__PURE__*/
function () {
function Form(fields, initialValues, options) {
var _this = this;
if (initialValues === void 0) {
initialValues = {};
}
if (options === void 0) {
options = {};
}
this.fields = {};
this.showErrors = function () {
var hasSetFocus = false;
_this.fieldNames.forEach(function (name) {
_this.fields[name].isTouched = true; // Set the first invalid field we find to isFocused so we can focus on that field
if (!_this.fields[name].isValid && !hasSetFocus) {
_this.fields[name].isFocused = true;
hasSetFocus = true;
}
});
};
this.reset = function () {
_this.fieldNames.forEach(function (name) {
return _this.fields[name].reset();
});
};
fields.forEach(function (props) {
_this.fieldNames.push(props.name);
var initialValue = initialValues[props.name] || props.initialValue;
var newProps = _extends({}, props, {
initialValue: initialValue
});
_this.fields[newProps.name] = new Field(_this, newProps, {
additionalValidators: validators(options.additionalValidators || {})
});
});
}
_createClass(Form, [{
key: "fieldNames",
get: function get() {
return Object.keys(this.fields);
}
}, {
key: "isValid",
get: function get() {
var _this2 = this;
return this.fieldNames.filter(function (name) {
return !_this2.fields[name].isValid;
}).length === 0;
}
}, {
key: "errors",
get: function get() {
var _this3 = this;
return this.fieldNames.flatMap(function (name) {
return _this3.fields[name].errors;
});
}
}, {
key: "isDirty",
get: function get() {
var _this4 = this;
return this.fieldNames.some(function (name) {
return _this4.fields[name].isDirty;
});
}
}, {
key: "values",
get: function get() {
var _this5 = this;
return this.fieldNames.reduce(function (dataset, name) {
var _extends2;
return _extends({}, dataset, (_extends2 = {}, _extends2[name] = _this5.fields[name].value, _extends2));
}, {});
}
}]);
return Form;
}();
tslib.__decorate([mobx.observable.struct], Form.prototype, "fields", void 0);
tslib.__decorate([mobx.computed], Form.prototype, "fieldNames", null);
tslib.__decorate([mobx.computed], Form.prototype, "isValid", null);
tslib.__decorate([mobx.computed], Form.prototype, "errors", null);
tslib.__decorate([mobx.computed], Form.prototype, "isDirty", null);
tslib.__decorate([mobx.computed], Form.prototype, "values", null);
tslib.__decorate([mobx.action('TinyMobXForm | showErrors')], Form.prototype, "showErrors", void 0);
tslib.__decorate([mobx.action('TinyMobXForm | reset')], Form.prototype, "reset", void 0);
exports.Field = Field;
exports.Form = Form;
//# sourceMappingURL=tiny-mobx-form.cjs.development.js.map