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