UNPKG

@react-form-builder/core

Version:

React JSON Schema Form Builder to create complex, validated, reusable forms with no deep React knowledge required

309 lines (308 loc) 9 kB
import { makeAutoObservable as F, observable as v, autorun as S, runInAction as R, reaction as I } from "mobx"; import { ComponentStore as u, dataKey as y, isComputedProperty as w } from "../../../stores/ComponentStore.js"; import { mergeData as b } from "../../../utils/data-utils.js"; import { isRecord as A } from "../../../utils/isRecord.js"; import { needRender as k } from "../../../utils/needRender.js"; import { nameObservable as V, nameAutorun as O } from "../../../utils/observableNaming.js"; import { isNull as g, isUndefined as C } from "../../../utils/tools.js"; class B { /** * Creates the field with repeater data for the component. * @param repeaterComponentData the component data. * @param calculateValue the function for calculating the value of the field. * @param createDataValidator the function to create a data validator. * @param getInitialData the function to get initial data for the field. * @param setInitialData the function to update initial data for the field. * @param componentDataFactory the factory for creating ComponentData instances. * @param deferFieldCalculation if true, then the calculated field must be explicitly initialized. */ constructor(t, e, a, n, l, o, i) { this.repeaterComponentData = t, this.calculateValue = e, this.createDataValidator = a, this.getInitialData = n, this.setInitialData = l, this.componentDataFactory = o, this.deferFieldCalculation = i; const { model: s, store: r } = t; if (this.model = s, this.componentStore = r, !s.valued) throw new Error("'model.valued' is falsy"); if (!s.valueType) throw new Error("'model.typeOfValue' is undefined"); this.valued = s.valued, this.valueType = s.valueType; const h = "RepeaterField"; F(this, { model: !1, dataValidator: v.ref }, { name: V(h, { key: r.key }), autoBind: !0 }), this.initialData = this.isComputed ? this.computedValue : this.initialDataValue, this.#a = [ S( () => { this.dataValidator = this.createDataValidator( t, this.valueType, (c) => this.error = c ); }, { name: O(h, "setValidator", { key: r.key }) } ) ], this.#t = this.createDataChangeReaction(); } repeaterComponentData; calculateValue; createDataValidator; getInitialData; setInitialData; componentDataFactory; deferFieldCalculation; #e = []; /** * @inheritDoc */ error; /** * @inheritDoc */ touched = !1; /** * @inheritDoc */ valued; /** * The type of the field value. */ valueType; dataValidator; #a; #t; initialData; componentStore; model; /** * @inheritDoc */ get fieldType() { return "repeater"; } /** * @inheritDoc */ init() { if (this.deferFieldCalculation = !1, this.isComputed) { setTimeout(() => { this.initialData = this.computedValue, this.initFields(this.componentData); }, 0); return; } this.initialData = this.initialDataValue, this.initFields(this.componentData); } /** * @returns the initial value for the field. */ get initialValue() { return this.componentStore.props[this.valued]?.value ?? this.modelValue; } /** * @returns the default value for the field from {@link Model}. */ get modelValue() { return this.model.defaultProps?.[this.valued]; } /** * @inheritDoc */ dispose() { this.#a.forEach((t) => t()), this.disableReaction(), this.disposeOldComponentDatas(); } /** * @inheritDoc */ get value() { return this.componentData.map((t) => t.generatedData()); } /** * @inheritDoc */ setValue(t) { if (g(t) || C(t) || Array.isArray(t)) { this.initialData = t; return; } } /** * @inheritDoc */ setTouched() { this.touched = !0; } /** * @inheritDoc */ async validate() { if (!this.needValidate) { this.clearError(); return; } const t = this.componentData.map((e) => e.validate()); await Promise.allSettled(t), await this.dataValidator?.validate?.(this.value); } /** * @inheritDoc */ async getValidationResult() { if (!this.needValidate) return; const t = []; for (let e = 0; e < this.componentData.length; e++) { const n = await this.componentData[e].getValidationResult(); t.push(n); } return t; } /** * @inheritDoc */ reset() { this.setValue(this.initialValue), this.componentData.forEach((t) => { t.allFields.forEach((e) => e.reset()); }), this.clearError(); } /** * @inheritDoc */ clear() { this.setValue(this.modelValue), this.touched = !1, this.clearError(); } /** * @returns true if the field should be validated, false otherwise. */ get needValidate() { return k(this.componentStore, this.repeaterComponentData.dataRoot); } /** * Clears the error message for this field. */ clearError() { this.error = void 0, this.componentData.forEach((t) => { t.allFields.forEach((e) => e.setError(void 0)); }); } /** * @inheritDoc */ get errors() { let t = !1; const e = []; if (this.componentData.forEach((a) => { e.push(a.errors), t = t || a.hasErrors; }), !!t) return e; } /** * @inheritDoc */ setError = (t) => { if (C(t) || g(t)) { this.clearError(); return; } if (!A(t)) throw new Error(`Expected 'object' type, got '${typeof t}'`); this.error = t[this.errorFieldName]; const e = t; this.componentData.forEach((a, n) => { const l = e?.[n]; a.allComponentFields.forEach(({ field: o, dataKey: i }) => o.setError(l?.[i])); }); }; /** * @returns the component settings for the RepeaterItem component. */ get repeaterItemStore() { const t = JSON.parse(JSON.stringify(this.componentStore)), e = new u(this.componentStore.key, "RepeaterItem"); return e.type = "RepeaterItem", e.children = t.children, e.renderWhen = t.props?.itemRenderWhen, e; } /** * @returns the number of elements in the repeater. */ get itemsCount() { return !this.initialData || !Array.isArray(this.initialData) ? 0 : this.initialData.length; } /** * @inheritDoc */ get componentData() { const t = this.itemsCount, e = this.repeaterItemStore, a = this.componentStore.key, n = y(this.componentStore), l = this.repeaterComponentData.dataRoot; return R(() => { const o = []; for (let i = 0; i < t; i++) { const s = new u(`${a}-context-item-${i}`, "Fragment"); s.props = { repeaterDataKey: { value: n } }; const r = this.componentDataFactory.createComponentData(s, !1); r.index = i, r.parent = l, r.dataRootProvider = { get dataRoot() { return r; } }, r.getInitialData = () => { const d = this.initialData; if (Array.isArray(d)) return d[i]; }, r.setInitialData = (d, E) => { const D = this.initialData, p = Array.isArray(D) ? [...D] : [], f = b(r.generatedData(), p[i]); f[d] = E, p[i] = f, this.setInitialData(p); }; const h = new u(`${a}-root-item-${i}`, "Fragment"), c = this.componentDataFactory.createComponentData(h, !1); c.setParent(r); const m = u.createFromObject(e); m.key = `${a}-item-${i}`, this.componentDataFactory.createComponentData(m, !0).setParent(c), o.push(r); } return this.disposeOldComponentDatas(), this.#e = o, this.deferFieldCalculation || this.initFields(o), o; }); } /** * @returns the initial data value for the field. */ get initialDataValue() { return this.getInitialData() ?? this.initialValue; } /** * @returns the computed value for the field. */ get computedValue() { if (this.deferFieldCalculation) return this.initialDataValue; const [, t] = this.calculateValue(this.componentStore, this.valued); return t; } /** * @returns true if the field value is calculated, otherwise false. */ get isComputed() { return w(this.componentStore.props[this.valued]); } initFields(t) { t.map((e) => { e.allFields.forEach((a) => a.init()); }); } get errorFieldName() { return `${y(this.componentStore)}Error`; } disposeOldComponentDatas() { this.#e.forEach((t) => { t.dispose(); }); } /** * @inheritDoc */ disableReaction() { this.#t?.(); } /** * @inheritDoc */ enableReaction() { this.#t = this.createDataChangeReaction(); } createDataChangeReaction() { return I(() => ({ isComputed: this.isComputed, computedValue: this.computedValue, initialDataValue: this.initialDataValue }), (t) => { this.initialData = t.isComputed ? t.computedValue : t.initialDataValue; }, { name: V("RepeaterField", { key: this.componentStore.key }) }); } } export { B as RepeaterField }; //# sourceMappingURL=RepeaterField.js.map