diff --git a/frontend/src/components/shared/markdown.tsx b/frontend/src/components/shared/markdown.tsx index a3d32b6..8d37a41 100644 --- a/frontend/src/components/shared/markdown.tsx +++ b/frontend/src/components/shared/markdown.tsx @@ -147,8 +147,8 @@ const Markdown = ({ children, className, searchValue }: MarkdownProps) => { ); // Optimized helper function to process text nodes recursively - const processTextNode = useCallback( - (nodeChildren: any): any => { + const processTextNode = useMemo(() => { + const fn = (nodeChildren: any): any => { if (!processedSearch) { return nodeChildren; } @@ -163,15 +163,13 @@ const Markdown = ({ children, className, searchValue }: MarkdownProps) => { return createHighlightedText(child); } - // Avoid deep cloning React elements to prevent memory leaks - // Only process if it's a simple object with props if (child && typeof child === 'object' && child.props && child.props.children !== undefined) { return { ...child, key: child.key || `processed-${index}`, props: { ...child.props, - children: processTextNode(child.props.children), + children: fn(child.props.children), }, }; } @@ -180,7 +178,6 @@ const Markdown = ({ children, className, searchValue }: MarkdownProps) => { }); } - // Handle React elements safely if ( nodeChildren && typeof nodeChildren === 'object' && @@ -191,25 +188,31 @@ const Markdown = ({ children, className, searchValue }: MarkdownProps) => { ...nodeChildren, props: { ...nodeChildren.props, - children: processTextNode(nodeChildren.props.children), + children: fn(nodeChildren.props.children), }, }; } return nodeChildren; - }, - [processedSearch, createHighlightedText], - ); + }; + + return fn; + }, [processedSearch, createHighlightedText]); // Create a simple component renderer factory to avoid recreating functions const createComponentRenderer = useCallback( (ComponentName: string) => { - return ({ children: nodeChildren, ...props }: any) => { + const Component = ComponentName as React.ElementType; + + const Renderer = ({ children: nodeChildren, ...props }: Record) => { const processedChildren = processTextNode(nodeChildren); - const Component = ComponentName as any; return {processedChildren}; }; + + Renderer.displayName = `Highlighted(${ComponentName})`; + + return Renderer; }, [processTextNode], ); diff --git a/frontend/src/components/shared/monaco-terminal.tsx b/frontend/src/components/shared/monaco-terminal.tsx index 52b5e09..43c0a3f 100644 --- a/frontend/src/components/shared/monaco-terminal.tsx +++ b/frontend/src/components/shared/monaco-terminal.tsx @@ -67,7 +67,11 @@ const injectedColorClasses = new Set(); const rgbStringToHex = (rgb: string): string => rgb .split(',') - .map((part) => Math.min(255, Math.max(0, parseInt(part.trim(), 10))).toString(16).padStart(2, '0')) + .map((part) => + Math.min(255, Math.max(0, parseInt(part.trim(), 10))) + .toString(16) + .padStart(2, '0'), + ) .join(''); /** diff --git a/frontend/src/components/shared/terminal/use-xterm.ts b/frontend/src/components/shared/terminal/use-xterm.ts index 5153a97..0ebd1f2 100644 --- a/frontend/src/components/shared/terminal/use-xterm.ts +++ b/frontend/src/components/shared/terminal/use-xterm.ts @@ -102,10 +102,7 @@ export function useXterm({ theme }: { theme: 'dark' | 'light' | 'system' }): Use const openLink = (event: MouseEvent, uri: string) => { const uriLower = uri.toLowerCase(); - if ( - (mac ? event.metaKey : event.ctrlKey) && - SAFE_PROTOCOLS.some((p) => uriLower.startsWith(p)) - ) { + if ((mac ? event.metaKey : event.ctrlKey) && SAFE_PROTOCOLS.some((p) => uriLower.startsWith(p))) { window.open(uri, '_blank', 'noopener,noreferrer'); } }; diff --git a/frontend/src/components/ui/input-group.tsx b/frontend/src/components/ui/input-group.tsx index 31d91d2..6b4a104 100644 --- a/frontend/src/components/ui/input-group.tsx +++ b/frontend/src/components/ui/input-group.tsx @@ -121,7 +121,7 @@ function InputGroupText({ className, ...props }: React.ComponentProps<'span'>) { ); } -function InputGroupTextarea({ className, ...props }: React.ComponentProps<'textarea'>) { +function InputGroupTextarea({ className, ...props }: React.ComponentProps) { return (