UNPKG

analytica-frontend-lib

Version:

Repositório público dos componentes utilizados nas plataformas da Analytica Ensino

1 lines 11.2 kB
{"version":3,"sources":["../src/components/LatexRenderer/LatexRenderer.tsx"],"sourcesContent":["import { CSSProperties, ReactNode } from 'react';\nimport 'katex/dist/katex.min.css';\nimport { KatexMath } from '../HtmlMathRenderer/KatexMath';\nimport DOMPurify from 'dompurify';\nimport parse, {\n DOMNode,\n Element,\n HTMLReactParserOptions,\n} from 'html-react-parser';\nimport { cn } from '../../utils/utils';\n\n/**\n * Props for the LatexRenderer component\n */\nexport interface LatexRendererProps {\n /** HTML content containing LaTeX expressions to render */\n content: string;\n /** Additional CSS classes to apply */\n className?: string;\n /** Inline styles to apply */\n style?: CSSProperties;\n /** Custom error renderer for invalid LaTeX expressions */\n onError?: (latex: string) => ReactNode;\n}\n\n/**\n * Helper function to sanitize HTML content to prevent XSS attacks\n */\nconst sanitizeHtml = (value: string): string => {\n return DOMPurify.sanitize(value, {\n ADD_ATTR: ['data-latex', 'data-display-mode', 'data-math', 'data-math-id'],\n });\n};\n\n/**\n * Helper function to decode HTML entities\n * Converts entities like &amp;, &lt;, &gt; back to their actual characters\n */\nconst decodeHtmlEntities = (str: string): string => {\n const textarea = document.createElement('textarea');\n textarea.innerHTML = str;\n return textarea.value;\n};\n\n/**\n * Helper function to clean latex from invisible characters\n */\nconst cleanLatex = (str: string): string => {\n // Remove zero-width characters, invisible characters, and other problematic Unicode\n return str.replaceAll(/[\\u200B-\\u200D\\uFEFF]/g, '').trim();\n};\n\n/**\n * Type for math parts used in rendering\n */\ninterface MathPart {\n id: number;\n type: 'inline' | 'block';\n latex: string;\n}\n\n/**\n * Creates a replace function for html-react-parser that replaces math placeholders\n * with KaTeX components\n */\nconst createMathReplacer = (\n mathParts: MathPart[],\n errorRenderer: (latex: string) => ReactNode\n) => {\n return (domNode: DOMNode) => {\n if (\n domNode instanceof Element &&\n domNode.name === 'span' &&\n domNode.attribs['data-math-id']\n ) {\n const mathId = Number.parseInt(domNode.attribs['data-math-id'], 10);\n const mathPart = mathParts[mathId];\n\n if (!mathPart) return domNode;\n\n if (mathPart.type === 'inline') {\n return (\n <KatexMath\n key={`math-${mathId}`}\n math={mathPart.latex}\n renderError={() => errorRenderer(mathPart.latex)}\n />\n );\n } else {\n return (\n <div key={`math-${mathId}`} className=\"my-2.5 text-center\">\n <KatexMath\n math={mathPart.latex}\n displayMode\n renderError={() => errorRenderer(mathPart.latex)}\n />\n </div>\n );\n }\n }\n return domNode;\n };\n};\n\n/**\n * LatexRenderer component for Analytica Ensino platforms\n *\n * Renders HTML content with embedded LaTeX/KaTeX mathematical expressions.\n * Supports multiple LaTeX formats:\n * - Inline math: `$...$` or `<latex>...</latex>`\n * - Block math: `$$...$$`\n * - LaTeX environments: `\\begin{equation}...\\end{equation}`, etc.\n * - Editor format: `<span class=\"math-formula\" data-latex=\"...\">...</span>`\n *\n * @param content - HTML content with LaTeX expressions\n * @param className - Additional CSS classes\n * @param style - Inline styles\n * @param onError - Custom error renderer\n * @returns Rendered content with mathematical expressions\n *\n * @example\n * ```tsx\n * <LatexRenderer content=\"The formula is $E = mc^2$\" />\n *\n * <LatexRenderer\n * content=\"Block equation: $$\\sum_{i=1}^{n} x_i$$\"\n * className=\"my-custom-class\"\n * />\n *\n * <LatexRenderer\n * content=\"<p>Matrix: \\begin{pmatrix} a & b \\\\ c & d \\end{pmatrix}</p>\"\n * onError={(latex) => <span>Invalid: {latex}</span>}\n * />\n * ```\n */\nconst LatexRenderer = ({\n content,\n className,\n style,\n onError,\n}: LatexRendererProps) => {\n const renderContentWithMath = (htmlContent: string) => {\n if (!htmlContent) return null;\n\n let processedContent = htmlContent;\n const mathParts: MathPart[] = [];\n\n // Step 1: Handle math-formula spans (from the editor)\n const mathFormulaPattern =\n /<span[^>]*class=\"math-formula\"[^>]*data-latex=\"([^\"]*)\"[^>]*>[\\s\\S]*?<\\/span>/g;\n processedContent = processedContent.replaceAll(\n mathFormulaPattern,\n (match, latex) => {\n const isDisplayMode = match.includes('data-display-mode=\"true\"');\n const id = mathParts.length;\n mathParts.push({\n id,\n type: isDisplayMode ? 'block' : 'inline',\n latex: cleanLatex(decodeHtmlEntities(latex)),\n });\n return `<span data-math-id=\"${id}\"></span>`;\n }\n );\n\n // Step 2: Handle wrapped math expressions (from math modal - legacy)\n const wrappedMathPattern =\n /<span[^>]*class=\"math-expression\"[^>]*data-math=\"([^\"]*)\"[^>]*>.*?<\\/span>/g;\n processedContent = processedContent.replaceAll(\n wrappedMathPattern,\n (match, latex) => {\n const id = mathParts.length;\n mathParts.push({\n id,\n type: 'inline',\n latex: cleanLatex(decodeHtmlEntities(latex)),\n });\n return `<span data-math-id=\"${id}\"></span>`;\n }\n );\n\n // Step 3: Handle raw $$...$$ expressions (manual input or saved content) - BEFORE single $\n const doubleDollarPattern = /(?<!\\\\)\\$\\$([\\s\\S]+?)\\$\\$/g;\n processedContent = processedContent.replaceAll(\n doubleDollarPattern,\n (match, latex) => {\n const id = mathParts.length;\n mathParts.push({\n id,\n type: 'block',\n latex: cleanLatex(latex),\n });\n return `<span data-math-id=\"${id}\"></span>`;\n }\n );\n\n // Step 4: Handle single $...$ expressions for inline math\n const singleDollarPattern = /(?<!\\\\)\\$([\\s\\S]+?)\\$/g;\n processedContent = processedContent.replaceAll(\n singleDollarPattern,\n (match, latex) => {\n const id = mathParts.length;\n mathParts.push({\n id,\n type: 'inline',\n latex: cleanLatex(latex),\n });\n return `<span data-math-id=\"${id}\"></span>`;\n }\n );\n\n // Step 5: Handle <latex>...</latex> tags for inline math\n const latexTagPattern =\n /(?:<latex>|&lt;latex&gt;)([\\s\\S]*?)(?:<\\/latex>|&lt;\\/latex&gt;)/g;\n processedContent = processedContent.replaceAll(\n latexTagPattern,\n (match, latex) => {\n const id = mathParts.length;\n mathParts.push({\n id,\n type: 'inline',\n latex: cleanLatex(latex),\n });\n return `<span data-math-id=\"${id}\"></span>`;\n }\n );\n\n // Step 6: Handle standalone LaTeX environments (align, equation, pmatrix, etc.) for block math\n const latexEnvPattern = /\\\\begin\\{([^}]+)\\}([\\s\\S]*?)\\\\end\\{\\1\\}/g;\n processedContent = processedContent.replaceAll(latexEnvPattern, (match) => {\n const id = mathParts.length;\n mathParts.push({\n id,\n type: 'block',\n latex: cleanLatex(match),\n });\n return `<span data-math-id=\"${id}\"></span>`;\n });\n\n // Sanitize the HTML with placeholders\n const sanitizedContent = sanitizeHtml(processedContent);\n\n // Default error renderer\n const defaultErrorRenderer = (latex: string) => (\n <span className=\"text-red-600\">Math Error: {latex}</span>\n );\n\n const errorRenderer = onError || defaultErrorRenderer;\n\n // Parse HTML and replace math placeholders with React components\n const options: HTMLReactParserOptions = {\n replace: createMathReplacer(mathParts, errorRenderer),\n };\n\n return <>{parse(sanitizedContent, options)}</>;\n };\n\n return (\n <div\n className={cn('whitespace-pre-wrap leading-relaxed', className)}\n style={style}\n >\n {renderContentWithMath(content)}\n </div>\n );\n};\n\nexport default LatexRenderer;\n"],"mappings":"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","names":[]}