Skip to content

Commit 616146f

Browse files
silverwindlunny
andauthored
Various Mermaid improvements (#18776)
* Various Mermaid improvments - Render into iframe for improved security - Use built-in dark theme instead of color inversion - Remove flexbox attributes, resulting in more consistent size rendering - Update API usage and update to latest version * restart ci * misc tweaks * remove unneccesary declaration * make it work without allow-same-origin, add loading=lazy * remove loading attribute, does not seem to work * rename variable * skip roundtrip to DOM for rendering * don't guess chart height * update comment to make it clear it's intentional * tweak * replace deprecated 'scrolling' property * remove unused css file Co-authored-by: Lunny Xiao <[email protected]>
1 parent 1eb6bb9 commit 616146f

File tree

9 files changed

+50
-50
lines changed

9 files changed

+50
-50
lines changed

package-lock.json

+15-15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"less": "4.1.2",
2424
"less-loader": "10.2.0",
2525
"license-checker-webpack-plugin": "0.2.1",
26-
"mermaid": "8.13.10",
26+
"mermaid": "8.14.0",
2727
"mini-css-extract-plugin": "2.5.3",
2828
"monaco-editor": "0.32.1",
2929
"monaco-editor-webpack-plugin": "7.0.1",

web_src/js/markup/mermaid.js

+24-15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
import {isDarkTheme} from '../utils.js';
12
const {mermaidMaxSourceCharacters} = window.config;
23

4+
const iframeCss = `
5+
body {margin: 0; padding: 0}
6+
#mermaid {display: block; margin: 0 auto}
7+
`;
8+
39
function displayError(el, err) {
410
el.closest('pre').classList.remove('is-loading');
511
const errorNode = document.createElement('div');
@@ -15,26 +21,22 @@ export async function renderMermaid() {
1521
const {default: mermaid} = await import(/* webpackChunkName: "mermaid" */'mermaid');
1622

1723
mermaid.initialize({
18-
mermaid: {
19-
startOnLoad: false,
20-
},
21-
flowchart: {
22-
useMaxWidth: true,
23-
htmlLabels: false,
24-
},
25-
theme: 'neutral',
24+
startOnLoad: false,
25+
theme: isDarkTheme() ? 'dark' : 'neutral',
2626
securityLevel: 'strict',
2727
});
2828

2929
for (const el of els) {
30-
if (mermaidMaxSourceCharacters >= 0 && el.textContent.length > mermaidMaxSourceCharacters) {
31-
displayError(el, new Error(`Mermaid source of ${el.textContent.length} characters exceeds the maximum allowed length of ${mermaidMaxSourceCharacters}.`));
30+
const source = el.textContent;
31+
32+
if (mermaidMaxSourceCharacters >= 0 && source.length > mermaidMaxSourceCharacters) {
33+
displayError(el, new Error(`Mermaid source of ${source.length} characters exceeds the maximum allowed length of ${mermaidMaxSourceCharacters}.`));
3234
continue;
3335
}
3436

3537
let valid;
3638
try {
37-
valid = mermaid.parse(el.textContent);
39+
valid = mermaid.parse(source);
3840
} catch (err) {
3941
displayError(el, err);
4042
}
@@ -45,10 +47,17 @@ export async function renderMermaid() {
4547
}
4648

4749
try {
48-
mermaid.init(undefined, el, (id) => {
49-
const svg = document.getElementById(id);
50-
svg.classList.add('mermaid-chart');
51-
svg.closest('pre').replaceWith(svg);
50+
// can't use bindFunctions here because we can't cross the iframe boundary. This
51+
// means js-based interactions won't work but they aren't intended to work either
52+
mermaid.mermaidAPI.render('mermaid', source, (svgStr) => {
53+
const heightStr = (svgStr.match(/height="(.+?)"/) || [])[1];
54+
if (!heightStr) return displayError(el, new Error('Could not determine chart height'));
55+
const iframe = document.createElement('iframe');
56+
iframe.classList.add('markup-render');
57+
iframe.sandbox = 'allow-scripts';
58+
iframe.style.height = `${Math.ceil(parseFloat(heightStr))}px`;
59+
iframe.srcdoc = `<html><head><style>${iframeCss}</style></head><body>${svgStr}</body></html>`;
60+
el.closest('pre').replaceWith(iframe);
5261
});
5362
} catch (err) {
5463
displayError(el, err);

web_src/less/_base.less

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
/* other variables */
77
--border-radius: .28571429rem;
88
--opacity-disabled: .55;
9+
--height-loading: 12rem;
910
--color-primary: #4183c4;
1011
--color-primary-dark-1: #3876b3;
1112
--color-primary-dark-2: #31699f;

web_src/less/animations.less

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
.markup pre.is-loading,
3232
.editor-loading.is-loading {
33-
height: 12rem;
33+
height: var(--height-loading);
3434
}
3535

3636
@keyframes fadein {

web_src/less/index.less

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
@import "./features/codeeditor.less";
1111
@import "./features/projects.less";
1212
@import "./markup/content.less";
13-
@import "./markup/mermaid.less";
1413
@import "./markup/codecopy.less";
1514
@import "./code/linebutton.less";
1615

web_src/less/markup/content.less

+8
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,14 @@
536536
}
537537
}
538538

539+
.markup-render {
540+
display: block;
541+
border: none;
542+
width: 100%;
543+
height: var(--height-loading); // actual height is set in JS after loading
544+
overflow: hidden;
545+
}
546+
539547
.markup-block-error {
540548
margin-bottom: 0 !important;
541549
border-bottom-left-radius: 0 !important;

web_src/less/markup/mermaid.less

-13
This file was deleted.

web_src/less/themes/theme-arc-green.less

-4
Original file line numberDiff line numberDiff line change
@@ -455,10 +455,6 @@ img[src$="/img/matrix.svg"] {
455455
filter: invert(80%);
456456
}
457457

458-
.mermaid-chart {
459-
filter: invert(84%) hue-rotate(180deg);
460-
}
461-
462458
.is-loading::after {
463459
border-color: #4a4c58 #4a4c58 #d7d7da #d7d7da;
464460
}

0 commit comments

Comments
 (0)