silverbullet/web/components/panel.tsx

101 lines
2.5 KiB
TypeScript
Raw Permalink Normal View History

import { useEffect, useRef } from "preact/hooks";
2024-07-30 23:33:33 +08:00
import type { Client } from "../client.ts";
import type { PanelConfig } from "../type.ts";
import { panelHtml } from "./panel_html.ts";
export function Panel({
config,
editor,
}: {
config: PanelConfig;
2023-07-14 22:56:20 +08:00
editor: Client;
}) {
const iFrameRef = useRef<HTMLIFrameElement>(null);
function updateContent() {
if (!iFrameRef.current?.contentWindow) {
return;
}
iFrameRef.current.contentWindow.postMessage({
type: "html",
html: config.html,
script: config.script,
2024-08-02 23:14:40 +08:00
theme: document.getElementsByTagName("html")[0].dataset.theme,
});
}
useEffect(() => {
const iframe = iFrameRef.current;
if (!iframe) {
return;
}
2024-08-02 23:14:40 +08:00
iframe.addEventListener("load", updateContent);
updateContent();
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;
}
2023-01-16 17:40:16 +08:00
switch (data.type) {
case "event":
editor.dispatchAppEvent(data.name, ...data.args);
break;
case "syscall": {
const { id, name, args } = data;
editor.clientSystem.localSyscall(name, args).then(
2023-07-14 19:44:30 +08:00
(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;
}
2023-01-16 17:40:16 +08:00
iFrameRef.current!.contentWindow!.postMessage({
type: "syscall-response",
id,
error: e.message,
});
});
break;
}
}
};
globalThis.addEventListener("message", messageListener);
return () => {
globalThis.removeEventListener("message", messageListener);
};
}, []);
return (
<div className="sb-panel" style={{ flex: config.mode }}>
2024-08-02 23:14:40 +08:00
<iframe
srcDoc={panelHtml}
ref={iFrameRef}
style={{ visibility: "hidden" }}
onLoad={() => iFrameRef.current!.style.visibility = "visible"}
/>
</div>
);
}