@ai-react-markdown/mantine 2.11.0 → 2.13.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 +17 -12
- package/dist/index.cjs +323 -117
- package/dist/index.cjs.map +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +311 -99
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -69,7 +69,7 @@ yarn add @ai-react-markdown/mantine @ai-react-markdown/core
|
|
|
69
69
|
{
|
|
70
70
|
"react": ">=19",
|
|
71
71
|
"react-dom": ">=19",
|
|
72
|
-
"@ai-react-markdown/core": "^2.
|
|
72
|
+
"@ai-react-markdown/core": "^2.13.0",
|
|
73
73
|
"@mantine/core": "^9.0.0",
|
|
74
74
|
"@mantine/code-highlight": "^9.0.0",
|
|
75
75
|
"highlight.js": "^11.11.2"
|
|
@@ -150,10 +150,13 @@ The Mantine package adds one behavior group on top of core's flat props: the `co
|
|
|
150
150
|
|
|
151
151
|
### `codeBlock` (`Partial<MantineCodeBlockOptions>`)
|
|
152
152
|
|
|
153
|
-
| Field | Type | Default | Description
|
|
154
|
-
| --------------------------- | --------- | ------- |
|
|
155
|
-
| `defaultExpanded` | `boolean` | `true` | Whether code blocks start in their expanded state. When `false`, long blocks are collapsed with an expand button.
|
|
156
|
-
| `autoDetectUnknownLanguage` | `boolean` | `false` | When `true`, uses `highlight.js`'s `highlightAuto` to determine the language of code blocks lacking an explicit annotation.
|
|
153
|
+
| Field | Type | Default | Description |
|
|
154
|
+
| --------------------------- | --------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
155
|
+
| `defaultExpanded` | `boolean` | `true` | Whether code blocks start in their expanded state. When `false`, long blocks are collapsed with an expand button. |
|
|
156
|
+
| `autoDetectUnknownLanguage` | `boolean` | `false` | When `true`, uses `highlight.js`'s `highlightAuto` to determine the language of code blocks lacking an explicit annotation. |
|
|
157
|
+
| `formatJson` | `boolean` | `true` | Format JSON while preserving number tokens, key order and duplicate keys. Set `false` to display source text. |
|
|
158
|
+
| `expandNestedJson` | `boolean` | `true` | When JSON formatting is enabled, expand string values containing JSON objects or arrays. Set `false` for whitespace formatting only. |
|
|
159
|
+
| `highlightIntervalMs` | `number` | `50` | Coalesce streaming code display updates over this interval in milliseconds; `0` updates every frame. Completion and replacement update immediately; copy always uses latest source. |
|
|
157
160
|
|
|
158
161
|
### Example: Collapsed Code Blocks
|
|
159
162
|
|
|
@@ -237,13 +240,15 @@ Activated by importing `@ai-react-markdown/mantine/styles.css` in your app entry
|
|
|
237
240
|
|
|
238
241
|
The Mantine package installs a default `<pre>` renderer (`MantineAIMPreCode`) that powers all code-block features. Behavior by code-block flavor:
|
|
239
242
|
|
|
240
|
-
| Code-block flavor | Rendered as | Notes
|
|
241
|
-
| ------------------------------------------ | --------------------------- |
|
|
242
|
-
| Annotated, known language (e.g. ` ```ts `) | `<CodeHighlightTabs>` | Tab label = language name (lower-cased)
|
|
243
|
-
| Annotated, unknown language identifier | `<CodeHighlightTabs>` | Tab label = the identifier (lower-cased); Mantine's highlight adapter degrades an unknown language to plaintext
|
|
244
|
-
| No language annotation | `<CodeHighlight>` plaintext | Label = `"unknown"`. With `codeBlock.autoDetectUnknownLanguage: true`, `hljs.highlightAuto` guesses early, re-checks as the block grows, and settles at end of stream — label/highlighting upgrade in place
|
|
245
|
-
| ` ```mermaid ` (any case) | Interactive Mermaid diagram | See [Mermaid Diagrams](#mermaid-diagrams); the language match is case-insensitive
|
|
246
|
-
| ` ```json ` (any case) | Pretty-printed JSON | As soon as the block looks complete (ends in `}`/`]` with balanced brackets outside strings), parsed, string values holding a nested JSON object/array expanded (primitive-looking strings such as `"true"` stay strings), then
|
|
243
|
+
| Code-block flavor | Rendered as | Notes |
|
|
244
|
+
| ------------------------------------------ | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
245
|
+
| Annotated, known language (e.g. ` ```ts `) | `<CodeHighlightTabs>` | Tab label = language name (lower-cased) |
|
|
246
|
+
| Annotated, unknown language identifier | `<CodeHighlightTabs>` | Tab label = the identifier (lower-cased); Mantine's highlight adapter degrades an unknown language to plaintext |
|
|
247
|
+
| No language annotation | `<CodeHighlight>` plaintext | Label = `"unknown"`. With `codeBlock.autoDetectUnknownLanguage: true`, `hljs.highlightAuto` guesses early, re-checks as the block grows, and settles at end of stream — label/highlighting upgrade in place |
|
|
248
|
+
| ` ```mermaid ` (any case) | Interactive Mermaid diagram | See [Mermaid Diagrams](#mermaid-diagrams); the language match is case-insensitive |
|
|
249
|
+
| ` ```json ` (any case) | Pretty-printed JSON | As soon as the block looks complete (ends in `}`/`]` with balanced brackets outside strings), parsed, string values holding a nested JSON object/array expanded (primitive-looking strings such as `"true"` stay strings), then formatted with 2-space indent while retaining exact numeric tokens; both formatting and nested expansion can be disabled |
|
|
250
|
+
|
|
251
|
+
The copy control copies the original code text, including its trailing newline, independently of JSON display formatting. Raw HTML `<pre>` structures with nested elements, sibling text, or additional attributes retain their original rendering instead of entering the code highlighter.
|
|
247
252
|
|
|
248
253
|
All non-special blocks render with `withBorder` and `withExpandButton`, collapsing to `maxCollapsedHeight="320px"` until expanded.
|
|
249
254
|
|
package/dist/index.cjs
CHANGED
|
@@ -42,9 +42,9 @@ __export(index_exports, {
|
|
|
42
42
|
module.exports = __toCommonJS(index_exports);
|
|
43
43
|
|
|
44
44
|
// src/MantineAIMarkdown.tsx
|
|
45
|
-
var
|
|
46
|
-
var
|
|
47
|
-
var
|
|
45
|
+
var import_react6 = require("react");
|
|
46
|
+
var import_core7 = __toESM(require("@ai-react-markdown/core"), 1);
|
|
47
|
+
var import_core8 = require("@ai-react-markdown/core");
|
|
48
48
|
|
|
49
49
|
// src/components/typography/MantineTypography.tsx
|
|
50
50
|
var import_react = require("react");
|
|
@@ -62,7 +62,7 @@ var MantineAIMDefaultExtraStyles = ({ children }) => {
|
|
|
62
62
|
var DefaultExtraStyles_default = MantineAIMDefaultExtraStyles;
|
|
63
63
|
|
|
64
64
|
// src/components/customized/PreCode.tsx
|
|
65
|
-
var
|
|
65
|
+
var import_react5 = require("react");
|
|
66
66
|
var import_code_highlight2 = require("@mantine/code-highlight");
|
|
67
67
|
var import_core5 = require("@ai-react-markdown/core");
|
|
68
68
|
|
|
@@ -73,7 +73,10 @@ var import_core2 = require("@ai-react-markdown/core");
|
|
|
73
73
|
// src/defs.tsx
|
|
74
74
|
var defaultMantineCodeBlockOptions = Object.freeze({
|
|
75
75
|
defaultExpanded: true,
|
|
76
|
-
autoDetectUnknownLanguage: false
|
|
76
|
+
autoDetectUnknownLanguage: false,
|
|
77
|
+
formatJson: true,
|
|
78
|
+
expandNestedJson: true,
|
|
79
|
+
highlightIntervalMs: 50
|
|
77
80
|
});
|
|
78
81
|
|
|
79
82
|
// src/hooks/useMantineCodeBlockOptions.ts
|
|
@@ -86,10 +89,50 @@ function useMantineCodeBlockOptions() {
|
|
|
86
89
|
const value = group?.[key];
|
|
87
90
|
if (value !== void 0) resolved[key] = value;
|
|
88
91
|
}
|
|
92
|
+
if (!Number.isFinite(resolved.highlightIntervalMs) || resolved.highlightIntervalMs < 0) {
|
|
93
|
+
resolved.highlightIntervalMs = defaultMantineCodeBlockOptions.highlightIntervalMs;
|
|
94
|
+
}
|
|
89
95
|
return resolved;
|
|
90
96
|
}, [group]);
|
|
91
97
|
}
|
|
92
98
|
|
|
99
|
+
// src/components/customized/MermaidCode/renderQueue.ts
|
|
100
|
+
function createRenderQueue() {
|
|
101
|
+
const pending = /* @__PURE__ */ new Map();
|
|
102
|
+
let running = false;
|
|
103
|
+
async function drain() {
|
|
104
|
+
if (running) return;
|
|
105
|
+
running = true;
|
|
106
|
+
try {
|
|
107
|
+
while (pending.size) {
|
|
108
|
+
const [owner, job] = pending.entries().next().value;
|
|
109
|
+
pending.delete(owner);
|
|
110
|
+
try {
|
|
111
|
+
await job.run();
|
|
112
|
+
job.resolve();
|
|
113
|
+
} catch (error) {
|
|
114
|
+
job.reject(error);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} finally {
|
|
118
|
+
running = false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
enqueue(owner, run) {
|
|
123
|
+
pending.get(owner)?.resolve();
|
|
124
|
+
const promise = new Promise((resolve, reject) => pending.set(owner, { run, resolve, reject }));
|
|
125
|
+
void drain();
|
|
126
|
+
return promise;
|
|
127
|
+
},
|
|
128
|
+
cancel(owner) {
|
|
129
|
+
pending.get(owner)?.resolve();
|
|
130
|
+
pending.delete(owner);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
var mermaidRenderQueue = createRenderQueue();
|
|
135
|
+
|
|
93
136
|
// src/components/customized/MermaidCode/index.tsx
|
|
94
137
|
var import_react3 = require("react");
|
|
95
138
|
var import_code_highlight = require("@mantine/code-highlight");
|
|
@@ -211,14 +254,7 @@ var MantineAIMMermaidCode = (0, import_react3.memo)((props) => {
|
|
|
211
254
|
if (!ref.current || cancelled || renderVersion !== renderVersionRef.current) {
|
|
212
255
|
return;
|
|
213
256
|
}
|
|
214
|
-
|
|
215
|
-
if (initializedTheme !== (isDark ? "dark" : "light")) {
|
|
216
|
-
if (!ref.current || cancelled || renderVersion !== renderVersionRef.current) {
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
ensureMermaidInitialized(mermaid, isDark);
|
|
220
|
-
rendered = await mermaid.render(generateMermaidUUID(), props.code);
|
|
221
|
-
}
|
|
257
|
+
const rendered = await mermaid.render(generateMermaidUUID(), props.code);
|
|
222
258
|
const { svg, bindFunctions, diagramType } = rendered;
|
|
223
259
|
if (!ref.current || cancelled || renderVersion !== renderVersionRef.current) {
|
|
224
260
|
return;
|
|
@@ -246,9 +282,11 @@ var MantineAIMMermaidCode = (0, import_react3.memo)((props) => {
|
|
|
246
282
|
applyView({ kind: "error" });
|
|
247
283
|
}
|
|
248
284
|
};
|
|
249
|
-
|
|
285
|
+
const owner = renderVersionRef;
|
|
286
|
+
void mermaidRenderQueue.enqueue(owner, renderMermaid);
|
|
250
287
|
return () => {
|
|
251
288
|
cancelled = true;
|
|
289
|
+
mermaidRenderQueue.cancel(owner);
|
|
252
290
|
if (retryTimer !== void 0) clearTimeout(retryTimer);
|
|
253
291
|
};
|
|
254
292
|
}, [props.code, isDark, showOriginalCode, streaming, loadAttempt]);
|
|
@@ -398,6 +436,140 @@ var MantineAIMMermaidCode = (0, import_react3.memo)((props) => {
|
|
|
398
436
|
MantineAIMMermaidCode.displayName = "MantineAIMMermaidCode";
|
|
399
437
|
var MermaidCode_default = MantineAIMMermaidCode;
|
|
400
438
|
|
|
439
|
+
// src/components/customized/PreCode.tsx
|
|
440
|
+
var import_core6 = require("@mantine/core");
|
|
441
|
+
|
|
442
|
+
// src/components/customized/formatJson.ts
|
|
443
|
+
function prettyPrintJson(text, expandNested = true) {
|
|
444
|
+
try {
|
|
445
|
+
return format(text, expandNested, 0);
|
|
446
|
+
} catch {
|
|
447
|
+
return text;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
function format(text, expandNested, baseIndent) {
|
|
451
|
+
JSON.parse(text);
|
|
452
|
+
const tokens = text.match(/"(?:\\[\s\S]|[^"\\])*"|-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?|true|false|null|[{}[\],:]/g) ?? [];
|
|
453
|
+
const out = [];
|
|
454
|
+
let indent = baseIndent;
|
|
455
|
+
const newline = () => out.push("\n", " ".repeat(indent));
|
|
456
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
457
|
+
const token = tokens[i];
|
|
458
|
+
if (token === "{" || token === "[") {
|
|
459
|
+
out.push(token);
|
|
460
|
+
if (tokens[i + 1] !== (token === "{" ? "}" : "]")) {
|
|
461
|
+
indent++;
|
|
462
|
+
newline();
|
|
463
|
+
}
|
|
464
|
+
} else if (token === "}" || token === "]") {
|
|
465
|
+
if (tokens[i - 1] !== (token === "}" ? "{" : "[")) {
|
|
466
|
+
indent--;
|
|
467
|
+
newline();
|
|
468
|
+
}
|
|
469
|
+
out.push(token);
|
|
470
|
+
} else if (token === ",") {
|
|
471
|
+
out.push(",");
|
|
472
|
+
newline();
|
|
473
|
+
} else if (token === ":") {
|
|
474
|
+
out.push(": ");
|
|
475
|
+
} else if (token.startsWith('"')) {
|
|
476
|
+
const value = JSON.parse(token);
|
|
477
|
+
const trimmed = value.trim();
|
|
478
|
+
if (expandNested && tokens[i + 1] !== ":" && /^[{[]/.test(trimmed) && indent < 100) {
|
|
479
|
+
try {
|
|
480
|
+
out.push(format(trimmed, true, indent));
|
|
481
|
+
continue;
|
|
482
|
+
} catch {
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
out.push(JSON.stringify(value));
|
|
486
|
+
} else {
|
|
487
|
+
out.push(token);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
return out.join("");
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// src/components/customized/jsonCompleteness.ts
|
|
494
|
+
function createJsonCompletenessScanner() {
|
|
495
|
+
let previous = "";
|
|
496
|
+
let depth = 0;
|
|
497
|
+
let quoted = false;
|
|
498
|
+
let escaped = false;
|
|
499
|
+
let invalid = false;
|
|
500
|
+
let last = "";
|
|
501
|
+
return (text) => {
|
|
502
|
+
let from = previous.length;
|
|
503
|
+
if (!text.startsWith(previous)) {
|
|
504
|
+
from = 0;
|
|
505
|
+
depth = 0;
|
|
506
|
+
quoted = escaped = invalid = false;
|
|
507
|
+
last = "";
|
|
508
|
+
}
|
|
509
|
+
previous = text;
|
|
510
|
+
for (let i = from; i < text.length; i++) {
|
|
511
|
+
const c = text[i];
|
|
512
|
+
if (!/\s/.test(c)) last = c;
|
|
513
|
+
if (quoted) {
|
|
514
|
+
if (escaped) escaped = false;
|
|
515
|
+
else if (c === "\\") escaped = true;
|
|
516
|
+
else if (c === '"') quoted = false;
|
|
517
|
+
} else if (c === '"') quoted = true;
|
|
518
|
+
else if (c === "{" || c === "[") depth++;
|
|
519
|
+
else if (c === "}" || c === "]") {
|
|
520
|
+
depth--;
|
|
521
|
+
if (depth < 0) invalid = true;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return !invalid && !quoted && depth === 0 && (last === "}" || last === "]");
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// src/components/customized/useCodeFrame.ts
|
|
529
|
+
var import_react4 = require("react");
|
|
530
|
+
|
|
531
|
+
// src/components/customized/codeFrame.ts
|
|
532
|
+
function createCodeFrame(initial, publish) {
|
|
533
|
+
let shown = initial;
|
|
534
|
+
let latest = initial;
|
|
535
|
+
let delay = 0;
|
|
536
|
+
let timer;
|
|
537
|
+
const cancel = () => {
|
|
538
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
539
|
+
timer = void 0;
|
|
540
|
+
};
|
|
541
|
+
const flush = () => {
|
|
542
|
+
cancel();
|
|
543
|
+
if (shown.code === latest.code && shown.language === latest.language) return;
|
|
544
|
+
shown = latest;
|
|
545
|
+
publish(shown);
|
|
546
|
+
};
|
|
547
|
+
return {
|
|
548
|
+
update(next, streaming, interval) {
|
|
549
|
+
const replaced = next.language !== latest.language || !next.code.startsWith(latest.code);
|
|
550
|
+
latest = next;
|
|
551
|
+
if (delay !== interval) cancel();
|
|
552
|
+
delay = interval;
|
|
553
|
+
if (!streaming || interval === 0 || replaced) return flush();
|
|
554
|
+
if (shown.code === next.code && shown.language === next.language) return cancel();
|
|
555
|
+
timer ??= setTimeout(flush, interval);
|
|
556
|
+
},
|
|
557
|
+
// Cancellation is reversible: Strict Mode replays the update effect.
|
|
558
|
+
dispose: cancel
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// src/components/customized/useCodeFrame.ts
|
|
563
|
+
function useCodeFrame(code, language, streaming, interval) {
|
|
564
|
+
const [frame, setFrame] = (0, import_react4.useState)(() => ({ code, language }));
|
|
565
|
+
const [controller] = (0, import_react4.useState)(() => createCodeFrame({ code, language }, setFrame));
|
|
566
|
+
(0, import_react4.useEffect)(() => {
|
|
567
|
+
controller.update({ code, language }, streaming, interval);
|
|
568
|
+
}, [controller, code, language, streaming, interval]);
|
|
569
|
+
(0, import_react4.useEffect)(() => () => controller.dispose(), [controller]);
|
|
570
|
+
return !streaming || interval === 0 || language !== frame.language || !code.startsWith(frame.code) ? code : frame.code;
|
|
571
|
+
}
|
|
572
|
+
|
|
401
573
|
// src/components/customized/PreCode.tsx
|
|
402
574
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
403
575
|
var hljsAutoPromise = null;
|
|
@@ -415,14 +587,20 @@ var AUTODETECT_MIN_CHARS = 32;
|
|
|
415
587
|
var HLJS_LOAD_RETRIES = 3;
|
|
416
588
|
var HLJS_LOAD_RETRY_MS = 1500;
|
|
417
589
|
function useAutoDetectedLanguage(codeText, enabled, streaming) {
|
|
418
|
-
const [detected, setDetected] = (0,
|
|
590
|
+
const [detected, setDetected] = (0, import_react5.useState)(
|
|
419
591
|
null
|
|
420
592
|
);
|
|
421
|
-
const [loadAttempt, setLoadAttempt] = (0,
|
|
422
|
-
const loadFailuresRef = (0,
|
|
423
|
-
(0,
|
|
424
|
-
|
|
425
|
-
const
|
|
593
|
+
const [loadAttempt, setLoadAttempt] = (0, import_react5.useState)(0);
|
|
594
|
+
const loadFailuresRef = (0, import_react5.useRef)(0);
|
|
595
|
+
const previousTextRef = (0, import_react5.useRef)(codeText);
|
|
596
|
+
(0, import_react5.useEffect)(() => {
|
|
597
|
+
const appended = codeText.startsWith(previousTextRef.current);
|
|
598
|
+
previousTextRef.current = codeText;
|
|
599
|
+
if (!enabled) {
|
|
600
|
+
if (detected) setDetected(null);
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
const prior = !appended || detected !== null && codeText.length < detected.atLength ? null : detected;
|
|
426
604
|
if (prior !== detected) setDetected(null);
|
|
427
605
|
if (codeText.length < AUTODETECT_MIN_CHARS) return;
|
|
428
606
|
const due = prior === null || // Not streaming: the verdict must be for THIS text (end-of-stream, or a
|
|
@@ -461,115 +639,133 @@ function preloadMantineCodeAssets() {
|
|
|
461
639
|
() => void 0
|
|
462
640
|
);
|
|
463
641
|
}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
642
|
+
var RawCodeContext = (0, import_react5.createContext)("");
|
|
643
|
+
function RawCodeCopy() {
|
|
644
|
+
const code = (0, import_react5.useContext)(RawCodeContext);
|
|
645
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core6.CopyButton, { value: code, children: ({ copied, copy }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
646
|
+
import_code_highlight2.CodeHighlightControl,
|
|
647
|
+
{
|
|
648
|
+
tooltipLabel: copied ? "Copied" : "Copy",
|
|
649
|
+
"aria-label": copied ? "Copied" : "Copy code",
|
|
650
|
+
onClick: copy,
|
|
651
|
+
children: copied ? "\u2713" : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
652
|
+
"svg",
|
|
653
|
+
{
|
|
654
|
+
width: "16",
|
|
655
|
+
height: "16",
|
|
656
|
+
viewBox: "0 0 24 24",
|
|
657
|
+
fill: "none",
|
|
658
|
+
stroke: "currentColor",
|
|
659
|
+
strokeWidth: "1.5",
|
|
660
|
+
"aria-hidden": "true",
|
|
661
|
+
children: [
|
|
662
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "8", y: "8", width: "12", height: "12", rx: "2" }),
|
|
663
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M16 8V4H4v12h4" })
|
|
664
|
+
]
|
|
665
|
+
}
|
|
666
|
+
)
|
|
667
|
+
}
|
|
668
|
+
) });
|
|
472
669
|
}
|
|
473
|
-
function
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
670
|
+
function createCachedHighlightAdapter(highlight) {
|
|
671
|
+
let previous;
|
|
672
|
+
let result;
|
|
673
|
+
return {
|
|
674
|
+
getHighlighter: () => (input) => {
|
|
675
|
+
if (!previous || input.code !== previous.code || input.language !== previous.language || input.colorScheme !== previous.colorScheme) {
|
|
676
|
+
result = highlight(input);
|
|
677
|
+
previous = input;
|
|
481
678
|
}
|
|
679
|
+
return result;
|
|
482
680
|
}
|
|
483
|
-
|
|
484
|
-
}
|
|
485
|
-
if (Array.isArray(value)) return value.map(expandNestedJson);
|
|
486
|
-
if (value !== null && typeof value === "object") {
|
|
487
|
-
const out = /* @__PURE__ */ Object.create(null);
|
|
488
|
-
for (const [k, v] of Object.entries(value)) out[k] = expandNestedJson(v);
|
|
489
|
-
return out;
|
|
490
|
-
}
|
|
491
|
-
return value;
|
|
681
|
+
};
|
|
492
682
|
}
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
683
|
+
var OrdinaryCodeHighlight = (0, import_react5.memo)(function OrdinaryCodeHighlight2({
|
|
684
|
+
code,
|
|
685
|
+
language,
|
|
686
|
+
fileName,
|
|
687
|
+
fontSize,
|
|
688
|
+
defaultExpanded
|
|
689
|
+
}) {
|
|
690
|
+
const highlight = (0, import_code_highlight2.useHighlight)();
|
|
691
|
+
const adapter = (0, import_react5.useMemo)(() => createCachedHighlightAdapter(highlight), [highlight]);
|
|
692
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_code_highlight2.CodeHighlightAdapterProvider, { adapter, children: fileName === "unknown" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
693
|
+
import_code_highlight2.CodeHighlight,
|
|
694
|
+
{
|
|
695
|
+
mb: 15,
|
|
696
|
+
fz: fontSize,
|
|
697
|
+
w: "100%",
|
|
698
|
+
code,
|
|
699
|
+
withBorder: true,
|
|
700
|
+
withExpandButton: true,
|
|
701
|
+
defaultExpanded,
|
|
702
|
+
maxCollapsedHeight: "320px",
|
|
703
|
+
withCopyButton: false,
|
|
704
|
+
controls: [/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RawCodeCopy, {}, "copy")]
|
|
509
705
|
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
706
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
707
|
+
import_code_highlight2.CodeHighlightTabs,
|
|
708
|
+
{
|
|
709
|
+
mb: 15,
|
|
710
|
+
fz: fontSize,
|
|
711
|
+
w: "100%",
|
|
712
|
+
code: [
|
|
713
|
+
{
|
|
714
|
+
fileName,
|
|
715
|
+
code,
|
|
716
|
+
language
|
|
717
|
+
}
|
|
718
|
+
],
|
|
719
|
+
withBorder: true,
|
|
720
|
+
withExpandButton: true,
|
|
721
|
+
defaultExpanded,
|
|
722
|
+
maxCollapsedHeight: "320px",
|
|
723
|
+
withCopyButton: false,
|
|
724
|
+
controls: [/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RawCodeCopy, {}, "copy")]
|
|
725
|
+
}
|
|
726
|
+
) });
|
|
727
|
+
});
|
|
513
728
|
var SpecialCodeLanguage = /* @__PURE__ */ ((SpecialCodeLanguage2) => {
|
|
514
729
|
SpecialCodeLanguage2["Mermaid"] = "mermaid";
|
|
515
730
|
return SpecialCodeLanguage2;
|
|
516
731
|
})(SpecialCodeLanguage || {});
|
|
517
732
|
var SPECIAL_LANGUAGES = new Set(Object.values(SpecialCodeLanguage));
|
|
518
|
-
var MantineAIMPreCode = (0,
|
|
733
|
+
var MantineAIMPreCode = (0, import_react5.memo)(
|
|
519
734
|
(props) => {
|
|
520
735
|
const { fontSize } = (0, import_core5.useAIMarkdownTheme)();
|
|
521
736
|
const { streaming } = (0, import_core5.useAIMarkdownState)();
|
|
522
|
-
const { autoDetectUnknownLanguage, defaultExpanded } = useMantineCodeBlockOptions();
|
|
737
|
+
const { autoDetectUnknownLanguage, defaultExpanded, formatJson, expandNestedJson, highlightIntervalMs } = useMantineCodeBlockOptions();
|
|
523
738
|
const detectedLanguage = useAutoDetectedLanguage(
|
|
524
739
|
props.codeText,
|
|
525
740
|
autoDetectUnknownLanguage && !props.existLanguage,
|
|
526
741
|
streaming
|
|
527
742
|
);
|
|
528
743
|
const codeLanguage = (props.existLanguage || detectedLanguage).toLowerCase();
|
|
529
|
-
const [usedCodeLanguage, usedFileName] = (0,
|
|
744
|
+
const [usedCodeLanguage, usedFileName] = (0, import_react5.useMemo)(
|
|
530
745
|
() => codeLanguage ? [codeLanguage, codeLanguage] : ["plaintext", "unknown"],
|
|
531
746
|
[codeLanguage]
|
|
532
747
|
);
|
|
533
748
|
const isSpecialCodeBlock = SPECIAL_LANGUAGES.has(codeLanguage);
|
|
534
|
-
const
|
|
749
|
+
const [scanJson] = (0, import_react5.useState)(createJsonCompletenessScanner);
|
|
750
|
+
const jsonComplete = (0, import_react5.useMemo)(
|
|
751
|
+
() => usedCodeLanguage === "json" && formatJson && streaming ? scanJson(props.codeText) : false,
|
|
752
|
+
[usedCodeLanguage, formatJson, streaming, scanJson, props.codeText]
|
|
753
|
+
);
|
|
754
|
+
const normalCodeBlockContent = (0, import_react5.useMemo)(() => {
|
|
535
755
|
if (isSpecialCodeBlock) return null;
|
|
536
756
|
let usedCodeStr = props.codeText;
|
|
537
|
-
if (usedCodeStr && usedCodeLanguage === "json" && (!streaming ||
|
|
538
|
-
usedCodeStr = prettyPrintJson(usedCodeStr);
|
|
757
|
+
if (formatJson && usedCodeStr && usedCodeLanguage === "json" && (!streaming || jsonComplete)) {
|
|
758
|
+
usedCodeStr = prettyPrintJson(usedCodeStr, expandNestedJson);
|
|
539
759
|
}
|
|
540
|
-
return
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
defaultExpanded,
|
|
550
|
-
maxCollapsedHeight: "320px"
|
|
551
|
-
}
|
|
552
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
553
|
-
import_code_highlight2.CodeHighlightTabs,
|
|
554
|
-
{
|
|
555
|
-
mb: 15,
|
|
556
|
-
fz: fontSize,
|
|
557
|
-
w: "100%",
|
|
558
|
-
code: [
|
|
559
|
-
{
|
|
560
|
-
fileName: usedFileName,
|
|
561
|
-
code: usedCodeStr,
|
|
562
|
-
language: usedCodeLanguage
|
|
563
|
-
}
|
|
564
|
-
],
|
|
565
|
-
withBorder: true,
|
|
566
|
-
withExpandButton: true,
|
|
567
|
-
defaultExpanded,
|
|
568
|
-
maxCollapsedHeight: "320px"
|
|
569
|
-
}
|
|
570
|
-
);
|
|
571
|
-
}, [isSpecialCodeBlock, props.codeText, usedCodeLanguage, usedFileName, fontSize, defaultExpanded, streaming]);
|
|
572
|
-
const specialCodeBlockContent = (0, import_react4.useMemo)(() => {
|
|
760
|
+
return usedCodeStr;
|
|
761
|
+
}, [isSpecialCodeBlock, props.codeText, usedCodeLanguage, streaming, formatJson, expandNestedJson, jsonComplete]);
|
|
762
|
+
const displayedCode = useCodeFrame(
|
|
763
|
+
normalCodeBlockContent ?? "",
|
|
764
|
+
usedCodeLanguage,
|
|
765
|
+
streaming && !isSpecialCodeBlock,
|
|
766
|
+
highlightIntervalMs
|
|
767
|
+
);
|
|
768
|
+
const specialCodeBlockContent = (0, import_react5.useMemo)(() => {
|
|
573
769
|
switch (codeLanguage) {
|
|
574
770
|
case "mermaid" /* Mermaid */:
|
|
575
771
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MermaidCode_default, { code: props.codeText });
|
|
@@ -577,29 +773,39 @@ var MantineAIMPreCode = (0, import_react4.memo)(
|
|
|
577
773
|
return null;
|
|
578
774
|
}
|
|
579
775
|
}, [codeLanguage, props.codeText]);
|
|
580
|
-
return isSpecialCodeBlock ? specialCodeBlockContent :
|
|
776
|
+
return isSpecialCodeBlock ? specialCodeBlockContent : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RawCodeContext.Provider, { value: props.codeText, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
777
|
+
OrdinaryCodeHighlight,
|
|
778
|
+
{
|
|
779
|
+
code: displayedCode,
|
|
780
|
+
language: usedCodeLanguage,
|
|
781
|
+
fileName: usedFileName,
|
|
782
|
+
fontSize,
|
|
783
|
+
defaultExpanded
|
|
784
|
+
}
|
|
785
|
+
) });
|
|
581
786
|
}
|
|
582
787
|
);
|
|
583
788
|
MantineAIMPreCode.displayName = "MantineAIMPreCode";
|
|
584
789
|
var PreCode_default = MantineAIMPreCode;
|
|
585
790
|
|
|
586
791
|
// src/MantineAIMarkdown.tsx
|
|
587
|
-
var
|
|
792
|
+
var import_core9 = require("@mantine/core");
|
|
588
793
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
589
794
|
var NO_GROUPS = Object.freeze({});
|
|
590
795
|
var MANTINE_STABILITY_TABLE = {
|
|
591
|
-
codeBlock:
|
|
796
|
+
codeBlock: import_core8.AIMarkdownStabilityPolicy.DEEP_EQUAL
|
|
592
797
|
};
|
|
593
798
|
var DefaultCustomComponents = {
|
|
594
799
|
pre: ({ node, ...usefulProps }) => {
|
|
595
800
|
const code = node?.children[0];
|
|
596
|
-
if (!code || code.type !== "element" || code.tagName !== "code" || !code.position) {
|
|
801
|
+
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) {
|
|
597
802
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("pre", { ...usefulProps });
|
|
598
803
|
}
|
|
599
804
|
const key = `pre-code-${node?.position?.start?.offset || 0}`;
|
|
600
805
|
const classNames = code.properties?.className;
|
|
601
806
|
const classList = Array.isArray(classNames) ? classNames.filter((c) => typeof c === "string") : typeof classNames === "string" ? classNames.split(/\s+/) : [];
|
|
602
807
|
const detectedLanguage = classList.find((className) => className.startsWith("language-"))?.substring("language-".length);
|
|
808
|
+
if (classList.some((className) => !className.startsWith("language-"))) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("pre", { ...usefulProps });
|
|
603
809
|
const codeText = code.children.map((child) => child.value ?? "").join("");
|
|
604
810
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PreCode_default, { codeText, existLanguage: detectedLanguage }, key);
|
|
605
811
|
}
|
|
@@ -612,18 +818,18 @@ var MantineAIMarkdownComponent = ({
|
|
|
612
818
|
codeBlock,
|
|
613
819
|
...props
|
|
614
820
|
}) => {
|
|
615
|
-
const stableCustomComponents = (0,
|
|
616
|
-
const usedComponents = (0,
|
|
821
|
+
const stableCustomComponents = (0, import_core8.useStableValue)(customComponents);
|
|
822
|
+
const usedComponents = (0, import_react6.useMemo)(() => {
|
|
617
823
|
return stableCustomComponents ? { ...DefaultCustomComponents, ...stableCustomComponents } : DefaultCustomComponents;
|
|
618
824
|
}, [stableCustomComponents]);
|
|
619
|
-
const computedColorScheme = (0,
|
|
620
|
-
const stable = (0,
|
|
621
|
-
const behaviorGroups = (0,
|
|
825
|
+
const computedColorScheme = (0, import_core9.useComputedColorScheme)("light");
|
|
826
|
+
const stable = (0, import_core8.useStableRecord)({ codeBlock }, MANTINE_STABILITY_TABLE);
|
|
827
|
+
const behaviorGroups = (0, import_react6.useMemo)(
|
|
622
828
|
() => stable.codeBlock != null ? { codeBlock: stable.codeBlock } : NO_GROUPS,
|
|
623
829
|
[stable.codeBlock]
|
|
624
830
|
);
|
|
625
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
626
|
-
|
|
831
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_core8.AIMarkdownBehaviorsProvider, { value: behaviorGroups, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
832
|
+
import_core7.default,
|
|
627
833
|
{
|
|
628
834
|
Typography: Typography2,
|
|
629
835
|
ExtraStyles,
|
|
@@ -633,7 +839,7 @@ var MantineAIMarkdownComponent = ({
|
|
|
633
839
|
}
|
|
634
840
|
) });
|
|
635
841
|
};
|
|
636
|
-
var MantineAIMarkdown = (0,
|
|
842
|
+
var MantineAIMarkdown = (0, import_react6.memo)(MantineAIMarkdownComponent);
|
|
637
843
|
MantineAIMarkdown.displayName = "MantineAIMarkdown";
|
|
638
844
|
var MantineAIMarkdown_default = MantineAIMarkdown;
|
|
639
845
|
|
|
@@ -643,9 +849,9 @@ function defineMantineBehaviors(values) {
|
|
|
643
849
|
}
|
|
644
850
|
|
|
645
851
|
// src/hooks/useMantineAIMarkdownMetadata.ts
|
|
646
|
-
var
|
|
852
|
+
var import_core10 = require("@ai-react-markdown/core");
|
|
647
853
|
var useMantineAIMarkdownMetadata = () => {
|
|
648
|
-
return (0,
|
|
854
|
+
return (0, import_core10.useAIMarkdownMetadata)();
|
|
649
855
|
};
|
|
650
856
|
// Annotate the CommonJS export names for ESM import in node:
|
|
651
857
|
0 && (module.exports = {
|