@mobx-ecosystem/mobx-form
Version:
provides the ability to use forms with validation in MobX stores
1,366 lines (1,351 loc) • 49.2 kB
JavaScript
import { makeAutoObservable } from 'mobx';
import mitt from 'mitt';
const isObject = (obj) => obj !== null && typeof obj === 'object';
const isString = (obj) => typeof obj === 'string';
const isNumber = (value) => typeof value === 'number';
const isBoolean = (value) => typeof value === 'boolean';
function isEqual(value, other) {
// Если оба значения одинаковы (включая примитивы и ссылки на один объект)
if (value === other) {
return true;
}
// Если одно из значений null или не объект, и они не равны (уже проверено выше)
if (value === null || other === null || typeof value !== 'object' || typeof other !== 'object') {
return false;
}
// Если один из аргументов — Date, сравниваем их временные метки
if (value instanceof Date && other instanceof Date) {
return value.getTime() === other.getTime();
}
// Если один из аргументов — RegExp, сравниваем их строковые представления
if (value instanceof RegExp && other instanceof RegExp) {
return value.toString() === other.toString();
}
// Если один из аргументов — Map, преобразуем их в массивы и сравниваем
if (value instanceof Map && other instanceof Map) {
if (value.size !== other.size)
return false;
for (const [key, val] of value) {
if (!other.has(key) || !isEqual(val, other.get(key))) {
return false;
}
}
return true;
}
// Если один из аргументов — Set, преобразуем их в массивы и сравниваем
if (value instanceof Set && other instanceof Set) {
if (value.size !== other.size)
return false;
for (const val of value) {
if (!other.has(val)) {
return false;
}
}
return true;
}
// Если это массивы, сравниваем их длины и элементы
if (Array.isArray(value) && Array.isArray(other)) {
if (value.length !== other.length)
return false;
for (let i = 0; i < value.length; i++) {
if (!isEqual(value[i], other[i])) {
return false;
}
}
return true;
}
// Если это объекты, сравниваем их ключи и значения
const valueKeys = Object.keys(value);
const otherKeys = Object.keys(other);
// Если количество ключей разное, объекты не равны
if (valueKeys.length !== otherKeys.length) {
return false;
}
// Рекурсивно сравниваем все свойства
for (const key of valueKeys) {
if (!Object.hasOwnProperty.call(other, key) || !isEqual(value[key], other[key])) {
return false;
}
}
return true;
}
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
function __rest(s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
}
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
let validate;
let preSubmitValidationError;
const configureForm = (configuration) => {
validate = configuration.validation.validate;
preSubmitValidationError = configuration.validation.preSubmitValidationError;
};
const _checkConfiguration = () => {
if (!validate || !preSubmitValidationError)
throw new Error("You must define configureForm to configure mobx-form");
};
class CombinedFormFieldService {
constructor(initValue) {
Object.defineProperty(this, "_touched", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "_disabled", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "_error", {
enumerable: true,
configurable: true,
writable: true,
value: undefined
});
Object.defineProperty(this, "_initValue", {
enumerable: true,
configurable: true,
writable: true,
value: []
});
Object.defineProperty(this, "_value", {
enumerable: true,
configurable: true,
writable: true,
value: []
});
Object.defineProperty(this, "_validate", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "setTouched", {
enumerable: true,
configurable: true,
writable: true,
value: (touched) => {
this._touched = touched;
}
});
Object.defineProperty(this, "add", {
enumerable: true,
configurable: true,
writable: true,
value: (value) => {
var _a;
this.value.push(value);
this.setTouched(true);
(_a = this.validate) === null || _a === void 0 ? void 0 : _a.call(this, 'only-touched');
}
});
Object.defineProperty(this, "removeByIndex", {
enumerable: true,
configurable: true,
writable: true,
value: (index) => {
var _a;
this.value.splice(index, 1);
this.setTouched(true);
(_a = this.validate) === null || _a === void 0 ? void 0 : _a.call(this, 'only-touched');
}
});
Object.defineProperty(this, "reset", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this._value = this.initValue.slice(0); // copy array without objects
this._value.forEach(it => it.formService.reset());
this.setTouched(false);
}
});
Object.defineProperty(this, "clear", {
enumerable: true,
configurable: true,
writable: true,
value: ({ validate = true }) => {
this._value = this.initValue.slice(0); // copy array without objects
this._value.forEach(it => it.formService.clear({ validate }));
this.setTouched(false);
}
});
Object.defineProperty(this, "setAsInit", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.initValue = this.value;
this._value.forEach(it => it.formService.setAsInit());
this.setTouched(false);
}
});
Object.defineProperty(this, "getValues", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
return this.value.map(it => it.formService.getValues());
}
});
Object.defineProperty(this, "touch", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.value.forEach(it => it.formService.touch());
this.setTouched(true);
}
});
Object.defineProperty(this, "validateFields", {
enumerable: true,
configurable: true,
writable: true,
value: (type = 'everything') => {
return Promise.all(this.value.map(it => it.formService.validate(type)));
}
});
Object.defineProperty(this, "validate", {
enumerable: true,
configurable: true,
writable: true,
value: (type = 'everything') => __awaiter(this, void 0, void 0, function* () {
var _a;
return Promise.all([(_a = this._validate) === null || _a === void 0 ? void 0 : _a.call(this), this.validateFields(type)]);
})
});
Object.defineProperty(this, "disable", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.disabled = true;
}
});
Object.defineProperty(this, "enable", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.disabled = false;
}
});
Object.defineProperty(this, "setDisabledFn", {
enumerable: true,
configurable: true,
writable: true,
value: (disabledFn) => {
this.value.forEach(it => it.formService.setDisabledFn(disabledFn));
}
});
Object.defineProperty(this, "setInitValue", {
enumerable: true,
configurable: true,
writable: true,
value: (_initValue, { validate } = {}) => {
var _a;
this._initValue = _initValue;
this._value = _initValue.slice(0); // copy array without objects
this.setTouched(false);
if (validate) {
(_a = this.validate) === null || _a === void 0 ? void 0 : _a.call(this, 'only-touched');
}
}
});
makeAutoObservable(this);
this.initValue = initValue || [];
}
get initValue() {
return this._initValue;
}
set initValue(_initValue) {
var _a;
this._initValue = _initValue;
this._value = _initValue.slice(0); // copy array without objects
this.setTouched(false);
(_a = this.validate) === null || _a === void 0 ? void 0 : _a.call(this, 'only-touched');
}
get value() {
return this._value;
}
set value(array) {
this._value = array;
this.setTouched(true);
}
get disabled() {
return this._disabled;
}
set disabled(disabled) {
this._disabled = disabled;
if (disabled) {
this.value.forEach(it => it.formService.disable());
}
else {
this.value.forEach(it => it.formService.enable());
}
}
get error() {
return this._error;
}
set error(error) {
this._error = error;
}
get isValid() {
return !this._error && this.value.every(it => it.formService.isValid);
}
get isTouched() {
return this._touched || this.value.some(it => it.formService.isTouched);
}
get isInit() {
return !this.isTouched;
}
get hasItems() {
return Boolean(this.value.length);
}
}
class AutocompleteFieldService {
constructor(initValue, options) {
Object.defineProperty(this, "field", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "inputField", {
enumerable: true,
configurable: true,
writable: true,
value: new FieldService('')
});
Object.defineProperty(this, "options", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "setValue", {
enumerable: true,
configurable: true,
writable: true,
value: (value, { inputValue = "", withNotification = true, withBlur = true }) => {
var _a, _b, _c, _d;
if (!withNotification) {
this.field.value = value;
this.inputField.value = inputValue;
(_b = (_a = this.field).validate) === null || _b === void 0 ? void 0 : _b.call(_a);
(_d = (_c = this.inputField).validate) === null || _d === void 0 ? void 0 : _d.call(_c);
}
else {
this.field.value = value;
this.inputField.value = inputValue;
}
if (withBlur) {
return this.field.isBlurred = true;
}
}
});
Object.defineProperty(this, "reset", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.field.reset();
}
});
Object.defineProperty(this, "clear", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.field.clear();
}
});
Object.defineProperty(this, "setAsInit", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.field.setAsInit();
}
});
Object.defineProperty(this, "onInputChange", {
enumerable: true,
configurable: true,
writable: true,
value: (e, value) => {
var _a, _b, _c, _d;
const result = (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.onInputBeforeChange) === null || _b === void 0 ? void 0 : _b.call(_a, value);
if (result === 'abort') {
return;
}
const oldValue = this.inputField.value;
this.inputField.value = value;
if (oldValue !== value) {
(_d = (_c = this.options) === null || _c === void 0 ? void 0 : _c.onInputChange) === null || _d === void 0 ? void 0 : _d.call(_c, value);
}
}
});
Object.defineProperty(this, "onFocus", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
var _a, _b;
(_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.onFocus) === null || _b === void 0 ? void 0 : _b.call(_a);
}
});
Object.defineProperty(this, "touch", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.field.touch();
}
});
Object.defineProperty(this, "disable", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.field.disabled = true;
}
});
Object.defineProperty(this, "setDisabledFn", {
enumerable: true,
configurable: true,
writable: true,
value: (disabledFn) => {
this.field.setDisabledFn(disabledFn);
}
});
Object.defineProperty(this, "enable", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.field.disabled = false;
}
});
Object.defineProperty(this, "setInitValue", {
enumerable: true,
configurable: true,
writable: true,
value: (initValue, { validate } = {}) => {
var _a;
this.field.setInitValue(initValue, { validate });
if (validate) {
(_a = this.validate) === null || _a === void 0 ? void 0 : _a.call(this);
}
}
});
Object.defineProperty(this, "dispose", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.field.dispose();
}
});
makeAutoObservable(this);
this.options = options;
this.field = new FieldService(initValue, { onChange: options === null || options === void 0 ? void 0 : options.onChange, beforeOnChange: options === null || options === void 0 ? void 0 : options.beforeOnChange, hasEvents: options === null || options === void 0 ? void 0 : options.hasEvents, disabledFn: options === null || options === void 0 ? void 0 : options.disabledFn });
}
get events() {
return this.field.events;
}
get validate() {
return this.field.validate;
}
set validate(validate) {
this.field.validate = validate;
}
get value() {
return this.field.value;
}
set value(value) {
this.field.value = value;
}
get error() {
return this.field.error;
}
set error(error) {
this.field.error = error;
}
get disabled() {
return this.field.disabled;
}
set disabled(disabled) {
this.field.disabled = disabled;
}
get isValid() {
return this.field.isValid;
}
get isInit() {
return this.field.isInit;
}
set initValue(initValue) {
this.field.initValue = initValue;
}
get isTouched() {
return this.field.isTouched;
}
get initValue() {
return this.field.initValue;
}
get props() {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
const optionsFn = (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.optionsFn) === null || _b === void 0 ? void 0 : _b.call(_a);
const loadingFn = (_d = (_c = this.options) === null || _c === void 0 ? void 0 : _c.loadingFn) === null || _d === void 0 ? void 0 : _d.call(_c);
const onInputBeforeChange = (_e = this.options) === null || _e === void 0 ? void 0 : _e.onInputBeforeChange;
const onInputChange = (_f = this.options) === null || _f === void 0 ? void 0 : _f.onInputChange;
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, this.field.props), { onFocus: this.onFocus }), ((onInputBeforeChange !== undefined || onInputChange !== undefined) && { onSearchChange: this.onInputChange || undefined })), (loadingFn !== undefined && { loading: ((_h = (_g = this.options) === null || _g === void 0 ? void 0 : _g.loadingFn) === null || _h === void 0 ? void 0 : _h.call(_g)) || false })), (optionsFn !== undefined && { options: ((_k = (_j = this.options) === null || _j === void 0 ? void 0 : _j.optionsFn) === null || _k === void 0 ? void 0 : _k.call(_j)) || [] }));
}
}
class FormService {
constructor(fields, validationSchema) {
Object.defineProperty(this, "fields", {
enumerable: true,
configurable: true,
writable: true,
value: {}
});
Object.defineProperty(this, "validationSchema", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "onSubmit", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "onValidate", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "onClear", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "onReset", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "setOnSubmit", {
enumerable: true,
configurable: true,
writable: true,
value: (onSubmit) => {
this.onSubmit = onSubmit;
}
});
Object.defineProperty(this, "setOnValidate", {
enumerable: true,
configurable: true,
writable: true,
value: (onValidate) => {
this.onValidate = onValidate;
}
});
Object.defineProperty(this, "setOnClear", {
enumerable: true,
configurable: true,
writable: true,
value: (onClear) => {
this.onClear = onClear;
}
});
Object.defineProperty(this, "setOnReset", {
enumerable: true,
configurable: true,
writable: true,
value: (onReset) => {
this.onReset = onReset;
}
});
Object.defineProperty(this, "submit", {
enumerable: true,
configurable: true,
writable: true,
value: () => __awaiter(this, void 0, void 0, function* () {
var _a;
yield this.validate('everything');
if (this.canBeSubmitted) {
return (_a = this.onSubmit) === null || _a === void 0 ? void 0 : _a.call(this);
}
else {
preSubmitValidationError === null || preSubmitValidationError === void 0 ? void 0 : preSubmitValidationError();
}
})
});
/***
* Validate the form
*
* *Configure this method with configureForm from mobx-form
*/
Object.defineProperty(this, "validate", {
enumerable: true,
configurable: true,
writable: true,
value: (type = 'only-touched') => __awaiter(this, void 0, void 0, function* () {
var _b;
const fieldValues = this.getValues();
// валидация для сложных форм снизу -> вверх
yield this.bypassFields(this.fields, (field) => __awaiter(this, void 0, void 0, function* () {
var _c;
if (isFormService(field)) {
return yield field.validate(type);
}
if (field instanceof CombinedFormFieldService) {
return yield ((_c = field.validateFields) === null || _c === void 0 ? void 0 : _c.call(field, type));
}
return null;
}));
if (fieldValues) {
// валидация для простейших полей сверху -> вниз
const errors = yield (validate === null || validate === void 0 ? void 0 : validate(fieldValues, this.validationSchema));
if (errors && Object.keys(errors || []).length != 0) {
this.setValidationError(errors, type);
}
else {
this.resetValidationErrors();
}
}
(_b = this.onValidate) === null || _b === void 0 ? void 0 : _b.call(this, type);
})
});
Object.defineProperty(this, "setValidationSchema", {
enumerable: true,
configurable: true,
writable: true,
value: (validationSchema) => {
this.validationSchema = validationSchema;
this.setValidationToFields();
}
});
/**
*
* @returns Object of field values
*/
Object.defineProperty(this, "getValues", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
const values = {};
for (const key of this.keys) {
const current = this.fields[key];
if (hasFormService(current)) {
values[key] = current.formService.getValues();
}
else {
values[key] = this.getValue(current);
}
}
return values;
}
});
Object.defineProperty(this, "getValue", {
enumerable: true,
configurable: true,
writable: true,
value: (value) => {
if (value instanceof FieldService || value instanceof CombinedFormFieldService || value instanceof AutocompleteFieldService) {
return value === null || value === void 0 ? void 0 : value.value;
}
else if (typeof value === 'object') {
const values = {};
for (const key of Object.keys(value)) {
values[key] = this.getValue(value === null || value === void 0 ? void 0 : value[key]);
}
return values;
}
return value;
}
});
/**
* Set fields by this
*/
Object.defineProperty(this, "setFieldsByThis", {
enumerable: true,
configurable: true,
writable: true,
value: (obj) => {
const fields = {};
Object.keys(obj).forEach(key => {
if (obj[key] && obj[key] instanceof FieldService || obj[key] instanceof CombinedFormFieldService || obj[key] instanceof AutocompleteFieldService) {
fields[key] = obj[key];
}
});
this.fields = fields;
this.setValidationToFields();
}
});
Object.defineProperty(this, "bypassFields", {
enumerable: true,
configurable: true,
writable: true,
value: (fields, action, levelParams) => {
if (fields instanceof FieldService || fields instanceof CombinedFormFieldService || fields instanceof AutocompleteFieldService) {
return action(fields, levelParams);
}
else if (hasFormService(fields)) {
return action(fields.formService, levelParams);
}
else if (typeof fields === 'object') {
return Promise.all(Object.keys(fields || {}).map(key => {
return this.bypassFields(fields === null || fields === void 0 ? void 0 : fields[key], action, levelParams === null || levelParams === void 0 ? void 0 : levelParams[key]);
}));
}
}
});
Object.defineProperty(this, "setValidationToFields", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.bypassFields(this.fields, (field) => {
if (!isFormService(field)) {
if (field instanceof FieldService || field instanceof AutocompleteFieldService) {
field.validate = this.validate;
}
else {
field._validate = this.validate;
}
}
});
}
});
Object.defineProperty(this, "getFieldsByKeys", {
enumerable: true,
configurable: true,
writable: true,
value: ({ keyType = 'include', keys = [] }) => {
let _keys = [];
if (keyType === 'include') {
_keys = keys;
}
else {
_keys = Object.keys(this.fields).filter(fieldKey => !keys.includes(fieldKey));
}
let fields = {};
_keys.forEach(key => { var _a; return fields[key] = (_a = this.fields) === null || _a === void 0 ? void 0 : _a[key]; });
return fields;
}
});
/**
* Set object to init values by form service keys
*/
Object.defineProperty(this, "setInitValues", {
enumerable: true,
configurable: true,
writable: true,
value: (values, { validate } = {}) => {
const fields = this.getFieldsByKeys({
keyType: 'include',
keys: Object.keys(values)
});
this.bypassFields(fields, (field, levelParams) => {
if (isFormService(field)) {
field.setInitValues(levelParams, { validate });
}
else {
field.setInitValue(levelParams, { validate });
}
}, values);
if (validate) {
this.validate();
}
}
});
/**
* Set object to values by form service keys
*/
Object.defineProperty(this, "setValues", {
enumerable: true,
configurable: true,
writable: true,
value: (values, { validate } = {}) => {
const fields = this.getFieldsByKeys({
keyType: 'include',
keys: Object.keys(values)
});
this.bypassFields(fields, (field, levelParams) => {
if (isFormService(field)) {
field.setValues(levelParams);
}
else {
field.value = levelParams;
}
}, values);
if (validate) {
this.validate('everything');
}
}
});
Object.defineProperty(this, "resetValidationErrors", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.bypassFields(this.fields, (field) => {
if (!isFormService(field)) {
field.error = undefined;
}
});
}
});
/**
* Set field errors to undefined
*/
Object.defineProperty(this, "resetErrors", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.bypassFields(this.fields, (field) => {
if (isFormService(field)) {
field.resetErrors();
}
else {
field.error = undefined;
}
});
}
});
Object.defineProperty(this, "setValidationError", {
enumerable: true,
configurable: true,
writable: true,
value: (error, validationType = 'only-touched') => {
this.bypassFields(this.fields, (field, levelParams) => {
if (field.isTouched || validationType === 'everything') { // set error only if it's changed
if (!isFormService(field)) {
field.error = levelParams;
}
}
}, error);
}
});
/**
* Set field values to init values
*/
Object.defineProperty(this, "setAsInit", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.bypassFields(this.fields, (field) => {
field.setAsInit();
});
}
});
/**
* Reset fields to their own initial values
*/
Object.defineProperty(this, "reset", {
enumerable: true,
configurable: true,
writable: true,
value: (params) => {
var _a;
const _b = params || {}, { to, validate = true } = _b, keyParams = __rest(_b, ["to", "validate"]);
const fields = (keyParams === null || keyParams === void 0 ? void 0 : keyParams.keys) ? this.getFieldsByKeys(keyParams) : this.fields;
this.bypassFields(fields, (field) => {
field.reset({ to });
});
(_a = this.onReset) === null || _a === void 0 ? void 0 : _a.call(this, { to });
if (validate) {
this.validate();
}
}
});
/**
* Clear fields to their first/constructor initial values
*/
Object.defineProperty(this, "clear", {
enumerable: true,
configurable: true,
writable: true,
value: (params) => {
var _a;
const _b = params || {}, { validate = true } = _b, keyParams = __rest(_b, ["validate"]);
const fields = (keyParams === null || keyParams === void 0 ? void 0 : keyParams.keys) ? this.getFieldsByKeys(keyParams) : this.fields;
this.bypassFields(fields, (field) => {
field.clear({ validate });
});
(_a = this.onClear) === null || _a === void 0 ? void 0 : _a.call(this);
if (validate) {
this.validate();
}
}
});
/**
* Pass true to the property 'disabled'
* Useful for editing / readonly mode when the fields has their own business logic
*/
Object.defineProperty(this, "disable", {
enumerable: true,
configurable: true,
writable: true,
value: (params) => {
const keyParams = __rest(params || {}, []);
const fields = (keyParams === null || keyParams === void 0 ? void 0 : keyParams.keys) ? this.getFieldsByKeys(keyParams) : this.fields;
this.bypassFields(fields, (field) => field.disable());
}
});
/**
* Pass false to the property 'disabled'
*/
Object.defineProperty(this, "enable", {
enumerable: true,
configurable: true,
writable: true,
value: (params) => {
const keyParams = __rest(params || {}, []);
const fields = (keyParams === null || keyParams === void 0 ? void 0 : keyParams.keys) ? this.getFieldsByKeys(keyParams) : this.fields;
this.bypassFields(fields, (field) => field.enable());
}
});
Object.defineProperty(this, "touch", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.bypassFields(this.fields, (field) => field.touch());
}
});
Object.defineProperty(this, "setDisabledFn", {
enumerable: true,
configurable: true,
writable: true,
value: (disabledFn) => {
this.bypassFields(this.fields, (field) => {
if (isFormService(field)) {
field.setDisabledFn(disabledFn);
}
else {
field.setDisabledFn(disabledFn);
}
});
}
});
_checkConfiguration();
makeAutoObservable(this);
this.fields = fields;
this.validationSchema = validationSchema;
this.setValidationToFields();
}
/**
* Return field keys
*/
get keys() {
return Object.keys(this.fields);
}
/**
* Check each field if its isValid = true
*/
get isValid() {
let isValid = true;
this.bypassFields(this.fields, (field) => {
if (!field.isValid) {
isValid = false;
}
});
return isValid;
}
/**
* Check each field if its isTouched = true
*/
get isTouched() {
let isTouched = false;
this.bypassFields(this.fields, (field) => {
if (field.isTouched) {
isTouched = true;
}
});
return isTouched;
}
/**
* Check if isTouched = true && isValid = true
*/
get canBeSubmitted() {
return this.isTouched && this.isValid;
}
/**
* always true if the form service is empty
*/
get disabled() {
let disabled = true;
this.bypassFields(this.fields, (field) => {
if (!field.disabled) {
disabled = false;
}
});
return disabled;
}
/**
* Set errors for fields
* @param errors object of string which provides errors for fields
*/
setErrors(error, validationType = 'only-touched') {
this.bypassFields(this.fields, (field, levelParams) => {
if (field.isTouched || validationType === 'everything') { // set error only if it's changed
if (isFormService(field)) {
if (levelParams) {
field.setErrors(levelParams, validationType);
}
}
else {
field.error = levelParams;
}
}
}, error);
}
}
const hasFormService = (obj) => {
return obj && typeof obj === 'object' && 'formService' in obj;
};
const isFormService = (obj) => {
return obj && obj instanceof FormService;
};
const getEmptyValueType = (value) => {
if (isString(value)) {
return '';
}
else if (isNumber(value)) {
return 0;
}
else if (isBoolean(value)) {
return false;
}
else if (Array.isArray(value)) {
return [];
}
else if (value === null || isObject(value) || isBoolean(value)) {
return null;
}
return undefined;
};
class FieldService {
constructor(initValue, options) {
var _a;
Object.defineProperty(this, "events", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_emptyValueType", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "validate", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_serviceType", {
enumerable: true,
configurable: true,
writable: true,
value: 'field-service'
});
Object.defineProperty(this, "_initValue", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_value", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_error", {
enumerable: true,
configurable: true,
writable: true,
value: undefined
});
Object.defineProperty(this, "_disabled", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "_isBlurred", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "options", {
enumerable: true,
configurable: true,
writable: true,
value: {}
});
Object.defineProperty(this, "emit", {
enumerable: true,
configurable: true,
writable: true,
value: (key, value) => {
var _a;
if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.hasEvents) && this.events) {
this.events.emit(key, value);
}
}
});
Object.defineProperty(this, "setDisabledFn", {
enumerable: true,
configurable: true,
writable: true,
value: (disabledFn) => {
this.options.disabledFn = disabledFn;
}
});
Object.defineProperty(this, "setOptions", {
enumerable: true,
configurable: true,
writable: true,
value: (options) => {
this.options = options;
}
});
Object.defineProperty(this, "setInitValue", {
enumerable: true,
configurable: true,
writable: true,
value: (initValue, { validate } = {}) => {
var _a;
this.initValue = initValue;
if (validate) {
(_a = this.validate) === null || _a === void 0 ? void 0 : _a.call(this);
}
}
});
Object.defineProperty(this, "setValue", {
enumerable: true,
configurable: true,
writable: true,
value: (value, { validate } = {}) => {
var _a;
this.value = value;
if (validate) {
(_a = this.validate) === null || _a === void 0 ? void 0 : _a.call(this);
}
}
});
Object.defineProperty(this, "onChange", {
enumerable: true,
configurable: true,
writable: true,
value: (_, value) => {
var _a;
this.value = value;
(_a = this.validate) === null || _a === void 0 ? void 0 : _a.call(this);
}
});
Object.defineProperty(this, "onBlur", {
enumerable: true,
configurable: true,
writable: true,
value: (_) => {
var _a;
this.isBlurred = true;
(_a = this.validate) === null || _a === void 0 ? void 0 : _a.call(this);
}
});
Object.defineProperty(this, "reset", {
enumerable: true,
configurable: true,
writable: true,
value: (params) => {
const { to = 'initValue' } = params || {};
this._value = to === 'initValue' ? this.initValue : this._emptyValueType;
this.isBlurred = false;
}
});
Object.defineProperty(this, "clear", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.value = this._emptyValueType;
this.isBlurred = true;
}
});
Object.defineProperty(this, "setAsInit", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.initValue = this.value;
this.isBlurred = false;
}
});
Object.defineProperty(this, "touch", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.isBlurred = true;
}
});
Object.defineProperty(this, "disable", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.disabled = true;
}
});
Object.defineProperty(this, "enable", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.disabled = false;
}
});
Object.defineProperty(this, "dispose", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
var _a;
if (this.events) {
(_a = this.events) === null || _a === void 0 ? void 0 : _a.all.clear();
this.events = undefined;
}
}
});
makeAutoObservable(this);
this._emptyValueType = getEmptyValueType(initValue);
this.initValue = initValue;
this.options = options || {};
if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.hasEvents) {
this.events = mitt();
}
}
get initValue() {
return this._initValue;
}
set initValue(initValue) {
var _a;
if (initValue || initValue === this._emptyValueType) {
this._initValue = initValue;
}
else {
this._initValue = this._emptyValueType;
}
this._value = this._initValue;
(_a = this.validate) === null || _a === void 0 ? void 0 : _a.call(this);
}
get value() {
return this._value;
}
set value(value) {
var _a, _b, _c, _d;
const result = (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.beforeOnChange) === null || _b === void 0 ? void 0 : _b.call(_a, value);
if (result === 'abort') {
return;
}
const oldValue = this._value;
this._value = value;
if (oldValue !== value) {
(_d = (_c = this.options) === null || _c === void 0 ? void 0 : _c.onChange) === null || _d === void 0 ? void 0 : _d.call(_c, value);
this.emit("ON_CHANGE", value);
}
}
get error() {
return this._error;
}
set error(error) {
this._error = error;
}
get disabled() {
var _a, _b;
return this._disabled || Boolean((_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.disabledFn) === null || _b === void 0 ? void 0 : _b.call(_a));
}
set disabled(disabled) {
this._disabled = disabled;
}
get isValid() {
return !this._error;
}
get isInit() {
if (isObject(this.value)) {
return isEqual(this.value, this._initValue);
}
return this._value === this._initValue;
}
get isBlurred() {
return this._isBlurred;
}
set isBlurred(isBlurred) {
this._isBlurred = isBlurred;
}
get isTouched() {
return !this.isInit; //|| this.isBlurred
}
// TODO: Rethink...
get props() {
var _a;
let commonProps = {
value: this.value,
error: this.error,
disabled: this.disabled,
};
if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.onError) {
commonProps = Object.assign(Object.assign({}, commonProps), { onError: (err) => {
this.error = this.error || (err === null || err === void 0 ? void 0 : err.toString());
} });
}
return Object.assign(Object.assign({}, commonProps), { onChange: this.onChange, onBlur: this.onBlur });
}
}
export { AutocompleteFieldService, CombinedFormFieldService, FieldService, FormService, _checkConfiguration, configureForm, preSubmitValidationError, validate };
//# sourceMappingURL=index.dev.js.map