@ai-react-markdown/mantine 2.11.0 → 2.12.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 +16 -12
- package/dist/index.cjs +204 -77
- package/dist/index.cjs.map +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +195 -68
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -25,7 +25,7 @@ var DefaultExtraStyles_default = MantineAIMDefaultExtraStyles;
|
|
|
25
25
|
|
|
26
26
|
// src/components/customized/PreCode.tsx
|
|
27
27
|
import { memo as memo3, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
|
|
28
|
-
import { CodeHighlight, CodeHighlightTabs as CodeHighlightTabs2 } from "@mantine/code-highlight";
|
|
28
|
+
import { CodeHighlight, CodeHighlightTabs as CodeHighlightTabs2, CodeHighlightControl as CodeHighlightControl2 } from "@mantine/code-highlight";
|
|
29
29
|
import { useAIMarkdownState as useAIMarkdownState2, useAIMarkdownTheme as useAIMarkdownTheme2 } from "@ai-react-markdown/core";
|
|
30
30
|
|
|
31
31
|
// src/hooks/useMantineCodeBlockOptions.ts
|
|
@@ -35,7 +35,9 @@ import { useAIMarkdownBehaviors } from "@ai-react-markdown/core";
|
|
|
35
35
|
// src/defs.tsx
|
|
36
36
|
var defaultMantineCodeBlockOptions = Object.freeze({
|
|
37
37
|
defaultExpanded: true,
|
|
38
|
-
autoDetectUnknownLanguage: false
|
|
38
|
+
autoDetectUnknownLanguage: false,
|
|
39
|
+
formatJson: true,
|
|
40
|
+
expandNestedJson: true
|
|
39
41
|
});
|
|
40
42
|
|
|
41
43
|
// src/hooks/useMantineCodeBlockOptions.ts
|
|
@@ -52,6 +54,43 @@ function useMantineCodeBlockOptions() {
|
|
|
52
54
|
}, [group]);
|
|
53
55
|
}
|
|
54
56
|
|
|
57
|
+
// src/components/customized/MermaidCode/renderQueue.ts
|
|
58
|
+
function createRenderQueue() {
|
|
59
|
+
const pending = /* @__PURE__ */ new Map();
|
|
60
|
+
let running = false;
|
|
61
|
+
async function drain() {
|
|
62
|
+
if (running) return;
|
|
63
|
+
running = true;
|
|
64
|
+
try {
|
|
65
|
+
while (pending.size) {
|
|
66
|
+
const [owner, job] = pending.entries().next().value;
|
|
67
|
+
pending.delete(owner);
|
|
68
|
+
try {
|
|
69
|
+
await job.run();
|
|
70
|
+
job.resolve();
|
|
71
|
+
} catch (error) {
|
|
72
|
+
job.reject(error);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
} finally {
|
|
76
|
+
running = false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
enqueue(owner, run) {
|
|
81
|
+
pending.get(owner)?.resolve();
|
|
82
|
+
const promise = new Promise((resolve, reject) => pending.set(owner, { run, resolve, reject }));
|
|
83
|
+
void drain();
|
|
84
|
+
return promise;
|
|
85
|
+
},
|
|
86
|
+
cancel(owner) {
|
|
87
|
+
pending.get(owner)?.resolve();
|
|
88
|
+
pending.delete(owner);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
var mermaidRenderQueue = createRenderQueue();
|
|
93
|
+
|
|
55
94
|
// src/components/customized/MermaidCode/index.tsx
|
|
56
95
|
import { memo as memo2, useEffect, useRef, useState, useCallback } from "react";
|
|
57
96
|
import { CodeHighlightControl, CodeHighlightTabs } from "@mantine/code-highlight";
|
|
@@ -173,14 +212,7 @@ var MantineAIMMermaidCode = memo2((props) => {
|
|
|
173
212
|
if (!ref.current || cancelled || renderVersion !== renderVersionRef.current) {
|
|
174
213
|
return;
|
|
175
214
|
}
|
|
176
|
-
|
|
177
|
-
if (initializedTheme !== (isDark ? "dark" : "light")) {
|
|
178
|
-
if (!ref.current || cancelled || renderVersion !== renderVersionRef.current) {
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
ensureMermaidInitialized(mermaid, isDark);
|
|
182
|
-
rendered = await mermaid.render(generateMermaidUUID(), props.code);
|
|
183
|
-
}
|
|
215
|
+
const rendered = await mermaid.render(generateMermaidUUID(), props.code);
|
|
184
216
|
const { svg, bindFunctions, diagramType } = rendered;
|
|
185
217
|
if (!ref.current || cancelled || renderVersion !== renderVersionRef.current) {
|
|
186
218
|
return;
|
|
@@ -208,9 +240,11 @@ var MantineAIMMermaidCode = memo2((props) => {
|
|
|
208
240
|
applyView({ kind: "error" });
|
|
209
241
|
}
|
|
210
242
|
};
|
|
211
|
-
|
|
243
|
+
const owner = renderVersionRef;
|
|
244
|
+
void mermaidRenderQueue.enqueue(owner, renderMermaid);
|
|
212
245
|
return () => {
|
|
213
246
|
cancelled = true;
|
|
247
|
+
mermaidRenderQueue.cancel(owner);
|
|
214
248
|
if (retryTimer !== void 0) clearTimeout(retryTimer);
|
|
215
249
|
};
|
|
216
250
|
}, [props.code, isDark, showOriginalCode, streaming, loadAttempt]);
|
|
@@ -361,7 +395,96 @@ MantineAIMMermaidCode.displayName = "MantineAIMMermaidCode";
|
|
|
361
395
|
var MermaidCode_default = MantineAIMMermaidCode;
|
|
362
396
|
|
|
363
397
|
// src/components/customized/PreCode.tsx
|
|
364
|
-
import {
|
|
398
|
+
import { CopyButton as CopyButton2 } from "@mantine/core";
|
|
399
|
+
|
|
400
|
+
// src/components/customized/formatJson.ts
|
|
401
|
+
function prettyPrintJson(text, expandNested = true) {
|
|
402
|
+
try {
|
|
403
|
+
return format(text, expandNested, 0);
|
|
404
|
+
} catch {
|
|
405
|
+
return text;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
function format(text, expandNested, baseIndent) {
|
|
409
|
+
JSON.parse(text);
|
|
410
|
+
const tokens = text.match(/"(?:\\[\s\S]|[^"\\])*"|-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?|true|false|null|[{}[\],:]/g) ?? [];
|
|
411
|
+
const out = [];
|
|
412
|
+
let indent = baseIndent;
|
|
413
|
+
const newline = () => out.push("\n", " ".repeat(indent));
|
|
414
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
415
|
+
const token = tokens[i];
|
|
416
|
+
if (token === "{" || token === "[") {
|
|
417
|
+
out.push(token);
|
|
418
|
+
if (tokens[i + 1] !== (token === "{" ? "}" : "]")) {
|
|
419
|
+
indent++;
|
|
420
|
+
newline();
|
|
421
|
+
}
|
|
422
|
+
} else if (token === "}" || token === "]") {
|
|
423
|
+
if (tokens[i - 1] !== (token === "}" ? "{" : "[")) {
|
|
424
|
+
indent--;
|
|
425
|
+
newline();
|
|
426
|
+
}
|
|
427
|
+
out.push(token);
|
|
428
|
+
} else if (token === ",") {
|
|
429
|
+
out.push(",");
|
|
430
|
+
newline();
|
|
431
|
+
} else if (token === ":") {
|
|
432
|
+
out.push(": ");
|
|
433
|
+
} else if (token.startsWith('"')) {
|
|
434
|
+
const value = JSON.parse(token);
|
|
435
|
+
const trimmed = value.trim();
|
|
436
|
+
if (expandNested && tokens[i + 1] !== ":" && /^[{[]/.test(trimmed) && indent < 100) {
|
|
437
|
+
try {
|
|
438
|
+
out.push(format(trimmed, true, indent));
|
|
439
|
+
continue;
|
|
440
|
+
} catch {
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
out.push(JSON.stringify(value));
|
|
444
|
+
} else {
|
|
445
|
+
out.push(token);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return out.join("");
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// src/components/customized/jsonCompleteness.ts
|
|
452
|
+
function createJsonCompletenessScanner() {
|
|
453
|
+
let previous = "";
|
|
454
|
+
let depth = 0;
|
|
455
|
+
let quoted = false;
|
|
456
|
+
let escaped = false;
|
|
457
|
+
let invalid = false;
|
|
458
|
+
let last = "";
|
|
459
|
+
return (text) => {
|
|
460
|
+
let from = previous.length;
|
|
461
|
+
if (!text.startsWith(previous)) {
|
|
462
|
+
from = 0;
|
|
463
|
+
depth = 0;
|
|
464
|
+
quoted = escaped = invalid = false;
|
|
465
|
+
last = "";
|
|
466
|
+
}
|
|
467
|
+
previous = text;
|
|
468
|
+
for (let i = from; i < text.length; i++) {
|
|
469
|
+
const c = text[i];
|
|
470
|
+
if (!/\s/.test(c)) last = c;
|
|
471
|
+
if (quoted) {
|
|
472
|
+
if (escaped) escaped = false;
|
|
473
|
+
else if (c === "\\") escaped = true;
|
|
474
|
+
else if (c === '"') quoted = false;
|
|
475
|
+
} else if (c === '"') quoted = true;
|
|
476
|
+
else if (c === "{" || c === "[") depth++;
|
|
477
|
+
else if (c === "}" || c === "]") {
|
|
478
|
+
depth--;
|
|
479
|
+
if (depth < 0) invalid = true;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return !invalid && !quoted && depth === 0 && (last === "}" || last === "]");
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// src/components/customized/PreCode.tsx
|
|
487
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
365
488
|
var hljsAutoPromise = null;
|
|
366
489
|
var loadHljsForAutoDetect = () => {
|
|
367
490
|
hljsAutoPromise ??= import("highlight.js").then(
|
|
@@ -382,9 +505,15 @@ function useAutoDetectedLanguage(codeText, enabled, streaming) {
|
|
|
382
505
|
);
|
|
383
506
|
const [loadAttempt, setLoadAttempt] = useState2(0);
|
|
384
507
|
const loadFailuresRef = useRef2(0);
|
|
508
|
+
const previousTextRef = useRef2(codeText);
|
|
385
509
|
useEffect2(() => {
|
|
386
|
-
|
|
387
|
-
|
|
510
|
+
const appended = codeText.startsWith(previousTextRef.current);
|
|
511
|
+
previousTextRef.current = codeText;
|
|
512
|
+
if (!enabled) {
|
|
513
|
+
if (detected) setDetected(null);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
const prior = !appended || detected !== null && codeText.length < detected.atLength ? null : detected;
|
|
388
517
|
if (prior !== detected) setDetected(null);
|
|
389
518
|
if (codeText.length < AUTODETECT_MIN_CHARS) return;
|
|
390
519
|
const due = prior === null || // Not streaming: the verdict must be for THIS text (end-of-stream, or a
|
|
@@ -423,54 +552,31 @@ function preloadMantineCodeAssets() {
|
|
|
423
552
|
() => void 0
|
|
424
553
|
);
|
|
425
554
|
}
|
|
426
|
-
function
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
const out = /* @__PURE__ */ Object.create(null);
|
|
450
|
-
for (const [k, v] of Object.entries(value)) out[k] = expandNestedJson(v);
|
|
451
|
-
return out;
|
|
452
|
-
}
|
|
453
|
-
return value;
|
|
454
|
-
}
|
|
455
|
-
function jsonLooksComplete(text) {
|
|
456
|
-
if (!/[}\]]\s*$/.test(text)) return false;
|
|
457
|
-
let depth = 0;
|
|
458
|
-
let inString = false;
|
|
459
|
-
for (let i = 0; i < text.length; i++) {
|
|
460
|
-
const c = text.charCodeAt(i);
|
|
461
|
-
if (inString) {
|
|
462
|
-
if (c === 92) i += 1;
|
|
463
|
-
else if (c === 34) inString = false;
|
|
464
|
-
} else if (c === 34) {
|
|
465
|
-
inString = true;
|
|
466
|
-
} else if (c === 123 || c === 91) {
|
|
467
|
-
depth += 1;
|
|
468
|
-
} else if (c === 125 || c === 93) {
|
|
469
|
-
depth -= 1;
|
|
470
|
-
if (depth < 0) return false;
|
|
555
|
+
function RawCodeCopy({ code }) {
|
|
556
|
+
return /* @__PURE__ */ jsx4(CopyButton2, { value: code, children: ({ copied, copy }) => /* @__PURE__ */ jsx4(
|
|
557
|
+
CodeHighlightControl2,
|
|
558
|
+
{
|
|
559
|
+
tooltipLabel: copied ? "Copied" : "Copy",
|
|
560
|
+
"aria-label": copied ? "Copied" : "Copy code",
|
|
561
|
+
onClick: copy,
|
|
562
|
+
children: copied ? "\u2713" : /* @__PURE__ */ jsxs2(
|
|
563
|
+
"svg",
|
|
564
|
+
{
|
|
565
|
+
width: "16",
|
|
566
|
+
height: "16",
|
|
567
|
+
viewBox: "0 0 24 24",
|
|
568
|
+
fill: "none",
|
|
569
|
+
stroke: "currentColor",
|
|
570
|
+
strokeWidth: "1.5",
|
|
571
|
+
"aria-hidden": "true",
|
|
572
|
+
children: [
|
|
573
|
+
/* @__PURE__ */ jsx4("rect", { x: "8", y: "8", width: "12", height: "12", rx: "2" }),
|
|
574
|
+
/* @__PURE__ */ jsx4("path", { d: "M16 8V4H4v12h4" })
|
|
575
|
+
]
|
|
576
|
+
}
|
|
577
|
+
)
|
|
471
578
|
}
|
|
472
|
-
}
|
|
473
|
-
return depth === 0 && !inString;
|
|
579
|
+
) });
|
|
474
580
|
}
|
|
475
581
|
var SpecialCodeLanguage = /* @__PURE__ */ ((SpecialCodeLanguage2) => {
|
|
476
582
|
SpecialCodeLanguage2["Mermaid"] = "mermaid";
|
|
@@ -481,7 +587,7 @@ var MantineAIMPreCode = memo3(
|
|
|
481
587
|
(props) => {
|
|
482
588
|
const { fontSize } = useAIMarkdownTheme2();
|
|
483
589
|
const { streaming } = useAIMarkdownState2();
|
|
484
|
-
const { autoDetectUnknownLanguage, defaultExpanded } = useMantineCodeBlockOptions();
|
|
590
|
+
const { autoDetectUnknownLanguage, defaultExpanded, formatJson, expandNestedJson } = useMantineCodeBlockOptions();
|
|
485
591
|
const detectedLanguage = useAutoDetectedLanguage(
|
|
486
592
|
props.codeText,
|
|
487
593
|
autoDetectUnknownLanguage && !props.existLanguage,
|
|
@@ -493,11 +599,16 @@ var MantineAIMPreCode = memo3(
|
|
|
493
599
|
[codeLanguage]
|
|
494
600
|
);
|
|
495
601
|
const isSpecialCodeBlock = SPECIAL_LANGUAGES.has(codeLanguage);
|
|
602
|
+
const [scanJson] = useState2(createJsonCompletenessScanner);
|
|
603
|
+
const jsonComplete = useMemo2(
|
|
604
|
+
() => usedCodeLanguage === "json" && formatJson && streaming ? scanJson(props.codeText) : false,
|
|
605
|
+
[usedCodeLanguage, formatJson, streaming, scanJson, props.codeText]
|
|
606
|
+
);
|
|
496
607
|
const normalCodeBlockContent = useMemo2(() => {
|
|
497
608
|
if (isSpecialCodeBlock) return null;
|
|
498
609
|
let usedCodeStr = props.codeText;
|
|
499
|
-
if (usedCodeStr && usedCodeLanguage === "json" && (!streaming ||
|
|
500
|
-
usedCodeStr = prettyPrintJson(usedCodeStr);
|
|
610
|
+
if (formatJson && usedCodeStr && usedCodeLanguage === "json" && (!streaming || jsonComplete)) {
|
|
611
|
+
usedCodeStr = prettyPrintJson(usedCodeStr, expandNestedJson);
|
|
501
612
|
}
|
|
502
613
|
return usedFileName === "unknown" ? /* @__PURE__ */ jsx4(
|
|
503
614
|
CodeHighlight,
|
|
@@ -509,7 +620,9 @@ var MantineAIMPreCode = memo3(
|
|
|
509
620
|
withBorder: true,
|
|
510
621
|
withExpandButton: true,
|
|
511
622
|
defaultExpanded,
|
|
512
|
-
maxCollapsedHeight: "320px"
|
|
623
|
+
maxCollapsedHeight: "320px",
|
|
624
|
+
withCopyButton: false,
|
|
625
|
+
controls: [/* @__PURE__ */ jsx4(RawCodeCopy, { code: props.codeText }, "copy")]
|
|
513
626
|
}
|
|
514
627
|
) : /* @__PURE__ */ jsx4(
|
|
515
628
|
CodeHighlightTabs2,
|
|
@@ -527,10 +640,23 @@ var MantineAIMPreCode = memo3(
|
|
|
527
640
|
withBorder: true,
|
|
528
641
|
withExpandButton: true,
|
|
529
642
|
defaultExpanded,
|
|
530
|
-
maxCollapsedHeight: "320px"
|
|
643
|
+
maxCollapsedHeight: "320px",
|
|
644
|
+
withCopyButton: false,
|
|
645
|
+
controls: [/* @__PURE__ */ jsx4(RawCodeCopy, { code: props.codeText }, "copy")]
|
|
531
646
|
}
|
|
532
647
|
);
|
|
533
|
-
}, [
|
|
648
|
+
}, [
|
|
649
|
+
isSpecialCodeBlock,
|
|
650
|
+
props.codeText,
|
|
651
|
+
usedCodeLanguage,
|
|
652
|
+
usedFileName,
|
|
653
|
+
fontSize,
|
|
654
|
+
defaultExpanded,
|
|
655
|
+
streaming,
|
|
656
|
+
formatJson,
|
|
657
|
+
expandNestedJson,
|
|
658
|
+
jsonComplete
|
|
659
|
+
]);
|
|
534
660
|
const specialCodeBlockContent = useMemo2(() => {
|
|
535
661
|
switch (codeLanguage) {
|
|
536
662
|
case "mermaid" /* Mermaid */:
|
|
@@ -555,13 +681,14 @@ var MANTINE_STABILITY_TABLE = {
|
|
|
555
681
|
var DefaultCustomComponents = {
|
|
556
682
|
pre: ({ node, ...usefulProps }) => {
|
|
557
683
|
const code = node?.children[0];
|
|
558
|
-
if (!code || code.type !== "element" || code.tagName !== "code" || !code.position) {
|
|
684
|
+
if (!code || code.type !== "element" || code.tagName !== "code" || !code.position || node?.children.length !== 1 || code.children.some((child) => !("value" in child) || typeof child.value !== "string") || Object.keys(code.properties ?? {}).some((key2) => key2 !== "className") || Object.keys(node.properties ?? {}).length > 0) {
|
|
559
685
|
return /* @__PURE__ */ jsx5("pre", { ...usefulProps });
|
|
560
686
|
}
|
|
561
687
|
const key = `pre-code-${node?.position?.start?.offset || 0}`;
|
|
562
688
|
const classNames = code.properties?.className;
|
|
563
689
|
const classList = Array.isArray(classNames) ? classNames.filter((c) => typeof c === "string") : typeof classNames === "string" ? classNames.split(/\s+/) : [];
|
|
564
690
|
const detectedLanguage = classList.find((className) => className.startsWith("language-"))?.substring("language-".length);
|
|
691
|
+
if (classList.some((className) => !className.startsWith("language-"))) return /* @__PURE__ */ jsx5("pre", { ...usefulProps });
|
|
565
692
|
const codeText = code.children.map((child) => child.value ?? "").join("");
|
|
566
693
|
return /* @__PURE__ */ jsx5(PreCode_default, { codeText, existLanguage: detectedLanguage }, key);
|
|
567
694
|
}
|