-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Mermaid.vue
82 lines (71 loc) · 1.92 KB
/
Mermaid.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<!--
Mermaid
(auto transformed, you don't need to use this component directly)
Usage:
```mermaid
pie
"Dogs" : 386
"Cats" : 85
"Rats" : 15
```
-->
<script setup lang="ts">
import { getCurrentInstance, ref, watch, watchEffect } from 'vue'
import { renderMermaid } from '../modules/mermaid'
import ShadowRoot from '../internals/ShadowRoot.vue'
import { isDark } from '../logic/dark'
const props = defineProps<{
codeLz: string
scale?: number
theme?: string
}>()
const vm = getCurrentInstance()
const el = ref<ShadowRoot>()
const error = ref<string | null>(null)
const html = ref('')
watchEffect(async (onCleanup) => {
let disposed = false
onCleanup(() => {
disposed = true
})
error.value = null
try {
const svg = await renderMermaid(
props.codeLz || '',
{
theme: props.theme || (isDark.value ? 'dark' : undefined),
...vm!.attrs,
},
)
if (!disposed)
html.value = svg
}
catch (e) {
error.value = `${e}`
console.warn(e)
}
})
const actualHeight = ref<number>()
watch(html, () => {
actualHeight.value = undefined
})
watchEffect(() => {
const svgEl = el.value?.children?.[0] as SVGElement | undefined
if (svgEl && svgEl.hasAttribute('viewBox') && actualHeight.value == null) {
const v = Number.parseFloat(svgEl.getAttribute('viewBox')?.split(' ')[3] || '')
actualHeight.value = Number.isNaN(v) ? undefined : v
}
}, { flush: 'post' })
watchEffect(() => {
const svgEl = el.value?.children?.[0] as SVGElement | undefined
if (svgEl != null && props.scale != null && actualHeight.value != null) {
svgEl.setAttribute('height', `${actualHeight.value * props.scale}`)
svgEl.removeAttribute('width')
svgEl.removeAttribute('style')
}
}, { flush: 'post' })
</script>
<template>
<pre v-if="error" border="1 red rounded" class="pa-3 text-wrap">{{ error }}</pre>
<ShadowRoot v-else class="mermaid" :inner-html="html" @shadow="el = $event" />
</template>