UNPKG

@ea-lab/reactive-json

Version:

A REACT-based lib that transforms JSON (or YAML) into interactive HTML markup.

377 lines (376 loc) 12 kB
import { jsx as C, jsxs as L, Fragment as pt } from "react/jsx-runtime"; import { a as _ } from "../httpRequestCommon-COBq6B-n.js"; import { l as ut } from "../lodash-CYNxjS-I.js"; import { useReducer as dt, useState as w, useRef as ft, useEffect as q } from "react"; import { r as mt } from "../dnd-kit-sortable-tree.esm-Cz1RJyIg.js"; import { coreComponentsPlugin as tt } from "../coreComponentsPlugin.js"; import { mergeComponentCollections as ht } from "./ComponentCollector.js"; import { EventDispatcherProvider as gt } from "./EventDispatcherProvider.js"; import { GlobalDataContextProvider as yt } from "./GlobalDataContextProvider.js"; import Dt from "./ParsingDebugDisplay/ParsingDebugDisplay.js"; import { TemplateContext as Pt } from "./TemplateContext.js"; import { dataLocationToPath as Ct } from "./TemplateSystem.js"; import { alterData as bt } from "./utility/alterData.js"; import { applyDataMapping as Et } from "./utility/dataMappingSystem.js"; import { parseRjBuild as vt } from "./utility/parseRjBuild.js"; import { stringToBoolean as wt } from "./utility/stringToBoolean.js"; import { View as St } from "./View.js"; const xt = ({ dataOverride: S, dataFetchMethod: M, dataUrl: z, debugMode: et, DebugModeContentWrapper: A, DebugModeDataWrapper: K, DebugModeRootWrapper: rt, headersForData: X, headersForRjBuild: c, maybeRawAppData: $, maybeRawAppRjBuild: d, plugins: H, rjBuildFetchMethod: b, rjBuildUrl: f, upstreamUpdateCallbacks: N }) => { const h = []; M && (h.push({ deprecatedProperty: "dataFetchMethod", newProperty: "rjBuildFetchMethod" }), b = M), z && (h.push({ deprecatedProperty: "dataUrl", newProperty: "rjBuildUrl" }), f = z), X && (h.push({ deprecatedProperty: "headersForData", newProperty: "headersForRjBuild" }), c = X), $ && (h.push({ deprecatedProperty: "maybeRawAppData", newProperty: "maybeRawAppRjBuild" }), d = $), h.length > 0 && console.warn( "A ReactiveJsonRoot component got the following deprecated properties that must be replaced: " + h.map((t) => t.deprecatedProperty + " -> " + t.newProperty).join(", ") ); const [x, g] = dt( (t, a) => { switch (a.type) { case "setData": return { updateId: 0, realCurrentData: a.data }; case "updateData": return it(t, a.path, a.value, a.updateMode); default: return t; } }, { updateId: 0, realCurrentData: {} } ), [at, ot] = w({}), [nt, Q] = w({}), [st, Y] = w([]), [I, T] = w(() => { if (d) return typeof d == "string" ? d : JSON.stringify(d); }), [V, Z] = w(null), n = ft(null); q(() => () => { typeof document < "u" && n.current && n.current.parentNode && (n.current.parentNode.removeChild(n.current), n.current = null); }, []); const E = H ? ht([tt, H]) : tt; q(() => { f && (typeof b == "string" && b.toLowerCase() === "post" ? _.post(f, { headers: c }).then((t) => { T(t.data); }) : _.get(f, { headers: c }).then((t) => { T(t.data); })); }, [f, c]), q(() => { if (!I) return; const t = vt(I); if (!t.success) { if (console.group( `Tried to load the app's RjBuild but the ${t.format} content could not be parsed.` ), console.error(t.error.message), console.debug("Context:", { rjBuildUrl: f, rjBuildFetchMethod: b, headersForRjBuild: c, maybeRawAppRjBuild: d, dataOverride: S }), console.debug("Error details:", t.error), console.groupEnd(), typeof document < "u") { let e = document.getElementById("rj-parsing-error-root"); if (e || (e = document.createElement("div"), e.id = "rj-parsing-error-root", document.body.appendChild(e)), !n.current) { const p = document.createElement("div"); e.appendChild(p), n.current = p; } Z( mt.createPortal( /* @__PURE__ */ C( Dt, { processedRjBuild: t, errorContext: { rjBuildUrl: f, rjBuildFetchMethod: b, headersForRjBuild: c, maybeRawAppRjBuild: d } } ), n.current, () => { n.current && (n.current.parentNode.removeChild(n.current), n.current = null); } ) ); } return; } V && (Z(null), typeof document < "u" && n.current && n.current.parentNode && (n.current.parentNode.removeChild(n.current), n.current = null)); const a = t.data; ot(a.templates ?? a.listForms), !a.templates && a.listForms && console.log( "'listForms' needs to be renamed to 'templates'. The support for 'listForms' will be removed in the next releases of reactive-json." ); let i = S === void 0 ? a.data : S; const s = a.additionalDataSource; if (!Array.isArray(s) || s.length === 0) { g({ type: "setData", data: i }), Q(a.renderView), Y(Object.keys(a.renderView)); return; } const m = { headersForRjBuild: c, plugins: E, templateData: i, templatePath: "data", setData: R, updateData: W }, r = { templateData: i, templatePath: "data" }, l = s.filter((e) => e.blocking === !0), v = s.filter((e) => e.blocking !== !0), o = async (e, p) => { var y; try { if (!e.src) { console.warn("additionalDataSource item number " + p + " missing 'src' property.", e); return; } const D = { method: ((y = e.method) == null ? void 0 : y.toUpperCase()) || "GET", url: e.src }; c && Object.keys(c).length > 0 && (D.headers = c); const k = await _(D), ct = { url: D.url, method: D.method, headers: D.headers || {}, body: D.data }, lt = { headers: k.headers || {}, status: k.status, data: k.data }, P = bt({ requestContext: ct, responseContext: lt, responseBody: k.data, // additionalDataSource always processes raw data, not RjBuild. isRjBuild: !1, dataProcessors: (E == null ? void 0 : E.dataProcessor) || {} }); if (e.dataMapping) try { Et({ dataMapping: e.dataMapping, responseData: P, globalDataContext: m, templateContext: r }); return; } catch (u) { console.error("Error applying dataMapping for additionalDataSource:", u); } if (!e.path) { if (typeof P != "object" || Array.isArray(P)) { console.warn( "additionalDataSource data cannot be merged at root - must be an object:", P ); return; } Object.entries(P).forEach(([u, G]) => { g({ type: "updateData", path: u, value: G }); }); return; } try { const u = Ct({ dataLocation: e.path, currentPath: "data", globalDataContext: m, templateContext: r }); if (typeof u != "string") { console.warn( "additionalDataSource path evaluation did not result in a string:", e.path, "->", u ); return; } const G = u.substring(5); g({ type: "updateData", path: G, value: P }); } catch (u) { console.error("Error evaluating additionalDataSource path:", e.path, u); } } catch (B) { console.error("Error fetching additional data source:", e.src, B); } }; g({ type: "setData", data: i }), (async () => { if (l.length > 0) { const e = l.map((p, y) => o(p, y)); await Promise.allSettled(e).catch((p) => { console.error("Error processing blocking additionalDataSource:", p); }); } if (Q(a.renderView), Y(Object.keys(a.renderView)), v.length > 0) { const e = v.map( (p, y) => o(p, l.length + y) ); Promise.allSettled(e); } })(); }, [I, S, c]); function j(t, a, i) { if (!N || N.size === 0) return !1; for (const [s, m] of N) if (t === s || t.startsWith(s + ".") || s === "") { const r = s === "" ? t : t.substring(s.length + 1); try { return m(a, r, i), !0; } catch (l) { console.warn("Error during upstream update:", l); break; } } return !1; } function W(t, a, i = void 0) { let s = a.replace("data.", ""); j(s, t, i) || g({ type: "updateData", path: s, value: t, updateMode: i }); } function R(t) { j("", t, void 0) || g({ type: "setData", data: t }); } function it(t, a, i, s = void 0) { const m = a.split("."); (typeof t.realCurrentData != "object" || t.realCurrentData === null || Array.isArray(t.realCurrentData)) && (t.realCurrentData = {}); let r = t.realCurrentData; for (let l = 0, v = m.length; l < v; l++) { const o = m[l]; if (l === v - 1) { if (s === "remove" && Array.isArray(r)) r.splice(o, 1); else if (s === "move") if (i.increment) { if (!Array.isArray(r)) return t; const J = Math.min( r.length, Math.max(0, parseInt(o) + parseInt(i.increment)) ); if (J === parseInt(o)) return t; const e = r.splice(o, 1); if (e.length < 1) return t; r.splice(J, 0, e[0]); } else return t; else if (i === void 0) delete r[o]; else { if (ut.isEqual(i, r[o])) return t; s === "add" ? (r[o] === void 0 && (r[o] = []), r[o].push(i)) : r[o] = i; } return { // Using modulo in case of massive update counts in long frontend sessions. updateId: (t.updateId ?? 0) % (Number.MAX_SAFE_INTEGER - 1) + 1, realCurrentData: t.realCurrentData }; } if (r.hasOwnProperty(o)) { (typeof r[o] != "object" || r[o] === null) && (r[o] = {}), r = r[o]; continue; } r[o] = {}, r = r[o]; } throw new Error("Could not update data."); } if (!I) return null; const U = st.map((t) => { var a; return /* @__PURE__ */ C( St, { datafield: t, props: nt[t], path: "data." + t, currentData: (a = x.realCurrentData) == null ? void 0 : a[t] }, t ); }), O = wt(et), F = /* @__PURE__ */ C(gt, { children: /* @__PURE__ */ L( yt, { value: { element: at, headersForRjBuild: c, plugins: E, // Expose the root component to avoid import cycles in core plugins. ReactiveJsonRoot: xt, setData: R, setRawAppRjBuild: T, templateData: x.realCurrentData, templatePath: "data", updateData: W }, children: [ /* @__PURE__ */ C( Pt.Provider, { value: { templateData: x.realCurrentData, templatePath: "data" }, children: O && A ? /* @__PURE__ */ C(A, { children: U }) : U } ), O ? K && /* @__PURE__ */ C(K, { children: JSON.stringify(x.realCurrentData, null, " ") }) : null ] } ) }); return O && A ? /* @__PURE__ */ L(rt, { children: [ F, V ] }) : /* @__PURE__ */ L(pt, { children: [ F, V ] }); }; export { xt as ReactiveJsonRoot };