markstream-react 0.0.50 → 0.0.52
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 +134 -104
- package/dist/{Tooltip-D786qxIk.js → Tooltip-Ux2h3oiV.js} +125 -125
- package/dist/{codeBlockExtraProps-7n9FWJXk.js → codeBlockExtraProps-NhTjbA1T.js} +1 -1
- package/dist/{index-o_DISWz2.js → index-DdaK6qko.js} +14 -14
- package/dist/index.css +1 -1
- package/dist/index.js +1 -1
- package/dist/index.px.css +1 -1
- package/dist/index.tailwind.css +1 -1
- package/dist/markstream-react.css +1 -1
- package/dist/next.d.ts +1 -2
- package/dist/next.js +1 -1
- package/dist/server.d.ts +41 -42
- package/dist/server.js +1 -1
- package/dist/tailwind.cjs +4 -0
- package/dist/tailwind.d.ts +2 -0
- package/dist/tailwind.js +2 -0
- package/dist/types/components/AdmonitionNode/AdmonitionNode.d.ts +2 -1
- package/dist/types/components/BlockquoteNode/BlockquoteNode.d.ts +2 -1
- package/dist/types/components/CheckboxNode/CheckboxNode.d.ts +2 -1
- package/dist/types/components/CodeBlockNode/CodeBlockNode.d.ts +2 -1
- package/dist/types/components/CodeBlockNode/PreCodeNode.d.ts +2 -1
- package/dist/types/components/D2BlockNode/D2BlockNode.d.ts +2 -1
- package/dist/types/components/DefinitionListNode/DefinitionListNode.d.ts +2 -1
- package/dist/types/components/EmojiNode/EmojiNode.d.ts +2 -1
- package/dist/types/components/EmphasisNode/EmphasisNode.d.ts +2 -1
- package/dist/types/components/FootnoteAnchorNode/FootnoteAnchorNode.d.ts +2 -1
- package/dist/types/components/FootnoteNode/FootnoteNode.d.ts +2 -1
- package/dist/types/components/FootnoteReferenceNode/FootnoteReferenceNode.d.ts +2 -1
- package/dist/types/components/HardBreakNode/HardBreakNode.d.ts +2 -1
- package/dist/types/components/HeadingNode/HeadingNode.d.ts +2 -1
- package/dist/types/components/HighlightNode/HighlightNode.d.ts +2 -1
- package/dist/types/components/HtmlBlockNode/HtmlBlockNode.d.ts +1 -1
- package/dist/types/components/HtmlInlineNode/HtmlInlineNode.d.ts +2 -1
- package/dist/types/components/ImageNode/ImageNode.d.ts +1 -1
- package/dist/types/components/InfographicBlockNode/InfographicBlockNode.d.ts +2 -1
- package/dist/types/components/InlineCodeNode/InlineCodeNode.d.ts +2 -1
- package/dist/types/components/InsertNode/InsertNode.d.ts +2 -1
- package/dist/types/components/LinkNode/LinkNode.d.ts +2 -1
- package/dist/types/components/ListItemNode/ListItemNode.d.ts +2 -1
- package/dist/types/components/ListNode/ListNode.d.ts +2 -1
- package/dist/types/components/MarkdownCodeBlockNode/MarkdownCodeBlockNode.d.ts +2 -1
- package/dist/types/components/Math/MathBlockNode.d.ts +1 -1
- package/dist/types/components/Math/MathInlineNode.d.ts +1 -1
- package/dist/types/components/MermaidBlockNode/MermaidBlockNode.d.ts +2 -1
- package/dist/types/components/NodeRenderer/FallbackComponent.d.ts +2 -1
- package/dist/types/components/ParagraphNode/ParagraphNode.d.ts +2 -1
- package/dist/types/components/ReferenceNode/ReferenceNode.d.ts +1 -1
- package/dist/types/components/StrikethroughNode/StrikethroughNode.d.ts +2 -1
- package/dist/types/components/StrongNode/StrongNode.d.ts +2 -1
- package/dist/types/components/SubscriptNode/SubscriptNode.d.ts +2 -1
- package/dist/types/components/SuperscriptNode/SuperscriptNode.d.ts +2 -1
- package/dist/types/components/TableNode/TableNode.d.ts +2 -1
- package/dist/types/components/TextNode/TextNode.d.ts +2 -1
- package/dist/types/components/ThematicBreakNode/ThematicBreakNode.d.ts +2 -1
- package/dist/types/components/VmrContainerNode/VmrContainerNode.d.ts +2 -1
- package/dist/types/context/viewportPriority.d.ts +1 -1
- package/dist/types/renderers/renderChildren.d.ts +1 -1
- package/dist/types/renderers/renderNode.d.ts +1 -1
- package/dist/types/server-renderer/index.d.ts +41 -41
- package/dist/types/styles.d.ts +1 -0
- package/package.json +39 -40
- package/dist/tailwind.ts +0 -3
package/README.md
CHANGED
|
@@ -1,166 +1,196 @@
|
|
|
1
1
|
# markstream-react
|
|
2
2
|
|
|
3
|
-
React renderer
|
|
3
|
+
React/Next.js streaming Markdown renderer for AI chat, SSE/WebSocket output, long AI responses, Mermaid, KaTeX, and code blocks.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`markstream-react` is the React renderer in the Markstream family. It renders raw Markdown strings with `content`, and it can also accept pre-parsed `nodes` when a worker or store already owns parsing.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
6
8
|
|
|
7
9
|
```bash
|
|
8
|
-
pnpm
|
|
10
|
+
pnpm add markstream-react
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
Optional features are peer dependencies. Install only what your Markdown output needs.
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
pnpm --filter markstream-react build
|
|
15
|
-
pnpm --filter markstream-react build:analyze
|
|
16
|
-
pnpm --filter markstream-react size:check
|
|
17
|
-
```
|
|
15
|
+
## Quick Start
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
Import one Markstream CSS file explicitly. The JavaScript entry does not inject styles automatically.
|
|
20
18
|
|
|
21
19
|
```tsx
|
|
22
|
-
import
|
|
20
|
+
import MarkdownRender from 'markstream-react'
|
|
23
21
|
import 'markstream-react/index.css'
|
|
24
22
|
|
|
25
|
-
export default function
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
export default function ChatMessage({
|
|
24
|
+
content,
|
|
25
|
+
isDone,
|
|
26
|
+
}: {
|
|
27
|
+
content: string
|
|
28
|
+
isDone: boolean
|
|
29
|
+
}) {
|
|
30
|
+
return <MarkdownRender content={content} final={isDone} fade={false} />
|
|
29
31
|
}
|
|
30
32
|
```
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
Use `markstream-react/index.px.css` instead when your app scales the root font size on mobile and you want renderer sizing to stay pixel-based.
|
|
35
|
+
|
|
36
|
+
## Streaming Example
|
|
37
|
+
|
|
38
|
+
For most SSE/WebSocket chat surfaces, accumulate the Markdown string and pass `content` plus `final`:
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import MarkdownRender from 'markstream-react'
|
|
42
|
+
import { useEffect, useState } from 'react'
|
|
43
|
+
import 'markstream-react/index.css'
|
|
44
|
+
|
|
45
|
+
export function ChatView() {
|
|
46
|
+
const [content, setContent] = useState('')
|
|
47
|
+
const [isDone, setIsDone] = useState(false)
|
|
48
|
+
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
const eventSource = new EventSource('/api/chat/stream')
|
|
51
|
+
eventSource.onmessage = (event) => {
|
|
52
|
+
if (event.data === '[DONE]') {
|
|
53
|
+
setIsDone(true)
|
|
54
|
+
eventSource.close()
|
|
55
|
+
return
|
|
56
|
+
}
|
|
33
57
|
|
|
34
|
-
|
|
58
|
+
const data = JSON.parse(event.data) as { content?: string }
|
|
59
|
+
setContent(prev => prev + (data.content ?? ''))
|
|
60
|
+
}
|
|
35
61
|
|
|
36
|
-
|
|
62
|
+
return () => eventSource.close()
|
|
63
|
+
}, [])
|
|
64
|
+
|
|
65
|
+
return <MarkdownRender content={content} final={isDone} fade={false} />
|
|
66
|
+
}
|
|
67
|
+
```
|
|
37
68
|
|
|
38
|
-
|
|
39
|
-
- Keep `viewportPriority` enabled unless you explicitly want eager rendering. Mermaid / Monaco / D2 blocks now stay idle while offscreen and resume when they approach the viewport.
|
|
69
|
+
If parsing is already external, pass `nodes`. Use a per-message parser id so generated code-block DOM ids stay unique across chat lists.
|
|
40
70
|
|
|
41
71
|
```tsx
|
|
42
|
-
import
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
72
|
+
import MarkdownRender from 'markstream-react'
|
|
73
|
+
import { useMemo } from 'react'
|
|
74
|
+
import { getMarkdown, parseMarkdownToStructure } from 'stream-markdown-parser'
|
|
75
|
+
|
|
76
|
+
export function ParsedChatMessage({
|
|
77
|
+
messageId,
|
|
78
|
+
content,
|
|
79
|
+
isDone,
|
|
80
|
+
}: {
|
|
81
|
+
messageId: string
|
|
82
|
+
content: string
|
|
83
|
+
isDone: boolean
|
|
84
|
+
}) {
|
|
85
|
+
const md = useMemo(() => getMarkdown(`chat-${messageId}`), [messageId])
|
|
86
|
+
const nodes = useMemo(
|
|
87
|
+
() => parseMarkdownToStructure(content, md, { final: isDone }),
|
|
88
|
+
[content, isDone, md],
|
|
52
89
|
)
|
|
90
|
+
|
|
91
|
+
return <MarkdownRender nodes={nodes} final={isDone} fade={false} />
|
|
53
92
|
}
|
|
54
93
|
```
|
|
55
94
|
|
|
56
|
-
##
|
|
95
|
+
## Next.js SSR
|
|
57
96
|
|
|
58
|
-
|
|
97
|
+
Import styles once from your app shell:
|
|
59
98
|
|
|
60
99
|
```tsx
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
mermaidProps={{
|
|
64
|
-
showHeader: false,
|
|
65
|
-
renderDebounceMs: 180,
|
|
66
|
-
previewPollDelayMs: 500,
|
|
67
|
-
}}
|
|
68
|
-
d2Props={{ progressiveIntervalMs: 500 }}
|
|
69
|
-
infographicProps={{ showHeader: false }}
|
|
70
|
-
/>
|
|
100
|
+
// app/layout.tsx or pages/_app.tsx
|
|
101
|
+
import 'markstream-react/index.css'
|
|
71
102
|
```
|
|
72
103
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
104
|
+
Use the root package in client components for live SSE/WebSocket streams:
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
'use client'
|
|
108
|
+
|
|
109
|
+
import MarkdownRender from 'markstream-react'
|
|
76
110
|
|
|
77
|
-
|
|
111
|
+
export function LiveMessage({ content, isDone }: { content: string, isDone: boolean }) {
|
|
112
|
+
return <MarkdownRender content={content} final={isDone} fade={false} />
|
|
113
|
+
}
|
|
114
|
+
```
|
|
78
115
|
|
|
79
|
-
|
|
116
|
+
Use `markstream-react/next` for SSR-first Markdown with client enhancement, or `markstream-react/server` for server-only rendering:
|
|
80
117
|
|
|
81
118
|
```tsx
|
|
82
|
-
import
|
|
83
|
-
import { setCustomComponents } from 'markstream-react'
|
|
119
|
+
import MarkdownRender from 'markstream-react/next'
|
|
84
120
|
|
|
85
|
-
function
|
|
86
|
-
return <
|
|
121
|
+
export default function Page() {
|
|
122
|
+
return <MarkdownRender content="# Server HTML first" final />
|
|
87
123
|
}
|
|
88
|
-
|
|
89
|
-
setCustomComponents('docs', {
|
|
90
|
-
echarts: EChartsBlockNode,
|
|
91
|
-
})
|
|
92
124
|
```
|
|
93
125
|
|
|
94
|
-
|
|
95
|
-
- `echarts` only catches fences whose language is `echarts`.
|
|
96
|
-
- Code block routing priority is exact language key -> built-in `mermaid` / `d2` / `infographic` routes -> `code_block`.
|
|
97
|
-
- Custom `mermaid` / `d2` / `infographic` overrides keep their specialized top-level props; other custom language keys use the normal custom component contract (`node`, `ctx`, `renderNode`, and friends).
|
|
126
|
+
## Optional Peers
|
|
98
127
|
|
|
99
|
-
|
|
128
|
+
| Feature | Package |
|
|
129
|
+
| --- | --- |
|
|
130
|
+
| Shiki code blocks | `stream-markdown` |
|
|
131
|
+
| Monaco editor code blocks | `stream-monaco` |
|
|
132
|
+
| Mermaid diagrams | `mermaid` |
|
|
133
|
+
| KaTeX math | `katex` |
|
|
134
|
+
| D2 diagrams | `@terrastruct/d2` |
|
|
135
|
+
| Infographic blocks | `@antv/infographic` |
|
|
100
136
|
|
|
101
|
-
|
|
137
|
+
KaTeX still needs its CSS in your app when math rendering is enabled:
|
|
102
138
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
- `previewPollMaxDelayMs`: cap for preview polling backoff.
|
|
107
|
-
- `previewPollMaxAttempts`: maximum retry count while the Mermaid source is still incomplete.
|
|
139
|
+
```tsx
|
|
140
|
+
import 'katex/dist/katex.min.css'
|
|
141
|
+
```
|
|
108
142
|
|
|
109
|
-
##
|
|
143
|
+
## Tailwind
|
|
110
144
|
|
|
111
|
-
-
|
|
112
|
-
- Infrequent language icons are split into an async chunk and loaded on demand.
|
|
113
|
-
- To avoid first-hit fallback icons, preload once when the app is idle:
|
|
145
|
+
Non-Tailwind projects should import the precompiled CSS:
|
|
114
146
|
|
|
115
147
|
```tsx
|
|
116
|
-
import
|
|
117
|
-
|
|
118
|
-
if (typeof window !== 'undefined')
|
|
119
|
-
void preloadExtendedLanguageIcons()
|
|
148
|
+
import 'markstream-react/index.css'
|
|
120
149
|
```
|
|
121
150
|
|
|
122
|
-
|
|
151
|
+
Tailwind projects can import the Tailwind-ready CSS and include the extracted class list in `tailwind.config.js`:
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
import 'markstream-react/index.tailwind.css'
|
|
155
|
+
```
|
|
123
156
|
|
|
124
|
-
|
|
125
|
-
|
|
157
|
+
```js
|
|
158
|
+
module.exports = {
|
|
159
|
+
content: [
|
|
160
|
+
'./src/**/*.{js,ts,jsx,tsx}',
|
|
161
|
+
require('markstream-react/tailwind'),
|
|
162
|
+
],
|
|
163
|
+
}
|
|
164
|
+
```
|
|
126
165
|
|
|
127
|
-
## Custom
|
|
166
|
+
## Custom Components
|
|
128
167
|
|
|
129
|
-
Custom tag-like blocks are exposed as nodes with `type
|
|
168
|
+
Register custom renderers with `setCustomComponents`. Custom tag-like blocks are exposed as nodes with `type` equal to the tag name when the parser is configured for that tag.
|
|
130
169
|
|
|
131
170
|
```tsx
|
|
132
171
|
import type { NodeComponentProps } from 'markstream-react'
|
|
133
|
-
import
|
|
172
|
+
import MarkdownRender, { setCustomComponents } from 'markstream-react'
|
|
134
173
|
|
|
135
174
|
function ThinkingNode(props: NodeComponentProps<{ type: 'thinking', content: string }>) {
|
|
136
|
-
|
|
137
|
-
return (
|
|
138
|
-
<div className="thinking-node">
|
|
139
|
-
<div className="thinking-title">Thinking</div>
|
|
140
|
-
<NodeRenderer
|
|
141
|
-
content={node.content}
|
|
142
|
-
customId={ctx?.customId}
|
|
143
|
-
isDark={ctx?.isDark}
|
|
144
|
-
typewriter={false}
|
|
145
|
-
batchRendering={false}
|
|
146
|
-
deferNodesUntilVisible={false}
|
|
147
|
-
viewportPriority={false}
|
|
148
|
-
maxLiveNodes={0}
|
|
149
|
-
/>
|
|
150
|
-
</div>
|
|
151
|
-
)
|
|
175
|
+
return <MarkdownRender content={props.node.content} fade={false} />
|
|
152
176
|
}
|
|
153
177
|
|
|
154
178
|
setCustomComponents('chat', { thinking: ThinkingNode })
|
|
155
179
|
```
|
|
156
180
|
|
|
157
|
-
##
|
|
181
|
+
## When Not to Use It
|
|
182
|
+
|
|
183
|
+
Use `react-markdown`, `marked`, or `markdown-it` when you only render short static Markdown, need the smallest possible Markdown stack, or already have a complete remark/rehype pipeline and do not need streaming mid-state handling.
|
|
184
|
+
|
|
185
|
+
## Type Exports
|
|
186
|
+
|
|
187
|
+
The package root exports the public component and renderer types, including `NodeRendererProps`, `NodeComponentProps`, `RenderContext`, `RenderNodeFn`, `CustomComponentMap`, and code-block option types.
|
|
158
188
|
|
|
159
|
-
|
|
189
|
+
## Development
|
|
160
190
|
|
|
161
|
-
|
|
162
|
-
-
|
|
163
|
-
-
|
|
164
|
-
-
|
|
165
|
-
-
|
|
166
|
-
|
|
191
|
+
```bash
|
|
192
|
+
pnpm --filter markstream-react dev
|
|
193
|
+
pnpm --filter markstream-react build
|
|
194
|
+
pnpm --filter markstream-react check:exports
|
|
195
|
+
pnpm --filter markstream-react size:check
|
|
196
|
+
```
|