"use client";
import * as React from "react";
import ReactMarkdown, { type Components } from "react-markdown";
import remarkGfm from "remark-gfm";
import remarkMath from "remark-math";
import rehypeKatex from "rehype-katex";
import "katex/dist/katex.min.css";
import { CodeBlock } from "./code-block";
import { normalizeMath, splitStreamingMarkdown } from "@/lib/chat/markdown-blocks";
import { cn } from "@/lib/utils";
/**
* Chat Markdown renderer.
*
* - GFM (tables, task lists, strikethrough) + LaTeX (`$…$`, `$$…$$`, and the `\(…\)` / `\[…\]` forms
* models emit, normalised in `lib/chat/markdown-blocks`). Raw HTML is skipped (never injected).
* - Streaming: the text is split into completed top-level blocks that are rendered once and memoised;
* only the trailing block re-parses on each token, so long answers stay cheap and tables/code do not flicker.
*/
const components = (wrap: boolean): Components => ({
code({ className, children, ...props }) {
const match = /language-(\w[\w+#-]*)/.exec(className ?? "");
const text = String(children ?? "").replace(/\n$/, "");
const isBlock = Boolean(match) || text.includes("\n");
if (isBlock) return
{children}
);
},
pre({ children }) {
return <>{children}>;
},
a({ href, children }) {
return (
{children}
);
},
table({ children }) {
return (