This commit is contained in:
Rizky 2023-12-09 18:02:47 +07:00
parent 65da157965
commit 07c55a63d6
6 changed files with 192 additions and 146 deletions

View File

@ -63,7 +63,7 @@ const target = {
instance_item_id: false as any,
};
export const active = {
hover_id: "",
hover: { id: "", renderTree: () => {}, renderMain: () => {} },
text: { id: "", content: "", timeout: null as any, el: null as any },
get item_id() {
if (target.active_id === false) {

View File

@ -212,7 +212,7 @@ export const syncWalkMap = (
string,
FNCompDef
>;
const propvis = {};
if (mprops) {
const mitem_comp = mitem.get("component");
if (mitem_comp) {

View File

@ -1,5 +1,5 @@
import { useEffect } from "react";
import { useGlobal } from "web-utils";
import { ReactNode, useEffect } from "react";
import { useGlobal, useLocal } from "web-utils";
import { Loading } from "../../../../utils/ui/loading";
import { View } from "../../../view/view";
import { EDGlobal, EdMeta, active } from "../../logic/ed-global";
@ -9,146 +9,173 @@ import { code } from "../popup/code/code";
export const EdMain = () => {
const p = useGlobal(EDGlobal, "EDITOR");
const local = useLocal({
el: null as ReactNode,
});
active.hover.renderMain = local.render;
if (code.mode && !p.page.building) {
local.el = (
<View
mode={p.mode}
code_mode={code.mode}
layout={{ show: false }}
isEditor={true}
api_url={p.site.config.api_url}
component={{
async load(id_comp) {
await loadComponent(p, id_comp);
},
}}
load={{
mode: "tree_meta",
meta: p.page.meta,
entry: p.page.entry,
scope: p.page.scope,
}}
site_id={p.site.id}
page_id={p.page.cur.id}
bind={({ render }) => {
p.page.render = render;
}}
hidden={(meta) => {
if (meta.item.hidden) return true;
return false;
}}
hover={{
get(meta) {
return false;
},
set(meta) {
const outer = getOuterItem(meta);
if (outer) {
if (active.hover.id !== outer.id) {
active.hover.id = outer.id;
active.hover.renderTree();
active.hover.renderMain();
}
}
},
}}
active={{
get(meta) {
return active.item_id === meta.item.id;
},
set(meta) {
const outer = getOuterItem(meta);
if (outer) {
active.item_id = outer.id;
}
p.render();
p.page.render();
focus();
},
text({ meta }) {
const { item } = meta;
useEffect(() => {
return () => {
active.text.id = "";
p.render();
};
}, []);
const updateWithTimeout = (timeout: number) => {
return new Promise<void>((resolve) => {
const saving = {
id: active.text.id,
content: active.text.content,
};
clearTimeout(active.text.timeout);
active.text.timeout = setTimeout(() => {
const meta = getMetaById(p, saving.id);
if (meta && meta.mitem) {
meta.mitem.set("html", saving.content);
}
resolve();
}, timeout);
});
};
if (active.text.id !== item.id) {
clearTimeout(active.text.timeout);
active.text.id = item.id;
active.text.content = item.html || "";
active.text.el = (
<div
className={cx(
`v-text-${item.id} v-text-${item.originalId} outline-none`
)}
ref={(ref) => {
if (ref !== document.activeElement && ref) {
const renaming = document.querySelector(".rename-item");
const modals = document.querySelectorAll(
"[data-floating-ui-portal]"
);
if (modals.length === 0 && !renaming) {
ref.focus();
setEndOfContenteditable(ref);
}
}
}}
onPointerDownCapture={(e) => {
e.stopPropagation();
}}
contentEditable
spellCheck={false}
onInput={(e) => {
const val = e.currentTarget.innerHTML;
item.html = val;
active.text.id = item.id;
active.text.content = val;
updateWithTimeout(100);
}}
dangerouslySetInnerHTML={{ __html: item.html || "" }}
></div>
);
}
return active.text.el;
},
}}
/>
);
}
return (
<div
className={cx(
"flex flex-1 relative overflow-auto ",
css`
contain: content;
`
`,
active.hover.id &&
active.hover.id !== active.item_id &&
css`
.s-${active.hover.id} {
position: relative;
&::after {
content: " ";
pointer-events: none;
position: absolute;
z-index: 100;
left: 0;
right: 0;
bottom: 0;
top: 0;
border: 2px solid #b2d2fd;
}
}
`
)}
>
{/* <div className="absolute bg-white px-1 z-10">{active.hover.id}</div> */}
<div className="absolute inset-0 flex flex-col">
{!!p.page.building && <Loading backdrop={false} />}
{!p.page.building && code.mode !== "" && (
<View
mode={p.mode}
code_mode={code.mode}
layout={{ show: false }}
isEditor={true}
api_url={p.site.config.api_url}
component={{
async load(id_comp) {
await loadComponent(p, id_comp);
},
}}
load={{
mode: "tree_meta",
meta: p.page.meta,
entry: p.page.entry,
scope: p.page.scope,
}}
site_id={p.site.id}
page_id={p.page.cur.id}
bind={({ render }) => {
p.page.render = render;
}}
hidden={(meta) => {
if (meta.item.hidden) return true;
return false;
}}
hover={{
get(meta) {
return active.hover_id === meta.item.id;
},
set(meta) {
const outer = getOuterItem(meta);
if (outer) {
active.hover_id = outer.id;
}
p.render();
p.page.render();
},
}}
active={{
get(meta) {
return active.item_id === meta.item.id;
},
set(meta) {
const outer = getOuterItem(meta);
console.log(meta);
if (outer) {
active.item_id = outer.id;
}
p.render();
p.page.render();
focus();
},
text({ meta }) {
const { item } = meta;
useEffect(() => {
return () => {
active.text.id = "";
p.render();
};
}, []);
const updateWithTimeout = (timeout: number) => {
return new Promise<void>((resolve) => {
const saving = {
id: active.text.id,
content: active.text.content,
};
clearTimeout(active.text.timeout);
active.text.timeout = setTimeout(() => {
const meta = getMetaById(p, saving.id);
if (meta && meta.mitem) {
meta.mitem.set("html", saving.content);
}
resolve();
}, timeout);
});
};
if (active.text.id !== item.id) {
clearTimeout(active.text.timeout);
active.text.id = item.id;
active.text.content = item.html || "";
active.text.el = (
<div
className={cx(
`v-text-${item.id} v-text-${item.originalId} outline-none`
)}
ref={(ref) => {
if (ref !== document.activeElement && ref) {
const renaming =
document.querySelector(".rename-item");
const modals = document.querySelectorAll(
"[data-floating-ui-portal]"
);
if (modals.length === 0 && !renaming) {
ref.focus();
setEndOfContenteditable(ref);
}
}
}}
onPointerDownCapture={(e) => {
e.stopPropagation();
}}
contentEditable
spellCheck={false}
onInput={(e) => {
const val = e.currentTarget.innerHTML;
item.html = val;
active.text.id = item.id;
active.text.content = val;
updateWithTimeout(100);
}}
dangerouslySetInnerHTML={{ __html: item.html || "" }}
></div>
);
}
return active.text.el;
},
}}
/>
)}
{!p.page.building && code.mode !== "" && local.el}
</div>
</div>
);

View File

@ -19,6 +19,8 @@ export const EdTreeBody = () => {
const local = useLocal({ tree: null as TreeMethods | null, comp_id: "" });
const TypedTree = DNDTree<EdMeta>;
active.hover.renderTree = local.render;
expandTreeHook(p, local);
if (active.comp_id && local.comp_id !== active.comp_id) {

View File

@ -9,8 +9,7 @@ import { EdTreeIndent } from "./item/indent";
import { EdTreeName } from "./item/name";
import { treeItemKeyMap } from "./key-map";
const jsxPropLoadingRender = {} as Record<string, string>;
const jsxPropVisCache = {} as Record<string, any>;
const jsxPropVis = {} as Record<string, string>;
export const nodeRender: NodeRender<EdMeta> = (node, prm) => {
const p = useGlobal(EDGlobal, "EDITOR");
@ -30,11 +29,29 @@ export const nodeRender: NodeRender<EdMeta> = (node, prm) => {
}
if (node.data?.jsx_prop_root && node.data?.jsx_prop_name) {
const prop_name = node.data?.jsx_prop_name;
const meta = getMetaById(p, node.data?.parent_item.id);
if (meta) {
if (meta.propvis) {
jsxPropVisCache[meta.item.id] = meta.propvis;
if (meta.propvis[node.data.jsx_prop_name] === false) return <></>;
if (meta && prop_name && !active.comp_id) {
if (!meta.propvis) {
if (!meta.parent_mcomp) {
setTimeout(local.render, 100);
const id = meta.item.originalId || meta.item.id;
if (!jsxPropVis[id] || jsxPropVis[id] === prop_name) {
jsxPropVis[id] = prop_name;
return (
<div
className={"relative border-b flex items-stretch min-h-[26px]"}
>
<Loading backdrop={false} />
</div>
);
} else {
return <></>;
}
}
} else {
if (meta.propvis[prop_name] === false) return <></>;
}
}
}
@ -61,7 +78,7 @@ export const nodeRender: NodeRender<EdMeta> = (node, prm) => {
active.item_id === item.id
? ["bg-blue-100"]
: [isComponent && `bg-purple-50`],
active.hover_id === item.id && "bg-blue-50"
active.hover.id === item.id && "bg-blue-50"
)}
onKeyDown={treeItemKeyMap(p, prm, item)}
onContextMenu={(event) => {
@ -80,12 +97,12 @@ export const nodeRender: NodeRender<EdMeta> = (node, prm) => {
p.page.render();
}}
onMouseOver={() => {
active.hover_id = item.id;
p.render();
p.page.render();
active.hover.id = item.id;
active.hover.renderTree();
active.hover.renderMain();
}}
>
{active.hover_id === item.id && (
{active.hover.id === item.id && (
<div
className={cx("absolute left-0 bottom-0 top-0 w-[4px] bg-blue-300")}
></div>

View File

@ -21,7 +21,7 @@ export const produceCSS = (
): string => {
try {
return cx([
item.name,
`s-${item.id}`,
css`
display: flex;
position: relative;