streaming-markdown-react 0.1.4 → 0.2.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 +227 -20
- package/README.zh-CN.md +227 -0
- package/dist/index.d.mts +245 -2
- package/dist/index.d.ts +245 -2
- package/dist/index.js +671 -103
- package/dist/index.mjs +629 -97
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -64,8 +64,7 @@ var MessageBlockStore = class {
|
|
|
64
64
|
var messageBlockStore = new MessageBlockStore();
|
|
65
65
|
|
|
66
66
|
// src/components/Markdown/StreamingMarkdown.tsx
|
|
67
|
-
import { useEffect as useEffect3, useMemo, useRef as useRef2, useState as useState2 } from "react";
|
|
68
|
-
import ReactMarkdown from "react-markdown";
|
|
67
|
+
import { memo as memo3, useEffect as useEffect3, useId, useMemo, useRef as useRef2, useState as useState2 } from "react";
|
|
69
68
|
import remarkGfm from "remark-gfm";
|
|
70
69
|
|
|
71
70
|
// src/hooks/useSmoothStream.ts
|
|
@@ -179,6 +178,124 @@ function useSmoothStream({
|
|
|
179
178
|
return { addChunk, reset };
|
|
180
179
|
}
|
|
181
180
|
|
|
181
|
+
// src/utils/markdown/parseMarkdownIntoBlocks.ts
|
|
182
|
+
import { Lexer } from "marked";
|
|
183
|
+
var blockIdCounter = 0;
|
|
184
|
+
function generateBlockId() {
|
|
185
|
+
blockIdCounter += 1;
|
|
186
|
+
return `block-${Date.now()}-${blockIdCounter}`;
|
|
187
|
+
}
|
|
188
|
+
function parseMarkdownIntoBlocks(markdown) {
|
|
189
|
+
if (!markdown.trim()) {
|
|
190
|
+
return [];
|
|
191
|
+
}
|
|
192
|
+
const hasFootnoteReference = /\[\^[^\]\s]{1,200}\](?!:)/.test(markdown);
|
|
193
|
+
const hasFootnoteDefinition = /\[\^[^\]\s]{1,200}\]:/.test(markdown);
|
|
194
|
+
if (hasFootnoteReference || hasFootnoteDefinition) {
|
|
195
|
+
return [markdown];
|
|
196
|
+
}
|
|
197
|
+
const tokens = Lexer.lex(markdown, { gfm: true });
|
|
198
|
+
const mergedBlocks = [];
|
|
199
|
+
const htmlStack = [];
|
|
200
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
201
|
+
const token = tokens[i];
|
|
202
|
+
const currentBlock = token.raw;
|
|
203
|
+
if (htmlStack.length > 0) {
|
|
204
|
+
mergedBlocks[mergedBlocks.length - 1] += currentBlock;
|
|
205
|
+
if (token.type === "html") {
|
|
206
|
+
const closingTagMatch = currentBlock.match(/<\/(\w+)>/);
|
|
207
|
+
if (closingTagMatch) {
|
|
208
|
+
const closingTag = closingTagMatch[1];
|
|
209
|
+
if (htmlStack[htmlStack.length - 1] === closingTag) {
|
|
210
|
+
htmlStack.pop();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (token.type === "html" && token.block) {
|
|
217
|
+
const openingTagMatch = currentBlock.match(/<(\w+)[\s>]/);
|
|
218
|
+
if (openingTagMatch) {
|
|
219
|
+
const tagName = openingTagMatch[1];
|
|
220
|
+
const hasClosingTag = currentBlock.includes(`</${tagName}>`);
|
|
221
|
+
if (!hasClosingTag) {
|
|
222
|
+
htmlStack.push(tagName);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (currentBlock.trim() === "$" && mergedBlocks.length > 0) {
|
|
227
|
+
const previousBlock = mergedBlocks.at(-1);
|
|
228
|
+
if (!previousBlock) {
|
|
229
|
+
mergedBlocks.push(currentBlock);
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
const prevStartsWith$ = previousBlock.trimStart().startsWith("$");
|
|
233
|
+
const prevDollarCount = (previousBlock.match(/\$\$/g) || []).length;
|
|
234
|
+
if (prevStartsWith$ && prevDollarCount % 2 === 1) {
|
|
235
|
+
mergedBlocks[mergedBlocks.length - 1] = previousBlock + currentBlock;
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (mergedBlocks.length > 0 && currentBlock.trimEnd().endsWith("$")) {
|
|
240
|
+
const previousBlock = mergedBlocks.at(-1);
|
|
241
|
+
if (!previousBlock) {
|
|
242
|
+
mergedBlocks.push(currentBlock);
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
const prevStartsWith$ = previousBlock.trimStart().startsWith("$");
|
|
246
|
+
const prevDollarCount = (previousBlock.match(/\$\$/g) || []).length;
|
|
247
|
+
const currDollarCount = (currentBlock.match(/\$\$/g) || []).length;
|
|
248
|
+
if (prevStartsWith$ && prevDollarCount % 2 === 1 && !currentBlock.trimStart().startsWith("$") && currDollarCount === 1) {
|
|
249
|
+
mergedBlocks[mergedBlocks.length - 1] = previousBlock + currentBlock;
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
mergedBlocks.push(currentBlock);
|
|
254
|
+
}
|
|
255
|
+
return mergedBlocks;
|
|
256
|
+
}
|
|
257
|
+
function splitMarkdownIntoBlocks({
|
|
258
|
+
messageId,
|
|
259
|
+
markdown,
|
|
260
|
+
status = "idle" /* IDLE */
|
|
261
|
+
}) {
|
|
262
|
+
const blocks = parseMarkdownIntoBlocks(markdown);
|
|
263
|
+
return blocks.map((content) => {
|
|
264
|
+
const block = {
|
|
265
|
+
id: generateBlockId(),
|
|
266
|
+
messageId,
|
|
267
|
+
type: "main_text" /* MAIN_TEXT */,
|
|
268
|
+
status,
|
|
269
|
+
content,
|
|
270
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
271
|
+
};
|
|
272
|
+
return block;
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// src/components/Markdown/Block.tsx
|
|
277
|
+
import { memo } from "react";
|
|
278
|
+
import ReactMarkdown from "react-markdown";
|
|
279
|
+
import { jsx } from "react/jsx-runtime";
|
|
280
|
+
var Block = memo(
|
|
281
|
+
({ content, components, remarkPlugins, rehypePlugins, className }) => {
|
|
282
|
+
return /* @__PURE__ */ jsx(
|
|
283
|
+
ReactMarkdown,
|
|
284
|
+
{
|
|
285
|
+
className,
|
|
286
|
+
components,
|
|
287
|
+
remarkPlugins,
|
|
288
|
+
rehypePlugins,
|
|
289
|
+
children: content
|
|
290
|
+
}
|
|
291
|
+
);
|
|
292
|
+
},
|
|
293
|
+
(prevProps, nextProps) => {
|
|
294
|
+
return prevProps.content === nextProps.content && prevProps.className === nextProps.className;
|
|
295
|
+
}
|
|
296
|
+
);
|
|
297
|
+
Block.displayName = "Block";
|
|
298
|
+
|
|
182
299
|
// src/hooks/useShikiHighlight.ts
|
|
183
300
|
import { useEffect as useEffect2, useState } from "react";
|
|
184
301
|
import { createHighlighterCore } from "shiki/core";
|
|
@@ -270,7 +387,7 @@ function escapeHtml(unsafe) {
|
|
|
270
387
|
}
|
|
271
388
|
|
|
272
389
|
// src/components/Markdown/CodeBlock.tsx
|
|
273
|
-
import { jsx } from "react/jsx-runtime";
|
|
390
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
274
391
|
function CodeBlock({
|
|
275
392
|
code,
|
|
276
393
|
language = "text",
|
|
@@ -279,9 +396,9 @@ function CodeBlock({
|
|
|
279
396
|
}) {
|
|
280
397
|
const { html, isLoading } = useShikiHighlight({ code, language, theme });
|
|
281
398
|
if (isLoading) {
|
|
282
|
-
return /* @__PURE__ */
|
|
399
|
+
return /* @__PURE__ */ jsx2("pre", { className, children: /* @__PURE__ */ jsx2("code", { "data-language": language, children: code }) });
|
|
283
400
|
}
|
|
284
|
-
return /* @__PURE__ */
|
|
401
|
+
return /* @__PURE__ */ jsx2(
|
|
285
402
|
"div",
|
|
286
403
|
{
|
|
287
404
|
dangerouslySetInnerHTML: { __html: html },
|
|
@@ -294,89 +411,286 @@ function CodeBlock({
|
|
|
294
411
|
);
|
|
295
412
|
}
|
|
296
413
|
|
|
297
|
-
// src/components/Markdown/
|
|
298
|
-
import {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
414
|
+
// src/components/Markdown/MemoizedComponents.tsx
|
|
415
|
+
import { memo as memo2 } from "react";
|
|
416
|
+
|
|
417
|
+
// src/utils/markdown/sameNodePosition.ts
|
|
418
|
+
function sameNodePosition(prev, next) {
|
|
419
|
+
if (!(prev?.position || next?.position)) {
|
|
420
|
+
return true;
|
|
421
|
+
}
|
|
422
|
+
if (!(prev?.position && next?.position)) {
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
const prevStart = prev.position.start;
|
|
426
|
+
const nextStart = next.position.start;
|
|
427
|
+
const prevEnd = prev.position.end;
|
|
428
|
+
const nextEnd = next.position.end;
|
|
429
|
+
return prevStart?.line === nextStart?.line && prevStart?.column === nextStart?.column && prevEnd?.line === nextEnd?.line && prevEnd?.column === nextEnd?.column;
|
|
430
|
+
}
|
|
431
|
+
function sameClassAndNode(prev, next) {
|
|
432
|
+
return prev.className === next.className && sameNodePosition(prev.node, next.node);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// src/components/Markdown/MemoizedComponents.tsx
|
|
436
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
437
|
+
var MemoH1 = memo2(
|
|
438
|
+
({ children, className, ...props }) => /* @__PURE__ */ jsx3("h1", { className, ...props, children }),
|
|
439
|
+
(p, n) => sameClassAndNode(p, n)
|
|
440
|
+
);
|
|
441
|
+
MemoH1.displayName = "MemoH1";
|
|
442
|
+
var MemoH2 = memo2(
|
|
443
|
+
({ children, className, ...props }) => /* @__PURE__ */ jsx3("h2", { className, ...props, children }),
|
|
444
|
+
(p, n) => sameClassAndNode(p, n)
|
|
445
|
+
);
|
|
446
|
+
MemoH2.displayName = "MemoH2";
|
|
447
|
+
var MemoH3 = memo2(
|
|
448
|
+
({ children, className, ...props }) => /* @__PURE__ */ jsx3("h3", { className, ...props, children }),
|
|
449
|
+
(p, n) => sameClassAndNode(p, n)
|
|
450
|
+
);
|
|
451
|
+
MemoH3.displayName = "MemoH3";
|
|
452
|
+
var MemoH4 = memo2(
|
|
453
|
+
({ children, className, ...props }) => /* @__PURE__ */ jsx3("h4", { className, ...props, children }),
|
|
454
|
+
(p, n) => sameClassAndNode(p, n)
|
|
455
|
+
);
|
|
456
|
+
MemoH4.displayName = "MemoH4";
|
|
457
|
+
var MemoH5 = memo2(
|
|
458
|
+
({ children, className, ...props }) => /* @__PURE__ */ jsx3("h5", { className, ...props, children }),
|
|
459
|
+
(p, n) => sameClassAndNode(p, n)
|
|
460
|
+
);
|
|
461
|
+
MemoH5.displayName = "MemoH5";
|
|
462
|
+
var MemoH6 = memo2(
|
|
463
|
+
({ children, className, ...props }) => /* @__PURE__ */ jsx3("h6", { className, ...props, children }),
|
|
464
|
+
(p, n) => sameClassAndNode(p, n)
|
|
465
|
+
);
|
|
466
|
+
MemoH6.displayName = "MemoH6";
|
|
467
|
+
var MemoParagraph = memo2(
|
|
468
|
+
({ children, className, ...props }) => /* @__PURE__ */ jsx3("p", { className, ...props, children }),
|
|
469
|
+
(p, n) => sameClassAndNode(p, n)
|
|
470
|
+
);
|
|
471
|
+
MemoParagraph.displayName = "MemoParagraph";
|
|
472
|
+
var MemoLink = memo2(
|
|
473
|
+
({ children, className, href, title, ...props }) => /* @__PURE__ */ jsx3(
|
|
474
|
+
"a",
|
|
475
|
+
{
|
|
476
|
+
className,
|
|
477
|
+
href,
|
|
478
|
+
title,
|
|
479
|
+
target: "_blank",
|
|
480
|
+
rel: "noopener noreferrer",
|
|
481
|
+
...props,
|
|
482
|
+
children
|
|
329
483
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
}
|
|
343
|
-
pre: (props) => {
|
|
344
|
-
const { children: children2, ...rest } = props;
|
|
345
|
-
if (children2?.type === CodeBlock) {
|
|
346
|
-
return children2;
|
|
347
|
-
}
|
|
348
|
-
return /* @__PURE__ */ jsx2("pre", { style: { overflow: "visible" }, ...rest, children: children2 });
|
|
349
|
-
},
|
|
350
|
-
p: (props) => {
|
|
351
|
-
const hasCodeBlock = props?.node?.children?.some(
|
|
352
|
-
(child) => child.tagName === "pre" || child.tagName === "code"
|
|
353
|
-
);
|
|
354
|
-
if (hasCodeBlock) {
|
|
355
|
-
return /* @__PURE__ */ jsx2(Fragment, { children: props.children });
|
|
356
|
-
}
|
|
357
|
-
const hasImage = props?.node?.children?.some((child) => child.tagName === "img");
|
|
358
|
-
if (hasImage) return /* @__PURE__ */ jsx2("div", { ...props });
|
|
359
|
-
return /* @__PURE__ */ jsx2("p", { ...props });
|
|
360
|
-
}
|
|
361
|
-
};
|
|
362
|
-
if (/<style\b[^>]*>/i.test(markdown)) {
|
|
363
|
-
baseComponents.style = (props) => /* @__PURE__ */ jsx2("div", { ...props });
|
|
484
|
+
),
|
|
485
|
+
(p, n) => sameClassAndNode(p, n) && p.href === n.href && p.title === n.title
|
|
486
|
+
);
|
|
487
|
+
MemoLink.displayName = "MemoLink";
|
|
488
|
+
var MemoBlockquote = memo2(
|
|
489
|
+
({ children, className, ...props }) => /* @__PURE__ */ jsx3("blockquote", { className, ...props, children }),
|
|
490
|
+
(p, n) => sameClassAndNode(p, n)
|
|
491
|
+
);
|
|
492
|
+
MemoBlockquote.displayName = "MemoBlockquote";
|
|
493
|
+
var MemoList = memo2(
|
|
494
|
+
({ children, className, ordered, start, ...props }) => {
|
|
495
|
+
if (ordered) {
|
|
496
|
+
return /* @__PURE__ */ jsx3("ol", { className, start, ...props, children });
|
|
364
497
|
}
|
|
365
|
-
return {
|
|
366
|
-
},
|
|
367
|
-
|
|
368
|
-
|
|
498
|
+
return /* @__PURE__ */ jsx3("ul", { className, ...props, children });
|
|
499
|
+
},
|
|
500
|
+
(p, n) => sameClassAndNode(p, n) && p.ordered === n.ordered && p.start === n.start
|
|
501
|
+
);
|
|
502
|
+
MemoList.displayName = "MemoList";
|
|
503
|
+
var MemoListItem = memo2(
|
|
504
|
+
({ children, className, ...props }) => /* @__PURE__ */ jsx3("li", { className, ...props, children }),
|
|
505
|
+
(p, n) => sameClassAndNode(p, n)
|
|
506
|
+
);
|
|
507
|
+
MemoListItem.displayName = "MemoListItem";
|
|
508
|
+
var MemoTable = memo2(
|
|
509
|
+
({ children, className, ...props }) => /* @__PURE__ */ jsx3("table", { className, ...props, children }),
|
|
510
|
+
(p, n) => sameClassAndNode(p, n)
|
|
511
|
+
);
|
|
512
|
+
MemoTable.displayName = "MemoTable";
|
|
513
|
+
var MemoTableHead = memo2(
|
|
514
|
+
({ children, className, ...props }) => /* @__PURE__ */ jsx3("thead", { className, ...props, children }),
|
|
515
|
+
(p, n) => sameClassAndNode(p, n)
|
|
516
|
+
);
|
|
517
|
+
MemoTableHead.displayName = "MemoTableHead";
|
|
518
|
+
var MemoTableBody = memo2(
|
|
519
|
+
({ children, className, ...props }) => /* @__PURE__ */ jsx3("tbody", { className, ...props, children }),
|
|
520
|
+
(p, n) => sameClassAndNode(p, n)
|
|
521
|
+
);
|
|
522
|
+
MemoTableBody.displayName = "MemoTableBody";
|
|
523
|
+
var MemoTableRow = memo2(
|
|
524
|
+
({ children, className, ...props }) => /* @__PURE__ */ jsx3("tr", { className, ...props, children }),
|
|
525
|
+
(p, n) => sameClassAndNode(p, n)
|
|
526
|
+
);
|
|
527
|
+
MemoTableRow.displayName = "MemoTableRow";
|
|
528
|
+
var MemoTableCell = memo2(
|
|
529
|
+
({ children, className, isHeader, align, ...props }) => {
|
|
530
|
+
const style = align ? { textAlign: align } : void 0;
|
|
531
|
+
if (isHeader) {
|
|
532
|
+
return /* @__PURE__ */ jsx3("th", { className, style, ...props, children });
|
|
533
|
+
}
|
|
534
|
+
return /* @__PURE__ */ jsx3("td", { className, style, ...props, children });
|
|
535
|
+
},
|
|
536
|
+
(p, n) => sameClassAndNode(p, n) && p.isHeader === n.isHeader && p.align === n.align
|
|
537
|
+
);
|
|
538
|
+
MemoTableCell.displayName = "MemoTableCell";
|
|
539
|
+
var MemoCode = memo2(
|
|
540
|
+
({ children, className, inline, ...props }) => {
|
|
541
|
+
if (inline) {
|
|
542
|
+
return /* @__PURE__ */ jsx3("code", { className, ...props, children });
|
|
543
|
+
}
|
|
544
|
+
return /* @__PURE__ */ jsx3("code", { className, ...props, children });
|
|
545
|
+
},
|
|
546
|
+
(p, n) => sameClassAndNode(p, n) && p.inline === n.inline
|
|
547
|
+
);
|
|
548
|
+
MemoCode.displayName = "MemoCode";
|
|
549
|
+
var MemoPreformatted = memo2(
|
|
550
|
+
({ children, className, ...props }) => /* @__PURE__ */ jsx3("pre", { className, ...props, children }),
|
|
551
|
+
(p, n) => sameClassAndNode(p, n)
|
|
552
|
+
);
|
|
553
|
+
MemoPreformatted.displayName = "MemoPreformatted";
|
|
554
|
+
var MemoStrong = memo2(
|
|
555
|
+
({ children, className, ...props }) => /* @__PURE__ */ jsx3("strong", { className, ...props, children }),
|
|
556
|
+
(p, n) => sameClassAndNode(p, n)
|
|
557
|
+
);
|
|
558
|
+
MemoStrong.displayName = "MemoStrong";
|
|
559
|
+
var MemoEmphasis = memo2(
|
|
560
|
+
({ children, className, ...props }) => /* @__PURE__ */ jsx3("em", { className, ...props, children }),
|
|
561
|
+
(p, n) => sameClassAndNode(p, n)
|
|
562
|
+
);
|
|
563
|
+
MemoEmphasis.displayName = "MemoEmphasis";
|
|
564
|
+
var MemoHr = memo2(
|
|
565
|
+
({ className, ...props }) => /* @__PURE__ */ jsx3("hr", { className, ...props }),
|
|
566
|
+
(p, n) => sameClassAndNode(p, n)
|
|
567
|
+
);
|
|
568
|
+
MemoHr.displayName = "MemoHr";
|
|
569
|
+
var MemoImage = memo2(
|
|
570
|
+
({ className, href, title, ...props }) => /* @__PURE__ */ jsx3(
|
|
571
|
+
"img",
|
|
369
572
|
{
|
|
370
573
|
className,
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
574
|
+
src: href,
|
|
575
|
+
alt: title ?? "",
|
|
576
|
+
title,
|
|
577
|
+
...props
|
|
374
578
|
}
|
|
375
|
-
)
|
|
376
|
-
|
|
579
|
+
),
|
|
580
|
+
(p, n) => sameClassAndNode(p, n) && p.href === n.href && p.title === n.title
|
|
581
|
+
);
|
|
582
|
+
MemoImage.displayName = "MemoImage";
|
|
583
|
+
var MemoDelete = memo2(
|
|
584
|
+
({ children, className, ...props }) => /* @__PURE__ */ jsx3("del", { className, ...props, children }),
|
|
585
|
+
(p, n) => sameClassAndNode(p, n)
|
|
586
|
+
);
|
|
587
|
+
MemoDelete.displayName = "MemoDelete";
|
|
588
|
+
|
|
589
|
+
// src/components/Markdown/StreamingMarkdown.tsx
|
|
590
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
591
|
+
var StreamingMarkdown = memo3(
|
|
592
|
+
function StreamingMarkdown2({
|
|
593
|
+
children,
|
|
594
|
+
className,
|
|
595
|
+
components: customComponents,
|
|
596
|
+
status = "idle",
|
|
597
|
+
onComplete,
|
|
598
|
+
minDelay = 10
|
|
599
|
+
}) {
|
|
600
|
+
const markdown = typeof children === "string" ? children : String(children || "");
|
|
601
|
+
const [displayedText, setDisplayedText] = useState2(status !== "streaming" ? markdown : "");
|
|
602
|
+
const previousChildrenRef = useRef2(status !== "streaming" ? markdown : "");
|
|
603
|
+
const generatedId = useId();
|
|
604
|
+
const { addChunk, reset } = useSmoothStream({
|
|
605
|
+
onUpdate: setDisplayedText,
|
|
606
|
+
streamDone: status !== "streaming",
|
|
607
|
+
minDelay,
|
|
608
|
+
initialText: status !== "streaming" ? markdown : "",
|
|
609
|
+
onComplete
|
|
610
|
+
});
|
|
611
|
+
useEffect3(() => {
|
|
612
|
+
const currentContent = markdown;
|
|
613
|
+
const previousContent = previousChildrenRef.current;
|
|
614
|
+
if (currentContent !== previousContent) {
|
|
615
|
+
if (currentContent.startsWith(previousContent)) {
|
|
616
|
+
const delta = currentContent.slice(previousContent.length);
|
|
617
|
+
addChunk(delta);
|
|
618
|
+
} else {
|
|
619
|
+
reset(currentContent);
|
|
620
|
+
}
|
|
621
|
+
previousChildrenRef.current = currentContent;
|
|
622
|
+
}
|
|
623
|
+
}, [markdown, addChunk, reset]);
|
|
624
|
+
const blocks = useMemo(
|
|
625
|
+
() => parseMarkdownIntoBlocks(displayedText),
|
|
626
|
+
[displayedText]
|
|
627
|
+
);
|
|
628
|
+
const components = useMemo(() => {
|
|
629
|
+
const baseComponents = {
|
|
630
|
+
h1: MemoH1,
|
|
631
|
+
h2: MemoH2,
|
|
632
|
+
h3: MemoH3,
|
|
633
|
+
h4: MemoH4,
|
|
634
|
+
h5: MemoH5,
|
|
635
|
+
h6: MemoH6,
|
|
636
|
+
p: MemoParagraph,
|
|
637
|
+
a: MemoLink,
|
|
638
|
+
blockquote: MemoBlockquote,
|
|
639
|
+
ul: (props) => /* @__PURE__ */ jsx4(MemoList, { ordered: false, ...props }),
|
|
640
|
+
ol: (props) => /* @__PURE__ */ jsx4(MemoList, { ordered: true, ...props }),
|
|
641
|
+
li: MemoListItem,
|
|
642
|
+
table: MemoTable,
|
|
643
|
+
thead: MemoTableHead,
|
|
644
|
+
tbody: MemoTableBody,
|
|
645
|
+
tr: MemoTableRow,
|
|
646
|
+
th: (props) => /* @__PURE__ */ jsx4(MemoTableCell, { isHeader: true, ...props }),
|
|
647
|
+
td: MemoTableCell,
|
|
648
|
+
strong: MemoStrong,
|
|
649
|
+
em: MemoEmphasis,
|
|
650
|
+
hr: MemoHr,
|
|
651
|
+
img: (props) => /* @__PURE__ */ jsx4(MemoImage, { href: props.src, title: props.alt, ...props }),
|
|
652
|
+
del: MemoDelete,
|
|
653
|
+
code: (props) => {
|
|
654
|
+
const { node, inline, className: className2, children: children2, ...rest } = props;
|
|
655
|
+
if (inline) {
|
|
656
|
+
return /* @__PURE__ */ jsx4(MemoCode, { inline: true, className: className2, node, ...rest, children: children2 });
|
|
657
|
+
}
|
|
658
|
+
const match = /language-(\w+)/.exec(className2 || "");
|
|
659
|
+
const language = match ? match[1] : void 0;
|
|
660
|
+
const code = String(children2).replace(/\n$/, "");
|
|
661
|
+
return /* @__PURE__ */ jsx4(CodeBlock, { code, language, className: className2 });
|
|
662
|
+
},
|
|
663
|
+
pre: (props) => {
|
|
664
|
+
const { children: children2, ...rest } = props;
|
|
665
|
+
if (children2?.type === CodeBlock) {
|
|
666
|
+
return children2;
|
|
667
|
+
}
|
|
668
|
+
return /* @__PURE__ */ jsx4(MemoPreformatted, { ...rest, children: children2 });
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
if (/<style\b[^>]*>/i.test(markdown)) {
|
|
672
|
+
baseComponents.style = (props) => /* @__PURE__ */ jsx4("div", { ...props });
|
|
673
|
+
}
|
|
674
|
+
return { ...baseComponents, ...customComponents };
|
|
675
|
+
}, [markdown, customComponents]);
|
|
676
|
+
return /* @__PURE__ */ jsx4("div", { className, children: blocks.map((block, index) => /* @__PURE__ */ jsx4(
|
|
677
|
+
Block,
|
|
678
|
+
{
|
|
679
|
+
content: block,
|
|
680
|
+
components,
|
|
681
|
+
remarkPlugins: [remarkGfm]
|
|
682
|
+
},
|
|
683
|
+
`${generatedId}-block-${index}`
|
|
684
|
+
)) });
|
|
685
|
+
},
|
|
686
|
+
(prevProps, nextProps) => {
|
|
687
|
+
return prevProps.children === nextProps.children && prevProps.status === nextProps.status && prevProps.className === nextProps.className;
|
|
688
|
+
}
|
|
689
|
+
);
|
|
690
|
+
StreamingMarkdown.displayName = "StreamingMarkdown";
|
|
377
691
|
|
|
378
692
|
// src/components/Message/MessageBlockRenderer.tsx
|
|
379
|
-
import { jsx as
|
|
693
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
380
694
|
function MessageBlockRenderer({ block, className }) {
|
|
381
695
|
switch (block.type) {
|
|
382
696
|
case "main_text" /* MAIN_TEXT */:
|
|
@@ -385,7 +699,7 @@ function MessageBlockRenderer({ block, className }) {
|
|
|
385
699
|
case "error" /* ERROR */:
|
|
386
700
|
case "unknown" /* UNKNOWN */: {
|
|
387
701
|
const textBlock = block;
|
|
388
|
-
return /* @__PURE__ */
|
|
702
|
+
return /* @__PURE__ */ jsx5(
|
|
389
703
|
StreamingMarkdown,
|
|
390
704
|
{
|
|
391
705
|
className,
|
|
@@ -396,18 +710,18 @@ function MessageBlockRenderer({ block, className }) {
|
|
|
396
710
|
}
|
|
397
711
|
case "code" /* CODE */: {
|
|
398
712
|
const codeBlock = block;
|
|
399
|
-
return /* @__PURE__ */
|
|
713
|
+
return /* @__PURE__ */ jsx5("div", { className, children: /* @__PURE__ */ jsx5("pre", { children: /* @__PURE__ */ jsx5("code", { children: codeBlock.content }) }) });
|
|
400
714
|
}
|
|
401
715
|
case "image" /* IMAGE */:
|
|
402
716
|
case "video" /* VIDEO */:
|
|
403
717
|
case "file" /* FILE */: {
|
|
404
718
|
const mediaBlock = block;
|
|
405
|
-
return /* @__PURE__ */
|
|
719
|
+
return /* @__PURE__ */ jsx5("div", { className, children: /* @__PURE__ */ jsx5("a", { href: mediaBlock.url, target: "_blank", rel: "noopener noreferrer", children: mediaBlock.name ?? "Media File" }) });
|
|
406
720
|
}
|
|
407
721
|
case "tool" /* TOOL */:
|
|
408
722
|
case "citation" /* CITATION */: {
|
|
409
723
|
const toolBlock = block;
|
|
410
|
-
return /* @__PURE__ */
|
|
724
|
+
return /* @__PURE__ */ jsx5("div", { className, children: /* @__PURE__ */ jsx5("pre", { children: JSON.stringify(toolBlock.payload ?? {}, null, 2) }) });
|
|
411
725
|
}
|
|
412
726
|
default:
|
|
413
727
|
return null;
|
|
@@ -415,17 +729,17 @@ function MessageBlockRenderer({ block, className }) {
|
|
|
415
729
|
}
|
|
416
730
|
|
|
417
731
|
// src/components/Message/MessageItem.tsx
|
|
418
|
-
import { useId, useMemo as useMemo2 } from "react";
|
|
732
|
+
import { useId as useId2, useMemo as useMemo2 } from "react";
|
|
419
733
|
import ReactMarkdown2 from "react-markdown";
|
|
420
734
|
import remarkGfm2 from "remark-gfm";
|
|
421
735
|
|
|
422
736
|
// src/utils/markdown/splitMarkdownIntoBlocks.ts
|
|
423
|
-
var
|
|
424
|
-
function
|
|
425
|
-
|
|
426
|
-
return `block-${Date.now()}-${
|
|
737
|
+
var blockIdCounter2 = 0;
|
|
738
|
+
function generateBlockId2() {
|
|
739
|
+
blockIdCounter2 += 1;
|
|
740
|
+
return `block-${Date.now()}-${blockIdCounter2}`;
|
|
427
741
|
}
|
|
428
|
-
function
|
|
742
|
+
function splitMarkdownIntoBlocks2({
|
|
429
743
|
messageId,
|
|
430
744
|
markdown,
|
|
431
745
|
status = "idle" /* IDLE */
|
|
@@ -434,7 +748,7 @@ function splitMarkdownIntoBlocks({
|
|
|
434
748
|
return [];
|
|
435
749
|
}
|
|
436
750
|
const block = {
|
|
437
|
-
id:
|
|
751
|
+
id: generateBlockId2(),
|
|
438
752
|
messageId,
|
|
439
753
|
type: "main_text" /* MAIN_TEXT */,
|
|
440
754
|
status,
|
|
@@ -445,7 +759,7 @@ function splitMarkdownIntoBlocks({
|
|
|
445
759
|
}
|
|
446
760
|
|
|
447
761
|
// src/components/Message/MessageItem.tsx
|
|
448
|
-
import { jsx as
|
|
762
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
449
763
|
function MessageItem({
|
|
450
764
|
children,
|
|
451
765
|
role = "assistant",
|
|
@@ -455,9 +769,9 @@ function MessageItem({
|
|
|
455
769
|
}) {
|
|
456
770
|
const markdown = typeof children === "string" ? children : String(children ?? "");
|
|
457
771
|
if (role === "user") {
|
|
458
|
-
return /* @__PURE__ */
|
|
772
|
+
return /* @__PURE__ */ jsx6("div", { className, "data-role": "user", children: /* @__PURE__ */ jsx6(ReactMarkdown2, { remarkPlugins: [remarkGfm2], children: markdown }) });
|
|
459
773
|
}
|
|
460
|
-
const generatedId =
|
|
774
|
+
const generatedId = useId2();
|
|
461
775
|
const messageIdRef = messageId ?? generatedId;
|
|
462
776
|
const blocks = useMemo2(() => {
|
|
463
777
|
const allBlocks = messageBlockStore.selectAll();
|
|
@@ -465,7 +779,7 @@ function MessageItem({
|
|
|
465
779
|
if (oldBlockIds.length > 0) {
|
|
466
780
|
messageBlockStore.remove(oldBlockIds);
|
|
467
781
|
}
|
|
468
|
-
const newBlocks =
|
|
782
|
+
const newBlocks = splitMarkdownIntoBlocks2({
|
|
469
783
|
messageId: messageIdRef,
|
|
470
784
|
markdown,
|
|
471
785
|
status: "idle" /* IDLE */
|
|
@@ -473,18 +787,236 @@ function MessageItem({
|
|
|
473
787
|
messageBlockStore.upsert(newBlocks);
|
|
474
788
|
return newBlocks;
|
|
475
789
|
}, [markdown, messageIdRef]);
|
|
476
|
-
return /* @__PURE__ */
|
|
790
|
+
return /* @__PURE__ */ jsx6("div", { className, "data-message-id": messageIdRef, "data-role": role, children: blocks.map((block) => /* @__PURE__ */ jsx6(MessageBlockRenderer, { block, className: blockClassName }, block.id)) });
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// src/utils/shiki/ShikiHighlighterManager.ts
|
|
794
|
+
import { createHighlighterCore as createHighlighterCore2 } from "shiki/core";
|
|
795
|
+
import { createJavaScriptRegexEngine as createJavaScriptRegexEngine2 } from "shiki/engine/javascript";
|
|
796
|
+
|
|
797
|
+
// src/utils/shiki/languageRegistry.ts
|
|
798
|
+
var LANGUAGE_REGISTRY = {
|
|
799
|
+
javascript: () => import("shiki/langs/javascript.mjs"),
|
|
800
|
+
js: () => import("shiki/langs/javascript.mjs"),
|
|
801
|
+
typescript: () => import("shiki/langs/typescript.mjs"),
|
|
802
|
+
ts: () => import("shiki/langs/typescript.mjs"),
|
|
803
|
+
tsx: () => import("shiki/langs/tsx.mjs"),
|
|
804
|
+
jsx: () => import("shiki/langs/jsx.mjs"),
|
|
805
|
+
python: () => import("shiki/langs/python.mjs"),
|
|
806
|
+
py: () => import("shiki/langs/python.mjs"),
|
|
807
|
+
java: () => import("shiki/langs/java.mjs"),
|
|
808
|
+
json: () => import("shiki/langs/json.mjs"),
|
|
809
|
+
html: () => import("shiki/langs/html.mjs"),
|
|
810
|
+
css: () => import("shiki/langs/css.mjs"),
|
|
811
|
+
bash: () => import("shiki/langs/bash.mjs"),
|
|
812
|
+
sh: () => import("shiki/langs/bash.mjs"),
|
|
813
|
+
shell: () => import("shiki/langs/shell.mjs"),
|
|
814
|
+
sql: () => import("shiki/langs/sql.mjs"),
|
|
815
|
+
markdown: () => import("shiki/langs/markdown.mjs"),
|
|
816
|
+
md: () => import("shiki/langs/markdown.mjs"),
|
|
817
|
+
go: () => import("shiki/langs/go.mjs"),
|
|
818
|
+
rust: () => import("shiki/langs/rust.mjs"),
|
|
819
|
+
rs: () => import("shiki/langs/rust.mjs"),
|
|
820
|
+
c: () => import("shiki/langs/c.mjs"),
|
|
821
|
+
cpp: () => import("shiki/langs/cpp.mjs"),
|
|
822
|
+
"c++": () => import("shiki/langs/cpp.mjs"),
|
|
823
|
+
csharp: () => import("shiki/langs/csharp.mjs"),
|
|
824
|
+
"c#": () => import("shiki/langs/csharp.mjs"),
|
|
825
|
+
cs: () => import("shiki/langs/csharp.mjs"),
|
|
826
|
+
php: () => import("shiki/langs/php.mjs"),
|
|
827
|
+
ruby: () => import("shiki/langs/ruby.mjs"),
|
|
828
|
+
rb: () => import("shiki/langs/ruby.mjs"),
|
|
829
|
+
swift: () => import("shiki/langs/swift.mjs"),
|
|
830
|
+
kotlin: () => import("shiki/langs/kotlin.mjs"),
|
|
831
|
+
kt: () => import("shiki/langs/kotlin.mjs"),
|
|
832
|
+
yaml: () => import("shiki/langs/yaml.mjs"),
|
|
833
|
+
yml: () => import("shiki/langs/yaml.mjs"),
|
|
834
|
+
xml: () => import("shiki/langs/xml.mjs"),
|
|
835
|
+
dockerfile: () => import("shiki/langs/dockerfile.mjs"),
|
|
836
|
+
graphql: () => import("shiki/langs/graphql.mjs"),
|
|
837
|
+
gql: () => import("shiki/langs/graphql.mjs"),
|
|
838
|
+
terraform: () => import("shiki/langs/terraform.mjs"),
|
|
839
|
+
tf: () => import("shiki/langs/terraform.mjs"),
|
|
840
|
+
lua: () => import("shiki/langs/lua.mjs"),
|
|
841
|
+
r: () => import("shiki/langs/r.mjs"),
|
|
842
|
+
scala: () => import("shiki/langs/scala.mjs"),
|
|
843
|
+
elixir: () => import("shiki/langs/elixir.mjs"),
|
|
844
|
+
ex: () => import("shiki/langs/elixir.mjs"),
|
|
845
|
+
dart: () => import("shiki/langs/dart.mjs"),
|
|
846
|
+
vue: () => import("shiki/langs/vue.mjs"),
|
|
847
|
+
svelte: () => import("shiki/langs/svelte.mjs"),
|
|
848
|
+
astro: () => import("shiki/langs/astro.mjs")
|
|
849
|
+
};
|
|
850
|
+
var THEME_REGISTRY = {
|
|
851
|
+
"github-light": () => import("shiki/themes/github-light.mjs"),
|
|
852
|
+
"github-dark": () => import("shiki/themes/github-dark.mjs"),
|
|
853
|
+
"github-dark-dimmed": () => import("shiki/themes/github-dark-dimmed.mjs"),
|
|
854
|
+
"dracula": () => import("shiki/themes/dracula.mjs"),
|
|
855
|
+
"monokai": () => import("shiki/themes/monokai.mjs"),
|
|
856
|
+
"nord": () => import("shiki/themes/nord.mjs"),
|
|
857
|
+
"one-dark-pro": () => import("shiki/themes/one-dark-pro.mjs"),
|
|
858
|
+
"solarized-light": () => import("shiki/themes/solarized-light.mjs"),
|
|
859
|
+
"solarized-dark": () => import("shiki/themes/solarized-dark.mjs"),
|
|
860
|
+
"vitesse-light": () => import("shiki/themes/vitesse-light.mjs"),
|
|
861
|
+
"vitesse-dark": () => import("shiki/themes/vitesse-dark.mjs")
|
|
862
|
+
};
|
|
863
|
+
function getLanguageImport(lang) {
|
|
864
|
+
const normalizedLang = lang.toLowerCase();
|
|
865
|
+
const importFn = LANGUAGE_REGISTRY[normalizedLang];
|
|
866
|
+
if (!importFn) {
|
|
867
|
+
console.warn(`[Shiki] Language "${lang}" not found in registry, falling back to plain text`);
|
|
868
|
+
return import("shiki/langs/javascript.mjs");
|
|
869
|
+
}
|
|
870
|
+
return importFn();
|
|
871
|
+
}
|
|
872
|
+
function getThemeImport(theme) {
|
|
873
|
+
const normalizedTheme = theme.toLowerCase();
|
|
874
|
+
const importFn = THEME_REGISTRY[normalizedTheme];
|
|
875
|
+
if (!importFn) {
|
|
876
|
+
console.warn(`[Shiki] Theme "${theme}" not found in registry, falling back to github-light`);
|
|
877
|
+
return import("shiki/themes/github-light.mjs");
|
|
878
|
+
}
|
|
879
|
+
return importFn();
|
|
880
|
+
}
|
|
881
|
+
function isLanguageSupported(lang) {
|
|
882
|
+
return lang.toLowerCase() in LANGUAGE_REGISTRY;
|
|
883
|
+
}
|
|
884
|
+
function isThemeSupported(theme) {
|
|
885
|
+
return theme.toLowerCase() in THEME_REGISTRY;
|
|
886
|
+
}
|
|
887
|
+
function getSupportedLanguages() {
|
|
888
|
+
return Object.keys(LANGUAGE_REGISTRY);
|
|
477
889
|
}
|
|
890
|
+
function getSupportedThemes() {
|
|
891
|
+
return Object.keys(THEME_REGISTRY);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
// src/utils/shiki/ShikiHighlighterManager.ts
|
|
895
|
+
var ShikiHighlighterManager = class {
|
|
896
|
+
constructor() {
|
|
897
|
+
this.lightHighlighter = null;
|
|
898
|
+
this.darkHighlighter = null;
|
|
899
|
+
this.lightTheme = null;
|
|
900
|
+
this.darkTheme = null;
|
|
901
|
+
this.loadedLanguages = /* @__PURE__ */ new Set();
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* 高亮代码(返回 light 和 dark 两个主题的 HTML)
|
|
905
|
+
*
|
|
906
|
+
* @param code - 代码字符串
|
|
907
|
+
* @param language - 语言标识符
|
|
908
|
+
* @param themes - [light theme, dark theme] 元组
|
|
909
|
+
* @returns [lightHtml, darkHtml] - 两个主题的 HTML 元组
|
|
910
|
+
*/
|
|
911
|
+
async highlightCode(code, language, themes) {
|
|
912
|
+
const [lightTheme, darkTheme] = themes;
|
|
913
|
+
const needsLightRecreation = !this.lightHighlighter || this.lightTheme !== lightTheme;
|
|
914
|
+
const needsDarkRecreation = !this.darkHighlighter || this.darkTheme !== darkTheme;
|
|
915
|
+
if (needsLightRecreation || needsDarkRecreation) {
|
|
916
|
+
this.loadedLanguages.clear();
|
|
917
|
+
}
|
|
918
|
+
const languageSupported = isLanguageSupported(language);
|
|
919
|
+
const needsLanguageLoad = !this.loadedLanguages.has(language) && languageSupported;
|
|
920
|
+
if (needsLightRecreation) {
|
|
921
|
+
this.lightHighlighter = await createHighlighterCore2({
|
|
922
|
+
themes: [getThemeImport(lightTheme)],
|
|
923
|
+
langs: languageSupported ? [getLanguageImport(language)] : [],
|
|
924
|
+
engine: createJavaScriptRegexEngine2({ forgiving: true })
|
|
925
|
+
});
|
|
926
|
+
this.lightTheme = lightTheme;
|
|
927
|
+
if (languageSupported) {
|
|
928
|
+
this.loadedLanguages.add(language);
|
|
929
|
+
}
|
|
930
|
+
} else if (needsLanguageLoad && this.lightHighlighter) {
|
|
931
|
+
await this.lightHighlighter.loadLanguage(getLanguageImport(language));
|
|
932
|
+
this.loadedLanguages.add(language);
|
|
933
|
+
}
|
|
934
|
+
if (needsDarkRecreation) {
|
|
935
|
+
this.darkHighlighter = await createHighlighterCore2({
|
|
936
|
+
themes: [getThemeImport(darkTheme)],
|
|
937
|
+
langs: languageSupported ? [getLanguageImport(language)] : [],
|
|
938
|
+
engine: createJavaScriptRegexEngine2({ forgiving: true })
|
|
939
|
+
});
|
|
940
|
+
this.darkTheme = darkTheme;
|
|
941
|
+
} else if (needsLanguageLoad && this.darkHighlighter) {
|
|
942
|
+
await this.darkHighlighter.loadLanguage(getLanguageImport(language));
|
|
943
|
+
}
|
|
944
|
+
const lang = languageSupported ? language : "text";
|
|
945
|
+
const light = this.lightHighlighter?.codeToHtml(code, {
|
|
946
|
+
lang,
|
|
947
|
+
theme: lightTheme
|
|
948
|
+
}) ?? "";
|
|
949
|
+
const dark = this.darkHighlighter?.codeToHtml(code, {
|
|
950
|
+
lang,
|
|
951
|
+
theme: darkTheme
|
|
952
|
+
}) ?? "";
|
|
953
|
+
return [light, dark];
|
|
954
|
+
}
|
|
955
|
+
/**
|
|
956
|
+
* 高亮代码(单一主题版本)
|
|
957
|
+
*/
|
|
958
|
+
async highlightCodeSingle(code, language, theme) {
|
|
959
|
+
const [light] = await this.highlightCode(code, language, [theme, theme]);
|
|
960
|
+
return light;
|
|
961
|
+
}
|
|
962
|
+
/**
|
|
963
|
+
* 清除缓存(用于测试或内存清理)
|
|
964
|
+
*/
|
|
965
|
+
clear() {
|
|
966
|
+
this.lightHighlighter = null;
|
|
967
|
+
this.darkHighlighter = null;
|
|
968
|
+
this.lightTheme = null;
|
|
969
|
+
this.darkTheme = null;
|
|
970
|
+
this.loadedLanguages.clear();
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
var highlighterManager = new ShikiHighlighterManager();
|
|
478
974
|
export {
|
|
975
|
+
Block,
|
|
479
976
|
CodeBlock,
|
|
977
|
+
MemoBlockquote,
|
|
978
|
+
MemoCode,
|
|
979
|
+
MemoDelete,
|
|
980
|
+
MemoEmphasis,
|
|
981
|
+
MemoH1,
|
|
982
|
+
MemoH2,
|
|
983
|
+
MemoH3,
|
|
984
|
+
MemoH4,
|
|
985
|
+
MemoH5,
|
|
986
|
+
MemoH6,
|
|
987
|
+
MemoHr,
|
|
988
|
+
MemoImage,
|
|
989
|
+
MemoLink,
|
|
990
|
+
MemoList,
|
|
991
|
+
MemoListItem,
|
|
992
|
+
MemoParagraph,
|
|
993
|
+
MemoPreformatted,
|
|
994
|
+
MemoStrong,
|
|
995
|
+
MemoTable,
|
|
996
|
+
MemoTableBody,
|
|
997
|
+
MemoTableCell,
|
|
998
|
+
MemoTableHead,
|
|
999
|
+
MemoTableRow,
|
|
480
1000
|
MessageBlockRenderer,
|
|
481
1001
|
MessageBlockStatus,
|
|
482
1002
|
MessageBlockStore,
|
|
483
1003
|
MessageBlockType,
|
|
484
1004
|
MessageItem,
|
|
485
1005
|
MessageStatus,
|
|
1006
|
+
ShikiHighlighterManager,
|
|
486
1007
|
StreamingMarkdown,
|
|
1008
|
+
getLanguageImport,
|
|
1009
|
+
getSupportedLanguages,
|
|
1010
|
+
getSupportedThemes,
|
|
1011
|
+
getThemeImport,
|
|
1012
|
+
highlighterManager,
|
|
1013
|
+
isLanguageSupported,
|
|
1014
|
+
isThemeSupported,
|
|
487
1015
|
messageBlockStore,
|
|
1016
|
+
parseMarkdownIntoBlocks,
|
|
1017
|
+
sameClassAndNode,
|
|
1018
|
+
sameNodePosition,
|
|
1019
|
+
splitMarkdownIntoBlocks,
|
|
488
1020
|
useShikiHighlight,
|
|
489
1021
|
useSmoothStream
|
|
490
1022
|
};
|