/**
* T074: Markdown rendering configuration and wikilink handling
*/
import React from 'react';
import type { Components } from 'react-markdown';
export interface WikilinkComponentProps {
linkText: string;
resolved: boolean;
onClick?: (linkText: string) => void;
}
/**
* Custom renderer for wikilinks in markdown
*/
export function createWikilinkComponent(
onWikilinkClick?: (linkText: string) => void
): Components {
return {
// Override the text renderer to handle wikilinks
text: ({ children }: any) => {
const value = String(children || '');
const parts: React.ReactNode[] = [];
const pattern = /\[\[([^\]]+)\]\]/g;
let lastIndex = 0;
let match;
let key = 0;
while ((match = pattern.exec(value)) !== null) {
// Add text before the wikilink
if (match.index > lastIndex) {
parts.push(value.slice(lastIndex, match.index));
}
// Add the wikilink as a clickable element
const linkText = match[1];
parts.push(
{
e.preventDefault();
onWikilinkClick?.(linkText);
}}
role="link"
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
onWikilinkClick?.(linkText);
}
}}
>
[[{linkText}]]
);
lastIndex = pattern.lastIndex;
}
// Add remaining text
if (lastIndex < value.length) {
parts.push(value.slice(lastIndex));
}
return parts.length > 0 ? <>{parts}> : value;
},
// Style code blocks
code: ({ className, children, ...props }) => {
const match = /language-(\w+)/.exec(className || '');
const isInline = !match;
if (isInline) {
return (
{children}
);
}
return (
{children}
);
},
// Style links
a: ({ href, children, ...props }) => {
const isExternal = href?.startsWith('http');
return (
{children}
);
},
// Style headings
h1: ({ children, ...props }) => (
{children}), // Style tables table: ({ children, ...props }) => (