@incremark/react 0.0.1 → 0.0.4
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.en.md +149 -0
- package/README.md +12 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +13 -0
- package/dist/styles.css +191 -0
- package/package.json +12 -5
package/README.en.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# @incremark/react
|
|
2
|
+
|
|
3
|
+
React 18+ integration for Incremark.
|
|
4
|
+
|
|
5
|
+
**[🇨🇳 中文](./README.md)** | 🇺🇸 English
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- 📦 **Out of the Box** - Provides `useIncremark` hook and `<Incremark>` component
|
|
10
|
+
- 🎨 **Customizable** - Support for custom render components
|
|
11
|
+
- ⚡ **High Performance** - Leverages React's reconciliation mechanism
|
|
12
|
+
- 🔧 **DevTools** - Built-in developer tools
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm add @incremark/core @incremark/react
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
**1. Import Styles**
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import '@incremark/react/styles.css'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**2. Use in Your Component**
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { useIncremark, Incremark } from '@incremark/react'
|
|
32
|
+
import '@incremark/react/styles.css'
|
|
33
|
+
|
|
34
|
+
function App() {
|
|
35
|
+
const { blocks, append, finalize, reset } = useIncremark({ gfm: true })
|
|
36
|
+
|
|
37
|
+
async function handleStream(stream: ReadableStream) {
|
|
38
|
+
reset()
|
|
39
|
+
const reader = stream.getReader()
|
|
40
|
+
const decoder = new TextDecoder()
|
|
41
|
+
|
|
42
|
+
while (true) {
|
|
43
|
+
const { done, value } = await reader.read()
|
|
44
|
+
if (done) break
|
|
45
|
+
append(decoder.decode(value))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
finalize()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<>
|
|
53
|
+
<button onClick={() => handleStream(stream)}>Start</button>
|
|
54
|
+
<Incremark blocks={blocks} />
|
|
55
|
+
</>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## API
|
|
61
|
+
|
|
62
|
+
### useIncremark(options)
|
|
63
|
+
|
|
64
|
+
Core hook.
|
|
65
|
+
|
|
66
|
+
**Returns:**
|
|
67
|
+
|
|
68
|
+
| Property | Type | Description |
|
|
69
|
+
|----------|------|-------------|
|
|
70
|
+
| `markdown` | `string` | Complete Markdown |
|
|
71
|
+
| `blocks` | `Block[]` | All blocks |
|
|
72
|
+
| `completedBlocks` | `Block[]` | Completed blocks |
|
|
73
|
+
| `pendingBlocks` | `Block[]` | Pending blocks |
|
|
74
|
+
| `append` | `Function` | Append content |
|
|
75
|
+
| `finalize` | `Function` | Complete parsing |
|
|
76
|
+
| `reset` | `Function` | Reset state |
|
|
77
|
+
| `render` | `Function` | Render once (reset + append + finalize) |
|
|
78
|
+
|
|
79
|
+
### useDevTools(incremark)
|
|
80
|
+
|
|
81
|
+
Enable DevTools.
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
const incremark = useIncremark()
|
|
85
|
+
useDevTools(incremark)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### \<Incremark\>
|
|
89
|
+
|
|
90
|
+
Render component.
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
<Incremark
|
|
94
|
+
blocks={blocks}
|
|
95
|
+
components={{ heading: MyHeading }}
|
|
96
|
+
/>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Custom Components
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
import { useIncremark, Incremark } from '@incremark/react'
|
|
103
|
+
import MyCode from './MyCode'
|
|
104
|
+
|
|
105
|
+
function App() {
|
|
106
|
+
const { blocks } = useIncremark()
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<Incremark
|
|
110
|
+
blocks={blocks}
|
|
111
|
+
components={{ code: MyCode }}
|
|
112
|
+
/>
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Integration with React Query
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
import { useQuery } from '@tanstack/react-query'
|
|
121
|
+
import { useIncremark, Incremark } from '@incremark/react'
|
|
122
|
+
|
|
123
|
+
function StreamingContent() {
|
|
124
|
+
const { blocks, append, finalize, reset } = useIncremark()
|
|
125
|
+
|
|
126
|
+
const { refetch } = useQuery({
|
|
127
|
+
queryKey: ['chat'],
|
|
128
|
+
queryFn: async () => {
|
|
129
|
+
reset()
|
|
130
|
+
// ... streaming handling
|
|
131
|
+
finalize()
|
|
132
|
+
return null
|
|
133
|
+
},
|
|
134
|
+
enabled: false
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<>
|
|
139
|
+
<button onClick={() => refetch()}>Start</button>
|
|
140
|
+
<Incremark blocks={blocks} />
|
|
141
|
+
</>
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## License
|
|
147
|
+
|
|
148
|
+
MIT
|
|
149
|
+
|
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Incremark 的 React 18+ 集成库。
|
|
4
4
|
|
|
5
|
+
🇨🇳 中文 | **[🇺🇸 English](./README.en.md)**
|
|
6
|
+
|
|
5
7
|
## 特性
|
|
6
8
|
|
|
7
9
|
- 📦 **开箱即用** - 提供 `useIncremark` hook 和 `<Incremark>` 组件
|
|
@@ -17,8 +19,17 @@ pnpm add @incremark/core @incremark/react
|
|
|
17
19
|
|
|
18
20
|
## 快速开始
|
|
19
21
|
|
|
22
|
+
**1. 引入样式**
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import '@incremark/react/styles.css'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**2. 在组件中使用**
|
|
29
|
+
|
|
20
30
|
```tsx
|
|
21
31
|
import { useIncremark, Incremark } from '@incremark/react'
|
|
32
|
+
import '@incremark/react/styles.css'
|
|
22
33
|
|
|
23
34
|
function App() {
|
|
24
35
|
const { blocks, append, finalize, reset } = useIncremark({ gfm: true })
|
|
@@ -63,6 +74,7 @@ function App() {
|
|
|
63
74
|
| `append` | `Function` | 追加内容 |
|
|
64
75
|
| `finalize` | `Function` | 完成解析 |
|
|
65
76
|
| `reset` | `Function` | 重置状态 |
|
|
77
|
+
| `render` | `Function` | 一次性渲染(reset + append + finalize) |
|
|
66
78
|
|
|
67
79
|
### useDevTools(incremark)
|
|
68
80
|
|
package/dist/index.d.ts
CHANGED
|
@@ -51,6 +51,8 @@ declare function useIncremark(options?: UseIncremarkOptions): {
|
|
|
51
51
|
abort: () => IncrementalUpdate;
|
|
52
52
|
/** 重置解析器 */
|
|
53
53
|
reset: () => void;
|
|
54
|
+
/** 一次性渲染(reset + append + finalize) */
|
|
55
|
+
render: (content: string) => IncrementalUpdate;
|
|
54
56
|
/** 解析器实例 */
|
|
55
57
|
parser: IncremarkParser;
|
|
56
58
|
};
|
package/dist/index.js
CHANGED
|
@@ -66,6 +66,17 @@ function useIncremark(options = {}) {
|
|
|
66
66
|
setMarkdown("");
|
|
67
67
|
setIsLoading(false);
|
|
68
68
|
}, [parser]);
|
|
69
|
+
const render = useCallback(
|
|
70
|
+
(content) => {
|
|
71
|
+
const update = parser.render(content);
|
|
72
|
+
setMarkdown(parser.getBuffer());
|
|
73
|
+
setCompletedBlocks(parser.getCompletedBlocks());
|
|
74
|
+
setPendingBlocks([]);
|
|
75
|
+
setIsLoading(false);
|
|
76
|
+
return update;
|
|
77
|
+
},
|
|
78
|
+
[parser]
|
|
79
|
+
);
|
|
69
80
|
return {
|
|
70
81
|
/** 已收集的完整 Markdown 字符串 */
|
|
71
82
|
markdown,
|
|
@@ -87,6 +98,8 @@ function useIncremark(options = {}) {
|
|
|
87
98
|
abort,
|
|
88
99
|
/** 重置解析器 */
|
|
89
100
|
reset,
|
|
101
|
+
/** 一次性渲染(reset + append + finalize) */
|
|
102
|
+
render,
|
|
90
103
|
/** 解析器实例 */
|
|
91
104
|
parser
|
|
92
105
|
};
|
package/dist/styles.css
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/* Incremark React 样式 */
|
|
2
|
+
|
|
3
|
+
/* 主容器 */
|
|
4
|
+
.incremark {
|
|
5
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
6
|
+
line-height: 1.6;
|
|
7
|
+
color: #333;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/* 块状态显示 */
|
|
11
|
+
.incremark-block.pending {
|
|
12
|
+
border-left: 3px solid #a855f7;
|
|
13
|
+
padding-left: 12px;
|
|
14
|
+
opacity: 0.8;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* 标题 */
|
|
18
|
+
.incremark-heading {
|
|
19
|
+
margin: 0.5em 0;
|
|
20
|
+
font-weight: 600;
|
|
21
|
+
line-height: 1.3;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.incremark-heading h1 {
|
|
25
|
+
font-size: 2em;
|
|
26
|
+
border-bottom: 1px solid #eee;
|
|
27
|
+
padding-bottom: 0.3em;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.incremark-heading h2 {
|
|
31
|
+
font-size: 1.5em;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.incremark-heading h3 {
|
|
35
|
+
font-size: 1.25em;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.incremark-heading h4 {
|
|
39
|
+
font-size: 1em;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.incremark-heading h5 {
|
|
43
|
+
font-size: 0.875em;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.incremark-heading h6 {
|
|
47
|
+
font-size: 0.85em;
|
|
48
|
+
color: #666;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* 段落 */
|
|
52
|
+
.incremark-paragraph {
|
|
53
|
+
margin: 0.75em 0;
|
|
54
|
+
line-height: 1.6;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* 行内代码 */
|
|
58
|
+
.incremark-inline-code {
|
|
59
|
+
padding: 0.2em 0.4em;
|
|
60
|
+
background: rgba(0, 0, 0, 0.06);
|
|
61
|
+
border-radius: 4px;
|
|
62
|
+
font-family: 'Fira Code', 'SF Mono', Consolas, monospace;
|
|
63
|
+
font-size: 0.9em;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* 代码块 */
|
|
67
|
+
.incremark-code {
|
|
68
|
+
margin: 1em 0;
|
|
69
|
+
border-radius: 8px;
|
|
70
|
+
overflow: hidden;
|
|
71
|
+
background: #24292e;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.incremark-code .code-header {
|
|
75
|
+
display: flex;
|
|
76
|
+
justify-content: space-between;
|
|
77
|
+
align-items: center;
|
|
78
|
+
padding: 8px 16px;
|
|
79
|
+
background: #1f2428;
|
|
80
|
+
border-bottom: 1px solid #30363d;
|
|
81
|
+
font-size: 12px;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.incremark-code .language {
|
|
85
|
+
color: #8b949e;
|
|
86
|
+
text-transform: uppercase;
|
|
87
|
+
font-weight: 500;
|
|
88
|
+
letter-spacing: 0.5px;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.incremark-code pre {
|
|
92
|
+
margin: 0;
|
|
93
|
+
padding: 16px;
|
|
94
|
+
overflow-x: auto;
|
|
95
|
+
background: transparent;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.incremark-code code {
|
|
99
|
+
font-family: 'Fira Code', 'SF Mono', 'Monaco', 'Consolas', monospace;
|
|
100
|
+
font-size: 14px;
|
|
101
|
+
line-height: 1.6;
|
|
102
|
+
color: #c9d1d9;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* 列表 */
|
|
106
|
+
.incremark-list {
|
|
107
|
+
margin: 0.75em 0;
|
|
108
|
+
padding-left: 2em;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.incremark-list li {
|
|
112
|
+
margin: 0.25em 0;
|
|
113
|
+
line-height: 1.6;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* 引用块 */
|
|
117
|
+
.incremark-blockquote {
|
|
118
|
+
margin: 1em 0;
|
|
119
|
+
padding: 0.5em 1em;
|
|
120
|
+
border-left: 4px solid #3b82f6;
|
|
121
|
+
background: #f0f7ff;
|
|
122
|
+
border-radius: 0 4px 4px 0;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.incremark-blockquote p {
|
|
126
|
+
margin: 0.5em 0;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.incremark-blockquote p:first-child {
|
|
130
|
+
margin-top: 0;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.incremark-blockquote p:last-child {
|
|
134
|
+
margin-bottom: 0;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* 表格 */
|
|
138
|
+
.incremark-table-wrapper {
|
|
139
|
+
overflow-x: auto;
|
|
140
|
+
margin: 1em 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.incremark-table {
|
|
144
|
+
width: 100%;
|
|
145
|
+
border-collapse: collapse;
|
|
146
|
+
font-size: 14px;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.incremark-table th,
|
|
150
|
+
.incremark-table td {
|
|
151
|
+
border: 1px solid #ddd;
|
|
152
|
+
padding: 10px 14px;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.incremark-table th {
|
|
156
|
+
background: #f8f9fa;
|
|
157
|
+
font-weight: 600;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.incremark-table tr:nth-child(even) {
|
|
161
|
+
background: #fafafa;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.incremark-table tr:hover {
|
|
165
|
+
background: #f0f0f0;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* 分隔线 */
|
|
169
|
+
.incremark-hr {
|
|
170
|
+
margin: 2em 0;
|
|
171
|
+
border: none;
|
|
172
|
+
border-top: 2px solid #e5e5e5;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* 未知类型 */
|
|
176
|
+
.incremark-unknown {
|
|
177
|
+
margin: 0.5em 0;
|
|
178
|
+
padding: 10px;
|
|
179
|
+
background: #fff3cd;
|
|
180
|
+
border: 1px solid #ffc107;
|
|
181
|
+
border-radius: 4px;
|
|
182
|
+
font-size: 12px;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.incremark-unknown pre {
|
|
186
|
+
margin: 0;
|
|
187
|
+
white-space: pre-wrap;
|
|
188
|
+
word-break: break-all;
|
|
189
|
+
font-size: 11px;
|
|
190
|
+
}
|
|
191
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@incremark/react",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Incremark React integration - Incremental Markdown parser for AI streaming",
|
|
6
6
|
"type": "module",
|
|
@@ -11,17 +11,18 @@
|
|
|
11
11
|
".": {
|
|
12
12
|
"import": "./dist/index.js",
|
|
13
13
|
"types": "./dist/index.d.ts"
|
|
14
|
-
}
|
|
14
|
+
},
|
|
15
|
+
"./styles.css": "./dist/styles.css"
|
|
15
16
|
},
|
|
16
17
|
"files": [
|
|
17
18
|
"dist"
|
|
18
19
|
],
|
|
19
20
|
"peerDependencies": {
|
|
20
21
|
"react": ">=18.0.0",
|
|
21
|
-
"@incremark/core": "0.0.
|
|
22
|
+
"@incremark/core": "0.0.4"
|
|
22
23
|
},
|
|
23
24
|
"dependencies": {
|
|
24
|
-
"@incremark/devtools": "0.0.
|
|
25
|
+
"@incremark/devtools": "0.0.4"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
28
|
"@types/react": "^18.2.0",
|
|
@@ -29,8 +30,14 @@
|
|
|
29
30
|
"tsup": "^8.0.0",
|
|
30
31
|
"typescript": "^5.3.0"
|
|
31
32
|
},
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/kingshuaishuai/incremark.git",
|
|
36
|
+
"directory": "packages/react"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://incremark-docs.vercel.app/",
|
|
32
39
|
"scripts": {
|
|
33
|
-
"build": "tsup",
|
|
40
|
+
"build": "tsup && cp src/styles.css dist/styles.css",
|
|
34
41
|
"dev": "tsup --watch"
|
|
35
42
|
}
|
|
36
43
|
}
|