import { useEffect, useRef, useState } from "react"; declare global { interface Window { MathJax?: { startup?: { promise?: Promise }; typesetPromise?: (elements?: Element[]) => Promise; [key: string]: any; }; } } interface MediaFile { id: number; fileName: string; mediaUrl: string; } interface LaTextContainerProps { html: string; latex: string; mediaFiles?: MediaFile[]; } let mathJaxPromise: Promise | null = null; const loadMathJax = () => { if (mathJaxPromise) return mathJaxPromise; mathJaxPromise = new Promise((resolve, reject) => { if (window.MathJax?.typesetPromise) { resolve(); return; } (window as any).MathJax = { tex: { inlineMath: [["$$$", "$$$"]], displayMath: [["$$$$$$", "$$$$$$"]], processEscapes: true, }, options: { skipHtmlTags: ["script", "noscript", "style", "textarea", "pre", "code"], }, startup: { typeset: false }, }; const script = document.createElement("script"); script.id = "mathjax-script"; script.src = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"; script.async = true; script.onload = () => { window.MathJax?.startup?.promise?.then(resolve).catch(reject); }; script.onerror = reject; document.head.appendChild(script); }); return mathJaxPromise; }; const replaceImages = (html: string, latex: string, mediaFiles?: MediaFile[]) => { const parser = new DOMParser(); const doc = parser.parseFromString(html, "text/html"); const latexImageNames = Array.from(latex.matchAll(/\\includegraphics\{(.+?)\}/g)).map( (match) => match[1] ); const imgs = doc.querySelectorAll("img.tex-graphics"); imgs.forEach((img, idx) => { const imageName = latexImageNames[idx]; if (!imageName || !mediaFiles) return; const mediaFile = mediaFiles.find((f) => f.fileName === imageName); if (mediaFile) img.src = mediaFile.mediaUrl; }); return doc.body.innerHTML; }; const LaTextContainer: React.FC = ({ html, latex, mediaFiles }) => { const containerRef = useRef(null); const [processedHtml, setProcessedHtml] = useState(html); // 1️⃣ Обновляем HTML при изменении входных данных useEffect(() => { setProcessedHtml(replaceImages(html, latex, mediaFiles)); }, [html, latex, mediaFiles]); // 2️⃣ После рендера обновленного HTML применяем MathJax useEffect(() => { const renderMath = () => { if (containerRef.current && window.MathJax?.typesetPromise) { window.MathJax.typesetPromise([containerRef.current]).catch(console.error); } }; loadMathJax().then(renderMath).catch(console.error); }, [processedHtml]); // 👈 ключевой момент — триггерим именно по processedHtml return (
); }; export default LaTextContainer;