@copilotkit/markdown 0.0.1 → 2.0.0-rc.12

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.
@@ -0,0 +1,300 @@
1
+ import React, { Fragment, useMemo } from "react";
2
+ import { Text, View } from "react-native";
3
+ import { createStreamingMarkdownParserState, finalizeStreamingMarkdown, parseStreamingMarkdownChunk } from "@copilotkit/markdown";
4
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
+
6
+ //#region src/react-native/streaming-markdown-renderer.tsx
7
+ /**
8
+ * Default styles for all built-in node types.
9
+ *
10
+ * @public
11
+ */
12
+ const defaultMarkdownStyles = {
13
+ paragraph: {
14
+ fontSize: 16,
15
+ lineHeight: 24,
16
+ color: "#1a1a1a",
17
+ marginTop: 4,
18
+ marginBottom: 4
19
+ },
20
+ h1: {
21
+ fontSize: 24,
22
+ fontWeight: "bold",
23
+ marginTop: 12,
24
+ marginBottom: 8,
25
+ color: "#111111"
26
+ },
27
+ h2: {
28
+ fontSize: 20,
29
+ fontWeight: "bold",
30
+ marginTop: 10,
31
+ marginBottom: 6,
32
+ color: "#111111"
33
+ },
34
+ h3: {
35
+ fontSize: 18,
36
+ fontWeight: "600",
37
+ marginTop: 8,
38
+ marginBottom: 4,
39
+ color: "#222222"
40
+ },
41
+ h4: {
42
+ fontSize: 16,
43
+ fontWeight: "600",
44
+ marginTop: 6,
45
+ marginBottom: 4,
46
+ color: "#222222"
47
+ },
48
+ h5: {
49
+ fontSize: 14,
50
+ fontWeight: "600",
51
+ marginTop: 4,
52
+ marginBottom: 2,
53
+ color: "#333333"
54
+ },
55
+ h6: {
56
+ fontSize: 13,
57
+ fontWeight: "600",
58
+ marginTop: 4,
59
+ marginBottom: 2,
60
+ color: "#444444"
61
+ },
62
+ strong: { fontWeight: "bold" },
63
+ em: { fontStyle: "italic" },
64
+ strikethrough: { textDecorationLine: "line-through" },
65
+ inlineCode: {
66
+ backgroundColor: "#f0f0f0",
67
+ fontFamily: "monospace",
68
+ fontSize: 14
69
+ },
70
+ codeBlock: {
71
+ backgroundColor: "#f0f0f0",
72
+ borderRadius: 8,
73
+ padding: 12,
74
+ marginVertical: 4
75
+ },
76
+ codeBlockText: {
77
+ fontFamily: "monospace",
78
+ fontSize: 14,
79
+ color: "#1a1a1a"
80
+ },
81
+ blockquote: {
82
+ backgroundColor: "#f5f5f5",
83
+ borderLeftWidth: 4,
84
+ borderLeftColor: "#cccccc",
85
+ paddingLeft: 12,
86
+ marginVertical: 4
87
+ },
88
+ list: {
89
+ marginTop: 4,
90
+ marginBottom: 4
91
+ },
92
+ listItem: {
93
+ flexDirection: "row",
94
+ alignItems: "flex-start"
95
+ },
96
+ listBullet: {
97
+ marginRight: 6,
98
+ fontSize: 16,
99
+ lineHeight: 24
100
+ },
101
+ link: {
102
+ color: "#0066cc",
103
+ textDecorationLine: "underline"
104
+ },
105
+ image: {},
106
+ tableRow: {
107
+ flexDirection: "row",
108
+ borderBottomWidth: 1,
109
+ borderBottomColor: "#e0e0e0"
110
+ },
111
+ tableCell: {
112
+ flex: 1,
113
+ padding: 4
114
+ }
115
+ };
116
+ function renderChildren(node, ctx) {
117
+ return node.children.map((id) => {
118
+ const child = ctx.nodeById.get(id);
119
+ if (!child) return null;
120
+ return /* @__PURE__ */ jsx(Fragment, { children: renderNode(child, ctx) }, id);
121
+ });
122
+ }
123
+ function renderTextContent(node, ctx) {
124
+ return node.children.map((id) => {
125
+ const child = ctx.nodeById.get(id);
126
+ if (!child) return null;
127
+ return /* @__PURE__ */ jsx(Fragment, { children: renderInlineNode(child, ctx) }, id);
128
+ });
129
+ }
130
+ /**
131
+ * Render an inline node (text, strong, em, etc.) as a React Native `<Text>`.
132
+ * Returns `null` for block-level nodes that can't be nested in `<Text>`.
133
+ */
134
+ function renderInlineNode(node, ctx) {
135
+ switch (node.type) {
136
+ case "text": return node.text;
137
+ case "strong": return /* @__PURE__ */ jsx(Text, {
138
+ style: ctx.s.strong,
139
+ children: renderTextContent(node, ctx)
140
+ }, node.id);
141
+ case "em": return /* @__PURE__ */ jsx(Text, {
142
+ style: ctx.s.em,
143
+ children: renderTextContent(node, ctx)
144
+ }, node.id);
145
+ case "strikethrough": return /* @__PURE__ */ jsx(Text, {
146
+ style: ctx.s.strikethrough,
147
+ children: renderTextContent(node, ctx)
148
+ }, node.id);
149
+ case "inline-code": return /* @__PURE__ */ jsx(Text, {
150
+ style: ctx.s.inlineCode,
151
+ children: node.text
152
+ }, node.id);
153
+ case "link":
154
+ case "autolink": return /* @__PURE__ */ jsx(Text, {
155
+ style: ctx.s.link,
156
+ children: "children" in node ? renderTextContent(node, ctx) : node.text
157
+ }, node.id);
158
+ case "image": return /* @__PURE__ */ jsx(Text, {
159
+ style: ctx.s.image,
160
+ children: node.alt
161
+ }, node.id);
162
+ case "soft-break": return "\n";
163
+ case "hard-break": return "\n";
164
+ case "citation": return /* @__PURE__ */ jsxs(Text, {
165
+ style: {
166
+ fontSize: 12,
167
+ verticalAlign: "top"
168
+ },
169
+ children: [
170
+ "[",
171
+ node.number ?? node.idRef,
172
+ "]"
173
+ ]
174
+ }, node.id);
175
+ default:
176
+ if ("text" in node && typeof node.text === "string") return node.text;
177
+ if ("children" in node) return renderTextContent(node, ctx);
178
+ return null;
179
+ }
180
+ }
181
+ function renderNode(node, ctx) {
182
+ switch (node.type) {
183
+ case "document": return /* @__PURE__ */ jsx(Fragment, { children: renderChildren(node, ctx) }, node.id);
184
+ case "paragraph": return /* @__PURE__ */ jsx(Text, {
185
+ style: ctx.s.paragraph,
186
+ children: renderTextContent(node, ctx)
187
+ }, node.id);
188
+ case "heading": {
189
+ const level = node.level;
190
+ return /* @__PURE__ */ jsx(Text, {
191
+ style: ctx.s[`h${level}`] ?? ctx.s.h6,
192
+ children: renderTextContent(node, ctx)
193
+ }, node.id);
194
+ }
195
+ case "blockquote": return /* @__PURE__ */ jsx(View, {
196
+ style: ctx.s.blockquote,
197
+ children: renderChildren(node, ctx)
198
+ }, node.id);
199
+ case "list": return /* @__PURE__ */ jsx(View, {
200
+ style: ctx.s.list,
201
+ children: node.children.map((itemId, index) => {
202
+ const item = ctx.nodeById.get(itemId);
203
+ if (!item) return null;
204
+ const bullet = node.ordered ? `${(node.start ?? 1) + index}. ` : "• ";
205
+ return /* @__PURE__ */ jsxs(View, {
206
+ style: ctx.s.listItem,
207
+ children: [/* @__PURE__ */ jsx(Text, {
208
+ style: ctx.s.listBullet,
209
+ children: bullet
210
+ }), /* @__PURE__ */ jsx(View, {
211
+ style: { flex: 1 },
212
+ children: renderChildren(item, ctx)
213
+ })]
214
+ }, itemId);
215
+ })
216
+ }, node.id);
217
+ case "list-item": return /* @__PURE__ */ jsx(View, {
218
+ style: ctx.s.listItem,
219
+ children: renderChildren(node, ctx)
220
+ }, node.id);
221
+ case "code-block": return /* @__PURE__ */ jsx(View, {
222
+ style: ctx.s.codeBlock,
223
+ children: /* @__PURE__ */ jsx(Text, {
224
+ style: ctx.s.codeBlockText,
225
+ children: node.text
226
+ })
227
+ }, node.id);
228
+ case "table": return /* @__PURE__ */ jsx(View, { children: renderChildren(node, ctx) }, node.id);
229
+ case "table-row": return /* @__PURE__ */ jsx(View, {
230
+ style: ctx.s.tableRow,
231
+ children: renderChildren(node, ctx)
232
+ }, node.id);
233
+ case "table-cell": return /* @__PURE__ */ jsx(View, {
234
+ style: ctx.s.tableCell,
235
+ children: /* @__PURE__ */ jsx(Text, { children: renderTextContent(node, ctx) })
236
+ }, node.id);
237
+ case "thematic-break": return /* @__PURE__ */ jsx(View, { style: {
238
+ borderBottomWidth: 1,
239
+ borderBottomColor: "#e0e0e0",
240
+ marginVertical: 8
241
+ } }, node.id);
242
+ case "text": return /* @__PURE__ */ jsx(Text, { children: node.text }, node.id);
243
+ case "strong":
244
+ case "em":
245
+ case "strikethrough":
246
+ case "inline-code":
247
+ case "link":
248
+ case "autolink":
249
+ case "image":
250
+ case "soft-break":
251
+ case "hard-break":
252
+ case "citation": return /* @__PURE__ */ jsx(Text, { children: renderInlineNode(node, ctx) }, node.id);
253
+ default: return null;
254
+ }
255
+ }
256
+ function buildParserState(content, isComplete, animate) {
257
+ const parsed = parseStreamingMarkdownChunk(createStreamingMarkdownParserState({
258
+ segmenter: animate,
259
+ enableTables: true,
260
+ enableAutolinks: true
261
+ }), content);
262
+ return isComplete ? finalizeStreamingMarkdown(parsed) : parsed;
263
+ }
264
+ /**
265
+ * React Native streaming markdown renderer powered by the zero-dependency
266
+ * `@copilotkit/markdown` parser.
267
+ *
268
+ * Defaults `segmenter: false` — safe on Hermes which may not ship `Intl.Segmenter`.
269
+ * Pass `animate={true}` only when you have confirmed Segmenter availability.
270
+ *
271
+ * @public
272
+ */
273
+ function StreamingMarkdownRenderer({ content, isComplete = false, style, animate = false }) {
274
+ const mergedStyles = useMemo(() => style ? {
275
+ ...defaultMarkdownStyles,
276
+ ...style
277
+ } : defaultMarkdownStyles, [style]);
278
+ const parserState = useMemo(() => buildParserState(content ?? "", isComplete, animate), [
279
+ content,
280
+ isComplete,
281
+ animate
282
+ ]);
283
+ const nodeById = useMemo(() => {
284
+ const map = /* @__PURE__ */ new Map();
285
+ for (const node of parserState.nodes) map.set(node.id, node);
286
+ return map;
287
+ }, [parserState.nodes]);
288
+ const ctx = useMemo(() => ({
289
+ nodeById,
290
+ s: mergedStyles
291
+ }), [nodeById, mergedStyles]);
292
+ if (parserState.rootId == null) return null;
293
+ const rootNode = nodeById.get(parserState.rootId);
294
+ if (!rootNode) return null;
295
+ return /* @__PURE__ */ jsx(Fragment$1, { children: renderNode(rootNode, ctx) });
296
+ }
297
+
298
+ //#endregion
299
+ export { StreamingMarkdownRenderer, defaultMarkdownStyles };
300
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/react-native/streaming-markdown-renderer.tsx"],"sourcesContent":["import React, { Fragment, useMemo } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { Text, View } from \"react-native\";\nimport {\n createStreamingMarkdownParserState,\n finalizeStreamingMarkdown,\n parseStreamingMarkdownChunk,\n} from \"@copilotkit/markdown\";\nimport type {\n StreamingMarkdownAstNode,\n StreamingMarkdownParserState,\n} from \"@copilotkit/markdown\";\n\n// ---------------------------------------------------------------------------\n// Style types\n// ---------------------------------------------------------------------------\n\n/**\n * Style-object for the RN streaming markdown renderer.\n * Every key is optional — defaults cover all built-in node types.\n *\n * @public\n */\nexport type MarkdownStyle = {\n paragraph?: Record<string, unknown>;\n h1?: Record<string, unknown>;\n h2?: Record<string, unknown>;\n h3?: Record<string, unknown>;\n h4?: Record<string, unknown>;\n h5?: Record<string, unknown>;\n h6?: Record<string, unknown>;\n strong?: Record<string, unknown>;\n em?: Record<string, unknown>;\n strikethrough?: Record<string, unknown>;\n inlineCode?: Record<string, unknown>;\n codeBlock?: Record<string, unknown>;\n codeBlockText?: Record<string, unknown>;\n blockquote?: Record<string, unknown>;\n list?: Record<string, unknown>;\n listItem?: Record<string, unknown>;\n listBullet?: Record<string, unknown>;\n link?: Record<string, unknown>;\n image?: Record<string, unknown>;\n tableRow?: Record<string, unknown>;\n tableCell?: Record<string, unknown>;\n};\n\n/**\n * Default styles for all built-in node types.\n *\n * @public\n */\nexport const defaultMarkdownStyles: MarkdownStyle = {\n paragraph: {\n fontSize: 16,\n lineHeight: 24,\n color: \"#1a1a1a\",\n marginTop: 4,\n marginBottom: 4,\n },\n h1: {\n fontSize: 24,\n fontWeight: \"bold\",\n marginTop: 12,\n marginBottom: 8,\n color: \"#111111\",\n },\n h2: {\n fontSize: 20,\n fontWeight: \"bold\",\n marginTop: 10,\n marginBottom: 6,\n color: \"#111111\",\n },\n h3: {\n fontSize: 18,\n fontWeight: \"600\",\n marginTop: 8,\n marginBottom: 4,\n color: \"#222222\",\n },\n h4: {\n fontSize: 16,\n fontWeight: \"600\",\n marginTop: 6,\n marginBottom: 4,\n color: \"#222222\",\n },\n h5: {\n fontSize: 14,\n fontWeight: \"600\",\n marginTop: 4,\n marginBottom: 2,\n color: \"#333333\",\n },\n h6: {\n fontSize: 13,\n fontWeight: \"600\",\n marginTop: 4,\n marginBottom: 2,\n color: \"#444444\",\n },\n strong: { fontWeight: \"bold\" },\n em: { fontStyle: \"italic\" },\n strikethrough: { textDecorationLine: \"line-through\" },\n inlineCode: {\n backgroundColor: \"#f0f0f0\",\n fontFamily: \"monospace\",\n fontSize: 14,\n },\n codeBlock: {\n backgroundColor: \"#f0f0f0\",\n borderRadius: 8,\n padding: 12,\n marginVertical: 4,\n },\n codeBlockText: {\n fontFamily: \"monospace\",\n fontSize: 14,\n color: \"#1a1a1a\",\n },\n blockquote: {\n backgroundColor: \"#f5f5f5\",\n borderLeftWidth: 4,\n borderLeftColor: \"#cccccc\",\n paddingLeft: 12,\n marginVertical: 4,\n },\n list: { marginTop: 4, marginBottom: 4 },\n listItem: { flexDirection: \"row\", alignItems: \"flex-start\" } as any,\n listBullet: { marginRight: 6, fontSize: 16, lineHeight: 24 },\n link: { color: \"#0066cc\", textDecorationLine: \"underline\" },\n image: {},\n tableRow: {\n flexDirection: \"row\",\n borderBottomWidth: 1,\n borderBottomColor: \"#e0e0e0\",\n } as any,\n tableCell: { flex: 1, padding: 4 },\n};\n\n// ---------------------------------------------------------------------------\n// Props\n// ---------------------------------------------------------------------------\n\n/**\n * Props for the React Native `StreamingMarkdownRenderer`.\n *\n * @public\n */\nexport interface StreamingMarkdownRendererProps {\n /** Full markdown source (may grow over time during streaming). */\n content: string;\n /** When true, finalizes the parser state after processing content. */\n isComplete?: boolean;\n /** Style overrides merged with `defaultMarkdownStyles`. */\n style?: MarkdownStyle;\n /**\n * When true, enables `Intl.Segmenter`-based per-token animation.\n * Defaults to `false` — safe on Hermes which may not ship Segmenter.\n */\n animate?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\ntype RenderContext = {\n nodeById: Map<number, StreamingMarkdownAstNode>;\n s: MarkdownStyle;\n};\n\nfunction renderChildren(\n node: Extract<StreamingMarkdownAstNode, { children: number[] }>,\n ctx: RenderContext,\n): ReactNode {\n return node.children.map((id) => {\n const child = ctx.nodeById.get(id);\n if (!child) return null;\n return <Fragment key={id}>{renderNode(child, ctx)}</Fragment>;\n });\n}\n\nfunction renderTextContent(\n node: Extract<StreamingMarkdownAstNode, { children: number[] }>,\n ctx: RenderContext,\n): ReactNode {\n return node.children.map((id) => {\n const child = ctx.nodeById.get(id);\n if (!child) return null;\n return <Fragment key={id}>{renderInlineNode(child, ctx)}</Fragment>;\n });\n}\n\n/**\n * Render an inline node (text, strong, em, etc.) as a React Native `<Text>`.\n * Returns `null` for block-level nodes that can't be nested in `<Text>`.\n */\nfunction renderInlineNode(\n node: StreamingMarkdownAstNode,\n ctx: RenderContext,\n): ReactNode {\n switch (node.type) {\n case \"text\":\n return node.text;\n\n case \"strong\":\n return (\n <Text key={node.id} style={ctx.s.strong as any}>\n {renderTextContent(node, ctx)}\n </Text>\n );\n\n case \"em\":\n return (\n <Text key={node.id} style={ctx.s.em as any}>\n {renderTextContent(node, ctx)}\n </Text>\n );\n\n case \"strikethrough\":\n return (\n <Text key={node.id} style={ctx.s.strikethrough as any}>\n {renderTextContent(node, ctx)}\n </Text>\n );\n\n case \"inline-code\":\n return (\n <Text key={node.id} style={ctx.s.inlineCode as any}>\n {node.text}\n </Text>\n );\n\n case \"link\":\n case \"autolink\":\n // Non-navigable: render as styled Text only — zero URL/XSS surface.\n return (\n <Text key={node.id} style={ctx.s.link as any}>\n {\"children\" in node\n ? renderTextContent(node as any, ctx)\n : (node as any).text}\n </Text>\n );\n\n case \"image\":\n // Images can't be embedded in <Text>; render alt text.\n return (\n <Text key={node.id} style={ctx.s.image as any}>\n {(node as any).alt}\n </Text>\n );\n\n case \"soft-break\":\n return \"\\n\";\n\n case \"hard-break\":\n return \"\\n\";\n\n case \"citation\":\n // Citation marker (e.g. \"[1]\"). This is an inline-level node reached via\n // a paragraph/heading's renderTextContent; without this case it would\n // fall through to `default` and render nothing (no text/children).\n // Prefer the resolved number, fall back to the citation id.\n return (\n <Text\n key={node.id}\n style={{ fontSize: 12, verticalAlign: \"top\" } as any}\n >\n [{(node as any).number ?? (node as any).idRef}]\n </Text>\n );\n\n default:\n // Fallback for any inline nodes not explicitly handled\n if (\"text\" in node && typeof (node as any).text === \"string\") {\n return (node as any).text;\n }\n if (\"children\" in node) {\n return renderTextContent(node as any, ctx);\n }\n return null;\n }\n}\n\nfunction renderNode(\n node: StreamingMarkdownAstNode,\n ctx: RenderContext,\n): ReactNode {\n switch (node.type) {\n case \"document\":\n return <Fragment key={node.id}>{renderChildren(node, ctx)}</Fragment>;\n\n case \"paragraph\":\n return (\n <Text key={node.id} style={ctx.s.paragraph as any}>\n {renderTextContent(node, ctx)}\n </Text>\n );\n\n case \"heading\": {\n const level = node.level as 1 | 2 | 3 | 4 | 5 | 6;\n const headingStyle =\n ctx.s[`h${level}` as keyof MarkdownStyle] ?? ctx.s.h6;\n return (\n <Text key={node.id} style={headingStyle as any}>\n {renderTextContent(node, ctx)}\n </Text>\n );\n }\n\n case \"blockquote\":\n return (\n <View key={node.id} style={ctx.s.blockquote as any}>\n {renderChildren(node, ctx)}\n </View>\n );\n\n case \"list\":\n return (\n <View key={node.id} style={ctx.s.list as any}>\n {node.children.map((itemId, index) => {\n const item = ctx.nodeById.get(itemId);\n if (!item) return null;\n const bullet = node.ordered\n ? `${(node.start ?? 1) + index}. `\n : \"• \";\n return (\n <View key={itemId} style={ctx.s.listItem as any}>\n <Text style={ctx.s.listBullet as any}>{bullet}</Text>\n <View style={{ flex: 1 }}>\n {renderChildren(\n item as Extract<\n StreamingMarkdownAstNode,\n { children: number[] }\n >,\n ctx,\n )}\n </View>\n </View>\n );\n })}\n </View>\n );\n\n case \"list-item\":\n // Handled inside \"list\" above; fallback in case a list-item appears standalone\n return (\n <View key={node.id} style={ctx.s.listItem as any}>\n {renderChildren(node, ctx)}\n </View>\n );\n\n case \"code-block\":\n return (\n <View key={node.id} style={ctx.s.codeBlock as any}>\n <Text style={ctx.s.codeBlockText as any}>{node.text}</Text>\n </View>\n );\n\n case \"table\":\n return <View key={node.id}>{renderChildren(node, ctx)}</View>;\n\n case \"table-row\":\n return (\n <View key={node.id} style={ctx.s.tableRow as any}>\n {renderChildren(node, ctx)}\n </View>\n );\n\n case \"table-cell\":\n return (\n <View key={node.id} style={ctx.s.tableCell as any}>\n <Text>{renderTextContent(node, ctx)}</Text>\n </View>\n );\n\n case \"thematic-break\":\n return (\n <View\n key={node.id}\n style={{\n borderBottomWidth: 1,\n borderBottomColor: \"#e0e0e0\",\n marginVertical: 8,\n }}\n />\n );\n\n case \"text\":\n return <Text key={node.id}>{node.text}</Text>;\n\n case \"strong\":\n case \"em\":\n case \"strikethrough\":\n case \"inline-code\":\n case \"link\":\n case \"autolink\":\n case \"image\":\n case \"soft-break\":\n case \"hard-break\":\n case \"citation\":\n // These are inline; wrap in Text for block-level context. Citation\n // rendering lives in renderInlineNode so block and inline paths agree.\n return <Text key={node.id}>{renderInlineNode(node, ctx)}</Text>;\n\n default:\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nfunction buildParserState(\n content: string,\n isComplete: boolean,\n animate: boolean,\n): StreamingMarkdownParserState {\n const state = createStreamingMarkdownParserState({\n segmenter: animate,\n enableTables: true,\n enableAutolinks: true,\n });\n const parsed = parseStreamingMarkdownChunk(state, content);\n return isComplete ? finalizeStreamingMarkdown(parsed) : parsed;\n}\n\n/**\n * React Native streaming markdown renderer powered by the zero-dependency\n * `@copilotkit/markdown` parser.\n *\n * Defaults `segmenter: false` — safe on Hermes which may not ship `Intl.Segmenter`.\n * Pass `animate={true}` only when you have confirmed Segmenter availability.\n *\n * @public\n */\nexport function StreamingMarkdownRenderer({\n content,\n isComplete = false,\n style,\n animate = false,\n}: StreamingMarkdownRendererProps): React.ReactElement | null {\n const mergedStyles = useMemo<MarkdownStyle>(\n () =>\n style ? { ...defaultMarkdownStyles, ...style } : defaultMarkdownStyles,\n [style],\n );\n\n const parserState = useMemo(\n () => buildParserState(content ?? \"\", isComplete, animate),\n [content, isComplete, animate],\n );\n\n const nodeById = useMemo(() => {\n const map = new Map<number, StreamingMarkdownAstNode>();\n for (const node of parserState.nodes) {\n map.set(node.id, node);\n }\n return map;\n }, [parserState.nodes]);\n\n const ctx: RenderContext = useMemo(\n () => ({ nodeById, s: mergedStyles }),\n [nodeById, mergedStyles],\n );\n\n if (parserState.rootId == null) {\n return null;\n }\n\n const rootNode = nodeById.get(parserState.rootId);\n if (!rootNode) {\n return null;\n }\n\n return <>{renderNode(rootNode, ctx)}</>;\n}\n"],"mappings":"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"}
@@ -0,0 +1,256 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ let vue = require("vue");
3
+ let _copilotkit_markdown = require("@copilotkit/markdown");
4
+
5
+ //#region src/vue/streaming-markdown-renderer.ts
6
+ const SAFE_HREF = /^(https?:|mailto:|tel:|#|\/|\.\/|\.\.\/)/i;
7
+ const SAFE_IMG_SRC = /^(https?:|data:image\/(?!svg)|\/|\.\/|\.\.\/)/i;
8
+ function sanitizeHref(href) {
9
+ if (!href) return void 0;
10
+ return SAFE_HREF.test(href.trim()) ? href : void 0;
11
+ }
12
+ function sanitizeImgSrc(src) {
13
+ if (!src) return void 0;
14
+ return SAFE_IMG_SRC.test(src.trim()) ? src : void 0;
15
+ }
16
+ const DEFAULT_OPTIONS = {
17
+ segmenter: true,
18
+ enableTables: true,
19
+ enableAutolinks: true
20
+ };
21
+ function normalizeOptions(options) {
22
+ return {
23
+ segmenter: options?.segmenter ?? DEFAULT_OPTIONS.segmenter,
24
+ enableTables: options?.enableTables ?? DEFAULT_OPTIONS.enableTables,
25
+ enableAutolinks: options?.enableAutolinks ?? DEFAULT_OPTIONS.enableAutolinks
26
+ };
27
+ }
28
+ function buildParserState(content, options, isComplete) {
29
+ const state = (0, _copilotkit_markdown.createStreamingMarkdownParserState)(options);
30
+ const parsed = content.length > 0 ? (0, _copilotkit_markdown.parseStreamingMarkdownChunk)(state, content) : state;
31
+ return isComplete ? (0, _copilotkit_markdown.finalizeStreamingMarkdown)(parsed) : parsed;
32
+ }
33
+ function renderTextSegments(node) {
34
+ if (node.text.length === 0) return [];
35
+ if (node.segments.length === 0) return [(0, vue.h)("span", { class: "cpk-streaming-markdown-segment" }, node.text)];
36
+ return node.segments.map((segment) => (0, vue.h)("span", {
37
+ class: "cpk-streaming-markdown-segment",
38
+ "data-streaming-markdown-segment-kind": segment.kind,
39
+ "data-streaming-markdown-whitespace": String(segment.isWhitespace)
40
+ }, segment.noBreakBefore ? `⁠${segment.text}` : segment.text));
41
+ }
42
+ function renderChildren(childIds, nodeById, nodeRenderers) {
43
+ return childIds.map((id) => {
44
+ const child = nodeById.get(id);
45
+ return child ? renderNode(child, nodeById, nodeRenderers) : null;
46
+ });
47
+ }
48
+ function renderNode(node, nodeById, nodeRenderers) {
49
+ function withOverride(key, defaultVNode) {
50
+ const override = nodeRenderers?.[key];
51
+ return override ? override(node, defaultVNode) : defaultVNode;
52
+ }
53
+ switch (node.type) {
54
+ case "document": return (0, vue.h)("span", { style: "display:contents" }, renderChildren(node.children, nodeById, nodeRenderers));
55
+ case "paragraph": return withOverride("paragraph", (0, vue.h)("p", {
56
+ "data-streaming-markdown-node": "paragraph",
57
+ "data-node-open": String(!node.closed)
58
+ }, renderChildren(node.children, nodeById, nodeRenderers)));
59
+ case "heading": return withOverride("heading", (0, vue.h)(`h${node.level}`, {
60
+ "data-streaming-markdown-node": "heading",
61
+ "data-node-open": String(!node.closed)
62
+ }, renderChildren(node.children, nodeById, nodeRenderers)));
63
+ case "blockquote": return withOverride("blockquote", (0, vue.h)("blockquote", {
64
+ "data-streaming-markdown-node": "blockquote",
65
+ "data-node-open": String(!node.closed)
66
+ }, renderChildren(node.children, nodeById, nodeRenderers)));
67
+ case "list": {
68
+ const tag = node.ordered ? "ol" : "ul";
69
+ const attrs = {
70
+ "data-streaming-markdown-node": "list",
71
+ "data-node-open": String(!node.closed),
72
+ "data-list-tight": String(node.tight)
73
+ };
74
+ if (node.ordered && node.start != null) attrs.start = node.start;
75
+ return withOverride("list", (0, vue.h)(tag, attrs, renderChildren(node.children, nodeById, nodeRenderers)));
76
+ }
77
+ case "list-item": return withOverride("listItem", (0, vue.h)("li", {
78
+ "data-streaming-markdown-node": "list-item",
79
+ "data-node-open": String(!node.closed)
80
+ }, renderChildren(node.children, nodeById, nodeRenderers)));
81
+ case "code-block": return withOverride("codeBlock", (0, vue.h)("pre", {
82
+ "data-streaming-markdown-node": "code-block",
83
+ "data-node-open": String(!node.closed)
84
+ }, [(0, vue.h)("code", { "data-code-info": node.info ?? void 0 }, node.text)]));
85
+ case "table": return withOverride("table", (0, vue.h)("table", {
86
+ "data-streaming-markdown-node": "table",
87
+ "data-node-open": String(!node.closed)
88
+ }, [(0, vue.h)("tbody", renderChildren(node.children, nodeById, nodeRenderers))]));
89
+ case "table-row": return withOverride("tableRow", (0, vue.h)("tr", {
90
+ "data-streaming-markdown-node": "table-row",
91
+ "data-node-open": String(!node.closed)
92
+ }, renderChildren(node.children, nodeById, nodeRenderers)));
93
+ case "table-cell": {
94
+ const parent = node.parentId != null ? nodeById.get(node.parentId) : void 0;
95
+ return withOverride("tableCell", (0, vue.h)(parent?.type === "table-row" && parent.isHeader ? "th" : "td", {
96
+ "data-streaming-markdown-node": "table-cell",
97
+ "data-node-open": String(!node.closed)
98
+ }, renderChildren(node.children, nodeById, nodeRenderers)));
99
+ }
100
+ case "thematic-break": return withOverride("thematicBreak", (0, vue.h)("hr", {
101
+ "data-streaming-markdown-node": "thematic-break",
102
+ "data-node-open": String(!node.closed)
103
+ }));
104
+ case "text": return (0, vue.h)("span", { style: "display:contents" }, renderTextSegments(node));
105
+ case "em": return withOverride("em", (0, vue.h)("em", {
106
+ "data-streaming-markdown-node": "em",
107
+ "data-node-open": String(!node.closed)
108
+ }, renderChildren(node.children, nodeById, nodeRenderers)));
109
+ case "strong": return withOverride("strong", (0, vue.h)("strong", {
110
+ "data-streaming-markdown-node": "strong",
111
+ "data-node-open": String(!node.closed)
112
+ }, renderChildren(node.children, nodeById, nodeRenderers)));
113
+ case "strikethrough": return withOverride("strikethrough", (0, vue.h)("del", {
114
+ "data-streaming-markdown-node": "strikethrough",
115
+ "data-node-open": String(!node.closed)
116
+ }, renderChildren(node.children, nodeById, nodeRenderers)));
117
+ case "inline-code": return withOverride("inlineCode", (0, vue.h)("code", {
118
+ "data-streaming-markdown-node": "inline-code",
119
+ "data-node-open": String(!node.closed)
120
+ }, node.text));
121
+ case "soft-break": return "\n";
122
+ case "hard-break": return withOverride("hardBreak", (0, vue.h)("br", {
123
+ "data-streaming-markdown-node": "hard-break",
124
+ "data-node-open": String(!node.closed)
125
+ }));
126
+ case "link": {
127
+ const safeHref = sanitizeHref(node.url);
128
+ const attrs = {
129
+ "data-streaming-markdown-node": "link",
130
+ "data-node-open": String(!node.closed),
131
+ target: "_blank",
132
+ rel: "noopener noreferrer"
133
+ };
134
+ if (safeHref != null) attrs.href = safeHref;
135
+ if (node.title) attrs.title = node.title;
136
+ return withOverride("link", (0, vue.h)("a", attrs, renderChildren(node.children, nodeById, nodeRenderers)));
137
+ }
138
+ case "image": {
139
+ const safeSrc = sanitizeImgSrc(node.url);
140
+ const attrs = {
141
+ "data-streaming-markdown-node": "image",
142
+ "data-node-open": String(!node.closed),
143
+ alt: node.alt
144
+ };
145
+ if (safeSrc != null) attrs.src = safeSrc;
146
+ if (node.title) attrs.title = node.title;
147
+ return withOverride("image", (0, vue.h)("img", attrs));
148
+ }
149
+ case "autolink": {
150
+ const safeHref = sanitizeHref(node.url);
151
+ const attrs = {
152
+ "data-streaming-markdown-node": "autolink",
153
+ "data-node-open": String(!node.closed),
154
+ target: "_blank",
155
+ rel: "noopener noreferrer"
156
+ };
157
+ if (safeHref != null) attrs.href = safeHref;
158
+ return withOverride("autolink", (0, vue.h)("a", attrs, node.text));
159
+ }
160
+ case "citation": return withOverride("citation", (0, vue.h)("sup", {
161
+ "data-streaming-markdown-node": "citation",
162
+ "data-node-open": String(!node.closed),
163
+ class: "cpk-streaming-markdown-citation"
164
+ }, [(0, vue.h)("span", {
165
+ role: "doc-noteref",
166
+ class: "cpk-streaming-markdown-citation-label"
167
+ }, String(node.number ?? node.idRef))]));
168
+ default: return null;
169
+ }
170
+ }
171
+ /**
172
+ * Vue 3 streaming markdown renderer.
173
+ *
174
+ * Drives the `@copilotkit/markdown` zero-dep parser and walks the
175
+ * resulting AST into VNodes via `h()`.
176
+ *
177
+ * @public
178
+ */
179
+ const StreamingMarkdownRenderer = (0, vue.defineComponent)({
180
+ name: "StreamingMarkdownRenderer",
181
+ props: {
182
+ content: {
183
+ type: String,
184
+ required: true
185
+ },
186
+ isComplete: {
187
+ type: Boolean,
188
+ default: false
189
+ },
190
+ options: {
191
+ type: Object,
192
+ default: void 0
193
+ },
194
+ class: {
195
+ type: String,
196
+ default: void 0
197
+ },
198
+ caret: {
199
+ type: Boolean,
200
+ default: false
201
+ },
202
+ nodeRenderers: {
203
+ type: Object,
204
+ default: void 0
205
+ }
206
+ },
207
+ setup(props) {
208
+ const parserState = (0, vue.computed)(() => {
209
+ const opts = normalizeOptions(props.options);
210
+ return buildParserState(props.content ?? "", opts, props.isComplete);
211
+ });
212
+ const nodeById = (0, vue.computed)(() => {
213
+ const map = /* @__PURE__ */ new Map();
214
+ for (const node of parserState.value.nodes) map.set(node.id, node);
215
+ return map;
216
+ });
217
+ return () => {
218
+ const state = parserState.value;
219
+ const byId = nodeById.value;
220
+ const rootNode = state.rootId != null ? byId.get(state.rootId) : void 0;
221
+ const renderers = props.nodeRenderers;
222
+ const rootClass = props.class ? `cpk-streaming-markdown-root ${props.class}` : "cpk-streaming-markdown-root";
223
+ if (!rootNode) return (0, vue.h)("div", {
224
+ class: rootClass,
225
+ "data-streaming-markdown-root": true
226
+ });
227
+ const children = rootNode.type === "document" ? rootNode.children.map((id) => {
228
+ const child = byId.get(id);
229
+ return child ? renderNode(child, byId, renderers) : null;
230
+ }) : [renderNode(rootNode, byId, renderers)];
231
+ if (props.caret && !state.isComplete) children.push((0, vue.h)("span", {
232
+ "aria-hidden": true,
233
+ class: "cpk-streaming-markdown-caret",
234
+ "data-streaming-markdown-caret": true,
235
+ style: {
236
+ display: "inline-block",
237
+ width: "0.48em",
238
+ height: "0.48em",
239
+ marginInlineStart: "0.08em",
240
+ verticalAlign: "-0.08em",
241
+ borderRadius: "999px",
242
+ backgroundColor: "currentColor",
243
+ opacity: "0.55"
244
+ }
245
+ }));
246
+ return (0, vue.h)("div", {
247
+ class: rootClass,
248
+ "data-streaming-markdown-root": true
249
+ }, children);
250
+ };
251
+ }
252
+ });
253
+
254
+ //#endregion
255
+ exports.StreamingMarkdownRenderer = StreamingMarkdownRenderer;
256
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../src/vue/streaming-markdown-renderer.ts"],"sourcesContent":["import { computed, defineComponent, h } from \"vue\";\nimport type { PropType, VNode } from \"vue\";\nimport {\n createStreamingMarkdownParserState,\n finalizeStreamingMarkdown,\n parseStreamingMarkdownChunk,\n} from \"@copilotkit/markdown\";\nimport type {\n StreamingMarkdownAstNode,\n StreamingMarkdownParserOptions,\n StreamingMarkdownParserState,\n TextSegment,\n} from \"@copilotkit/markdown\";\n\n// ---------------------------------------------------------------------------\n// URL sanitization (allowlisted href and image src schemes)\n// ---------------------------------------------------------------------------\n\nconst SAFE_HREF = /^(https?:|mailto:|tel:|#|\\/|\\.\\/|\\.\\.\\/)/i;\nconst SAFE_IMG_SRC = /^(https?:|data:image\\/(?!svg)|\\/|\\.\\/|\\.\\.\\/)/i;\n\nfunction sanitizeHref(href: string | undefined): string | undefined {\n if (!href) return undefined;\n return SAFE_HREF.test(href.trim()) ? href : undefined;\n}\n\nfunction sanitizeImgSrc(src: string | undefined): string | undefined {\n if (!src) return undefined;\n return SAFE_IMG_SRC.test(src.trim()) ? src : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Parser helpers (full re-parse approach — simple and correct)\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_OPTIONS: StreamingMarkdownParserOptions = {\n segmenter: true,\n enableTables: true,\n enableAutolinks: true,\n};\n\nfunction normalizeOptions(\n options?: Partial<StreamingMarkdownParserOptions>,\n): StreamingMarkdownParserOptions {\n return {\n segmenter: options?.segmenter ?? DEFAULT_OPTIONS.segmenter,\n enableTables: options?.enableTables ?? DEFAULT_OPTIONS.enableTables,\n enableAutolinks:\n options?.enableAutolinks ?? DEFAULT_OPTIONS.enableAutolinks,\n };\n}\n\nfunction buildParserState(\n content: string,\n options: StreamingMarkdownParserOptions,\n isComplete: boolean,\n): StreamingMarkdownParserState {\n const state = createStreamingMarkdownParserState(options);\n const parsed =\n content.length > 0 ? parseStreamingMarkdownChunk(state, content) : state;\n return isComplete ? finalizeStreamingMarkdown(parsed) : parsed;\n}\n\n// ---------------------------------------------------------------------------\n// AST → VNode walker\n// ---------------------------------------------------------------------------\n\ntype NodeById = Map<number, StreamingMarkdownAstNode>;\n\ntype TextNode = Extract<StreamingMarkdownAstNode, { type: \"text\" }>;\n\nfunction renderTextSegments(node: TextNode): (VNode | string)[] {\n if (node.text.length === 0) return [];\n if (node.segments.length === 0) {\n return [h(\"span\", { class: \"cpk-streaming-markdown-segment\" }, node.text)];\n }\n return node.segments.map((segment: TextSegment) =>\n h(\n \"span\",\n {\n class: \"cpk-streaming-markdown-segment\",\n \"data-streaming-markdown-segment-kind\": segment.kind,\n \"data-streaming-markdown-whitespace\": String(segment.isWhitespace),\n },\n segment.noBreakBefore ? `⁠${segment.text}` : segment.text,\n ),\n );\n}\n\nfunction renderChildren(\n childIds: number[],\n nodeById: NodeById,\n nodeRenderers?: VueStreamingMarkdownNodeRenderers,\n): (VNode | string | null)[] {\n return childIds.map((id) => {\n const child = nodeById.get(id);\n return child ? renderNode(child, nodeById, nodeRenderers) : null;\n });\n}\n\nfunction renderNode(\n node: StreamingMarkdownAstNode,\n nodeById: NodeById,\n nodeRenderers?: VueStreamingMarkdownNodeRenderers,\n): VNode | string | null {\n // Helper: apply a nodeRenderers override if one is registered for this node type.\n function withOverride(\n key: VueStreamingMarkdownNodeRendererKey,\n defaultVNode: VNode | string | null,\n ): VNode | string | null {\n const override = nodeRenderers?.[key];\n return override ? override(node, defaultVNode) : defaultVNode;\n }\n\n switch (node.type) {\n case \"document\": {\n // Document is transparent — render children directly as a Fragment via array\n // We wrap in a div for the root element, handled at the top level.\n // Here just return children inlined (will be wrapped by root div).\n return h(\n \"span\",\n { style: \"display:contents\" },\n renderChildren(node.children, nodeById, nodeRenderers),\n );\n }\n\n case \"paragraph\": {\n const defaultVNode = h(\n \"p\",\n {\n \"data-streaming-markdown-node\": \"paragraph\",\n \"data-node-open\": String(!node.closed),\n },\n renderChildren(node.children, nodeById, nodeRenderers),\n );\n return withOverride(\"paragraph\", defaultVNode);\n }\n\n case \"heading\": {\n const tag = `h${node.level}` as \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\";\n const defaultVNode = h(\n tag,\n {\n \"data-streaming-markdown-node\": \"heading\",\n \"data-node-open\": String(!node.closed),\n },\n renderChildren(node.children, nodeById, nodeRenderers),\n );\n return withOverride(\"heading\", defaultVNode);\n }\n\n case \"blockquote\": {\n const defaultVNode = h(\n \"blockquote\",\n {\n \"data-streaming-markdown-node\": \"blockquote\",\n \"data-node-open\": String(!node.closed),\n },\n renderChildren(node.children, nodeById, nodeRenderers),\n );\n return withOverride(\"blockquote\", defaultVNode);\n }\n\n case \"list\": {\n const tag = node.ordered ? \"ol\" : \"ul\";\n const attrs: Record<string, unknown> = {\n \"data-streaming-markdown-node\": \"list\",\n \"data-node-open\": String(!node.closed),\n \"data-list-tight\": String(node.tight),\n };\n if (node.ordered && node.start != null) {\n attrs.start = node.start;\n }\n const defaultVNode = h(\n tag,\n attrs,\n renderChildren(node.children, nodeById, nodeRenderers),\n );\n return withOverride(\"list\", defaultVNode);\n }\n\n case \"list-item\": {\n const defaultVNode = h(\n \"li\",\n {\n \"data-streaming-markdown-node\": \"list-item\",\n \"data-node-open\": String(!node.closed),\n },\n renderChildren(node.children, nodeById, nodeRenderers),\n );\n return withOverride(\"listItem\", defaultVNode);\n }\n\n case \"code-block\": {\n const defaultVNode = h(\n \"pre\",\n {\n \"data-streaming-markdown-node\": \"code-block\",\n \"data-node-open\": String(!node.closed),\n },\n [h(\"code\", { \"data-code-info\": node.info ?? undefined }, node.text)],\n );\n return withOverride(\"codeBlock\", defaultVNode);\n }\n\n case \"table\": {\n const defaultVNode = h(\n \"table\",\n {\n \"data-streaming-markdown-node\": \"table\",\n \"data-node-open\": String(!node.closed),\n },\n [h(\"tbody\", renderChildren(node.children, nodeById, nodeRenderers))],\n );\n return withOverride(\"table\", defaultVNode);\n }\n\n case \"table-row\": {\n const defaultVNode = h(\n \"tr\",\n {\n \"data-streaming-markdown-node\": \"table-row\",\n \"data-node-open\": String(!node.closed),\n },\n renderChildren(node.children, nodeById, nodeRenderers),\n );\n return withOverride(\"tableRow\", defaultVNode);\n }\n\n case \"table-cell\": {\n const parent =\n node.parentId != null ? nodeById.get(node.parentId) : undefined;\n const isHeader = parent?.type === \"table-row\" && parent.isHeader;\n const tag = isHeader ? \"th\" : \"td\";\n const defaultVNode = h(\n tag,\n {\n \"data-streaming-markdown-node\": \"table-cell\",\n \"data-node-open\": String(!node.closed),\n },\n renderChildren(node.children, nodeById, nodeRenderers),\n );\n return withOverride(\"tableCell\", defaultVNode);\n }\n\n case \"thematic-break\": {\n const defaultVNode = h(\"hr\", {\n \"data-streaming-markdown-node\": \"thematic-break\",\n \"data-node-open\": String(!node.closed),\n });\n return withOverride(\"thematicBreak\", defaultVNode);\n }\n\n case \"text\": {\n return h(\"span\", { style: \"display:contents\" }, renderTextSegments(node));\n }\n\n case \"em\": {\n const defaultVNode = h(\n \"em\",\n {\n \"data-streaming-markdown-node\": \"em\",\n \"data-node-open\": String(!node.closed),\n },\n renderChildren(node.children, nodeById, nodeRenderers),\n );\n return withOverride(\"em\", defaultVNode);\n }\n\n case \"strong\": {\n const defaultVNode = h(\n \"strong\",\n {\n \"data-streaming-markdown-node\": \"strong\",\n \"data-node-open\": String(!node.closed),\n },\n renderChildren(node.children, nodeById, nodeRenderers),\n );\n return withOverride(\"strong\", defaultVNode);\n }\n\n case \"strikethrough\": {\n const defaultVNode = h(\n \"del\",\n {\n \"data-streaming-markdown-node\": \"strikethrough\",\n \"data-node-open\": String(!node.closed),\n },\n renderChildren(node.children, nodeById, nodeRenderers),\n );\n return withOverride(\"strikethrough\", defaultVNode);\n }\n\n case \"inline-code\": {\n const defaultVNode = h(\n \"code\",\n {\n \"data-streaming-markdown-node\": \"inline-code\",\n \"data-node-open\": String(!node.closed),\n },\n node.text,\n );\n return withOverride(\"inlineCode\", defaultVNode);\n }\n\n case \"soft-break\": {\n return \"\\n\";\n }\n\n case \"hard-break\": {\n const defaultVNode = h(\"br\", {\n \"data-streaming-markdown-node\": \"hard-break\",\n \"data-node-open\": String(!node.closed),\n });\n return withOverride(\"hardBreak\", defaultVNode);\n }\n\n case \"link\": {\n const safeHref = sanitizeHref(node.url);\n const attrs: Record<string, unknown> = {\n \"data-streaming-markdown-node\": \"link\",\n \"data-node-open\": String(!node.closed),\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n };\n if (safeHref != null) {\n attrs.href = safeHref;\n }\n if (node.title) {\n attrs.title = node.title;\n }\n const defaultVNode = h(\n \"a\",\n attrs,\n renderChildren(node.children, nodeById, nodeRenderers),\n );\n return withOverride(\"link\", defaultVNode);\n }\n\n case \"image\": {\n const safeSrc = sanitizeImgSrc(node.url);\n const attrs: Record<string, unknown> = {\n \"data-streaming-markdown-node\": \"image\",\n \"data-node-open\": String(!node.closed),\n alt: node.alt,\n };\n if (safeSrc != null) {\n attrs.src = safeSrc;\n }\n if (node.title) {\n attrs.title = node.title;\n }\n const defaultVNode = h(\"img\", attrs);\n return withOverride(\"image\", defaultVNode);\n }\n\n case \"autolink\": {\n const safeHref = sanitizeHref(node.url);\n const attrs: Record<string, unknown> = {\n \"data-streaming-markdown-node\": \"autolink\",\n \"data-node-open\": String(!node.closed),\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n };\n if (safeHref != null) {\n attrs.href = safeHref;\n }\n const defaultVNode = h(\"a\", attrs, node.text);\n return withOverride(\"autolink\", defaultVNode);\n }\n\n case \"citation\": {\n // Render as a superscript with the citation reference\n const defaultVNode = h(\n \"sup\",\n {\n \"data-streaming-markdown-node\": \"citation\",\n \"data-node-open\": String(!node.closed),\n class: \"cpk-streaming-markdown-citation\",\n },\n [\n h(\n \"span\",\n {\n role: \"doc-noteref\",\n class: \"cpk-streaming-markdown-citation-label\",\n },\n String(node.number ?? node.idRef),\n ),\n ],\n );\n return withOverride(\"citation\", defaultVNode);\n }\n\n default: {\n return null;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Vue component props types (exported for consumer use)\n// ---------------------------------------------------------------------------\n\n/**\n * Custom Vue render function for a specific AST node.\n * @public\n */\nexport type VueStreamingMarkdownNodeRenderer = (\n node: StreamingMarkdownAstNode,\n defaultVNode: VNode | string | null,\n) => VNode | string | null;\n\n/**\n * Supported key names for Vue `nodeRenderers`.\n * CamelCase, matching `StreamingMarkdownNodeRendererKey` on the React renderer.\n *\n * @public\n */\nexport type VueStreamingMarkdownNodeRendererKey =\n | \"paragraph\"\n | \"heading\"\n | \"blockquote\"\n | \"list\"\n | \"listItem\"\n | \"codeBlock\"\n | \"table\"\n | \"tableRow\"\n | \"tableCell\"\n | \"thematicBreak\"\n | \"em\"\n | \"strong\"\n | \"strikethrough\"\n | \"inlineCode\"\n | \"hardBreak\"\n | \"image\"\n | \"link\"\n | \"autolink\"\n | \"citation\";\n\n/**\n * Optional map of node-type renderer keys to custom Vue render functions.\n * @public\n */\nexport type VueStreamingMarkdownNodeRenderers = Partial<\n Record<VueStreamingMarkdownNodeRendererKey, VueStreamingMarkdownNodeRenderer>\n>;\n\n// ---------------------------------------------------------------------------\n// StreamingMarkdownRenderer — Vue 3 Composition API component (.ts)\n// ---------------------------------------------------------------------------\n\n/**\n * Vue 3 streaming markdown renderer.\n *\n * Drives the `@copilotkit/markdown` zero-dep parser and walks the\n * resulting AST into VNodes via `h()`.\n *\n * @public\n */\nexport const StreamingMarkdownRenderer = defineComponent({\n name: \"StreamingMarkdownRenderer\",\n\n props: {\n /** The full markdown source string, which may grow over time during streaming. */\n content: {\n type: String as PropType<string>,\n required: true,\n },\n /** When true, finalizes the parser state (end of stream). */\n isComplete: {\n type: Boolean as PropType<boolean>,\n default: false,\n },\n /** Optional parser option overrides. */\n options: {\n type: Object as PropType<Partial<StreamingMarkdownParserOptions>>,\n default: undefined,\n },\n /** Optional CSS class applied to the root wrapper element. */\n class: {\n type: String as PropType<string>,\n default: undefined,\n },\n /**\n * When true, renders a trailing cursor span after the last open node.\n * Animation niceties are left to CSS; this just inserts the element.\n */\n caret: {\n type: Boolean as PropType<boolean>,\n default: false,\n },\n /**\n * Optional map of node-type keys to custom Vue render functions.\n * Each function receives the AST node and the default VNode and can return\n * a replacement VNode (or the defaultVNode to keep the default).\n * Supported keys: paragraph, heading, blockquote, list, listItem, codeBlock,\n * table, tableRow, tableCell, thematicBreak, em, strong, strikethrough,\n * inlineCode, hardBreak, link, image, autolink, citation.\n */\n nodeRenderers: {\n type: Object as PropType<VueStreamingMarkdownNodeRenderers>,\n default: undefined,\n },\n },\n\n setup(props) {\n const parserState = computed<StreamingMarkdownParserState>(() => {\n const opts = normalizeOptions(props.options);\n return buildParserState(props.content ?? \"\", opts, props.isComplete);\n });\n\n const nodeById = computed<NodeById>(() => {\n const map = new Map<number, StreamingMarkdownAstNode>();\n for (const node of parserState.value.nodes) {\n map.set(node.id, node);\n }\n return map;\n });\n\n return () => {\n const state = parserState.value;\n const byId = nodeById.value;\n const rootNode =\n state.rootId != null ? byId.get(state.rootId) : undefined;\n const renderers = props.nodeRenderers;\n\n const rootClass = props.class\n ? `cpk-streaming-markdown-root ${props.class}`\n : \"cpk-streaming-markdown-root\";\n\n if (!rootNode) {\n return h(\"div\", {\n class: rootClass,\n \"data-streaming-markdown-root\": true,\n });\n }\n\n // Render children of document directly (skip the transparent document wrapper)\n const children: (VNode | string | null)[] =\n rootNode.type === \"document\"\n ? rootNode.children.map((id) => {\n const child = byId.get(id);\n return child ? renderNode(child, byId, renderers) : null;\n })\n : [renderNode(rootNode, byId, renderers)];\n\n // Append caret if requested and not complete\n if (props.caret && !state.isComplete) {\n children.push(\n h(\"span\", {\n \"aria-hidden\": true,\n class: \"cpk-streaming-markdown-caret\",\n \"data-streaming-markdown-caret\": true,\n style: {\n display: \"inline-block\",\n width: \"0.48em\",\n height: \"0.48em\",\n marginInlineStart: \"0.08em\",\n verticalAlign: \"-0.08em\",\n borderRadius: \"999px\",\n backgroundColor: \"currentColor\",\n opacity: \"0.55\",\n },\n }),\n );\n }\n\n return h(\n \"div\",\n {\n class: rootClass,\n \"data-streaming-markdown-root\": true,\n },\n children,\n );\n };\n },\n});\n"],"mappings":"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"}