@affanhamid/markdown-renderer 2.2.0 → 2.3.0

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.
Files changed (2) hide show
  1. package/README.md +134 -7
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,16 +1,16 @@
1
1
  # @affanhamid/markdown-renderer
2
2
 
3
- A React markdown renderer built for AI-generated content. Handles the math rendering problems that react-markdown + remark-math can't.
3
+ > A React markdown renderer built for AI-generated content. One import. Math, code, diagrams, callouts all handled.
4
4
 
5
- ## Why this exists
5
+ ## The Problem
6
6
 
7
7
  If you've used `react-markdown` with `remark-math` and `rehype-katex` to render LLM output, you've hit these problems:
8
8
 
9
- **1. Dollar signs break everything.** `remark-math` uses `$` for LaTeX math, but `$` is also currency. Their `singleDollarTextMath: false` option disables single-dollar math entirely, forcing `$$` for everything. This package disambiguates intelligently: `$20` renders as currency (digit follows `$`), while `$x + y$` renders as math. It also handles CJK characters, Devanagari/Hindi punctuation, and fullwidth punctuation as valid math boundaries.
10
-
11
- **2. AI models use inconsistent math delimiters.** GPT, Claude, and Gemini variously output `$...$`, `$$...$$`, `\(...\)`, and `\[...\]`. `remark-math` does not support `\(...\)` or `\[...\]` there's an [open discussion](https://github.com/remarkjs/remark-math/issues) with no resolution. This package normalizes all four formats automatically before rendering.
12
-
13
- **3. Too many moving parts.** The standard setup requires `react-markdown` + `remark-math` + `remark-gfm` + `rehype-katex` + KaTeX CSS + a syntax highlighter + custom components for tables, images, code blocks. This package is one import.
9
+ | Problem | Details |
10
+ |---------|---------|
11
+ | **Dollar signs break everything** | `remark-math` uses `$` for math, but `$` is also currency. Their `singleDollarTextMath: false` disables single-dollar math entirely. This package disambiguates intelligently: `$20` currency, `$x + y$` math. |
12
+ | **Inconsistent math delimiters** | GPT, Claude, and Gemini variously output `$`, `$$`, `\(…\)`, and `\[…\]`. `remark-math` doesn't support `\(…\)` or `\[…\]`. This package normalizes all four formats automatically. |
13
+ | **Too many moving parts** | The standard setup: `react-markdown` + `remark-math` + `remark-gfm` + `rehype-katex` + KaTeX CSS + syntax highlighter + custom components. This package is **one import**. |
14
14
 
15
15
  ## Features
16
16
 
@@ -21,6 +21,8 @@ If you've used `react-markdown` with `remark-math` and `rehype-katex` to render
21
21
  - **Executable code blocks** — optional `onRunCode` callback for running Python, R, etc.
22
22
  - **Inline images** — `![alt](url)` works inside paragraphs, not just as standalone blocks
23
23
  - **Semantic color tags** — `{color:important}text{/color}` for highlighting (important, definition, example, note, formula)
24
+ - **Callout blocks** — LaTeX-style `\begin{callout}{color}...\end{callout}` with any Tailwind color name
25
+ - **Mermaid diagrams** — fenced `mermaid` code blocks render as diagrams (client-side hydration with dynamic import)
24
26
  - **Auto-scaling brackets** — `($x + y$)` automatically uses `\left(` and `\right)` for proper sizing
25
27
  - **Prompt appendix** — exported `MATH_MARKDOWN_RULES_APPENDIX` string to append to your LLM system prompt, steering models toward consistent delimiter usage
26
28
 
@@ -98,6 +100,36 @@ import { MATH_MARKDOWN_RULES_APPENDIX } from "@affanhamid/markdown-renderer";
98
100
  const systemPrompt = `You are a helpful assistant.\n\n${MATH_MARKDOWN_RULES_APPENDIX}`;
