diff --git a/app/srv/ws/sync/actions/code_edit.ts b/app/srv/ws/sync/actions/code_edit.ts index 521762ff..485ac1f0 100644 --- a/app/srv/ws/sync/actions/code_edit.ts +++ b/app/srv/ws/sync/actions/code_edit.ts @@ -38,6 +38,7 @@ export const code_edit: SAction["code"]["edit"] = async function ( if (root) { const mitem = findId(root, item_id); + if (mitem) { if (arg.type === "adv") { const mode = arg.mode; @@ -78,6 +79,7 @@ export const code_edit: SAction["code"]["edit"] = async function ( .get("component") ?.get("props") ?.get(arg.prop_name); + if (mprop) { try { const res = await transform(`return ${src}`, { @@ -137,7 +139,6 @@ export const code_edit: SAction["code"]["edit"] = async function ( } } } - return false; }; 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 e0341d0c..9148cdb9 100644 --- a/app/web/src/nova/ed/panel/popup/script/monaco.tsx +++ b/app/web/src/nova/ed/panel/popup/script/monaco.tsx @@ -211,7 +211,7 @@ export const EdScriptMonaco: FC<{}> = () => { }); } else if (p.ui.popup.script.type === "prop-instance") { scope = await p.sync.code.edit({ - type: "adv", + type: "prop-instance", mode: type, prop_name: p.ui.popup.script.prop_name, item_id: active.item_id, diff --git a/app/web/src/nova/ed/panel/popup/script/scope/scope.tsx b/app/web/src/nova/ed/panel/popup/script/scope/scope.tsx index 2802fcdb..bd7db2c6 100644 --- a/app/web/src/nova/ed/panel/popup/script/scope/scope.tsx +++ b/app/web/src/nova/ed/panel/popup/script/scope/scope.tsx @@ -65,14 +65,6 @@ const map_childs = ( for (const m of childs) { const meta = metas[m.id]; if (meta) { - if ( - meta.item.type === "item" && - meta.item.component?.id && - meta.item.component?.id !== active.comp_id - ) { - continue; - } - let cur: null | IMeta[] = null; for (const path of paths) { if (path[path.length - 1] === parent) { @@ -88,8 +80,16 @@ const map_childs = ( } if (cur) { - if (Array.isArray(meta.item.childs)) { - map_childs(metas, meta.item.childs, paths, cur, meta); + if ( + meta.item.type === "item" && + meta.item.component?.id && + meta.item.component?.id !== active.comp_id + ) { + continue; + } else { + if (Array.isArray(meta.item.childs)) { + map_childs(metas, meta.item.childs, paths, cur, meta); + } } } } diff --git a/app/web/src/nova/ed/panel/popup/script/snippet.tsx b/app/web/src/nova/ed/panel/popup/script/snippet.tsx index 3fe767ca..e566b550 100644 --- a/app/web/src/nova/ed/panel/popup/script/snippet.tsx +++ b/app/web/src/nova/ed/panel/popup/script/snippet.tsx @@ -46,9 +46,7 @@ effect={async (local) => { onClick={() => { p.script.do_edit( `\ - -{children} - + `, false ); @@ -63,9 +61,9 @@ effect={async (local) => { `\
{(local.list || []).map((item, idx) => ( - -{children} - + + + ))}
`, diff --git a/app/web/src/nova/ed/panel/popup/script/workbench.tsx b/app/web/src/nova/ed/panel/popup/script/workbench.tsx index 0300437c..5d71f94e 100644 --- a/app/web/src/nova/ed/panel/popup/script/workbench.tsx +++ b/app/web/src/nova/ed/panel/popup/script/workbench.tsx @@ -68,6 +68,9 @@ const CompTitleInstance = () => { const props = item.component.props; return (
+
+ INSTANCE +
{item.name}
{p.ui.popup.script.prop_name}
@@ -91,6 +94,9 @@ const CompTitleMaster = () => { const props = item.component.props; return (
+
+ MASTER +
{item.name}
{p.ui.popup.script.prop_name}
diff --git a/app/web/src/nova/ed/panel/side/prop-instance.tsx b/app/web/src/nova/ed/panel/side/prop-instance.tsx index cd583cf2..43af5a2d 100644 --- a/app/web/src/nova/ed/panel/side/prop-instance.tsx +++ b/app/web/src/nova/ed/panel/side/prop-instance.tsx @@ -1,4 +1,4 @@ -import { FC } from "react"; +import { FC, MouseEvent } from "react"; import { useGlobal, useLocal } from "web-utils"; import { IItem } from "../../../../utils/types/item"; import { FMCompDef } from "../../../../utils/types/meta-fn"; @@ -8,12 +8,13 @@ import { EdPropInstanceCode } from "./prop-instance/prop-code"; import { EdPropInstanceOptions } from "./prop-instance/prop-option"; import { reset } from "./prop-instance/prop-reset"; import { EdPropInstanceText } from "./prop-instance/prop-text"; +import { createEditScript } from "./prop-instance/edit-script"; export const EdSidePropInstance: FC<{ meta: IMeta }> = ({ meta }) => { const p = useGlobal(EDGlobal, "EDITOR"); const local = useLocal({ rightClickEvent: null as any, - reset: { mprop: null as any, name: "" }, + pick: { mprop: null as any, name: "" }, showJSX: false, }); @@ -125,12 +126,20 @@ export const EdSidePropInstance: FC<{ meta: IMeta }> = ({ meta }) => { { - if (local.reset.name) { - reset(p, comp_id, local.reset.mprop, local.reset.name); + if (local.pick.name) { + reset(p, comp_id, local.pick.mprop, local.pick.name); } }} /> - {}} /> + )} {filtered.length === 0 && ( @@ -143,35 +152,52 @@ export const EdSidePropInstance: FC<{ meta: IMeta }> = ({ meta }) => { let hasCode = false; const value = mprop.get("value") || ""; - if (!!value && ![`"`, "'", "`"].includes(value[0])) { + if ( + !!value && + (![`"`, "'", "`"].includes(value[0]) || + ![`"`, "'", "`"].includes(value[value.length - 1])) + ) { hasCode = true; } if (value.length > 100) { hasCode = true; } + const labelClick = (e: MouseEvent) => { + e.preventDefault(); + local.pick = { mprop, name }; + local.rightClickEvent = e; + local.render(); + }; return (
{ - e.preventDefault(); - local.reset = { mprop, name }; - local.rightClickEvent = e; - local.render(); - }} + className="border-b text-[13px] relative hover:bg-orange-100 cursor-default" + onContextMenu={labelClick} > {hasCode ? ( <> - + ) : ( <> {type === "text" && ( - + )} {type === "option" && ( - + )} {type === "content-element" && (
diff --git a/app/web/src/nova/ed/panel/side/prop-instance/edit-script.tsx b/app/web/src/nova/ed/panel/side/prop-instance/edit-script.tsx new file mode 100644 index 00000000..5133f0e3 --- /dev/null +++ b/app/web/src/nova/ed/panel/side/prop-instance/edit-script.tsx @@ -0,0 +1,25 @@ +import { MouseEventHandler } from "react"; +import { FMCompDef } from "../../../../../utils/types/meta-fn"; +import { PG, PropFieldKind } from "../../../logic/ed-global"; + +export const createEditScript = ( + p: PG, + kind: PropFieldKind, + mprop: FMCompDef, + name: string +) => { + return ((e) => { + e.preventDefault(); + e.stopPropagation(); + + const meta = mprop.get("meta"); + if (meta) { + p.ui.popup.script.mode = "js"; + p.ui.popup.script.open = true; + p.ui.popup.script.type = "prop-instance"; + p.ui.popup.script.prop_kind = kind; + p.ui.popup.script.prop_name = name; + p.render(); + } + }) as MouseEventHandler; +}; diff --git a/app/web/src/nova/ed/panel/side/prop-instance/prop-code.tsx b/app/web/src/nova/ed/panel/side/prop-instance/prop-code.tsx index afe29924..587e428a 100644 --- a/app/web/src/nova/ed/panel/side/prop-instance/prop-code.tsx +++ b/app/web/src/nova/ed/panel/side/prop-instance/prop-code.tsx @@ -7,11 +7,12 @@ import { EDGlobal, active } from "../../../logic/ed-global"; export const EdPropInstanceCode: FC<{ name: string; mprop: FMCompDef; -}> = ({ name, mprop }) => { + labelClick?: React.MouseEventHandler | undefined; +}> = ({ name, labelClick }) => { const p = useGlobal(EDGlobal, "EDITOR"); return (
- +
= ({ name }) => { +export const EdPropLabel: FC<{ + name: string; + labelClick?: React.MouseEventHandler | undefined; +}> = ({ name, labelClick }) => { const label = ( -
-
+
+
{name}
diff --git a/app/web/src/nova/ed/panel/side/prop-instance/prop-option.tsx b/app/web/src/nova/ed/panel/side/prop-instance/prop-option.tsx index a34f530e..60fde070 100644 --- a/app/web/src/nova/ed/panel/side/prop-instance/prop-option.tsx +++ b/app/web/src/nova/ed/panel/side/prop-instance/prop-option.tsx @@ -10,7 +10,8 @@ import { EdPropLabel } from "./prop-label"; export const EdPropInstanceOptions: FC<{ name: string; mprop: FMCompDef; -}> = ({ name, mprop }) => { + labelClick?: React.MouseEventHandler | undefined; +}> = ({ name, mprop, labelClick }) => { const prop = mprop.toJSON() as FNCompDef; const local = useLocal({ codeEditing: false, @@ -85,7 +86,7 @@ else metaOptions = resOpt; if (!mode) mode = "button"; return (
- +
{mode === "dropdown" && ( <> diff --git a/app/web/src/nova/ed/panel/side/prop-instance/prop-text.tsx b/app/web/src/nova/ed/panel/side/prop-instance/prop-text.tsx index f3c8dcdb..b94e0d5b 100644 --- a/app/web/src/nova/ed/panel/side/prop-instance/prop-text.tsx +++ b/app/web/src/nova/ed/panel/side/prop-instance/prop-text.tsx @@ -12,7 +12,8 @@ import { EdPropLabel } from "./prop-label"; export const EdPropInstanceText: FC<{ name: string; mprop: FMCompDef; -}> = ({ name, mprop }) => { + labelClick?: React.MouseEventHandler | undefined; +}> = ({ name, mprop, labelClick }) => { const val = mprop.get("value"); const local = useLocal({ @@ -28,7 +29,7 @@ export const EdPropInstanceText: FC<{ return (
- + { ids: instance, }); + if (item.component) { + item.component.loaded = true; + } + let smeta = p.comps[item.component.id].smeta; if (smeta) { smeta = applySMeta(smeta, instance); diff --git a/app/web/src/nova/vi/render/parts.tsx b/app/web/src/nova/vi/render/parts.tsx index b6f1e8e4..23554359 100644 --- a/app/web/src/nova/vi/render/parts.tsx +++ b/app/web/src/nova/vi/render/parts.tsx @@ -34,9 +34,11 @@ export const viParts = ( const childs = meta.item.childs; let children = undefined; + if ((meta.item as IContent).type === "text") { children = ; } else { + children = Array.isArray(childs) && childs?.map((item) => { diff --git a/app/web/src/nova/vi/render/render.tsx b/app/web/src/nova/vi/render/render.tsx index 45ba6db0..7f9c415c 100644 --- a/app/web/src/nova/vi/render/render.tsx +++ b/app/web/src/nova/vi/render/render.tsx @@ -13,6 +13,7 @@ export const ViRender: FC<{ }> = ({ meta, children, passprop }) => { if (!meta) return null; + if (meta.item.hidden) return null; if (meta.item.adv?.js || meta.item.component?.id) { diff --git a/app/web/src/nova/vi/render/script.tsx b/app/web/src/nova/vi/render/script.tsx index d554e548..0dc62d84 100644 --- a/app/web/src/nova/vi/render/script.tsx +++ b/app/web/src/nova/vi/render/script.tsx @@ -22,8 +22,8 @@ export const ViScript: FC<{ } if (meta.item.adv?.js) { - viEvalScript(vi, meta, _pass); - if (meta.script) return meta.script.result; + const mhash = viEvalScript(vi, meta, _pass); + if (meta.script && meta.script[mhash]) return meta.script[mhash].result; } return ( diff --git a/app/web/src/nova/vi/render/script/eval-script.tsx b/app/web/src/nova/vi/render/script/eval-script.tsx index 02d2702f..30b51bc1 100644 --- a/app/web/src/nova/vi/render/script/eval-script.tsx +++ b/app/web/src/nova/vi/render/script/eval-script.tsx @@ -7,6 +7,7 @@ import { viScriptArg } from "./arg"; import { updatePropScope } from "./eval-prop"; import { createViLocal } from "./local"; import { createViPassProp } from "./passprop"; +import hash_sum from "hash-sum"; export const viEvalScript = ( vi: { @@ -21,8 +22,11 @@ export const viEvalScript = ( if (vi.visit) vi.visit(meta, parts); - if (!meta.script) { - meta.script = { + const mhash = hash_sum(passprop); + + if (!meta.script) meta.script = {}; + if (!meta.script[mhash]) { + meta.script[mhash] = { result: null, Local: createViLocal( vi.meta, @@ -33,7 +37,7 @@ export const viEvalScript = ( PassProp: createViPassProp(vi, meta, passprop), }; } - const script = meta.script; + const script = meta.script[mhash]; const exports = (window as any).exports; const arg = { @@ -61,4 +65,5 @@ ${meta.item.adv?.jsBuilt || ""} fn(...Object.values(arg)); updatePropScope(meta, passprop); + return mhash; }; diff --git a/app/web/src/nova/vi/render/script/passprop.tsx b/app/web/src/nova/vi/render/script/passprop.tsx index f5e4c619..07794763 100644 --- a/app/web/src/nova/vi/render/script/passprop.tsx +++ b/app/web/src/nova/vi/render/script/passprop.tsx @@ -32,6 +32,7 @@ const modify = (el: ReactNode, arg: any, passprop?: any) => { if (isValidElement(el)) { const passarg = { ...arg }; delete passarg.children; + return { ...el, props: { ...el.props, passprop: { ...passprop, ...passarg } }, diff --git a/app/web/src/nova/vi/utils/types.ts b/app/web/src/nova/vi/utils/types.ts index 6cc9d822..a406f9c5 100644 --- a/app/web/src/nova/vi/utils/types.ts +++ b/app/web/src/nova/vi/utils/types.ts @@ -59,11 +59,14 @@ export type IMeta = { comp_id: string; is_root: boolean; }; - script?: { - result: ReactNode; - Local: ReturnType; - PassProp: ReturnType; - }; + script?: Record< + string, + { + result: ReactNode; + Local: ReturnType; + PassProp: ReturnType; + } + >; scope: { def?: ReturnType; }; diff --git a/app/web/src/utils/types/meta-fn.ts b/app/web/src/utils/types/meta-fn.ts index d2faa9e2..a98eaee7 100644 --- a/app/web/src/utils/types/meta-fn.ts +++ b/app/web/src/utils/types/meta-fn.ts @@ -22,7 +22,7 @@ export type FMAdv = TypedMap; export type FNComponent = { id: string; name?: string; - updated_at?: number; + loaded?: boolean; props: Record; ref_ids?: Record; };