{"version":3,"sources":["../src/components/HtmlMathRenderer/HtmlMathRenderer.tsx","../src/components/MarkdownMathRenderer/MarkdownMathRenderer.tsx","../src/components/HtmlMathRenderer/utils.ts"],"sourcesContent":["import { CSSProperties, forwardRef, memo, ReactNode, Ref } from 'react';\nimport 'katex/dist/katex.min.css';\nimport { KatexMath } from './KatexMath';\nimport { cn } from '../../utils/utils';\nimport { normalizeLineBreaksInHtml } from '../../utils/htmlLineBreaks';\nimport MarkdownMathRenderer from '../MarkdownMathRenderer/MarkdownMathRenderer';\nimport {\n  isLikelyMarkdown,\n  processHtmlWithMath,\n  sanitizeHtmlForDisplay,\n} from './utils';\n\nexport interface HtmlMathRendererProps {\n  /** HTML content to render, may contain LaTeX math expressions */\n  content: string;\n  /** Additional CSS class names */\n  className?: string;\n  /** Inline styles */\n  style?: CSSProperties;\n  /** Whether to sanitize HTML before rendering (default: true) */\n  sanitize?: boolean;\n  /** Custom error renderer for math errors */\n  renderMathError?: (latex: string) => ReactNode;\n  /** Test ID for testing */\n  testId?: string;\n  /** Whether to render as inline element (span) instead of block (div). Use when inside labels or other phrasing content. */\n  inline?: boolean;\n}\n\n/**\n * HtmlMathRenderer - Renders HTML content with LaTeX math expressions\n *\n * Supports multiple LaTeX formats:\n * - Display mode: $$...$$ (centered block)\n * - Inline mode: $...$ (inline with text)\n * - LaTeX tags: <latex>...</latex>\n * - Editor spans: <span class=\"math-formula\" data-latex=\"...\">\n * - Legacy spans: <span class=\"math-expression\" data-math=\"...\">\n * - LaTeX environments: \\begin{...}...\\end{...}\n *\n * @example\n * ```tsx\n * <HtmlMathRenderer\n *   content=\"<p>A fórmula é: $$x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}$$</p>\"\n * />\n * ```\n */\nconst HtmlMathRenderer = forwardRef<HTMLElement, HtmlMathRendererProps>(\n  (\n    {\n      content,\n      className,\n      style,\n      sanitize = true,\n      renderMathError,\n      testId,\n      inline = false,\n    },\n    ref\n  ) => {\n    // AI-generated questions/resolutions arrive as Markdown + LaTeX. The HTML\n    // pipeline below would render their `**`/`####`/`*` tokens literally and\n    // collapse line breaks, so route that content to the Markdown renderer.\n    // Inline usage stays on the HTML path to keep phrasing-content validity\n    // (Markdown emits block elements: <p>, <ul>, <h4>, ...).\n    //\n    // Note: `renderMathError` is intentionally not forwarded here. The Markdown\n    // path renders math via rehype-katex, which already degrades gracefully on\n    // invalid LaTeX (KaTeX's built-in red error output) rather than throwing.\n    // `renderMathError` is an HTML-path-only customization and is currently\n    // unused by any consumer; honoring it on the Markdown path would require a\n    // bespoke rehype plugin for no practical gain.\n    if (!inline && content && isLikelyMarkdown(content)) {\n      return (\n        <MarkdownMathRenderer\n          ref={ref as Ref<HTMLDivElement>}\n          content={content}\n          className={className}\n          style={style}\n          testId={testId}\n        />\n      );\n    }\n\n    const defaultErrorRenderer = (latex: string) => (\n      <span className=\"text-error-600 text-sm\">Math Error: {latex}</span>\n    );\n\n    const errorRenderer = renderMathError || defaultErrorRenderer;\n\n    const renderContent = () => {\n      if (!content) return null;\n\n      // Question content is stored as plain text with `\\n` line breaks mixed\n      // with loose inline tags. Newlines are insignificant whitespace in HTML,\n      // so without this the whole thing renders as one collapsed run of text.\n      // Content that is already structured HTML passes through untouched.\n      //\n      // Breaks are always emitted as <br>, never <p>: the mixed text+math path\n      // below wraps each part in its own element, which would cut a paragraph\n      // in half across a math expression. <br> is inline and survives the split\n      // intact — and `[&_p]:mb-0` below means paragraphs carry no spacing here\n      // anyway, so there is nothing to gain from block elements.\n      const normalizedContent = normalizeLineBreaksInHtml(content, {\n        inline: true,\n      });\n\n      const processedContent = sanitize\n        ? sanitizeHtmlForDisplay(normalizedContent)\n        : normalizedContent;\n\n      const parts = processHtmlWithMath(processedContent);\n\n      // If all parts are text (or empty), render as plain HTML. Use the\n      // joined parts (not the raw `processedContent`) so post-split fixes\n      // applied inside `processHtmlWithMath` — like decoding `\\$` escapes\n      // to literal `$` — actually reach the rendered output.\n      if (parts.every((part) => part.type === 'text')) {\n        const joinedHtml = parts.map((part) => part.content).join('');\n        // Use span for inline mode to allow valid nesting in labels\n        const Element = inline ? 'span' : 'div';\n        return (\n          <Element\n            dangerouslySetInnerHTML={{\n              __html: joinedHtml || processedContent,\n            }}\n          />\n        );\n      }\n\n      // Generate stable keys based on content\n      const getPartKey = (part: (typeof parts)[0], idx: number) => {\n        const contentHash = (part.latex || part.content).slice(0, 20);\n        return `${part.type}-${idx}-${contentHash}`;\n      };\n\n      return (\n        <>\n          {parts.map((part, index) => {\n            const key = getPartKey(part, index);\n            if (part.type === 'math' && part.latex) {\n              return (\n                <KatexMath\n                  key={key}\n                  math={part.latex}\n                  renderError={() => errorRenderer(part.latex!)}\n                />\n              );\n            } else if (part.type === 'block-math' && part.latex) {\n              // When inline mode, render inline to avoid block-level elements inside span\n              if (inline) {\n                return (\n                  <KatexMath\n                    key={key}\n                    math={part.latex}\n                    renderError={() => errorRenderer(part.latex!)}\n                  />\n                );\n              }\n              return (\n                <div key={key} className=\"my-2.5 text-center\">\n                  <KatexMath\n                    math={part.latex}\n                    displayMode\n                    renderError={() => errorRenderer(part.latex!)}\n                  />\n                </div>\n              );\n            } else {\n              return (\n                <span\n                  key={key}\n                  dangerouslySetInnerHTML={{ __html: part.content }}\n                />\n              );\n            }\n          })}\n        </>\n      );\n    };\n\n    const sharedClassName = cn(\n      // Base styles\n      'leading-relaxed',\n      // Paragraph styles\n      '[&_p]:mb-0',\n      // Hide the KaTeX MathML accessibility layer visually (still readable\n      // to screen readers). Tailwind preflight overrides the KaTeX default\n      // `position: absolute; clip:...` rule, so the MathML layer ends up\n      // duplicating every formula as raw text next to the visual render.\n      '[&_.katex-mathml]:sr-only',\n      // Table styles (only relevant for block mode, but harmless for inline)\n      '[&_table]:border-collapse [&_table]:w-full [&_table]:my-2.5 [&_table]:table-auto',\n      '[&_table_td]:border [&_table_td]:border-border-200 [&_table_td]:p-2 [&_table_td]:min-w-[50px] [&_table_td]:align-top',\n      '[&_table_th]:border [&_table_th]:border-border-200 [&_table_th]:p-2 [&_table_th]:min-w-[50px] [&_table_th]:align-top [&_table_th]:bg-background-50 [&_table_th]:font-semibold',\n      '[&_table_tr:nth-child(even)]:bg-background-50/50',\n      '[&_table_tr:hover]:bg-background-100/50',\n      // Image styles\n      '[&_img]:max-w-full [&_img]:h-auto [&_img]:rounded-md [&_img]:my-2',\n      // Link styles\n      '[&_a]:text-primary-500 [&_a]:underline [&_a:hover]:text-primary-600',\n      // Text formatting styles\n      '[&_b]:font-bold [&_strong]:font-bold',\n      '[&_i]:italic [&_em]:italic',\n      '[&_u]:underline',\n      className\n    );\n\n    if (inline) {\n      return (\n        <span\n          ref={ref as Ref<HTMLSpanElement>}\n          className={sharedClassName}\n          style={style}\n          data-testid={testId}\n        >\n          {renderContent()}\n        </span>\n      );\n    }\n\n    return (\n      <div\n        ref={ref as Ref<HTMLDivElement>}\n        className={sharedClassName}\n        style={style}\n        data-testid={testId}\n      >\n        {renderContent()}\n      </div>\n    );\n  }\n);\n\nHtmlMathRenderer.displayName = 'HtmlMathRenderer';\n\nexport default memo(HtmlMathRenderer);\n","import { CSSProperties, forwardRef, memo } from 'react';\nimport 'katex/dist/katex.min.css';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport remarkMath from 'remark-math';\nimport rehypeKatex from 'rehype-katex';\nimport { cn } from '../../utils/utils';\nimport { looksLikeLatex } from '../HtmlMathRenderer/utils';\n\nexport interface MarkdownMathRendererProps {\n  /** Markdown content, may contain LaTeX math expressions ($...$ / $$...$$) */\n  content: string;\n  /** Additional CSS class names */\n  className?: string;\n  /** Inline styles */\n  style?: CSSProperties;\n  /** Test ID for testing */\n  testId?: string;\n}\n\n/**\n * Strips zero-width / invisible characters that occasionally leak into\n * AI-generated content and break KaTeX parsing.\n */\nconst stripInvisibleChars = (str: string): string =>\n  str.replaceAll(/[\\u200B-\\u200D\\uFEFF]/g, '');\n\n/**\n * Escapes the `$` of inline `$...$` spans that do NOT look like real math, so\n * `remark-math` leaves them as literal text. Without this, currency prose like\n * \"R$ 15,00 ... R$ 42,00\" gets paired up and rendered as gibberish math.\n *\n * Reuses the exact `looksLikeLatex` heuristic the HTML renderer applies to\n * single-`$` spans, so both renderers agree on what is math vs currency.\n * Display math (`$$...$$`) is intentionally left untouched (handled below).\n */\nexport const protectCurrencyInlineMath = (markdown: string): string =>\n  markdown.replaceAll(\n    /(?<!\\\\)\\$(?!\\$)([^\\n$]+?)(?<!\\\\)\\$(?!\\$)/g,\n    (match, inner: string) =>\n      looksLikeLatex(inner) ? match : match.replaceAll('$', String.raw`\\$`)\n  );\n\n/**\n * `remark-math` only renders a `$$...$$` block as centered display math when\n * the delimiters sit on their own lines (\"math flow\"). AI content usually puts\n * the whole equation on a single line (`$$x = y$$`), which would otherwise be\n * rendered inline. Reflow single-line `$$...$$` into block form so equations\n * stay centered, matching how the HTML renderer treats `$$`.\n */\nexport const reflowDisplayMath = (markdown: string): string =>\n  markdown.replaceAll(\n    /(?<!\\$)\\$\\$(?!\\$)([^\\n]+?)\\$\\$(?!\\$)/g,\n    (_match, inner: string) => `\\n\\n$$\\n${inner.trim()}\\n$$\\n\\n`\n  );\n\n/**\n * Runs `transform` over the markdown while shielding fenced code blocks and\n * inline code spans: each is stashed behind a placeholder, the transform runs\n * on the rest, then the originals are restored before the markdown reaches\n * react-markdown. Without this, the currency / display-math passes would\n * rewrite literal `$`/`$$` that authors put inside code samples (e.g. a fenced\n * block containing `price = $value`). The placeholder is purely transient (it\n * never reaches the markdown parser) and contains no `$`, so the passes ignore\n * it.\n */\nconst withProtectedCode = (\n  markdown: string,\n  transform: (input: string) => string\n): string => {\n  const stash: string[] = [];\n  const tokenized = markdown.replaceAll(\n    /```[\\s\\S]*?```|`[^`\\n]*`/g,\n    (segment) => {\n      const token = `__CODE_SEG_${stash.length}__`;\n      stash.push(segment);\n      return token;\n    }\n  );\n  return transform(tokenized).replaceAll(\n    /__CODE_SEG_(\\d+)__/g,\n    (_match, index: string) => stash[Number(index)]\n  );\n};\n\nconst preprocessMarkdown = (content: string): string =>\n  withProtectedCode(stripInvisibleChars(content), (safe) =>\n    reflowDisplayMath(protectCurrencyInlineMath(safe))\n  );\n\n/**\n * MarkdownMathRenderer - Renders Markdown content with embedded LaTeX math.\n *\n * Used for AI-generated questions and resolutions, which arrive as Markdown\n * (`**bold**`, `#### headings`, `* lists`, paragraphs) mixed with LaTeX\n * (`$...$` inline, `$$...$$` display). Built on `react-markdown` with\n * `remark-gfm` (tables/lists), `remark-math` + `rehype-katex` (math).\n *\n * SECURITY: raw HTML is intentionally NOT enabled (no `rehype-raw`). This\n * renderer only receives content classified as Markdown (no HTML tags) by\n * `isLikelyMarkdown`; HTML content keeps flowing through `HtmlMathRenderer`,\n * which sanitizes it. Adding raw-HTML support here would reintroduce an XSS\n * vector and requires a dedicated sanitization pipeline + security review.\n */\nconst MarkdownMathRenderer = forwardRef<\n  HTMLDivElement,\n  MarkdownMathRendererProps\n>(({ content, className, style, testId }, ref) => {\n  const sharedClassName = cn(\n    'leading-relaxed',\n    // Paragraph spacing\n    '[&_p]:my-2 [&_p:first-child]:mt-0 [&_p:last-child]:mb-0',\n    // Headings\n    '[&_h1]:text-xl [&_h1]:font-bold [&_h1]:mt-3 [&_h1]:mb-2',\n    '[&_h2]:text-lg [&_h2]:font-bold [&_h2]:mt-3 [&_h2]:mb-2',\n    '[&_h3]:text-base [&_h3]:font-semibold [&_h3]:mt-2.5 [&_h3]:mb-1.5',\n    '[&_h4]:text-base [&_h4]:font-semibold [&_h4]:mt-2.5 [&_h4]:mb-1.5',\n    '[&_h5]:font-semibold [&_h6]:font-semibold',\n    // Lists\n    '[&_ul]:list-disc [&_ul]:pl-5 [&_ul]:my-2',\n    '[&_ol]:list-decimal [&_ol]:pl-5 [&_ol]:my-2',\n    '[&_li]:my-1 [&_li>ul]:my-1 [&_li>ol]:my-1',\n    // Text formatting\n    '[&_b]:font-bold [&_strong]:font-bold',\n    '[&_i]:italic [&_em]:italic',\n    '[&_u]:underline',\n    '[&_blockquote]:border-l-4 [&_blockquote]:border-border-200 [&_blockquote]:pl-3 [&_blockquote]:text-text-700',\n    '[&_code]:rounded [&_code]:bg-background-100 [&_code]:px-1 [&_code]:py-0.5 [&_code]:text-sm',\n    // Hide the KaTeX MathML accessibility layer visually (still readable to\n    // screen readers). Tailwind preflight overrides KaTeX's default clip\n    // rule, so without this the MathML layer duplicates every formula as\n    // raw text next to the visual render.\n    '[&_.katex-mathml]:sr-only',\n    // Display math spacing\n    '[&_.katex-display]:my-2.5',\n    // Tables (GFM)\n    '[&_table]:border-collapse [&_table]:w-full [&_table]:my-2.5 [&_table]:table-auto',\n    '[&_table_td]:border [&_table_td]:border-border-200 [&_table_td]:p-2 [&_table_td]:min-w-[50px] [&_table_td]:align-top',\n    '[&_table_th]:border [&_table_th]:border-border-200 [&_table_th]:p-2 [&_table_th]:min-w-[50px] [&_table_th]:align-top [&_table_th]:bg-background-50 [&_table_th]:font-semibold',\n    // Images and links\n    '[&_img]:max-w-full [&_img]:h-auto [&_img]:rounded-md [&_img]:my-2',\n    '[&_a]:text-primary-500 [&_a]:underline [&_a:hover]:text-primary-600',\n    className\n  );\n\n  return (\n    <div\n      ref={ref}\n      className={sharedClassName}\n      style={style}\n      data-testid={testId}\n    >\n      <ReactMarkdown\n        remarkPlugins={[remarkGfm, remarkMath]}\n        rehypePlugins={[rehypeKatex]}\n      >\n        {preprocessMarkdown(content)}\n      </ReactMarkdown>\n    </div>\n  );\n});\n\nMarkdownMathRenderer.displayName = 'MarkdownMathRenderer';\n\nexport default memo(MarkdownMathRenderer);\n","/**\n * Utilities for processing HTML content with LaTeX math expressions\n */\n\nexport interface MathPart {\n  type: 'text' | 'math' | 'block-math';\n  content: string;\n  latex?: string;\n}\n\n/**\n * Generates a random ID for placeholder uniqueness\n * Uses crypto.randomUUID() (Web Crypto API - available in all modern browsers)\n */\nconst generateSecureRandomId = (): string => {\n  return crypto.randomUUID();\n};\n\n/**\n * Cleans LaTeX string from invisible characters and decodes HTML entities\n * that the editor saved in place of math operators.\n *\n * Why decode here: KaTeX is a LaTeX parser, not an HTML parser. If the\n * source has `&lt;`/`&gt;` (because the editor HTML-escaped them on save)\n * KaTeX throws \"Expected 'EOF', got '&'\". `&lt;`/`&gt;` map to the\n * equivalent `\\lt`/`\\gt` commands. `&amp;` decodes back to a bare `&` \\u2014\n * NOT `\\&` \\u2014 because in LaTeX `&` is the alignment character (used by\n * `\\begin{align}`, matrices, etc.); rewriting it to `\\&` would break\n * alignment and stop already-escaped `\\&` from round-tripping.\n */\nexport const cleanLatex = (str: string): string => {\n  return str\n    .replaceAll(/[\\u200B-\\u200D\\uFEFF]/g, '')\n    .replaceAll(/&amp;lt;|&lt;/gi, String.raw`\\lt `)\n    .replaceAll(/&amp;gt;|&gt;/gi, String.raw`\\gt `)\n    .replaceAll(/&amp;amp;|&amp;/gi, '&')\n    .trim();\n};\n\n/**\n * Heuristic that flags a string as \"likely real LaTeX math\" vs prose.\n * Used to reject `$...$` blocks that wrap regular text \\u2014 typically\n * happens when authors type `$` as a currency symbol and the renderer\n * pairs unrelated occurrences as math delimiters, sending Portuguese\n * prose to KaTeX (which then renders each letter as a math variable).\n *\n * Approach:\n * - Backslash commands / sub-super / grouping braces \\u2192 definitely math.\n * - Otherwise, treat it as PROSE only when it contains 2+ real words\n *   (runs of 3+ letters). A sentence like \"15,00 pelo custo fixo\" has\n *   many such words; genuine math \\u2014 `x = 1`, `a + b`, `1 < 2`, `f0`,\n *   even a lone `abc` \\u2014 does not. This keeps normal spaced equations\n *   rendering while still rejecting currency-`$` prose.\n */\nexport const looksLikeLatex = (str: string): boolean => {\n  if (/[\\\\^_{}]/.test(str)) return true;\n  const words = str.match(/[a-zA-Z]{3,}/g);\n  if (words && words.length >= 2) return false;\n  return true;\n};\n\n/**\n * HTML element names the backoffice RichEditor emits. Kept as a Set (instead\n * of a long regex alternation) so the tag-detection regex below stays simple\n * and cheap to reason about.\n */\nconst HTML_TAG_NAMES = new Set([\n  'p',\n  'div',\n  'span',\n  'br',\n  'b',\n  'strong',\n  'i',\n  'em',\n  'u',\n  's',\n  'ul',\n  'ol',\n  'li',\n  'h1',\n  'h2',\n  'h3',\n  'h4',\n  'h5',\n  'h6',\n  'a',\n  'img',\n  'table',\n  'thead',\n  'tbody',\n  'tfoot',\n  'tr',\n  'td',\n  'th',\n  'blockquote',\n  'pre',\n  'code',\n  'sub',\n  'sup',\n  'font',\n  'latex',\n]);\n\n/**\n * True when `content` contains a real HTML element tag (open or close) whose\n * name is one the editor produces. A single generic regex captures any\n * `<tag`/`</tag` candidate; membership is then checked against the Set, which\n * keeps the regex trivial and avoids a giant alternation.\n */\nconst containsHtmlTag = (content: string): boolean => {\n  for (const match of content.matchAll(/<\\/?([a-z][a-z0-9]*)/gi)) {\n    if (HTML_TAG_NAMES.has(match[1].toLowerCase())) return true;\n  }\n  return false;\n};\n\n/**\n * Heuristic that decides whether `content` is Markdown (as opposed to the\n * HTML the backoffice RichEditor produces). AI-generated questions and\n * resolutions arrive as Markdown + LaTeX (`**bold**`, `#### heading`,\n * `* lists`, `$...$`, `$$...$$`), whereas the editor stores HTML (`<p>`,\n * `<b>`, `<span class=\"math-formula\" data-latex=\"...\">`). The two sources are\n * cleanly separable, so we bias toward the proven HTML path:\n *\n * - If any real HTML element tag is present we return `false` and let\n *   `HtmlMathRenderer` handle it exactly as before (math-formula spans,\n *   currency heuristic, katex-error recovery, sanitization).\n * - Otherwise we return `true` only when an unmistakable Markdown marker is\n *   present (ATX heading, bold, bullet/ordered list, GFM table, or a paragraph\n *   break), which is what breaks today: Markdown rendered as HTML shows the raw\n *   `**`/`####`/`*` tokens and collapses line breaks.\n *\n * Regex note: line-anchored signals use the `m` flag with `^` and restrict\n * horizontal whitespace to `[ \\t]` (never `\\s`, which also matches `\\n`). This\n * keeps each quantifier on a single line and avoids the super-linear\n * backtracking that `(?:^|\\n)\\s*…\\s+` can trigger across newlines.\n */\nexport const isLikelyMarkdown = (content: string): boolean => {\n  if (!content) return false;\n\n  // Presence of real HTML element tags => treat as HTML (RichEditor output).\n  if (containsHtmlTag(content)) return false;\n\n  const MARKDOWN_SIGNALS = [\n    /^#{1,6}[ \\t]+\\S/m, // ATX heading (#, ##, ... ######)\n    /\\*\\*[^*\\n]+\\*\\*/, // bold\n    /__[^_\\n]+__/, // bold (underscore)\n    /^[ \\t]*[-*+][ \\t]+\\S/m, // bullet list\n    /^[ \\t]*\\d+\\.[ \\t]+\\S/m, // ordered list\n    /\\|[ \\t]*:?-+:?[ \\t]*\\|/, // GFM table delimiter row (|---|---|)\n    /\\n\\n/, // paragraph break (only reached when no HTML tag is present)\n  ];\n  return MARKDOWN_SIGNALS.some((pattern) => pattern.test(content));\n};\n\n/**\n * Recovers usable LaTeX source from `<span class=\"katex-error\">` wrappers\n * that previous editor cycles persisted into the database. The error's\n * `title` attribute carries the original LaTeX after \"at position N: \".\n * Replaces each wrapper with `$LATEX$` so downstream patterns can render\n * it cleanly via KaTeX.\n *\n * No-op outside browser contexts (no `document`).\n */\nconst recoverFromKatexErrorSpans = (htmlContent: string): string => {\n  if (\n    typeof document === 'undefined' ||\n    !/class=\"[^\"]*katex-error/i.test(htmlContent)\n  ) {\n    return htmlContent;\n  }\n\n  const tempContainer = document.createElement('div');\n  tempContainer.innerHTML = htmlContent;\n\n  const sanitizeRecoveredLatex = (raw: string): string =>\n    raw\n      // Strip combining marks KaTeX puts in error titles at the error pos\n      .replaceAll(/[\\u0300-\\u036F]/g, '')\n      // Drop truncated tag markers leftover from broken serialization.\n      // Done while literal `<`/`>` are still present (before they get\n      // mapped to LaTeX commands below).\n      .replaceAll(/<\\/?[a-zA-Z][a-zA-Z0-9]*\\s*>?$/g, '')\n      // Map comparison operators to equivalent LaTeX commands. We match\n      // both the entity forms AND the literal `<`/`>` characters: the\n      // `title` attribute is entity-decoded by the DOM when read, so we\n      // often get literal `<`/`>`. Mapping them to `\\lt`/`\\gt` also avoids\n      // re-encoding to `&lt;`/`&gt;` on DOM serialization (which would make\n      // `looksLikeLatex` reject the recovered block as non-math).\n      // `&amp;` decodes to a bare `&` (the LaTeX alignment character), not\n      // `\\&`, so `\\begin{align}` environments survive recovery.\n      .replaceAll(/&amp;lt;|&lt;|</gi, String.raw`\\lt `)\n      .replaceAll(/&amp;gt;|&gt;|>/gi, String.raw`\\gt `)\n      .replaceAll(/&amp;amp;|&amp;/gi, '&')\n      .trim();\n\n  Array.from(tempContainer.querySelectorAll('.katex-error')).forEach(\n    (errorNode) => {\n      if (!tempContainer.contains(errorNode)) return;\n\n      const title = errorNode.getAttribute('title') || '';\n      // Note: no `\\s*` before the capture group — `\\s*(.+)` would let\n      // whitespace be split ambiguously between the two, causing\n      // super-linear backtracking (ReDoS). The capture is trimmed by\n      // sanitizeRecoveredLatex below instead.\n      const positionMatch = /at position\\s+\\d+:(.+)$/.exec(title);\n      let recovered = positionMatch ? positionMatch[1] : '';\n\n      if (!recovered) {\n        // Fallback: collect from inner <annotation> elements, skipping the\n        // visual `katex-html` layer to avoid duplicating Unicode glyphs.\n        const parts: string[] = [];\n        const walk = (n: Node) => {\n          if (n.nodeType === Node.TEXT_NODE) {\n            parts.push(n.textContent || '');\n            return;\n          }\n          if (n.nodeType !== Node.ELEMENT_NODE) return;\n          const el = n as Element;\n          if (el.tagName.toLowerCase() === 'annotation') {\n            parts.push(el.textContent || '');\n            return;\n          }\n          if (el.classList.contains('katex-html')) return;\n          Array.from(el.childNodes).forEach(walk);\n        };\n        Array.from(errorNode.childNodes).forEach(walk);\n        recovered = parts.join(' ');\n      }\n\n      recovered = sanitizeRecoveredLatex(recovered);\n      if (recovered) {\n        errorNode.replaceWith(document.createTextNode(`$${recovered}$`));\n      } else {\n        errorNode.remove();\n      }\n    }\n  );\n\n  return tempContainer.innerHTML;\n};\n\n/**\n * Decodes `\\$` escape sequences to literal `$` characters. Applied only to\n * text fragments outside math blocks \\u2014 the `(?<!\\\\)` lookbehind in the\n * `$...$` matcher already skipped these, but the `\\` is still in the output\n * unless we decode it. Without this, currency strings like `R\\$ 130,00`\n * render with a visible backslash.\n */\nconst decodeDollarEscapes = (text: string): string =>\n  text.replaceAll(String.raw`\\$`, '$');\n\n/**\n * Dangerous attributes that should be removed for XSS protection\n */\nconst DANGEROUS_ATTRIBUTES = new Set([\n  'contenteditable',\n  'srcdoc',\n  'formaction',\n  'xlink:href',\n]);\n\n/**\n * Dangerous URI schemes that should be removed from href/src attributes\n */\nconst DANGEROUS_URI_PATTERN = /^\\s*(javascript|vbscript|data):/i;\n\n/**\n * Sanitizes HTML content for safe display\n * Removes event handlers, dangerous attributes, script/style tags, and javascript: URIs\n */\nexport const sanitizeHtmlForDisplay = (htmlContent: string): string => {\n  if (!htmlContent) return htmlContent;\n\n  // Create a temporary div to parse HTML\n  if (typeof document === 'undefined') {\n    // Server-side: use regex-based sanitization as fallback\n    let sanitized = htmlContent;\n    // Remove script tags\n    sanitized = sanitized.replaceAll(\n      /<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi,\n      ''\n    );\n    // Remove style tags\n    sanitized = sanitized.replaceAll(\n      /<style\\b[^<]*(?:(?!<\\/style>)<[^<]*)*<\\/style>/gi,\n      ''\n    );\n    // Remove on* event handlers (split into separate patterns to avoid ReDoS)\n    sanitized = sanitized.replaceAll(/ on[a-z]+=\"[^\"]*\"/gi, '');\n    sanitized = sanitized.replaceAll(/ on[a-z]+='[^']*'/gi, '');\n    sanitized = sanitized.replaceAll(/ on[a-z]+=[^\\s>\"']+/gi, '');\n    // Remove dangerous URI schemes (javascript, vbscript, data) - matching client-side DANGEROUS_URI_PATTERN\n    sanitized = sanitized.replaceAll(\n      / href=\"(?:javascript|vbscript|data):[^\"]*\"/gi,\n      ''\n    );\n    sanitized = sanitized.replaceAll(\n      / href='(?:javascript|vbscript|data):[^']*'/gi,\n      ''\n    );\n    sanitized = sanitized.replaceAll(\n      / src=\"(?:javascript|vbscript|data):[^\"]*\"/gi,\n      ''\n    );\n    sanitized = sanitized.replaceAll(\n      / src='(?:javascript|vbscript|data):[^']*'/gi,\n      ''\n    );\n    sanitized = sanitized.replaceAll(\n      / action=\"(?:javascript|vbscript|data):[^\"]*\"/gi,\n      ''\n    );\n    sanitized = sanitized.replaceAll(\n      / action='(?:javascript|vbscript|data):[^']*'/gi,\n      ''\n    );\n    return sanitized;\n  }\n\n  const tempDiv = document.createElement('div');\n  tempDiv.innerHTML = htmlContent;\n\n  // Remove script and style tags entirely\n  const dangerousTags = tempDiv.querySelectorAll(\n    'script, style, iframe, object, embed'\n  );\n  dangerousTags.forEach((element) => element.remove());\n\n  // Process all elements\n  const allElements = tempDiv.querySelectorAll('*');\n  allElements.forEach((element) => {\n    // Get all attribute names\n    const attributeNames = element.getAttributeNames();\n\n    attributeNames.forEach((attrName) => {\n      const lowerAttrName = attrName.toLowerCase();\n\n      // Remove all on* event handler attributes (onclick, onerror, onload, etc.)\n      if (lowerAttrName.startsWith('on')) {\n        element.removeAttribute(attrName);\n        return;\n      }\n\n      // Remove dangerous attributes\n      if (DANGEROUS_ATTRIBUTES.has(lowerAttrName)) {\n        element.removeAttribute(attrName);\n        return;\n      }\n\n      // Check href, src, and action for dangerous URIs\n      if (\n        lowerAttrName === 'href' ||\n        lowerAttrName === 'src' ||\n        lowerAttrName === 'action'\n      ) {\n        const value = element.getAttribute(attrName);\n        if (value && DANGEROUS_URI_PATTERN.test(value)) {\n          element.removeAttribute(attrName);\n        }\n      }\n    });\n  });\n\n  return tempDiv.innerHTML;\n};\n\n/**\n * Processes HTML content and extracts math expressions\n * Returns an array of parts (text and math) for rendering\n */\nexport const processHtmlWithMath = (htmlContent: string): MathPart[] => {\n  if (!htmlContent) return [];\n\n  // Pre-pass: recover original LaTeX from any `katex-error` wrappers that\n  // older editor saves left in the content. This turns persisted error HTML\n  // into clean `$LATEX$` strings so the steps below can render them.\n  let processedContent = recoverFromKatexErrorSpans(htmlContent);\n  const parts: MathPart[] = [];\n\n  // Generate unique sentinel per call to avoid collision with content\n  const sentinel = `__MATH_${generateSecureRandomId()}_`;\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 placeholder = `${sentinel}${parts.length}__`;\n      parts.push({\n        type: isDisplayMode ? 'block-math' : 'math',\n        content: match,\n        latex: cleanLatex(latex),\n      });\n      return placeholder;\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 placeholder = `${sentinel}${parts.length}__`;\n      parts.push({\n        type: 'math',\n        content: match,\n        latex: cleanLatex(latex),\n      });\n      return placeholder;\n    }\n  );\n\n  // Step 3: Handle raw $$...$$ expressions (display mode) - BEFORE single $\n  const doubleDollarPattern = /(?<!\\\\)\\$\\$([\\s\\S]+?)\\$\\$/g;\n  processedContent = processedContent.replaceAll(\n    doubleDollarPattern,\n    (match, latex) => {\n      const placeholder = `${sentinel}${parts.length}__`;\n      parts.push({\n        type: 'block-math',\n        content: match,\n        latex: cleanLatex(latex),\n      });\n      return placeholder;\n    }\n  );\n\n  // Step 4: Handle single $...$ expressions for inline math.\n  // Skip matches whose content doesn't look like LaTeX — those are usually\n  // currency `$` symbols pairing up across prose (e.g. `R$ 15,00 ... R$ 42,00`)\n  // and sending Portuguese text to KaTeX produces gibberish output.\n  const singleDollarPattern = /(?<!\\\\)\\$([\\s\\S]+?)\\$/g;\n  processedContent = processedContent.replaceAll(\n    singleDollarPattern,\n    (match, latex) => {\n      if (!looksLikeLatex(latex)) return match;\n      const placeholder = `${sentinel}${parts.length}__`;\n      parts.push({\n        type: 'math',\n        content: match,\n        latex: cleanLatex(latex),\n      });\n      return placeholder;\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 placeholder = `${sentinel}${parts.length}__`;\n      parts.push({\n        type: 'math',\n        content: match,\n        latex: cleanLatex(latex),\n      });\n      return placeholder;\n    }\n  );\n\n  // Step 6: Handle standalone LaTeX environments (align, equation, pmatrix, etc.)\n  const latexEnvPattern = /\\\\begin\\{([^}]+)\\}([\\s\\S]*?)\\\\end\\{\\1\\}/g;\n  processedContent = processedContent.replaceAll(latexEnvPattern, (match) => {\n    const placeholder = `${sentinel}${parts.length}__`;\n    parts.push({\n      type: 'block-math',\n      content: match,\n      latex: cleanLatex(match),\n    });\n    return placeholder;\n  });\n\n  // Step 7: Split remaining content by placeholders\n  const finalParts: MathPart[] = [];\n  let currentIndex = 0;\n  // Escape sentinel for regex (though it should be safe alphanumeric)\n  const escapedSentinel = sentinel.replaceAll(\n    /[.*+?^${}()|[\\]\\\\]/g,\n    String.raw`\\$&`\n  );\n  const placeholderPattern = new RegExp(\n    String.raw`${escapedSentinel}(\\d+)__`,\n    'g'\n  );\n  let match;\n\n  while ((match = placeholderPattern.exec(processedContent)) !== null) {\n    // Add text before math\n    if (match.index > currentIndex) {\n      finalParts.push({\n        type: 'text',\n        content: decodeDollarEscapes(\n          processedContent.slice(currentIndex, match.index)\n        ),\n      });\n    }\n\n    // Add math expression\n    const mathIndex = Number.parseInt(match[1], 10);\n    if (parts[mathIndex]) {\n      finalParts.push(parts[mathIndex]);\n    }\n\n    currentIndex = match.index + match[0].length;\n  }\n\n  // Add remaining text\n  if (currentIndex < processedContent.length) {\n    finalParts.push({\n      type: 'text',\n      content: decodeDollarEscapes(processedContent.slice(currentIndex)),\n    });\n  }\n\n  return finalParts;\n};\n\n/**\n * Checks if content contains any math expressions\n */\nexport const containsMath = (content: string): boolean => {\n  if (!content) return false;\n\n  // Check for various math patterns\n  const patterns = [\n    /\\$\\$[\\s\\S]+?\\$\\$/, // Display mode $$...$$\n    /(?<!\\\\)\\$[\\s\\S]+?\\$/, // Inline mode $...$\n    /<span[^>]*class=\"math-formula\"/, // Editor spans\n    /<span[^>]*class=\"math-expression\"/, // Legacy spans\n    /<latex>|&lt;latex&gt;/, // LaTeX tags\n    /\\\\begin\\{[^}]+\\}/, // LaTeX environments\n  ];\n\n  return patterns.some((pattern) => pattern.test(content));\n};\n\n/**\n * Extracts plain text from HTML content (removes all tags and LaTeX notation)\n */\nexport const stripHtml = (htmlContent: string): string => {\n  if (!htmlContent) return '';\n\n  let content = htmlContent;\n\n  // Remove math-formula spans (keep nothing as the LaTeX is in data attribute)\n  content = content.replaceAll(\n    /<span[^>]*class=\"math-formula\"[^>]*>[\\s\\S]*?<\\/span>/g,\n    ''\n  );\n\n  // Remove math-expression spans (legacy)\n  content = content.replaceAll(\n    /<span[^>]*class=\"math-expression\"[^>]*>[\\s\\S]*?<\\/span>/g,\n    ''\n  );\n\n  // Remove $$...$$ block math\n  content = content.replaceAll(/\\$\\$[\\s\\S]+?\\$\\$/g, '');\n\n  // Remove $...$ inline math\n  content = content.replaceAll(/\\$[^$]+\\$/g, '');\n\n  // Remove <latex>...</latex> tags\n  content = content.replaceAll(\n    /(?:<latex>|&lt;latex&gt;)[\\s\\S]*?(?:<\\/latex>|&lt;\\/latex&gt;)/g,\n    ''\n  );\n\n  // Remove LaTeX environments like \\begin{...}...\\end{...}\n  // Using non-greedy match without backreference to avoid ReDoS vulnerability\n  content = content.replaceAll(\n    /\\\\begin\\{[a-zA-Z*]+\\}[\\s\\S]*?\\\\end\\{[a-zA-Z*]+\\}/g,\n    ''\n  );\n\n  // Remove HTML tags\n  if (typeof document === 'undefined') {\n    // Server-side: use regex (excluding both < and > prevents quadratic backtracking)\n    return content.replaceAll(/<[^<>]*>/g, '').trim();\n  }\n\n  const tempDiv = document.createElement('div');\n  tempDiv.innerHTML = content;\n  return (tempDiv.textContent || tempDiv.innerText || '').trim();\n};\n"],"mappings":"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","names":["forwardRef","memo","match","jsx","forwardRef","memo"]}