1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
/**
* AsciiDocView renders an AsciiDoc document to HTML with Asciidoctor,
* lazy-loading the (heavy) converter on first use.
*
* The converted HTML comes from files in the user's own workspace, rendered
* for the user who owns them — the same trust model as opening the file in
* any editor's preview.
*
* @example
* <AsciiDocView content="= Title" />
*/
import { useEffect, useState } from "react";
export function AsciiDocView({ content }: { content: string }) {
const [html, setHtml] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
let cancelled = false;
// @asciidoctor/core v4 exposes an async convert() as a named export
// (the v3 synchronous asciidoctor() factory is gone).
import("@asciidoctor/core")
.then(({ convert }) =>
convert(content, {
safe: "safe",
attributes: { showtitle: true, icons: "font" },
}),
)
.then((converted) => {
if (!cancelled) {
setHtml(String(converted));
}
})
.catch((cause: Error) => {
if (!cancelled) {
setError(`AsciiDoc rendering failed: ${cause.message}`);
}
});
return () => {
cancelled = true;
};
}, [content]);
if (error) {
return <p className="pane-error">{error}</p>;
}
if (html === null) {
return <p className="pane-empty">rendering…</p>;
}
return (
<div
className="markdown asciidoc"
// biome-ignore lint/security/noDangerouslySetInnerHtml: Asciidoctor's output over the user's own workspace files, converted in safe mode — the accepted pattern for a local document preview.
dangerouslySetInnerHTML={{ __html: html }}
/>
);
}
|