/** * DrawioView renders a .drawio / .dio diagram with the diagrams.net embed * viewer, loaded in an iframe and fed the XML over its postMessage protocol * (`init` → `load`). There is no offline renderer for draw.io's shape * library that ori could bundle, so an isolated sandbox without access to * embed.diagrams.net gets a notice and the XML source instead. * * @example * setMode("source")} /> */ import { useEffect, useRef, useState } from "react"; /** Read-only embed: lightbox chrome (zoom, pages, layers), no editor UI. */ export const DRAWIO_EMBED_URL = "https://embed.diagrams.net/?embed=1&proto=json&spin=1&lightbox=1&nav=1&chrome=0"; /** How long to wait for the viewer's `init` before declaring it unreachable. */ const DEFAULT_TIMEOUT_MS = 8000; interface DrawioViewProps { xml: string; /** Override for tests; defaults to DRAWIO_EMBED_URL. */ embedUrl?: string; /** Override for tests; defaults to 8 s. */ timeoutMs?: number; } type ViewerStatus = "loading" | "ready" | "unavailable"; export function DrawioView({ xml, embedUrl = DRAWIO_EMBED_URL, timeoutMs = DEFAULT_TIMEOUT_MS, }: DrawioViewProps) { const frameRef = useRef(null); const [status, setStatus] = useState("loading"); useEffect(() => { const frame = frameRef.current; if (!frame) { return; } const timer = setTimeout(() => { setStatus((current) => (current === "ready" ? current : "unavailable")); }, timeoutMs); const onMessage = (event: MessageEvent) => { if (event.source !== frame.contentWindow) { return; } const message = parseViewerMessage(event.data); if (message?.event === "init") { frame.contentWindow?.postMessage( JSON.stringify({ action: "load", xml, autosave: 0 }), "*", ); } if (message?.event === "init" || message?.event === "load") { clearTimeout(timer); setStatus("ready"); } }; window.addEventListener("message", onMessage); return () => { clearTimeout(timer); window.removeEventListener("message", onMessage); }; }, [xml, timeoutMs]); return (
{status === "unavailable" && (

The diagram viewer (embed.diagrams.net) is not reachable from this browser; use the Source view to read the diagram XML.

)} {status === "loading" &&

loading viewer…

}