@ai-react-markdown/core 1.2.9 → 1.4.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.
package/README.md CHANGED
@@ -12,7 +12,7 @@ A batteries-included React component for rendering AI-generated markdown with fi
12
12
  - **LaTeX math** -- inline and display math rendered with KaTeX; smart preprocessing handles currency `$` signs, bracket delimiters (`\[...\]`, `\(...\)`), pipe escaping, and mhchem commands
13
13
  - **Emoji** -- shortcode support (`:smile:`) via `remark-emoji`
14
14
  - **CJK-friendly** -- proper line breaking and spacing for Chinese, Japanese, and Korean text
15
- - **Extra syntax** -- highlight (`==text==`), definition lists, superscript/subscript
15
+ - **Extra syntax** -- highlight (`==text==`), definition lists
16
16
  - **Display optimizations** -- SmartyPants typography, pangu CJK spacing, HTML comment removal
17
17
  - **Streaming-aware** -- built-in `streaming` flag propagated via context for custom components
18
18
  - **Customizable** -- swap typography, color scheme, individual markdown element renderers, and inject extra style wrappers
@@ -81,20 +81,21 @@ function StreamingChat({ content, isStreaming }: { content: string; isStreaming:
81
81
 
82
82
  ### `AIMarkdownProps<TConfig, TRenderData>`
83
83
 
84
- | Prop | Type | Default | Description |
85
- | ---------------------- | -------------------------------- | ------------------------------- | ---------------------------------------------------------------------- |
86
- | `content` | `string` | **(required)** | Raw markdown content to render. |
87
- | `streaming` | `boolean` | `false` | Whether content is actively being streamed (e.g. from an LLM). |
88
- | `fontSize` | `number \| string` | `'0.9375rem'` | Base font size. Numbers are treated as pixels. |
89
- | `variant` | `AIMarkdownVariant` | `'default'` | Typography variant name. |
90
- | `colorScheme` | `AIMarkdownColorScheme` | `'light'` | Color scheme name (`'light'`, `'dark'`, or custom). |
91
- | `config` | `PartialDeep<TConfig>` | `undefined` | Partial render config, deep-merged with defaults. |
92
- | `defaultConfig` | `TConfig` | `defaultAIMarkdownRenderConfig` | Base config to merge against. Sub-packages can pass extended defaults. |
93
- | `metadata` | `TRenderData` | `undefined` | Arbitrary data passed to custom components via a dedicated context. |
94
- | `contentPreprocessors` | `AIMDContentPreprocessor[]` | `[]` | Additional preprocessors run after the built-in LaTeX preprocessor. |
95
- | `customComponents` | `AIMarkdownCustomComponents` | `undefined` | `react-markdown` component overrides for specific HTML elements. |
96
- | `Typography` | `AIMarkdownTypographyComponent` | `DefaultTypography` | Typography wrapper component. |
97
- | `ExtraStyles` | `AIMarkdownExtraStylesComponent` | `undefined` | Optional extra style wrapper rendered between typography and content. |
84
+ | Prop | Type | Default | Description |
85
+ | ---------------------- | -------------------------------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
86
+ | `content` | `string` | **(required)** | Raw markdown content to render. |
87
+ | `streaming` | `boolean` | `false` | Whether content is actively being streamed (e.g. from an LLM). |
88
+ | `fontSize` | `number \| string` | `'0.9375rem'` | Base font size. Numbers are treated as pixels. |
89
+ | `variant` | `AIMarkdownVariant` | `'default'` | Typography variant name. |
90
+ | `colorScheme` | `AIMarkdownColorScheme` | `'light'` | Color scheme name (`'light'`, `'dark'`, or custom). |
91
+ | `config` | `PartialDeep<TConfig>` | `undefined` | Partial render config, deep-merged with defaults. |
92
+ | `defaultConfig` | `TConfig` | `defaultAIMarkdownRenderConfig` | Base config to merge against. Sub-packages can pass extended defaults. |
93
+ | `metadata` | `TRenderData` | `undefined` | Arbitrary data passed to custom components via a dedicated context. |
94
+ | `contentPreprocessors` | `AIMDContentPreprocessor[]` | `[]` | Additional preprocessors run after the built-in LaTeX preprocessor. |
95
+ | `customComponents` | `AIMarkdownCustomComponents` | `undefined` | `react-markdown` component overrides for specific HTML elements. |
96
+ | `Typography` | `AIMarkdownTypographyComponent` | `DefaultTypography` | Typography wrapper component. |
97
+ | `ExtraStyles` | `AIMarkdownExtraStylesComponent` | `undefined` | Optional extra style wrapper rendered between typography and content. |
98
+ | `documentId` | `string` | auto via `useId()` | Stable id for the _logical markdown document_ this `<AIMarkdown>` is rendering. Used as the id namespace for clobberable attributes (`id`, hash hrefs) so two documents on the same page do not cross-link (footnote `[^1]` in message A won't scroll to `[^1]` in message B). When one document is split into chunks rendered by multiple `<AIMarkdown>` instances, pass the SAME `documentId` to every chunk so prefixes align. The value is passed through `encodeURIComponent` before being injected into HTML attributes, so any string is safe (React's `useId()` output, your own opaque ids, user-supplied UUIDs). |
98
99
 
99
100
  ## Configuration
100
101
 
@@ -108,7 +109,6 @@ Enable via `config.extraSyntaxSupported`. All are enabled by default.
108
109
  | --------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
109
110
  | `AIMarkdownRenderExtraSyntax.HIGHLIGHT` | `==Highlight==` syntax support |
110
111
  | `AIMarkdownRenderExtraSyntax.DEFINITION_LIST` | Definition list syntax ([PHP Markdown Extra](https://michelf.ca/projects/php-markdown/extra/#def-list)) |
111
- | `AIMarkdownRenderExtraSyntax.SUBSCRIPT` | Superscript (`^text^`) and subscript (`~text~`) |
112
112
 
113
113
  ### Display Optimization Abilities
114
114
 
@@ -137,7 +137,60 @@ import AIMarkdown, {
137
137
  />;
138
138
  ```
139
139
 
140
- 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.
140
+ 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.
141
+
142
+ ### Other Config Fields
143
+
144
+ | Field | Type | Default | Description |
145
+ | -------------------------- | --------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
146
+ | `blockMemoEnabled` | `boolean` | `true` | Enables block-level memoization: the renderer splits each document into per-block units and memoizes each block's React subtree by source identity, so unchanged blocks skip `toJsxRuntime` and React reconcile work during streaming. Output is byte-identical to the disabled path. Set `false` as an escape hatch for debugging. |
147
+ | `preserveOrphanReferences` | `boolean` | `true` | Protects orphan `[^x]: …` footnote definitions from being silently dropped by `mdast-util-to-hast` when no matching `[^x]` reference exists. Useful for streamed content where the reference may arrive in a later chunk. Inside `<AIMarkdownDocuments>`, the wrapper's `preserveOrphanReferences` prop overrides this field unconditionally. |
148
+
149
+ ## Cross-chunk Coordination
150
+
151
+ When a single logical markdown document is split across multiple
152
+ `<AIMarkdown>` instances (chunked streaming for chat UIs, etc.), wrap
153
+ them in `<AIMarkdownDocuments>` and pass the SAME `documentId` to every
154
+ chunk to coordinate footnotes, link references, and image references
155
+ across chunks:
156
+
157
+ ```tsx
158
+ import AIMarkdown, { AIMarkdownDocuments } from '@ai-react-markdown/core';
159
+
160
+ <AIMarkdownDocuments>
161
+ {message.chunks.map((c, i) => (
162
+ <AIMarkdown key={i} content={c} documentId={message.id} />
163
+ ))}
164
+ </AIMarkdownDocuments>;
165
+ ```
166
+
167
+ Without the wrapper, each `<AIMarkdown>` is independent — its
168
+ references resolve only within its own content (current standalone
169
+ behavior).
170
+
171
+ ### `<AIMarkdownDocuments>` Props
172
+
173
+ | Prop | Type | Default | Description |
174
+ | -------------------------- | ----------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
175
+ | `preserveOrphanReferences` | `boolean` | `true` | Controls orphan-reference protection for every chunk under this wrapper. Unconditionally overrides each chunk's `config.preserveOrphanReferences`. Does not gate cross-chunk coordination itself (that's gated by wrapper + `documentId`). |
176
+ | `children` | `ReactNode` | - | The `<AIMarkdown>` instances to coordinate. Nesting `<AIMarkdownDocuments>` inside another `<AIMarkdownDocuments>` throws. |
177
+
178
+ ### `useDocumentRegistry(documentId)`
179
+
180
+ Returns the cross-chunk `Registry` for the given `documentId`, or
181
+ `null` when called outside `<AIMarkdownDocuments>` or when
182
+ `documentId` is empty. The `Registry` shape is exported and stable
183
+ across minor versions — use it when writing typed helpers that operate
184
+ on the cross-chunk registry directly.
185
+
186
+ ```tsx
187
+ import { useDocumentRegistry, type Registry } from '@ai-react-markdown/core';
188
+
189
+ function MyHelper({ documentId }: { documentId: string }) {
190
+ const registry: Registry | null = useDocumentRegistry(documentId);
191
+ // null when no <AIMarkdownDocuments> ancestor — treat as "run standalone".
192
+ }
193
+ ```
141
194
 
142
195
  ## Hooks
143
196
 
@@ -160,13 +213,15 @@ function CustomCodeBlock({ children }: PropsWithChildren) {
160
213
 
161
214
  **Returns** `AIMarkdownRenderState<TConfig>`:
162
215
 
163
- | Field | Type | Description |
164
- | ------------- | ----------------------- | --------------------------------------------------- |
165
- | `streaming` | `boolean` | Whether content is being streamed. |
166
- | `fontSize` | `string` | Resolved CSS font-size value. |
167
- | `variant` | `AIMarkdownVariant` | Active typography variant. |
168
- | `colorScheme` | `AIMarkdownColorScheme` | Active color scheme. |
169
- | `config` | `TConfig` | Active render configuration (merged with defaults). |
216
+ | Field | Type | Description |
217
+ | --------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
218
+ | `streaming` | `boolean` | Whether content is being streamed. |
219
+ | `fontSize` | `string` | Resolved CSS font-size value. |
220
+ | `variant` | `AIMarkdownVariant` | Active typography variant. |
221
+ | `colorScheme` | `AIMarkdownColorScheme` | Active color scheme. |
222
+ | `documentId` | `string` | Stable id for the logical markdown document — caller-supplied or auto-generated via `useId()`. |
223
+ | `clobberPrefix` | `string` | URI-safe id prefix derived from `documentId`, used by every clobberable HTML attribute (`id=…` / `href="#…"`). Read this from the render state rather than recomputing locally when writing components that emit anchors. |
224
+ | `config` | `TConfig` | Active render configuration (merged with defaults). |
170
225
 
171
226
  ### `useAIMarkdownMetadata<TMetadata>()`
172
227
 
@@ -355,7 +410,7 @@ interface MyMetadata extends AIMarkdownMetadata {
355
410
  />;
356
411
  ```
357
412
 
358
- 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.
413
+ Sub-packages like `@ai-react-markdown/mantine` use this pattern to extend the base config with additional options (e.g. `codeBlock.defaultExpanded`, `codeBlock.autoDetectUnknownLanguage`) while inheriting all core functionality.
359
414
 
360
415
  Similarly, hooks accept generic parameters for type-safe access:
361
416
 
@@ -388,9 +443,14 @@ The metadata and render state providers are deliberately separated so that metad
388
443
 
389
444
  - `AIMarkdown` -- the main component (memoized)
390
445
 
446
+ ### Components
447
+
448
+ - `AIMarkdownDocuments` -- optional outer wrapper enabling cross-chunk coordination
449
+
391
450
  ### Types
392
451
 
393
452
  - `AIMarkdownProps`
453
+ - `AIMarkdownDocumentsProps`
394
454
  - `AIMarkdownCustomComponents`
395
455
  - `AIMarkdownRenderConfig`
396
456
  - `AIMarkdownRenderState`
@@ -403,6 +463,7 @@ The metadata and render state providers are deliberately separated so that metad
403
463
  - `AIMarkdownColorScheme`
404
464
  - `AIMDContentPreprocessor`
405
465
  - `PartialDeep`
466
+ - Cross-chunk registry types: `Registry`, `ChunkData`, `FootnoteDef`, `LinkDef`, `RefRecord`, `RefKind`
406
467
 
407
468
  ### Enums and Constants
408
469
 
@@ -414,6 +475,7 @@ The metadata and render state providers are deliberately separated so that metad
414
475
 
415
476
  - `useAIMarkdownRenderState()`
416
477
  - `useAIMarkdownMetadata()`
478
+ - `useDocumentRegistry()`
417
479
  - `useStableValue()`
418
480
 
419
481
  ## License