"use client"; /** * Renders a message body from its entity spans. * * Nothing here parses markup — the server already turned the composer's * markers into clean text plus spans, so a message cannot inject markup into * anyone else's thread. This component only decorates ranges. */ import { buildEntityTree, type EntityNode } from "@/lib/chat-format"; import type { MessageEntity } from "@/lib/chat"; function renderNodes(nodes: EntityNode[], keyPrefix: string): React.ReactNode[] { return nodes.map((node, i) => { const key = `${keyPrefix}-${i}`; if (node.kind === "text") return {node.text}; const children = renderNodes(node.children, key); switch (node.entity.type) { case "bold": return {children}; case "strike": return {children}; case "code": return ( {children} ); case "url": return ( {children} ); default: return {children}; } }); } export function MessageText({ body, entities, }: { body: string; entities: MessageEntity[]; }) { // whitespace-pre-wrap keeps the sender's line breaks without turning the // body into markup. return ( {renderNodes(buildEntityTree(body, entities), "e")} ); }