(undefined);
const [copied, setCopied] = useState(false);
const handleCopy = useCallback(() => {
if (!navigator.clipboard) return;
const text = preRef.current?.textContent ?? "";
navigator.clipboard
.writeText(text)
.then(() => {
setCopied(true);
window.clearTimeout(resetTimerRef.current);
resetTimerRef.current = window.setTimeout(() => setCopied(false), 1500);
})
.catch(() => {});
}, []);
return (
);
}
const components: Components = {
a({ node: _node, children, href, className, ...props }) {
const external = isExternalMarkdownUrl(href);
const childText =
typeof children === "string"
? children
: Array.isArray(children) && children.length === 1 && typeof children[0] === "string"
? children[0]
: undefined;
const citationNum = parseCitationBadgeLabel(childText, href);
if (citationNum) {
const domain = citationDomainLabel(href);
return (
{citationNum}
);
}
const linkClass = external
? className
? `${className} rk-chat-markdown-external-link`
: "rk-chat-markdown-external-link"
: className;
return (
{children}
{external ? : null}
);
},
code({ node: _node, className, children, ...props }) {
const rawText = typeof children === "string" ? children : undefined;
const hex = !className ? parseHexColorToken(rawText) : undefined;
if (hex) {
return {children};
}
return (
{children}
);
},
img({ node: _node, ...props }) {
return
;
},
pre({ node: _node, ...props }) {
return ;
},
};
export const ChatMarkdown = memo(function ChatMarkdown({
children,
streaming = false,
}: ChatMarkdownProps) {
const source = streaming ? closeUnterminatedFence(children) : children;
return (
sanitizeMarkdownUrl(url, true) ?? ""}
>
{source}
{streaming ? : null}
);
});
export type { ChatMarkdownProps } from "./markdown";