feat: code blocks with shiki highlighting
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
import { memo, useEffect, useState } from "react";
|
||||
import type { ExcalidrawProps } from "@excalidraw/excalidraw/types";
|
||||
import type {
|
||||
ExcalidrawEmbeddableElement,
|
||||
NonDeleted,
|
||||
} from "@excalidraw/excalidraw/element/types";
|
||||
import { getCodeBlockCustomData, isCodeBlockEmbeddable } from "../codeblock";
|
||||
import { renderHighlightedCodeBlockHtml } from "../codeblockHighlight";
|
||||
|
||||
type CodeBlockEmbeddableProps = {
|
||||
element: NonDeleted<ExcalidrawEmbeddableElement>;
|
||||
};
|
||||
|
||||
const CodeBlockEmbeddable = memo(function CodeBlockEmbeddable({
|
||||
element,
|
||||
}: CodeBlockEmbeddableProps) {
|
||||
const customData = getCodeBlockCustomData(element);
|
||||
const [html, setHtml] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!customData) {
|
||||
setHtml(null);
|
||||
return;
|
||||
}
|
||||
|
||||
let cancelled = false;
|
||||
void renderHighlightedCodeBlockHtml(customData.code, customData.language)
|
||||
.then((nextHtml) => {
|
||||
if (!cancelled) {
|
||||
setHtml(nextHtml);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
if (!cancelled) {
|
||||
setHtml(null);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [customData]);
|
||||
|
||||
if (!customData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={[
|
||||
"codeblock-embeddable",
|
||||
customData.showBackground
|
||||
? "codeblock-surface--background"
|
||||
: "codeblock-surface--transparent",
|
||||
].join(" ")}
|
||||
>
|
||||
{html ? (
|
||||
<div
|
||||
className="codeblock-embeddable-html"
|
||||
dangerouslySetInnerHTML={{ __html: html }}
|
||||
/>
|
||||
) : (
|
||||
<pre className="codeblock-embeddable-fallback">
|
||||
<code>{customData.code}</code>
|
||||
</pre>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export const renderCodeBlockEmbeddable: NonNullable<
|
||||
ExcalidrawProps["renderEmbeddable"]
|
||||
> = (element) => {
|
||||
if (!isCodeBlockEmbeddable(element)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <CodeBlockEmbeddable element={element} />;
|
||||
};
|
||||
Reference in New Issue
Block a user