@ai-matrx/rich-content 0.2.6 → 0.2.8
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/CHANGELOG.md +21 -0
- package/dist/code-block/CodeBlock.js +1 -1
- package/dist/display/blocks/chart/ChartBlock.js +1 -1
- package/dist/display/blocks/csv/CsvBlock.js +1 -1
- package/dist/display/blocks/diff/DiffBlock.js +1 -1
- package/dist/display/blocks/generic/StructuredValueTabs.js +1 -1
- package/dist/display/blocks/json/JsonBlock.js +1 -1
- package/dist/display/blocks/markdown-preview/MarkdownPreviewBlock.js +1 -1
- package/dist/display/blocks/svg/SvgBlock.js +1 -1
- package/dist/display/blocks/table/StreamingTableRenderer.js +2 -2
- package/dist/display/blocks/toml/TomlBlock.js +1 -1
- package/dist/display/blocks/tree/TreeBlock.js +1 -1
- package/dist/display/blocks/xml/XmlBlock.js +1 -1
- package/dist/display/blocks/yaml/YamlBlock.js +1 -1
- package/dist/display/chat-markdown/InlineCodeSnippet.js +1 -1
- package/dist/display/chat-markdown/internal-handlers/PlainTextFallback.js +2 -2
- package/dist/display/tables/MarkdownTable.js +2 -2
- package/dist/display/tables/TableWithSeparatedControls.js +2 -2
- package/dist/mermaid/print-render.js +11 -11
- package/package.json +24 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.8
|
|
4
|
+
### Unreleased
|
|
5
|
+
|
|
6
|
+
### Shared fence parsing
|
|
7
|
+
|
|
8
|
+
- The plain-text fallback and Mermaid print reader use Content IR's canonical
|
|
9
|
+
fence rules instead of private regex copies.
|
|
10
|
+
- Mermaid print preserves unfinished bodies and dedenting, ignores malformed
|
|
11
|
+
fence info, and does not render diagrams nested inside another code block.
|
|
12
|
+
|
|
13
|
+
### Consumer action
|
|
14
|
+
|
|
15
|
+
- None required. Public imports and host setup are unchanged.
|
|
16
|
+
|
|
17
|
+
## 0.2.7
|
|
18
|
+
|
|
19
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
20
|
+
`git diff npm/rich-content/v0.2.6..npm/rich-content/v0.2.7 -- apps/shared/rich-content`).
|
|
21
|
+
No source changes intended and no consumer action required.
|
|
22
|
+
|
|
3
23
|
## 0.2.6
|
|
4
24
|
|
|
5
25
|
The Mermaid runtime scheduling test now supplies Mermaid and ELK through the
|
|
@@ -100,3 +120,4 @@ held-back streaming text; the heal tests encode 1.3.1's behavior).
|
|
|
100
120
|
|
|
101
121
|
- matrx-frontend: call `configureRichContent` at the root (see README) and import from
|
|
102
122
|
`@ai-matrx/rich-content/<domain>/<module>`.
|
|
123
|
+
|
|
@@ -38,7 +38,7 @@ const ChartBlock = ({ content = "", isStreamActive = false, className }) => {
|
|
|
38
38
|
const paneLayout = chartPaneLayout(presentation, spec?.type ?? "");
|
|
39
39
|
const handleCopy = async () => {
|
|
40
40
|
try {
|
|
41
|
-
await copyText(source);
|
|
41
|
+
if (!await copyText(source)) return;
|
|
42
42
|
setCopied(true);
|
|
43
43
|
setTimeout(() => setCopied(false), 1500);
|
|
44
44
|
} catch {
|
|
@@ -86,7 +86,7 @@ const CsvBlock = ({
|
|
|
86
86
|
const headers = data[0] || [];
|
|
87
87
|
const bodyRows = data.slice(1);
|
|
88
88
|
const handleCopy = async () => {
|
|
89
|
-
await copyText(content);
|
|
89
|
+
if (!await copyText(content)) return;
|
|
90
90
|
setCopied(true);
|
|
91
91
|
setTimeout(() => setCopied(false), 2e3);
|
|
92
92
|
};
|
|
@@ -85,7 +85,7 @@ const DiffSpecBlock = ({ content = "", isStreamActive = false, className }) => {
|
|
|
85
85
|
});
|
|
86
86
|
const handleCopy = async () => {
|
|
87
87
|
try {
|
|
88
|
-
await copyText(content.trim());
|
|
88
|
+
if (!await copyText(content.trim())) return;
|
|
89
89
|
setCopied(true);
|
|
90
90
|
setTimeout(() => setCopied(false), 1500);
|
|
91
91
|
} catch {
|
|
@@ -47,7 +47,7 @@ function StructuredValueTabs({
|
|
|
47
47
|
const json = value !== void 0 && value !== null ? JSON.stringify(value, null, 2) : raw ?? "";
|
|
48
48
|
const copy = async () => {
|
|
49
49
|
try {
|
|
50
|
-
await copyText(json);
|
|
50
|
+
if (!await copyText(json)) return;
|
|
51
51
|
setCopied(true);
|
|
52
52
|
setTimeout(() => setCopied(false), 1500);
|
|
53
53
|
} catch {
|
|
@@ -489,7 +489,7 @@ const JsonViewHeader = ({
|
|
|
489
489
|
const [copied, setCopied] = useState(false);
|
|
490
490
|
const handleCopy = async () => {
|
|
491
491
|
try {
|
|
492
|
-
await copyText(content);
|
|
492
|
+
if (!await copyText(content)) return;
|
|
493
493
|
setCopied(true);
|
|
494
494
|
toast.success("Copied JSON to clipboard");
|
|
495
495
|
setTimeout(() => setCopied(false), 1500);
|
|
@@ -24,7 +24,7 @@ const MarkdownPreviewBlock = ({
|
|
|
24
24
|
const [mode, setMode] = useState("preview");
|
|
25
25
|
const [copied, setCopied] = useState(false);
|
|
26
26
|
const handleCopy = async () => {
|
|
27
|
-
await copyText(content);
|
|
27
|
+
if (!await copyText(content)) return;
|
|
28
28
|
setCopied(true);
|
|
29
29
|
setTimeout(() => setCopied(false), 2e3);
|
|
30
30
|
};
|
|
@@ -40,7 +40,7 @@ const SvgBlock = ({ content = "", isStreamActive = false, className }) => {
|
|
|
40
40
|
const [fullscreen, setFullscreen] = useState(false);
|
|
41
41
|
const handleCopy = async () => {
|
|
42
42
|
try {
|
|
43
|
-
await copyText(svg);
|
|
43
|
+
if (!await copyText(svg)) return;
|
|
44
44
|
setCopied(true);
|
|
45
45
|
setTimeout(() => setCopied(false), 1500);
|
|
46
46
|
} catch {
|
|
@@ -268,9 +268,9 @@ const StreamingTableRendererCore = ({
|
|
|
268
268
|
};
|
|
269
269
|
const copyJsonToClipboard = async () => {
|
|
270
270
|
try {
|
|
271
|
-
await copyText(
|
|
271
|
+
if (!await copyText(
|
|
272
272
|
JSON.stringify(tableData.normalizedData, null, 2)
|
|
273
|
-
);
|
|
273
|
+
)) return;
|
|
274
274
|
toast.success("JSON copied to clipboard");
|
|
275
275
|
} catch (err) {
|
|
276
276
|
toast.error(err instanceof Error ? err.message : "Failed to copy JSON");
|
|
@@ -75,7 +75,7 @@ const TomlBlock = ({ content, className }) => {
|
|
|
75
75
|
);
|
|
76
76
|
const lines = parseTomlLines(content);
|
|
77
77
|
const handleCopy = async () => {
|
|
78
|
-
await copyText(content);
|
|
78
|
+
if (!await copyText(content)) return;
|
|
79
79
|
setCopied(true);
|
|
80
80
|
setTimeout(() => setCopied(false), 2e3);
|
|
81
81
|
};
|
|
@@ -94,7 +94,7 @@ const TreeBlock = ({ content, className }) => {
|
|
|
94
94
|
const lines = parseTreeLines(content);
|
|
95
95
|
const wrap = treeWrapsLines(useCanvasPresentation());
|
|
96
96
|
const handleCopy = async () => {
|
|
97
|
-
await copyText(content);
|
|
97
|
+
if (!await copyText(content)) return;
|
|
98
98
|
setCopied(true);
|
|
99
99
|
setTimeout(() => setCopied(false), 2e3);
|
|
100
100
|
};
|
|
@@ -38,7 +38,7 @@ const XmlBlock = ({
|
|
|
38
38
|
const tokens = tokenizeXml(content);
|
|
39
39
|
const isStreaming = useMarkdownStreaming();
|
|
40
40
|
const handleCopy = async () => {
|
|
41
|
-
await copyText(content);
|
|
41
|
+
if (!await copyText(content)) return;
|
|
42
42
|
setCopied(true);
|
|
43
43
|
setTimeout(() => setCopied(false), 2e3);
|
|
44
44
|
};
|
|
@@ -81,7 +81,7 @@ const YamlBlock = ({ content, className }) => {
|
|
|
81
81
|
const [collapsed, setCollapsed] = useState(/* @__PURE__ */ new Set());
|
|
82
82
|
const lines = parseYamlLines(content);
|
|
83
83
|
const handleCopy = async () => {
|
|
84
|
-
await copyText(content);
|
|
84
|
+
if (!await copyText(content)) return;
|
|
85
85
|
setCopied(true);
|
|
86
86
|
setTimeout(() => setCopied(false), 2e3);
|
|
87
87
|
};
|
|
@@ -91,7 +91,7 @@ const InlineCodeSnippet = ({
|
|
|
91
91
|
const langColor = language ? LANGUAGE_COLORS[language] : void 0;
|
|
92
92
|
const handleCopy = async () => {
|
|
93
93
|
try {
|
|
94
|
-
await copyText(code);
|
|
94
|
+
if (!await copyText(code)) return;
|
|
95
95
|
setCopied(true);
|
|
96
96
|
setTimeout(() => setCopied(false), 2e3);
|
|
97
97
|
} catch {
|
|
@@ -3,6 +3,7 @@ import { Suspense, lazy } from "react";
|
|
|
3
3
|
import { cn } from "@ai-matrx/design-system";
|
|
4
4
|
import { MarkdownErrorBoundary } from "./MarkdownErrorBoundary.js";
|
|
5
5
|
import { findEmbeddedKindJsonRegions } from "@ai-matrx/content-ir/surfaces";
|
|
6
|
+
import { fenceOpenerOf } from "@ai-matrx/content-ir/source";
|
|
6
7
|
import {
|
|
7
8
|
firstKindSlug,
|
|
8
9
|
hasKindKey,
|
|
@@ -15,12 +16,11 @@ import { humanizeKind } from "@ai-matrx/content-ir/surfaces";
|
|
|
15
16
|
const KindInstanceRender = lazy(
|
|
16
17
|
() => import("../../../host/app-bindings.js").then((m) => ({ default: m.KindInstanceRender }))
|
|
17
18
|
);
|
|
18
|
-
const FENCE_LINE = /^[ \t]*(`{3,}|~{3,})[^\n`]*$/gm;
|
|
19
19
|
function isKindObject(value) {
|
|
20
20
|
return typeof value === "object" && value !== null && !Array.isArray(value) && typeof value.__kind === "string";
|
|
21
21
|
}
|
|
22
22
|
function textPieces(text) {
|
|
23
|
-
const cleaned = text.
|
|
23
|
+
const cleaned = text.split("\n").map((line) => fenceOpenerOf(line) ? "" : line).join("\n");
|
|
24
24
|
if (!hasKindKey(cleaned)) return cleaned.trim() ? [{ type: "text", text: cleaned }] : [];
|
|
25
25
|
const keyAt = cleaned.search(/"__kind"\s*:/);
|
|
26
26
|
const objectAt = cleaned.lastIndexOf("{", keyAt);
|
|
@@ -269,9 +269,9 @@ const MarkdownTable = ({
|
|
|
269
269
|
};
|
|
270
270
|
const copyJsonToClipboard = async () => {
|
|
271
271
|
try {
|
|
272
|
-
await copyText(
|
|
272
|
+
if (!await copyText(
|
|
273
273
|
JSON.stringify(internalTableData.normalizedData, null, 2)
|
|
274
|
-
);
|
|
274
|
+
)) return;
|
|
275
275
|
toast.success("JSON copied to clipboard");
|
|
276
276
|
} catch (err) {
|
|
277
277
|
toast.error(err instanceof Error ? err.message : "Failed to copy JSON");
|
|
@@ -86,9 +86,9 @@ const TableControls = ({
|
|
|
86
86
|
}, [generateMarkdownTable, toast]);
|
|
87
87
|
const copyJsonToClipboard = useCallback(async () => {
|
|
88
88
|
try {
|
|
89
|
-
await copyText(
|
|
89
|
+
if (!await copyText(
|
|
90
90
|
JSON.stringify(debouncedTableData.normalizedData, null, 2)
|
|
91
|
-
);
|
|
91
|
+
)) return;
|
|
92
92
|
toast.success("JSON copied to clipboard");
|
|
93
93
|
} catch (err) {
|
|
94
94
|
toast.error(err instanceof Error ? err.message : "Failed to copy JSON");
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { renderMermaid } from "./runtime.js";
|
|
2
|
+
import { closeFence, fenceOpenerOf } from "@ai-matrx/content-ir/source";
|
|
2
3
|
const PRINT_OPTIONS = { theme: "default", look: "classic", layout: "dagre" };
|
|
3
4
|
function mermaidFenceSources(markdown) {
|
|
4
5
|
const out = [];
|
|
5
6
|
const lines = markdown.split("\n");
|
|
7
|
+
const fenceLines = { count: lines.length, line: (index) => lines[index] ?? null };
|
|
6
8
|
for (let i = 0; i < lines.length; i++) {
|
|
7
|
-
const
|
|
8
|
-
if (!
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
for (; j < lines.length; j++) {
|
|
14
|
-
const close = /^\s*(`{3,}|~{3,})\s*$/.exec(lines[j]);
|
|
15
|
-
if (close && close[1][0] === marker[0] && close[1].length >= marker.length) break;
|
|
16
|
-
body.push(lines[j]);
|
|
9
|
+
const opener = fenceOpenerOf(lines[i]);
|
|
10
|
+
if (!opener) continue;
|
|
11
|
+
const end = closeFence(fenceLines, i, opener);
|
|
12
|
+
if (opener.lang !== "mermaid") {
|
|
13
|
+
i = end.line;
|
|
14
|
+
continue;
|
|
17
15
|
}
|
|
16
|
+
const indent = lines[i].length - lines[i].trimStart().length;
|
|
17
|
+
const body = lines.slice(i + 1, end.closed ? end.line : end.line + 1);
|
|
18
18
|
out.push(body.map((l) => l.slice(Math.min(indent, l.length - l.trimStart().length))).join("\n"));
|
|
19
|
-
i =
|
|
19
|
+
i = end.line;
|
|
20
20
|
}
|
|
21
21
|
return out;
|
|
22
22
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-matrx/rich-content",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"description": "The AI Matrx formatted-text engine: the one markdown renderer, streaming markdown, the block splitter and renderer, the generic blocks, <RichContent> levels, the rich-document action registry and menus, copy, and the selection toolbar — as portable React.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,39 +25,48 @@
|
|
|
25
25
|
"exports": {
|
|
26
26
|
"./host": {
|
|
27
27
|
"types": "./dist/host/index.d.ts",
|
|
28
|
-
"import": "./dist/host/index.js"
|
|
28
|
+
"import": "./dist/host/index.js",
|
|
29
|
+
"default": "./dist/host/index.js"
|
|
29
30
|
},
|
|
30
31
|
"./host/*": {
|
|
31
32
|
"types": "./dist/host/*.d.ts",
|
|
32
|
-
"import": "./dist/host/*.js"
|
|
33
|
+
"import": "./dist/host/*.js",
|
|
34
|
+
"default": "./dist/host/*.js"
|
|
33
35
|
},
|
|
34
36
|
"./markdown-core/*": {
|
|
35
37
|
"types": "./dist/markdown-core/*.d.ts",
|
|
36
|
-
"import": "./dist/markdown-core/*.js"
|
|
38
|
+
"import": "./dist/markdown-core/*.js",
|
|
39
|
+
"default": "./dist/markdown-core/*.js"
|
|
37
40
|
},
|
|
38
41
|
"./display/*": {
|
|
39
42
|
"types": "./dist/display/*.d.ts",
|
|
40
|
-
"import": "./dist/display/*.js"
|
|
43
|
+
"import": "./dist/display/*.js",
|
|
44
|
+
"default": "./dist/display/*.js"
|
|
41
45
|
},
|
|
42
46
|
"./levels/*": {
|
|
43
47
|
"types": "./dist/levels/*.d.ts",
|
|
44
|
-
"import": "./dist/levels/*.js"
|
|
48
|
+
"import": "./dist/levels/*.js",
|
|
49
|
+
"default": "./dist/levels/*.js"
|
|
45
50
|
},
|
|
46
51
|
"./code-block/*": {
|
|
47
52
|
"types": "./dist/code-block/*.d.ts",
|
|
48
|
-
"import": "./dist/code-block/*.js"
|
|
53
|
+
"import": "./dist/code-block/*.js",
|
|
54
|
+
"default": "./dist/code-block/*.js"
|
|
49
55
|
},
|
|
50
56
|
"./mermaid/*": {
|
|
51
57
|
"types": "./dist/mermaid/*.d.ts",
|
|
52
|
-
"import": "./dist/mermaid/*.js"
|
|
58
|
+
"import": "./dist/mermaid/*.js",
|
|
59
|
+
"default": "./dist/mermaid/*.js"
|
|
53
60
|
},
|
|
54
61
|
"./kinds/*": {
|
|
55
62
|
"types": "./dist/kinds/*.d.ts",
|
|
56
|
-
"import": "./dist/kinds/*.js"
|
|
63
|
+
"import": "./dist/kinds/*.js",
|
|
64
|
+
"default": "./dist/kinds/*.js"
|
|
57
65
|
},
|
|
58
66
|
"./utils/*": {
|
|
59
67
|
"types": "./dist/utils/*.d.ts",
|
|
60
|
-
"import": "./dist/utils/*.js"
|
|
68
|
+
"import": "./dist/utils/*.js",
|
|
69
|
+
"default": "./dist/utils/*.js"
|
|
61
70
|
},
|
|
62
71
|
"./styles.css": "./dist/styles.css",
|
|
63
72
|
"./package.json": "./package.json"
|
|
@@ -107,19 +116,19 @@
|
|
|
107
116
|
"unist-util-visit": "^5.1.0",
|
|
108
117
|
"unist-util-visit-parents": "^6.0.2",
|
|
109
118
|
"yaml": "^2.9.1",
|
|
110
|
-
"@ai-matrx/agents": "latest",
|
|
111
119
|
"@ai-matrx/canvas": "latest",
|
|
120
|
+
"@ai-matrx/data": "latest",
|
|
112
121
|
"@ai-matrx/content-ir": "latest",
|
|
113
122
|
"@ai-matrx/content-ir-react": "latest",
|
|
114
|
-
"@ai-matrx/data": "latest",
|
|
115
123
|
"@ai-matrx/design-system": "latest",
|
|
124
|
+
"@ai-matrx/agents": "latest",
|
|
116
125
|
"@ai-matrx/diff": "latest",
|
|
126
|
+
"@ai-matrx/icons": "latest",
|
|
127
|
+
"@ai-matrx/kit": "latest",
|
|
117
128
|
"@ai-matrx/media": "latest",
|
|
118
129
|
"@ai-matrx/print": "latest",
|
|
119
|
-
"@ai-matrx/icons": "latest",
|
|
120
130
|
"@ai-matrx/records": "latest",
|
|
121
|
-
"@ai-matrx/tap-target": "latest"
|
|
122
|
-
"@ai-matrx/kit": "latest"
|
|
131
|
+
"@ai-matrx/tap-target": "latest"
|
|
123
132
|
},
|
|
124
133
|
"peerDependencies": {
|
|
125
134
|
"react": ">=19.0.0",
|