@incremark/vue 0.0.4 → 0.1.0
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 +180 -1
- package/dist/index.css +17 -0
- package/dist/index.css.map +1 -1
- package/dist/index.js +460 -48
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/AutoScrollContainer.vue +164 -0
- package/src/components/Incremark.vue +3 -1
- package/src/components/IncremarkInline.vue +83 -10
- package/src/components/index.ts +3 -0
- package/src/composables/index.ts +4 -1
- package/src/composables/useBlockTransformer.ts +141 -0
- package/src/composables/useIncremark.ts +239 -27
- package/src/index.ts +37 -4
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// src/composables/useIncremark.ts
|
|
2
|
-
import { ref, shallowRef, computed, markRaw } from "vue";
|
|
2
|
+
import { ref, shallowRef, computed, markRaw, watch, onUnmounted } from "vue";
|
|
3
3
|
import {
|
|
4
|
-
createIncremarkParser
|
|
4
|
+
createIncremarkParser,
|
|
5
|
+
createBlockTransformer,
|
|
6
|
+
defaultPlugins
|
|
5
7
|
} from "@incremark/core";
|
|
6
8
|
function useIncremark(options = {}) {
|
|
7
9
|
const parser = createIncremarkParser(options);
|
|
@@ -9,6 +11,28 @@ function useIncremark(options = {}) {
|
|
|
9
11
|
const pendingBlocks = shallowRef([]);
|
|
10
12
|
const isLoading = ref(false);
|
|
11
13
|
const markdown = ref("");
|
|
14
|
+
const typewriterEnabled = ref(options.typewriter?.enabled ?? !!options.typewriter);
|
|
15
|
+
const displayBlocksRef = shallowRef([]);
|
|
16
|
+
const isTypewriterProcessing = ref(false);
|
|
17
|
+
const isTypewriterPaused = ref(false);
|
|
18
|
+
const typewriterEffect = ref(options.typewriter?.effect ?? "none");
|
|
19
|
+
const typewriterCursor = ref(options.typewriter?.cursor ?? "|");
|
|
20
|
+
let transformer = null;
|
|
21
|
+
if (options.typewriter) {
|
|
22
|
+
const twOptions = options.typewriter;
|
|
23
|
+
transformer = createBlockTransformer({
|
|
24
|
+
charsPerTick: twOptions.charsPerTick ?? [1, 3],
|
|
25
|
+
tickInterval: twOptions.tickInterval ?? 30,
|
|
26
|
+
effect: twOptions.effect ?? "none",
|
|
27
|
+
pauseOnHidden: twOptions.pauseOnHidden ?? true,
|
|
28
|
+
plugins: twOptions.plugins ?? defaultPlugins,
|
|
29
|
+
onChange: (blocks2) => {
|
|
30
|
+
displayBlocksRef.value = blocks2;
|
|
31
|
+
isTypewriterProcessing.value = transformer?.isProcessing() ?? false;
|
|
32
|
+
isTypewriterPaused.value = transformer?.isPausedState() ?? false;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
12
36
|
const ast = computed(() => ({
|
|
13
37
|
type: "root",
|
|
14
38
|
children: [
|
|
@@ -16,7 +40,55 @@ function useIncremark(options = {}) {
|
|
|
16
40
|
...pendingBlocks.value.map((b) => b.node)
|
|
17
41
|
]
|
|
18
42
|
}));
|
|
19
|
-
const
|
|
43
|
+
const sourceBlocks = computed(() => {
|
|
44
|
+
return completedBlocks.value.map((block) => ({
|
|
45
|
+
id: block.id,
|
|
46
|
+
node: block.node,
|
|
47
|
+
status: block.status
|
|
48
|
+
}));
|
|
49
|
+
});
|
|
50
|
+
if (transformer) {
|
|
51
|
+
watch(
|
|
52
|
+
sourceBlocks,
|
|
53
|
+
(blocks2) => {
|
|
54
|
+
transformer.push(blocks2);
|
|
55
|
+
const currentDisplaying = displayBlocksRef.value.find((b) => !b.isDisplayComplete);
|
|
56
|
+
if (currentDisplaying) {
|
|
57
|
+
const updated = blocks2.find((b) => b.id === currentDisplaying.id);
|
|
58
|
+
if (updated) {
|
|
59
|
+
transformer.update(updated);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
{ immediate: true, deep: true }
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
function addCursorToNode(node, cursor) {
|
|
67
|
+
const cloned = JSON.parse(JSON.stringify(node));
|
|
68
|
+
function addToLast(n) {
|
|
69
|
+
if (n.children && n.children.length > 0) {
|
|
70
|
+
for (let i = n.children.length - 1; i >= 0; i--) {
|
|
71
|
+
if (addToLast(n.children[i])) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
n.children.push({ type: "text", value: cursor });
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
if (n.type === "text" && typeof n.value === "string") {
|
|
79
|
+
n.value += cursor;
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
if (typeof n.value === "string") {
|
|
83
|
+
n.value += cursor;
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
addToLast(cloned);
|
|
89
|
+
return cloned;
|
|
90
|
+
}
|
|
91
|
+
const rawBlocks = computed(() => {
|
|
20
92
|
const result = [];
|
|
21
93
|
for (const block of completedBlocks.value) {
|
|
22
94
|
result.push({ ...block, stableId: block.id });
|
|
@@ -29,6 +101,29 @@ function useIncremark(options = {}) {
|
|
|
29
101
|
}
|
|
30
102
|
return result;
|
|
31
103
|
});
|
|
104
|
+
const blocks = computed(() => {
|
|
105
|
+
if (!typewriterEnabled.value || !transformer) {
|
|
106
|
+
return rawBlocks.value;
|
|
107
|
+
}
|
|
108
|
+
return displayBlocksRef.value.map((db, index) => {
|
|
109
|
+
const isPending = !db.isDisplayComplete;
|
|
110
|
+
const isLastPending = isPending && index === displayBlocksRef.value.length - 1;
|
|
111
|
+
let node = db.displayNode;
|
|
112
|
+
if (typewriterEffect.value === "typing" && isLastPending) {
|
|
113
|
+
node = addCursorToNode(db.displayNode, typewriterCursor.value);
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
id: db.id,
|
|
117
|
+
stableId: db.id,
|
|
118
|
+
status: db.isDisplayComplete ? "completed" : "pending",
|
|
119
|
+
isLastPending,
|
|
120
|
+
node,
|
|
121
|
+
startOffset: 0,
|
|
122
|
+
endOffset: 0,
|
|
123
|
+
rawText: ""
|
|
124
|
+
};
|
|
125
|
+
});
|
|
126
|
+
});
|
|
32
127
|
function append(chunk) {
|
|
33
128
|
isLoading.value = true;
|
|
34
129
|
const update = parser.append(chunk);
|
|
@@ -64,8 +159,9 @@ function useIncremark(options = {}) {
|
|
|
64
159
|
pendingBlocks.value = [];
|
|
65
160
|
markdown.value = "";
|
|
66
161
|
isLoading.value = false;
|
|
162
|
+
transformer?.reset();
|
|
67
163
|
}
|
|
68
|
-
function
|
|
164
|
+
function render14(content) {
|
|
69
165
|
const update = parser.render(content);
|
|
70
166
|
markdown.value = parser.getBuffer();
|
|
71
167
|
completedBlocks.value = parser.getCompletedBlocks().map((b) => markRaw(b));
|
|
@@ -73,6 +169,43 @@ function useIncremark(options = {}) {
|
|
|
73
169
|
isLoading.value = false;
|
|
74
170
|
return update;
|
|
75
171
|
}
|
|
172
|
+
const typewriter = {
|
|
173
|
+
enabled: typewriterEnabled,
|
|
174
|
+
isProcessing: computed(() => isTypewriterProcessing.value),
|
|
175
|
+
isPaused: computed(() => isTypewriterPaused.value),
|
|
176
|
+
effect: computed(() => typewriterEffect.value),
|
|
177
|
+
skip: () => transformer?.skip(),
|
|
178
|
+
pause: () => {
|
|
179
|
+
transformer?.pause();
|
|
180
|
+
isTypewriterPaused.value = true;
|
|
181
|
+
},
|
|
182
|
+
resume: () => {
|
|
183
|
+
transformer?.resume();
|
|
184
|
+
isTypewriterPaused.value = false;
|
|
185
|
+
},
|
|
186
|
+
setOptions: (opts) => {
|
|
187
|
+
if (opts.enabled !== void 0) {
|
|
188
|
+
typewriterEnabled.value = opts.enabled;
|
|
189
|
+
}
|
|
190
|
+
if (opts.charsPerTick !== void 0 || opts.tickInterval !== void 0 || opts.effect !== void 0 || opts.pauseOnHidden !== void 0) {
|
|
191
|
+
transformer?.setOptions({
|
|
192
|
+
charsPerTick: opts.charsPerTick,
|
|
193
|
+
tickInterval: opts.tickInterval,
|
|
194
|
+
effect: opts.effect,
|
|
195
|
+
pauseOnHidden: opts.pauseOnHidden
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
if (opts.effect !== void 0) {
|
|
199
|
+
typewriterEffect.value = opts.effect;
|
|
200
|
+
}
|
|
201
|
+
if (opts.cursor !== void 0) {
|
|
202
|
+
typewriterCursor.value = opts.cursor;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
onUnmounted(() => {
|
|
207
|
+
transformer?.destroy();
|
|
208
|
+
});
|
|
76
209
|
return {
|
|
77
210
|
/** 已收集的完整 Markdown 字符串 */
|
|
78
211
|
markdown,
|
|
@@ -82,7 +215,7 @@ function useIncremark(options = {}) {
|
|
|
82
215
|
pendingBlocks,
|
|
83
216
|
/** 当前完整的 AST */
|
|
84
217
|
ast,
|
|
85
|
-
/**
|
|
218
|
+
/** 用于渲染的 blocks(根据打字机设置自动处理) */
|
|
86
219
|
blocks,
|
|
87
220
|
/** 是否正在加载 */
|
|
88
221
|
isLoading,
|
|
@@ -92,12 +225,14 @@ function useIncremark(options = {}) {
|
|
|
92
225
|
finalize,
|
|
93
226
|
/** 强制中断 */
|
|
94
227
|
abort,
|
|
95
|
-
/**
|
|
228
|
+
/** 重置解析器和打字机 */
|
|
96
229
|
reset,
|
|
97
230
|
/** 一次性渲染(reset + append + finalize) */
|
|
98
|
-
render:
|
|
231
|
+
render: render14,
|
|
99
232
|
/** 解析器实例 */
|
|
100
|
-
parser
|
|
233
|
+
parser,
|
|
234
|
+
/** 打字机控制 */
|
|
235
|
+
typewriter
|
|
101
236
|
};
|
|
102
237
|
}
|
|
103
238
|
|
|
@@ -126,7 +261,7 @@ function useStreamRenderer(options) {
|
|
|
126
261
|
}
|
|
127
262
|
|
|
128
263
|
// src/composables/useDevTools.ts
|
|
129
|
-
import { onMounted, onUnmounted } from "vue";
|
|
264
|
+
import { onMounted, onUnmounted as onUnmounted2 } from "vue";
|
|
130
265
|
import { createDevTools } from "@incremark/devtools";
|
|
131
266
|
function useDevTools(incremark, options = {}) {
|
|
132
267
|
const devtools = createDevTools(options);
|
|
@@ -147,27 +282,87 @@ function useDevTools(incremark, options = {}) {
|
|
|
147
282
|
onMounted(() => {
|
|
148
283
|
devtools.mount();
|
|
149
284
|
});
|
|
150
|
-
|
|
285
|
+
onUnmounted2(() => {
|
|
151
286
|
devtools.unmount();
|
|
152
287
|
incremark.parser.setOnChange(void 0);
|
|
153
288
|
});
|
|
154
289
|
return devtools;
|
|
155
290
|
}
|
|
156
291
|
|
|
292
|
+
// src/composables/useBlockTransformer.ts
|
|
293
|
+
import { ref as ref3, watch as watch2, computed as computed3, onUnmounted as onUnmounted3 } from "vue";
|
|
294
|
+
import {
|
|
295
|
+
createBlockTransformer as createBlockTransformer2
|
|
296
|
+
} from "@incremark/core";
|
|
297
|
+
function useBlockTransformer(sourceBlocks, options = {}) {
|
|
298
|
+
const displayBlocksRef = ref3([]);
|
|
299
|
+
const isProcessingRef = ref3(false);
|
|
300
|
+
const isPausedRef = ref3(false);
|
|
301
|
+
const effectRef = ref3(options.effect ?? "none");
|
|
302
|
+
const transformer = createBlockTransformer2({
|
|
303
|
+
...options,
|
|
304
|
+
onChange: (blocks) => {
|
|
305
|
+
displayBlocksRef.value = blocks;
|
|
306
|
+
isProcessingRef.value = transformer.isProcessing();
|
|
307
|
+
isPausedRef.value = transformer.isPausedState();
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
watch2(
|
|
311
|
+
sourceBlocks,
|
|
312
|
+
(blocks) => {
|
|
313
|
+
transformer.push(blocks);
|
|
314
|
+
const currentDisplaying = displayBlocksRef.value.find((b) => !b.isDisplayComplete);
|
|
315
|
+
if (currentDisplaying) {
|
|
316
|
+
const updated = blocks.find((b) => b.id === currentDisplaying.id);
|
|
317
|
+
if (updated) {
|
|
318
|
+
transformer.update(updated);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
{ immediate: true, deep: true }
|
|
323
|
+
);
|
|
324
|
+
onUnmounted3(() => {
|
|
325
|
+
transformer.destroy();
|
|
326
|
+
});
|
|
327
|
+
return {
|
|
328
|
+
displayBlocks: computed3(() => displayBlocksRef.value),
|
|
329
|
+
isProcessing: computed3(() => isProcessingRef.value),
|
|
330
|
+
isPaused: computed3(() => isPausedRef.value),
|
|
331
|
+
effect: computed3(() => effectRef.value),
|
|
332
|
+
skip: () => transformer.skip(),
|
|
333
|
+
reset: () => transformer.reset(),
|
|
334
|
+
pause: () => {
|
|
335
|
+
transformer.pause();
|
|
336
|
+
isPausedRef.value = true;
|
|
337
|
+
},
|
|
338
|
+
resume: () => {
|
|
339
|
+
transformer.resume();
|
|
340
|
+
isPausedRef.value = false;
|
|
341
|
+
},
|
|
342
|
+
setOptions: (opts) => {
|
|
343
|
+
transformer.setOptions(opts);
|
|
344
|
+
if (opts.effect !== void 0) {
|
|
345
|
+
effectRef.value = opts.effect;
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
transformer
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
157
352
|
// sfc-script:/Users/yishuai/develop/ai/markdown/packages/vue/src/components/Incremark.vue?type=script
|
|
158
353
|
import { defineComponent as _defineComponent11 } from "vue";
|
|
159
|
-
import { computed as
|
|
354
|
+
import { computed as computed8 } from "vue";
|
|
160
355
|
|
|
161
356
|
// sfc-script:/Users/yishuai/develop/ai/markdown/packages/vue/src/components/IncremarkHeading.vue?type=script
|
|
162
357
|
import { defineComponent as _defineComponent3 } from "vue";
|
|
163
|
-
import { computed as
|
|
358
|
+
import { computed as computed5 } from "vue";
|
|
164
359
|
|
|
165
360
|
// sfc-script:/Users/yishuai/develop/ai/markdown/packages/vue/src/components/IncremarkInline.vue?type=script
|
|
166
361
|
import { defineComponent as _defineComponent2 } from "vue";
|
|
167
362
|
|
|
168
363
|
// sfc-script:/Users/yishuai/develop/ai/markdown/packages/vue/src/components/IncremarkMath.vue?type=script
|
|
169
364
|
import { defineComponent as _defineComponent } from "vue";
|
|
170
|
-
import { computed as
|
|
365
|
+
import { computed as computed4, ref as ref4, watch as watch3, shallowRef as shallowRef2, onUnmounted as onUnmounted4 } from "vue";
|
|
171
366
|
var IncremarkMath_default = /* @__PURE__ */ _defineComponent({
|
|
172
367
|
__name: "IncremarkMath",
|
|
173
368
|
props: {
|
|
@@ -177,13 +372,13 @@ var IncremarkMath_default = /* @__PURE__ */ _defineComponent({
|
|
|
177
372
|
setup(__props, { expose: __expose }) {
|
|
178
373
|
__expose();
|
|
179
374
|
const props = __props;
|
|
180
|
-
const renderedHtml =
|
|
181
|
-
const renderError =
|
|
182
|
-
const isLoading =
|
|
375
|
+
const renderedHtml = ref4("");
|
|
376
|
+
const renderError = ref4("");
|
|
377
|
+
const isLoading = ref4(false);
|
|
183
378
|
const katexRef = shallowRef2(null);
|
|
184
379
|
let renderTimer = null;
|
|
185
|
-
const isInline =
|
|
186
|
-
const formula =
|
|
380
|
+
const isInline = computed4(() => props.node.type === "inlineMath");
|
|
381
|
+
const formula = computed4(() => props.node.value);
|
|
187
382
|
function scheduleRender() {
|
|
188
383
|
if (!formula.value) {
|
|
189
384
|
renderedHtml.value = "";
|
|
@@ -218,12 +413,12 @@ var IncremarkMath_default = /* @__PURE__ */ _defineComponent({
|
|
|
218
413
|
isLoading.value = false;
|
|
219
414
|
}
|
|
220
415
|
}
|
|
221
|
-
|
|
416
|
+
onUnmounted4(() => {
|
|
222
417
|
if (renderTimer) {
|
|
223
418
|
clearTimeout(renderTimer);
|
|
224
419
|
}
|
|
225
420
|
});
|
|
226
|
-
|
|
421
|
+
watch3(formula, scheduleRender, { immediate: true });
|
|
227
422
|
const __returned__ = { props, renderedHtml, renderError, isLoading, katexRef, get renderTimer() {
|
|
228
423
|
return renderTimer;
|
|
229
424
|
}, set renderTimer(v) {
|
|
@@ -326,10 +521,28 @@ var IncremarkInline_default = /* @__PURE__ */ _defineComponent2({
|
|
|
326
521
|
},
|
|
327
522
|
setup(__props, { expose: __expose }) {
|
|
328
523
|
__expose();
|
|
329
|
-
function
|
|
330
|
-
|
|
524
|
+
function getStableText(node) {
|
|
525
|
+
if (!node.chunks || node.chunks.length === 0) {
|
|
526
|
+
return node.value;
|
|
527
|
+
}
|
|
528
|
+
return node.value.slice(0, node.stableLength ?? 0);
|
|
529
|
+
}
|
|
530
|
+
function hasChunks(node) {
|
|
531
|
+
return node.type === "text" && "chunks" in node && Array.isArray(node.chunks);
|
|
331
532
|
}
|
|
332
|
-
|
|
533
|
+
function getChunks(node) {
|
|
534
|
+
if (hasChunks(node)) {
|
|
535
|
+
return node.chunks;
|
|
536
|
+
}
|
|
537
|
+
return void 0;
|
|
538
|
+
}
|
|
539
|
+
function isHtmlNode(node) {
|
|
540
|
+
return node.type === "html";
|
|
541
|
+
}
|
|
542
|
+
function isInlineMath(node) {
|
|
543
|
+
return node.type === "inlineMath";
|
|
544
|
+
}
|
|
545
|
+
const __returned__ = { getStableText, hasChunks, getChunks, isHtmlNode, isInlineMath, IncremarkMath: IncremarkMath_default2 };
|
|
333
546
|
Object.defineProperty(__returned__, "__isScriptSetup", { enumerable: false, value: true });
|
|
334
547
|
return __returned__;
|
|
335
548
|
}
|
|
@@ -340,6 +553,7 @@ import { renderList as _renderList, Fragment as _Fragment2, openBlock as _openBl
|
|
|
340
553
|
var _hoisted_12 = { class: "incremark-inline-code" };
|
|
341
554
|
var _hoisted_22 = ["href"];
|
|
342
555
|
var _hoisted_32 = ["src", "alt"];
|
|
556
|
+
var _hoisted_42 = ["innerHTML"];
|
|
343
557
|
function render2(_ctx, _cache, $props, $setup, $data, $options) {
|
|
344
558
|
const _component_IncremarkInline = _resolveComponent("IncremarkInline", true);
|
|
345
559
|
return _openBlock2(true), _createElementBlock2(
|
|
@@ -350,20 +564,40 @@ function render2(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
350
564
|
_Fragment2,
|
|
351
565
|
{ key: idx },
|
|
352
566
|
[
|
|
353
|
-
_createCommentVNode2(" \u6587\u672C "),
|
|
567
|
+
_createCommentVNode2(" \u6587\u672C\uFF08\u652F\u6301 chunks \u6E10\u5165\u52A8\u753B\uFF09 "),
|
|
354
568
|
node.type === "text" ? (_openBlock2(), _createElementBlock2(
|
|
355
569
|
_Fragment2,
|
|
356
570
|
{ key: 0 },
|
|
357
571
|
[
|
|
572
|
+
_createCommentVNode2(" \u7A33\u5B9A\u6587\u672C\uFF08\u5DF2\u7ECF\u663E\u793A\u8FC7\u7684\u90E8\u5206\uFF0C\u65E0\u52A8\u753B\uFF09 "),
|
|
358
573
|
_createTextVNode(
|
|
359
|
-
_toDisplayString2(node
|
|
574
|
+
" " + _toDisplayString2($setup.getStableText(node)) + " ",
|
|
360
575
|
1
|
|
361
576
|
/* TEXT */
|
|
362
|
-
)
|
|
577
|
+
),
|
|
578
|
+
_createCommentVNode2(" \u65B0\u589E\u7684 chunk \u90E8\u5206\uFF08\u5E26\u6E10\u5165\u52A8\u753B\uFF09 "),
|
|
579
|
+
(_openBlock2(true), _createElementBlock2(
|
|
580
|
+
_Fragment2,
|
|
581
|
+
null,
|
|
582
|
+
_renderList($setup.getChunks(node), (chunk) => {
|
|
583
|
+
return _openBlock2(), _createElementBlock2(
|
|
584
|
+
"span",
|
|
585
|
+
{
|
|
586
|
+
key: chunk.createdAt,
|
|
587
|
+
class: "incremark-fade-in"
|
|
588
|
+
},
|
|
589
|
+
_toDisplayString2(chunk.text),
|
|
590
|
+
1
|
|
591
|
+
/* TEXT */
|
|
592
|
+
);
|
|
593
|
+
}),
|
|
594
|
+
128
|
|
595
|
+
/* KEYED_FRAGMENT */
|
|
596
|
+
))
|
|
363
597
|
],
|
|
364
598
|
64
|
|
365
599
|
/* STABLE_FRAGMENT */
|
|
366
|
-
)) : node
|
|
600
|
+
)) : $setup.isInlineMath(node) ? (_openBlock2(), _createElementBlock2(
|
|
367
601
|
_Fragment2,
|
|
368
602
|
{ key: 1 },
|
|
369
603
|
[
|
|
@@ -473,6 +707,17 @@ function render2(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
473
707
|
],
|
|
474
708
|
2112
|
|
475
709
|
/* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
|
|
710
|
+
)) : $setup.isHtmlNode(node) ? (_openBlock2(), _createElementBlock2(
|
|
711
|
+
_Fragment2,
|
|
712
|
+
{ key: 9 },
|
|
713
|
+
[
|
|
714
|
+
_createCommentVNode2(" \u539F\u59CB HTML "),
|
|
715
|
+
_createElementVNode2("span", {
|
|
716
|
+
innerHTML: node.value
|
|
717
|
+
}, null, 8, _hoisted_42)
|
|
718
|
+
],
|
|
719
|
+
2112
|
|
720
|
+
/* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
|
|
476
721
|
)) : _createCommentVNode2("v-if", true)
|
|
477
722
|
],
|
|
478
723
|
64
|
|
@@ -498,7 +743,7 @@ var IncremarkHeading_default = /* @__PURE__ */ _defineComponent3({
|
|
|
498
743
|
setup(__props, { expose: __expose }) {
|
|
499
744
|
__expose();
|
|
500
745
|
const props = __props;
|
|
501
|
-
const tag =
|
|
746
|
+
const tag = computed5(() => `h${props.node.depth}`);
|
|
502
747
|
const __returned__ = { props, tag, IncremarkInline: IncremarkInline_default2 };
|
|
503
748
|
Object.defineProperty(__returned__, "__isScriptSetup", { enumerable: false, value: true });
|
|
504
749
|
return __returned__;
|
|
@@ -559,7 +804,7 @@ var IncremarkParagraph_default2 = IncremarkParagraph_default;
|
|
|
559
804
|
|
|
560
805
|
// sfc-script:/Users/yishuai/develop/ai/markdown/packages/vue/src/components/IncremarkCode.vue?type=script
|
|
561
806
|
import { defineComponent as _defineComponent5 } from "vue";
|
|
562
|
-
import { computed as
|
|
807
|
+
import { computed as computed6, ref as ref5, watch as watch4, shallowRef as shallowRef3, onUnmounted as onUnmounted5 } from "vue";
|
|
563
808
|
var IncremarkCode_default = /* @__PURE__ */ _defineComponent5({
|
|
564
809
|
__name: "IncremarkCode",
|
|
565
810
|
props: {
|
|
@@ -571,22 +816,22 @@ var IncremarkCode_default = /* @__PURE__ */ _defineComponent5({
|
|
|
571
816
|
setup(__props, { expose: __expose }) {
|
|
572
817
|
__expose();
|
|
573
818
|
const props = __props;
|
|
574
|
-
const copied =
|
|
575
|
-
const highlightedHtml =
|
|
576
|
-
const isHighlighting =
|
|
577
|
-
const highlightError =
|
|
578
|
-
const mermaidSvg =
|
|
579
|
-
const mermaidError =
|
|
580
|
-
const mermaidLoading =
|
|
819
|
+
const copied = ref5(false);
|
|
820
|
+
const highlightedHtml = ref5("");
|
|
821
|
+
const isHighlighting = ref5(false);
|
|
822
|
+
const highlightError = ref5(false);
|
|
823
|
+
const mermaidSvg = ref5("");
|
|
824
|
+
const mermaidError = ref5("");
|
|
825
|
+
const mermaidLoading = ref5(false);
|
|
581
826
|
const mermaidRef = shallowRef3(null);
|
|
582
827
|
let mermaidTimer = null;
|
|
583
|
-
const mermaidViewMode =
|
|
828
|
+
const mermaidViewMode = ref5("preview");
|
|
584
829
|
function toggleMermaidView() {
|
|
585
830
|
mermaidViewMode.value = mermaidViewMode.value === "preview" ? "source" : "preview";
|
|
586
831
|
}
|
|
587
|
-
const language =
|
|
588
|
-
const code =
|
|
589
|
-
const isMermaid =
|
|
832
|
+
const language = computed6(() => props.node.lang || "text");
|
|
833
|
+
const code = computed6(() => props.node.value);
|
|
834
|
+
const isMermaid = computed6(() => language.value === "mermaid");
|
|
590
835
|
const highlighterRef = shallowRef3(null);
|
|
591
836
|
const loadedLanguages = /* @__PURE__ */ new Set();
|
|
592
837
|
const loadedThemes = /* @__PURE__ */ new Set();
|
|
@@ -624,7 +869,7 @@ var IncremarkCode_default = /* @__PURE__ */ _defineComponent5({
|
|
|
624
869
|
mermaidLoading.value = false;
|
|
625
870
|
}
|
|
626
871
|
}
|
|
627
|
-
|
|
872
|
+
onUnmounted5(() => {
|
|
628
873
|
if (mermaidTimer) {
|
|
629
874
|
clearTimeout(mermaidTimer);
|
|
630
875
|
}
|
|
@@ -677,7 +922,7 @@ var IncremarkCode_default = /* @__PURE__ */ _defineComponent5({
|
|
|
677
922
|
isHighlighting.value = false;
|
|
678
923
|
}
|
|
679
924
|
}
|
|
680
|
-
|
|
925
|
+
watch4([code, () => props.theme, isMermaid], highlight, { immediate: true });
|
|
681
926
|
async function copyCode() {
|
|
682
927
|
try {
|
|
683
928
|
await navigator.clipboard.writeText(code.value);
|
|
@@ -706,7 +951,7 @@ var _hoisted_14 = {
|
|
|
706
951
|
};
|
|
707
952
|
var _hoisted_23 = { class: "mermaid-header" };
|
|
708
953
|
var _hoisted_33 = { class: "mermaid-actions" };
|
|
709
|
-
var
|
|
954
|
+
var _hoisted_43 = ["disabled"];
|
|
710
955
|
var _hoisted_52 = { class: "mermaid-content" };
|
|
711
956
|
var _hoisted_62 = {
|
|
712
957
|
key: 0,
|
|
@@ -747,7 +992,7 @@ function render5(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
747
992
|
onClick: $setup.toggleMermaidView,
|
|
748
993
|
type: "button",
|
|
749
994
|
disabled: !$setup.mermaidSvg
|
|
750
|
-
}, _toDisplayString3($setup.mermaidViewMode === "preview" ? "\u6E90\u7801" : "\u9884\u89C8"), 9,
|
|
995
|
+
}, _toDisplayString3($setup.mermaidViewMode === "preview" ? "\u6E90\u7801" : "\u9884\u89C8"), 9, _hoisted_43),
|
|
751
996
|
_createElementVNode3(
|
|
752
997
|
"button",
|
|
753
998
|
{
|
|
@@ -903,7 +1148,7 @@ var IncremarkCode_default2 = IncremarkCode_default;
|
|
|
903
1148
|
|
|
904
1149
|
// sfc-script:/Users/yishuai/develop/ai/markdown/packages/vue/src/components/IncremarkList.vue?type=script
|
|
905
1150
|
import { defineComponent as _defineComponent6 } from "vue";
|
|
906
|
-
import { computed as
|
|
1151
|
+
import { computed as computed7 } from "vue";
|
|
907
1152
|
var IncremarkList_default = /* @__PURE__ */ _defineComponent6({
|
|
908
1153
|
__name: "IncremarkList",
|
|
909
1154
|
props: {
|
|
@@ -912,7 +1157,7 @@ var IncremarkList_default = /* @__PURE__ */ _defineComponent6({
|
|
|
912
1157
|
setup(__props, { expose: __expose }) {
|
|
913
1158
|
__expose();
|
|
914
1159
|
const props = __props;
|
|
915
|
-
const tag =
|
|
1160
|
+
const tag = computed7(() => props.node.ordered ? "ol" : "ul");
|
|
916
1161
|
function getItemContent(item) {
|
|
917
1162
|
const firstChild = item.children[0];
|
|
918
1163
|
if (firstChild?.type === "paragraph") {
|
|
@@ -1234,7 +1479,7 @@ var Incremark_default = /* @__PURE__ */ _defineComponent11({
|
|
|
1234
1479
|
math: IncremarkMath_default2,
|
|
1235
1480
|
inlineMath: IncremarkMath_default2
|
|
1236
1481
|
};
|
|
1237
|
-
const mergedComponents =
|
|
1482
|
+
const mergedComponents = computed8(() => ({
|
|
1238
1483
|
...defaultComponents,
|
|
1239
1484
|
...props.components
|
|
1240
1485
|
}));
|
|
@@ -1265,7 +1510,8 @@ function render11(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
1265
1510
|
class: _normalizeClass2([
|
|
1266
1511
|
"incremark-block",
|
|
1267
1512
|
block.status === "completed" ? $props.completedClass : $props.pendingClass,
|
|
1268
|
-
{ "incremark-show-status": $props.showBlockStatus }
|
|
1513
|
+
{ "incremark-show-status": $props.showBlockStatus },
|
|
1514
|
+
{ "incremark-last-pending": block.isLastPending }
|
|
1269
1515
|
])
|
|
1270
1516
|
},
|
|
1271
1517
|
[
|
|
@@ -1332,7 +1578,160 @@ function render12(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
1332
1578
|
IncremarkRenderer_default.render = render12;
|
|
1333
1579
|
IncremarkRenderer_default.__file = "src/components/IncremarkRenderer.vue";
|
|
1334
1580
|
var IncremarkRenderer_default2 = IncremarkRenderer_default;
|
|
1581
|
+
|
|
1582
|
+
// sfc-script:/Users/yishuai/develop/ai/markdown/packages/vue/src/components/AutoScrollContainer.vue?type=script
|
|
1583
|
+
import { defineComponent as _defineComponent13 } from "vue";
|
|
1584
|
+
import { ref as ref6, onMounted as onMounted2, onUnmounted as onUnmounted6, nextTick } from "vue";
|
|
1585
|
+
var AutoScrollContainer_default = /* @__PURE__ */ _defineComponent13({
|
|
1586
|
+
__name: "AutoScrollContainer",
|
|
1587
|
+
props: {
|
|
1588
|
+
enabled: { type: Boolean, required: false, default: true },
|
|
1589
|
+
threshold: { type: Number, required: false, default: 50 },
|
|
1590
|
+
behavior: { type: null, required: false, default: "instant" }
|
|
1591
|
+
},
|
|
1592
|
+
setup(__props, { expose: __expose }) {
|
|
1593
|
+
const props = __props;
|
|
1594
|
+
const containerRef = ref6(null);
|
|
1595
|
+
const isUserScrolledUp = ref6(false);
|
|
1596
|
+
let lastScrollTop = 0;
|
|
1597
|
+
let lastScrollHeight = 0;
|
|
1598
|
+
function isNearBottom() {
|
|
1599
|
+
const container = containerRef.value;
|
|
1600
|
+
if (!container) return true;
|
|
1601
|
+
const { scrollTop, scrollHeight, clientHeight } = container;
|
|
1602
|
+
return scrollHeight - scrollTop - clientHeight <= props.threshold;
|
|
1603
|
+
}
|
|
1604
|
+
function scrollToBottom(force = false) {
|
|
1605
|
+
const container = containerRef.value;
|
|
1606
|
+
if (!container) return;
|
|
1607
|
+
if (isUserScrolledUp.value && !force) return;
|
|
1608
|
+
container.scrollTo({
|
|
1609
|
+
top: container.scrollHeight,
|
|
1610
|
+
behavior: props.behavior
|
|
1611
|
+
});
|
|
1612
|
+
}
|
|
1613
|
+
function hasScrollbar() {
|
|
1614
|
+
const container = containerRef.value;
|
|
1615
|
+
if (!container) return false;
|
|
1616
|
+
return container.scrollHeight > container.clientHeight;
|
|
1617
|
+
}
|
|
1618
|
+
function handleScroll() {
|
|
1619
|
+
const container = containerRef.value;
|
|
1620
|
+
if (!container) return;
|
|
1621
|
+
const { scrollTop, scrollHeight, clientHeight } = container;
|
|
1622
|
+
if (scrollHeight <= clientHeight) {
|
|
1623
|
+
isUserScrolledUp.value = false;
|
|
1624
|
+
lastScrollTop = 0;
|
|
1625
|
+
lastScrollHeight = scrollHeight;
|
|
1626
|
+
return;
|
|
1627
|
+
}
|
|
1628
|
+
if (isNearBottom()) {
|
|
1629
|
+
isUserScrolledUp.value = false;
|
|
1630
|
+
} else {
|
|
1631
|
+
const isScrollingUp = scrollTop < lastScrollTop;
|
|
1632
|
+
const isContentUnchanged = scrollHeight === lastScrollHeight;
|
|
1633
|
+
if (isScrollingUp && isContentUnchanged) {
|
|
1634
|
+
isUserScrolledUp.value = true;
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
lastScrollTop = scrollTop;
|
|
1638
|
+
lastScrollHeight = scrollHeight;
|
|
1639
|
+
}
|
|
1640
|
+
let observer = null;
|
|
1641
|
+
onMounted2(() => {
|
|
1642
|
+
if (!containerRef.value) return;
|
|
1643
|
+
lastScrollTop = containerRef.value.scrollTop;
|
|
1644
|
+
lastScrollHeight = containerRef.value.scrollHeight;
|
|
1645
|
+
observer = new MutationObserver(() => {
|
|
1646
|
+
nextTick(() => {
|
|
1647
|
+
if (!containerRef.value) return;
|
|
1648
|
+
if (!hasScrollbar()) {
|
|
1649
|
+
isUserScrolledUp.value = false;
|
|
1650
|
+
}
|
|
1651
|
+
lastScrollHeight = containerRef.value.scrollHeight;
|
|
1652
|
+
if (props.enabled && !isUserScrolledUp.value) {
|
|
1653
|
+
scrollToBottom();
|
|
1654
|
+
}
|
|
1655
|
+
});
|
|
1656
|
+
});
|
|
1657
|
+
observer.observe(containerRef.value, {
|
|
1658
|
+
childList: true,
|
|
1659
|
+
subtree: true,
|
|
1660
|
+
characterData: true
|
|
1661
|
+
});
|
|
1662
|
+
});
|
|
1663
|
+
onUnmounted6(() => {
|
|
1664
|
+
observer?.disconnect();
|
|
1665
|
+
});
|
|
1666
|
+
__expose({
|
|
1667
|
+
/** 强制滚动到底部 */
|
|
1668
|
+
scrollToBottom: () => scrollToBottom(true),
|
|
1669
|
+
/** 是否用户手动向上滚动了 */
|
|
1670
|
+
isUserScrolledUp: () => isUserScrolledUp.value,
|
|
1671
|
+
/** 容器元素引用 */
|
|
1672
|
+
container: containerRef
|
|
1673
|
+
});
|
|
1674
|
+
const __returned__ = { props, containerRef, isUserScrolledUp, get lastScrollTop() {
|
|
1675
|
+
return lastScrollTop;
|
|
1676
|
+
}, set lastScrollTop(v) {
|
|
1677
|
+
lastScrollTop = v;
|
|
1678
|
+
}, get lastScrollHeight() {
|
|
1679
|
+
return lastScrollHeight;
|
|
1680
|
+
}, set lastScrollHeight(v) {
|
|
1681
|
+
lastScrollHeight = v;
|
|
1682
|
+
}, isNearBottom, scrollToBottom, hasScrollbar, handleScroll, get observer() {
|
|
1683
|
+
return observer;
|
|
1684
|
+
}, set observer(v) {
|
|
1685
|
+
observer = v;
|
|
1686
|
+
} };
|
|
1687
|
+
Object.defineProperty(__returned__, "__isScriptSetup", { enumerable: false, value: true });
|
|
1688
|
+
return __returned__;
|
|
1689
|
+
}
|
|
1690
|
+
});
|
|
1691
|
+
|
|
1692
|
+
// sfc-template:/Users/yishuai/develop/ai/markdown/packages/vue/src/components/AutoScrollContainer.vue?type=template
|
|
1693
|
+
import { renderSlot as _renderSlot, openBlock as _openBlock13, createElementBlock as _createElementBlock11 } from "vue";
|
|
1694
|
+
function render13(_ctx, _cache, $props, $setup, $data, $options) {
|
|
1695
|
+
return _openBlock13(), _createElementBlock11(
|
|
1696
|
+
"div",
|
|
1697
|
+
{
|
|
1698
|
+
ref: "containerRef",
|
|
1699
|
+
class: "auto-scroll-container",
|
|
1700
|
+
onScroll: $setup.handleScroll
|
|
1701
|
+
},
|
|
1702
|
+
[
|
|
1703
|
+
_renderSlot(_ctx.$slots, "default", {}, void 0, true)
|
|
1704
|
+
],
|
|
1705
|
+
544
|
|
1706
|
+
/* NEED_HYDRATION, NEED_PATCH */
|
|
1707
|
+
);
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
// src/components/AutoScrollContainer.vue
|
|
1711
|
+
AutoScrollContainer_default.render = render13;
|
|
1712
|
+
AutoScrollContainer_default.__file = "src/components/AutoScrollContainer.vue";
|
|
1713
|
+
AutoScrollContainer_default.__scopeId = "data-v-e0d180b8";
|
|
1714
|
+
var AutoScrollContainer_default2 = AutoScrollContainer_default;
|
|
1715
|
+
|
|
1716
|
+
// src/index.ts
|
|
1717
|
+
import {
|
|
1718
|
+
BlockTransformer as BlockTransformer2,
|
|
1719
|
+
createBlockTransformer as createBlockTransformer3,
|
|
1720
|
+
countChars,
|
|
1721
|
+
sliceAst,
|
|
1722
|
+
cloneNode,
|
|
1723
|
+
codeBlockPlugin,
|
|
1724
|
+
mermaidPlugin,
|
|
1725
|
+
imagePlugin,
|
|
1726
|
+
mathPlugin,
|
|
1727
|
+
thematicBreakPlugin,
|
|
1728
|
+
defaultPlugins as defaultPlugins2,
|
|
1729
|
+
allPlugins,
|
|
1730
|
+
createPlugin
|
|
1731
|
+
} from "@incremark/core";
|
|
1335
1732
|
export {
|
|
1733
|
+
AutoScrollContainer_default2 as AutoScrollContainer,
|
|
1734
|
+
BlockTransformer2 as BlockTransformer,
|
|
1336
1735
|
Incremark_default2 as Incremark,
|
|
1337
1736
|
IncremarkBlockquote_default2 as IncremarkBlockquote,
|
|
1338
1737
|
IncremarkCode_default2 as IncremarkCode,
|
|
@@ -1345,6 +1744,19 @@ export {
|
|
|
1345
1744
|
IncremarkRenderer_default2 as IncremarkRenderer,
|
|
1346
1745
|
IncremarkTable_default2 as IncremarkTable,
|
|
1347
1746
|
IncremarkThematicBreak_default2 as IncremarkThematicBreak,
|
|
1747
|
+
allPlugins,
|
|
1748
|
+
cloneNode,
|
|
1749
|
+
codeBlockPlugin,
|
|
1750
|
+
countChars,
|
|
1751
|
+
createBlockTransformer3 as createBlockTransformer,
|
|
1752
|
+
createPlugin,
|
|
1753
|
+
defaultPlugins2 as defaultPlugins,
|
|
1754
|
+
imagePlugin,
|
|
1755
|
+
mathPlugin,
|
|
1756
|
+
mermaidPlugin,
|
|
1757
|
+
sliceAst,
|
|
1758
|
+
thematicBreakPlugin,
|
|
1759
|
+
useBlockTransformer,
|
|
1348
1760
|
useDevTools,
|
|
1349
1761
|
useIncremark,
|
|
1350
1762
|
useStreamRenderer
|