import React from "react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
interface MarkdownBlockProps {
content: string;
}
import { Components } from "react-markdown";
const SafeLink: Components["a"] = ({ href, children, ...rest }) => {
const rawHref = typeof href === "string" ? href.trim() : "";
const normalized = rawHref.toLowerCase();
const isAllowed =
normalized.startsWith("https://") || normalized.startsWith("mailto:");
if (!isAllowed) {
return {children};
}
return (
{children}
);
};
const SanitizedImage: Components["img"] = ({ alt }) => {
if (typeof alt === "string" && alt.trim().length > 0) {
return {alt};
}
return null;
};
// Minimal remark plugin to convert raw HTML
nodes to mdast hard breaks.
// This preserves line breaks inside table cells without enabling arbitrary HTML.
function remarkHtmlBrToBreak() {
return (tree: any) => {
const walk = (node: any) => {
if (!node) return;
if (node.type === 'html' && typeof node.value === 'string') {
const raw = node.value.trim().toLowerCase();
if (/^
$/.test(raw)) {
node.type = 'break';
delete node.value;
} else {
// Render other raw HTML as plain text to avoid showing tags as elements
node.type = 'text';
// keep original text
}
}
if (Array.isArray(node.children)) {
for (const child of node.children) walk(child);
}
};
walk(tree);
};
}
const MarkdownBlock: React.FC = React.memo(({ content }) => {
const markdown = content || '';
return (
{markdown}
);
});
export default MarkdownBlock;