presentation/renderers/diagram.renderer.ts
presentation/renderers/diagram.renderer.ts is a file in Bane's Lab Site. 73 lines of code and 14 definitions.
import { DIAGRAM_MISSING, VIEW_FULL_DIAGRAM_TITLE } from "#configuration/strings/diagram.strings";
import {
DIAGRAM_RATIO_PROPERTY,
VIEWBOX_ATTRIBUTE,
VIEWBOX_HEIGHT_INDEX,
VIEWBOX_SEPARATOR,
VIEWBOX_WIDTH_INDEX,
} from "#configuration/constants/diagram.constants";
import { LANGUAGE_ATTRIBUTE, MERMAID_LANGUAGE } from "#configuration/constants/code.constants";
import { createElement, createVectorElement } from "#core/factories/element.factory";
import { DIAGRAM_FILLED } from "#core/ids/diagram.ids";
import type { MermaidBlock } from "#types/block.types";
import type { PanelHandle } from "#types/panel.types";
import { attachDiagramWalk } from "#presentation/components/diagram.component";
import { createExpandButton } from "#presentation/components/overlay.component";
import { createPanel } from "#presentation/components/panel.component";
import { declareStyle } from "#core/registries/style.registry";
import { isStaticRender } from "#core/predicates/document.predicate";
import { loadDiagram } from "#core/loaders/diagram.loader";
const ratioOf = function ratioOf(vector: Element): number | null {
const parts = (vector.getAttribute(VIEWBOX_ATTRIBUTE) ?? "").split(VIEWBOX_SEPARATOR).map(Number);
const width = parts[VIEWBOX_WIDTH_INDEX] ?? 0;
const height = parts[VIEWBOX_HEIGHT_INDEX] ?? 0;
return width > 0 && height > 0 ? width / height : null;
};
const fill = function fill(holder: HTMLElement, canvas: HTMLElement, markup: string | null): void {
if (markup === null) {
holder.replaceChildren(createElement("p", { className: "diagram-missing", text: DIAGRAM_MISSING }));
return;
}
const vector = createVectorElement(markup);
const ratio = ratioOf(vector);
if (ratio !== null) {
declareStyle(canvas, DIAGRAM_RATIO_PROPERTY, String(ratio));
}
holder.replaceChildren(vector);
};
const createCanvas = function createCanvas(source: string, className: string): HTMLElement {
const holder = createElement("div");
const panel: PanelHandle = createPanel(holder, className, "fit");
if (isStaticRender()) {
return panel.element;
}
void loadDiagram(source).then((markup) => {
fill(holder, panel.element, markup);
void attachDiagramWalk(holder);
panel.reset();
panel.element.dispatchEvent(new Event(DIAGRAM_FILLED));
});
return panel.element;
};
export const renderDiagram = function renderDiagram(block: MermaidBlock): Element {
const caption = block.caption ?? VIEW_FULL_DIAGRAM_TITLE;
const expand = createExpandButton("diagram-expand", VIEW_FULL_DIAGRAM_TITLE, caption, () =>
createCanvas(block.text, "diagram-full"),
);
const header = createElement("figcaption", {
children: [createElement("span", { className: "diagram-caption", text: caption }), expand],
className: "diagram-header",
});
return createElement("figure", {
children: [
header,
createCanvas(block.text, "diagram-canvas"),
createElement("pre", {
attributes: { [LANGUAGE_ATTRIBUTE]: MERMAID_LANGUAGE },
children: [createElement("code", { text: block.text })],
className: "diagram-source",
}),
],
className: "diagram-figure",
});
};