From a5695ccab63ebc8d60d10f70eee610c99be666e4 Mon Sep 17 00:00:00 2001 From: Maksim Skobaro Date: Sat, 8 Feb 2025 03:33:42 +0300 Subject: [PATCH] add InputRestriction support for reactiveValue.ts --- web/src/utils/reactive/reactiveValue.ts | 45 +++++++++++++++++++++---- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/web/src/utils/reactive/reactiveValue.ts b/web/src/utils/reactive/reactiveValue.ts index c8b82b4..fbf36c8 100644 --- a/web/src/utils/reactive/reactiveValue.ts +++ b/web/src/utils/reactive/reactiveValue.ts @@ -1,11 +1,14 @@ import {action, computed, makeObservable, observable, reaction} from "mobx"; +import _ from "lodash"; export class ReactiveValue { @observable private val: T; @observable private isTouched: boolean = false; @observable private validators: ((value: T, field: string) => string)[] = []; + @observable private inputRestrictions: ((value: T, field: string) => string)[] = []; @observable private errors: string[] = []; + @observable private inputRestrictionError: string; @observable private fieldName: string; constructor(fireImmediately: boolean = false) { @@ -13,8 +16,10 @@ export class ReactiveValue { reaction(() => ({value: this.val, touched: this.isTouched}), () => { if (!this.isTouched) { this.errors = []; + this.inputRestrictionError = undefined; return; } + this.errors = this.validators .map(validator => validator(this.val, this.fieldName)) .filter(error => error && error.length > 0); @@ -28,8 +33,23 @@ export class ReactiveValue { @action.bound set(value: T) { - this.val = value; this.isTouched = true; + this.inputRestrictionError = undefined; + + if (!_.isEmpty(value)) { + for (const restriction of this.inputRestrictions) { + const error = restriction(value, this.fieldName); + if (error) { + this.inputRestrictionError = error; + } + } + } + + const lengthIsLessIfStringOrTrue = _.isString(value) && _.isString(this.val) ? value.length < this.val?.length : true; + if (!this.inputRestrictionError || lengthIsLessIfStringOrTrue) { + this.setAuto(value); + } + return this; } @@ -56,23 +76,35 @@ export class ReactiveValue { @action.bound addValidator(validator: (value: T, field?: string) => string) { - this.validators.push(validator); + if (validator) { + this.validators.push(validator); + } + + return this; + } + + @action.bound + addInputRestriction(restriction: (value: T) => string) { + if (restriction) { + this.inputRestrictions.push(restriction); + } + return this; } @computed get invalid() { - return this.errors.length > 0; + return this.errors.length > 0 || !!this.inputRestrictionError; } @computed get allErrors() { - return this.errors; + return [...this.errors, this.inputRestrictionError].filter(error => error); } @computed get firstError() { - return this.errors[0]; + return this.inputRestrictionError ?? this.errors[0]; } @action.bound @@ -87,9 +119,10 @@ export class ReactiveValue { @action.bound clear() { - this.val = null; + this.val = undefined; this.isTouched = false; this.errors = []; + this.inputRestrictionError = undefined; } }