import type { AnchorHTMLAttributes } from "react"; import { CITE_SCHEME } from "../../lib/citations/inline"; import type { CitationView } from "../../lib/report/views"; import { Markdown } from "../Markdown"; import { CitationsProvider } from "./CitationsContext"; import { InlineCite } from "./InlineCite"; // Report markdown with its citations live: every `[label](cite:)` link // (lib/citations/inline.ts) becomes an InlineCite for that id; every other // link renders as Markdown's own external link, except a `#` link to a // place on the same page, which stays in the tab. The house markdown setup // (Markdown.tsx — markdown-to-jsx, raw HTML escaped, token-styled) is // unchanged; this only swaps its link component. A `cite:` link inside code is // code, never a citation: markdown-to-jsx makes no link there. // // The views come from the page's one CitationsProvider (a page with many // markdown blocks serializes its citation map once). A block rendered on its // own may pass `citations`, and gets a provider of its own. const EXTERNAL_LINK_CLASS = "text-brand underline decoration-brand/40 hover:decoration-brand"; export function citeIdOf(href: string | undefined): string | null { return href?.startsWith(CITE_SCHEME) ? href.slice(CITE_SCHEME.length).trim() : null; } type Citations = Readonly>; // The `` of cited markdown: one stable component. function CiteLink({ href, children: label, ...rest }: AnchorHTMLAttributes) { const id = citeIdOf(href); if (id !== null) return {label}; if (href?.startsWith("#")) { return ( {label} ); } return ( {label} ); } export function CitedMarkdown({ children, citations, className, }: { children: string; citations?: Citations; className?: string; }) { const md = ( {children} ); return citations ? {md} : md; }