fix(app): markdown rendering with morphdom for better dom functions (#10373)

This commit is contained in:
Rahul A Mistry
2026-01-25 05:59:58 +05:30
committed by GitHub
parent 8d1a66d043
commit 399fec770f
3 changed files with 53 additions and 6 deletions

View File

@@ -1,6 +1,7 @@
import { useMarked } from "../context/marked"
import { useI18n } from "../context/i18n"
import DOMPurify from "dompurify"
import morphdom from "morphdom"
import { checksum } from "@opencode-ai/util/encode"
import { ComponentProps, createEffect, createResource, createSignal, onCleanup, splitProps } from "solid-js"
import { isServer } from "solid-js/web"
@@ -194,18 +195,61 @@ export function Markdown(
{ initialValue: "" },
)
let copySetupTimer: ReturnType<typeof setTimeout> | undefined
let copyCleanup: (() => void) | undefined
createEffect(() => {
const container = root()
const content = html()
if (!container) return
if (!content) return
if (isServer) return
const cleanup = setupCodeCopy(container, {
copy: i18n.t("ui.message.copy"),
copied: i18n.t("ui.message.copied"),
if (!content) {
container.innerHTML = ""
return
}
const temp = document.createElement("div")
temp.innerHTML = content
morphdom(container, temp, {
childrenOnly: true,
onBeforeElUpdated: (fromEl, toEl) => {
if (fromEl.isEqualNode(toEl)) return false
if (fromEl.getAttribute("data-component") === "markdown-code") {
const fromPre = fromEl.querySelector("pre")
const toPre = toEl.querySelector("pre")
if (fromPre && toPre && !fromPre.isEqualNode(toPre)) {
morphdom(fromPre, toPre)
}
return false
}
return true
},
onBeforeNodeDiscarded: (node) => {
if (node instanceof Element) {
if (node.getAttribute("data-slot") === "markdown-copy-button") return false
if (node.getAttribute("data-component") === "markdown-code") return false
}
return true
},
})
onCleanup(cleanup)
if (copySetupTimer) clearTimeout(copySetupTimer)
copySetupTimer = setTimeout(() => {
if (copyCleanup) copyCleanup()
copyCleanup = setupCodeCopy(container, {
copy: i18n.t("ui.message.copy"),
copied: i18n.t("ui.message.copied"),
})
}, 150)
})
onCleanup(() => {
if (copySetupTimer) clearTimeout(copySetupTimer)
if (copyCleanup) copyCleanup()
})
return (
<div
data-component="markdown"
@@ -213,7 +257,6 @@ export function Markdown(
...(local.classList ?? {}),
[local.class ?? ""]: !!local.class,
}}
innerHTML={html.latest}
ref={setRoot}
{...others}
/>