@smkit/ui
Version:
UI Kit of SberMarketing
125 lines (124 loc) • 4.13 kB
JavaScript
import { InputTypes } from './types';
import { DEFAULT_INPUT_SETTINGS, LACK_OF_SCHEMA_ERROR } from './constants';
import { get, writable } from 'svelte/store';
export class Form {
inputNames;
data;
validators;
errors;
isValid;
constructor() {
this.inputNames = [];
this.data = writable({});
this.validators = {};
this.errors = writable({});
this.isValid = writable(false);
}
parseInputValue(name) {
const value = this.data[name];
const schema = this.validators[name];
if (!schema)
throw new Error(LACK_OF_SCHEMA_ERROR);
return schema.safeParse(value);
}
checkFormValidity() {
const errors = get(this.errors);
const activeErrors = Object.values(errors).filter((err) => err);
const isFormValid = activeErrors.length === 0;
this.isValid.set(isFormValid);
return isFormValid;
}
setError(name, message) {
this.errors.update((v) => ({ ...v, [name]: message }));
}
validateInput(name) {
const validationStatus = this.parseInputValue(name);
if (validationStatus.success)
return this.setError(name, '');
return this.setError(name, validationStatus.error.issues[0].message);
}
parseAllInputValues() {
const activeErrors = this.inputNames
.map((input) => {
if (!this.validators[input])
return;
this.validateInput(input);
})
.filter((err) => err);
return activeErrors;
}
validateForm() {
const errors = this.parseAllInputValues();
const isValid = this.checkFormValidity();
if (isValid)
return { success: true };
return { success: false, error: errors };
}
getInputValue(evt) {
const type = evt.target.type;
switch (type) {
case InputTypes.Text:
return evt.target.value;
case InputTypes.Checkbox:
return evt.target.checked;
case InputTypes.Radio:
return evt.target.value;
default:
return evt.target.value;
}
}
// TODO: исправить типы
handleInput(evt, name) {
const value = this.getInputValue(evt);
this.data[name] = value;
if (!this.validators[name])
return;
this.validateInput(name);
this.checkFormValidity();
}
handleSelect(name, value, selectField = '') {
const data = selectField ? value[selectField] : value;
this.data[name] = data;
if (!this.validators[name])
return;
this.validateInput(name);
this.checkFormValidity();
return this.data[name];
}
provideInitialValue(elem, name) {
return (elem.value = this.data[name]);
}
defineDynamicField(field) {
Object.defineProperty(this.data, field, {
get() {
return get(this)[field];
},
set(value) {
this.update((v) => ({ ...v, [field]: value }));
},
configurable: true
});
}
// TODO: Добавить возможность вписывать кастомные функции
registerInput(name, settings = DEFAULT_INPUT_SETTINGS) {
this.defineDynamicField(name);
this.inputNames.push(name);
if (!this.data[name])
this.data[name] = settings.value ?? '';
this.validators[name] = settings.validation || null;
if (settings.validation)
this.validateInput(name);
return {
name,
value: this.data[name],
oninput: (evt) => this.handleInput(evt, name),
onmount: (elem) => this.provideInitialValue(elem, name),
onselect: (value) => this.handleSelect(name, value, settings?.selectField),
errors: this.errors,
validators: this.validators
};
}
registerDataField(name, value) {
return (this.data[name] = value);
}
}