Panels - strings to elements

This commit is contained in:
onespaceman
2026-02-05 21:44:01 +00:00
parent 502b636aef
commit 9129f15e57
4 changed files with 37 additions and 78 deletions
+34 -75
View File
@@ -10,92 +10,51 @@ export function Panel({
config: PanelConfig;
editor: Client;
}) {
const iFrameRef = useRef<HTMLIFrameElement>(null);
const html = useMemo(() => {
return panelHtml.replace("{{.HostPrefix}}", document.baseURI);
}, []);
const panelRef = useRef<HTMLDivElement>(null);
const shadowRef = useRef<ShadowRoot>(null);
function updateContent() {
if (!iFrameRef.current?.contentWindow) {
return;
}
const shadow = shadowRef.current;
if (!shadow) return;
iFrameRef.current.contentWindow.postMessage({
type: "html",
html: config.html,
script: config.script,
theme: document.getElementsByTagName("html")[0].dataset.theme,
});
const root = shadow.getElementById("panel-root");
if (!root) return;
root.innerHTML = "";
root.setAttribute(
"data-theme",
document.documentElement.dataset.theme || "light",
);
if (Array.isArray(config.html)) {
root.append(...config.html);
} else {
root.append(config.html as HTMLElement);
}
}
useEffect(() => {
const iframe = iFrameRef.current;
if (!iframe) {
return;
}
if (!panelRef.current) return;
iframe.addEventListener("load", updateContent);
updateContent();
shadowRef.current = panelRef.current.attachShadow({ mode: "closed" });
const container = document.createElement("div");
container.id = "panel-root";
shadowRef.current.appendChild(container);
return () => {
iframe.removeEventListener("load", updateContent);
};
}, [config.html, config.script]);
useEffect(() => {
const messageListener = (evt: any) => {
if (evt.source !== iFrameRef.current!.contentWindow) {
return;
}
const data = evt.data;
if (!data) {
return;
}
switch (data.type) {
case "syscall": {
const { id, name, args } = data;
editor.clientSystem.localSyscall(name, args).then(
(result) => {
if (!iFrameRef.current?.contentWindow) {
// iFrame already went away
return;
}
iFrameRef.current!.contentWindow!.postMessage({
type: "syscall-response",
id,
result,
});
},
).catch((e: any) => {
if (!iFrameRef.current?.contentWindow) {
// iFrame already went away
return;
}
iFrameRef.current!.contentWindow!.postMessage({
type: "syscall-response",
id,
error: e.message,
});
});
break;
}
}
};
globalThis.addEventListener("message", messageListener);
return () => {
globalThis.removeEventListener("message", messageListener);
shadowRef.current = null;
};
}, []);
useEffect(() => {
updateContent();
}, [config.html, config.script]);
return (
<div className="sb-panel" style={{ flex: config.mode }}>
<iframe
srcDoc={html}
ref={iFrameRef}
style={{ visibility: "hidden" }}
onLoad={() => iFrameRef.current!.style.visibility = "visible"}
/>
</div>
<div
className="sb-panel"
style={{ flex: config.mode }}
ref={panelRef}
/>
);
}
+1 -1
View File
@@ -311,7 +311,7 @@ export function editorSyscalls(client: Client): SysCallMapping {
_ctx,
id: string,
mode: number,
html: string,
html: HTMLElement | HTMLElement[] | string,
script: string,
) => {
client.ui.viewDispatch({
+1 -1
View File
@@ -14,7 +14,7 @@ import type { SyncStatus } from "../spaces/sync.ts";
export type PanelConfig = {
mode?: PanelMode;
html?: string;
html?: HTMLElement | HTMLElement[] | string;
script?: string;
};
+1 -1
View File
@@ -249,7 +249,7 @@ export function filterBox(
export function showPanel(
id: "lhs" | "rhs" | "bhs" | "modal",
mode: number,
html: string,
html: HTMLElement | HTMLElement[] | string,
script = "",
): Promise<void> {
return syscall("editor.showPanel", id, mode, html, script);