Skip to content

Commit

Permalink
adding mermaid rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
pelikhan committed Jan 15, 2025
1 parent 2b3f406 commit 37e6f6d
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 13 deletions.
33 changes: 31 additions & 2 deletions packages/sample/genaisrc/envoutput.genai.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,34 @@ $`Write a poem`

output.itemValue("item", "value")
output.fence("This is a fence")
output.fence([{a: 1, b: 2}, {a: 3, b: 4}], "md")
output.fence([{a: 1, b: 2}, {a: 3, b: 4}], "csv")
output.fence(
[
{ a: 1, b: 2 },
{ a: 3, b: 4 },
],
"md"
)
output.fence(
[
{ a: 1, b: 2 },
{ a: 3, b: 4 },
],
"csv"
)
output.fence(`A --> B`, "mermaid")
output.fence(`A -> B`, "mermaid")
output.fence(
`
sequenceDiagram
Alice ->> Bob: Hello Bob, how are you?
Bob-->>John: How about you John?
Bob--x Alice: I am good thanks!
Bob-x John: I am good thanks!
Note right of John: Bob thinks a long<br/>long time, so long<br/>that the text does<br/>not fit on a row.
Bob-->Alice: Checking with John...
Alice->John: Yes... John, how are you?
`,
"mermaid"
)
2 changes: 2 additions & 0 deletions packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@vscode-elements/webview-playground": "^1.3.0",
"clsx": "^2.1.1",
"esbuild": "^0.24.2",
"mermaid": "^11.4.1",
"pretty-bytes": "^6.1.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
Expand All @@ -32,6 +33,7 @@
"remark-gfm": "^4.0.0",
"remark-github-blockquote-alert": "^1.3.0",
"remark-math": "^6.0.0",
"remark-mermaid": "^0.2.0",
"typescript": "^5.7.2"
}
}
15 changes: 14 additions & 1 deletion packages/web/src/Markdown.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// src/components/FormField.tsx
import React from "react"
import React, { use, useEffect, useMemo, useRef } from "react"
import ReactMarkdown from "react-markdown"
import remarkGfm from "remark-gfm"
import rehypeRaw from "rehype-raw"
Expand All @@ -11,6 +11,7 @@ import remarkMath from "remark-math"
import rehypeMathML from "@daiji256/rehype-mathml"
import { ErrorBoundary } from "react-error-boundary"
import rehypeHighlight from "rehype-highlight"
import Mermaid from "./Mermaid"

