"use client"; import * as React from "react"; import { cn } from "./lib/utils"; export interface MarkdownEditorProps extends React.HTMLAttributes { value?: string; defaultValue?: string; onValueChange?: (value: string) => void; } /** Markdown write and preview tabs: basic renderer (headings, lists, code, links, bold). */ function renderMarkdown(src: string): React.ReactNode { const lines = src.split("\n"); const out: React.ReactNode[] = []; let listItems: string[] = []; let inCode = false; let codeLines: string[] = []; const flushList = () => { if (listItems.length) { out.push( ); listItems = []; } }; const inline = (text: string): React.ReactNode => { const parts = text.split(/(\*\*[^*]+\*\*|`[^`]+`|\[[^\]]+\]\([^)]+\))/g); return parts.map((part, i) => { if (part.startsWith("**") && part.endsWith("**")) return {part.slice(2, -2)}; if (part.startsWith("`") && part.endsWith("`")) return {part.slice(1, -1)}; const link = part.match(/\[([^\]]+)\]\(([^)]+)\)/); if (link) return {link[1]}; return part; }); }; for (const line of lines) { if (line.trim().startsWith("```")) { if (inCode) { out.push(
            {codeLines.join("\n")}
          
); codeLines = []; inCode = false; } else { inCode = true; flushList(); } continue; } if (inCode) { codeLines.push(line); continue; } const heading = line.match(/^(#{1,4})\s+(.*)/); if (heading) { flushList(); const level = heading[1].length; const sizes = ["text-xl font-bold", "text-lg font-bold", "text-base font-semibold", "text-sm font-semibold"]; out.push(

{inline(heading[2])}

); continue; } if (/^[-*]\s+/.test(line)) { listItems.push(line.replace(/^[-*]\s+/, "")); continue; } flushList(); if (line.trim() === "") { out.push(
); continue; } out.push(

{inline(line)}

); } flushList(); return out; } /** Markdown write and preview tabs component. */ export function MarkdownEditor({ value, defaultValue = "# Heading\n\n**bold** and `code`.\n\n- item 1\n- item 2", onValueChange, className, ...props }: MarkdownEditorProps) { const [internal, setInternal] = React.useState(defaultValue); const [tab, setTab] = React.useState<"write" | "preview">("write"); const src = value ?? internal; return (
{(["write", "preview"] as const).map((t) => ( ))}
{tab === "write" ? (