@react-form-builder/core
Version:
React JSON Schema Form Builder to create complex, validated, reusable forms with no deep React knowledge required
363 lines (362 loc) • 10.4 kB
JavaScript
import v from "clsx";
import { makeAutoObservable as A } from "mobx";
import { calculateProperties as w } from "../features/calculation/propertyCalculator.js";
import { silentTransformCssString as p } from "../features/css-style/cssTransform.js";
import { cfRequiredProperties as O, cfEventHandlers as P } from "../features/define/utils/integratedComponentFeatures.js";
import { isFunctionArgumentValue as E, getArgumentFunction as N } from "../features/event/consts/functionArgument.js";
import { DidMountEvent as m, WillUnmountEvent as g } from "../features/event/eventNames.js";
import { ActionEventArgs as h } from "../features/event/utils/ActionEventArgs.js";
import { getDefaultPropertiesContext as j } from "../features/properties-context/getDefaultPropertiesContext.js";
import { isPromise as S } from "../utils/isPromise.js";
import { nameObservable as x } from "../utils/observableNaming.js";
import { ComponentStore as D } from "./ComponentStore.js";
import { generateClass as f, reactStylesToCss as y, flattenNestedCSS as R } from "./css.js";
const F = (o) => {
const t = o.features[P];
if (t) return t;
}, q = (o) => o.htmlAttributes?.reduce((t, { name: e, value: s }) => {
try {
t[e] = JSON.parse(s);
} catch {
t[e] = s;
}
return t;
}, {}), H = (o, t) => {
const e = [];
for (const [r, n] of Object.entries(t))
if (E(n)) {
const i = N(n.body || "");
e.push([r, i]);
}
const s = { ...t };
for (const [r, n] of e)
s[r] = (i, a, ...l) => !(i instanceof h) && a !== s ? n(o, s, ...l) : n(i, a, ...l);
return s;
};
function k(o, t) {
const e = t.map((s) => ({
func: o.findAction(s).func,
args: { ...s.args }
}));
return async (s) => {
try {
for (const { func: r, args: n } of e) {
const i = H(s, n), a = r(s, i);
S(a) && await a;
}
} catch (r) {
console.info("Action handler throws an error", r);
}
};
}
const b = (o, t) => async (...e) => {
const { data: s, store: r } = o, n = s.store.events?.[t] ?? [], i = k(r, n), a = o.get, l = new h(t, s, r, e, a, o.context.cellInfo);
await i(l);
}, V = (o) => {
const t = {}, { data: e } = o, s = F(e.model) ?? o.context.eventHandlers ?? {}, r = [
...Object.keys(e.store.events ?? {}),
...Object.keys(s)
], n = new Set(r);
return n.delete(m), n.delete(g), n.forEach((i) => {
t[i] = async (...a) => {
const l = s[i];
if (l) {
const c = new h(
i,
e,
o.store,
a,
o.get,
o.context.cellInfo
), d = l(c);
S(d) && await d;
}
await b(o, i)(...a);
};
}), t;
};
class X {
/**
* Creates an instance that calculates the properties of the form viewer component.
* @param data the data needed to display the component.
* @param store the form viewer settings.
* @param localizer the function to localize the properties of a component, returns a Record with localized properties.
* @param computeChildren the function that calculates all child properties of a component.
* @param context the context for working with component properties.
*/
constructor(t, e, s, r, n) {
this.data = t, this.store = e, this.localizer = s, this.computeChildren = r, this.context = n ?? j(t), this.#e = null, A(this, void 0, { name: x("ComponentState", { key: t.key }) });
}
data;
store;
localizer;
computeChildren;
#t = {
css: {
className: f()
},
wrapperCss: {
className: f("wc-")
}
};
/**
* The ref object associated with this component in the viewer. **Internal use only.**
*/
#e;
/**
* The context for working with component properties.
*/
context;
/**
* @inheritDoc
*/
get get() {
const t = this.propsWithoutChildren;
return Object.assign({}, t, { className: this.className }, this.children(t));
}
/**
* @inheritDoc
*/
get ownProps() {
return { ...this.propsWithoutChildren, className: this.className };
}
/**
* @inheritDoc
*/
get propsWithoutChildren() {
const { htmlAttributes: t, ...e } = this.calculatedProps;
return Object.assign(
{ key: this.data.store.key },
this.data.model.defaultProps,
e,
this.localizedProps,
this.value,
this.readOnly,
this.required,
this.disabled,
this.events,
t ?? this.htmlAttributes,
this.style,
this.data.userDefinedProps
);
}
/**
* @returns the component's field value data, if the component can have a field value.
*/
get value() {
const t = this.context.valueProperty;
if (t)
return { [t.propertyName]: t.propertyValue };
}
/**
* @returns the read-only property of a component if the component has a read-only flag.
*/
get readOnly() {
if (this.data.model.readOnly)
return { [this.data.model.readOnly]: this.isReadOnly };
}
/**
* @returns the required property of a component if the component has a required flag.
*/
get required() {
const t = this.data.model.features[O];
if (!t || !this.hasRequiredValidation) return;
const e = {};
return t.forEach((s) => e[s] = !0), e;
}
/**
* @inheritDoc
*/
get isReadOnly() {
const t = this.data.model.readOnly && this.selfProps[this.data.model.readOnly];
return this.store.formViewerPropsStore.readOnly || this.data.parent?.componentState.isReadOnly || (t ?? !1);
}
/**
* @returns the disabled property of a component if the component has a disabled flag.
*/
get disabled() {
if (this.data.model.disabled)
return { [this.data.model.disabled]: this.isDisabled };
}
/**
* @inheritDoc
*/
get isDisabled() {
const t = this.data.model.disabled && this.selfProps[this.data.model.disabled];
return this.store.formViewerPropsStore.disabled || this.data.parent?.componentState.isDisabled || (t ?? !1);
}
/**
* @returns the values for all properties of the component, calculates the values of the calculated properties.
*/
get calculatedProps() {
return w(this.data.store, this.data.dataRoot);
}
/**
* @returns component localized properties.
*/
get localizedProps() {
return this.localizer(this.data.store);
}
/**
* @returns the component event handlers that send events to the event bus.
*/
get events() {
return V(this);
}
/**
* Calculates and returns className property.
* @returns the Record that contains the className property for the component.
*/
get className() {
return v(
this.requiredClassName,
this.propsWithoutChildren.className,
this.#t.css.className
);
}
/**
* @inheritDoc
*/
get wrapperClassName() {
return this.#t.wrapperCss.className;
}
/**
* @returns the Record that contains the style property for the component.
*/
get style() {
return this.getStyleFromStylePart(this.data.store.style);
}
/**
* @inheritDoc
*/
get wrapperStyle() {
return this.getStyleFromStylePart(this.data.store.wrapperStyle);
}
/**
* @returns all arbitrary HTML attributes of the component.
*/
get htmlAttributes() {
return q(this.data.store);
}
/**
* Calculates and returns all child components.
* @param props the React component properties.
* @returns the Record that contains the child components of a component.
*/
children(t) {
return this.computeChildren(this.data, t);
}
/**
* @inheritDoc
*/
onDidMount() {
this.executeLifecycleEvent(m), this.applyAllStyles();
}
/**
* @inheritDoc
*/
onWillUnmount() {
this.executeLifecycleEvent(g), this.cleanStyles();
}
/**
* @inheritDoc
*/
applyStyles(t, e) {
e && this.updateAdoptedStyleSheets(t, e);
}
applyAllStyles() {
this.applyStyles("css", this.flatCss), this.applyStyles("wrapperCss", this.flatWrapperCss);
}
/**
* Clears component styles.
*/
cleanStyles() {
const t = [];
Object.values(this.#t).forEach((e) => {
e.styleSheet && t.push(e.styleSheet), e.styleSheet = void 0, e.flatCss = void 0;
}), t.length && (document.adoptedStyleSheets = document.adoptedStyleSheets.filter((e) => !t.includes(e)));
}
/**
* @inheritDoc
*/
setRef = (t) => {
this.#e = t;
};
/**
* @inheritDoc
*/
getRefValue = () => this.#e;
executeLifecycleEvent(t) {
const e = b(this, t), s = new h(t, this.data, this.store, [], this.get, this.context.cellInfo);
e(s).catch(console.error);
}
getStyleFromStylePart(t) {
const { viewMode: e } = this.store, s = p(t?.any?.string), r = p(t?.[e]?.string);
if (s || r) return { style: { ...s, ...r } };
}
/**
* @inheritDoc
*/
get flatCss() {
return this.computeFlatCssForPart("css");
}
/**
* @inheritDoc
*/
get flatWrapperCss() {
return this.computeFlatCssForPart("wrapperCss");
}
computeFlatCssForPart(t) {
const { model: e, store: s } = this.data, { viewMode: r } = this.store, n = y(Object.assign(
{},
e[t]?.any?.object,
s[t]?.any?.object
)), i = y(Object.assign(
{},
e[t]?.[r]?.object,
s[t]?.[r]?.object
)), a = s[t]?.any?.string ? s[t]?.any?.string?.replaceAll(`
`, " ") : "", l = s[t]?.[r]?.string ? s[t]?.[r]?.string?.replaceAll(`
`, " ") : "", u = [n, i, a, l].map((C) => C?.trim()).filter(Boolean);
if (!u.length)
return "";
const c = this.#t[t].className, d = `.${c}.${c} {` + u.join(`
`) + "}";
return R(d);
}
updateAdoptedStyleSheets(t, e) {
try {
const s = this.#t[t], r = s.styleSheet;
if (r) {
s.flatCss !== e && (r.replaceSync(e), s.flatCss = e);
return;
}
const n = new CSSStyleSheet();
n.replaceSync(e), s.styleSheet = n, s.flatCss = e, document.adoptedStyleSheets.push(n);
} catch (s) {
console.error(s);
}
}
get selfProps() {
const { htmlAttributes: t, ...e } = this.calculatedProps;
return {
...this.data.model.defaultProps,
...e,
...this.localizedProps,
...this.value,
...this.style,
...this.data.userDefinedProps
};
}
get hasRequiredValidation() {
return D.hasValidationRule(this.data.store, "required");
}
get requiredClassName() {
if (this.hasRequiredValidation)
return { required: !0 };
}
}
export {
X as ComponentState
};
//# sourceMappingURL=ComponentState.js.map