mermaid-isomorphic
Version:
Transform mermaid diagrams in the browser or Node.js
87 lines (72 loc) • 2.15 kB
text/typescript
import type {
MermaidRenderer,
createMermaidRenderer as nodeImplementation,
RenderResult
} from './mermaid-isomorphic.js'
import mermaid from 'mermaid'
const parser = new DOMParser()
const serializer = new XMLSerializer()
/**
* Get an aria value form a referencing attribute.
*
* @param element
* The SVG element the get the value from.
* @param attribute
* The attribute whose value to get.
* @returns
* The aria value.
*/
function getAriaValue(element: SVGSVGElement, attribute: string): string | undefined {
const value = element.getAttribute(attribute)
if (!value) {
return
}
let result = ''
for (const id of value.split(/\s+/)) {
const node = element.getElementById(id)
if (node) {
result += node.textContent
}
}
return result
}
let count = 0
const renderer: MermaidRenderer = async (diagrams, options) => {
const container = document.createElement('div')
container.ariaHidden = 'true'
container.style.maxHeight = '0'
container.style.opacity = '0'
container.style.overflow = 'hidden'
if (options?.containerStyle) {
Object.assign(container.style, options.containerStyle)
}
document.body.append(container)
const results = await Promise.allSettled(
diagrams.map(async (diagram) => {
const id = `${options?.prefix ?? 'mermaid'}-${count}`
count += 1
const { svg } = await mermaid.render(id, diagram, container)
const root = parser.parseFromString(svg, 'text/html')
const [element] = root.getElementsByTagName('svg')
const { height, width } = element.viewBox.baseVal
const description = getAriaValue(element, 'aria-describedby')
const title = getAriaValue(element, 'aria-labelledby')
const result: RenderResult = {
height,
id,
svg: serializer.serializeToString(element),
width
}
if (description) {
result.description = description
}
if (title) {
result.title = title
}
return result
})
)
container.remove()
return results
}
export const createMermaidRenderer: typeof nodeImplementation = () => renderer