import React from 'react'; import { CopyButton } from '@renderer/components/common/CopyButton'; import { PROSE_BODY } from '@renderer/constants/cssVariables'; import { extractTextFromReactNode } from './markdownCopyUtils'; import { highlightSearchInChildren, type SearchContext } from './searchHighlightUtils'; import { FileLink, isRelativeUrl } from './viewers/FileLink'; import type { Components } from 'react-markdown'; interface MarkdownComponentOptions { copyCodeBlocks?: boolean; } /** * Create inline markdown components for rendering prose content. * When searchCtx is provided, search term highlighting is applied * to text nodes while preserving full markdown rendering. */ export function createMarkdownComponents( searchCtx: SearchContext | null, options: MarkdownComponentOptions = {} ): Components { const { copyCodeBlocks = false } = options; const hl = (children: React.ReactNode): React.ReactNode => searchCtx ? highlightSearchInChildren(children, searchCtx) : children; return { // Headings - Bold text with generous spacing to break up content h1: ({ children }) => (
{hl(children)}
), // Links — inline element, no hl(); parent block element's hl() descends here a: ({ href, children }) => { if (href && isRelativeUrl(href)) { return
{hl(children)}
);
}
// Inline code — no hl(); parent block element's hl() descends here
return (
{children}
);
},
// Code blocks
pre: ({ children }) => {
const codeText = copyCodeBlocks ? extractTextFromReactNode(children).trim() : '';
return (
{codeText ? : null}
{children}
);
},
// Blockquotes
blockquote: ({ children }) => (
{hl(children)}), // Lists ul: ({ children }) => (