@incremark/solid 0.3.3

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.
Files changed (82) hide show
  1. package/LICENSE +22 -0
  2. package/README.en.md +278 -0
  3. package/README.md +278 -0
  4. package/dist/components/AutoScrollContainer.d.ts +17 -0
  5. package/dist/components/AutoScrollContainer.d.ts.map +1 -0
  6. package/dist/components/CachedCodeRenderer.d.ts +12 -0
  7. package/dist/components/CachedCodeRenderer.d.ts.map +1 -0
  8. package/dist/components/ConfigProvider.d.ts +17 -0
  9. package/dist/components/ConfigProvider.d.ts.map +1 -0
  10. package/dist/components/Incremark.d.ts +35 -0
  11. package/dist/components/Incremark.d.ts.map +1 -0
  12. package/dist/components/IncremarkBlockquote.d.ts +7 -0
  13. package/dist/components/IncremarkBlockquote.d.ts.map +1 -0
  14. package/dist/components/IncremarkCode.d.ts +26 -0
  15. package/dist/components/IncremarkCode.d.ts.map +1 -0
  16. package/dist/components/IncremarkCodeDefault.d.ts +15 -0
  17. package/dist/components/IncremarkCodeDefault.d.ts.map +1 -0
  18. package/dist/components/IncremarkCodeMermaid.d.ts +14 -0
  19. package/dist/components/IncremarkCodeMermaid.d.ts.map +1 -0
  20. package/dist/components/IncremarkContainer.d.ts +22 -0
  21. package/dist/components/IncremarkContainer.d.ts.map +1 -0
  22. package/dist/components/IncremarkContent.d.ts +10 -0
  23. package/dist/components/IncremarkContent.d.ts.map +1 -0
  24. package/dist/components/IncremarkDefault.d.ts +11 -0
  25. package/dist/components/IncremarkDefault.d.ts.map +1 -0
  26. package/dist/components/IncremarkFootnotes.d.ts +10 -0
  27. package/dist/components/IncremarkFootnotes.d.ts.map +1 -0
  28. package/dist/components/IncremarkHeading.d.ts +7 -0
  29. package/dist/components/IncremarkHeading.d.ts.map +1 -0
  30. package/dist/components/IncremarkHtmlElement.d.ts +26 -0
  31. package/dist/components/IncremarkHtmlElement.d.ts.map +1 -0
  32. package/dist/components/IncremarkInline.d.ts +7 -0
  33. package/dist/components/IncremarkInline.d.ts.map +1 -0
  34. package/dist/components/IncremarkList.d.ts +7 -0
  35. package/dist/components/IncremarkList.d.ts.map +1 -0
  36. package/dist/components/IncremarkMath.d.ts +16 -0
  37. package/dist/components/IncremarkMath.d.ts.map +1 -0
  38. package/dist/components/IncremarkParagraph.d.ts +7 -0
  39. package/dist/components/IncremarkParagraph.d.ts.map +1 -0
  40. package/dist/components/IncremarkRenderer.d.ts +20 -0
  41. package/dist/components/IncremarkRenderer.d.ts.map +1 -0
  42. package/dist/components/IncremarkTable.d.ts +7 -0
  43. package/dist/components/IncremarkTable.d.ts.map +1 -0
  44. package/dist/components/IncremarkThematicBreak.d.ts +7 -0
  45. package/dist/components/IncremarkThematicBreak.d.ts.map +1 -0
  46. package/dist/components/SvgIcon.d.ts +14 -0
  47. package/dist/components/SvgIcon.d.ts.map +1 -0
  48. package/dist/components/ThemeProvider.d.ts +17 -0
  49. package/dist/components/ThemeProvider.d.ts.map +1 -0
  50. package/dist/components/index.d.ts +47 -0
  51. package/dist/components/index.d.ts.map +1 -0
  52. package/dist/composables/index.d.ts +10 -0
  53. package/dist/composables/index.d.ts.map +1 -0
  54. package/dist/composables/useBlockTransformer.d.ts +33 -0
  55. package/dist/composables/useBlockTransformer.d.ts.map +1 -0
  56. package/dist/composables/useDefinationsContext.d.ts +7 -0
  57. package/dist/composables/useDefinationsContext.d.ts.map +1 -0
  58. package/dist/composables/useDevTools.d.ts +35 -0
  59. package/dist/composables/useDevTools.d.ts.map +1 -0
  60. package/dist/composables/useIncremark.d.ts +84 -0
  61. package/dist/composables/useIncremark.d.ts.map +1 -0
  62. package/dist/composables/useLocale.d.ts +2 -0
  63. package/dist/composables/useLocale.d.ts.map +1 -0
  64. package/dist/composables/useProvideDefinations.d.ts +36 -0
  65. package/dist/composables/useProvideDefinations.d.ts.map +1 -0
  66. package/dist/composables/useShiki.d.ts +71 -0
  67. package/dist/composables/useShiki.d.ts.map +1 -0
  68. package/dist/composables/useStreamRenderer.d.ts +25 -0
  69. package/dist/composables/useStreamRenderer.d.ts.map +1 -0
  70. package/dist/composables/useTypewriter.d.ts +48 -0
  71. package/dist/composables/useTypewriter.d.ts.map +1 -0
  72. package/dist/index.d.ts +17 -0
  73. package/dist/index.d.ts.map +1 -0
  74. package/dist/index.js +2123 -0
  75. package/dist/index.js.map +1 -0
  76. package/dist/types.d.ts +27 -0
  77. package/dist/types.d.ts.map +1 -0
  78. package/dist/utils/animatedChunks.d.ts +20 -0
  79. package/dist/utils/animatedChunks.d.ts.map +1 -0
  80. package/dist/utils/cursor.d.ts +9 -0
  81. package/dist/utils/cursor.d.ts.map +1 -0
  82. package/package.json +74 -0
