@ai-react-markdown/core 1.0.1 → 1.0.5
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/README.md +407 -0
- package/dist/index.cjs +41 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +421 -38
- package/dist/index.d.ts +421 -38
- package/dist/index.js +37 -16
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
package/README.md
ADDED
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
# @ai-react-markdown/core
|
|
2
|
+
|
|
3
|
+
A batteries-included React component for rendering AI-generated markdown with first-class support for LaTeX math, GFM, CJK text, and streaming content.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **GFM** -- tables, strikethrough, task lists, autolinks via `remark-gfm`
|
|
8
|
+
- **LaTeX math** -- inline and display math rendered with KaTeX; smart preprocessing handles currency `$` signs, bracket delimiters (`\[...\]`, `\(...\)`), pipe escaping, and mhchem commands
|
|
9
|
+
- **Emoji** -- shortcode support (`:smile:`) via `remark-emoji`
|
|
10
|
+
- **CJK-friendly** -- proper line breaking and spacing for Chinese, Japanese, and Korean text
|
|
11
|
+
- **Extra syntax** -- highlight (`==text==`), definition lists, superscript/subscript
|
|
12
|
+
- **Display optimizations** -- SmartyPants typography, pangu CJK spacing, HTML comment removal
|
|
13
|
+
- **Streaming-aware** -- built-in `streaming` flag propagated via context for custom components
|
|
14
|
+
- **Customizable** -- swap typography, color scheme, individual markdown element renderers, and inject extra style wrappers
|
|
15
|
+
- **Metadata context** -- pass arbitrary data to deeply nested custom components without prop drilling, isolated from render state to avoid unnecessary re-renders
|
|
16
|
+
- **TypeScript** -- full generic support for extended configs and metadata types
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# npm
|
|
22
|
+
npm install @ai-react-markdown/core
|
|
23
|
+
|
|
24
|
+
# pnpm
|
|
25
|
+
pnpm add @ai-react-markdown/core
|
|
26
|
+
|
|
27
|
+
# yarn
|
|
28
|
+
yarn add @ai-react-markdown/core
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Peer Dependencies
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"react": ">=19.0.0",
|
|
36
|
+
"react-dom": ">=19.0.0"
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### CSS Dependencies
|
|
41
|
+
|
|
42
|
+
For LaTeX math rendering, include the KaTeX stylesheet:
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import 'katex/dist/katex.min.css';
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
For the built-in default typography, include the typography CSS:
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import '@ai-react-markdown/core/typography/default.css';
|
|
52
|
+
// or import all typography variants at once:
|
|
53
|
+
import '@ai-react-markdown/core/typography/all.css';
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import AIMarkdown from '@ai-react-markdown/core';
|
|
60
|
+
import 'katex/dist/katex.min.css';
|
|
61
|
+
import '@ai-react-markdown/core/typography/default.css';
|
|
62
|
+
|
|
63
|
+
function App() {
|
|
64
|
+
return <AIMarkdown content="Hello **world**! Math: $E = mc^2$" />;
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Streaming Example
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
function StreamingChat({ content, isStreaming }: { content: string; isStreaming: boolean }) {
|
|
72
|
+
return <AIMarkdown content={content} streaming={isStreaming} colorScheme="dark" />;
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Props API Reference
|
|
77
|
+
|
|
78
|
+
### `AIMarkdownProps<TConfig, TRenderData>`
|
|
79
|
+
|
|
80
|
+
| Prop | Type | Default | Description |
|
|
81
|
+
| ---------------------- | -------------------------------- | ------------------------------- | ---------------------------------------------------------------------- |
|
|
82
|
+
| `content` | `string` | **(required)** | Raw markdown content to render. |
|
|
83
|
+
| `streaming` | `boolean` | `false` | Whether content is actively being streamed (e.g. from an LLM). |
|
|
84
|
+
| `fontSize` | `number \| string` | `'0.875rem'` | Base font size. Numbers are treated as pixels. |
|
|
85
|
+
| `variant` | `AIMarkdownVariant` | `'default'` | Typography variant name. |
|
|
86
|
+
| `colorScheme` | `AIMarkdownColorScheme` | `'light'` | Color scheme name (`'light'`, `'dark'`, or custom). |
|
|
87
|
+
| `config` | `PartialDeep<TConfig>` | `undefined` | Partial render config, deep-merged with defaults. |
|
|
88
|
+
| `defaultConfig` | `TConfig` | `defaultAIMarkdownRenderConfig` | Base config to merge against. Sub-packages can pass extended defaults. |
|
|
89
|
+
| `metadata` | `TRenderData` | `undefined` | Arbitrary data passed to custom components via a dedicated context. |
|
|
90
|
+
| `contentPreprocessors` | `AIMDContentPreprocessor[]` | `[]` | Additional preprocessors run after the built-in LaTeX preprocessor. |
|
|
91
|
+
| `customComponents` | `AIMarkdownCustomComponents` | `undefined` | `react-markdown` component overrides for specific HTML elements. |
|
|
92
|
+
| `Typography` | `AIMarkdownTypographyComponent` | `DefaultTypography` | Typography wrapper component. |
|
|
93
|
+
| `ExtraStyles` | `AIMarkdownExtraStylesComponent` | `undefined` | Optional extra style wrapper rendered between typography and content. |
|
|
94
|
+
|
|
95
|
+
## Configuration
|
|
96
|
+
|
|
97
|
+
Rendering behavior is controlled by `AIMarkdownRenderConfig`, which has two configuration arrays:
|
|
98
|
+
|
|
99
|
+
### Extra Syntax Extensions
|
|
100
|
+
|
|
101
|
+
Enable via `config.extraSyntaxSupported`. All are enabled by default.
|
|
102
|
+
|
|
103
|
+
| Value | Description |
|
|
104
|
+
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
105
|
+
| `AIMarkdownRenderExtraSyntax.HIGHLIGHT` | `==Highlight==` syntax support |
|
|
106
|
+
| `AIMarkdownRenderExtraSyntax.DEFINITION_LIST` | Definition list syntax ([PHP Markdown Extra](https://michelf.ca/projects/php-markdown/extra/#def-list)) |
|
|
107
|
+
| `AIMarkdownRenderExtraSyntax.SUBSCRIPT` | Superscript (`^text^`) and subscript (`~text~`) |
|
|
108
|
+
|
|
109
|
+
### Display Optimization Abilities
|
|
110
|
+
|
|
111
|
+
Enable via `config.displayOptimizeAbilities`. All are enabled by default.
|
|
112
|
+
|
|
113
|
+
| Value | Description |
|
|
114
|
+
| -------------------------------------------------------- | -------------------------------------------------------- |
|
|
115
|
+
| `AIMarkdownRenderDisplayOptimizeAbility.REMOVE_COMMENTS` | Strip HTML comments |
|
|
116
|
+
| `AIMarkdownRenderDisplayOptimizeAbility.SMARTYPANTS` | Typographic enhancements (curly quotes, em-dashes, etc.) |
|
|
117
|
+
| `AIMarkdownRenderDisplayOptimizeAbility.PANGU` | Auto-insert spaces between CJK and half-width characters |
|
|
118
|
+
|
|
119
|
+
### Example: Selective Configuration
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
import AIMarkdown, {
|
|
123
|
+
AIMarkdownRenderExtraSyntax,
|
|
124
|
+
AIMarkdownRenderDisplayOptimizeAbility,
|
|
125
|
+
} from '@ai-react-markdown/core';
|
|
126
|
+
|
|
127
|
+
<AIMarkdown
|
|
128
|
+
content={markdown}
|
|
129
|
+
config={{
|
|
130
|
+
extraSyntaxSupported: [AIMarkdownRenderExtraSyntax.HIGHLIGHT],
|
|
131
|
+
displayOptimizeAbilities: [AIMarkdownRenderDisplayOptimizeAbility.SMARTYPANTS],
|
|
132
|
+
}}
|
|
133
|
+
/>;
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
When you provide a partial `config`, it is deep-merged with the defaults. Array values (like `extraSyntaxSupported`) are **replaced entirely**, not merged by index -- so the example above enables only the highlight extension, disabling definition lists and subscript.
|
|
137
|
+
|
|
138
|
+
## Hooks
|
|
139
|
+
|
|
140
|
+
### `useAIMarkdownRenderState<TConfig>()`
|
|
141
|
+
|
|
142
|
+
Access the current render state from within any component rendered inside `<AIMarkdown>`. Throws if called outside the provider boundary.
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
import { useAIMarkdownRenderState } from '@ai-react-markdown/core';
|
|
146
|
+
|
|
147
|
+
function CustomCodeBlock({ children }: PropsWithChildren) {
|
|
148
|
+
const { streaming, config, fontSize, variant, colorScheme } = useAIMarkdownRenderState();
|
|
149
|
+
|
|
150
|
+
if (streaming) {
|
|
151
|
+
return <pre className="streaming">{children}</pre>;
|
|
152
|
+
}
|
|
153
|
+
return <pre>{children}</pre>;
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Returns** `AIMarkdownRenderState<TConfig>`:
|
|
158
|
+
|
|
159
|
+
| Field | Type | Description |
|
|
160
|
+
| ------------- | ----------------------- | --------------------------------------------------- |
|
|
161
|
+
| `streaming` | `boolean` | Whether content is being streamed. |
|
|
162
|
+
| `fontSize` | `string` | Resolved CSS font-size value. |
|
|
163
|
+
| `variant` | `AIMarkdownVariant` | Active typography variant. |
|
|
164
|
+
| `colorScheme` | `AIMarkdownColorScheme` | Active color scheme. |
|
|
165
|
+
| `config` | `TConfig` | Active render configuration (merged with defaults). |
|
|
166
|
+
|
|
167
|
+
### `useAIMarkdownMetadata<TMetadata>()`
|
|
168
|
+
|
|
169
|
+
Access arbitrary metadata from within the `<AIMarkdown>` tree. Metadata lives in a **separate** React context from render state, so metadata changes do not trigger re-renders in components that only consume render state.
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
import { useAIMarkdownMetadata } from '@ai-react-markdown/core';
|
|
173
|
+
|
|
174
|
+
interface MyMetadata {
|
|
175
|
+
onCopyCode: (code: string) => void;
|
|
176
|
+
messageId: string;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function CustomCodeBlock({ children }: PropsWithChildren) {
|
|
180
|
+
const metadata = useAIMarkdownMetadata<MyMetadata>();
|
|
181
|
+
return (
|
|
182
|
+
<pre>
|
|
183
|
+
<button onClick={() => metadata?.onCopyCode(String(children))}>Copy</button>
|
|
184
|
+
{children}
|
|
185
|
+
</pre>
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Returns** `TMetadata | undefined` -- `undefined` when no metadata was provided.
|
|
191
|
+
|
|
192
|
+
### `useStableValue<T>(value: T)`
|
|
193
|
+
|
|
194
|
+
Returns a referentially stable version of `value`. On each render the new value is deep-compared (via `lodash/isEqual`) against the previous one. If they are structurally equal, the previous reference is returned, preventing unnecessary re-renders in downstream `useMemo`/`useEffect` consumers.
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
import { useStableValue } from '@ai-react-markdown/core';
|
|
198
|
+
|
|
199
|
+
const stableConfig = useStableValue(config);
|
|
200
|
+
// stableConfig keeps the same reference as long as config is deep-equal.
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Typography and Styling
|
|
204
|
+
|
|
205
|
+
The `<AIMarkdown>` component wraps its content in a typography component that controls font size, variant, and color scheme.
|
|
206
|
+
|
|
207
|
+
### Built-in Default Typography
|
|
208
|
+
|
|
209
|
+
The built-in `DefaultTypography` renders a `<div>` with CSS class names for the active variant and color scheme:
|
|
210
|
+
|
|
211
|
+
```html
|
|
212
|
+
<div class="aim-typography-root default light" style="width: 100%; font-size: 0.875rem">
|
|
213
|
+
<!-- markdown content -->
|
|
214
|
+
</div>
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Import the corresponding CSS to activate styles:
|
|
218
|
+
|
|
219
|
+
```tsx
|
|
220
|
+
import '@ai-react-markdown/core/typography/default.css';
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Custom Typography Component
|
|
224
|
+
|
|
225
|
+
Replace the typography wrapper by passing a custom component:
|
|
226
|
+
|
|
227
|
+
```tsx
|
|
228
|
+
import type { AIMarkdownTypographyProps } from '@ai-react-markdown/core';
|
|
229
|
+
|
|
230
|
+
function MyTypography({ children, fontSize, variant, colorScheme }: AIMarkdownTypographyProps) {
|
|
231
|
+
return (
|
|
232
|
+
<div className={`my-markdown ${colorScheme}`} style={{ fontSize }}>
|
|
233
|
+
{children}
|
|
234
|
+
</div>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
<AIMarkdown content={markdown} Typography={MyTypography} />;
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Extra Styles Wrapper
|
|
242
|
+
|
|
243
|
+
The `ExtraStyles` prop accepts a component rendered between the typography wrapper and the markdown content. Useful for injecting additional CSS scope or theme providers:
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
import type { AIMarkdownExtraStylesProps } from '@ai-react-markdown/core';
|
|
247
|
+
|
|
248
|
+
function MyExtraStyles({ children }: AIMarkdownExtraStylesProps) {
|
|
249
|
+
return <div className="my-extra-scope">{children}</div>;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
<AIMarkdown content={markdown} ExtraStyles={MyExtraStyles} />;
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Custom Components
|
|
256
|
+
|
|
257
|
+
Override the default renderers for specific HTML elements using the `customComponents` prop. This maps directly to `react-markdown`'s `Components` type:
|
|
258
|
+
|
|
259
|
+
```tsx
|
|
260
|
+
import type { AIMarkdownCustomComponents } from '@ai-react-markdown/core';
|
|
261
|
+
|
|
262
|
+
const components: AIMarkdownCustomComponents = {
|
|
263
|
+
a: ({ href, children }) => (
|
|
264
|
+
<a href={href} target="_blank" rel="noopener noreferrer">
|
|
265
|
+
{children}
|
|
266
|
+
</a>
|
|
267
|
+
),
|
|
268
|
+
img: ({ src, alt }) => <img src={src} alt={alt} loading="lazy" />,
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
<AIMarkdown content={markdown} customComponents={components} />;
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Streaming Support
|
|
275
|
+
|
|
276
|
+
Pass `streaming={true}` when content is actively being generated (e.g. token-by-token from an LLM). The flag is propagated to all descendant components via `useAIMarkdownRenderState()`, allowing custom renderers to adapt their behavior (e.g. show a cursor, disable copy buttons, or skip animations).
|
|
277
|
+
|
|
278
|
+
```tsx
|
|
279
|
+
function ChatMessage({ content, isStreaming }: { content: string; isStreaming: boolean }) {
|
|
280
|
+
return <AIMarkdown content={content} streaming={isStreaming} />;
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Metadata
|
|
285
|
+
|
|
286
|
+
The `metadata` prop lets you pass arbitrary data to deeply nested custom components without prop drilling. Metadata is stored in a **separate React context** from the render state, so updating metadata does not cause re-renders in components that only read render state (like the core `MarkdownContent`).
|
|
287
|
+
|
|
288
|
+
```tsx
|
|
289
|
+
interface ChatMetadata {
|
|
290
|
+
messageId: string;
|
|
291
|
+
onCopyCode: (code: string) => void;
|
|
292
|
+
onRegenerate: () => void;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
<AIMarkdown<AIMarkdownRenderConfig, ChatMetadata>
|
|
296
|
+
content={markdown}
|
|
297
|
+
metadata={{
|
|
298
|
+
messageId: msg.id,
|
|
299
|
+
onCopyCode: handleCopy,
|
|
300
|
+
onRegenerate: handleRegenerate,
|
|
301
|
+
}}
|
|
302
|
+
/>;
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## Content Preprocessors
|
|
306
|
+
|
|
307
|
+
The rendering pipeline runs a LaTeX preprocessor by default. You can append additional preprocessors that transform the raw markdown string before it enters the remark/rehype pipeline:
|
|
308
|
+
|
|
309
|
+
```tsx
|
|
310
|
+
import type { AIMDContentPreprocessor } from '@ai-react-markdown/core';
|
|
311
|
+
|
|
312
|
+
const stripFrontmatter: AIMDContentPreprocessor = (content) => content.replace(/^---[\s\S]*?---\n/, '');
|
|
313
|
+
|
|
314
|
+
<AIMarkdown content={markdown} contentPreprocessors={[stripFrontmatter]} />;
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Preprocessors run in sequence: built-in LaTeX preprocessor first, then your custom ones in array order.
|
|
318
|
+
|
|
319
|
+
## TypeScript Generics
|
|
320
|
+
|
|
321
|
+
The component supports two generic type parameters for type-safe config and metadata:
|
|
322
|
+
|
|
323
|
+
```tsx
|
|
324
|
+
import AIMarkdown, { type AIMarkdownRenderConfig, type AIMarkdownMetadata } from '@ai-react-markdown/core';
|
|
325
|
+
|
|
326
|
+
// Extended config (e.g. adding code block options)
|
|
327
|
+
interface MyConfig extends AIMarkdownRenderConfig {
|
|
328
|
+
codeBlock: { defaultExpanded: boolean };
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Extended metadata
|
|
332
|
+
interface MyMetadata extends AIMarkdownMetadata {
|
|
333
|
+
messageId: string;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
<AIMarkdown<MyConfig, MyMetadata>
|
|
337
|
+
content={markdown}
|
|
338
|
+
defaultConfig={myDefaultConfig}
|
|
339
|
+
config={{ codeBlock: { defaultExpanded: false } }}
|
|
340
|
+
metadata={{ messageId: '123' }}
|
|
341
|
+
/>;
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Sub-packages like `@ai-react-markdown/mantine` use this pattern to extend the base config with additional options (e.g. `forceSameFontSize`, `codeBlock.autoDetectUnknownLanguage`) while inheriting all core functionality.
|
|
345
|
+
|
|
346
|
+
Similarly, hooks accept generic parameters for type-safe access:
|
|
347
|
+
|
|
348
|
+
```tsx
|
|
349
|
+
const { config } = useAIMarkdownRenderState<MyConfig>();
|
|
350
|
+
const metadata = useAIMarkdownMetadata<MyMetadata>();
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## Architecture Overview
|
|
354
|
+
|
|
355
|
+
```text
|
|
356
|
+
<AIMarkdown>
|
|
357
|
+
<AIMarkdownMetadataProvider> // Separate context for metadata
|
|
358
|
+
<AIMarkdownRenderStateProvider> // Context for render state (streaming, config, etc.)
|
|
359
|
+
<Typography> // Configurable typography wrapper
|
|
360
|
+
<ExtraStyles?> // Optional extra style wrapper
|
|
361
|
+
<AIMarkdownContent /> // react-markdown with remark/rehype plugin chain
|
|
362
|
+
</ExtraStyles?>
|
|
363
|
+
</Typography>
|
|
364
|
+
</AIMarkdownRenderStateProvider>
|
|
365
|
+
</AIMarkdownMetadataProvider>
|
|
366
|
+
</AIMarkdown>
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
The metadata and render state providers are deliberately separated so that metadata changes (e.g. callback updates) do not trigger re-renders in `AIMarkdownContent`, which only consumes render state.
|
|
370
|
+
|
|
371
|
+
## Exported API
|
|
372
|
+
|
|
373
|
+
### Default Export
|
|
374
|
+
|
|
375
|
+
- `AIMarkdown` -- the main component (memoized)
|
|
376
|
+
|
|
377
|
+
### Types
|
|
378
|
+
|
|
379
|
+
- `AIMarkdownProps`
|
|
380
|
+
- `AIMarkdownCustomComponents`
|
|
381
|
+
- `AIMarkdownRenderConfig`
|
|
382
|
+
- `AIMarkdownRenderState`
|
|
383
|
+
- `AIMarkdownMetadata`
|
|
384
|
+
- `AIMarkdownTypographyProps`
|
|
385
|
+
- `AIMarkdownTypographyComponent`
|
|
386
|
+
- `AIMarkdownExtraStylesProps`
|
|
387
|
+
- `AIMarkdownExtraStylesComponent`
|
|
388
|
+
- `AIMarkdownVariant`
|
|
389
|
+
- `AIMarkdownColorScheme`
|
|
390
|
+
- `AIMDContentPreprocessor`
|
|
391
|
+
- `PartialDeep`
|
|
392
|
+
|
|
393
|
+
### Enums and Constants
|
|
394
|
+
|
|
395
|
+
- `AIMarkdownRenderExtraSyntax`
|
|
396
|
+
- `AIMarkdownRenderDisplayOptimizeAbility`
|
|
397
|
+
- `defaultAIMarkdownRenderConfig`
|
|
398
|
+
|
|
399
|
+
### Hooks (re-exported)
|
|
400
|
+
|
|
401
|
+
- `useAIMarkdownRenderState()`
|
|
402
|
+
- `useAIMarkdownMetadata()`
|
|
403
|
+
- `useStableValue()`
|
|
404
|
+
|
|
405
|
+
## License
|
|
406
|
+
|
|
407
|
+
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -34,15 +34,18 @@ __export(index_exports, {
|
|
|
34
34
|
AIMarkdownRenderDisplayOptimizeAbility: () => AIMarkdownRenderDisplayOptimizeAbility,
|
|
35
35
|
AIMarkdownRenderExtraSyntax: () => AIMarkdownRenderExtraSyntax,
|
|
36
36
|
default: () => index_default,
|
|
37
|
-
|
|
37
|
+
defaultAIMarkdownRenderConfig: () => defaultAIMarkdownRenderConfig,
|
|
38
|
+
useAIMarkdownMetadata: () => useAIMarkdownMetadata,
|
|
39
|
+
useAIMarkdownRenderState: () => useAIMarkdownRenderState,
|
|
40
|
+
useStableValue: () => useStableValue
|
|
38
41
|
});
|
|
39
42
|
module.exports = __toCommonJS(index_exports);
|
|
40
43
|
var import_react5 = require("react");
|
|
41
44
|
|
|
42
45
|
// src/context.tsx
|
|
43
46
|
var import_react = require("react");
|
|
44
|
-
var import_cloneDeep = __toESM(require("lodash/cloneDeep"), 1);
|
|
45
|
-
var import_mergeWith = __toESM(require("lodash/mergeWith"), 1);
|
|
47
|
+
var import_cloneDeep = __toESM(require("lodash-es/cloneDeep"), 1);
|
|
48
|
+
var import_mergeWith = __toESM(require("lodash-es/mergeWith"), 1);
|
|
46
49
|
|
|
47
50
|
// src/defs.ts
|
|
48
51
|
var AIMarkdownRenderExtraSyntax = /* @__PURE__ */ ((AIMarkdownRenderExtraSyntax2) => {
|
|
@@ -73,6 +76,7 @@ var defaultAIMarkdownRenderConfig = Object.freeze({
|
|
|
73
76
|
// src/context.tsx
|
|
74
77
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
75
78
|
var AIMarkdownRenderStateContext = (0, import_react.createContext)(null);
|
|
79
|
+
var AIMarkdownMetadataContext = (0, import_react.createContext)(void 0);
|
|
76
80
|
function useAIMarkdownRenderState() {
|
|
77
81
|
const context = (0, import_react.useContext)(AIMarkdownRenderStateContext);
|
|
78
82
|
if (!context) {
|
|
@@ -80,30 +84,43 @@ function useAIMarkdownRenderState() {
|
|
|
80
84
|
}
|
|
81
85
|
return context;
|
|
82
86
|
}
|
|
87
|
+
function useAIMarkdownMetadata() {
|
|
88
|
+
return (0, import_react.useContext)(AIMarkdownMetadataContext);
|
|
89
|
+
}
|
|
83
90
|
var configMergeCustomizer = (_objValue, srcValue, _key, _object, _source, _stack) => {
|
|
84
91
|
if (Array.isArray(srcValue)) {
|
|
85
92
|
return srcValue;
|
|
86
93
|
}
|
|
87
94
|
};
|
|
95
|
+
var AIMarkdownMetadataProvider = ({
|
|
96
|
+
metadata,
|
|
97
|
+
children
|
|
98
|
+
}) => {
|
|
99
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AIMarkdownMetadataContext.Provider, { value: metadata, children });
|
|
100
|
+
};
|
|
88
101
|
var AIMarkdownRenderStateProvider = ({
|
|
89
102
|
streaming,
|
|
90
103
|
fontSize,
|
|
104
|
+
variant,
|
|
105
|
+
colorScheme,
|
|
106
|
+
defaultConfig,
|
|
91
107
|
config,
|
|
92
|
-
metadata,
|
|
93
108
|
children
|
|
94
109
|
}) => {
|
|
110
|
+
const baseConfig = defaultConfig ?? defaultAIMarkdownRenderConfig;
|
|
95
111
|
const mergedConfig = (0, import_react.useMemo)(
|
|
96
|
-
() => config ? (0, import_mergeWith.default)((0, import_cloneDeep.default)(
|
|
97
|
-
[config]
|
|
112
|
+
() => config ? (0, import_mergeWith.default)((0, import_cloneDeep.default)(baseConfig), config, configMergeCustomizer) : baseConfig,
|
|
113
|
+
[baseConfig, config]
|
|
98
114
|
);
|
|
99
115
|
const state = (0, import_react.useMemo)(
|
|
100
116
|
() => Object.freeze({
|
|
101
117
|
streaming,
|
|
102
118
|
fontSize,
|
|
103
|
-
|
|
104
|
-
|
|
119
|
+
variant,
|
|
120
|
+
colorScheme,
|
|
121
|
+
config: mergedConfig
|
|
105
122
|
}),
|
|
106
|
-
[streaming, fontSize,
|
|
123
|
+
[streaming, fontSize, variant, colorScheme, mergedConfig]
|
|
107
124
|
);
|
|
108
125
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AIMarkdownRenderStateContext.Provider, { value: state, children });
|
|
109
126
|
};
|
|
@@ -375,7 +392,7 @@ var MarkdownContent_default = AIMarkdownContent;
|
|
|
375
392
|
|
|
376
393
|
// src/hooks/useStableValue.ts
|
|
377
394
|
var import_react3 = require("react");
|
|
378
|
-
var import_isEqual = __toESM(require("lodash/isEqual"), 1);
|
|
395
|
+
var import_isEqual = __toESM(require("lodash-es/isEqual"), 1);
|
|
379
396
|
function useStableValue(value) {
|
|
380
397
|
const ref = (0, import_react3.useRef)(value);
|
|
381
398
|
const prev = ref.current;
|
|
@@ -408,14 +425,16 @@ var AIMarkdownComponent = ({
|
|
|
408
425
|
fontSize,
|
|
409
426
|
contentPreprocessors,
|
|
410
427
|
customComponents,
|
|
428
|
+
defaultConfig,
|
|
411
429
|
config,
|
|
412
430
|
metadata,
|
|
413
|
-
|
|
414
|
-
|
|
431
|
+
Typography = Default_default,
|
|
432
|
+
ExtraStyles,
|
|
415
433
|
variant = "default",
|
|
416
434
|
colorScheme = "light"
|
|
417
435
|
}) => {
|
|
418
436
|
const usedFontSize = fontSize ? typeof fontSize === "number" ? `${fontSize}px` : fontSize : "0.875rem";
|
|
437
|
+
const stableDefaultConfig = useStableValue(defaultConfig);
|
|
419
438
|
const stableConfig = useStableValue(config);
|
|
420
439
|
const stablePreprocessors = useStableValue(contentPreprocessors);
|
|
421
440
|
const stableCustomComponents = useStableValue(customComponents);
|
|
@@ -423,16 +442,18 @@ var AIMarkdownComponent = ({
|
|
|
423
442
|
() => content ? preprocessAIMDContent(content, stablePreprocessors) : content,
|
|
424
443
|
[content, stablePreprocessors]
|
|
425
444
|
);
|
|
426
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
445
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AIMarkdownMetadataProvider, { metadata, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
427
446
|
context_default,
|
|
428
447
|
{
|
|
429
448
|
streaming,
|
|
430
449
|
fontSize: usedFontSize,
|
|
450
|
+
variant,
|
|
451
|
+
colorScheme,
|
|
452
|
+
defaultConfig: stableDefaultConfig,
|
|
431
453
|
config: stableConfig,
|
|
432
|
-
|
|
433
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Typography, { fontSize: usedFontSize, variant, colorScheme, children: ExtraStyle ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ExtraStyle, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MarkdownContent_default, { content: usedContent, customComponents: stableCustomComponents }) }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MarkdownContent_default, { content: usedContent, customComponents: stableCustomComponents }) })
|
|
454
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Typography, { fontSize: usedFontSize, variant, colorScheme, children: ExtraStyles ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ExtraStyles, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MarkdownContent_default, { content: usedContent, customComponents: stableCustomComponents }) }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MarkdownContent_default, { content: usedContent, customComponents: stableCustomComponents }) })
|
|
434
455
|
}
|
|
435
|
-
);
|
|
456
|
+
) });
|
|
436
457
|
};
|
|
437
458
|
var AIMarkdown = (0, import_react5.memo)(AIMarkdownComponent);
|
|
438
459
|
AIMarkdown.displayName = "AIMarkdown";
|
|
@@ -441,6 +462,9 @@ var index_default = AIMarkdown;
|
|
|
441
462
|
0 && (module.exports = {
|
|
442
463
|
AIMarkdownRenderDisplayOptimizeAbility,
|
|
443
464
|
AIMarkdownRenderExtraSyntax,
|
|
444
|
-
|
|
465
|
+
defaultAIMarkdownRenderConfig,
|
|
466
|
+
useAIMarkdownMetadata,
|
|
467
|
+
useAIMarkdownRenderState,
|
|
468
|
+
useStableValue
|
|
445
469
|
});
|
|
446
470
|
//# sourceMappingURL=index.cjs.map
|