From 209d26ac9ab3ddf0975d035c93c3e46749a6d974 Mon Sep 17 00:00:00 2001 From: Rizky Date: Sun, 10 Dec 2023 15:45:16 +0700 Subject: [PATCH] wip fix --- .../src/nova/ed/panel/popup/script/monaco.tsx | 9 +- .../src/nova/ed/panel/popup/script/scope.tsx | 50 +++++--- app/web/src/nova/view/logic/meta/comp.tsx | 117 ++++++++++++++++++ .../view/logic/meta/comp/eval-prop-vis.ts | 20 +++ .../nova/view/logic/meta/comp/instantiate.tsx | 40 ++++++ .../nova/view/logic/meta/comp/walk-prop.tsx | 32 +++++ app/web/src/nova/view/logic/meta/meta.tsx | 65 ++++++++++ app/web/src/nova/view/logic/meta/ref-ids.tsx | 34 +++++ app/web/src/nova/view/logic/meta/simplify.tsx | 18 +++ app/web/src/nova/view/logic/meta/types.ts | 52 ++++++++ 10 files changed, 420 insertions(+), 17 deletions(-) create mode 100644 app/web/src/nova/view/logic/meta/comp.tsx create mode 100644 app/web/src/nova/view/logic/meta/comp/eval-prop-vis.ts create mode 100644 app/web/src/nova/view/logic/meta/comp/instantiate.tsx create mode 100644 app/web/src/nova/view/logic/meta/comp/walk-prop.tsx create mode 100644 app/web/src/nova/view/logic/meta/meta.tsx create mode 100644 app/web/src/nova/view/logic/meta/ref-ids.tsx create mode 100644 app/web/src/nova/view/logic/meta/simplify.tsx create mode 100644 app/web/src/nova/view/logic/meta/types.ts diff --git a/app/web/src/nova/ed/panel/popup/script/monaco.tsx b/app/web/src/nova/ed/panel/popup/script/monaco.tsx index 4065c702..3f872bee 100644 --- a/app/web/src/nova/ed/panel/popup/script/monaco.tsx +++ b/app/web/src/nova/ed/panel/popup/script/monaco.tsx @@ -51,6 +51,7 @@ export const ScriptMonaco = () => { (async () => { const editor = local.editor; const monaco = local.monaco; + if (monaco && editor) { if (!local.init) { if (p.ui.popup.script.mode === "js") { @@ -87,9 +88,11 @@ export const ScriptMonaco = () => { monaco, { types: {}, values: {} } ); - declareScope(p, editor, monaco).then(() => { - local.render(); - }); + if (meta) { + declareScope(p, meta, editor, monaco).then(() => { + local.render(); + }); + } } local.init = true; diff --git a/app/web/src/nova/ed/panel/popup/script/scope.tsx b/app/web/src/nova/ed/panel/popup/script/scope.tsx index 4eec377d..53a6d2b6 100644 --- a/app/web/src/nova/ed/panel/popup/script/scope.tsx +++ b/app/web/src/nova/ed/panel/popup/script/scope.tsx @@ -1,26 +1,48 @@ import type { OnMount } from "@monaco-editor/react"; import { deepClone } from "web-utils"; -import { EPage, ISingleScope, PG, active } from "../../../logic/ed-global"; +import { + EPage, + EdMeta, + ISingleScope, + PG, + active, +} from "../../../logic/ed-global"; import { getMetaById } from "../../../logic/tree/build"; type Monaco = Parameters[1]; export type MonacoEditor = Parameters[0]; export const declareScope = async ( p: PG, + meta: EdMeta, editor: MonacoEditor, monaco: Monaco ) => { let active_id = active.item_id; - let s = deepClone(p.page.scope[active_id]); - if (active.comp_id && p.comp.list[active.comp_id]) { - s = deepClone(p.comp.list[active.comp_id].scope[active.item_id]); + const root = active.comp_id + ? p.comp.list[active.comp_id].scope + : p.page.scope; + + const meta_root = active.comp_id + ? p.comp.list[active.comp_id].meta + : p.page.meta; + + if (!root) return; + + let cur = meta; + while (!root[cur.item.id]) { + const parent = meta_root[cur.parent_item.id]; + if (parent) { + cur = parent; + } else { + break; + } } + const s = root[cur.item.id]; if (!s) return; s.p.push(active_id); - const existing: Record = {}; spreadScope(p, s, (arg) => { @@ -50,10 +72,10 @@ export const declareScope = async ( arg.type }~${arg.name}~${arg.id}`, `\ -export const {}; -declare global { - const ${arg.name} = ${arg.value}; -}` + export const {}; + declare global { + const ${arg.name} = ${arg.value}; + }` ); } else { addScope( @@ -62,11 +84,11 @@ declare global { arg.type }~${arg.id}`, `\ -export const {}; -const __val = ${arg.value}; -declare global { - const ${arg.name}: typeof __val & { render: ()=>void }; -}` + export const {}; + const __val = ${arg.value}; + declare global { + const ${arg.name}: typeof __val & { render: ()=>void }; + }` ); } }); diff --git a/app/web/src/nova/view/logic/meta/comp.tsx b/app/web/src/nova/view/logic/meta/comp.tsx new file mode 100644 index 00000000..d2d852fa --- /dev/null +++ b/app/web/src/nova/view/logic/meta/comp.tsx @@ -0,0 +1,117 @@ +import { MItem } from "../../../../utils/types/item"; +import { evalPropVis } from "./comp/eval-prop-vis"; +import { instantiate } from "./comp/instantiate"; +import { walkProp } from "./comp/walk-prop"; +import { genMeta } from "./meta"; +import { applyRefIds } from "./ref-ids"; +import { simplify } from "./simplify"; +import { GenMetaArg, GenMetaP, IMeta } from "./types"; + +export const genComp = ( + p: GenMetaP, + arg: GenMetaArg, + r: ReturnType +) => { + const { item } = arg; + const mitem = arg.mitem as MItem; + if (item.type === "item" && item.component?.id && arg.parent?.item.id) { + let pcomp = p.comps[item.component.id]; + if (!pcomp && p.on.load_component) { + p.on.load_component(item.component.id); + return; + } + if (pcomp) { + const ref_ids = r?.ref_ids || item.component?.ref_ids || {}; + let mref_ids = r?.mref_ids || mitem.get("component")?.get("ref_ids"); + + if (!mref_ids && mitem) { + mitem.get("component")?.set("ref_ids", new Y.Map() as any); + mref_ids = mitem.get("component")?.get("ref_ids"); + } + + instantiate(item, pcomp.comp, ref_ids, mref_ids); + + const meta: IMeta = { + item: simplify(item), + parent: { + id: arg.parent.item.id, + instance_id: arg.parent?.instance?.id, + comp_id: arg.parent?.comp?.id, + }, + scope: { + def: { + props: {}, + }, + }, + }; + + const props = {} as Record; + + walkProp({ + item, + mitem: mitem, + pcomp, + each(name, prop, mprop) { + if (meta.scope.def?.props) { + meta.scope.def.props[name] = { + value: prop.valueBuilt, + visible: true, + }; + } + props[name] = { value: prop.valueBuilt, visible: prop.visible }; + if (prop.meta?.type === "content-element" && prop.content) { + genMeta(p, { + item: prop.content, + mitem: mprop?.get("content"), + is_root: false, + jsx_prop: { + is_root: true, + name, + }, + parent: { + item, + mitem: mitem, + comp: pcomp.comp, + mcomp: pcomp.mcomp, + instance: arg.parent?.instance || item, + minstance: arg.parent?.minstance || mitem, + }, + }); + } + }, + }); + + const vis = evalPropVis(props); + if (vis && meta.scope.def?.props) { + for (const [k, v] of Object.entries(vis)) { + if (meta.scope.def.props[k]) { + meta.scope.def.props[k].visible = !!v; + } + } + } + + p.meta[item.id] = meta; + + if (p.on.visit) { + p.on.visit(meta); + } + + for (const [k, v] of Object.entries(item.childs)) { + const mchild = mitem.get("childs")?.get(k as unknown as number); + genMeta(p, { + item: v, + mitem: mchild, + is_root: false, + parent: { + item, + mitem: mitem, + comp: pcomp.comp, + mcomp: pcomp.mcomp, + instance: arg.parent?.instance || item, + minstance: arg.parent?.minstance || mitem, + }, + }); + } + } + } +}; diff --git a/app/web/src/nova/view/logic/meta/comp/eval-prop-vis.ts b/app/web/src/nova/view/logic/meta/comp/eval-prop-vis.ts new file mode 100644 index 00000000..8ffb059c --- /dev/null +++ b/app/web/src/nova/view/logic/meta/comp/eval-prop-vis.ts @@ -0,0 +1,20 @@ +export const evalPropVis = ( + props: Record +) => { + try { + const fn = new Function(` +${Object.entries(props) + .map(([k, v]) => `const ${k} = ${v.value};`) + .join("\n")} + +return { + ${Object.entries(props) + .filter(([k, v]) => v.visible) + .map(([k, v]) => `${k}: ${v},`) + .join("\n")} +} +`); + + return fn() as Record; + } catch (e) {} +}; diff --git a/app/web/src/nova/view/logic/meta/comp/instantiate.tsx b/app/web/src/nova/view/logic/meta/comp/instantiate.tsx new file mode 100644 index 00000000..2f227ee2 --- /dev/null +++ b/app/web/src/nova/view/logic/meta/comp/instantiate.tsx @@ -0,0 +1,40 @@ +import { TypedMap } from "yjs-types"; +import { IItem } from "../../../../../utils/types/item"; +import { applyRefIds } from "../ref-ids"; +import { createId } from "@paralleldrive/cuid2"; + +export const instantiate = ( + item: IItem, + comp: IItem, + ref_ids: Record, + mref_ids?: Record & TypedMap> +) => { + const newitem = structuredClone(comp); + if (item.id) { + newitem.id = item.id; + } + if (item.component) { + newitem.component = item.component; + } + + walkChild(newitem, ref_ids, mref_ids); +}; + +const walkChild = ( + item: IItem, + ref_ids: Record, + mref_ids?: Record & TypedMap> +) => { + if (!ref_ids[item.id]) { + ref_ids[item.id] = createId(); + mref_ids?.set(item.id, ref_ids[item.id]); + } + + item.id = ref_ids[item.id]; + + if (item.childs) { + for (const child of item.childs) { + walkChild(item, ref_ids, mref_ids); + } + } +}; diff --git a/app/web/src/nova/view/logic/meta/comp/walk-prop.tsx b/app/web/src/nova/view/logic/meta/comp/walk-prop.tsx new file mode 100644 index 00000000..39a9507a --- /dev/null +++ b/app/web/src/nova/view/logic/meta/comp/walk-prop.tsx @@ -0,0 +1,32 @@ +import { IItem, MItem } from "../../../../../utils/types/item"; +import { FMCompDef, FNCompDef } from "../../../../../utils/types/meta-fn"; + +export const walkProp = (arg: { + item: IItem; + mitem?: MItem; + pcomp: { comp: IItem; mcomp?: MItem }; + each: (name: string, prop: FNCompDef, mprop?: FMCompDef) => void; +}) => { + for (const [k, v] of Object.entries(arg.pcomp.comp.component?.props || {})) { + let mprop = arg.mitem?.get("component")?.get("props")?.get(k); + if (!mprop) { + const map = new Y.Map() as any; + syncronize(map, v); + arg.mitem?.get("component")?.get("props")?.set(k, map); + mprop = arg.mitem?.get("component")?.get("props")?.get(k); + } + + const props = arg.item.component?.props; + let prop = props?.[k]; + if (props) { + if (!props[k]) { + props[k] = v; + prop = v; + } + } + + if (prop) { + arg.each(k, prop, mprop); + } + } +}; diff --git a/app/web/src/nova/view/logic/meta/meta.tsx b/app/web/src/nova/view/logic/meta/meta.tsx new file mode 100644 index 00000000..f8b69254 --- /dev/null +++ b/app/web/src/nova/view/logic/meta/meta.tsx @@ -0,0 +1,65 @@ +import { IItem, MItem } from "../../../../utils/types/item"; +import { genComp } from "./comp"; +import { applyRefIds } from "./ref-ids"; +import { simplify } from "./simplify"; +import { GenMetaArg, GenMetaP, IMeta } from "./types"; + +export const genMeta = (p: GenMetaP, arg: GenMetaArg) => { + let wrapper = (fn: any) => { + fn(); + }; + + if (arg.is_root && arg.mitem) { + const transact = arg.mitem.doc?.transact; + if (transact) { + wrapper = transact; + } + } + + wrapper(() => { + const { parent } = arg; + const item = arg.item as IItem; + const mitem = arg.mitem as MItem; + + const r = applyRefIds(item, mitem, parent); + if (item.type === "item" && item.component?.id) { + genComp(p, arg, r); + return; + } + + const meta: IMeta = { + item: simplify(item), + parent: { + id: arg.parent?.item.id || "root", + instance_id: arg.parent?.instance?.id, + comp_id: arg.parent?.comp?.id, + }, + scope: {}, + }; + + if (p.on.visit) { + p.on.visit(meta); + } + + p.meta[item.id] = meta; + + if (item.childs) { + for (const [k, v] of Object.entries(item.childs)) { + const mchild = mitem.get("childs")?.get(k as unknown as number); + genMeta(p, { + item: v, + mitem: mchild, + is_root: false, + parent: { + item, + mitem: mitem, + comp: arg.parent?.comp, + mcomp: arg.parent?.mcomp, + instance: arg.parent?.instance, + minstance: arg.parent?.minstance, + }, + }); + } + } + }); +}; diff --git a/app/web/src/nova/view/logic/meta/ref-ids.tsx b/app/web/src/nova/view/logic/meta/ref-ids.tsx new file mode 100644 index 00000000..6ad380a4 --- /dev/null +++ b/app/web/src/nova/view/logic/meta/ref-ids.tsx @@ -0,0 +1,34 @@ +import { createId } from "@paralleldrive/cuid2"; +import { IContent, MContent } from "../../../../utils/types/general"; +import { IItem } from "../../../../utils/types/item"; + +export const applyRefIds = ( + item: IContent, + mitem?: MContent, + parent?: { instance?: IItem; minstance?: MContent } +) => { + const instance = parent?.instance; + + if (instance && instance.component) { + let mref_ids = parent?.minstance?.get("component")?.get("ref_ids"); + if (!mref_ids) { + mref_ids = new Y.Map() as any; + } + + if (mref_ids) parent?.minstance?.get("component")?.set("ref_ids", mref_ids); + + const ref_ids = instance.component.ref_ids || {}; + if (!ref_ids[item.id]) { + ref_ids[item.id] = createId(); + mref_ids?.set(item.id, ref_ids[item.id]); + } + + if (ref_ids[item.id]) { + if (!item.originalId) item.originalId = item.id; + item.id = ref_ids[item.id]; + mitem?.set("id", item.id); + } + + return { ref_ids, mref_ids }; + } +}; diff --git a/app/web/src/nova/view/logic/meta/simplify.tsx b/app/web/src/nova/view/logic/meta/simplify.tsx new file mode 100644 index 00000000..c0c4825d --- /dev/null +++ b/app/web/src/nova/view/logic/meta/simplify.tsx @@ -0,0 +1,18 @@ +import { IItem } from "../../../../utils/types/item"; + +export const simplify = (item: IItem) => { + const newitem = {} as any; + for (const [k, v] of Object.entries(item)) { + if (k === "childs") { + newitem.childs = []; + if (v && Array.isArray(v)) { + for (const child of v) { + newitem.childs.push({ id: child.id }); + } + } + } else { + newitem[k] = v; + } + } + return newitem as IItem; +}; diff --git a/app/web/src/nova/view/logic/meta/types.ts b/app/web/src/nova/view/logic/meta/types.ts new file mode 100644 index 00000000..eff59ba3 --- /dev/null +++ b/app/web/src/nova/view/logic/meta/types.ts @@ -0,0 +1,52 @@ +import { IContent, MContent } from "../../../../utils/types/general"; +import { IItem, MItem } from "../../../../utils/types/item"; + +export type GenMetaP = { + meta: Record; + comps: Record; + on: { + load_component?: (id: string) => Promise<{ item: IItem; mcomp?: MItem }>; + visit?: (meta: IMeta) => void; + }; +}; + +export type GenMetaArg = { + item: IContent; + is_root?: boolean; + mitem?: MContent; + jsx_prop?: IMeta["jsx_prop"]; + parent?: { + item: IItem; + mitem?: MItem; + comp?: IItem; + mcomp?: MItem; + instance?: IItem; + minstance?: MItem; + }; +}; + +export type IMeta = { + item: IItem; + parent?: { + id: string; + instance_id?: string; + comp_id?: string; + }; + jsx_prop?: { + name: string; + is_root: boolean; + }; + scope: { + val?: any; + def?: { + props?: Record; + local?: { + name: string; + idx: number; + idxval: Record; + src: string; + }; + pass?: Record; + }; + }; +};