1+ const uml = async className => {
2+
3+ // Custom element to encapsulate Mermaid content.
4+ class MermaidDiv extends HTMLElement {
5+
6+ /**
7+ * Creates a special Mermaid div shadow DOM.
8+ * Works around issues of shared IDs.
9+ * @return {void }
10+ */
11+ constructor ( ) {
12+ super ( )
13+
14+ // Create the Shadow DOM and attach style
15+ const shadow = this . attachShadow ( { mode : "open" } )
16+ const style = document . createElement ( "style" )
17+ style . textContent = `
18+ :host {
19+ display: block;
20+ line-height: initial;
21+ font-size: 16px;
22+ }
23+ div.diagram {
24+ margin: 0;
25+ overflow: visible;
26+ }`
27+ shadow . appendChild ( style )
28+ }
29+ }
30+
31+ if ( typeof customElements . get ( "diagram-div" ) === "undefined" ) {
32+ customElements . define ( "diagram-div" , MermaidDiv )
33+ }
34+
35+ const getFromCode = parent => {
36+ // Handles <pre><code> text extraction.
37+ let text = ""
38+ for ( let j = 0 ; j < parent . childNodes . length ; j ++ ) {
39+ const subEl = parent . childNodes [ j ]
40+ if ( subEl . tagName . toLowerCase ( ) === "code" ) {
41+ for ( let k = 0 ; k < subEl . childNodes . length ; k ++ ) {
42+ const child = subEl . childNodes [ k ]
43+ const whitespace = / ^ \s * $ /
44+ if ( child . nodeName === "#text" && ! ( whitespace . test ( child . nodeValue ) ) ) {
45+ text = child . nodeValue
46+ break
47+ }
48+ }
49+ }
50+ }
51+ return text
52+ }
53+
54+ // Provide a default config in case one is not specified
55+ const defaultConfig = {
56+ startOnLoad : false ,
57+ theme : "default" ,
58+ flowchart : {
59+ htmlLabels : false
60+ } ,
61+ er : {
62+ useMaxWidth : false
63+ } ,
64+ sequence : {
65+ useMaxWidth : false ,
66+ noteFontWeight : "14px" ,
67+ actorFontSize : "14px" ,
68+ messageFontSize : "16px"
69+ }
70+ }
71+
72+ // Load up the config
73+ mermaid . mermaidAPI . globalReset ( )
74+ const config = ( typeof mermaidConfig === "undefined" ) ? defaultConfig : mermaidConfig
75+ mermaid . initialize ( config )
76+
77+ // Find all of our Mermaid sources and render them.
78+ const blocks = document . querySelectorAll ( `pre.${ className } , diagram-div` )
79+ const surrogate = document . querySelector ( "html body" )
80+ for ( let i = 0 ; i < blocks . length ; i ++ ) {
81+ const block = blocks [ i ]
82+ const parentEl = ( block . tagName . toLowerCase ( ) === "diagram-div" ) ?
83+ block . shadowRoot . querySelector ( `pre.${ className } ` ) :
84+ block
85+
86+ // Create a temporary element with the typeset and size we desire.
87+ // Insert it at the end of our parent to render the SVG.
88+ const temp = document . createElement ( "div" )
89+ temp . style . visibility = "hidden"
90+ temp . style . display = "display"
91+ temp . style . padding = "0"
92+ temp . style . margin = "0"
93+ temp . style . lineHeight = "initial"
94+ temp . style . fontSize = "16px"
95+ surrogate . appendChild ( temp )
96+
97+ try {
98+ const res = await mermaid . render ( `_diagram_${ i } ` , getFromCode ( parentEl ) , temp )
99+ const content = res . svg
100+ const fn = res . bindFunctions
101+ const el = document . createElement ( "div" )
102+ el . className = className
103+ el . innerHTML = content
104+ if ( fn ) {
105+ fn ( el )
106+ }
107+
108+ // Insert the render where we want it and remove the original text source.
109+ // Mermaid will clean up the temporary element.
110+ const shadow = document . createElement ( "diagram-div" )
111+ shadow . shadowRoot . appendChild ( el )
112+ block . parentNode . insertBefore ( shadow , block )
113+ parentEl . style . display = "none"
114+ shadow . shadowRoot . appendChild ( parentEl )
115+ if ( parentEl !== block ) {
116+ block . parentNode . removeChild ( block )
117+ }
118+ } catch ( err ) { } // eslint-disable-line no-empty
119+
120+ if ( surrogate . contains ( temp ) ) {
121+ surrogate . removeChild ( temp )
122+ }
123+ }
124+ }
125+
126+ // This should be run on document load
127+ document . addEventListener ( "DOMContentLoaded" , ( ) => { uml ( "mermaid" ) } )
0 commit comments