Merge pull request #1032 from mermaid-js/develop

Develop
This commit is contained in:
Sidharth Vinod
2022-09-12 10:03:18 +05:30
committed by GitHub
11 changed files with 95 additions and 110 deletions
-1
View File
@@ -48,4 +48,3 @@ jobs:
parallel: true
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
MERMAID_DISABLE_DEBOUNCE: 'true'
+3 -3
View File
@@ -5,7 +5,7 @@
"license": "MIT",
"scripts": {
"dev": "vite dev",
"dev:test": "MERMAID_DISABLE_DEBOUNCE=true yarn dev",
"dev:test": "yarn dev",
"build": "vite build",
"preview": "vite preview",
"lint": "prettier --check --cache --plugin-search-dir=. .;eslint --ignore-path .gitignore .",
@@ -31,7 +31,7 @@
"@types/uuid": "8.3.4",
"@typescript-eslint/eslint-plugin": "5.36.2",
"@typescript-eslint/parser": "5.36.2",
"@vitest/ui": "0.23.1",
"@vitest/ui": "0.23.2",
"autoprefixer": "10.4.8",
"c8": "7.12.0",
"chai": "4.3.6",
@@ -62,7 +62,7 @@
"tslib": "2.4.0",
"typescript": "4.8.3",
"vite": "3.1.0",
"vitest": "0.23.1"
"vitest": "0.23.2"
},
"dependencies": {
"@analytics/google-analytics": "1.0.3",
+5 -5
View File
@@ -115,19 +115,19 @@
const onCopyClipboard = (event: Event) => {
exportImage(event, clipboardCopy);
void logEvent('copyClipboard');
logEvent('copyClipboard');
};
const onDownloadPNG = (event: Event) => {
exportImage(event, downloadImage);
void logEvent('download', {
logEvent('download', {
type: 'png'
});
};
const onDownloadSVG = () => {
simulateDownload(getFileName('svg'), `data:image/svg+xml;base64,${getBase64SVG()}`);
void logEvent('download', {
logEvent('download', {
type: 'svg'
});
};
@@ -135,7 +135,7 @@
const onCopyMarkdown = () => {
(document.getElementById('markdown') as HTMLInputElement).select();
document.execCommand('Copy');
void logEvent('copyMarkdown');
logEvent('copyMarkdown');
};
let gistURL = '';
@@ -151,7 +151,7 @@
alert('Please enter a Gist URL first');
}
window.location.href = `${window.location.pathname}?gist=${gistURL}`;
void logEvent('loadGist');
logEvent('loadGist');
};
let iUrl: string;
+5 -20
View File
@@ -7,7 +7,6 @@
import { onMount } from 'svelte';
import initEditor from 'monaco-mermaid';
import { logEvent } from '$lib/util/stats';
import { debounceEnabled } from '$lib/util/env';
let divEl: HTMLDivElement = null;
let editor: monaco.editor.IStandaloneCodeEditor;
@@ -37,8 +36,8 @@
Monaco?.editor.setModelLanguage(editor.getModel(), language);
}
// Display/clear error
Monaco?.editor.setModelMarkers(editor.getModel(), 'test', errorMarkers);
// Display/clear errors
Monaco?.editor.setModelMarkers(editor.getModel(), 'mermaid', errorMarkers);
});
themeStore.subscribe(({ isDark }) => {
@@ -53,21 +52,6 @@
}
};
// Debounce state updates to avoid performance issues
let debounce: { [key: string]: number } = {};
const updateHandler = (newText: string) => {
text = newText;
const mode = $stateStore.editorMode;
if (debounceEnabled) {
clearTimeout(debounce[mode]);
debounce[mode] = window.setTimeout(() => {
handleUpdate(text, mode);
}, 300);
} else {
handleUpdate(text, mode);
}
};
const loadMonaco = async () => {
let i = 0;
while (i++ < 500) {
@@ -87,7 +71,8 @@
initEditor(Monaco);
editor = Monaco.editor.create(divEl, editorOptions);
editor.onDidChangeModelContent(() => {
updateHandler(editor.getValue());
text = editor.getValue();
handleUpdate(text, $stateStore.editorMode);
});
editor.addAction({
id: 'mermaid-render-diagram',
@@ -95,7 +80,7 @@
keybindings: [Monaco.KeyMod.CtrlCmd | Monaco.KeyCode.Enter],
run: function () {
syncDiagram();
void logEvent('renderDiagram', {
logEvent('renderDiagram', {
method: 'keyboadShortcut'
});
}
+1 -1
View File
@@ -100,7 +100,7 @@
updateDiagram: true,
resetPanZoom: true
});
void logEvent('loadSampleDiagram', { diagramType });
logEvent('loadSampleDiagram', { diagramType });
};
</script>
+48 -49
View File
@@ -3,7 +3,7 @@
import { onMount } from 'svelte';
import mermaid from 'mermaid';
import panzoom from 'svg-pan-zoom';
import type { State } from '$lib/types';
import type { State, ValidatedState } from '$lib/types';
import { logEvent } from '$lib/util/stats';
let code = '';
@@ -16,16 +16,12 @@
let manualUpdate = true;
let panZoomEnabled = $stateStore.panZoom;
let pzoom: SvgPanZoom.Instance;
let debounce: number;
const handlePanZoomChange = () => {
const pan = pzoom.getPan();
const zoom = pzoom.getZoom();
clearTimeout(debounce);
debounce = window.setTimeout(() => {
updateCodeStore({ pan, zoom });
void logEvent('panZoom');
}, 200);
updateCodeStore({ pan, zoom });
logEvent('panZoom');
};
const handlePanZoom = (state: State) => {
@@ -53,50 +49,53 @@
});
};
const handleStateChange = (state: ValidatedState) => {
if (state.error !== undefined) {
error = true;
return;
}
error = false;
try {
if (container && state && (state.updateDiagram || state.autoSync)) {
if (!state.autoSync) {
$inputStateStore.updateDiagram = false;
}
outOfSync = false;
manualUpdate = true;
if (code === state.code && config === state.mermaid && panZoomEnabled === state.panZoom) {
// Do not render if there is no change in Code/Config/PanZoom
return;
}
code = state.code;
config = state.mermaid;
panZoomEnabled = state.panZoom;
const scroll = view.parentElement.scrollTop;
delete container.dataset.processed;
mermaid.initialize(Object.assign({}, JSON.parse(state.mermaid)));
mermaid.render('graph-div', code, (svgCode) => {
if (svgCode.length > 0) {
handlePanZoom(state);
container.innerHTML = svgCode;
const graphDiv = document.getElementById('graph-div');
graphDiv.setAttribute('height', '100%');
graphDiv.style.maxWidth = '100%';
}
});
view.parentElement.scrollTop = scroll;
error = false;
} else if (manualUpdate) {
manualUpdate = false;
} else if (code !== state.code || config !== state.mermaid) {
outOfSync = true;
}
} catch (e) {
console.error('view fail', e);
error = true;
}
};
onMount(() => {
stateStore.subscribe((state) => {
if (state.error !== undefined) {
error = true;
return;
}
error = false;
try {
if (container && state && (state.updateDiagram || state.autoSync)) {
if (!state.autoSync) {
$inputStateStore.updateDiagram = false;
}
outOfSync = false;
manualUpdate = true;
if (code === state.code && config === state.mermaid && panZoomEnabled === state.panZoom) {
// Do not render if there is no change in Code/Config/PanZoom
return;
}
code = state.code;
config = state.mermaid;
panZoomEnabled = state.panZoom;
const scroll = view.parentElement.scrollTop;
delete container.dataset.processed;
mermaid.initialize(Object.assign({}, JSON.parse(state.mermaid)));
mermaid.render('graph-div', code, (svgCode) => {
if (svgCode.length > 0) {
handlePanZoom(state);
container.innerHTML = svgCode;
const graphDiv = document.getElementById('graph-div');
graphDiv.setAttribute('height', '100%');
graphDiv.style.maxWidth = '100%';
}
});
view.parentElement.scrollTop = scroll;
error = false;
} else if (manualUpdate) {
manualUpdate = false;
} else if (code !== state.code || config !== state.mermaid) {
outOfSync = true;
}
} catch (e) {
console.error('view fail', e);
error = true;
}
handleStateChange(state);
});
window.addEventListener('resize', () => {
if ($stateStore.panZoom && pzoom) {
-1
View File
@@ -2,4 +2,3 @@ export const rendererUrl: string =
(import.meta.env.MERMAID_RENDERER_URL as string) ?? 'https://mermaid.ink';
export const krokiRendererUrl: string =
(import.meta.env.MERMAID_KROKI_RENDERER_URL as string) ?? 'https://kroki.io';
export const debounceEnabled: boolean = import.meta.env.MERMAID_DISABLE_DEBOUNCE !== 'true';
+5 -1
View File
@@ -162,9 +162,13 @@ export const toggleDarkTheme = (dark: boolean): void => {
});
};
let urlDebounce: number;
export const initURLSubscription = (): void => {
stateStore.subscribe(({ serialized }) => {
history.replaceState(undefined, undefined, `#${serialized}`);
clearTimeout(urlDebounce);
urlDebounce = window.setTimeout(() => {
history.replaceState(undefined, undefined, `#${serialized}`);
}, 250);
});
};
+12 -13
View File
@@ -42,21 +42,20 @@ const detectType = (text: string): string => {
.split(' ')[0];
};
// manual debounce
let timeout: number;
export const saveStatistics = (graph: string): void => {
const graphType = detectType(graph);
console.debug(`ga: send event: render ${graphType}`);
logEvent('render', { graphType });
};
// manual debounce to only send analytics event every 5 seconds if same event is repeated frequently.
const timeouts: Record<string, number> = {};
export const logEvent = (name: string, data?: unknown): void => {
if (analytics) {
clearTimeout(timeout);
// Only save statistics after a 5 sec delay
timeout = window.setTimeout(() => {
const graphType = detectType(graph);
console.debug(`ga: send event: render ${graphType}`);
void logEvent('render', { graphType });
const key = data ? JSON.stringify({ name, data }) : name;
clearTimeout(timeouts[key]);
timeouts[key] = window.setTimeout(() => {
void analytics.track(name, data);
}, 5000);
}
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const logEvent = async (name: string, data?: any): Promise<void> => {
await analytics?.track(name, data);
};
+1 -1
View File
@@ -34,5 +34,5 @@ export const setTheme = (theme: string): void => {
const isDark = darkThemes.includes(theme);
console.log('Setting theme', theme);
themeStore.set({ theme, isDark });
void logEvent('themeChange', { theme, isDark });
logEvent('themeChange', { theme, isDark });
};
+15 -15
View File
@@ -598,10 +598,10 @@
"@typescript-eslint/types" "5.36.2"
eslint-visitor-keys "^3.3.0"
"@vitest/ui@0.23.1":
version "0.23.1"
resolved "https://registry.yarnpkg.com/@vitest/ui/-/ui-0.23.1.tgz#de3e95b7cc01137767d64c4a8464f2d586009925"
integrity sha512-W1ygPK4aTyLTPsf6NX3gZFbH0X1ipNzlHhxTRnZ4/HpQXs/qKw5NDY45/U2yC66Fevj5kXHI1tdrNfN00NouFQ==
"@vitest/ui@0.23.2":
version "0.23.2"
resolved "https://registry.yarnpkg.com/@vitest/ui/-/ui-0.23.2.tgz#0d4a3918edaca6d38f20c49467a03a51d4b26eff"
integrity sha512-dO1UxSwEm11OgumUVbEnF7wKwDPoBGjkrvATvvhkFaDw2iiQm8WewF0hmnUVHj6BSNoHUIJ3uXEzfF9T9W+2yg==
dependencies:
sirv "^2.0.2"
@@ -5129,15 +5129,15 @@ tiny-glob@^0.2.9:
globalyzer "0.1.0"
globrex "^0.1.2"
tinybench@^2.1.3:
tinybench@^2.1.5:
version "2.1.5"
resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.1.5.tgz#6864341415ff0f912ed160cfd90b7f833ece674c"
integrity sha512-ak+PZZEuH3mw6CCFOgf5S90YH0MARnZNhxjhjguAmoJimEMAJuNip/rJRd6/wyylHItomVpKTzZk9zrhTrQCoQ==
tinypool@^0.2.4:
version "0.2.4"
resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.2.4.tgz#4d2598c4689d1a2ce267ddf3360a9c6b3925a20c"
integrity sha512-Vs3rhkUH6Qq1t5bqtb816oT+HeJTXfwt2cbPH17sWHIYKTotQIFPk3tf2fgqRrVyMDVOc1EnPgzIxfIulXVzwQ==
tinypool@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.3.0.tgz#c405d8b743509fc28ea4ca358433190be654f819"
integrity sha512-NX5KeqHOBZU6Bc0xj9Vr5Szbb1j8tUHIeD18s41aDJaPeC5QTdEhK0SpdpUrZlj2nv5cctNcSjaKNanXlfcVEQ==
tinyspy@^1.0.2:
version "1.0.2"
@@ -5355,10 +5355,10 @@ vite@3.1.0:
optionalDependencies:
fsevents "~2.3.2"
vitest@0.23.1:
version "0.23.1"
resolved "https://registry.yarnpkg.com/vitest/-/vitest-0.23.1.tgz#da3f79a88a6570e4d8c1fe8cf5e2d997be2dc3bd"
integrity sha512-kn9pG+h6VA3yj/xRvwgLKEd33rOlzMqJEg3tl5HSm3WUPlkY1Lr1FK8RN1uIqVKvFxmz6HGU3EQW+xW2kazRkQ==
vitest@0.23.2:
version "0.23.2"
resolved "https://registry.yarnpkg.com/vitest/-/vitest-0.23.2.tgz#f978de0f2ada1b7c5ff8dc479ce75b976957ff19"
integrity sha512-kTBKp3ROPDkYC+x2zWt4znkDtnT08W1FQ6ngRFuqxpBGNuNVS+eWZKfffr8y2JGvEzZ9EzMAOcNaiqMj/FZqMw==
dependencies:
"@types/chai" "^4.3.3"
"@types/chai-subset" "^1.3.3"
@@ -5367,8 +5367,8 @@ vitest@0.23.1:
debug "^4.3.4"
local-pkg "^0.4.2"
strip-literal "^0.4.0"
tinybench "^2.1.3"
tinypool "^0.2.4"
tinybench "^2.1.5"
tinypool "^0.3.0"
tinyspy "^1.0.2"
vite "^2.9.12 || ^3.0.0-0"