package/dist/index.js ADDED
@@ -0,0 +1,2123 @@
1
+ // src/composables/useIncremark.ts
2
+ import {
3
+ createSignal as createSignal3,
4
+ createEffect as createEffect2
5
+ } from "solid-js";
6
+ import {
7
+ createIncremarkParser
8
+ } from "@incremark/core";
9
+
10
+ // src/composables/useProvideDefinations.tsx
11
+ import { createSignal } from "solid-js";
12
+ import { createContext } from "solid-js";
13
+ import { jsx } from "solid-js/jsx-runtime";
14
+ var DefinationsContext = createContext();
15
+ function DefinationsProvider(props) {
16
+ return /* @__PURE__ */ jsx(DefinationsContext.Provider, { value: props.value, children: props.children });
17
+ }
18
+ function useProvideDefinations() {
19
+ const [definations, setDefinations] = createSignal({});
20
+ const [footnoteDefinitions, setFootnoteDefinitions] = createSignal({});
21
+ const [footnoteReferenceOrder, setFootnoteReferenceOrder] = createSignal([]);
22
+ function clearDefinations() {
23
+ setDefinations({});
24
+ }
25
+ function clearFootnoteDefinitions() {
26
+ setFootnoteDefinitions({});
27
+ }
28
+ function clearFootnoteReferenceOrder() {
29
+ setFootnoteReferenceOrder([]);
30
+ }
31
+ function clearAllDefinations() {
32
+ clearDefinations();
33
+ clearFootnoteDefinitions();
34
+ clearFootnoteReferenceOrder();
35
+ }
36
+ const contextValue = {
37
+ definations,
38
+ setDefinations,
39
+ footnoteDefinitions,
40
+ setFootnoteDefinitions,
41
+ footnoteReferenceOrder,
42
+ setFootnoteReferenceOrder,
43
+ clearAllDefinations
44
+ };
45
+ return {
46
+ definations,
47
+ setDefinations,
48
+ footnoteDefinitions,
49
+ setFootnoteDefinitions,
50
+ footnoteReferenceOrder,
51
+ setFootnoteReferenceOrder,
52
+ clearDefinations,
53
+ clearFootnoteDefinitions,
54
+ clearFootnoteReferenceOrder,
55
+ clearAllDefinations,
56
+ DefinationsProvider,
57
+ contextValue
58
+ };
59
+ }
60
+
61
+ // src/composables/useTypewriter.ts
62
+ import {
63
+ createSignal as createSignal2,
64
+ createEffect,
65
+ onCleanup
66
+ } from "solid-js";
67
+ import { createStore, reconcile } from "solid-js/store";
68
+ import {
69
+ createBlockTransformer,
70
+ defaultPlugins,
71
+ mathPlugin,
72
+ collectFootnoteReferences
73
+ } from "@incremark/core";
74
+
75
+ // src/utils/cursor.ts
76
+ function addCursorToNode(node, cursor) {
77
+ if (node.type === "code") {
78
+ return node;
79
+ }
80
+ const cloned = JSON.parse(JSON.stringify(node));
81
+ function addToLast(n) {
82
+ if (n.type === "code") {
83
+ return false;
84
+ }
85
+ if (n.children && n.children.length > 0) {
86
+ for (let i = n.children.length - 1; i >= 0; i--) {
87
+ if (addToLast(n.children[i])) {
88
+ return true;
89
+ }
90
+ }
91
+ n.children.push({ type: "text", value: cursor });
92
+ return true;
93
+ }
94
+ if (n.type === "text" && typeof n.value === "string") {
95
+ n.value += cursor;
96
+ return true;
97
+ }
98
+ if (typeof n.value === "string") {
99
+ n.value += cursor;
100
+ return true;
101
+ }
102
+ return false;
103
+ }
104
+ addToLast(cloned);
105
+ return cloned;
106
+ }
107
+
108
+ // src/composables/useTypewriter.ts
109
+ function useTypewriter(options) {
110
+ const { typewriter: typewriterInput, completedBlocks, pendingBlocks } = options;
111
+ const initialConfig = typewriterInput();
112
+ const [typewriterEnabled, setTypewriterEnabled] = createSignal2(initialConfig?.enabled ?? !!initialConfig);
113
+ const [isTypewriterProcessing, setIsTypewriterProcessing] = createSignal2(false);
114
+ const [isTypewriterPaused, setIsTypewriterPaused] = createSignal2(false);
115
+ const [typewriterEffect, setTypewriterEffect] = createSignal2(initialConfig?.effect ?? "none");
116
+ const [typewriterCursor, setTypewriterCursor] = createSignal2(initialConfig?.cursor ?? "|");
117
+ const [isAnimationComplete, setIsAnimationComplete] = createSignal2(true);
118
+ const [blocksStore, setBlocksStore] = createStore({ items: [] });
119
+ let transformer = null;
120
+ let displayBlocksCache = [];
121
+ function convertToRenderBlocks(displayBlocks) {
122
+ return displayBlocks.map((db, index) => {
123
+ const isPending = !db.isDisplayComplete;
124
+ const isLastPending = isPending && index === displayBlocks.length - 1;
125
+ let node = db.displayNode;
126
+ if (typewriterEffect() === "typing" && isLastPending) {
127
+ node = addCursorToNode(db.displayNode, typewriterCursor());
128
+ }
129
+ return {
130
+ id: db.id,
131
+ status: db.status,
132
+ node,
133
+ startOffset: 0,
134
+ endOffset: 0,
135
+ rawText: "",
136
+ isLastPending
137
+ };
138
+ });
139
+ }
140
+ if (initialConfig) {
141
+ transformer = createBlockTransformer({
142
+ charsPerTick: initialConfig.charsPerTick ?? [1, 3],
143
+ tickInterval: initialConfig.tickInterval ?? 30,
144
+ effect: initialConfig.effect ?? "none",
145
+ pauseOnHidden: initialConfig.pauseOnHidden ?? true,
146
+ // 默认插件 + 数学公式插件(数学公式应该整体显示,不参与打字机逐字符效果)
147
+ plugins: initialConfig.plugins ?? [...defaultPlugins, mathPlugin],
148
+ onChange: (blocks) => {
149
+ displayBlocksCache = blocks;
150
+ const newRenderBlocks = convertToRenderBlocks(displayBlocksCache);
151
+ setBlocksStore("items", reconcile(newRenderBlocks, { key: "id", merge: true }));
152
+ setIsTypewriterProcessing(transformer?.isProcessing() ?? false);
153
+ setIsTypewriterPaused(transformer?.isPausedState() ?? false);
154
+ if (transformer?.isProcessing() ?? false) {
155
+ setIsAnimationComplete(false);
156
+ }
157
+ },
158
+ onAllComplete: () => {
159
+ setIsAnimationComplete(true);
160
+ }
161
+ });
162
+ }
163
+ createEffect(() => {
164
+ const newConfig = typewriterInput();
165
+ if (!newConfig) return;
166
+ if (newConfig.enabled !== void 0) {
167
+ setTypewriterEnabled(newConfig.enabled);
168
+ }
169
+ if (newConfig.effect !== void 0) {
170
+ setTypewriterEffect(newConfig.effect);
171
+ }
172
+ if (newConfig.cursor !== void 0) {
173
+ setTypewriterCursor(newConfig.cursor);
174
+ }
175
+ transformer?.setOptions({
176
+ charsPerTick: newConfig.charsPerTick,
177
+ tickInterval: newConfig.tickInterval,
178
+ effect: newConfig.effect,
179
+ pauseOnHidden: newConfig.pauseOnHidden
180
+ });
181
+ if (newConfig.enabled === false && transformer) {
182
+ transformer.reset();
183
+ }
184
+ });
185
+ if (transformer) {
186
+ createEffect(() => {
187
+ if (!typewriterEnabled()) return;
188
+ const allBlocks = [...completedBlocks(), ...pendingBlocks()];
189
+ transformer.push(allBlocks);
190
+ });
191
+ }
192
+ const rawBlocks = () => [...completedBlocks(), ...pendingBlocks()];
193
+ createEffect(() => {
194
+ const enabled = typewriterEnabled();
195
+ const blocks = rawBlocks();
196
+ if (!enabled || !transformer) {
197
+ setBlocksStore("items", reconcile(blocks, { key: "id", merge: true }));
198
+ }
199
+ });
200
+ const displayedFootnoteReferenceOrder = () => {
201
+ if (!typewriterEnabled() || !transformer) {
202
+ const references2 = [];
203
+ const seen2 = /* @__PURE__ */ new Set();
204
+ for (const block of rawBlocks()) {
205
+ const blockRefs = collectFootnoteReferences(block.node);
206
+ for (const ref of blockRefs) {
207
+ if (!seen2.has(ref)) {
208
+ seen2.add(ref);
209
+ references2.push(ref);
210
+ }
211
+ }
212
+ }
213
+ return references2;
214
+ }
215
+ if (!isAnimationComplete()) {
216
+ return [];
217
+ }
218
+ const references = [];
219
+ const seen = /* @__PURE__ */ new Set();
220
+ for (const db of displayBlocksCache) {
221
+ const blockRefs = collectFootnoteReferences(db.displayNode);
222
+ for (const ref of blockRefs) {
223
+ if (!seen.has(ref)) {
224
+ seen.add(ref);
225
+ references.push(ref);
226
+ }
227
+ }
228
+ }
229
+ return references;
230
+ };
231
+ const typewriterControls = {
232
+ enabled: () => typewriterEnabled(),
233
+ setEnabled: (value) => {
234
+ setTypewriterEnabled(value);
235
+ },
236
+ isProcessing: () => isTypewriterProcessing(),
237
+ isPaused: () => isTypewriterPaused(),
238
+ effect: () => typewriterEffect(),
239
+ skip: () => transformer?.skip(),
240
+ pause: () => {
241
+ transformer?.pause();
242
+ setIsTypewriterPaused(true);
243
+ },
244
+ resume: () => {
245
+ transformer?.resume();
246
+ setIsTypewriterPaused(false);
247
+ },
248
+ setOptions: (opts) => {
249
+ if (opts.enabled !== void 0) {
250
+ setTypewriterEnabled(opts.enabled);
251
+ }
252
+ if (opts.charsPerTick !== void 0 || opts.tickInterval !== void 0 || opts.effect !== void 0 || opts.pauseOnHidden !== void 0) {
253
+ transformer?.setOptions({
254
+ charsPerTick: opts.charsPerTick,
255
+ tickInterval: opts.tickInterval,
256
+ effect: opts.effect,
257
+ pauseOnHidden: opts.pauseOnHidden
258
+ });
259
+ }
260
+ if (opts.effect !== void 0) {
261
+ setTypewriterEffect(opts.effect);
262
+ }
263
+ if (opts.cursor !== void 0) {
264
+ setTypewriterCursor(opts.cursor);
265
+ }
266
+ }
267
+ };
268
+ onCleanup(() => {
269
+ transformer?.destroy();
270
+ });
271
+ return {
272
+ blocks: blocksStore.items,
273
+ typewriter: typewriterControls,
274
+ transformer,
275
+ isAnimationComplete: () => isAnimationComplete(),
276
+ displayedFootnoteReferenceOrder: () => displayedFootnoteReferenceOrder()
277
+ };
278
+ }
279
+
280
+ // src/utils/animatedChunks.ts
281
+ var animatedChunks = /* @__PURE__ */ new Set();
282
+ function shouldAnimateChunk(createdAt) {
283
+ if (animatedChunks.has(createdAt)) {
284
+ return false;
285
+ }
286
+ animatedChunks.add(createdAt);
287
+ return true;
288
+ }
289
+ function clearAnimatedChunks() {
290
+ animatedChunks.clear();
291
+ }
292
+
293
+ // src/composables/useIncremark.ts
294
+ function useIncremark(optionsInput = () => ({})) {
295
+ const { setDefinations, setFootnoteDefinitions, footnoteReferenceOrder, setFootnoteReferenceOrder, contextValue, DefinationsProvider: DefinationsProvider2 } = useProvideDefinations();
296
+ function createParser(options) {
297
+ return createIncremarkParser({
298
+ ...options,
299
+ onChange: (state) => {
300
+ setDefinations(state.definitions);
301
+ setFootnoteDefinitions(state.footnoteDefinitions);
302
+ options.onChange?.(state);
303
+ }
304
+ });
305
+ }
306
+ let parser = createParser(optionsInput());
307
+ const [completedBlocks, setCompletedBlocks] = createSignal3([]);
308
+ const [pendingBlocks, setPendingBlocks] = createSignal3([]);
309
+ const [isLoading, setIsLoading] = createSignal3(false);
310
+ const [markdown, setMarkdown] = createSignal3("");
311
+ const [isFinalized, setIsFinalized] = createSignal3(false);
312
+ const { blocks, typewriter, transformer, isAnimationComplete, displayedFootnoteReferenceOrder } = useTypewriter({
313
+ typewriter: () => optionsInput().typewriter,
314
+ completedBlocks,
315
+ pendingBlocks
316
+ });
317
+ const isDisplayComplete = () => {
318
+ if (!optionsInput().typewriter || !typewriter.enabled()) {
319
+ return isFinalized();
320
+ }
321
+ return isFinalized() && isAnimationComplete();
322
+ };
323
+ const [ast, setAst] = createSignal3({
324
+ type: "root",
325
+ children: []
326
+ });
327
+ function handleUpdate(update, isFinalize = false) {
328
+ setMarkdown(parser.getBuffer());
329
+ if (update.updated.length > 0) {
330
+ const idsToRemove = new Set(update.updated.map((b) => b.id));
331
+ setCompletedBlocks((prev) => prev.filter((b) => !idsToRemove.has(b.id)));
332
+ }
333
+ if (update.completed.length > 0) {
334
+ setCompletedBlocks((prev) => [...prev, ...update.completed]);
335
+ }
336
+ setPendingBlocks(update.pending);
337
+ if (isFinalize) {
338
+ if (update.pending.length > 0) {
339
+ setCompletedBlocks((prev) => [...prev, ...update.pending]);
340
+ setPendingBlocks([]);
341
+ }
342
+ setIsLoading(false);
343
+ setIsFinalized(true);
344
+ } else {
345
+ setIsLoading(true);
346
+ }
347
+ setFootnoteReferenceOrder(update.footnoteReferenceOrder);
348
+ }
349
+ function append(chunk) {
350
+ const update = parser.append(chunk);
351
+ setAst(update.ast);
352
+ handleUpdate(update, false);
353
+ return update;
354
+ }
355
+ function finalize() {
356
+ const update = parser.finalize();
357
+ handleUpdate(update, true);
358
+ return update;
359
+ }
360
+ function abort() {
361
+ return finalize();
362
+ }
363
+ function reset() {
364
+ parser.reset();
365
+ setCompletedBlocks([]);
366
+ setPendingBlocks([]);
367
+ setMarkdown("");
368
+ setIsLoading(false);
369
+ setIsFinalized(false);
370
+ setFootnoteReferenceOrder([]);
371
+ transformer?.reset();
372
+ clearAnimatedChunks();
373
+ }
374
+ let lastOptionsStr = "";
375
+ createEffect2(() => {
376
+ const opts = optionsInput();
377
+ const { typewriter: _, astBuilder, ...parserOptions } = opts;
378
+ const optionsStr = JSON.stringify(parserOptions) + "|" + (astBuilder?.name ?? "default");
379
+ if (optionsStr !== lastOptionsStr) {
380
+ lastOptionsStr = optionsStr;
381
+ const { typewriter: _2, ...parserOptions2 } = opts;
382
+ parser.updateOptions(parserOptions2);
383
+ setCompletedBlocks([]);
384
+ setPendingBlocks([]);
385
+ setMarkdown("");
386
+ setIsLoading(false);
387
+ setIsFinalized(false);
388
+ setFootnoteReferenceOrder([]);
389
+ transformer?.reset();
390
+ }
391
+ });
392
+ createEffect2(() => {
393
+ const newOrder = displayedFootnoteReferenceOrder();
394
+ setFootnoteReferenceOrder(newOrder);
395
+ });
396
+ function render(content) {
397
+ const update = parser.render(content);
398
+ setMarkdown(parser.getBuffer());
399
+ setCompletedBlocks(parser.getCompletedBlocks());
400
+ setPendingBlocks([]);
401
+ setIsLoading(false);
402
+ setIsFinalized(true);
403
+ setFootnoteReferenceOrder(update.footnoteReferenceOrder);
404
+ setFootnoteReferenceOrder(update.footnoteReferenceOrder);
405
+ return update;
406
+ }
407
+ const result = {
408
+ /** 已收集的完整 Markdown 字符串 */
409
+ markdown,
410
+ /** 已完成的块列表 */
411
+ completedBlocks,
412
+ /** 待处理的块列表 */
413
+ pendingBlocks,
414
+ /** 当前完整的 AST */
415
+ ast,
416
+ /** 用于渲染的 blocks(根据打字机设置自动处理) */
417
+ blocks,
418
+ /** 是否正在加载 */
419
+ isLoading,
420
+ /** 是否已完成(finalize) */
421
+ isFinalized,
422
+ /**
423
+ * 内容是否完全显示完成
424
+ * - 无打字机:等于 isFinalized
425
+ * - 有打字机:isFinalized + 动画播放完成
426
+ * 适用于控制 footnote 等需要在内容完全显示后才出现的元素
427
+ */
428
+ isDisplayComplete,
429
+ /** 脚注引用的出现顺序 */
430
+ footnoteReferenceOrder,
431
+ /** 追加内容 */
432
+ append,
433
+ /** 完成解析 */
434
+ finalize,
435
+ /** 强制中断 */
436
+ abort,
437
+ /** 重置解析器和打字机 */
438
+ reset,
439
+ /** 一次性渲染(reset + append + finalize) */
440
+ render,
441
+ /** 解析器实例 */
442
+ parser,
443
+ /** 打字机控制 */
444
+ typewriter,
445
+ /** Context value for DefinationsProvider */
446
+ contextValue,
447
+ /** DefinationsProvider component */
448
+ DefinationsProvider: DefinationsProvider2
449
+ };
450
+ return result;
451
+ }
452
+
453
+ // src/composables/useShiki.ts
454
+ import { createSignal as createSignal4 } from "solid-js";
455
+ var _ShikiManager = class _ShikiManager {
456
+ constructor() {
457
+ /** 存储 highlighter 实例,key 为主题名称 */
458
+ this.highlighters = /* @__PURE__ */ new Map();
459
+ }
460
+ static getInstance() {
461
+ if (!_ShikiManager.instance) {
462
+ _ShikiManager.instance = new _ShikiManager();
463
+ }
464
+ return _ShikiManager.instance;
465
+ }
466
+ /**
467
+ * 获取或创建 highlighter
468
+ * @param theme 主题名称
469
+ * @returns highlighter 实例
470
+ */
471
+ async getHighlighter(theme) {
472
+ if (this.highlighters.has(theme)) {
473
+ return this.highlighters.get(theme);
474
+ }
475
+ const { createHighlighter } = await import("shiki");
476
+ const highlighter = await createHighlighter({
477
+ themes: [theme],
478
+ langs: []
479
+ });
480
+ const info = {
481
+ highlighter,
482
+ loadedLanguages: /* @__PURE__ */ new Set(),
483
+ loadedThemes: /* @__PURE__ */ new Set([theme])
484
+ };
485
+ this.highlighters.set(theme, info);
486
+ return info;
487
+ }
488
+ /**
489
+ * 加载语言(按需)
490
+ * @param theme 主题名称
491
+ * @param lang 语言名称
492
+ */
493
+ async loadLanguage(theme, lang) {
494
+ const info = this.highlighters.get(theme);
495
+ if (!info || info.loadedLanguages.has(lang)) return;
496
+ try {
497
+ await info.highlighter.loadLanguage(lang);
498
+ info.loadedLanguages.add(lang);
499
+ } catch {
500
+ }
501
+ }
502
+ /**
503
+ * 加载主题(按需)
504
+ * @param theme 主题名称
505
+ */
506
+ async loadTheme(theme) {
507
+ const info = this.highlighters.get(theme);
508
+ if (!info || info.loadedThemes.has(theme)) return;
509
+ try {
510
+ await info.highlighter.loadTheme(theme);
511
+ info.loadedThemes.add(theme);
512
+ } catch {
513
+ }
514
+ }
515
+ /**
516
+ * 高亮代码
517
+ * @param theme 主题名称
518
+ * @param code 代码内容
519
+ * @param lang 语言名称
520
+ * @param fallbackTheme 回退主题
521
+ * @returns 高亮后的 HTML
522
+ */
523
+ async codeToHtml(theme, code, lang, fallbackTheme) {
524
+ const info = this.highlighters.get(theme);
525
+ if (!info) throw new Error("Highlighter not found");
526
+ const actualLang = info.loadedLanguages.has(lang) ? lang : "text";
527
+ const actualTheme = info.loadedThemes.has(theme) ? theme : fallbackTheme;
528
+ return info.highlighter.codeToHtml(code, {
529
+ lang: actualLang,
530
+ theme: actualTheme
531
+ });
532
+ }
533
+ /**
534
+ * 清理所有 highlighter(应用退出或需要重置时调用)
535
+ */
536
+ disposeAll() {
537
+ for (const [, info] of this.highlighters) {
538
+ if (info.highlighter?.dispose) {
539
+ info.highlighter.dispose();
540
+ }
541
+ }
542
+ this.highlighters.clear();
543
+ }
544
+ };
545
+ _ShikiManager.instance = null;
546
+ var ShikiManager = _ShikiManager;
547
+ var shikiManagerInstance = null;
548
+ function getShikiManager() {
549
+ if (!shikiManagerInstance) {
550
+ shikiManagerInstance = ShikiManager.getInstance();
551
+ }
552
+ return shikiManagerInstance;
553
+ }
554
+ function useShiki(theme) {
555
+ const [highlighterInfo, setHighlighterInfo] = createSignal4(null);
556
+ const [isHighlighting, setIsHighlighting] = createSignal4(false);
557
+ const [isReady, setIsReady] = createSignal4(false);
558
+ async function initHighlighter() {
559
+ if (isReady()) return;
560
+ try {
561
+ const info = await getShikiManager().getHighlighter(theme);
562
+ setHighlighterInfo(info);
563
+ setIsReady(true);
564
+ } catch (e) {
565
+ console.warn("Failed to initialize Shiki highlighter:", e);
566
+ throw e;
567
+ }
568
+ }
569
+ async function getHighlighter() {
570
+ if (!highlighterInfo()) {
571
+ const info = await getShikiManager().getHighlighter(theme);
572
+ setHighlighterInfo(info);
573
+ setIsReady(true);
574
+ return info;
575
+ }
576
+ return highlighterInfo();
577
+ }
578
+ async function highlight(code, lang, fallbackTheme) {
579
+ setIsHighlighting(true);
580
+ try {
581
+ const info = await getHighlighter();
582
+ const manager = getShikiManager();
583
+ if (!info.loadedLanguages.has(lang) && lang !== "text") {
584
+ await manager.loadLanguage(theme, lang);
585
+ }
586
+ if (!info.loadedThemes.has(theme)) {
587
+ await manager.loadTheme(theme);
588
+ }
589
+ return await manager.codeToHtml(
590
+ theme,
591
+ code,
592
+ lang,
593
+ fallbackTheme
594
+ );
595
+ } catch (e) {
596
+ throw e;
597
+ } finally {
598
+ setIsHighlighting(false);
599
+ }
600
+ }
601
+ return {
602
+ highlighterInfo,
603
+ isHighlighting,
604
+ isReady,
605
+ initHighlighter,
606
+ highlight
607
+ };
608
+ }
609
+
610
+ // src/components/ConfigProvider.tsx
611
+ import { createContext as createContext2, useContext, createSignal as createSignal5, createMemo } from "solid-js";
612
+ import { zhCN } from "@incremark/shared";
613
+ import { jsx as jsx2 } from "solid-js/jsx-runtime";
614
+ var LocaleContext = createContext2();
615
+ var ConfigProvider = (props) => {
616
+ const [locale, setLocale] = createSignal5(props.locale || zhCN);
617
+ createMemo(() => {
618
+ setLocale(props.locale || zhCN);
619
+ });
620
+ return /* @__PURE__ */ jsx2(LocaleContext.Provider, { value: { locale }, children: props.children });
621
+ };
622
+ function useLocale() {
623
+ const context = useContext(LocaleContext);
624
+ const locale = context?.locale || (() => zhCN);
625
+ return (key) => {
626
+ const keys = key.split(".");
627
+ let value = locale();
628
+ for (const k of keys) {
629
+ value = value?.[k];
630
+ }
631
+ return value || key;
632
+ };
633
+ }
634
+
635
+ // src/composables/useDefinationsContext.ts
636
+ import { useContext as useContext2 } from "solid-js";
637
+ function useDefinationsContext() {
638
+ const context = useContext2(DefinationsContext);
639
+ if (!context) {
640
+ throw new Error("DefinationsContext not found. Make sure you are using this within a component that provides DefinationsContext.");
641
+ }
642
+ return context;
643
+ }
644
+
645
+ // src/composables/useDevTools.ts
646
+ import { createSignal as createSignal6 } from "solid-js";
647
+ function useDevTools(options = {}) {
648
+ const [enabled, setEnabled] = createSignal6(options.enabled ?? false);
649
+ const [blocks, setBlocks] = createSignal6([]);
650
+ const [ast, setAst] = createSignal6(null);
651
+ const stats = () => ({
652
+ blockCount: blocks().length,
653
+ completedCount: blocks().filter((b) => b.status === "completed").length,
654
+ pendingCount: blocks().filter((b) => b.status !== "completed").length
655
+ });
656
+ function toggle() {
657
+ setEnabled((prev) => !prev);
658
+ }
659
+ return {
660
+ enabled,
661
+ toggle,
662
+ setEnabled,
663
+ blocks,
664
+ setBlocks,
665
+ ast,
666
+ setAst,
667
+ stats
668
+ };
669
+ }
670
+
671
+ // src/composables/useStreamRenderer.ts
672
+ import { createSignal as createSignal7 } from "solid-js";
673
+ function useStreamRenderer(options = {}) {
674
+ const [blocks, setBlocks] = createSignal7(options.initialBlocks ?? []);
675
+ function addBlocks(newBlocks) {
676
+ setBlocks((prev) => [...prev, ...newBlocks]);
677
+ }
678
+ function clearBlocks() {
679
+ setBlocks([]);
680
+ }
681
+ const blockCount = () => blocks().length;
682
+ return {
683
+ blocks,
684
+ setBlocks,
685
+ addBlocks,
686
+ clearBlocks,
687
+ blockCount
688
+ };
689
+ }
690
+
691
+ // src/composables/useBlockTransformer.ts
692
+ import { createSignal as createSignal8 } from "solid-js";
693
+ import {
694
+ createBlockTransformer as createBlockTransformer2
695
+ } from "@incremark/core";
696
+ function useBlockTransformer(options = {}) {
697
+ const [displayBlocks, setDisplayBlocks] = createSignal8([]);
698
+ const [isProcessing, setIsProcessing] = createSignal8(false);
699
+ const [isPaused, setIsPaused] = createSignal8(false);
700
+ const transformer = createBlockTransformer2({
701
+ charsPerTick: options.charsPerTick ?? [1, 3],
702
+ tickInterval: options.tickInterval ?? 30,
703
+ effect: options.effect ?? "none",
704
+ pauseOnHidden: options.pauseOnHidden ?? true,
705
+ plugins: options.plugins,
706
+ onChange: (blocks) => {
707
+ setDisplayBlocks(blocks);
708
+ setIsProcessing(transformer?.isProcessing() ?? false);
709
+ setIsPaused(transformer?.isPausedState() ?? false);
710
+ }
711
+ });
712
+ function push(blocks) {
713
+ transformer.push(blocks);
714
+ }
715
+ function skip() {
716
+ transformer.skip();
717
+ }
718
+ function pause() {
719
+ transformer.pause();
720
+ }
721
+ function resume() {
722
+ transformer.resume();
723
+ }
724
+ function reset() {
725
+ transformer.reset();
726
+ }
727
+ function destroy() {
728
+ transformer.destroy();
729
+ }
730
+ function setOptions(opts) {
731
+ transformer.setOptions(opts);
732
+ }
733
+ return {
734
+ displayBlocks,
735
+ isProcessing,
736
+ isPaused,
737
+ push,
738
+ skip,
739
+ pause,
740
+ resume,
741
+ reset,
742
+ destroy,
743
+ setOptions
744
+ };
745
+ }
746
+
747
+ // src/components/Incremark.tsx
748
+ import { For as For9, Show as Show13, mergeProps } from "solid-js";
749
+
750
+ // src/components/IncremarkRenderer.tsx
751
+ import { Show as Show11 } from "solid-js";
752
+ import { Dynamic as Dynamic5 } from "solid-js/web";
753
+
754
+ // src/components/IncremarkHeading.tsx
755
+ import { Dynamic as Dynamic2 } from "solid-js/web";
756
+
757
+ // src/components/IncremarkInline.tsx
758
+ import { hasChunks, getStableText, isHtmlNode } from "@incremark/shared";
759
+ import { For as For2, Index, Show as Show3 } from "solid-js";
760
+
761
+ // src/components/IncremarkMath.tsx
762
+ import { createSignal as createSignal9, createEffect as createEffect4, onCleanup as onCleanup3, Show } from "solid-js";
763
+ import { jsx as jsx3, jsxs } from "solid-js/jsx-runtime";
764
+ var IncremarkMath = (props) => {
765
+ const [renderedHtml, setRenderedHtml] = createSignal9("");
766
+ const [isLoading, setIsLoading] = createSignal9(false);
767
+ const isInline = () => props.node.type === "inlineMath";
768
+ const formula = () => props.node.value;
769
+ let renderTimer = null;
770
+ let katexRef = null;
771
+ function scheduleRender() {
772
+ if (!formula()) {
773
+ setRenderedHtml("");
774
+ return;
775
+ }
776
+ if (renderTimer) {
777
+ clearTimeout(renderTimer);
778
+ }
779
+ setIsLoading(true);
780
+ renderTimer = setTimeout(() => {
781
+ doRender();
782
+ }, props.renderDelay ?? 0);
783
+ }
784
+ async function doRender() {
785
+ if (!formula()) return;
786
+ try {
787
+ if (!katexRef) {
788
+ const katexModule = await import("katex");
789
+ katexRef = katexModule.default;
790
+ }
791
+ const katex = katexRef;
792
+ setRenderedHtml(katex.renderToString(formula(), {
793
+ displayMode: !isInline(),
794
+ throwOnError: false,
795
+ strict: false
796
+ }));
797
+ } catch {
798
+ setRenderedHtml("");
799
+ } finally {
800
+ setIsLoading(false);
801
+ }
802
+ }
803
+ createEffect4(() => {
804
+ scheduleRender();
805
+ });
806
+ onCleanup3(() => {
807
+ if (renderTimer) {
808
+ clearTimeout(renderTimer);
809
+ }
810
+ });
811
+ if (isInline()) {
812
+ return /* @__PURE__ */ jsxs("span", { class: "incremark-math-inline", children: [
813
+ /* @__PURE__ */ jsx3(Show, { when: renderedHtml() && !isLoading(), children: /* @__PURE__ */ jsx3("span", { innerHTML: renderedHtml() }) }),
814
+ /* @__PURE__ */ jsx3(Show, { when: !renderedHtml() || isLoading(), children: /* @__PURE__ */ jsx3("code", { class: "math-source", children: formula() }) })
815
+ ] });
816
+ }
817
+ return /* @__PURE__ */ jsxs("div", { class: "incremark-math-block", children: [
818
+ /* @__PURE__ */ jsx3(Show, { when: renderedHtml() && !isLoading(), children: /* @__PURE__ */ jsx3("div", { innerHTML: renderedHtml(), class: "math-rendered" }) }),
819
+ /* @__PURE__ */ jsx3(Show, { when: !renderedHtml() || isLoading(), children: /* @__PURE__ */ jsx3("pre", { class: "math-source-block", children: /* @__PURE__ */ jsx3("code", { children: formula() }) }) })
820
+ ] });
821
+ };
822
+
823
+ // src/components/IncremarkHtmlElement.tsx
824
+ import { For, Show as Show2 } from "solid-js";
825
+ import { Dynamic } from "solid-js/web";
826
+ import { Fragment, jsx as jsx4 } from "solid-js/jsx-runtime";
827
+ var INLINE_ELEMENTS = [
828
+ "a",
829
+ "abbr",
830
+ "acronym",
831
+ "b",
832
+ "bdo",
833
+ "big",
834
+ "br",
835
+ "button",
836
+ "cite",
837
+ "code",
838
+ "dfn",
839
+ "em",
840
+ "i",
841
+ "img",
842
+ "input",
843
+ "kbd",
844
+ "label",
845
+ "map",
846
+ "object",
847
+ "output",
848
+ "q",
849
+ "samp",
850
+ "script",
851
+ "select",
852
+ "small",
853
+ "span",
854
+ "strong",
855
+ "sub",
856
+ "sup",
857
+ "textarea",
858
+ "time",
859
+ "tt",
860
+ "var"
861
+ ];
862
+ var VOID_ELEMENTS = [
863
+ "area",
864
+ "base",
865
+ "br",
866
+ "col",
867
+ "embed",
868
+ "hr",
869
+ "img",
870
+ "input",
871
+ "link",
872
+ "meta",
873
+ "param",
874
+ "source",
875
+ "track",
876
+ "wbr"
877
+ ];
878
+ function isInlineElement(tagName) {
879
+ return INLINE_ELEMENTS.includes(tagName.toLowerCase());
880
+ }
881
+ function isVoidElement(tagName) {
882
+ return VOID_ELEMENTS.includes(tagName.toLowerCase());
883
+ }
884
+ function hasOnlyInlineChildren(children) {
885
+ if (!children || children.length === 0) return true;
886
+ return children.every((child) => {
887
+ const type = child.type;
888
+ const inlineTypes = ["text", "strong", "emphasis", "inlineCode", "link", "image", "break", "html", "htmlElement"];
889
+ if (inlineTypes.includes(type)) {
890
+ if (type === "htmlElement") {
891
+ return isInlineElement(child.tagName);
892
+ }
893
+ return true;
894
+ }
895
+ return false;
896
+ });
897
+ }
898
+ function renderChildren(children) {
899
+ if (!children || children.length === 0) return null;
900
+ if (hasOnlyInlineChildren(children)) {
901
+ return /* @__PURE__ */ jsx4(IncremarkInline, { nodes: children });
902
+ }
903
+ return /* @__PURE__ */ jsx4(For, { each: children, children: (child, idx) => {
904
+ if (child.type === "htmlElement") {
905
+ return /* @__PURE__ */ jsx4(IncremarkHtmlElement, { node: child });
906
+ }
907
+ if (child.type === "text") {
908
+ return /* @__PURE__ */ jsx4(Fragment, { children: child.value });
909
+ }
910
+ if (["strong", "emphasis", "inlineCode", "link", "image", "break"].includes(child.type)) {
911
+ return /* @__PURE__ */ jsx4(IncremarkInline, { nodes: [child] });
912
+ }
913
+ if (child.type === "paragraph") {
914
+ return /* @__PURE__ */ jsx4("p", { children: /* @__PURE__ */ jsx4(IncremarkInline, { nodes: child.children }) });
915
+ }
916
+ return /* @__PURE__ */ jsx4(IncremarkRenderer, { node: child });
917
+ } });
918
+ }
919
+ var IncremarkHtmlElement = (props) => {
920
+ const tagName = () => props.node.tagName;
921
+ const attrs = () => props.node.attrs || {};
922
+ const children = () => props.node.children || [];
923
+ const isVoid = () => isVoidElement(tagName());
924
+ return /* @__PURE__ */ jsx4(
925
+ Dynamic,
926
+ {
927
+ component: tagName(),
928
+ ...attrs(),
929
+ class: `incremark-html-element incremark-${tagName()}`,
930
+ children: /* @__PURE__ */ jsx4(Show2, { when: !isVoid(), children: renderChildren(children()) })
931
+ }
932
+ );
933
+ };
934
+
935
+ // src/components/IncremarkInline.tsx
936
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs2 } from "solid-js/jsx-runtime";
937
+ function isHtmlElementNode(node) {
938
+ return node.type === "htmlElement";
939
+ }
940
+ function isImageReference(node) {
941
+ return node.type === "imageReference";
942
+ }
943
+ function isLinkReference(node) {
944
+ return node.type === "linkReference";
945
+ }
946
+ var IncremarkInline = (props) => {
947
+ const { definations, footnoteDefinitions } = useDefinationsContext();
948
+ function getChunks(node) {
949
+ if (hasChunks(node)) {
950
+ return node.chunks;
951
+ }
952
+ return void 0;
953
+ }
954
+ function isInlineMath(node) {
955
+ return node.type === "inlineMath";
956
+ }
957
+ return /* @__PURE__ */ jsx5(Fragment2, { children: /* @__PURE__ */ jsx5(For2, { each: props.nodes, children: (node, idx) => /* @__PURE__ */ jsxs2(Fragment2, { children: [
958
+ /* @__PURE__ */ jsxs2(Show3, { when: node.type === "text", children: [
959
+ getStableText(node),
960
+ /* @__PURE__ */ jsx5(Index, { each: getChunks(node) || [], children: (chunk, idx2) => /* @__PURE__ */ jsx5(
961
+ "span",
962
+ {
963
+ class: "incremark-fade-in",
964
+ "data-chunk-key": chunk().createdAt,
965
+ children: chunk().text
966
+ }
967
+ ) })
968
+ ] }),
969
+ /* @__PURE__ */ jsx5(Show3, { when: isInlineMath(node), children: /* @__PURE__ */ jsx5(IncremarkMath, { node }) }),
970
+ /* @__PURE__ */ jsx5(Show3, { when: isHtmlElementNode(node), children: /* @__PURE__ */ jsx5(IncremarkHtmlElement, { node }) }),
971
+ /* @__PURE__ */ jsx5(Show3, { when: isHtmlNode(node), children: /* @__PURE__ */ jsx5("span", { class: "incremark-inline-html", innerHTML: node.value }) }),
972
+ /* @__PURE__ */ jsx5(Show3, { when: node.type === "strong", children: /* @__PURE__ */ jsx5("strong", { children: /* @__PURE__ */ jsx5(IncremarkInline, { nodes: node.children }) }) }),
973
+ /* @__PURE__ */ jsx5(Show3, { when: node.type === "emphasis", children: /* @__PURE__ */ jsx5("em", { children: /* @__PURE__ */ jsx5(IncremarkInline, { nodes: node.children }) }) }),
974
+ /* @__PURE__ */ jsx5(Show3, { when: node.type === "inlineCode", children: /* @__PURE__ */ jsx5("code", { class: "incremark-inline-code", children: node.value }) }),
975
+ /* @__PURE__ */ jsx5(Show3, { when: node.type === "link", children: /* @__PURE__ */ jsx5(
976
+ "a",
977
+ {
978
+ class: "incremark-link",
979
+ href: node.url,
980
+ target: "_blank",
981
+ rel: "noopener noreferrer",
982
+ children: /* @__PURE__ */ jsx5(IncremarkInline, { nodes: node.children })
983
+ }
984
+ ) }),
985
+ /* @__PURE__ */ jsx5(Show3, { when: node.type === "image", children: /* @__PURE__ */ jsx5(
986
+ "img",
987
+ {
988
+ class: "incremark-image",
989
+ src: node.url,
990
+ alt: node.alt || "",
991
+ title: node.title || void 0,
992
+ loading: "lazy"
993
+ }
994
+ ) }),
995
+ /* @__PURE__ */ jsx5(Show3, { when: isImageReference(node), children: /* @__PURE__ */ jsx5(
996
+ Show3,
997
+ {
998
+ when: definations()[node.identifier],
999
+ fallback: /* @__PURE__ */ jsxs2("span", { class: "incremark-image-ref-missing", children: [
1000
+ "![",
1001
+ node.alt,
1002
+ "][",
1003
+ node.identifier || node.label,
1004
+ "]"
1005
+ ] }),
1006
+ children: /* @__PURE__ */ jsx5(
1007
+ "img",
1008
+ {
1009
+ class: "incremark-image incremark-reference-image",
1010
+ src: definations()[node.identifier].url,
1011
+ alt: node.alt || "",
1012
+ title: definations()[node.identifier].title || void 0,
1013
+ loading: "lazy"
1014
+ }
1015
+ )
1016
+ }
1017
+ ) }),
1018
+ /* @__PURE__ */ jsx5(Show3, { when: isLinkReference(node), children: /* @__PURE__ */ jsx5(
1019
+ Show3,
1020
+ {
1021
+ when: definations()[node.identifier],
1022
+ fallback: /* @__PURE__ */ jsxs2("span", { class: "incremark-link-ref-missing", children: [
1023
+ "[",
1024
+ node.children.map((c) => c.value).join(""),
1025
+ "][",
1026
+ node.identifier || node.label,
1027
+ "]"
1028
+ ] }),
1029
+ children: /* @__PURE__ */ jsx5(
1030
+ "a",
1031
+ {
1032
+ class: "incremark-link incremark-reference-link",
1033
+ href: definations()[node.identifier].url,
1034
+ title: definations()[node.identifier].title || void 0,
1035
+ target: "_blank",
1036
+ rel: "noopener noreferrer",
1037
+ children: /* @__PURE__ */ jsx5(IncremarkInline, { nodes: node.children })
1038
+ }
1039
+ )
1040
+ }
1041
+ ) }),
1042
+ /* @__PURE__ */ jsx5(Show3, { when: node.type === "footnoteReference", children: /* @__PURE__ */ jsx5("sup", { class: "incremark-footnote-ref", children: /* @__PURE__ */ jsxs2("a", { href: `#fn-${node.identifier}`, id: `fnref-${node.identifier}`, children: [
1043
+ "[",
1044
+ node.identifier,
1045
+ "]"
1046
+ ] }) }) }),
1047
+ /* @__PURE__ */ jsx5(Show3, { when: node.type === "break", children: /* @__PURE__ */ jsx5("br", {}) }),
1048
+ /* @__PURE__ */ jsx5(Show3, { when: node.type === "delete", children: /* @__PURE__ */ jsx5("del", { children: /* @__PURE__ */ jsx5(IncremarkInline, { nodes: node.children }) }) })
1049
+ ] }) }) });
1050
+ };
1051
+
1052
+ // src/components/IncremarkHeading.tsx
1053
+ import { jsx as jsx6 } from "solid-js/jsx-runtime";
1054
+ var IncremarkHeading = (props) => {
1055
+ const tag = () => `h${props.node.depth}`;
1056
+ return /* @__PURE__ */ jsx6(Dynamic2, { component: tag(), class: `incremark-heading h${props.node.depth}`, children: /* @__PURE__ */ jsx6(IncremarkInline, { nodes: props.node.children }) });
1057
+ };
1058
+
1059
+ // src/components/IncremarkParagraph.tsx
1060
+ import { jsx as jsx7 } from "solid-js/jsx-runtime";
1061
+ var IncremarkParagraph = (props) => {
1062
+ return /* @__PURE__ */ jsx7("p", { class: "incremark-paragraph", children: /* @__PURE__ */ jsx7(IncremarkInline, { nodes: props.node.children }) });
1063
+ };
1064
+
1065
+ // src/components/IncremarkCode.tsx
1066
+ import { Show as Show7 } from "solid-js";
1067
+ import { Dynamic as Dynamic3 } from "solid-js/web";
1068
+
1069
+ // src/components/IncremarkCodeMermaid.tsx
1070
+ import { createEffect as createEffect5, createSignal as createSignal10, onCleanup as onCleanup4, onMount, Show as Show4 } from "solid-js";
1071
+ import { GravityMermaid, LucideCode, LucideEye, LucideCopy, LucideCopyCheck } from "@incremark/icons";
1072
+ import { isClipboardAvailable } from "@incremark/shared";
1073
+
1074
+ // src/components/SvgIcon.tsx
1075
+ import { jsx as jsx8 } from "solid-js/jsx-runtime";
1076
+ var SvgIcon = (props) => {
1077
+ return /* @__PURE__ */ jsx8(
1078
+ "span",
1079
+ {
1080
+ classList: {
1081
+ "incremark-icon": true,
1082
+ [props.sizeClass || ""]: !!props.sizeClass
1083
+ },
1084
+ innerHTML: props.svg,
1085
+ "aria-hidden": "true"
1086
+ }
1087
+ );
1088
+ };
1089
+
1090
+ // src/components/IncremarkCodeMermaid.tsx
1091
+ import { jsx as jsx9, jsxs as jsxs3 } from "solid-js/jsx-runtime";
1092
+ var IncremarkCodeMermaid = (props) => {
1093
+ const [mermaidSvg, setMermaidSvg] = createSignal10("");
1094
+ const [mermaidError, setMermaidError] = createSignal10("");
1095
+ const [mermaidLoading, setMermaidLoading] = createSignal10(false);
1096
+ const [copied, setCopied] = createSignal10(false);
1097
+ const [mermaidViewMode, setMermaidViewMode] = createSignal10("preview");
1098
+ let mermaidInstance = null;
1099
+ let renderTimer = null;
1100
+ let copyTimeoutId = null;
1101
+ let chartId = `mermaid-${Math.random().toString(36).substr(2, 9)}`;
1102
+ const code = () => props.node.value;
1103
+ const t = useLocale();
1104
+ function toggleMermaidView() {
1105
+ setMermaidViewMode((prev) => prev === "preview" ? "source" : "preview");
1106
+ }
1107
+ onMount(async () => {
1108
+ try {
1109
+ const mermaidModule = await import("mermaid");
1110
+ const mermaid = mermaidModule.default;
1111
+ mermaid.initialize({
1112
+ startOnLoad: false,
1113
+ theme: "dark",
1114
+ securityLevel: "loose",
1115
+ suppressErrorRendering: true
1116
+ });
1117
+ mermaidInstance = mermaid;
1118
+ } catch (e) {
1119
+ console.warn("Failed to initialize Mermaid:", e);
1120
+ setMermaidError("Failed to initialize");
1121
+ }
1122
+ });
1123
+ function scheduleRender() {
1124
+ if (!code()) {
1125
+ return;
1126
+ }
1127
+ if (renderTimer) {
1128
+ clearTimeout(renderTimer);
1129
+ }
1130
+ setMermaidLoading(true);
1131
+ setMermaidError("");
1132
+ renderTimer = setTimeout(() => {
1133
+ doRender();
1134
+ }, props.mermaidDelay ?? 500);
1135
+ }
1136
+ async function doRender() {
1137
+ if (!code() || !mermaidInstance) return;
1138
+ try {
1139
+ const { svg } = await mermaidInstance.render(chartId, code());
1140
+ setMermaidSvg(svg);
1141
+ setMermaidError("");
1142
+ } catch (e) {
1143
+ setMermaidError("");
1144
+ setMermaidSvg("");
1145
+ } finally {
1146
+ setMermaidLoading(false);
1147
+ }
1148
+ }
1149
+ createEffect5(() => {
1150
+ scheduleRender();
1151
+ });
1152
+ onCleanup4(() => {
1153
+ if (renderTimer) {
1154
+ clearTimeout(renderTimer);
1155
+ }
1156
+ if (copyTimeoutId) {
1157
+ clearTimeout(copyTimeoutId);
1158
+ }
1159
+ });
1160
+ async function copyCode() {
1161
+ if (!isClipboardAvailable()) return;
1162
+ try {
1163
+ await navigator.clipboard.writeText(code());
1164
+ setCopied(true);
1165
+ if (copyTimeoutId) {
1166
+ clearTimeout(copyTimeoutId);
1167
+ }
1168
+ copyTimeoutId = setTimeout(() => {
1169
+ setCopied(false);
1170
+ }, 2e3);
1171
+ } catch {
1172
+ }
1173
+ }
1174
+ return /* @__PURE__ */ jsxs3("div", { class: "incremark-mermaid", children: [
1175
+ /* @__PURE__ */ jsxs3("div", { class: "mermaid-header", children: [
1176
+ /* @__PURE__ */ jsxs3("span", { class: "language", children: [
1177
+ /* @__PURE__ */ jsx9(SvgIcon, { svg: GravityMermaid, sizeClass: "language-icon" }),
1178
+ "MERMAID"
1179
+ ] }),
1180
+ /* @__PURE__ */ jsxs3("div", { class: "mermaid-actions", children: [
1181
+ /* @__PURE__ */ jsx9(
1182
+ "button",
1183
+ {
1184
+ class: "code-btn",
1185
+ onClick: toggleMermaidView,
1186
+ type: "button",
1187
+ disabled: !mermaidSvg(),
1188
+ "aria-label": mermaidViewMode() === "preview" ? t("mermaid.viewSource") : t("mermaid.preview"),
1189
+ title: mermaidViewMode() === "preview" ? "View Source" : "Preview",
1190
+ children: /* @__PURE__ */ jsx9(SvgIcon, { svg: mermaidViewMode() === "preview" ? LucideCode : LucideEye })
1191
+ }
1192
+ ),
1193
+ /* @__PURE__ */ jsx9(
1194
+ "button",
1195
+ {
1196
+ class: "code-btn",
1197
+ onClick: copyCode,
1198
+ type: "button",
1199
+ "aria-label": copied() ? t("mermaid.copied") : t("mermaid.copy"),
1200
+ title: copied() ? "Copied!" : "Copy",
1201
+ children: /* @__PURE__ */ jsx9(SvgIcon, { svg: copied() ? LucideCopyCheck : LucideCopy })
1202
+ }
1203
+ )
1204
+ ] })
1205
+ ] }),
1206
+ /* @__PURE__ */ jsxs3("div", { class: "mermaid-content", children: [
1207
+ /* @__PURE__ */ jsx9(Show4, { when: mermaidLoading() && !mermaidSvg(), children: /* @__PURE__ */ jsx9("div", { class: "mermaid-loading", children: /* @__PURE__ */ jsx9("pre", { class: "mermaid-source-code", children: code() }) }) }),
1208
+ /* @__PURE__ */ jsx9(Show4, { when: mermaidViewMode() === "source" && !mermaidLoading(), children: /* @__PURE__ */ jsx9("pre", { class: "mermaid-source-code", children: code() }) }),
1209
+ /* @__PURE__ */ jsx9(Show4, { when: mermaidViewMode() === "preview" && mermaidSvg() && !mermaidLoading(), children: /* @__PURE__ */ jsx9("div", { innerHTML: mermaidSvg(), class: "mermaid-svg" }) }),
1210
+ /* @__PURE__ */ jsx9(Show4, { when: !mermaidSvg() && !mermaidLoading() && mermaidViewMode() === "preview", children: /* @__PURE__ */ jsx9("pre", { class: "mermaid-source-code", children: code() }) })
1211
+ ] })
1212
+ ] });
1213
+ };
1214
+
1215
+ // src/components/IncremarkCodeDefault.tsx
1216
+ import { createEffect as createEffect7, createSignal as createSignal12, onCleanup as onCleanup6, Show as Show6 } from "solid-js";
1217
+ import { LucideCopy as LucideCopy2, LucideCopyCheck as LucideCopyCheck2 } from "@incremark/icons";
1218
+ import { isClipboardAvailable as isClipboardAvailable2 } from "@incremark/shared";
1219
+
1220
+ // src/components/CachedCodeRenderer.tsx
1221
+ import { CodeToTokenTransformStream } from "shiki-stream";
1222
+ import { getTokenStyleObject } from "@shikijs/core";
1223
+ import { createEffect as createEffect6, createSignal as createSignal11, on, onCleanup as onCleanup5, onMount as onMount2, For as For3, Show as Show5 } from "solid-js";
1224
+ import { batch } from "solid-js";
1225
+ import { jsx as jsx10 } from "solid-js/jsx-runtime";
1226
+ var isBrowser = typeof window !== "undefined";
1227
+ var CachedCodeRenderer = (props) => {
1228
+ const [hasStreamError, setHasStreamError] = createSignal11(false);
1229
+ const [tokens, setTokens] = createSignal11([]);
1230
+ const [index, setIndex] = createSignal11(0);
1231
+ let controller = null;
1232
+ let abortController = null;
1233
+ onMount2(() => {
1234
+ if (!isBrowser) return;
1235
+ const textStream = new ReadableStream({
1236
+ start(_controller) {
1237
+ controller = _controller;
1238
+ }
1239
+ });
1240
+ try {
1241
+ const tokenStream = textStream.pipeThrough(
1242
+ new CodeToTokenTransformStream({
1243
+ highlighter: props.highlighter,
1244
+ lang: props.lang,
1245
+ theme: props.theme,
1246
+ allowRecalls: true
1247
+ })
1248
+ );
1249
+ let started = false;
1250
+ abortController = new AbortController();
1251
+ tokenStream.pipeTo(new WritableStream({
1252
+ write(token) {
1253
+ if (abortController?.signal.aborted) return;
1254
+ if (!started) {
1255
+ started = true;
1256
+ props.onStreamStart?.();
1257
+ }
1258
+ batch(() => {
1259
+ if ("recall" in token) {
1260
+ setTokens((ts) => ts.slice(0, -token.recall));
1261
+ } else {
1262
+ setTokens((ts) => [...ts, token]);
1263
+ }
1264
+ });
1265
+ },
1266
+ close: () => {
1267
+ if (!abortController?.signal.aborted) {
1268
+ props.onStreamEnd?.();
1269
+ }
1270
+ },
1271
+ abort: () => {
1272
+ if (!abortController?.signal.aborted) {
1273
+ props.onStreamEnd?.();
1274
+ }
1275
+ }
1276
+ }), { signal: abortController.signal }).catch((error) => {
1277
+ if (error instanceof Error && error.name === "AbortError") {
1278
+ return;
1279
+ }
1280
+ if (error instanceof Error && error.message.includes("not found")) {
1281
+ setHasStreamError(true);
1282
+ return;
1283
+ }
1284
+ console.error("Stream error:", error);
1285
+ setHasStreamError(true);
1286
+ });
1287
+ } catch (error) {
1288
+ if (error instanceof Error && error.message.includes("not found")) {
1289
+ setHasStreamError(true);
1290
+ return;
1291
+ }
1292
+ console.error("Failed to create token stream:", error);
1293
+ setHasStreamError(true);
1294
+ }
1295
+ });
1296
+ createEffect6(on(
1297
+ () => props.code,
1298
+ (newCode) => {
1299
+ if (!isBrowser || !controller || abortController?.signal.aborted) return;
1300
+ const currentIndex = index();
1301
+ if (newCode.length > currentIndex && !hasStreamError()) {
1302
+ const incremental = newCode.slice(currentIndex);
1303
+ controller.enqueue(incremental);
1304
+ setIndex(newCode.length);
1305
+ }
1306
+ }
1307
+ ));
1308
+ onCleanup5(() => {
1309
+ abortController?.abort();
1310
+ controller = null;
1311
+ setHasStreamError(false);
1312
+ setTokens([]);
1313
+ setIndex(0);
1314
+ });
1315
+ return /* @__PURE__ */ jsx10(
1316
+ Show5,
1317
+ {
1318
+ when: !(hasStreamError() || !isBrowser || tokens().length === 0),
1319
+ fallback: (
1320
+ // SSR 或错误时渲染原始代码
1321
+ /* @__PURE__ */ jsx10("pre", { class: "shiki incremark-code-stream", children: /* @__PURE__ */ jsx10("code", { children: props.code }) })
1322
+ ),
1323
+ children: /* @__PURE__ */ jsx10("pre", { class: "shiki incremark-code-stream", children: /* @__PURE__ */ jsx10("code", { children: /* @__PURE__ */ jsx10(For3, { each: tokens(), children: (token) => /* @__PURE__ */ jsx10("span", { style: token.htmlStyle ?? getTokenStyleObject(token), children: token.content }) }) }) })
1324
+ }
1325
+ );
1326
+ };
1327
+
1328
+ // src/components/IncremarkCodeDefault.tsx
1329
+ import { jsx as jsx11, jsxs as jsxs4 } from "solid-js/jsx-runtime";
1330
+ var IncremarkCodeDefault = (props) => {
1331
+ const [copied, setCopied] = createSignal12(false);
1332
+ const language = () => props.node.lang || "text";
1333
+ const code = () => props.node.value;
1334
+ const t = useLocale();
1335
+ const { highlighterInfo, initHighlighter } = useShiki(props.theme ?? "github-dark");
1336
+ const [isLanguageLoaded, setIsLanguageLoaded] = createSignal12(false);
1337
+ const shouldEnableHighlight = () => {
1338
+ return !props.disableHighlight && code() && code().length > 0;
1339
+ };
1340
+ createEffect7(async () => {
1341
+ const info = highlighterInfo();
1342
+ const lang = language();
1343
+ const shouldHighlight = shouldEnableHighlight();
1344
+ if (!shouldHighlight) {
1345
+ return;
1346
+ }
1347
+ if (!info) {
1348
+ await initHighlighter();
1349
+ } else if (lang && lang !== "text") {
1350
+ if (!info.loadedLanguages.has(lang)) {
1351
+ try {
1352
+ setIsLanguageLoaded(false);
1353
+ const supportedLangs = info.highlighter.getLoadedLanguages();
1354
+ const bundledLangs = await import("shiki").then((m) => Object.keys(m.bundledLanguages || {}));
1355
+ const isSupported = supportedLangs.includes(lang) || bundledLangs.includes(lang);
1356
+ if (isSupported) {
1357
+ await info.highlighter.loadLanguage(lang);
1358
+ info.loadedLanguages.add(lang);
1359
+ }
1360
+ setIsLanguageLoaded(true);
1361
+ } catch {
1362
+ setIsLanguageLoaded(true);
1363
+ }
1364
+ } else {
1365
+ setIsLanguageLoaded(true);
1366
+ }
1367
+ } else {
1368
+ setIsLanguageLoaded(true);
1369
+ }
1370
+ });
1371
+ let copyTimeoutId = null;
1372
+ onCleanup6(() => {
1373
+ if (copyTimeoutId) {
1374
+ clearTimeout(copyTimeoutId);
1375
+ }
1376
+ });
1377
+ async function copyCode() {
1378
+ if (!isClipboardAvailable2()) return;
1379
+ try {
1380
+ await navigator.clipboard.writeText(code());
1381
+ setCopied(true);
1382
+ if (copyTimeoutId) {
1383
+ clearTimeout(copyTimeoutId);
1384
+ }
1385
+ copyTimeoutId = setTimeout(() => {
1386
+ setCopied(false);
1387
+ }, 2e3);
1388
+ } catch {
1389
+ }
1390
+ }
1391
+ return /* @__PURE__ */ jsxs4("div", { class: "incremark-code", children: [
1392
+ /* @__PURE__ */ jsxs4("div", { class: "code-header", children: [
1393
+ /* @__PURE__ */ jsx11("span", { class: "language", children: language() }),
1394
+ /* @__PURE__ */ jsx11(
1395
+ "button",
1396
+ {
1397
+ class: "code-btn",
1398
+ onClick: copyCode,
1399
+ type: "button",
1400
+ "aria-label": copied() ? t("code.copied") : t("code.copy"),
1401
+ title: copied() ? "Copied!" : "Copy",
1402
+ children: /* @__PURE__ */ jsx11(SvgIcon, { svg: copied() ? LucideCopyCheck2 : LucideCopy2 })
1403
+ }
1404
+ )
1405
+ ] }),
1406
+ /* @__PURE__ */ jsx11("div", { class: "code-content", children: /* @__PURE__ */ jsx11("div", { class: "shiki-wrapper", children: /* @__PURE__ */ jsx11(
1407
+ Show6,
1408
+ {
1409
+ when: shouldEnableHighlight() && highlighterInfo() && isLanguageLoaded(),
1410
+ fallback: (
1411
+ // 无高亮模式(禁用高亮、无代码内容、或语言未加载完成时显示)
1412
+ /* @__PURE__ */ jsx11("pre", { class: "code-fallback", children: /* @__PURE__ */ jsx11("code", { children: code() }) })
1413
+ ),
1414
+ children: /* @__PURE__ */ jsx11(
1415
+ CachedCodeRenderer,
1416
+ {
1417
+ code: code(),
1418
+ lang: language(),
1419
+ theme: props.theme ?? "github-dark",
1420
+ highlighter: highlighterInfo().highlighter
1421
+ }
1422
+ )
1423
+ }
1424
+ ) }) })
1425
+ ] });
1426
+ };
1427
+
1428
+ // src/components/IncremarkCode.tsx
1429
+ import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs5 } from "solid-js/jsx-runtime";
1430
+ var IncremarkCode = (props) => {
1431
+ const language = () => props.node.lang || "text";
1432
+ const CustomCodeBlock = () => props.customCodeBlocks?.[language()];
1433
+ const shouldUseCustomCodeBlock = () => {
1434
+ const component = props.customCodeBlocks?.[language()];
1435
+ if (!component) return false;
1436
+ const config = props.codeBlockConfigs?.[language()];
1437
+ if (config?.takeOver) {
1438
+ return true;
1439
+ }
1440
+ return props.blockStatus === "completed";
1441
+ };
1442
+ const isMermaid = () => language() === "mermaid";
1443
+ const DefaultCodeComponent = () => props.defaultCodeComponent ?? IncremarkCodeDefault;
1444
+ const customProps = () => ({
1445
+ codeStr: props.node.value,
1446
+ lang: language(),
1447
+ completed: props.blockStatus === "completed",
1448
+ takeOver: props.codeBlockConfigs?.[language()]?.takeOver
1449
+ });
1450
+ const defaultProps = () => ({
1451
+ node: props.node,
1452
+ theme: props.theme,
1453
+ fallbackTheme: props.fallbackTheme,
1454
+ disableHighlight: props.disableHighlight,
1455
+ blockStatus: props.blockStatus
1456
+ });
1457
+ const mermaidProps = () => ({
1458
+ node: props.node,
1459
+ mermaidDelay: props.mermaidDelay
1460
+ });
1461
+ return /* @__PURE__ */ jsxs5(Fragment3, { children: [
1462
+ /* @__PURE__ */ jsx12(Show7, { when: CustomCodeBlock() && shouldUseCustomCodeBlock(), children: /* @__PURE__ */ jsx12(
1463
+ Dynamic3,
1464
+ {
1465
+ component: CustomCodeBlock(),
1466
+ ...customProps()
1467
+ }
1468
+ ) }),
1469
+ /* @__PURE__ */ jsx12(Show7, { when: isMermaid() && !shouldUseCustomCodeBlock(), children: /* @__PURE__ */ jsx12(
1470
+ IncremarkCodeMermaid,
1471
+ {
1472
+ node: props.node,
1473
+ mermaidDelay: props.mermaidDelay
1474
+ }
1475
+ ) }),
1476
+ /* @__PURE__ */ jsx12(Show7, { when: !isMermaid() && !shouldUseCustomCodeBlock(), children: /* @__PURE__ */ jsx12(
1477
+ Dynamic3,
1478
+ {
1479
+ component: DefaultCodeComponent(),
1480
+ ...defaultProps()
1481
+ }
1482
+ ) })
1483
+ ] });
1484
+ };
1485
+ var IncremarkCode_default = IncremarkCode;
1486
+
1487
+ // src/components/IncremarkList.tsx
1488
+ import { Show as Show8, Index as Index2 } from "solid-js";
1489
+ import { jsx as jsx13, jsxs as jsxs6 } from "solid-js/jsx-runtime";
1490
+ var IncremarkList = (props) => {
1491
+ const ordered = () => props.node.ordered;
1492
+ const start = () => props.node.start || void 0;
1493
+ function getItemInlineContent(item) {
1494
+ const firstChild = item.children[0];
1495
+ if (firstChild?.type === "paragraph") {
1496
+ return firstChild.children;
1497
+ }
1498
+ return [];
1499
+ }
1500
+ function getItemBlockChildren(item) {
1501
+ return item.children.filter((child, index) => {
1502
+ if (index === 0 && child.type === "paragraph") {
1503
+ return false;
1504
+ }
1505
+ return true;
1506
+ });
1507
+ }
1508
+ function hasBlockChildren(item) {
1509
+ return getItemBlockChildren(item).length > 0;
1510
+ }
1511
+ const hasTaskList = () => props.node.children.some((item) => item.checked !== null && item.checked !== void 0);
1512
+ return /* @__PURE__ */ jsx13(
1513
+ Show8,
1514
+ {
1515
+ when: ordered(),
1516
+ fallback: /* @__PURE__ */ jsx13(
1517
+ "ul",
1518
+ {
1519
+ class: `incremark-list${hasTaskList() ? " task-list" : ""}`,
1520
+ children: /* @__PURE__ */ jsx13(Index2, { each: props.node.children, children: (item, index) => {
1521
+ const itemData = item();
1522
+ const isTaskItem = itemData.checked !== null && itemData.checked !== void 0;
1523
+ return /* @__PURE__ */ jsxs6(
1524
+ "li",
1525
+ {
1526
+ class: `incremark-list-item${isTaskItem ? " task-item" : ""}`,
1527
+ children: [
1528
+ /* @__PURE__ */ jsx13(Show8, { when: isTaskItem, children: /* @__PURE__ */ jsxs6("label", { class: "task-label", children: [
1529
+ /* @__PURE__ */ jsx13(
1530
+ "input",
1531
+ {
1532
+ type: "checkbox",
1533
+ checked: itemData.checked ?? false,
1534
+ disabled: true,
1535
+ class: "checkbox"
1536
+ }
1537
+ ),
1538
+ /* @__PURE__ */ jsx13("span", { class: "task-content", children: /* @__PURE__ */ jsx13(IncremarkInline, { nodes: getItemInlineContent(itemData) }) })
1539
+ ] }) }),
1540
+ /* @__PURE__ */ jsxs6(Show8, { when: !isTaskItem, children: [
1541
+ /* @__PURE__ */ jsx13(IncremarkInline, { nodes: getItemInlineContent(itemData) }),
1542
+ /* @__PURE__ */ jsx13(Show8, { when: hasBlockChildren(itemData), children: /* @__PURE__ */ jsx13(Index2, { each: getItemBlockChildren(itemData), children: (child) => /* @__PURE__ */ jsx13(IncremarkRenderer, { node: child() }) }) })
1543
+ ] })
1544
+ ]
1545
+ }
1546
+ );
1547
+ } })
1548
+ }
1549
+ ),
1550
+ children: /* @__PURE__ */ jsx13(
1551
+ "ol",
1552
+ {
1553
+ class: `incremark-list${hasTaskList() ? " task-list" : ""}`,
1554
+ start: start(),
1555
+ children: /* @__PURE__ */ jsx13(Index2, { each: props.node.children, children: (item, index) => {
1556
+ const itemData = item();
1557
+ const isTaskItem = itemData.checked !== null && itemData.checked !== void 0;
1558
+ return /* @__PURE__ */ jsxs6(
1559
+ "li",
1560
+ {
1561
+ class: `incremark-list-item${isTaskItem ? " task-item" : ""}`,
1562
+ children: [
1563
+ /* @__PURE__ */ jsx13(Show8, { when: isTaskItem, children: /* @__PURE__ */ jsxs6("label", { class: "task-label", children: [
1564
+ /* @__PURE__ */ jsx13(
1565
+ "input",
1566
+ {
1567
+ type: "checkbox",
1568
+ checked: itemData.checked ?? false,
1569
+ disabled: true,
1570
+ class: "checkbox"
1571
+ }
1572
+ ),
1573
+ /* @__PURE__ */ jsx13("span", { class: "task-content", children: /* @__PURE__ */ jsx13(IncremarkInline, { nodes: getItemInlineContent(itemData) }) })
1574
+ ] }) }),
1575
+ /* @__PURE__ */ jsxs6(Show8, { when: !isTaskItem, children: [
1576
+ /* @__PURE__ */ jsx13(IncremarkInline, { nodes: getItemInlineContent(itemData) }),
1577
+ /* @__PURE__ */ jsx13(Show8, { when: hasBlockChildren(itemData), children: /* @__PURE__ */ jsx13(Index2, { each: getItemBlockChildren(itemData), children: (child) => /* @__PURE__ */ jsx13(IncremarkRenderer, { node: child() }) }) })
1578
+ ] })
1579
+ ]
1580
+ }
1581
+ );
1582
+ } })
1583
+ }
1584
+ )
1585
+ }
1586
+ );
1587
+ };
1588
+
1589
+ // src/components/IncremarkTable.tsx
1590
+ import { For as For5, Show as Show9 } from "solid-js";
1591
+ import { jsx as jsx14, jsxs as jsxs7 } from "solid-js/jsx-runtime";
1592
+ var IncremarkTable = (props) => {
1593
+ function getCellContent(cell) {
1594
+ return cell.children;
1595
+ }
1596
+ const firstRow = () => props.node.children[0];
1597
+ const remainingRows = () => props.node.children.slice(1);
1598
+ const getAlignClass = (cellIndex) => {
1599
+ return `incremark-table-align-${props.node.align?.[cellIndex] || "left"}`;
1600
+ };
1601
+ return /* @__PURE__ */ jsx14("div", { class: "incremark-table-wrapper", children: /* @__PURE__ */ jsxs7("table", { class: "incremark-table", children: [
1602
+ /* @__PURE__ */ jsx14(Show9, { when: firstRow(), children: /* @__PURE__ */ jsx14("thead", { children: /* @__PURE__ */ jsx14("tr", { children: /* @__PURE__ */ jsx14(For5, { each: firstRow().children, children: (cell, cellIndex) => /* @__PURE__ */ jsx14("th", { class: getAlignClass(cellIndex()), children: /* @__PURE__ */ jsx14(IncremarkInline, { nodes: getCellContent(cell) }) }) }) }) }) }),
1603
+ /* @__PURE__ */ jsx14("tbody", { children: /* @__PURE__ */ jsx14(For5, { each: remainingRows(), children: (row) => /* @__PURE__ */ jsx14("tr", { children: /* @__PURE__ */ jsx14(For5, { each: row.children, children: (cell, cellIndex) => /* @__PURE__ */ jsx14("td", { class: getAlignClass(cellIndex()), children: /* @__PURE__ */ jsx14(IncremarkInline, { nodes: getCellContent(cell) }) }) }) }) }) })
1604
+ ] }) });
1605
+ };
1606
+
1607
+ // src/components/IncremarkBlockquote.tsx
1608
+ import { For as For6 } from "solid-js";
1609
+ import { jsx as jsx15 } from "solid-js/jsx-runtime";
1610
+ var IncremarkBlockquote = (props) => {
1611
+ return /* @__PURE__ */ jsx15("blockquote", { class: "incremark-blockquote", children: /* @__PURE__ */ jsx15(For6, { each: props.node.children, children: (child) => /* @__PURE__ */ jsx15(IncremarkRenderer, { node: child }) }) });
1612
+ };
1613
+
1614
+ // src/components/IncremarkThematicBreak.tsx
1615
+ import { jsx as jsx16 } from "solid-js/jsx-runtime";
1616
+ var IncremarkThematicBreak = () => {
1617
+ return /* @__PURE__ */ jsx16("hr", { class: "incremark-thematic-break" });
1618
+ };
1619
+
1620
+ // src/components/IncremarkContainer.tsx
1621
+ import { For as For7, Show as Show10 } from "solid-js";
1622
+ import { Dynamic as Dynamic4 } from "solid-js/web";
1623
+ import { jsx as jsx17 } from "solid-js/jsx-runtime";
1624
+ function parseOptions(attributes) {
1625
+ if (!attributes) return {};
1626
+ const options = {};
1627
+ for (const [key, value] of Object.entries(attributes)) {
1628
+ try {
1629
+ options[key] = JSON.parse(value);
1630
+ } catch {
1631
+ options[key] = value;
1632
+ }
1633
+ }
1634
+ return options;
1635
+ }
1636
+ var IncremarkContainer = (props) => {
1637
+ const containerName = () => props.node.name;
1638
+ const options = () => parseOptions(props.node.attributes);
1639
+ const CustomContainer = () => props.customContainers?.[containerName()];
1640
+ const hasCustomContainer = () => !!props.customContainers?.[containerName()];
1641
+ return /* @__PURE__ */ jsx17(
1642
+ Show10,
1643
+ {
1644
+ when: hasCustomContainer(),
1645
+ fallback: /* @__PURE__ */ jsx17("div", { class: `incremark-container incremark-container-${containerName()}`, children: /* @__PURE__ */ jsx17(Show10, { when: props.node.children && props.node.children.length > 0, children: /* @__PURE__ */ jsx17("div", { class: "incremark-container-content", children: /* @__PURE__ */ jsx17(For7, { each: props.node.children, children: (child) => /* @__PURE__ */ jsx17(IncremarkRenderer, { node: child }) }) }) }) }),
1646
+ children: /* @__PURE__ */ jsx17(
1647
+ Dynamic4,
1648
+ {
1649
+ component: CustomContainer(),
1650
+ name: containerName(),
1651
+ options: options(),
1652
+ children: /* @__PURE__ */ jsx17(Show10, { when: props.node.children && props.node.children.length > 0, children: /* @__PURE__ */ jsx17(For7, { each: props.node.children, children: (child) => /* @__PURE__ */ jsx17(IncremarkRenderer, { node: child }) }) })
1653
+ }
1654
+ )
1655
+ }
1656
+ );
1657
+ };
1658
+
1659
+ // src/components/IncremarkDefault.tsx
1660
+ import { jsx as jsx18 } from "solid-js/jsx-runtime";
1661
+ var IncremarkDefault = (props) => {
1662
+ return /* @__PURE__ */ jsx18("pre", { class: "incremark-debug", children: /* @__PURE__ */ jsx18("code", { children: JSON.stringify(props.node, null, 2) }) });
1663
+ };
1664
+
1665
+ // src/components/IncremarkRenderer.tsx
1666
+ import { Fragment as Fragment4, jsx as jsx19, jsxs as jsxs8 } from "solid-js/jsx-runtime";
1667
+ var defaultComponentMap = {
1668
+ heading: IncremarkHeading,
1669
+ paragraph: IncremarkParagraph,
1670
+ code: IncremarkCode_default,
1671
+ list: IncremarkList,
1672
+ table: IncremarkTable,
1673
+ blockquote: IncremarkBlockquote,
1674
+ thematicBreak: IncremarkThematicBreak,
1675
+ math: IncremarkMath,
1676
+ inlineMath: IncremarkMath,
1677
+ htmlElement: IncremarkHtmlElement,
1678
+ containerDirective: IncremarkContainer,
1679
+ leafDirective: IncremarkContainer,
1680
+ textDirective: IncremarkContainer
1681
+ };
1682
+ function getComponent(type, customComponents) {
1683
+ const map = { ...defaultComponentMap, ...customComponents };
1684
+ return map[type] || IncremarkDefault;
1685
+ }
1686
+ function isContainerNode(node) {
1687
+ const type = node.type;
1688
+ return type === "containerDirective" || type === "leafDirective" || type === "textDirective";
1689
+ }
1690
+ function isHtmlNode2(node) {
1691
+ return node.type === "html";
1692
+ }
1693
+ var IncremarkRenderer = (props) => {
1694
+ return /* @__PURE__ */ jsxs8(Fragment4, { children: [
1695
+ /* @__PURE__ */ jsx19(Show11, { when: isHtmlNode2(props.node), children: /* @__PURE__ */ jsx19("pre", { class: "incremark-html-code", children: /* @__PURE__ */ jsx19("code", { children: props.node.value }) }) }),
1696
+ /* @__PURE__ */ jsx19(Show11, { when: isContainerNode(props.node) && !isHtmlNode2(props.node), children: /* @__PURE__ */ jsx19(
1697
+ IncremarkContainer,
1698
+ {
1699
+ node: props.node,
1700
+ customContainers: props.customContainers
1701
+ }
1702
+ ) }),
1703
+ /* @__PURE__ */ jsx19(
1704
+ Show11,
1705
+ {
1706
+ when: props.node.type === "code" && !isHtmlNode2(props.node) && !isContainerNode(props.node),
1707
+ children: /* @__PURE__ */ jsx19(
1708
+ IncremarkCode_default,
1709
+ {
1710
+ node: props.node,
1711
+ customCodeBlocks: props.customCodeBlocks,
1712
+ codeBlockConfigs: props.codeBlockConfigs,
1713
+ blockStatus: props.blockStatus,
1714
+ defaultCodeComponent: props.components?.["code"]
1715
+ }
1716
+ )
1717
+ }
1718
+ ),
1719
+ /* @__PURE__ */ jsx19(
1720
+ Show11,
1721
+ {
1722
+ when: props.node.type !== "code" && !isHtmlNode2(props.node) && !isContainerNode(props.node),
1723
+ children: /* @__PURE__ */ jsx19(
1724
+ Dynamic5,
1725
+ {
1726
+ component: getComponent(props.node.type, props.components),
1727
+ node: props.node
1728
+ }
1729
+ )
1730
+ }
1731
+ )
1732
+ ] });
1733
+ };
1734
+ var IncremarkRenderer_default = IncremarkRenderer;
1735
+
1736
+ // src/components/IncremarkFootnotes.tsx
1737
+ import { For as For8, Show as Show12 } from "solid-js";
1738
+ import { jsx as jsx20, jsxs as jsxs9 } from "solid-js/jsx-runtime";
1739
+ var IncremarkFootnotes = () => {
1740
+ const { footnoteDefinitions, footnoteReferenceOrder } = useDefinationsContext();
1741
+ const orderedFootnotes = () => {
1742
+ return footnoteReferenceOrder().map((identifier) => ({
1743
+ identifier,
1744
+ definition: footnoteDefinitions()[identifier]
1745
+ })).filter((item) => item.definition !== void 0);
1746
+ };
1747
+ const hasFootnotes = () => orderedFootnotes().length > 0;
1748
+ return /* @__PURE__ */ jsx20(Show12, { when: hasFootnotes(), children: /* @__PURE__ */ jsxs9("section", { class: "incremark-footnotes", children: [
1749
+ /* @__PURE__ */ jsx20("hr", { class: "incremark-footnotes-divider" }),
1750
+ /* @__PURE__ */ jsx20("ol", { class: "incremark-footnotes-list", children: /* @__PURE__ */ jsx20(For8, { each: orderedFootnotes(), children: (item, index) => /* @__PURE__ */ jsxs9(
1751
+ "li",
1752
+ {
1753
+ id: `fn-${item.identifier}`,
1754
+ class: "incremark-footnote-item",
1755
+ children: [
1756
+ /* @__PURE__ */ jsxs9("div", { class: "incremark-footnote-content", children: [
1757
+ /* @__PURE__ */ jsxs9("span", { class: "incremark-footnote-number", children: [
1758
+ index() + 1,
1759
+ "."
1760
+ ] }),
1761
+ /* @__PURE__ */ jsx20("div", { class: "incremark-footnote-body", children: /* @__PURE__ */ jsx20(For8, { each: item.definition.children, children: (child) => /* @__PURE__ */ jsx20(
1762
+ IncremarkRenderer_default,
1763
+ {
1764
+ node: child
1765
+ }
1766
+ ) }) })
1767
+ ] }),
1768
+ /* @__PURE__ */ jsx20(
1769
+ "a",
1770
+ {
1771
+ href: `#fnref-${item.identifier}`,
1772
+ class: "incremark-footnote-backref",
1773
+ "aria-label": "\u8FD4\u56DE\u5F15\u7528\u4F4D\u7F6E",
1774
+ children: "\u21A9"
1775
+ }
1776
+ )
1777
+ ]
1778
+ }
1779
+ ) }) })
1780
+ ] }) });
1781
+ };
1782
+
1783
+ // src/components/Incremark.tsx
1784
+ import { jsx as jsx21, jsxs as jsxs10 } from "solid-js/jsx-runtime";
1785
+ function IncremarkInner(props) {
1786
+ const mergedProps = mergeProps({
1787
+ isDisplayComplete: false,
1788
+ pendingClass: "incremark-pending",
1789
+ completedClass: "incremark-completed",
1790
+ showBlockStatus: false
1791
+ }, props);
1792
+ const components = () => mergedProps.components || {};
1793
+ const customContainers = () => mergedProps.customContainers || {};
1794
+ const customCodeBlocks = () => mergedProps.customCodeBlocks || {};
1795
+ const codeBlockConfigs = () => mergedProps.codeBlockConfigs || {};
1796
+ const {
1797
+ footnoteReferenceOrder
1798
+ } = useDefinationsContext();
1799
+ const actualBlocks = () => {
1800
+ if (mergedProps.incremark) {
1801
+ return mergedProps.incremark.blocks;
1802
+ }
1803
+ return typeof mergedProps.blocks === "function" ? mergedProps.blocks() : mergedProps.blocks;
1804
+ };
1805
+ const actualIsDisplayComplete = () => {
1806
+ if (mergedProps.incremark) {
1807
+ return mergedProps.incremark.isDisplayComplete();
1808
+ }
1809
+ return typeof mergedProps.isDisplayComplete === "function" ? mergedProps.isDisplayComplete() : mergedProps.isDisplayComplete;
1810
+ };
1811
+ return /* @__PURE__ */ jsxs10("div", { class: "incremark", children: [
1812
+ /* @__PURE__ */ jsx21(For9, { each: actualBlocks(), children: (block) => /* @__PURE__ */ jsx21(
1813
+ Show13,
1814
+ {
1815
+ when: block.node.type !== "definition" && block.node.type !== "footnoteDefinition",
1816
+ children: /* @__PURE__ */ jsx21(
1817
+ "div",
1818
+ {
1819
+ class: `incremark-block ${block.status === "completed" ? mergedProps.completedClass : mergedProps.pendingClass}${mergedProps.showBlockStatus ? " incremark-show-status" : ""}${block.isLastPending ? " incremark-last-pending" : ""}`,
1820
+ children: /* @__PURE__ */ jsx21(
1821
+ IncremarkRenderer_default,
1822
+ {
1823
+ node: block.node,
1824
+ customContainers: customContainers(),
1825
+ customCodeBlocks: customCodeBlocks(),
1826
+ codeBlockConfigs: codeBlockConfigs(),
1827
+ components: components(),
1828
+ blockStatus: block.status
1829
+ }
1830
+ )
1831
+ }
1832
+ )
1833
+ }
1834
+ ) }),
1835
+ /* @__PURE__ */ jsx21(Show13, { when: actualIsDisplayComplete() && footnoteReferenceOrder().length > 0, children: /* @__PURE__ */ jsx21(IncremarkFootnotes, {}) })
1836
+ ] });
1837
+ }
1838
+ var Incremark = (props) => {
1839
+ return /* @__PURE__ */ jsx21(IncremarkInner, { ...props });
1840
+ };
1841
+ var Incremark_default = Incremark;
1842
+
1843
+ // src/components/IncremarkContent.tsx
1844
+ import { createEffect as createEffect8 } from "solid-js";
1845
+ import { jsx as jsx22 } from "solid-js/jsx-runtime";
1846
+ var IncremarkContent = (props) => {
1847
+ const incremarkOptions = () => ({
1848
+ gfm: true,
1849
+ htmlTree: true,
1850
+ containers: true,
1851
+ math: true,
1852
+ ...props.incremarkOptions
1853
+ });
1854
+ const { blocks, append, finalize, render, reset, isDisplayComplete, markdown, contextValue, DefinationsProvider: DefinationsProvider2 } = useIncremark(incremarkOptions);
1855
+ const isStreamMode = () => typeof props.stream === "function";
1856
+ async function handleStreamInput() {
1857
+ if (!props.stream) return;
1858
+ try {
1859
+ const stream = props.stream();
1860
+ for await (const chunk of stream) {
1861
+ append(chunk);
1862
+ }
1863
+ finalize();
1864
+ } catch (error) {
1865
+ console.error("Stream error: ", error);
1866
+ finalize();
1867
+ }
1868
+ }
1869
+ function handleContentInput(newContent, oldContent) {
1870
+ if (!newContent) {
1871
+ if (oldContent) {
1872
+ reset();
1873
+ }
1874
+ return;
1875
+ }
1876
+ if (newContent?.startsWith(oldContent ?? "")) {
1877
+ const delta = newContent.slice((oldContent || "").length);
1878
+ append(delta);
1879
+ } else {
1880
+ render(newContent);
1881
+ }
1882
+ }
1883
+ createEffect8(() => {
1884
+ const newContent = props.content;
1885
+ if (isStreamMode()) {
1886
+ handleStreamInput();
1887
+ } else {
1888
+ handleContentInput(newContent, markdown());
1889
+ }
1890
+ });
1891
+ createEffect8(() => {
1892
+ const newIsFinished = props.isFinished;
1893
+ if (newIsFinished && props.content === markdown()) {
1894
+ finalize();
1895
+ }
1896
+ });
1897
+ return /* @__PURE__ */ jsx22(DefinationsProvider2, { value: contextValue, children: /* @__PURE__ */ jsx22(
1898
+ Incremark_default,
1899
+ {
1900
+ blocks,
1901
+ pendingClass: props.pendingClass,
1902
+ isDisplayComplete: isDisplayComplete(),
1903
+ showBlockStatus: props.showBlockStatus,
1904
+ components: props.components,
1905
+ customContainers: props.customContainers,
1906
+ customCodeBlocks: props.customCodeBlocks,
1907
+ codeBlockConfigs: props.codeBlockConfigs
1908
+ }
1909
+ ) });
1910
+ };
1911
+
1912
+ // src/components/AutoScrollContainer.tsx
1913
+ import { createSignal as createSignal13, onCleanup as onCleanup7, onMount as onMount4 } from "solid-js";
1914
+ import { jsx as jsx23 } from "solid-js/jsx-runtime";
1915
+ var AutoScrollContainer = (props) => {
1916
+ let containerRef;
1917
+ const [isUserScrolledUp, setIsUserScrolledUp] = createSignal13(false);
1918
+ let lastScrollTop = 0;
1919
+ let lastScrollHeight = 0;
1920
+ const enabled = () => typeof props.enabled === "function" ? props.enabled() : props.enabled ?? true;
1921
+ const threshold = () => props.threshold ?? 50;
1922
+ const scrollBehavior = () => props.behavior ?? "instant";
1923
+ function isNearBottom() {
1924
+ if (!containerRef) return true;
1925
+ const { scrollTop, scrollHeight, clientHeight } = containerRef;
1926
+ return scrollHeight - scrollTop - clientHeight <= threshold();
1927
+ }
1928
+ function scrollToBottom(force = false) {
1929
+ if (!containerRef) return;
1930
+ if (isUserScrolledUp() && !force) return;
1931
+ containerRef.scrollTo({
1932
+ top: containerRef.scrollHeight,
1933
+ behavior: scrollBehavior()
1934
+ });
1935
+ }
1936
+ function hasScrollbar() {
1937
+ if (!containerRef) return false;
1938
+ return containerRef.scrollHeight > containerRef.clientHeight;
1939
+ }
1940
+ function handleScroll() {
1941
+ if (!containerRef) return;
1942
+ const { scrollTop, scrollHeight, clientHeight } = containerRef;
1943
+ if (scrollHeight <= clientHeight) {
1944
+ setIsUserScrolledUp(false);
1945
+ lastScrollTop = 0;
1946
+ lastScrollHeight = scrollHeight;
1947
+ return;
1948
+ }
1949
+ if (isNearBottom()) {
1950
+ setIsUserScrolledUp(false);
1951
+ } else {
1952
+ const isScrollingUp = scrollTop < lastScrollTop;
1953
+ const isContentUnchanged = scrollHeight === lastScrollHeight;
1954
+ if (isScrollingUp && isContentUnchanged) {
1955
+ setIsUserScrolledUp(true);
1956
+ }
1957
+ }
1958
+ lastScrollTop = scrollTop;
1959
+ lastScrollHeight = scrollHeight;
1960
+ }
1961
+ let observer = null;
1962
+ onMount4(() => {
1963
+ if (!containerRef) return;
1964
+ lastScrollTop = containerRef.scrollTop;
1965
+ lastScrollHeight = containerRef.scrollHeight;
1966
+ observer = new MutationObserver(() => {
1967
+ requestAnimationFrame(() => {
1968
+ if (!containerRef) return;
1969
+ if (!hasScrollbar()) {
1970
+ setIsUserScrolledUp(false);
1971
+ }
1972
+ lastScrollHeight = containerRef.scrollHeight;
1973
+ if (enabled() && !isUserScrolledUp()) {
1974
+ scrollToBottom();
1975
+ }
1976
+ });
1977
+ });
1978
+ observer.observe(containerRef, {
1979
+ childList: true,
1980
+ subtree: true,
1981
+ characterData: true
1982
+ });
1983
+ });
1984
+ onCleanup7(() => {
1985
+ observer?.disconnect();
1986
+ });
1987
+ return /* @__PURE__ */ jsx23(
1988
+ "div",
1989
+ {
1990
+ ref: containerRef,
1991
+ class: "auto-scroll-container",
1992
+ onScroll: handleScroll,
1993
+ children: props.children
1994
+ }
1995
+ );
1996
+ };
1997
+
1998
+ // src/components/ThemeProvider.tsx
1999
+ import { createContext as createContext3, useContext as useContext3, createMemo as createMemo4, createSignal as createSignal14 } from "solid-js";
2000
+ import { applyTheme } from "@incremark/theme";
2001
+ import { jsx as jsx24 } from "solid-js/jsx-runtime";
2002
+ var ThemeContext = createContext3();
2003
+ var ThemeProvider = (props) => {
2004
+ let containerRef;
2005
+ const [theme, setTheme] = createSignal14(props.theme || "default");
2006
+ createMemo4(() => {
2007
+ const currentTheme = props.theme || "default";
2008
+ setTheme(currentTheme);
2009
+ if (typeof document !== "undefined" && containerRef) {
2010
+ applyTheme(containerRef, currentTheme);
2011
+ }
2012
+ });
2013
+ return /* @__PURE__ */ jsx24(ThemeContext.Provider, { value: { theme, setTheme }, children: /* @__PURE__ */ jsx24("div", { ref: containerRef, class: "incremark-theme-provider", children: props.children }) });
2014
+ };
2015
+ function useTheme() {
2016
+ const context = useContext3(ThemeContext);
2017
+ if (!context) {
2018
+ throw new Error("useTheme must be used within a ThemeProvider");
2019
+ }
2020
+ return context;
2021
+ }
2022
+
2023
+ // src/index.ts
2024
+ import {
2025
+ BlockTransformer,
2026
+ createBlockTransformer as createBlockTransformer3,
2027
+ countChars,
2028
+ sliceAst,
2029
+ cloneNode,
2030
+ codeBlockPlugin,
2031
+ mermaidPlugin,
2032
+ imagePlugin,
2033
+ mathPlugin as mathPlugin2,
2034
+ thematicBreakPlugin,
2035
+ defaultPlugins as defaultPlugins2,
2036
+ allPlugins,
2037
+ createPlugin
2038
+ } from "@incremark/core";
2039
+ import {
2040
+ defaultTheme,
2041
+ darkTheme,
2042
+ generateCSSVars,
2043
+ mergeTheme,
2044
+ applyTheme as applyTheme2
2045
+ } from "@incremark/theme";
2046
+ import { en as enShared, zhCN as zhCNShared } from "@incremark/shared";
2047
+ export {
2048
+ AutoScrollContainer,
2049
+ BlockTransformer,
2050
+ CachedCodeRenderer,
2051
+ ConfigProvider,
2052
+ ConfigProvider as ConfigProviderExport,
2053
+ Incremark,
2054
+ IncremarkBlockquote,
2055
+ IncremarkCode,
2056
+ IncremarkCode_default as IncremarkCodeAlias,
2057
+ IncremarkCodeDefault,
2058
+ IncremarkCodeMermaid,
2059
+ IncremarkContainer,
2060
+ IncremarkContent,
2061
+ IncremarkDefault,
2062
+ IncremarkFootnotes,
2063
+ IncremarkHeading,
2064
+ IncremarkHtmlElement,
2065
+ IncremarkInline,
2066
+ IncremarkList,
2067
+ IncremarkMath,
2068
+ IncremarkParagraph,
2069
+ IncremarkRenderer,
2070
+ IncremarkTable,
2071
+ IncremarkThematicBreak,
2072
+ SvgIcon,
2073
+ ThemeProvider,
2074
+ ThemeProvider as ThemeProviderExport,
2075
+ allPlugins,
2076
+ applyTheme2 as applyTheme,
2077
+ clearAnimatedChunks,
2078
+ cloneNode,
2079
+ codeBlockPlugin,
2080
+ countChars,
2081
+ createBlockTransformer3 as createBlockTransformer,
2082
+ createPlugin,
2083
+ darkTheme,
2084
+ defaultPlugins2 as defaultPlugins,
2085
+ defaultTheme,
2086
+ enShared as en,
2087
+ generateCSSVars,
2088
+ imagePlugin,
2089
+ mathPlugin2 as mathPlugin,
2090
+ mergeTheme,
2091
+ mermaidPlugin,
2092
+ shouldAnimateChunk,
2093
+ sliceAst,
2094
+ thematicBreakPlugin,
2095
+ useBlockTransformer,
2096
+ useDefinationsContext,
2097
+ useDevTools,
2098
+ useIncremark,
2099
+ useLocale,
2100
+ useProvideDefinations,
2101
+ useStreamRenderer,
2102
+ useTheme,
2103
+ zhCNShared as zhCN
2104
+ };
2105
+ /**
2106
+ * @file useTypewriter Composable - 打字机效果管理
2107
+ *
2108
+ * @description
2109
+ * 管理打字机效果的状态和控制逻辑。
2110
+ *
2111
+ * @author Incremark Team
2112
+ * @license MIT
2113
+ */
2114
+ /**
2115
+ * @file Animated Chunks Tracker
2116
+ *
2117
+ * @description
2118
+ * 跟踪已播放过动画的 chunk,避免重复播放动画导致闪烁
2119
+ *
2120
+ * @author Incremark Team
2121
+ * @license MIT
2122
+ */
2123
+ //# sourceMappingURL=index.js.map