This commit is contained in:
Rizky 2023-11-24 16:35:45 +07:00
parent c530a293ab
commit b5ff765254
15 changed files with 257 additions and 49 deletions

View File

@ -95,8 +95,31 @@ export const serverWalkMap = (
) => {
const { mitem, parent_item, parent_mcomp } = arg;
let override_id = "";
const id = mitem.get("id");
if (parent_mcomp && id) {
const fcomp = parent_mcomp.mitem.get("component");
if (fcomp) {
const ref_ids = fcomp.get("ref_ids");
if (ref_ids) {
let ref_id = ref_ids.get(id);
if (!ref_id) {
ref_id = createId();
ref_ids.set(id, ref_id);
}
override_id = ref_id;
}
}
}
const item = {} as unknown as IItem;
mapItem(mitem, item);
if (override_id) {
item.id = override_id;
}
const item_comp = item.component;
const mitem_comp = mitem.get("component");
@ -126,28 +149,27 @@ export const serverWalkMap = (
mapItem(mcomp, item);
item.id = original_id;
const pcomp = p.scope_comps[item_comp.id];
pcomp.scope[item.id] = { p: arg.parent_ids, s: null };
const js = item.adv?.js;
if (typeof js === "string") {
const scope = parseJs(js);
if (scope) pcomp.scope[item.id].s = scope;
}
const mprops = mcomp.get("component")?.get("props")?.toJSON() as Record<
string,
FNCompDef
>;
const scope = { props: {} } as Exclude<
ReturnType<typeof parseJs>,
undefined
>;
if (mprops) {
const mitem_comp = mitem.get("component");
if (mitem_comp) {
const mitem_props = ensureMItemProps(mitem_comp, item_comp);
if (mitem_props) {
for (const [k, v] of Object.entries(mprops)) {
scope.props[k] = { name: k, value: `null as any` };
const mprop = ensureMProp(mitem_props, k, v);
item_comp.props[k] = v;
if (mprop && v.meta?.type === "content-element") {
scope.props[k].value = "null as ReactElement";
const mcontent = ensurePropContent(mprop, k);
if (mcontent) {
serverWalkMap(p, {
@ -168,6 +190,27 @@ export const serverWalkMap = (
}
}
const pcomp = p.scope_comps[item_comp.id];
pcomp.scope[item.id] = { p: arg.parent_ids, s: null };
const js = item.adv?.js;
if (typeof js === "string") {
const res = parseJs(js);
if (res) {
scope.local = res.local;
scope.passprop = res.passprop;
}
}
if (scope) pcomp.scope[item.id].s = scope;
if (!parent_mcomp) {
p.scope[item.id] = {
p: arg.parent_ids,
name: item.name,
s: null,
} as any;
if (scope) p.scope[item.id].s = scope;
}
const childs = mcomp.get("childs")?.map((e) => e) || [];
for (const e of childs) {
serverWalkMap(p, {
@ -198,7 +241,7 @@ export const serverWalkMap = (
if (scope) pcomp.scope[item.id].s = scope;
}
} else {
p.scope[item.id] = { p: arg.parent_ids, s: null };
p.scope[item.id] = { p: arg.parent_ids, name: item.name, s: null } as any;
const js = item.adv?.js;
if (typeof js === "string") {
const scope = parseJs(js);

View File

@ -6,7 +6,7 @@ export const parseJs = (code: string) => {
});
const local = { name: "", value: "", index: 0 };
const passprop: any = {};
const passprop: Record<string, { value: string; index: number }> = {};
recast.visit(ast, {
visitJSXOpeningElement({ node }) {
if (node.name.type === "JSXIdentifier" && node.attributes) {
@ -65,6 +65,7 @@ export const parseJs = (code: string) => {
const result = {} as {
local: typeof local | undefined;
passprop: typeof passprop | undefined;
props: Record<string, { name: string; value: string }>;
};
if (local.name) {
result.local = local;

View File

@ -23,10 +23,11 @@ export type ESite = typeof EmptySite;
export type EPage = typeof EmptyPage;
export type EComp = typeof EmptyComp;
export type IScope = Record<
string,
{ p: string[]; s: null | Exclude<ReturnType<typeof parseJs>, undefined> }
>;
export type ISingleScope = {
p: string[];
s: null | Exclude<ReturnType<typeof parseJs>, undefined>;
};
export type IScope = Record<string, ISingleScope>;
export type IScopeComp = Record<
string,
@ -64,6 +65,16 @@ export const active = {
localStorage.setItem("prasi-active-id", val);
target.active_id = val;
},
get comp_id() {
if (target.active_id === false) {
target.active_id = localStorage.getItem("prasi-comp-id") || "";
}
return target.active_id;
},
set comp_id(val: string) {
localStorage.setItem("prasi-comp-id", val);
target.active_id = val;
},
};
export type EdMeta = {
@ -122,6 +133,7 @@ export const EDGlobal = {
on_update?: (bin: Uint8Array, origin: any) => Promise<void>;
}
>,
scope: {} as IScope,
building: false,
meta: {} as Record<string, EdMeta>,
entry: [] as string[],
@ -129,7 +141,6 @@ export const EDGlobal = {
render: () => {},
},
comp: {
cur: EmptyComp,
doc: null as null | DComp,
item: null as null | IItem,
map: {} as Record<string, { id: string; item: IItem }>,

View File

@ -47,6 +47,8 @@ export const reloadPage = async (p: PG, page_id: string) => {
p.render();
return;
}
p.page.scope = remotePage.scope || {};
if (remotePage.scope_comps) {
for (const [id_comp, c] of Object.entries(remotePage.scope_comps)) {
if (c && c.snapshot) {

View File

@ -1,5 +1,5 @@
import { useEffect } from "react";
import { PG } from "./ed-global";
import { PG, active } from "./ed-global";
import { treeRebuild } from "./tree/build";
export const edUndoManager = async (p: PG) => {
@ -18,8 +18,8 @@ export const edUndoManager = async (p: PG) => {
(evt.ctrlKey || evt.metaKey) &&
!evt.shiftKey
) {
if (p.comp.cur.id) {
p.sync.yjs.um("comp", "redo", p.comp.cur.id);
if (active.comp_id) {
p.sync.yjs.um("comp", "redo", active.comp_id);
} else {
p.sync.yjs.um("page", "redo", p.page.cur.id);
}
@ -31,8 +31,8 @@ export const edUndoManager = async (p: PG) => {
(evt.ctrlKey || evt.metaKey) &&
evt.shiftKey
) {
if (p.comp.cur.id) {
p.sync.yjs.um("comp", "redo", p.comp.cur.id);
if (active.comp_id) {
p.sync.yjs.um("comp", "redo", active.comp_id);
} else {
p.sync.yjs.um("page", "redo", p.page.cur.id);
}
@ -44,8 +44,8 @@ export const edUndoManager = async (p: PG) => {
(evt.ctrlKey || evt.metaKey) &&
!evt.shiftKey
) {
if (p.comp.cur.id) {
p.sync.yjs.um("comp", "undo", p.comp.cur.id);
if (active.comp_id) {
p.sync.yjs.um("comp", "undo", active.comp_id);
} else {
p.sync.yjs.um("page", "undo", p.page.cur.id);
}

View File

@ -1,12 +1,12 @@
import type { OnMount } from "@monaco-editor/react";
import { createStore } from "idb-keyval";
import trim from "lodash.trim";
import { useEffect } from "react";
import { useGlobal, useLocal } from "web-utils";
import { jscript } from "../../../../../utils/script/jscript";
import { EDGlobal, active } from "../../../logic/ed-global";
import { jsMount } from "../../../../../utils/script/mount";
import { monacoTypings } from "../../../../../utils/script/typings";
import { EDGlobal, active } from "../../../logic/ed-global";
import { declareScope } from "./scope";
export type MonacoEditor = Parameters<OnMount>[0];
export const ScriptMonaco = () => {
@ -109,8 +109,8 @@ export const ScriptMonaco = () => {
"typescript",
monaco.Uri.parse(
`ts:${
p.comp.cur.id
? `comp-${p.comp.cur.id}`
active.comp_id
? `comp-${active.comp_id}`
: `page-${p.page.cur.id}`
}-${active.item_id}.tsx`
)
@ -118,13 +118,22 @@ export const ScriptMonaco = () => {
editor.setModel(model);
}
monaco.editor.registerEditorOpener({
openCodeEditor(source, resource, selectionOrPosition) {
openCodeEditor(source, r, selectionOrPosition) {
const path = r.path.split("~");
const id = path[path.length - 1].replace(".d.ts", "");
const meta = p.page.meta[id];
if (meta) {
console.log(meta.item, meta);
}
// https://github.com/microsoft/vscode/pull/177064#issue-1623100628
return false;
},
});
await jsMount(editor, monaco);
await declareScope(p, editor, monaco);
await monacoTypings(
{
site_dts: p.site_dts,

View File

@ -0,0 +1,126 @@
import type { OnMount } from "@monaco-editor/react";
import { deepClone } from "web-utils";
import { ISingleScope, PG, active } from "../../../logic/ed-global";
type Monaco = Parameters<OnMount>[1];
export type MonacoEditor = Parameters<OnMount>[0];
export const declareScope = async (
p: PG,
editor: MonacoEditor,
monaco: Monaco
) => {
const active_id = active.item_id;
const s = deepClone(p.page.scope[active_id]);
monaco.editor.getModels().forEach((model) => {
if (model.uri.toString().startsWith("ts:scope~")) {
model.dispose();
}
});
const existing: Record<string, IEachArgScope> = {};
spreadScope(p, s, (arg) => {
const { name } = arg;
const e = existing[name];
if (e && e.s.s) {
if (e.type === "local") {
delete e.s.s.local;
}
if (e.type === "passprop" && e.s.s.passprop) {
delete e.s.s.passprop[e.name];
}
if (e.type === "prop" && e.s.s.props) {
delete e.s.s.props[e.name];
}
}
existing[name] = arg;
});
spreadScope(p, s, (arg) => {
addScope(
monaco,
`${arg.type}~${arg.id}`,
`\
export const {};
const __val = ${arg.value};
declare global {
const ${arg.name}: typeof __val;
}`
);
});
};
type IEachArgScope = {
s: ISingleScope;
name: string;
value: string;
id: string;
type: "local" | "prop" | "passprop";
index?: number;
isProp?: boolean;
};
const spreadScope = (
p: PG,
s: ISingleScope,
each: (arg: IEachArgScope) => void
) => {
for (const parent_id of s.p) {
const item = p.page.scope[parent_id];
if (item) {
const scope = item.s;
if (scope) {
if (scope.local)
each({
s,
type: "local",
id: parent_id,
name: scope.local.name,
value: scope.local?.value,
index: scope.local?.index,
});
if (scope.passprop) {
for (const [k, v] of Object.entries(scope.passprop)) {
each({
s,
type: "prop",
id: parent_id,
name: k,
value: v.value,
index: v.index,
});
}
}
if (scope.props) {
for (const [k, v] of Object.entries(scope.props)) {
each({
s,
type: "passprop",
id: parent_id,
name: k,
value: v.value,
isProp: true,
});
}
}
}
}
}
};
const addScope = (monaco: Monaco, id: string, source: string) => {
const model = monaco.editor.getModels().find((e) => {
return e.uri.toString() === `ts:scope~${id}.d.ts`;
});
if (model) {
model.setValue(source);
} else {
monaco.editor.createModel(
source,
"typescript",
monaco.Uri.parse(`ts:scope~${id}.d.ts`)
);
}
};

View File

@ -6,7 +6,7 @@ import {
TreeMethods,
} from "@minoru/react-dnd-treeview";
import { useGlobal, useLocal } from "web-utils";
import { EDGlobal, EdMeta } from "../../logic/ed-global";
import { EDGlobal, EdMeta, active } from "../../logic/ed-global";
import { indentHook } from "./node/item/indent-hook";
import { canDrop, nodeOnDrop } from "./node/on-drop";
import { nodeRender } from "./node/render";
@ -25,10 +25,12 @@ export const EdTreeBody = () => {
if (p.ui.tree.search) {
tree = doTreeSearch(p);
} else {
if (active.comp_id) {
}
tree = p.page.tree;
}
if (p.page.tree.length === 0)
if (tree.length === 0)
return (
<div className="flex py-[100px] select-none justify-center flex-1">
<div className="flex flex-col">
@ -43,6 +45,7 @@ export const EdTreeBody = () => {
</div>
</div>
);
return (
<TypedTree
tree={tree}

View File

@ -1,6 +1,7 @@
import { NodeModel, RenderParams } from "@minoru/react-dnd-treeview";
import { EDGlobal, EdMeta } from "../../../../logic/ed-global";
import { useGlobal } from "web-utils";
import { Tooltip } from "../../../../../../utils/ui/tooltip";
import { EDGlobal, EdMeta, active } from "../../../../logic/ed-global";
export const EdTreeAction = ({
node,
@ -21,8 +22,25 @@ export const EdTreeAction = ({
return (
<div className="flex items-center pr-1">
{isComponent && (
<Tooltip
content="Edit Component"
className="flex items-center border border-slate-500 bg-white rounded-sm text-[10px] px-[2px] cursor-pointer hover:bg-purple-100 hover:border-purple-600"
onClick={(e) => {
const comp_id = item.component?.id;
if (comp_id) {
active.comp_id = comp_id;
p.render();
}
}}
>
<>Edit</>
</Tooltip>
)}
{!isComponent && (
<div
<Tooltip
content={`Edit ${mode}`}
className={cx(
"border rounded-sm text-[9px] flex w-[20px] h-[15px] items-center cursor-pointer justify-center uppercase",
item.adv?.js || item.adv?.css || item.adv?.html
@ -55,7 +73,7 @@ export const EdTreeAction = ({
__html: `<svg width="12px" height="12px" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9.96424 2.68571C10.0668 2.42931 9.94209 2.13833 9.6857 2.03577C9.4293 1.93322 9.13832 2.05792 9.03576 2.31432L5.03576 12.3143C4.9332 12.5707 5.05791 12.8617 5.3143 12.9642C5.5707 13.0668 5.86168 12.9421 5.96424 12.6857L9.96424 2.68571ZM3.85355 5.14646C4.04882 5.34172 4.04882 5.6583 3.85355 5.85356L2.20711 7.50001L3.85355 9.14646C4.04882 9.34172 4.04882 9.6583 3.85355 9.85356C3.65829 10.0488 3.34171 10.0488 3.14645 9.85356L1.14645 7.85356C0.951184 7.6583 0.951184 7.34172 1.14645 7.14646L3.14645 5.14646C3.34171 4.9512 3.65829 4.9512 3.85355 5.14646ZM11.1464 5.14646C11.3417 4.9512 11.6583 4.9512 11.8536 5.14646L13.8536 7.14646C14.0488 7.34172 14.0488 7.6583 13.8536 7.85356L11.8536 9.85356C11.6583 10.0488 11.3417 10.0488 11.1464 9.85356C10.9512 9.6583 10.9512 9.34172 11.1464 9.14646L12.7929 7.50001L11.1464 5.85356C10.9512 5.6583 10.9512 5.34172 11.1464 5.14646Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg>`,
}}
></div>
</div>
</Tooltip>
)}
</div>
);

View File

@ -16,11 +16,11 @@ export const edActionNewComp = (
let item_id = active.item_id;
p.ui.tree.item_loading.push(item_id);
await treeRebuild(p);
if (p.comp.cur.id) {
if (active.comp_id) {
await p.sync.comp.new({
group_id,
item,
comp_id: p.comp.cur.id,
comp_id: active.comp_id,
item_id: active.item_id,
});
} else {

View File

@ -3,19 +3,19 @@ import { useGlobal, useLocal } from "web-utils";
import { IItem } from "../../../../../../utils/types/item";
import { FNComponent } from "../../../../../../utils/types/meta-fn";
import { Menu, MenuItem } from "../../../../../../utils/ui/context-menu";
import { EDGlobal, EdMeta } from "../../../../logic/ed-global";
import { EDGlobal, EdMeta, active } from "../../../../logic/ed-global";
import { edActionAttach } from "./action/attach";
import { edActionClone } from "./action/clone";
import { edActionCopy } from "./action/copy";
import { edActionCut } from "./action/cut";
import { edActionDelete } from "./action/del";
import { edActionDetach } from "./action/detach";
import { edActionHide } from "./action/hide";
import { edActionNewComp } from "./action/new-comp";
import { edActionPaste } from "./action/paste";
import { edActionWrap } from "./action/wrap";
import { edActionUnwrap } from "./action/unwrap";
import { edActionRename } from "./action/rename";
import { edActionDelete } from "./action/del";
import { edActionUnwrap } from "./action/unwrap";
import { edActionWrap } from "./action/wrap";
export const EdTreeCtxMenu = ({
node,
@ -52,9 +52,8 @@ export const EdTreeCtxMenu = ({
const item = node.data?.item;
const type = item?.type;
const comp = (item as IItem).component as FNComponent | undefined;
const rootComp = p.comp.cur;
const isComponent = comp?.id;
const isActiveComponent = rootComp && rootComp.id === item?.id && rootComp.id;
const isActiveComponent = active.comp_id === item?.id;
if (!item) {
return (

View File

@ -1,7 +1,7 @@
import { DropOptions, NodeModel } from "@minoru/react-dnd-treeview";
import { EdMeta, PG } from "../../../logic/ed-global";
import { MContent } from "../../../../../utils/types/general";
import get from "lodash.get";
import { MContent } from "../../../../../utils/types/general";
import { EdMeta, PG, active } from "../../../logic/ed-global";
export const nodeOnDrop: (
tree: NodeModel<EdMeta>[],
@ -48,7 +48,7 @@ export const canDrop = (p: PG, arg: DropOptions<EdMeta>) => {
dropTarget.data.item.component?.id
) {
if (p.comp) {
if (p.comp.cur.id === dropTarget.data.item.component?.id) {
if (active.comp_id === dropTarget.data.item.component?.id) {
return true;
}
}
@ -65,7 +65,7 @@ export const canDrop = (p: PG, arg: DropOptions<EdMeta>) => {
dropTarget.data.item.component?.id
) {
if (p.comp) {
if (p.comp.cur.id === dropTarget.data.item.component.id) {
if (active.comp_id === dropTarget.data.item.component.id) {
return true;
}
}

View File

@ -1,6 +1,3 @@
import { component } from "../../../../../db/db";
import { IItem } from "../../../utils/types/item";
import { FNComponent } from "../../../utils/types/meta-fn";
import { EdMeta, PG } from "../../ed/logic/ed-global";
export type VLoad =

View File

@ -53,7 +53,6 @@ export const registerMobile = () => {
if (window.parent) {
window.addEventListener("message", async ({ data: raw }) => {
if (typeof raw === "object" && raw.mobile) {
console.log("capacitor", raw);
const data = raw as unknown as
| {
type: "notification-token";

View File

@ -109,7 +109,7 @@ import "./api"
import type * as SRVAPI from "${apiPath}";`
)}
declare global {;
declare global {
const db: prisma.PrismaClient;
${baseTypings}