pd-markdown 2.0.4-0 → 2.0.4-2
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 +36 -0
- package/package.json +10 -8
- package/packages/parser/dist/index.cjs +1 -1
- package/packages/parser/dist/plugins/transform/heading.mjs +1 -1
- package/packages/web/dist/MarkdownRenderer-BBUT3J9I.js +43 -0
- package/packages/web/dist/MarkdownRenderer-BBUT3J9I.js.map +1 -0
- package/packages/web/dist/client.cjs +2 -2
- package/packages/web/dist/components/MarkdownRenderer.mjs +1 -1
- package/packages/web/dist/components/StreamMarkdownRenderer.mjs +1 -1
- package/packages/web/dist/hooks/useMarkdown.mjs +1 -1
- package/packages/web/dist/hooks/useStreamMarkdown.mjs +1 -1
- package/packages/web/dist/index.cjs +3 -3
- package/packages/web/dist/index.d.ts +1 -1
- package/packages/web/dist/server.cjs +2 -2
- package/packages/web/dist/useStreamMarkdown-DYda9did.js +459 -0
- package/packages/web/dist/useStreamMarkdown-DYda9did.js.map +1 -0
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
- 📋 **Frontmatter** - 支持 YAML frontmatter 解析
|
|
11
11
|
- ⚛️ **React 组件** - 提供开箱即用的 React 渲染组件
|
|
12
12
|
- 🎨 **可定制** - 支持自定义组件覆盖(Heading, Code, Table 等)
|
|
13
|
+
- 🚀 **RSC & SSG 友好** - 完美支持 React Server Components,零水和 (Zero Hydration) 成本
|
|
13
14
|
- 🔗 **自动锚点** - 标题自动生成 slug 锚点
|
|
14
15
|
- 📦 **Tree-shakable** - 基于 ESM 设计,支持按需加载,最小化打包体积
|
|
15
16
|
- 🛠️ **现代兼容性** - 完美支持 Subpath Exports,确保在 Next.js、Vite 等现代开发环境下无缝解析
|
|
@@ -54,8 +55,36 @@ This is a **markdown** document.
|
|
|
54
55
|
}
|
|
55
56
|
```
|
|
56
57
|
|
|
58
|
+
### 在 Next.js Server Components (RSC) 中使用
|
|
59
|
+
|
|
60
|
+
`pd-markdown` 深度优化了服务端渲染场景。`MarkdownRenderer` 是一个 **Shared Component**,可以直接在服务端运行,生成纯 HTML,浏览器端**零 JS 负担**。
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
// app/page.tsx (Next.js Server Component)
|
|
64
|
+
import { getMarkdownAst } from './lib/markdown'
|
|
65
|
+
import { MarkdownRenderer } from 'pd-markdown/web'
|
|
66
|
+
|
|
67
|
+
export default async function Page() {
|
|
68
|
+
// 1. 服务端解析 Markdown 为 AST
|
|
69
|
+
const ast = await getMarkdownAst(content)
|
|
70
|
+
|
|
71
|
+
// 2. 服务端直接渲染为静态 HTML
|
|
72
|
+
return (
|
|
73
|
+
<main>
|
|
74
|
+
<MarkdownRenderer ast={ast} />
|
|
75
|
+
</main>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
> [!TIP]
|
|
81
|
+
> 这种模式完美支持 **SSG (静态站点生成)**,搜索引擎优化 (SEO) 友好且交互响应极快。
|
|
82
|
+
|
|
57
83
|
### 流式渲染 (AI 场景)
|
|
58
84
|
|
|
85
|
+
> [!NOTE]
|
|
86
|
+
> 流式渲染组件 (`StreamMarkdownRenderer`) 需要在客户端运行,已内置 `'use client'` 指令。
|
|
87
|
+
|
|
59
88
|
```tsx
|
|
60
89
|
import { StreamMarkdownRenderer, useStreamMarkdown } from 'pd-markdown/web'
|
|
61
90
|
|
|
@@ -164,6 +193,13 @@ import { traverseAst, findNodes, slugify } from 'pd-markdown/utils'
|
|
|
164
193
|
const headings = findNodes(ast, 'heading')
|
|
165
194
|
```
|
|
166
195
|
|
|
196
|
+
## 示例 (Demos)
|
|
197
|
+
|
|
198
|
+
你可以参考 `examples` 目录下的项目:
|
|
199
|
+
|
|
200
|
+
- **[web-demo](./examples/web-demo)**: 基础的 Vite/React 客户端渲染示例。
|
|
201
|
+
- **[nextjs-demo](./examples/nextjs-demo)**: 基于 Next.js 15 App Router 的 **Server Components (RSC)** 与 **SSG** 最佳实践示例。
|
|
202
|
+
|
|
167
203
|
## 开发
|
|
168
204
|
|
|
169
205
|
```bash
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pd-markdown",
|
|
3
|
-
"version": "2.0.4-
|
|
3
|
+
"version": "2.0.4-2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./packages/web/dist/index.cjs",
|
|
6
6
|
"module": "./packages/web/dist/index.mjs",
|
|
@@ -67,10 +67,7 @@
|
|
|
67
67
|
"remark-parse": "^11.0.0",
|
|
68
68
|
"unified": "^11.0.5",
|
|
69
69
|
"unist-util-visit": "^5.0.0",
|
|
70
|
-
"yaml": "^2.7.0"
|
|
71
|
-
"pd-markdown-parser": "0.1.0",
|
|
72
|
-
"pd-markdown-utils": "0.1.0",
|
|
73
|
-
"pd-markdown-web": "0.1.0"
|
|
70
|
+
"yaml": "^2.7.0"
|
|
74
71
|
},
|
|
75
72
|
"devDependencies": {
|
|
76
73
|
"@rollup/plugin-commonjs": "^28.0.2",
|
|
@@ -84,7 +81,10 @@
|
|
|
84
81
|
"rollup-plugin-dts": "^6.1.1",
|
|
85
82
|
"tslib": "^2.8.1",
|
|
86
83
|
"typescript": "^5.7.3",
|
|
87
|
-
"vitest": "^3.0.7"
|
|
84
|
+
"vitest": "^3.0.7",
|
|
85
|
+
"pd-markdown-parser": "0.1.0",
|
|
86
|
+
"pd-markdown-utils": "0.1.0",
|
|
87
|
+
"pd-markdown-web": "0.1.0"
|
|
88
88
|
},
|
|
89
89
|
"keywords": [
|
|
90
90
|
"markdown",
|
|
@@ -101,11 +101,13 @@
|
|
|
101
101
|
},
|
|
102
102
|
"sideEffects": false,
|
|
103
103
|
"scripts": {
|
|
104
|
-
"build": "pnpm -r run build",
|
|
104
|
+
"build": "pnpm -r --filter \"./packages/*\" run build",
|
|
105
|
+
"build:examples": "pnpm -r --filter \"./examples/*\" run build",
|
|
106
|
+
"build:all": "pnpm -r run build",
|
|
105
107
|
"test": "vitest run",
|
|
106
108
|
"test:watch": "vitest",
|
|
107
109
|
"test:coverage": "vitest run --coverage",
|
|
108
110
|
"typecheck": "tsc --noEmit",
|
|
109
|
-
"clean": "pnpm -r run clean"
|
|
111
|
+
"clean": "pnpm -r --filter \"./packages/*\" run clean"
|
|
110
112
|
}
|
|
111
113
|
}
|
|
@@ -6,7 +6,7 @@ var remarkGfm = require('remark-gfm');
|
|
|
6
6
|
var remarkFrontmatter = require('remark-frontmatter');
|
|
7
7
|
var unistUtilVisit = require('unist-util-visit');
|
|
8
8
|
var yaml = require('yaml');
|
|
9
|
-
var pdMarkdownUtils = require('pd-markdown
|
|
9
|
+
var pdMarkdownUtils = require('pd-markdown/utils');
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Extract text content from phrasing content nodes
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var pdMarkdownParser = require('pd-markdown/parser');
|
|
5
|
+
var NodeRenderer = require('./NodeRenderer-DTR-8m1G.js');
|
|
6
|
+
|
|
7
|
+
// Singleton parser for client-side use
|
|
8
|
+
let defaultParser = null;
|
|
9
|
+
function getParser(options) {
|
|
10
|
+
if (options) {
|
|
11
|
+
return pdMarkdownParser.createParser(options);
|
|
12
|
+
}
|
|
13
|
+
if (!defaultParser) {
|
|
14
|
+
defaultParser = pdMarkdownParser.createParser();
|
|
15
|
+
}
|
|
16
|
+
return defaultParser;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Main markdown renderer component
|
|
20
|
+
*
|
|
21
|
+
* Supports both client-side and server-side rendering:
|
|
22
|
+
* - Pass `source` for automatic parsing
|
|
23
|
+
* - Pass `ast` for pre-parsed content (SSR optimization)
|
|
24
|
+
*/
|
|
25
|
+
const MarkdownRenderer = ({ source, ast, components = {}, className, style, parserOptions, }) => {
|
|
26
|
+
// Use provided AST or parse source
|
|
27
|
+
let tree;
|
|
28
|
+
if (ast) {
|
|
29
|
+
tree = ast;
|
|
30
|
+
}
|
|
31
|
+
else if (source) {
|
|
32
|
+
const parser = getParser(parserOptions);
|
|
33
|
+
tree = parser.parse(source);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// No content provided
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return (jsxRuntime.jsx("div", { className: className, style: style, children: jsxRuntime.jsx(NodeRenderer.NodeRenderer, { node: tree, components: components }) }));
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
exports.MarkdownRenderer = MarkdownRenderer;
|
|
43
|
+
//# sourceMappingURL=MarkdownRenderer-BBUT3J9I.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MarkdownRenderer-BBUT3J9I.js","sources":["../src/components/MarkdownRenderer.tsx"],"sourcesContent":[null],"names":["createParser","_jsx","NodeRenderer"],"mappings":";;;;;;AAqBA;AACA,IAAI,aAAa,GAA2C,IAAI;AAEhE,SAAS,SAAS,CAAC,OAAuB,EAAA;IACxC,IAAI,OAAO,EAAE;AACX,QAAA,OAAOA,6BAAY,CAAC,OAAO,CAAC;IAC9B;IACA,IAAI,CAAC,aAAa,EAAE;QAClB,aAAa,GAAGA,6BAAY,EAAE;IAChC;AACA,IAAA,OAAO,aAAa;AACtB;AAEA;;;;;;AAMG;MACU,gBAAgB,GAA8B,CAAC,EAC1D,MAAM,EACN,GAAG,EACH,UAAU,GAAG,EAAE,EACf,SAAS,EACT,KAAK,EACL,aAAa,GACd,KAAI;;AAEH,IAAA,IAAI,IAAU;IACd,IAAI,GAAG,EAAE;QACP,IAAI,GAAG,GAAG;IACZ;SAAO,IAAI,MAAM,EAAE;AACjB,QAAA,MAAM,MAAM,GAAG,SAAS,CAAC,aAAa,CAAC;AACvC,QAAA,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;IAC7B;SAAO;;AAEL,QAAA,OAAO,IAAI;IACb;IAEA,QACEC,wBAAK,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAA,QAAA,EACrCA,cAAA,CAACC,yBAAY,EAAA,EAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAA,CAAI,EAAA,CAChD;AAEV;;;;"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var useStreamMarkdown = require('./useStreamMarkdown-
|
|
3
|
+
var useStreamMarkdown = require('./useStreamMarkdown-DYda9did.js');
|
|
4
4
|
require('react');
|
|
5
|
-
require('pd-markdown
|
|
5
|
+
require('pd-markdown/parser');
|
|
6
6
|
require('react/jsx-runtime');
|
|
7
7
|
require('./NodeRenderer-DTR-8m1G.js');
|
|
8
8
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { useRef, useState, useEffect, useMemo } from 'react';
|
|
3
|
-
import { createParser } from 'pd-markdown
|
|
3
|
+
import { createParser } from 'pd-markdown/parser';
|
|
4
4
|
import { NodeRenderer } from './NodeRenderer.mjs';
|
|
5
5
|
|
|
6
6
|
// ─── Styles ───────────────────────────────────────────────────────────
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var NodeRenderer = require('./NodeRenderer-DTR-8m1G.js');
|
|
4
|
-
var useStreamMarkdown = require('./useStreamMarkdown-
|
|
5
|
-
var MarkdownRenderer = require('./MarkdownRenderer-
|
|
4
|
+
var useStreamMarkdown = require('./useStreamMarkdown-DYda9did.js');
|
|
5
|
+
var MarkdownRenderer = require('./MarkdownRenderer-BBUT3J9I.js');
|
|
6
6
|
require('react/jsx-runtime');
|
|
7
7
|
require('react');
|
|
8
|
-
require('pd-markdown
|
|
8
|
+
require('pd-markdown/parser');
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { ReactNode, FC, CSSProperties } from 'react';
|
|
3
3
|
import { Heading as Heading$1, Paragraph as Paragraph$1, List as List$1, ListItem as ListItem$1, Table as Table$1, TableRow as TableRow$1, TableCell as TableCell$1, Code as Code$1, InlineCode, Link as Link$1, Image as Image$1, Blockquote as Blockquote$1, Root, Content } from 'mdast';
|
|
4
|
-
import { ParserOptions } from 'pd-markdown
|
|
4
|
+
import { ParserOptions } from 'pd-markdown/parser';
|
|
5
5
|
|
|
6
6
|
interface HeadingProps {
|
|
7
7
|
node: Heading$1;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var MarkdownRenderer = require('./MarkdownRenderer-
|
|
3
|
+
var MarkdownRenderer = require('./MarkdownRenderer-BBUT3J9I.js');
|
|
4
4
|
var NodeRenderer = require('./NodeRenderer-DTR-8m1G.js');
|
|
5
5
|
require('react/jsx-runtime');
|
|
6
|
-
require('pd-markdown
|
|
6
|
+
require('pd-markdown/parser');
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var pdMarkdownParser = require('pd-markdown/parser');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
var NodeRenderer = require('./NodeRenderer-DTR-8m1G.js');
|
|
7
|
+
|
|
8
|
+
// Cached parser instance
|
|
9
|
+
let cachedParser$1 = null;
|
|
10
|
+
function getParser$1(options) {
|
|
11
|
+
if (options) {
|
|
12
|
+
return pdMarkdownParser.createParser(options);
|
|
13
|
+
}
|
|
14
|
+
if (!cachedParser$1) {
|
|
15
|
+
cachedParser$1 = pdMarkdownParser.createParser();
|
|
16
|
+
}
|
|
17
|
+
return cachedParser$1;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Hook for parsing markdown on the client side
|
|
21
|
+
*
|
|
22
|
+
* @param source - Markdown source string
|
|
23
|
+
* @param options - Parser options
|
|
24
|
+
* @returns Parsed AST
|
|
25
|
+
*/
|
|
26
|
+
function useMarkdown(source, options) {
|
|
27
|
+
const ast = react.useMemo(() => {
|
|
28
|
+
const parser = getParser$1(options);
|
|
29
|
+
return parser.parse(source);
|
|
30
|
+
}, [source, options]);
|
|
31
|
+
return ast;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Context for passing configuration down the component tree
|
|
36
|
+
*/
|
|
37
|
+
const MarkdownContext = react.createContext({
|
|
38
|
+
components: {},
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* Hook to access markdown context
|
|
42
|
+
*/
|
|
43
|
+
function useMarkdownContext() {
|
|
44
|
+
return react.useContext(MarkdownContext);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ─── Styles ───────────────────────────────────────────────────────────
|
|
48
|
+
const cursorKeyframes = `
|
|
49
|
+
@keyframes pd-md-cursor-blink {
|
|
50
|
+
0%, 100% { opacity: 1; }
|
|
51
|
+
50% { opacity: 0; }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@keyframes pd-md-fade-in {
|
|
55
|
+
from { opacity: 0; transform: translateY(4px); }
|
|
56
|
+
to { opacity: 1; transform: translateY(0); }
|
|
57
|
+
}
|
|
58
|
+
`;
|
|
59
|
+
const cursorStyle = {
|
|
60
|
+
display: 'inline-block',
|
|
61
|
+
width: '2px',
|
|
62
|
+
height: '1.1em',
|
|
63
|
+
backgroundColor: 'currentColor',
|
|
64
|
+
marginLeft: '2px',
|
|
65
|
+
verticalAlign: 'text-bottom',
|
|
66
|
+
animation: 'pd-md-cursor-blink 1s step-end infinite',
|
|
67
|
+
};
|
|
68
|
+
// ─── Internal Parsed AST Hook ─────────────────────────────────────────
|
|
69
|
+
function useParsedAst(source, options) {
|
|
70
|
+
const parserRef = react.useRef(null);
|
|
71
|
+
const optionsRef = react.useRef(options);
|
|
72
|
+
if (!parserRef.current ||
|
|
73
|
+
JSON.stringify(optionsRef.current) !== JSON.stringify(options)) {
|
|
74
|
+
parserRef.current = pdMarkdownParser.createParser(options);
|
|
75
|
+
optionsRef.current = options;
|
|
76
|
+
}
|
|
77
|
+
return react.useMemo(() => {
|
|
78
|
+
try {
|
|
79
|
+
return parserRef.current.parse(source);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return { type: 'root', children: [] };
|
|
83
|
+
}
|
|
84
|
+
}, [source]);
|
|
85
|
+
}
|
|
86
|
+
// ─── Cursor Component ─────────────────────────────────────────────────
|
|
87
|
+
const StreamCursor = ({ customElement }) => {
|
|
88
|
+
if (customElement) {
|
|
89
|
+
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: customElement });
|
|
90
|
+
}
|
|
91
|
+
return jsxRuntime.jsx("span", { style: cursorStyle, "aria-hidden": "true", "data-streaming-cursor": true });
|
|
92
|
+
};
|
|
93
|
+
// ─── Main Component ──────────────────────────────────────────────────
|
|
94
|
+
/**
|
|
95
|
+
* StreamMarkdownRenderer — A streaming-aware markdown renderer.
|
|
96
|
+
*
|
|
97
|
+
* This component is designed for rendering AI-generated streaming markdown.
|
|
98
|
+
* It shows a blinking cursor at the end while content is being streamed,
|
|
99
|
+
* and optionally animates new content blocks as they appear.
|
|
100
|
+
*
|
|
101
|
+
* Usage patterns:
|
|
102
|
+
*
|
|
103
|
+
* 1. **With `useStreamMarkdown` hook** (recommended):
|
|
104
|
+
* ```tsx
|
|
105
|
+
* const stream = useStreamMarkdown()
|
|
106
|
+
* // ... consume stream
|
|
107
|
+
* <StreamMarkdownRenderer
|
|
108
|
+
* source={stream.source}
|
|
109
|
+
* ast={stream.ast}
|
|
110
|
+
* isStreaming={stream.isStreaming}
|
|
111
|
+
* />
|
|
112
|
+
* ```
|
|
113
|
+
*
|
|
114
|
+
* 2. **Standalone** (pass source, let it parse internally):
|
|
115
|
+
* ```tsx
|
|
116
|
+
* <StreamMarkdownRenderer
|
|
117
|
+
* source={accumulatedText}
|
|
118
|
+
* isStreaming={isLoading}
|
|
119
|
+
* />
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
const StreamMarkdownRenderer = ({ source, isStreaming = false, ast: externalAst, components = {}, className, style, parserOptions, showCursor = true, cursorElement, animationClassName, enableAnimation = true, }) => {
|
|
123
|
+
// Use external AST if provided, otherwise parse internally
|
|
124
|
+
const internalAst = useParsedAst(externalAst ? '' : source, parserOptions);
|
|
125
|
+
const ast = externalAst || internalAst;
|
|
126
|
+
// Track previous child count for animation
|
|
127
|
+
const prevChildCountRef = react.useRef(0);
|
|
128
|
+
const [animatingIndices, setAnimatingIndices] = react.useState(new Set());
|
|
129
|
+
// Detect new blocks for animation
|
|
130
|
+
react.useEffect(() => {
|
|
131
|
+
const currentCount = ast.children.length;
|
|
132
|
+
const prevCount = prevChildCountRef.current;
|
|
133
|
+
if (enableAnimation &&
|
|
134
|
+
isStreaming &&
|
|
135
|
+
currentCount > prevCount &&
|
|
136
|
+
prevCount > 0) {
|
|
137
|
+
const newIndices = new Set();
|
|
138
|
+
for (let i = prevCount; i < currentCount; i++) {
|
|
139
|
+
newIndices.add(i);
|
|
140
|
+
}
|
|
141
|
+
setAnimatingIndices(newIndices);
|
|
142
|
+
// Clear animation flags after animation completes
|
|
143
|
+
const timer = setTimeout(() => {
|
|
144
|
+
setAnimatingIndices(new Set());
|
|
145
|
+
}, 300);
|
|
146
|
+
prevChildCountRef.current = currentCount;
|
|
147
|
+
return () => clearTimeout(timer);
|
|
148
|
+
}
|
|
149
|
+
prevChildCountRef.current = currentCount;
|
|
150
|
+
}, [ast.children.length, enableAnimation, isStreaming]);
|
|
151
|
+
// Auto-scroll ref
|
|
152
|
+
const containerRef = react.useRef(null);
|
|
153
|
+
// Inject keyframe styles
|
|
154
|
+
react.useEffect(() => {
|
|
155
|
+
const styleId = 'pd-md-stream-styles';
|
|
156
|
+
if (!document.getElementById(styleId)) {
|
|
157
|
+
const styleEl = document.createElement('style');
|
|
158
|
+
styleEl.id = styleId;
|
|
159
|
+
styleEl.textContent = cursorKeyframes;
|
|
160
|
+
document.head.appendChild(styleEl);
|
|
161
|
+
}
|
|
162
|
+
}, []);
|
|
163
|
+
if (!source && !externalAst) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
const wrapperStyle = {
|
|
167
|
+
...style,
|
|
168
|
+
position: 'relative',
|
|
169
|
+
};
|
|
170
|
+
return (jsxRuntime.jsxs("div", { ref: containerRef, className: className, style: wrapperStyle, children: [ast.children.map((child, index) => {
|
|
171
|
+
const isNewBlock = animatingIndices.has(index);
|
|
172
|
+
const isLastBlock = index === ast.children.length - 1;
|
|
173
|
+
const blockStyle = enableAnimation && isNewBlock
|
|
174
|
+
? {
|
|
175
|
+
animation: 'pd-md-fade-in 0.3s ease-out forwards',
|
|
176
|
+
}
|
|
177
|
+
: {};
|
|
178
|
+
const blockClassName = isNewBlock
|
|
179
|
+
? animationClassName || undefined
|
|
180
|
+
: undefined;
|
|
181
|
+
return (jsxRuntime.jsxs("div", { style: blockStyle, className: blockClassName, "data-stream-block": isLastBlock && isStreaming ? 'active' : undefined, children: [jsxRuntime.jsx(NodeRenderer.NodeRenderer, { node: child, components: components }), showCursor && isStreaming && isLastBlock && (jsxRuntime.jsx(StreamCursor, { customElement: cursorElement }))] }, index));
|
|
182
|
+
}), showCursor && isStreaming && ast.children.length === 0 && (jsxRuntime.jsx(StreamCursor, { customElement: cursorElement }))] }));
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// Singleton parser cache
|
|
186
|
+
let cachedParser = null;
|
|
187
|
+
let cachedParserOptions;
|
|
188
|
+
function getParser(options) {
|
|
189
|
+
if (options !== cachedParserOptions ||
|
|
190
|
+
(options && JSON.stringify(options) !== JSON.stringify(cachedParserOptions))) {
|
|
191
|
+
cachedParser = pdMarkdownParser.createParser(options);
|
|
192
|
+
cachedParserOptions = options;
|
|
193
|
+
}
|
|
194
|
+
if (!cachedParser) {
|
|
195
|
+
cachedParser = pdMarkdownParser.createParser(options);
|
|
196
|
+
cachedParserOptions = options;
|
|
197
|
+
}
|
|
198
|
+
return cachedParser;
|
|
199
|
+
}
|
|
200
|
+
const EMPTY_AST = { type: 'root', children: [] };
|
|
201
|
+
/**
|
|
202
|
+
* Hook for streaming markdown rendering.
|
|
203
|
+
*
|
|
204
|
+
* Provides a simple API to progressively append markdown text,
|
|
205
|
+
* automatically re-parsing into an AST that can be rendered
|
|
206
|
+
* by the MarkdownRenderer.
|
|
207
|
+
*
|
|
208
|
+
* Supports multiple consumption methods:
|
|
209
|
+
* - Manual `append()` + `done()` calls
|
|
210
|
+
* - `consume(readableStream)` for ReadableStream<string>
|
|
211
|
+
* - `consumeIterator(asyncIterable)` for async iterators
|
|
212
|
+
* - `consumeResponse(response)` for SSE/fetch responses
|
|
213
|
+
*/
|
|
214
|
+
function useStreamMarkdown(options = {}) {
|
|
215
|
+
const { parserOptions, onStart, onChunk, onDone, onError, parseDebounceMs = 50, } = options;
|
|
216
|
+
const [state, setState] = react.useState({
|
|
217
|
+
source: '',
|
|
218
|
+
ast: EMPTY_AST,
|
|
219
|
+
isStreaming: false,
|
|
220
|
+
isDone: false,
|
|
221
|
+
error: null,
|
|
222
|
+
});
|
|
223
|
+
const sourceRef = react.useRef('');
|
|
224
|
+
const isStreamingRef = react.useRef(false);
|
|
225
|
+
const parseTimerRef = react.useRef(null);
|
|
226
|
+
const abortControllerRef = react.useRef(null);
|
|
227
|
+
// Parse the current source and update AST
|
|
228
|
+
const parseSource = react.useCallback((source) => {
|
|
229
|
+
try {
|
|
230
|
+
const parser = getParser(parserOptions);
|
|
231
|
+
const ast = parser.parse(source);
|
|
232
|
+
setState((prev) => ({ ...prev, source, ast }));
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
// If parsing fails (e.g., incomplete markdown), keep previous AST
|
|
236
|
+
setState((prev) => ({ ...prev, source }));
|
|
237
|
+
}
|
|
238
|
+
}, [parserOptions]);
|
|
239
|
+
// Debounced parse
|
|
240
|
+
const debouncedParse = react.useCallback((source) => {
|
|
241
|
+
if (parseTimerRef.current) {
|
|
242
|
+
clearTimeout(parseTimerRef.current);
|
|
243
|
+
}
|
|
244
|
+
parseTimerRef.current = setTimeout(() => {
|
|
245
|
+
parseSource(source);
|
|
246
|
+
}, parseDebounceMs);
|
|
247
|
+
}, [parseSource, parseDebounceMs]);
|
|
248
|
+
// Append a chunk
|
|
249
|
+
const append = react.useCallback((chunk) => {
|
|
250
|
+
if (!isStreamingRef.current) {
|
|
251
|
+
isStreamingRef.current = true;
|
|
252
|
+
setState((prev) => ({
|
|
253
|
+
...prev,
|
|
254
|
+
isStreaming: true,
|
|
255
|
+
isDone: false,
|
|
256
|
+
error: null,
|
|
257
|
+
}));
|
|
258
|
+
onStart?.();
|
|
259
|
+
}
|
|
260
|
+
sourceRef.current += chunk;
|
|
261
|
+
const currentSource = sourceRef.current;
|
|
262
|
+
onChunk?.(chunk, currentSource);
|
|
263
|
+
debouncedParse(currentSource);
|
|
264
|
+
}, [debouncedParse, onStart, onChunk]);
|
|
265
|
+
// Signal completion
|
|
266
|
+
const done = react.useCallback(() => {
|
|
267
|
+
if (parseTimerRef.current) {
|
|
268
|
+
clearTimeout(parseTimerRef.current);
|
|
269
|
+
}
|
|
270
|
+
// Final parse with complete source
|
|
271
|
+
const finalSource = sourceRef.current;
|
|
272
|
+
parseSource(finalSource);
|
|
273
|
+
isStreamingRef.current = false;
|
|
274
|
+
setState((prev) => ({
|
|
275
|
+
...prev,
|
|
276
|
+
isStreaming: false,
|
|
277
|
+
isDone: true,
|
|
278
|
+
}));
|
|
279
|
+
onDone?.(finalSource);
|
|
280
|
+
}, [parseSource, onDone]);
|
|
281
|
+
// Reset state
|
|
282
|
+
const reset = react.useCallback(() => {
|
|
283
|
+
if (parseTimerRef.current) {
|
|
284
|
+
clearTimeout(parseTimerRef.current);
|
|
285
|
+
}
|
|
286
|
+
if (abortControllerRef.current) {
|
|
287
|
+
abortControllerRef.current.abort();
|
|
288
|
+
}
|
|
289
|
+
sourceRef.current = '';
|
|
290
|
+
isStreamingRef.current = false;
|
|
291
|
+
setState({
|
|
292
|
+
source: '',
|
|
293
|
+
ast: EMPTY_AST,
|
|
294
|
+
isStreaming: false,
|
|
295
|
+
isDone: false,
|
|
296
|
+
error: null,
|
|
297
|
+
});
|
|
298
|
+
}, []);
|
|
299
|
+
// Consume a ReadableStream<string>
|
|
300
|
+
const consume = react.useCallback(async (stream) => {
|
|
301
|
+
reset();
|
|
302
|
+
const reader = stream.getReader();
|
|
303
|
+
const controller = new AbortController();
|
|
304
|
+
abortControllerRef.current = controller;
|
|
305
|
+
try {
|
|
306
|
+
while (true) {
|
|
307
|
+
if (controller.signal.aborted)
|
|
308
|
+
break;
|
|
309
|
+
const { done: readerDone, value } = await reader.read();
|
|
310
|
+
if (readerDone)
|
|
311
|
+
break;
|
|
312
|
+
if (value)
|
|
313
|
+
append(value);
|
|
314
|
+
}
|
|
315
|
+
if (!controller.signal.aborted)
|
|
316
|
+
done();
|
|
317
|
+
}
|
|
318
|
+
catch (err) {
|
|
319
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
320
|
+
setState((prev) => ({ ...prev, error, isStreaming: false }));
|
|
321
|
+
onError?.(error);
|
|
322
|
+
}
|
|
323
|
+
finally {
|
|
324
|
+
reader.releaseLock();
|
|
325
|
+
}
|
|
326
|
+
}, [reset, append, done, onError]);
|
|
327
|
+
// Consume an async iterator
|
|
328
|
+
const consumeIterator = react.useCallback(async (iterator) => {
|
|
329
|
+
reset();
|
|
330
|
+
const controller = new AbortController();
|
|
331
|
+
abortControllerRef.current = controller;
|
|
332
|
+
try {
|
|
333
|
+
for await (const chunk of iterator) {
|
|
334
|
+
if (controller.signal.aborted)
|
|
335
|
+
break;
|
|
336
|
+
append(chunk);
|
|
337
|
+
}
|
|
338
|
+
if (!controller.signal.aborted)
|
|
339
|
+
done();
|
|
340
|
+
}
|
|
341
|
+
catch (err) {
|
|
342
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
343
|
+
setState((prev) => ({ ...prev, error, isStreaming: false }));
|
|
344
|
+
onError?.(error);
|
|
345
|
+
}
|
|
346
|
+
}, [reset, append, done, onError]);
|
|
347
|
+
// Consume a fetch Response (SSE format)
|
|
348
|
+
const consumeResponse = react.useCallback(async (response, opts) => {
|
|
349
|
+
if (!response.body) {
|
|
350
|
+
throw new Error('Response has no body');
|
|
351
|
+
}
|
|
352
|
+
if (!response.ok) {
|
|
353
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
354
|
+
}
|
|
355
|
+
reset();
|
|
356
|
+
const controller = new AbortController();
|
|
357
|
+
abortControllerRef.current = controller;
|
|
358
|
+
const reader = response.body.getReader();
|
|
359
|
+
const decoder = new TextDecoder();
|
|
360
|
+
const extractContent = opts?.extractContent ??
|
|
361
|
+
((data) => {
|
|
362
|
+
// Default: try to extract from SSE "data: ..." lines
|
|
363
|
+
// or OpenAI-style streaming content
|
|
364
|
+
try {
|
|
365
|
+
const parsed = JSON.parse(data);
|
|
366
|
+
// OpenAI format
|
|
367
|
+
if (parsed.choices?.[0]?.delta?.content !== undefined) {
|
|
368
|
+
return parsed.choices[0].delta.content;
|
|
369
|
+
}
|
|
370
|
+
// Generic content field
|
|
371
|
+
if (typeof parsed.content === 'string') {
|
|
372
|
+
return parsed.content;
|
|
373
|
+
}
|
|
374
|
+
if (typeof parsed.text === 'string') {
|
|
375
|
+
return parsed.text;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
catch {
|
|
379
|
+
// Not JSON, return as-is
|
|
380
|
+
}
|
|
381
|
+
return data;
|
|
382
|
+
});
|
|
383
|
+
try {
|
|
384
|
+
let buffer = '';
|
|
385
|
+
while (true) {
|
|
386
|
+
if (controller.signal.aborted)
|
|
387
|
+
break;
|
|
388
|
+
const { done: readerDone, value } = await reader.read();
|
|
389
|
+
if (readerDone)
|
|
390
|
+
break;
|
|
391
|
+
buffer += decoder.decode(value, { stream: true });
|
|
392
|
+
const lines = buffer.split('\n');
|
|
393
|
+
buffer = lines.pop() || ''; // Keep incomplete line in buffer
|
|
394
|
+
for (const line of lines) {
|
|
395
|
+
const trimmed = line.trim();
|
|
396
|
+
if (!trimmed)
|
|
397
|
+
continue;
|
|
398
|
+
if (trimmed === 'data: [DONE]')
|
|
399
|
+
continue;
|
|
400
|
+
let data = trimmed;
|
|
401
|
+
if (trimmed.startsWith('data: ')) {
|
|
402
|
+
data = trimmed.slice(6);
|
|
403
|
+
}
|
|
404
|
+
const content = extractContent(data);
|
|
405
|
+
if (content !== null && content !== '') {
|
|
406
|
+
append(content);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
// Process remaining buffer
|
|
411
|
+
if (buffer.trim()) {
|
|
412
|
+
const data = buffer.trim().startsWith('data: ')
|
|
413
|
+
? buffer.trim().slice(6)
|
|
414
|
+
: buffer.trim();
|
|
415
|
+
const content = extractContent(data);
|
|
416
|
+
if (content !== null && content !== '') {
|
|
417
|
+
append(content);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
if (!controller.signal.aborted)
|
|
421
|
+
done();
|
|
422
|
+
}
|
|
423
|
+
catch (err) {
|
|
424
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
425
|
+
setState((prev) => ({ ...prev, error, isStreaming: false }));
|
|
426
|
+
onError?.(error);
|
|
427
|
+
}
|
|
428
|
+
finally {
|
|
429
|
+
reader.releaseLock();
|
|
430
|
+
}
|
|
431
|
+
}, [reset, append, done, onError]);
|
|
432
|
+
// Cleanup on unmount
|
|
433
|
+
react.useEffect(() => {
|
|
434
|
+
return () => {
|
|
435
|
+
if (parseTimerRef.current) {
|
|
436
|
+
clearTimeout(parseTimerRef.current);
|
|
437
|
+
}
|
|
438
|
+
if (abortControllerRef.current) {
|
|
439
|
+
abortControllerRef.current.abort();
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
}, []);
|
|
443
|
+
return {
|
|
444
|
+
...state,
|
|
445
|
+
append,
|
|
446
|
+
done,
|
|
447
|
+
reset,
|
|
448
|
+
consume,
|
|
449
|
+
consumeIterator,
|
|
450
|
+
consumeResponse,
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
exports.MarkdownContext = MarkdownContext;
|
|
455
|
+
exports.StreamMarkdownRenderer = StreamMarkdownRenderer;
|
|
456
|
+
exports.useMarkdown = useMarkdown;
|
|
457
|
+
exports.useMarkdownContext = useMarkdownContext;
|
|
458
|
+
exports.useStreamMarkdown = useStreamMarkdown;
|
|
459
|
+
//# sourceMappingURL=useStreamMarkdown-DYda9did.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useStreamMarkdown-DYda9did.js","sources":["../src/hooks/useMarkdown.ts","../src/components/context.ts","../src/components/StreamMarkdownRenderer.tsx","../src/hooks/useStreamMarkdown.ts"],"sourcesContent":[null,null,null,null],"names":["cachedParser","getParser","createParser","useMemo","createContext","useContext","useRef","_jsx","_Fragment","useState","useEffect","_jsxs","NodeRenderer","useCallback"],"mappings":"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"}
|