@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
JavaScript
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