@incremark/core 0.0.4 → 0.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 CHANGED
@@ -8,6 +8,7 @@
8
8
 
9
9
  - 🚀 **增量解析** - 只解析新增内容,已完成的块不再重复处理
10
10
  - 🔄 **流式友好** - 专为 AI 流式输出场景设计
11
+ - ⌨️ **打字机效果** - 内置 BlockTransformer 实现逐字符显示
11
12
  - 🎯 **智能边界检测** - 准确识别 Markdown 块边界
12
13
  - 📦 **框架无关** - 可与任何前端框架配合使用
13
14
 
@@ -86,6 +87,70 @@ console.log(update.completed) // 已完成的块
86
87
 
87
88
  获取完整 AST。
88
89
 
90
+ ## BlockTransformer
91
+
92
+ 打字机效果控制器,作为解析器和渲染器之间的中间层。
93
+
94
+ ### 基本用法
95
+
96
+ ```ts
97
+ import { createBlockTransformer, defaultPlugins } from '@incremark/core'
98
+
99
+ const transformer = createBlockTransformer({
100
+ charsPerTick: 2, // 每次显示 2 个字符
101
+ tickInterval: 50, // 每 50ms 显示一次
102
+ plugins: defaultPlugins,
103
+ onChange: (displayBlocks) => {
104
+ // 更新 UI
105
+ render(displayBlocks)
106
+ }
107
+ })
108
+
109
+ // 推送源 blocks
110
+ transformer.push(sourceBlocks)
111
+
112
+ // 跳过动画
113
+ transformer.skip()
114
+
115
+ // 重置
116
+ transformer.reset()
117
+
118
+ // 销毁
119
+ transformer.destroy()
120
+ ```
121
+
122
+ ### 配置选项
123
+
124
+ ```ts
125
+ interface TransformerOptions {
126
+ charsPerTick?: number // 每次显示的字符数(默认:2)
127
+ tickInterval?: number // 显示间隔 ms(默认:50)
128
+ plugins?: TransformerPlugin[] // 插件列表
129
+ onChange?: (blocks: DisplayBlock[]) => void
130
+ }
131
+ ```
132
+
133
+ ### 插件系统
134
+
135
+ ```ts
136
+ import {
137
+ defaultPlugins, // 默认插件(图片、分隔线立即显示)
138
+ allPlugins, // 完整插件(代码块等整体显示)
139
+ codeBlockPlugin,
140
+ mermaidPlugin,
141
+ imagePlugin,
142
+ mathPlugin,
143
+ thematicBreakPlugin,
144
+ createPlugin
145
+ } from '@incremark/core'
146
+
147
+ // 自定义插件
148
+ const myPlugin = createPlugin('my-plugin',
149
+ (node) => node.type === 'myType',
150
+ { countChars: () => 1 }
151
+ )
152
+ ```
153
+
89
154
  ## 类型定义
90
155
 
91
156
  ```ts
@@ -97,6 +162,23 @@ interface ParsedBlock {
97
162
  endOffset: number
98
163
  rawText: string
99
164
  }
165
+
166
+ interface SourceBlock {
167
+ id: string
168
+ node: RootContent
169
+ status: 'pending' | 'stable' | 'completed'
170
+ meta?: unknown
171
+ }
172
+
173
+ interface DisplayBlock {
174
+ id: string
175
+ sourceNode: RootContent
176
+ displayNode: RootContent
177
+ displayedChars: number
178
+ totalChars: number
179
+ isDisplayComplete: boolean
180
+ meta?: unknown
181
+ }
100
182
  ```
101
183
 
102
184
  ## 与框架集成