export default function Markdown(props: { className?: string; children: any }) {
const { className, children } = props
Expand All @@ -22,6 +23,18 @@ export default function Markdown(props: { className?: string; children: any }) {
}
>
<ReactMarkdown
components={{
code({ node, className, children, ...props }) {
if (className?.includes("language-mermaid")) {
return <Mermaid value={String(children)} />
}
return (
<code className={className} {...props}>
{children}
</code>
)
},
}}
rehypePlugins={[
rehypeRaw,
[
Expand Down
48 changes: 48 additions & 0 deletions packages/web/src/Mermaid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// src/components/FormField.tsx
import React, { useEffect, useMemo, useRef } from "react"
import { ErrorBoundary } from "react-error-boundary"
import mermaid from "mermaid"
import { useAttributeValue } from "./useAttributeValue"

mermaid.initialize({
startOnLoad: false,
securityLevel: "strict",
})

function MermaidInternal(props: { value: string }) {
const { value } = props
const bodyClassName = useAttributeValue(document.body, "class")
const theme = bodyClassName?.includes("dark") ? "dark" : "default"
const ref = useRef<HTMLDivElement>(null)
const src = useMemo(() => {
try {
mermaid.detectType(value)
return value
} catch (error) {
return `graph TD; ` + value
}
}, [value])

useEffect(() => {
if (ref.current) {
mermaid.initialize({ theme })
mermaid.run({ nodes: [ref.current] })
}
}, [value, theme])
if (!value) return null
return (
<div className="mermaid" ref={ref}>
{src}
</div>
)
}

export default function Mermaid(props: { value: string }) {
return (
<ErrorBoundary
fallback={<p>⚠️Something went wrong while rendering mermaid.</p>}
>
<MermaidInternal {...props} />
</ErrorBoundary>
)
}
14 changes: 14 additions & 0 deletions packages/web/src/useAttributeValue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// src/components/FormField.tsx
import React, { useEffect, useState } from "react"

export function useAttributeValue(el: HTMLElement, name: string) {
const [value, setValue] = useState(el.getAttribute(name))
useEffect(() => {
const observer = new MutationObserver(() => {
setValue(el.getAttribute(name))
})
observer.observe(el, { attributes: true })
return () => observer.disconnect()
}, [el, name])
return value
}
4 changes: 4 additions & 0 deletions packages/web/src/vscode.markdown.css
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,7 @@
.markdown-body .vscode-dark td {
border-color: rgba(255, 255, 255, 0.18);
}

.markdown-body pre code.language-mermaid {
font-family: 'trebuchet ms', verdana, arial;
}
83 changes: 73 additions & 10 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4335,6 +4335,11 @@ commander@^12.1.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3"
integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==

commander@^2.9.0:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==

commander@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae"
Expand Down Expand Up @@ -5106,13 +5111,6 @@ encoding-sniffer@^0.2.0:
iconv-lite "^0.6.3"
whatwg-encoding "^3.1.1"

encoding@^0.1.13:
version "0.1.13"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==
dependencies:
iconv-lite "^0.6.2"

end-of-stream@^1.1.0, end-of-stream@^1.4.1:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
Expand Down Expand Up @@ -5670,6 +5668,15 @@ fs-extra@^11.1.1, fs-extra@^11.2.0:
jsonfile "^6.0.1"
universalify "^2.0.0"

fs-extra@^4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94"
integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==
dependencies:
graceful-fs "^4.1.2"
jsonfile "^4.0.0"
universalify "^0.1.0"

fs-minipass@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
Expand Down Expand Up @@ -6283,7 +6290,7 @@ humanize-ms@^1.2.1:
dependencies:
ms "^2.0.0"

[email protected], [email protected], iconv-lite@^0.6.2, iconv-lite@^0.6.3:
[email protected], [email protected], iconv-lite@^0.6.3:
version "0.6.3"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
Expand Down Expand Up @@ -6844,6 +6851,13 @@ jsonc-parser@^3.2.0:
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.3.1.tgz#f2a524b4f7fd11e3d791e559977ad60b98b798b4"
integrity sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==

jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==
optionalDependencies:
graceful-fs "^4.1.6"

jsonfile@^6.0.1:
version "6.1.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
Expand Down Expand Up @@ -7538,7 +7552,7 @@ mermaid-isomorphic@^3.0.0:
"@fortawesome/fontawesome-free" "^6.0.0"
mermaid "^11.0.0"

mermaid@^11.0.0:
mermaid@^11.0.0, mermaid@^11.4.1:
version "11.4.1"
resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-11.4.1.tgz#577fad5c31a01a06d9f793e298d411f1379eecc8"
integrity sha512-Mb01JT/x6CKDWaxigwfZYuYmDZ6xtrNwNlidKZwkSrDaY9n90tdrJTV5Umk+wP1fZscGptmKFXHsXMDEVZ+Q6A==
Expand Down Expand Up @@ -8156,6 +8170,13 @@ npm-check-updates@^17.1.13:
resolved "https://registry.yarnpkg.com/npm-check-updates/-/npm-check-updates-17.1.13.tgz#93e1c5fa5b8e11bca0bd143650b14ffcf9fc6b5a"
integrity sha512-m9Woo2J5XVab0VcQpYvrQ0hx3ySI1mGbiHR595mc6Lr1/FIaTWvv+oU+T1WKSfXRiluKC/V5P6Bdk5agaYpqqg==

npm-path@^2.0.2:
version "2.0.4"
resolved "https://registry.yarnpkg.com/npm-path/-/npm-path-2.0.4.tgz#c641347a5ff9d6a09e4d9bce5580c4f505278e64"
integrity sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw==
dependencies:
which "^1.2.10"

npm-run-all@^4.1.5:
version "4.1.5"
resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba"
Expand All @@ -8179,6 +8200,15 @@ npm-run-path@^6.0.0:
path-key "^4.0.0"
unicorn-magic "^0.3.0"

npm-which@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/npm-which/-/npm-which-3.0.1.tgz#9225f26ec3a285c209cae67c3b11a6b4ab7140aa"
integrity sha512-CM8vMpeFQ7MAPin0U3wzDhSGV0hMHNwHU0wjo402IVizPDrs45jSfSuoC+wThevY88LQti8VvaAnqYAeVy3I1A==
dependencies:
commander "^2.9.0"
npm-path "^2.0.2"
which "^1.2.10"

npmlog@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0"
Expand Down Expand Up @@ -9196,6 +9226,15 @@ remark-math@^6.0.0:
micromark-extension-math "^3.0.0"
unified "^11.0.0"

remark-mermaid@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/remark-mermaid/-/remark-mermaid-0.2.0.tgz#7873dacb6eca3fb145bc5d85250937619bf4dce3"
integrity sha512-eAFxk0D4MCLdWiNPDjz7+m357QPf4cUmPKwXnsl1h6nCWg0/YTKdcpKLxabSEf66MtauxXSu/rMxx9KDDv8vew==
dependencies:
fs-extra "^4.0.1"
npm-which "^3.0.1"
unist-util-visit "^1.1.3"

remark-parse@^11.0.0:
version "11.0.0"
resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-11.0.0.tgz#aa60743fcb37ebf6b069204eb4da304e40db45a1"
Expand Down Expand Up @@ -10462,6 +10501,11 @@ unist-util-find-after@^5.0.0:
"@types/unist" "^3.0.0"
unist-util-is "^6.0.0"

unist-util-is@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-3.0.0.tgz#d9e84381c2468e82629e4a5be9d7d05a2dd324cd"
integrity sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==

unist-util-is@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-6.0.0.tgz#b775956486aff107a9ded971d996c173374be424"
Expand Down Expand Up @@ -10491,6 +10535,13 @@ unist-util-stringify-position@^4.0.0:
dependencies:
"@types/unist" "^3.0.0"

unist-util-visit-parents@^2.0.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz#25e43e55312166f3348cae6743588781d112c1e9"
integrity sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==
dependencies:
unist-util-is "^3.0.0"

unist-util-visit-parents@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz#4d5f85755c3b8f0dc69e21eca5d6d82d22162815"
Expand All @@ -10499,6 +10550,13 @@ unist-util-visit-parents@^6.0.0:
"@types/unist" "^3.0.0"
unist-util-is "^6.0.0"

unist-util-visit@^1.1.3:
version "1.4.1"
resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.4.1.tgz#4724aaa8486e6ee6e26d7ff3c8685960d560b1e3"
integrity sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==
dependencies:
unist-util-visit-parents "^2.0.0"

unist-util-visit@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-5.0.0.tgz#a7de1f31f72ffd3519ea71814cccf5fd6a9217d6"
Expand All @@ -10518,6 +10576,11 @@ universal-user-agent@^7.0.0, universal-user-agent@^7.0.2:
resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-7.0.2.tgz#52e7d0e9b3dc4df06cc33cb2b9fd79041a54827e"
integrity sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==

universalify@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==

universalify@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d"
Expand Down Expand Up @@ -10834,7 +10897,7 @@ which-typed-array@^1.1.16, which-typed-array@^1.1.18, which-typed-array@^1.1.2:
gopd "^1.2.0"
has-tostringtag "^1.0.2"

which@^1.1.1, which@^1.2.9:
which@^1.1.1, which@^1.2.10, which@^1.2.9:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
Expand Down

0 comments on commit 37e6f6d

Please sign in to comment.