MathText: matrix [[..],[..]] drawn as a real matrix block instead of wrapping mid-row

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-14 22:13:34 +03:30
parent 2ac783d222
commit 782998e325

View File

@@ -41,7 +41,43 @@ const FORMULA = /[=<>≤≥≠∈∉⊂⊆∪∩+×÷^√∑∫]|[0-9۰-۹A-Za-z
* چشم وسطِ فرمول به خطِ بعد نیفتد. عددِ تنها و عبارتِ کوتاهِ بدونِ نمادِ عمل داخلِ جمله می‌ماند. * چشم وسطِ فرمول به خطِ بعد نیفتد. عددِ تنها و عبارتِ کوتاهِ بدونِ نمادِ عمل داخلِ جمله می‌ماند.
* آزموده نشده: صفحه‌ی واقعیِ اپ در Chrome و Safari؛ فقط منطقِ تشخیص با نمونه‌های بانک سنجیده شد. * آزموده نشده: صفحه‌ی واقعیِ اپ در Chrome و Safari؛ فقط منطقِ تشخیص با نمونه‌های بانک سنجیده شد.
*/ */
// ماتریس «[[۲، ۷]، [۴، ۱]]»: ردیف‌ها داخلِ کروشه‌ی تو در تو. اگر مثلِ متنِ عادی بگذاریم، در خطِ باریک
// وسطِ ردیف شکسته می‌شود و راست‌به‌چپ بودنِ جمله عددها را جابه‌جا نشان می‌دهد (گزارشِ مالک ۲۰۲۶-۱۰-۱۴).
const MATRIX = /\[\s*\[[^\[\]]*\](?:\s*[،,]\s*\[[^\[\]]*\])*\s*\]/g;
function Matrix({ src }: { src: string }) {
const rows = [...src.matchAll(/\[([^\[\]]*)\]/g)].map((m) => m[1].split(/[،,]/).map((c) => plainPersian(plainMath(c.trim()))));
const border = '2px solid currentColor';
return (
<span
dir="ltr"
style={{ display: 'inline-block', verticalAlign: 'middle', margin: '4px 6px', padding: '2px 8px', borderLeft: border, borderRight: border, borderRadius: 6, unicodeBidi: 'isolate' }}
>
{rows.map((row, i) => (
<span key={i} style={{ display: 'flex', justifyContent: 'center', gap: 14, lineHeight: 1.7, whiteSpace: 'nowrap' }}>
{row.map((c, j) => <span key={j} style={{ minWidth: 18, textAlign: 'center' }}>{c}</span>)}
</span>
))}
</span>
);
}
export function MathText({ text: raw, display = false }: { text: string; display?: boolean }) { export function MathText({ text: raw, display = false }: { text: string; display?: boolean }) {
if (!MATRIX.test(raw)) { MATRIX.lastIndex = 0; return <Inline raw={raw} display={display} />; }
MATRIX.lastIndex = 0;
const out: React.ReactNode[] = [];
let last = 0, k = 0;
for (const m of raw.matchAll(MATRIX)) {
const at = m.index ?? 0;
if (at > last) out.push(<Inline key={`t${k++}`} raw={raw.slice(last, at)} display={display} />);
out.push(<Matrix key={`m${k++}`} src={m[0]} />);
last = at + m[0].length;
}
if (last < raw.length) out.push(<Inline key={`t${k++}`} raw={raw.slice(last)} display={display} />);
return <>{out}</>;
}
function Inline({ raw, display }: { raw: string; display: boolean }) {
const text = plainPersian(plainMath(raw)); const text = plainPersian(plainMath(raw));
const out: React.ReactNode[] = []; const out: React.ReactNode[] = [];
const depth = bracketDepth(text); const depth = bracketDepth(text);