fix(ui): support cmd-click links in inline code (#12552)
This commit is contained in:
@@ -209,3 +209,8 @@
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-component="markdown"] a.external-link:hover > code {
|
||||||
|
text-decoration: underline;
|
||||||
|
text-underline-offset: 2px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -49,6 +49,19 @@ type CopyLabels = {
|
|||||||
copied: string
|
copied: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const urlPattern = /^https?:\/\/[^\s<>()`"']+$/
|
||||||
|
|
||||||
|
function codeUrl(text: string) {
|
||||||
|
const href = text.trim().replace(/[),.;!?]+$/, "")
|
||||||
|
if (!urlPattern.test(href)) return
|
||||||
|
try {
|
||||||
|
const url = new URL(href)
|
||||||
|
return url.toString()
|
||||||
|
} catch {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function createIcon(path: string, slot: string) {
|
function createIcon(path: string, slot: string) {
|
||||||
const icon = document.createElement("div")
|
const icon = document.createElement("div")
|
||||||
icon.setAttribute("data-component", "icon")
|
icon.setAttribute("data-component", "icon")
|
||||||
@@ -110,9 +123,39 @@ function setupCodeCopy(root: HTMLDivElement, labels: CopyLabels) {
|
|||||||
wrapper.appendChild(createCopyButton(labels))
|
wrapper.appendChild(createCopyButton(labels))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const markCodeLinks = () => {
|
||||||
|
const codeNodes = Array.from(root.querySelectorAll(":not(pre) > code"))
|
||||||
|
for (const code of codeNodes) {
|
||||||
|
const href = codeUrl(code.textContent ?? "")
|
||||||
|
const parentLink =
|
||||||
|
code.parentElement instanceof HTMLAnchorElement && code.parentElement.classList.contains("external-link")
|
||||||
|
? code.parentElement
|
||||||
|
: null
|
||||||
|
|
||||||
|
if (!href) {
|
||||||
|
if (parentLink) parentLink.replaceWith(code)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentLink) {
|
||||||
|
parentLink.href = href
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const link = document.createElement("a")
|
||||||
|
link.href = href
|
||||||
|
link.className = "external-link"
|
||||||
|
link.target = "_blank"
|
||||||
|
link.rel = "noopener noreferrer"
|
||||||
|
code.parentNode?.replaceChild(link, code)
|
||||||
|
link.appendChild(code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleClick = async (event: MouseEvent) => {
|
const handleClick = async (event: MouseEvent) => {
|
||||||
const target = event.target
|
const target = event.target
|
||||||
if (!(target instanceof Element)) return
|
if (!(target instanceof Element)) return
|
||||||
|
|
||||||
const button = target.closest('[data-slot="markdown-copy-button"]')
|
const button = target.closest('[data-slot="markdown-copy-button"]')
|
||||||
if (!(button instanceof HTMLButtonElement)) return
|
if (!(button instanceof HTMLButtonElement)) return
|
||||||
const code = button.closest('[data-component="markdown-code"]')?.querySelector("code")
|
const code = button.closest('[data-component="markdown-code"]')?.querySelector("code")
|
||||||
@@ -132,6 +175,7 @@ function setupCodeCopy(root: HTMLDivElement, labels: CopyLabels) {
|
|||||||
for (const block of blocks) {
|
for (const block of blocks) {
|
||||||
ensureWrapper(block)
|
ensureWrapper(block)
|
||||||
}
|
}
|
||||||
|
markCodeLinks()
|
||||||
|
|
||||||
const buttons = Array.from(root.querySelectorAll('[data-slot="markdown-copy-button"]'))
|
const buttons = Array.from(root.querySelectorAll('[data-slot="markdown-copy-button"]'))
|
||||||
for (const button of buttons) {
|
for (const button of buttons) {
|
||||||
|
|||||||
Reference in New Issue
Block a user