Package not found. Please check the package name and try again.

@cntyclub/ui-react 0.10.1 → 0.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cntyclub/ui-react",
3
- "version": "0.10.1",
3
+ "version": "0.10.3",
4
4
  "description": "React component library for the Country Club UI Kit — Base UI primitives styled with the Country Club design system (Tailwind CSS v4)",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -6,6 +6,87 @@ import remarkGfm from "remark-gfm";
6
6
 
7
7
  import { cn } from "../../lib/utils/css";
8
8
 
9
+ /** Common LaTeX command → readable-text replacements. */
10
+ const LATEX_SYMBOLS: Record<string, string> = {
11
+ times: "×",
12
+ cdot: "·",
13
+ div: "÷",
14
+ approx: "≈",
15
+ neq: "≠",
16
+ ne: "≠",
17
+ leq: "≤",
18
+ le: "≤",
19
+ geq: "≥",
20
+ ge: "≥",
21
+ pm: "±",
22
+ to: "→",
23
+ rightarrow: "→",
24
+ Rightarrow: "⇒",
25
+ infty: "∞",
26
+ cdots: "⋯",
27
+ ldots: "…",
28
+ deg: "°",
29
+ };
30
+
31
+ /** Wrap a fraction side in parens only when it holds an operator, so
32
+ * `\frac{116}{22}` → `116/22` but `\frac{a+b}{2}` → `(a+b)/2`. */
33
+ const wrapFracSide = (x: string): string => {
34
+ const t = x.trim();
35
+ return /[+\-*/×÷·\s]/.test(t) ? `(${t})` : t;
36
+ };
37
+
38
+ /**
39
+ * LLMs sometimes emit LaTeX math (`\( \frac{116}{22} \times 100 \approx 527\% \)`),
40
+ * which react-markdown renders as raw gibberish. We don't ship a full math
41
+ * engine (KaTeX + fonts) — assistant chat rarely needs typeset math — so this
42
+ * downgrades the common LaTeX constructs to readable plain text instead. Plain
43
+ * text with no backslash / `$` is returned untouched (fast path), and lone `$`
44
+ * amounts like "$100" are left alone (only `$…$` containing a command unwraps).
45
+ */
46
+ function normalizeLatex(src: string): string {
47
+ if (!src.includes("\\") && !src.includes("$")) return src;
48
+
49
+ let s = src;
50
+
51
+ // Unwrap math delimiters. `$$…$$` display + `\(…\)`/`\[…\]` inline always;
52
+ // single `$…$` only when the body looks like math (has a backslash).
53
+ s = s.replace(/\$\$([\s\S]*?)\$\$/g, " $1 ");
54
+ s = s.replace(/\$([^$\n]*\\[^$\n]*)\$/g, " $1 ");
55
+ s = s.replace(/\\[()[\]]/g, " ");
56
+
57
+ // \frac{a}{b} → a/b (a few passes for nesting), \sqrt{x} → √(x).
58
+ for (let i = 0; i < 3; i++) {
59
+ const next = s.replace(
60
+ /\\[dt]?frac\s*\{([^{}]*)\}\s*\{([^{}]*)\}/g,
61
+ (_m, a: string, b: string) => `${wrapFracSide(a)}/${wrapFracSide(b)}`,
62
+ );
63
+ if (next === s) break;
64
+ s = next;
65
+ }
66
+ s = s.replace(/\\sqrt\s*\{([^{}]*)\}/g, "√($1)");
67
+ s = s.replace(/\\(?:text|mathrm|mathbf|mathit|operatorname)\s*\{([^{}]*)\}/g, "$1");
68
+
69
+ // Known symbols → unicode; \left/\right dropped.
70
+ s = s.replace(/\\([a-zA-Z]+)/g, (m, name: string) => LATEX_SYMBOLS[name] ?? m);
71
+ s = s.replace(/\\(left|right)\b/g, "");
72
+
73
+ // Escaped chars (\% \$ \_ \{ …) and thin spaces (\, \; \!).
74
+ s = s.replace(/\\([%$&#_{}])/g, "$1");
75
+ s = s.replace(/\\[,;:!]/g, "");
76
+ s = s.replace(/\\ /g, " ");
77
+
78
+ // Any leftover unknown \command → keep the word, drop the backslash.
79
+ s = s.replace(/\\([a-zA-Z]+)/g, "$1");
80
+
81
+ // Collapse grouping braces ({x} → x) and runs of spaces.
82
+ for (let i = 0; i < 3; i++) {
83
+ const next = s.replace(/\{([^{}]*)\}/g, "$1");
84
+ if (next === s) break;
85
+ s = next;
86
+ }
87
+ return s.replace(/[ \t]{2,}/g, " ");
88
+ }
89
+
9
90
  export interface MarkdownProps {
10
91
  /** The markdown source to render. */
11
92
  children: string;
@@ -98,7 +179,7 @@ function Markdown({ children, className }: MarkdownProps) {
98
179
  remarkPlugins={[remarkGfm]}
99
180
  skipHtml
100
181
  >
101
- {children}
182
+ {normalizeLatex(children)}
102
183
  </ReactMarkdown>
103
184
  </div>
104
185
  );