From 6895b0c207a59152b0f73f6892d8f4b69d315387 Mon Sep 17 00:00:00 2001 From: 1shCha Date: Wed, 28 Jan 2026 22:51:36 -0500 Subject: [PATCH 1/3] better math rendering within quiz answers --- src/components/workspace-canvas/QuizContent.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/workspace-canvas/QuizContent.tsx b/src/components/workspace-canvas/QuizContent.tsx index 1b90353d..eac06995 100644 --- a/src/components/workspace-canvas/QuizContent.tsx +++ b/src/components/workspace-canvas/QuizContent.tsx @@ -299,7 +299,11 @@ export function QuizContent({ item, onUpdateData, isScrollLocked = false }: Quiz )}> {String.fromCharCode(65 + index)} - {option} + + + {option} + + {showCorrectness && isCorrect && } {showCorrectness && isSelected && !isCorrect && } From 6c591270738d5514edfba238013548aab45ce8ba Mon Sep 17 00:00:00 2001 From: 1shCha Date: Wed, 28 Jan 2026 23:21:40 -0500 Subject: [PATCH 2/3] general latex fixes --- src/components/assistant-ui/markdown-text.tsx | 18 +++++++++++++++--- .../assistant-ui/standalone-markdown.tsx | 9 +++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/components/assistant-ui/markdown-text.tsx b/src/components/assistant-ui/markdown-text.tsx index 385e5604..fbd726d4 100644 --- a/src/components/assistant-ui/markdown-text.tsx +++ b/src/components/assistant-ui/markdown-text.tsx @@ -149,7 +149,19 @@ function normalizeCustomMathTags(input: string): string { .replace(/\\{1,2}\(([\s\S]*?)\\{1,2}\)/g, (_, content) => `$$${content.trim()}$$`) // Convert \[ ... \] to $$...$$ (block math) - streamdown needs newlines for block triggers .replace( - /\\{1,2}\[([\s\S]*?)\\{1,2}\]/g, - (_, content) => `$$\n${content.trim()}\n$$` - )); + /\\{1,2}\[([\s\S]*?)\\{1,2}\]/g, + (_, content) => `$$\n${content.trim()}\n$$` + ) + // Convert single $ ... $ to $$...$$ (inline math), but avoid currency like $10 or $5.50 + // We use (^|[^\$]) to ensure it's not preceded by match (ignoring $$) + // and (?!\$) to ensure it's not followed by $ (ignoring $$) + .replace(/(^|[^\$])\$([^\$\n]+?)\$(?!\$)/g, (match, prefix, content) => { + // If content is purely numeric (with optional commas/periods), treat as currency + if (/^[\d,\.]+$/.test(content.trim())) { + return match; // Keep as-is (currency) + } + // Otherwise, convert to math. + // prefix is the character before the first $ (or empty string) + return `${prefix}$$${content.trim()}$$`; + })); } \ No newline at end of file diff --git a/src/components/assistant-ui/standalone-markdown.tsx b/src/components/assistant-ui/standalone-markdown.tsx index b97d2a7d..96890f95 100644 --- a/src/components/assistant-ui/standalone-markdown.tsx +++ b/src/components/assistant-ui/standalone-markdown.tsx @@ -67,6 +67,15 @@ function normalizeCustomMathTags(input: string): string { .replace(/\\{1,2}\(([\s\S]*?)\\{1,2}\)/g, (_, content) => `$$${content.trim()}$$`) // Convert \[ ... \] to $$...$$ (LaTeX block math) .replace(/\\{1,2}\[([\s\S]*?)\\{1,2}\]/g, (_, content) => `$$${content.trim()}$$`) + // Convert single $ ... $ to $$...$$ (inline math), but avoid currency like $10 or $5.50 + .replace(/(^|[^\$])\$([^\$\n]+?)\$(?!\$)/g, (match, prefix, content) => { + // If content is purely numeric (with optional commas/periods), treat as currency + if (/^[\d,\.]+$/.test(content.trim())) { + return match; // Keep as-is (currency) + } + // Otherwise, convert to math + return `${prefix}$$${content.trim()}$$`; + }) ); } From 047d18f2270d977f7bae74973fed20ec92c331e1 Mon Sep 17 00:00:00 2001 From: Urjit Chakraborty <135136842+urjitc@users.noreply.github.com> Date: Thu, 29 Jan 2026 03:14:34 -0500 Subject: [PATCH 3/3] Fix regex patterns and HTML nesting issues in LaTeX math support - Fix regex to handle consecutive math expressions using lookbehind/lookahead - Improve currency validation pattern to reject invalid formats - Prevent escaped dollar signs from being converted to math - Preserve single dollar signs for ReactMarkdown (remark-math compatibility) - Fix invalid HTML nesting by changing span to div for ReactMarkdown output Addresses PR review feedback on math rendering and currency detection --- src/components/assistant-ui/markdown-text.tsx | 15 +++++++-------- .../assistant-ui/standalone-markdown.tsx | 19 ++++++------------- .../workspace-canvas/QuizContent.tsx | 4 ++-- 3 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/components/assistant-ui/markdown-text.tsx b/src/components/assistant-ui/markdown-text.tsx index fbd726d4..50aa7992 100644 --- a/src/components/assistant-ui/markdown-text.tsx +++ b/src/components/assistant-ui/markdown-text.tsx @@ -153,15 +153,14 @@ function normalizeCustomMathTags(input: string): string { (_, content) => `$$\n${content.trim()}\n$$` ) // Convert single $ ... $ to $$...$$ (inline math), but avoid currency like $10 or $5.50 - // We use (^|[^\$]) to ensure it's not preceded by match (ignoring $$) - // and (?!\$) to ensure it's not followed by $ (ignoring $$) - .replace(/(^|[^\$])\$([^\$\n]+?)\$(?!\$)/g, (match, prefix, content) => { - // If content is purely numeric (with optional commas/periods), treat as currency - if (/^[\d,\.]+$/.test(content.trim())) { + // Use lookbehind to avoid consuming characters and handle consecutive expressions + // Exclude escaped dollar signs (prefixed with \) + .replace(/(? { + // More precise currency pattern: matches numbers like 10, 1,000, 10.50, 1,000.50 + if (/^\d{1,3}(?:,\d{3})*(?:\.\d{1,2})?$/.test(content.trim())) { return match; // Keep as-is (currency) } - // Otherwise, convert to math. - // prefix is the character before the first $ (or empty string) - return `${prefix}$$${content.trim()}$$`; + // Otherwise, convert to math + return `$$${content.trim()}$$`; })); } \ No newline at end of file diff --git a/src/components/assistant-ui/standalone-markdown.tsx b/src/components/assistant-ui/standalone-markdown.tsx index 96890f95..d4619035 100644 --- a/src/components/assistant-ui/standalone-markdown.tsx +++ b/src/components/assistant-ui/standalone-markdown.tsx @@ -61,21 +61,14 @@ function normalizeCustomMathTags(input: string): string { input // Convert [/math]...[/math] to $$...$$ (legacy block math format) .replace(/\[\/math\]([\s\S]*?)\[\/math\]/g, (_, content) => `$$${content.trim()}$$`) - // Convert [/inline]...[/inline] to $$...$$ (legacy inline format - Streamdown uses $$ for all) - .replace(/\[\/inline\]([\s\S]*?)\[\/inline\]/g, (_, content) => `$$${content.trim()}$$`) - // Convert \( ... \) to $$...$$ (LaTeX inline math - Streamdown uses $$ for all) - .replace(/\\{1,2}\(([\s\S]*?)\\{1,2}\)/g, (_, content) => `$$${content.trim()}$$`) + // Convert [/inline]...[/inline] to $...$ (legacy inline format - ReactMarkdown uses $ for inline) + .replace(/\[\/inline\]([\s\S]*?)\[\/inline\]/g, (_, content) => `$${content.trim()}$`) + // Convert \( ... \) to $...$ (LaTeX inline math - ReactMarkdown uses $ for inline) + .replace(/\\{1,2}\(([\s\S]*?)\\{1,2}\)/g, (_, content) => `$${content.trim()}$`) // Convert \[ ... \] to $$...$$ (LaTeX block math) .replace(/\\{1,2}\[([\s\S]*?)\\{1,2}\]/g, (_, content) => `$$${content.trim()}$$`) - // Convert single $ ... $ to $$...$$ (inline math), but avoid currency like $10 or $5.50 - .replace(/(^|[^\$])\$([^\$\n]+?)\$(?!\$)/g, (match, prefix, content) => { - // If content is purely numeric (with optional commas/periods), treat as currency - if (/^[\d,\.]+$/.test(content.trim())) { - return match; // Keep as-is (currency) - } - // Otherwise, convert to math - return `${prefix}$$${content.trim()}$$`; - }) + // Note: We DON'T convert $...$ to $$ here because ReactMarkdown with remark-math expects + // single dollar signs for inline math and double dollar signs for block math ); } diff --git a/src/components/workspace-canvas/QuizContent.tsx b/src/components/workspace-canvas/QuizContent.tsx index eac06995..78b46a33 100644 --- a/src/components/workspace-canvas/QuizContent.tsx +++ b/src/components/workspace-canvas/QuizContent.tsx @@ -299,11 +299,11 @@ export function QuizContent({ item, onUpdateData, isScrollLocked = false }: Quiz )}> {String.fromCharCode(65 + index)} - +
{option} - +
{showCorrectness && isCorrect && } {showCorrectness && isSelected && !isCorrect && }