import React, { memo, useMemo, useRef, useEffect, lazy, Suspense } from 'react'; import { useRecoilValue } from 'recoil'; import { PermissionTypes, Permissions } from 'librechat-data-provider'; import { useToastContext, useCodeBlockContext } from '~/Providers'; import CodeBlock from '~/components/Messages/Content/CodeBlock'; import useHasAccess from '~/hooks/Roles/useHasAccess'; import { useFileDownload } from '~/data-provider'; import useLocalize from '~/hooks/useLocalize'; import { handleDoubleClick } from '~/utils'; import store from '~/store'; // Loading fallback component for lazy-loaded Mermaid diagrams const MermaidLoadingFallback = memo(() => { const localize = useLocalize(); return (
{localize('com_ui_loading_diagram')}
); }); type TCodeProps = { inline?: boolean; className?: string; children: React.ReactNode; }; export const code: React.ElementType = memo(({ className, children }: TCodeProps) => { const canRunCode = useHasAccess({ permissionType: PermissionTypes.RUN_CODE, permission: Permissions.USE, }); const match = /language-(\w+)/.exec(className ?? ''); const lang = match && match[1]; const isMath = lang === 'math'; const isMermaid = lang === 'mermaid'; const isSingleLine = typeof children === 'string' && children.split('\n').length === 1; const { getNextIndex, resetCounter } = useCodeBlockContext(); const blockIndex = useRef(getNextIndex(isMath || isSingleLine)).current; useEffect(() => { resetCounter(); }, [children, resetCounter]); if (isMath) { return <>{children}; } else if (isMermaid && typeof children === 'string') { const SandpackMermaidDiagram = lazy(() => import('./SandpackMermaidDiagram')); return ( }> ); } else if (isSingleLine) { return ( {children} ); } else { return ( ); } }); export const codeNoExecution: React.ElementType = memo(({ className, children }: TCodeProps) => { const match = /language-(\w+)/.exec(className ?? ''); const lang = match && match[1]; const isMermaid = lang === 'mermaid'; if (lang === 'math') { return children; } else if (isMermaid && typeof children === 'string') { const SandpackMermaidDiagram = lazy(() => import('./SandpackMermaidDiagram')); return ( }> ); } else if (typeof children === 'string' && children.split('\n').length === 1) { return ( {children} ); } else { return ; } }); type TAnchorProps = { href: string; children: React.ReactNode; }; export const a: React.ElementType = memo(({ href, children }: TAnchorProps) => { const user = useRecoilValue(store.user); const { showToast } = useToastContext(); const localize = useLocalize(); const { file_id = '', filename = '', filepath, } = useMemo(() => { const pattern = new RegExp(`(?:files|outputs)/${user?.id}/([^\\s]+)`); const match = href.match(pattern); if (match && match[0]) { const path = match[0]; const parts = path.split('/'); const name = parts.pop(); const file_id = parts.pop(); return { file_id, filename: name, filepath: path }; } return { file_id: '', filename: '', filepath: '' }; }, [user?.id, href]); const { refetch: downloadFile } = useFileDownload(user?.id ?? '', file_id); const props: { target?: string; onClick?: React.MouseEventHandler } = { target: '_new' }; if (!file_id || !filename) { return ( {children} ); } const handleDownload = async (event: React.MouseEvent) => { event.preventDefault(); try { const stream = await downloadFile(); if (stream.data == null || stream.data === '') { console.error('Error downloading file: No data found'); showToast({ status: 'error', message: localize('com_ui_download_error'), }); return; } const link = document.createElement('a'); link.href = stream.data; link.setAttribute('download', filename); document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(stream.data); } catch (error) { console.error('Error downloading file:', error); } }; props.onClick = handleDownload; props.target = '_blank'; return ( {children} ); }); type TParagraphProps = { children: React.ReactNode; }; export const p: React.ElementType = memo(({ children }: TParagraphProps) => { return

{children}

; });