99
101
  ```
100
102
 
103
+ ### Callout blocks
104
+
105
+ Use LaTeX-style syntax with any Tailwind color name:
106
+
107
+ ```md
108
+ \begin{callout}{amber}
109
+ **Warning:** This operation is irreversible.
110
+ \end{callout}
111
+
112
+ \begin{callout}{green}
113
+ **Tip:** Use `Ctrl+S` to save quickly.
114
+ \end{callout}
115
+ ```
116
+
117
+ Renders as styled callout boxes with `border-{color}-200`, `bg-{color}-50`, and `text-{color}-900` classes.
118
+
119
+ ### Mermaid diagrams
120
+
121
+ Fenced code blocks with `mermaid` as the language render as diagrams:
122
+
123
+ ````md
124
+ ```mermaid
125
+ graph LR
126
+ A[Input] --> B[Process]
127
+ B --> C[Output]
128
+ ```
129
+ ````
130
+
131
+ On the client, mermaid is dynamically imported and renders after hydration. For server-side rendering (`renderMarkdownToHtml`), a `<pre>` fallback is output inside a `.md-mermaid` container with `data-mermaid-code` for later hydration.
132
+
101
133
  ## API
102
134
 
103
135
  ### `<MarkdownRenderer />` (default export)
@@ -105,6 +137,7 @@ const systemPrompt = `You are a helpful assistant.\n\n${MATH_MARKDOWN_RULES_APPE
105
137
  | Prop | Type | Default | Description |
106
138
  |------|------|---------|-------------|
107
139
  | `markdown` | `string` | required | Markdown content to render |
140
+ | `className` | `string` | `undefined` | CSS class applied to the wrapper `<div>` |
108
141
  | `onRunCode` | `(code: string, language: string) => Promise<CodeExecutionResult>` | `undefined` | Callback for executing code blocks |
109
142
  | `executableLanguages` | `string[]` | `["python", "r"]` | Languages that get a "Run" button |
110
143
 
@@ -130,6 +163,100 @@ Normalizes `\(...\)` to `$...$` and `\[...\]` to `$$...$$`. Converts inline `$$.
130
163
 
131
164
  A plain-text string with math formatting rules to append to LLM system prompts.
132
165
 
166
+ ## Theming with Tailwind CSS
167
+
168
+ The `className` prop sets a class on the outer wrapper `<div>`, which you can use as a scoping selector for custom themes.
169
+
170
+ ```tsx
171
+ <MarkdownRenderer markdown={content} className="my-theme" />
172
+ ```
173
+
174
+ This renders:
175
+
176
+ ```html
177
+ <div class="my-theme">
178
+ <h1>...</h1>
179
+ <p>...</p>
180
+ <div class="md-callout ...">...</div>
181
+ <!-- etc. -->
182
+ </div>
183
+ ```
184
+
185
+ ### Creating a theme file
186
+
187
+ Create a CSS file (e.g. `markdown-theme.css`) that uses descendant selectors scoped to your theme class. With Tailwind, use `@apply` for utility-based styling:
188
+
189
+ ```css
190
+ /* markdown-theme.css */
191
+
192
+ .my-theme h1 {
193
+ @apply text-3xl font-bold mt-8 mb-4 text-gray-900;
194
+ }
195
+
196
+ .my-theme h2 {
197
+ @apply text-2xl font-semibold mt-6 mb-3 text-gray-800;
198
+ }
199
+
200
+ .my-theme p {
201
+ @apply text-base leading-7 mb-4 text-gray-700;
202
+ }
203
+
204
+ .my-theme code {
205
+ @apply bg-gray-100 text-sm px-1.5 py-0.5 rounded font-mono;
206
+ }
207
+
208
+ .my-theme pre {
209
+ @apply rounded-lg my-4 overflow-x-auto;
210
+ }
211
+
212
+ .my-theme .md-callout {
213
+ @apply border-l-4 border-blue-400 bg-blue-50 px-4 py-3 my-4 rounded-r-lg;
214
+ }
215
+
216
+ .my-theme table {
217
+ @apply w-full border-collapse my-4 text-sm;
218
+ }
219
+
220
+ .my-theme th {
221
+ @apply bg-gray-50 font-semibold text-left px-3 py-2 border border-gray-200;
222
+ }
223
+
224
+ .my-theme td {
225
+ @apply px-3 py-2 border border-gray-200;
226
+ }
227
+ ```
228
+
229
+ Import the theme file in your app and pass the matching class name:
230
+
231
+ ```tsx
232
+ import "./markdown-theme.css";
233
+
234
+ <MarkdownRenderer markdown={content} className="my-theme" />
235
+ ```
236
+
237
+ ### Semantic CSS classes
238
+
239
+ The renderer outputs these classes that you can target in your theme:
240
+
241
+ | Class | Element |
242
+ |-------|---------|
243
+ | `md-callout` | Callout/admonition blocks (`> [!NOTE]`, etc.) |
244
+ | `md-code-block` | Executable code block wrapper |
245
+ | `md-code-block-header` | Header bar above executable code blocks |
246
+ | `md-code-output` | Code execution output area |
247
+ | `md-code-error` | Code execution error output |
248
+ | `md-mermaid` | Mermaid diagram container |
249
+ | `md-run-btn` | "Run" button on executable code blocks |
250
+
251
+ ### Works with server-side rendering
252
+
253
+ `renderMarkdownToHtml()` produces the same HTML structure (wrapped in `<div class="prose max-w-none">`), so the same theme CSS applies to both client and server-rendered output. For server rendering, scope your selectors to the `prose` class or add a wrapper with your theme class:
254
+
255
+ ```ts
256
+ const html = renderMarkdownToHtml(content);
257
+ const themed = `<div class="my-theme">${html}</div>`;
258
+ ```
259
+
133
260
  ## License
134
261
 
135
262
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@affanhamid/markdown-renderer",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Custom markdown renderer with KaTeX support",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",