@@ -107,4 +189,3 @@ interface ParsedBlock {
107
189
  ## License
108
190
 
109
191
  MIT
110
-
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { P as ParserOptions, I as IncrementalUpdate, a as ParsedBlock, b as ParserState } from './index-i_qABRHQ.js';
2
2
  export { c as BlockContext, B as BlockStatus, e as BlockTypeInfo, C as ContainerConfig, d as ContainerMatch, r as createInitialContext, o as detectContainer, p as detectContainerEnd, g as detectFenceEnd, f as detectFenceStart, q as isBlockBoundary, l as isBlockquoteStart, i as isEmptyLine, h as isHeading, m as isHtmlBlock, k as isListItemStart, n as isTableDelimiter, j as isThematicBreak, u as updateContext } from './index-i_qABRHQ.js';
3
- import { Root } from 'mdast';
3
+ import { Root, RootContent } from 'mdast';
4
4
  export { Root, RootContent } from 'mdast';
5
5
  export { calculateLineOffset, generateId, joinLines, resetIdCounter, splitLines } from './utils/index.js';
6
6
  import 'micromark-util-types';
@@ -92,4 +92,293 @@ declare class IncremarkParser {
92
92
  */
93
93
  declare function createIncremarkParser(options?: ParserOptions): IncremarkParser;
94
94
 
95
- export { IncremarkParser, IncrementalUpdate, ParsedBlock, ParserOptions, ParserState, createIncremarkParser };
95
+ /**
96
+ * 源 Block 类型(来自解析器)
97
+ */
98
+ interface SourceBlock<T = unknown> {
99
+ /** 唯一标识 */
100
+ id: string;
101
+ /** AST 节点 */
102
+ node: RootContent;
103
+ /** 块状态 */
104
+ status: 'pending' | 'stable' | 'completed';
105
+ /** 用户自定义元数据 */
106
+ meta?: T;
107
+ }
108
+ /**
109
+ * 显示用的 Block(转换后)
110
+ */
111
+ interface DisplayBlock<T = unknown> extends SourceBlock<T> {
112
+ /** 用于显示的 AST 节点(可能是截断的) */
113
+ displayNode: RootContent;
114
+ /** 显示进度 0-1 */
115
+ progress: number;
116
+ /** 是否已完成显示 */
117
+ isDisplayComplete: boolean;
118
+ }
119
+ /**
120
+ * 动画效果类型
121
+ * - 'none': 无动画效果
122
+ * - 'typing': 打字机光标效果(需配合 CSS)
123
+ */
124
+ type AnimationEffect = 'none' | 'typing';
125
+ /**
126
+ * Transformer 插件
127
+ */
128
+ interface TransformerPlugin {
129
+ /** 插件名称 */
130
+ name: string;
131
+ /**
132
+ * 判断是否处理此节点
133
+ * 返回 true 表示这个插件要处理此节点
134
+ */
135
+ match?: (node: RootContent) => boolean;
136
+ /**
137
+ * 自定义字符数计算
138
+ * 返回 undefined 则使用默认逻辑
139
+ * 返回 0 表示立即显示(不参与逐字符效果)
140
+ */
141
+ countChars?: (node: RootContent) => number | undefined;
142
+ /**
143
+ * 自定义截断逻辑
144
+ * @param node 原始节点
145
+ * @param displayedChars 当前应显示的字符数
146
+ * @param totalChars 该节点的总字符数
147
+ * @returns 截断后的节点,null 表示不显示
148
+ */
149
+ sliceNode?: (node: RootContent, displayedChars: number, totalChars: number) => RootContent | null;
150
+ /**
151
+ * 节点显示完成时的回调
152
+ */
153
+ onComplete?: (node: RootContent) => void;
154
+ }
155
+ /**
156
+ * Transformer 配置选项
157
+ */
158
+ interface TransformerOptions {
159
+ /**
160
+ * 每 tick 增加的字符数
161
+ * - number: 固定步长(默认 1)
162
+ * - [min, max]: 随机步长区间(更自然的打字效果)
163
+ */
164
+ charsPerTick?: number | [number, number];
165
+ /** tick 间隔 (ms),默认 20 */
166
+ tickInterval?: number;
167
+ /** 动画效果,默认 'none' */
168
+ effect?: AnimationEffect;
169
+ /** 插件列表 */
170
+ plugins?: TransformerPlugin[];
171
+ /** 状态变化回调 */
172
+ onChange?: (displayBlocks: DisplayBlock[]) => void;
173
+ /**
174
+ * 是否在页面不可见时自动暂停
175
+ * 默认 true,节省资源
176
+ */
177
+ pauseOnHidden?: boolean;
178
+ }
179
+ /**
180
+ * Transformer 内部状态
181
+ */
182
+ interface TransformerState<T = unknown> {
183
+ /** 已完成显示的 blocks */
184
+ completedBlocks: SourceBlock<T>[];
185
+ /** 当前正在显示的 block */
186
+ currentBlock: SourceBlock<T> | null;
187
+ /** 当前 block 已显示的字符数 */
188
+ currentProgress: number;
189
+ /** 等待显示的 blocks */
190
+ pendingBlocks: SourceBlock<T>[];
191
+ }
192
+
193
+ /**
194
+ * Block Transformer
195
+ *
196
+ * 用于控制 blocks 的逐步显示(打字机效果)
197
+ * 作为解析器和渲染器之间的中间层
198
+ *
199
+ * 特性:
200
+ * - 使用 requestAnimationFrame 实现流畅动画
201
+ * - 支持随机步长,模拟真实打字效果
202
+ * - 支持 typing 动画效果
203
+ * - 页面不可见时自动暂停,节省资源
204
+ * - 插件系统支持自定义节点处理
205
+ *
206
+ * @example
207
+ * ```typescript
208
+ * const transformer = new BlockTransformer({
209
+ * charsPerTick: [1, 3], // 随机 1-3 个字符
210
+ * tickInterval: 30,
211
+ * effect: 'typing',
212
+ * onChange: (displayBlocks) => {
213
+ * // 更新 UI
214
+ * }
215
+ * })
216
+ *
217
+ * // 推入新 blocks
218
+ * transformer.push(blocks)
219
+ *
220
+ * // 获取当前显示状态
221
+ * const displayBlocks = transformer.getDisplayBlocks()
222
+ * ```
223
+ */
224
+ declare class BlockTransformer<T = unknown> {
225
+ private state;
226
+ private options;
227
+ private rafId;
228
+ private lastTickTime;
229
+ private isRunning;
230
+ private isPaused;
231
+ private visibilityHandler;
232
+ constructor(options?: TransformerOptions);
233
+ /**
234
+ * 推入新的 blocks
235
+ * 会自动过滤已存在的 blocks
236
+ */
237
+ push(blocks: SourceBlock<T>[]): void;
238
+ /**
239
+ * 更新指定 block(用于 pending block 内容增加时)
240
+ */
241
+ update(block: SourceBlock<T>): void;
242
+ /**
243
+ * 跳过所有动画,直接显示全部内容
244
+ */
245
+ skip(): void;
246
+ /**
247
+ * 重置状态
248
+ */
249
+ reset(): void;
250
+ /**
251
+ * 暂停动画
252
+ */
253
+ pause(): void;
254
+ /**
255
+ * 恢复动画
256
+ */
257
+ resume(): void;
258
+ /**
259
+ * 获取用于渲染的 display blocks
260
+ */
261
+ getDisplayBlocks(): DisplayBlock<T>[];
262
+ /**
263
+ * 是否正在处理中
264
+ */
265
+ isProcessing(): boolean;
266
+ /**
267
+ * 是否已暂停
268
+ */
269
+ isPausedState(): boolean;
270
+ /**
271
+ * 获取内部状态(用于调试)
272
+ */
273
+ getState(): Readonly<TransformerState<T>>;
274
+ /**
275
+ * 动态更新配置
276
+ */
277
+ setOptions(options: Partial<Pick<TransformerOptions, 'charsPerTick' | 'tickInterval' | 'effect' | 'pauseOnHidden'>>): void;
278
+ /**
279
+ * 获取当前配置
280
+ */
281
+ getOptions(): {
282
+ charsPerTick: number | [number, number];
283
+ tickInterval: number;
284
+ effect: AnimationEffect;
285
+ };
286
+ /**
287
+ * 获取当前动画效果
288
+ */
289
+ getEffect(): AnimationEffect;
290
+ /**
291
+ * 销毁,清理资源
292
+ */
293
+ destroy(): void;
294
+ private getAllBlockIds;
295
+ private setupVisibilityHandler;
296
+ private removeVisibilityHandler;
297
+ private startIfNeeded;
298
+ private scheduleNextFrame;
299
+ private animationFrame;
300
+ private tick;
301
+ private getStep;
302
+ private processNext;
303
+ private cancelRaf;
304
+ private stop;
305
+ private emit;
306
+ private countChars;
307
+ private sliceNode;
308
+ private notifyComplete;
309
+ }
310
+ /**
311
+ * 创建 BlockTransformer 实例的工厂函数
312
+ */
313
+ declare function createBlockTransformer<T = unknown>(options?: TransformerOptions): BlockTransformer<T>;
314
+
315
+ /**
316
+ * 计算 AST 节点的总字符数
317
+ */
318
+ declare function countChars(node: RootContent): number;
319
+ /**
320
+ * 截断 AST 节点,只保留前 maxChars 个字符
321
+ *
322
+ * @param node 原始节点
323
+ * @param maxChars 最大字符数
324
+ * @returns 截断后的节点,如果 maxChars <= 0 返回 null
325
+ */
326
+ declare function sliceAst(node: RootContent, maxChars: number): RootContent | null;
327
+ /**
328
+ * 深拷贝 AST 节点
329
+ */
330
+ declare function cloneNode<T extends RootContent>(node: T): T;
331
+
332
+ /**
333
+ * 代码块插件:整体出现,不逐字符显示
334
+ *
335
+ * 注意:默认不启用,代码块默认参与打字机效果
336
+ * 如需整体显示代码块,可手动添加此插件
337
+ */
338
+ declare const codeBlockPlugin: TransformerPlugin;
339
+ /**
340
+ * Mermaid 图表插件:整体出现
341
+ *
342
+ * 注意:默认不启用,mermaid 默认参与打字机效果
343
+ * 如需整体显示 mermaid,可手动添加此插件
344
+ */
345
+ declare const mermaidPlugin: TransformerPlugin;
346
+ /**
347
+ * 图片插件:立即显示(不参与打字机效果)
348
+ * 图片没有文本内容,应立即显示
349
+ */
350
+ declare const imagePlugin: TransformerPlugin;
351
+ /**
352
+ * 数学公式插件:整体出现
353
+ *
354
+ * 注意:默认不启用,数学公式默认参与打字机效果
355
+ * 如需整体显示公式,可手动添加此插件
356
+ */
357
+ declare const mathPlugin: TransformerPlugin;
358
+ /**
359
+ * 分割线插件:立即显示
360
+ * 分隔线没有文本内容,应立即显示
361
+ */
362
+ declare const thematicBreakPlugin: TransformerPlugin;
363
+ /**
364
+ * 默认插件集合
365
+ *
366
+ * 只包含确实需要特殊处理的节点:
367
+ * - 图片:无文本内容,立即显示
368
+ * - 分隔线:无文本内容,立即显示
369
+ *
370
+ * 代码块、mermaid、数学公式默认参与打字机效果
371
+ * 如需整体显示,可手动添加对应插件
372
+ */
373
+ declare const defaultPlugins: TransformerPlugin[];
374
+ /**
375
+ * 完整插件集合(所有特殊节点整体显示)
376
+ * 包含代码块、mermaid、数学公式等的整体显示
377
+ */
378
+ declare const allPlugins: TransformerPlugin[];
379
+ /**
380
+ * 创建自定义插件的辅助函数
381
+ */
382
+ declare function createPlugin(name: string, matcher: (node: RootContent) => boolean, options?: Partial<Omit<TransformerPlugin, 'name' | 'match'>>): TransformerPlugin;
383
+
384
+ export { type AnimationEffect, BlockTransformer, type DisplayBlock, IncremarkParser, IncrementalUpdate, ParsedBlock, ParserOptions, ParserState, type SourceBlock, type TransformerOptions, type TransformerPlugin, type TransformerState, allPlugins, cloneNode, codeBlockPlugin, countChars, createBlockTransformer, createIncremarkParser, createPlugin, defaultPlugins, imagePlugin, mathPlugin, mermaidPlugin, sliceAst, thematicBreakPlugin };