From 647f4d47ff46406830d8f96a355755fecd6cf65a Mon Sep 17 00:00:00 2001 From: binzam Date: Fri, 16 Oct 2026 20:49:22 +0300 Subject: [PATCH] Render markdown tables in PromptMarkdown Add remark-gfm so GFM tables render as real tables, style table elements to match the card, keep wide tables readable inside a horizontal scroll container, and drop the linkifyBareUrls regex now that remark-gfm autolinks natively. --- components/prompt-markdown.tsx | 154 +++++++++++++++++++++------------ package.json | 1 + 2 files changed, 100 insertions(+), 55 deletions(-) diff --git a/components/prompt-markdown.tsx b/components/prompt-markdown.tsx index 12a096e..462f516 100644 --- a/components/prompt-markdown.tsx +++ b/components/prompt-markdown.tsx @@ -1,64 +1,108 @@ -import ReactMarkdown from "react-markdown"; +import ReactMarkdown, { type Components } from "react-markdown"; +import remarkGfm from "remark-gfm"; -/** Turn bare http(s) URLs into markdown links for display only. */ -function linkifyBareUrls(text: string): string { - return text.replace(/(?)]+)/g, (url) => `[${url}](${url})`); -} +/** + * Hoisted to module scope so the plugin list and component map keep a stable + * identity between renders (no re-creation on every render). + */ +const REMARK_PLUGINS = [remarkGfm]; + +const MARKDOWN_COMPONENTS: Components = { + h1: ({ children }) => ( +

{children}

+ ), + h2: ({ children }) => ( +

{children}

+ ), + h3: ({ children }) => ( +

{children}

+ ), + p: ({ children }) =>

{children}

, + ul: ({ children }) => ( + + ), + ol: ({ children }) => ( +
    {children}
+ ), + li: ({ children }) =>
  • {children}
  • , + strong: ({ children }) => ( + {children} + ), + em: ({ children }) => {children}, + code: ({ children }) => ( + + {children} + + ), + // Reset the inline-code chip styling for nested in a block
    .
    +  pre: ({ children }) => (
    +    
    +      {children}
    +    
    + ), + hr: () =>
    , + blockquote: ({ children }) => ( +
    + {children} +
    + ), + a: ({ href, children }) => ( + + {children} + + ), + + // GFM tables: the wrapper scrolls horizontally. The table sizes to its + // content (w-max) but never shrinks below the card (min-w-full), and cells + // have a min/max width so columns stay readable instead of being squeezed. + table: ({ children }) => ( +
    + + {children} +
    +
    + ), + thead: ({ children }) => ( + + {children} + + ), + tbody: ({ children }) => {children}, + tr: ({ children }) => ( + + {children} + + ), + th: ({ children, style }) => ( + + {children} + + ), + td: ({ children, style }) => ( + + {children} + + ), +}; export function PromptMarkdown({ children }: { children: string }) { return ( ( -

    {c}

    - ), - h2: ({ children: c }) => ( -

    {c}

    - ), - h3: ({ children: c }) => ( -

    {c}

    - ), - p: ({ children: c }) =>

    {c}

    , - ul: ({ children: c }) => ( -
      {c}
    - ), - ol: ({ children: c }) => ( -
      {c}
    - ), - li: ({ children: c }) =>
  • {c}
  • , - strong: ({ children: c }) => ( - {c} - ), - em: ({ children: c }) => {c}, - code: ({ children: c }) => ( - - {c} - - ), - pre: ({ children: c }) => ( -
    -            {c}
    -          
    - ), - hr: () =>
    , - blockquote: ({ children: c }) => ( -
    - {c} -
    - ), - a: ({ href, children: c }) => ( - - {c} - - ), - }} + remarkPlugins={REMARK_PLUGINS} + components={MARKDOWN_COMPONENTS} > - {linkifyBareUrls(children)} + {children}
    ); } diff --git a/package.json b/package.json index cce43b4..82e31de 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "react": "19.2.4", "react-dom": "19.2.4", "react-markdown": "^10.1.0", + "remark-gfm": "^4.0.1", "stripe": "^17.7.0", "undici": "^8.1.0", "zod": "^4.4.3"