({
block,
selectedRange,
density,
}: { block: Extract<MarkdownBlock, { type: "code" }>; selectedRange: { start: number; end: number } | null; density: MarkdownMessageDensity })
| 594 | } |
| 595 | |
| 596 | function MermaidBlock({ |
| 597 | block, |
| 598 | selectedRange, |
| 599 | density, |
| 600 | }: { block: Extract<MarkdownBlock, { type: "code" }>; selectedRange: { start: number; end: number } | null; density: MarkdownMessageDensity }) { |
| 601 | const ref = useRef<HTMLDivElement | null>(null) |
| 602 | const theme = useEditorTheme(ref) |
| 603 | const [svg, setSvg] = useState<string | null>(null) |
| 604 | const [error, setError] = useState<string | null>(null) |
| 605 | |
| 606 | useEffect(() => { |
| 607 | let cancelled = false |
| 608 | const id = `openade-mermaid-${++mermaidDiagramId}` |
| 609 | setSvg(null) |
| 610 | setError(null) |
| 611 | |
| 612 | mermaid.initialize({ |
| 613 | startOnLoad: false, |
| 614 | securityLevel: "strict", |
| 615 | theme: normalizeShikiTheme(theme) === "github-light" || normalizeShikiTheme(theme) === "light-plus" ? "default" : "dark", |
| 616 | }) |
| 617 | |
| 618 | mermaid |
| 619 | .render(id, block.text) |
| 620 | .then((result) => { |
| 621 | if (!cancelled) setSvg(sanitizeHtml(result.svg)) |
| 622 | }) |
| 623 | .catch((err) => { |
| 624 | if (!cancelled) setError(err instanceof Error ? err.message : "Unable to render diagram") |
| 625 | }) |
| 626 | |
| 627 | return () => { |
| 628 | cancelled = true |
| 629 | } |
| 630 | }, [block.text, theme]) |
| 631 | |
| 632 | const props = rangeProps(block.startLine, block.endLine, selectedRange) |
| 633 | |
| 634 | return ( |
| 635 | <div ref={ref} {...props} className={cx(props.className, "group/diagram relative my-2 border border-border bg-base-200 p-3")}> |
| 636 | <CopyButton |
| 637 | content={block.text} |
| 638 | label="Copy diagram" |
| 639 | className="absolute top-2 right-2 z-10 opacity-0 transition-opacity group-hover/diagram:opacity-100 group-focus-within/diagram:opacity-100" |
| 640 | /> |
| 641 | {svg ? ( |
| 642 | // biome-ignore lint/security/noDangerouslySetInnerHtml: Mermaid renders SVG markup for diagram output. |
| 643 | <div className="overflow-x-auto [&_svg]:mx-auto [&_svg]:max-w-full" dangerouslySetInnerHTML={{ __html: svg }} /> |
| 644 | ) : error ? ( |
| 645 | <HighlightedCodeBlock block={block} selectedRange={selectedRange} density={density} /> |
| 646 | ) : ( |
| 647 | <div className="text-sm text-muted">Rendering diagram…</div> |
| 648 | )} |
| 649 | </div> |
| 650 | ) |
| 651 | } |
| 652 | |
| 653 | function renderedMarkdownClass(density: MarkdownMessageDensity) { |
nothing calls this directly
no test coverage detected