mobx-hooks-form
Version:
React form package using mobX, React hooks and context
545 lines (441 loc) • 16.8 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var tslib = require('tslib');
var React = require('react');
var React__default = _interopDefault(React);
var mobx = require('mobx');
var mobxUtils = require('mobx-utils');
var mobxReactLite = require('mobx-react-lite');
var lodash = require('lodash');
var yup = require('yup');
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 isObject = function isObject(obj) {
return typeof obj === 'object' && obj !== null;
};
var pathToArr = function pathToArr(path) {
var output = [];
path.split('.').forEach(function (item) {
item.split(/\[([^}]+)\]/g).forEach(function (key) {
if (key.length > 0) {
output.push(key);
}
});
});
return output;
};
var get = function get(path) {
return function (obj) {
var ar = pathToArr(path);
if (ar[5]) {
throw Error('mobx form path is too deep');
} else if (ar[4]) {
var _obj$ar$, _obj$ar$$ar$, _obj$ar$$ar$$ar$, _obj$ar$$ar$$ar$$ar$;
return (_obj$ar$ = obj[ar[0]]) === null || _obj$ar$ === void 0 ? void 0 : (_obj$ar$$ar$ = _obj$ar$[ar[1]]) === null || _obj$ar$$ar$ === void 0 ? void 0 : (_obj$ar$$ar$$ar$ = _obj$ar$$ar$[ar[2]]) === null || _obj$ar$$ar$$ar$ === void 0 ? void 0 : (_obj$ar$$ar$$ar$$ar$ = _obj$ar$$ar$$ar$[ar[3]]) === null || _obj$ar$$ar$$ar$$ar$ === void 0 ? void 0 : _obj$ar$$ar$$ar$$ar$[ar[4]];
} else if (ar[3]) {
var _obj$ar$2, _obj$ar$2$ar$, _obj$ar$2$ar$$ar$;
return (_obj$ar$2 = obj[ar[0]]) === null || _obj$ar$2 === void 0 ? void 0 : (_obj$ar$2$ar$ = _obj$ar$2[ar[1]]) === null || _obj$ar$2$ar$ === void 0 ? void 0 : (_obj$ar$2$ar$$ar$ = _obj$ar$2$ar$[ar[2]]) === null || _obj$ar$2$ar$$ar$ === void 0 ? void 0 : _obj$ar$2$ar$$ar$[ar[3]];
} else if (ar[2]) {
var _obj$ar$3, _obj$ar$3$ar$;
return (_obj$ar$3 = obj[ar[0]]) === null || _obj$ar$3 === void 0 ? void 0 : (_obj$ar$3$ar$ = _obj$ar$3[ar[1]]) === null || _obj$ar$3$ar$ === void 0 ? void 0 : _obj$ar$3$ar$[ar[2]];
} else if (ar[1]) {
var _obj$ar$4;
return (_obj$ar$4 = obj[ar[0]]) === null || _obj$ar$4 === void 0 ? void 0 : _obj$ar$4[ar[1]];
} else {
return obj[ar[0]];
}
};
};
var set = function set(path) {
return function (value) {
return function (obj) {
var ar = pathToArr(path);
if (ar[5]) {
throw Error('mobx form path is too deep');
} else if (ar[4]) {
var _obj$ar$5, _obj$ar$5$ar$, _obj$ar$5$ar$$ar$;
var base = (_obj$ar$5 = obj[ar[0]]) === null || _obj$ar$5 === void 0 ? void 0 : (_obj$ar$5$ar$ = _obj$ar$5[ar[1]]) === null || _obj$ar$5$ar$ === void 0 ? void 0 : (_obj$ar$5$ar$$ar$ = _obj$ar$5$ar$[ar[2]]) === null || _obj$ar$5$ar$$ar$ === void 0 ? void 0 : _obj$ar$5$ar$$ar$[ar[3]];
if (isObject(base)) {
base[ar[4]] = value;
}
} else if (ar[3]) {
var _obj$ar$6, _obj$ar$6$ar$;
var _base = (_obj$ar$6 = obj[ar[0]]) === null || _obj$ar$6 === void 0 ? void 0 : (_obj$ar$6$ar$ = _obj$ar$6[ar[1]]) === null || _obj$ar$6$ar$ === void 0 ? void 0 : _obj$ar$6$ar$[ar[2]];
if (isObject(_base)) {
_base[ar[3]] = value;
}
} else if (ar[2]) {
var _obj$ar$7;
var _base2 = (_obj$ar$7 = obj[ar[0]]) === null || _obj$ar$7 === void 0 ? void 0 : _obj$ar$7[ar[1]];
if (isObject(_base2)) {
_base2[ar[2]] = value;
}
} else if (ar[1]) {
var _base3 = obj[ar[0]];
if (isObject(_base3)) {
_base3[ar[1]] = value;
}
} else {
obj[ar[0]] = value;
}
};
};
};
function getErrorsFromValidationError(validationError) {
var FIRST_ERROR = 0;
return validationError.inner.reduce(function (errors, error) {
var _extends2;
return _extends({}, errors, (_extends2 = {}, _extends2[error.path] = error.errors[FIRST_ERROR], _extends2));
}, {});
}
function validate(schema, values) {
try {
schema.validateSync(values, {
abortEarly: false,
recursive: true
});
return {};
} catch (error) {
return getErrorsFromValidationError(error);
}
}
var Store =
/*#__PURE__*/
function () {
function Store(props) {
var _this = this;
this.debug = false;
this.DEBOUNCE_MS = 0;
this.isTouchedAll = false;
this.touched = {};
this.submitting = false;
this.error = undefined;
this.setError = function (error) {
_this.error = error;
};
this.setSubmitting = function (submitting) {
_this.submitting = submitting;
};
this.values = {};
this.debouncedValues = {};
this.getValue = mobxUtils.computedFn(function getValue(path) {
var _get;
return (_get = get(path)(this.values)) !== null && _get !== void 0 ? _get : '';
});
this.getDebouncedValue = mobxUtils.computedFn(function getDebouncedValue(path) {
var _get2;
return (_get2 = get(path)(this.debouncedValues)) !== null && _get2 !== void 0 ? _get2 : '';
});
this.getValueLength = mobxUtils.computedFn(function getValueLength(path) {
var _ref, _this$getValue;
return (_ref = (_this$getValue = this.getValue(path)) === null || _this$getValue === void 0 ? void 0 : _this$getValue.length) !== null && _ref !== void 0 ? _ref : 0;
});
this.setDebouncedValue = lodash.debounce(function (path, value) {
set(path)(value)(_this.debouncedValues);
}, this.DEBOUNCE_MS);
this.pushDebouncedValue = lodash.debounce(function (path, value) {
get(path)(_this.debouncedValues).push(value);
}, this.DEBOUNCE_MS);
this.removeDebouncedValue = lodash.debounce(function (path, index) {
get(path)(_this.debouncedValues).splice(index, 1);
}, this.DEBOUNCE_MS);
this.pushValue = function (path, value) {
get(path)(_this.values).push(value);
_this.pushDebouncedValue(path, value);
};
this.removeValue = function (path, index) {
get(path)(_this.values).splice(index, 1);
_this.removeDebouncedValue(path, index);
};
this.setValue = function (path) {
return function (value) {
set(path)(value)(_this.values);
_this.setDebouncedValue(path, value);
};
};
this.setValues = function (values) {
_this.values = values;
_this.debouncedValues = values;
};
this.isRequired = mobxUtils.computedFn(function isRequired(path) {
try {
var _ref2;
var _yup$reach$describe = yup.reach(this.schema, path, this.debouncedValues, this.debouncedValues).describe(),
tests = _yup$reach$describe.tests;
return (_ref2 = !!(tests === null || tests === void 0 ? void 0 : tests.find(function (test) {
return test.name === 'required';
}))) !== null && _ref2 !== void 0 ? _ref2 : false;
} catch (error) {
return false;
}
});
this.reset = function () {
_this.setValues(_this.defaultValues);
_this.touched = {};
_this.isTouchedAll = false;
};
this.handleSubmit = function (submit) {
return mobx.action('handleSubmit', function (e) {
try {
e.preventDefault();
_this.touchAll();
var _temp2 = function () {
if (_this.isValid) {
var _submit;
_this.setSubmitting(true);
return Promise.resolve((_submit = submit(_this.values)) === null || _submit === void 0 ? void 0 : _submit["catch"](function (e) {
return _this.setError(e);
})).then(function () {
_this.setSubmitting(false);
});
}
}();
return Promise.resolve(_temp2 && _temp2.then ? _temp2.then(function () {}) : void 0);
} catch (e) {
return Promise.reject(e);
}
});
};
this.touch = function (path) {
_this.touched[path] = true;
};
this.touchAll = function () {
_this.isTouchedAll = true;
};
this.getError = mobxUtils.computedFn(function getError(key) {
return this.errors[key];
});
this.getId = function (path) {
return _this.formName + "_" + path;
};
this.getField = mobxUtils.computedFn(function getField(path) {
var store = this;
return {
path: path,
submitting: store.submitting,
get value() {
return store.getValue(path);
},
get error() {
return store.getError(path);
},
id: store.getId(path),
setValue: store.setValue(path),
onBlur: mobx.action('onBlur', function () {
store.touch(path);
}),
onChange: mobx.action('onChange', function (e) {
store.setValue(path)(e.target.value);
}),
onCheckedChange: mobx.action('onCheckedChange', function (e) {
store.setValue(path)(e.target.checked);
}),
isRequired: store.isRequired(path)
};
});
this.getFieldArray = mobxUtils.computedFn(function getFieldArray(path) {
var store = this;
return {
path: path,
get error() {
return store.getError(path);
},
get indexes() {
return Array.from(Array(store.getValueLength(path)).keys());
},
id: store.getId(path),
isRequired: store.isRequired(path),
add: mobx.action('add', function (value) {
var ar = store.getValue(path);
if (!Array.isArray(ar)) {
store.setValue(path)([]);
}
if (value === undefined) {
var defaultAr = get(path)(store.defaultValues);
if (Array.isArray(defaultAr)) {
value = defaultAr.length ? defaultAr[defaultAr.length - 1] : '';
} else if (defaultAr !== undefined) {
value = defaultAr;
} else {
value = ar.length ? ar[ar.length - 1] : '';
}
}
store.pushValue(path, value);
}),
remove: mobx.action('remove', function (index) {
var ar = store.getValue(path);
if (!Array.isArray(ar) || index >= ar.length) {
console.error('trying to remove item from non array or at wrong index');
} else {
store.removeValue(path, index);
if (ar.length === 0) {
var d = get(path)(store.defaultValues);
if (!Array.isArray(d)) {
store.setValue(path)(d);
}
}
}
})
};
});
var schema = props.schema,
defaultValues = props.defaultValues,
_props$formName = props.formName,
formName = _props$formName === void 0 ? '' : _props$formName,
_props$debug = props.debug,
debug = _props$debug === void 0 ? false : _props$debug,
_props$debugMobx = props.debugMobx,
debugMobx = _props$debugMobx === void 0 ? false : _props$debugMobx,
_props$DEBOUNCE_MS = props.DEBOUNCE_MS,
DEBOUNCE_MS = _props$DEBOUNCE_MS === void 0 ? 0 : _props$DEBOUNCE_MS;
this.defaultValues = defaultValues || {};
this.schema = schema;
this.debug = debug;
this.formName = formName;
this.DEBOUNCE_MS = DEBOUNCE_MS;
this.setValues(defaultValues || {});
var resetError = function resetError() {
_this.error = undefined;
};
mobx.observe(this.values, function () {
return resetError();
});
if (debug) {
mobx.autorun(function () {
console.log('values', mobx.toJS(_this.values));
console.log('validations', mobx.toJS(_this.validations));
console.log('error', mobx.toJS(_this.error));
});
if (debugMobx) {
mobx.spy(function (event) {
if (event.type === 'action') {
console.log("%c" + event.name + " %c[ " + event.arguments + " ]", 'color: #bad', 'color: #bada55');
} else {
if (event.type || event.name) {
console.log("%c " + event.type + " | " + event.name, 'color: #f9d299');
}
}
});
}
}
}
_createClass(Store, [{
key: "validations",
get: function get() {
return validate(this.schema, this.debouncedValues);
}
}, {
key: "isValid",
get: function get() {
return lodash.isEmpty(this.validations);
}
}, {
key: "errors",
get: function get() {
var _this2 = this;
return this.isTouchedAll ? this.validations : Object.fromEntries(Object.entries(this.validations).filter(function (_ref3) {
var key = _ref3[0];
return _this2.touched[key];
}));
}
}]);
return Store;
}();
tslib.__decorate([mobx.observable], Store.prototype, "isTouchedAll", void 0);
tslib.__decorate([mobx.observable], Store.prototype, "touched", void 0);
tslib.__decorate([mobx.observable], Store.prototype, "submitting", void 0);
tslib.__decorate([mobx.observable], Store.prototype, "error", void 0);
tslib.__decorate([mobx.action], Store.prototype, "setError", void 0);
tslib.__decorate([mobx.action], Store.prototype, "setSubmitting", void 0);
tslib.__decorate([mobx.observable], Store.prototype, "values", void 0);
tslib.__decorate([mobx.observable], Store.prototype, "debouncedValues", void 0);
tslib.__decorate([mobx.action], Store.prototype, "setDebouncedValue", void 0);
tslib.__decorate([mobx.action], Store.prototype, "pushDebouncedValue", void 0);
tslib.__decorate([mobx.action], Store.prototype, "removeDebouncedValue", void 0);
tslib.__decorate([mobx.action], Store.prototype, "pushValue", void 0);
tslib.__decorate([mobx.action], Store.prototype, "removeValue", void 0);
tslib.__decorate([mobx.action], Store.prototype, "setValue", void 0);
tslib.__decorate([mobx.action], Store.prototype, "setValues", void 0);
tslib.__decorate([mobx.computed], Store.prototype, "validations", null);
tslib.__decorate([mobx.computed], Store.prototype, "isValid", null);
tslib.__decorate([mobx.action], Store.prototype, "reset", void 0);
tslib.__decorate([mobx.action], Store.prototype, "touch", void 0);
tslib.__decorate([mobx.action], Store.prototype, "touchAll", void 0);
tslib.__decorate([mobx.computed], Store.prototype, "errors", null);
var useForm = function useForm(props) {
return mobxReactLite.useLocalStore(function (source) {
return new Store(source);
}, props);
};
var FormContext =
/*#__PURE__*/
React__default.createContext({}, function () {
return 0;
});
var useFormContext = function useFormContext() {
return React.useContext(FormContext);
};
var FormContextProvider = function FormContextProvider(_ref4) {
var children = _ref4.children,
formStore = _ref4.formStore;
return React__default.createElement(FormContext.Provider, {
value: formStore
}, children);
};
var useField = function useField(path) {
return React.useContext(FormContext).getField(path);
};
var useFieldArray = function useFieldArray(path) {
return React.useContext(FormContext).getFieldArray(path);
};
var FieldContext =
/*#__PURE__*/
React__default.createContext({});
var useFieldContext = function useFieldContext() {
return React.useContext(FieldContext);
};
var FieldContextProvider =
/*#__PURE__*/
mobxReactLite.observer(function (_ref5) {
var children = _ref5.children,
path = _ref5.path;
var field = React.useContext(FormContext).getField(path);
return React__default.createElement(FieldContext.Provider, {
value: field
}, typeof children === 'function' ? children(field) : children);
});
exports.FieldContextProvider = FieldContextProvider;
exports.FormContextProvider = FormContextProvider;
exports.useField = useField;
exports.useFieldArray = useFieldArray;
exports.useFieldContext = useFieldContext;
exports.useForm = useForm;
exports.useFormContext = useFormContext;
//# sourceMappingURL=mobx-hooks-form.cjs.development.js.map