This commit is contained in:
Rizky 2023-12-07 18:38:07 +07:00
parent 5699d37453
commit 77a527447c
9 changed files with 123 additions and 83 deletions

View File

@ -16,6 +16,7 @@ export const user = {
site_id: string; site_id: string;
page_id: string; page_id: string;
comp_id?: string; comp_id?: string;
client_id: string;
select: "" | "comp" | "item" | "section" | "text"; select: "" | "comp" | "item" | "section" | "text";
}, },
"client_id" "client_id"

View File

@ -12,6 +12,7 @@
"@minoru/react-dnd-treeview": "^3.4.4", "@minoru/react-dnd-treeview": "^3.4.4",
"@monaco-editor/react": "^4.6.0", "@monaco-editor/react": "^4.6.0",
"@paralleldrive/cuid2": "2.2.2", "@paralleldrive/cuid2": "2.2.2",
"react-contenteditable": "^3.3.7",
"@parcel/packager-wasm": "^2.10.3", "@parcel/packager-wasm": "^2.10.3",
"@parcel/service-worker": "^2.10.3", "@parcel/service-worker": "^2.10.3",
"recast": "^0.23.4", "recast": "^0.23.4",

View File

@ -64,7 +64,7 @@ const target = {
}; };
export const active = { export const active = {
hover_id: "", hover_id: "",
text: { id: "", content: "" }, text: { id: "", content: "", timeout: null as any, el: null as any },
get item_id() { get item_id() {
if (target.active_id === false) { if (target.active_id === false) {
target.active_id = localStorage.getItem("prasi-active-id") || ""; target.active_id = localStorage.getItem("prasi-active-id") || "";

View File

@ -1,10 +1,11 @@
import { useGlobal } from "web-utils"; import { useGlobal, useLocal } from "web-utils";
import { Loading } from "../../../../utils/ui/loading"; import { Loading } from "../../../../utils/ui/loading";
import { View } from "../../../view/view"; import { View } from "../../../view/view";
import { EDGlobal, active } from "../../logic/ed-global"; import { EDGlobal, active } from "../../logic/ed-global";
import { getMetaById } from "../../logic/tree/build"; import { getMetaById } from "../../logic/tree/build";
import { loadComponent } from "../../logic/tree/sync-walk"; import { loadComponent } from "../../logic/tree/sync-walk";
import { code } from "../popup/code/code"; import { code } from "../popup/code/code";
import { useEffect } from "react";
export const EdMain = () => { export const EdMain = () => {
const p = useGlobal(EDGlobal, "EDITOR"); const p = useGlobal(EDGlobal, "EDITOR");
@ -51,10 +52,11 @@ export const EdMain = () => {
const item = meta.item; const item = meta.item;
if (active.comp_id) { if (active.comp_id) {
if (meta.parent_mcomp) { const p = meta.parent_mcomp;
if (p) {
if ( if (
meta.parent_mcomp?.mcomp.get("component")?.get("id") !== p.mitem.get("id") !== active.instance.item_id ||
active.comp_id p.mcomp.get("component")?.get("id") !== active.comp_id
) )
return false; return false;
} }
@ -112,15 +114,16 @@ export const EdMain = () => {
const item = meta.item; const item = meta.item;
if (active.comp_id) { if (active.comp_id) {
if (meta.parent_mcomp) { const p = meta.parent_mcomp;
if (p) {
if ( if (
meta.parent_mcomp?.mcomp.get("component")?.get("id") !== p.mitem.get("id") !== active.instance.item_id ||
active.comp_id p.mcomp.get("component")?.get("id") !== active.comp_id
) )
return false; return false;
} }
} }
if ( if (
item.originalId === active.item_id || item.originalId === active.item_id ||
item.id === active.item_id item.id === active.item_id
@ -194,46 +197,74 @@ export const EdMain = () => {
p.page.render(); p.page.render();
focus(); focus();
}, },
text(meta) { text({ meta }) {
const { item } = 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) { if (active.text.id !== item.id) {
clearTimeout(active.text.timeout);
active.text.id = item.id; active.text.id = item.id;
active.text.content = item.html || ""; 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 ( return 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);
}
}
}}
contentEditable
spellCheck={false}
onInput={(e) => {
const val = e.currentTarget.innerHTML;
active.text.id = item.id;
active.text.content = val;
}}
onBlur={() => {
const meta = getMetaById(p, item.id);
if (meta && meta.mitem && active.text.id === item.id) {
meta.mitem.set("html", active.text.content);
}
}}
dangerouslySetInnerHTML={{ __html: item.html || "" }}
></div>
);
}, },
}} }}
/> />

View File

@ -29,7 +29,7 @@ export const EdPropInstanceText: FC<{
if (val) { if (val) {
try { try {
eval(`local.value = ${valBuilt}`); eval(`local.value = ${valBuilt}`);
} catch (e) { } } catch (e) {}
} else { } else {
local.value = ""; local.value = "";
} }
@ -41,7 +41,7 @@ export const EdPropInstanceText: FC<{
{name} {name}
</div> </div>
); );
return ( return (
<div className="flex items-center"> <div className="flex items-center">
{name.length > 8 ? ( {name.length > 8 ? (
@ -52,7 +52,7 @@ export const EdPropInstanceText: FC<{
label label
)} )}
<AutoHeightTextarea <AutoHeightTextarea
className="flex-1 outline-none border-l p-1 ml-1 overflow-hidden" className="flex-1 outline-none border-l p-1 ml-1 overflow-hidden focus:bg-blue-50"
value={local.value} value={local.value}
spellCheck={false} spellCheck={false}
onChange={(e) => { onChange={(e) => {

View File

@ -25,7 +25,7 @@ export const ViewGlobal = {
| { | {
get: (meta: EdMeta) => boolean; get: (meta: EdMeta) => boolean;
set: (meta: EdMeta) => void; set: (meta: EdMeta) => void;
text?: (meta: EdMeta) => ReactNode; text?: (arg: { meta: EdMeta }) => ReactNode;
}, },
hover: undefined as hover: undefined as
| undefined | undefined

View File

@ -1,42 +1,48 @@
import { FC, Fragment, ReactNode } from "react"; import { FC, Fragment, ReactNode } from "react";
import { useGlobal } from "web-utils"; import { useGlobal, useLocal } from "web-utils";
import { EdMeta } from "../../../ed/logic/ed-global"; import { EdMeta } from "../../../ed/logic/ed-global";
import { ViewGlobal } from "../../logic/global"; import { ViewGlobal } from "../../logic/global";
import { ViewMeta } from "./meta"; import { ViewMeta } from "./meta";
export const ViewMetaChildren: FC<{ export const ViewMetaChildren: FC<{
meta: EdMeta, meta: EdMeta;
className?: string className?: string;
}> = ({ }> = ({ meta, className }) => {
meta, const v = useGlobal(ViewGlobal, "VIEW");
className const children: Record<string, ReactNode> = {};
}) => { const item = meta.item;
const v = useGlobal(ViewGlobal, "VIEW"); if (item.type !== "text") {
const children: Record<string, ReactNode> = {}; for (const child of item.childs) {
const item = meta.item; if (child.id) {
if (item.type !== "text") { children[child.id] = <ViewMeta id={child.id} key={child.id} />;
for (const child of item.childs) {
if (child.id) {
children[child.id] = (<ViewMeta id={child.id} key={child.id} />);
}
}
} else {
if (item.id) {
if (v.view.active?.text && v.view.active?.get(meta)) {
children[item.id] = <Fragment key={item.id}>
{v.view.active.text(meta)}
</Fragment>;
} else {
children[item.id] = <span
key={item.id}
dangerouslySetInnerHTML={{ __html: item.html || '&nbsp;' }
}>
</span >;
}
} }
} }
} else {
if (item.id) {
if (v.view.active?.text && v.view.active?.get(meta)) {
const ActiveText = v.view.active.text;
children[item.id] = (
<Fragment key={item.id}>
<ActiveText meta={meta} />
</Fragment>
);
} else {
children[item.id] = (
<span
key={item.id}
dangerouslySetInnerHTML={{ __html: item.html || "&nbsp;" }}
></span>
);
}
}
}
return <> return (
{/* <div className={"text-[9px] text-gray-500 -mt-1"}>{item.id} - {item.originalId}</div> */} <>
{Object.values(children)}</>; {/* <div className={"text-[9px] text-gray-500 -mt-1"}>
}; {item.id} - {item.originalId}
</div> */}
{Object.values(children)}
</>
);
};

View File

@ -26,7 +26,7 @@ type ViewProp = {
active?: { active?: {
get: (item: EdMeta) => boolean; get: (item: EdMeta) => boolean;
set: (item: EdMeta) => void; set: (item: EdMeta) => void;
text?: (item: EdMeta) => ReactNode text?: (arg: { meta: EdMeta }) => ReactNode;
}; };
}; };
@ -59,8 +59,9 @@ const BoxedView: FC<ViewProp> = ({
v.script.api_url = api_url; v.script.api_url = api_url;
if (hidden) v.view.hidden = hidden; if (hidden) v.view.hidden = hidden;
if (hover) v.view.hover = hover; if (hover && !v.view.hover) v.view.hover = hover;
if (active) v.view.active = active; if (active && !v.view.active) v.view.active = active;
if (v.current.page_id !== page_id || v.current.site_id !== site_id) { if (v.current.page_id !== page_id || v.current.site_id !== site_id) {
v.status = "init"; v.status = "init";
} }

BIN
bun.lockb

Binary file not shown.