@copilotkit/markdown 0.0.0-stage → 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,330 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
+ key = keys[i];
13
+ if (!__hasOwnProp.call(to, key) && key !== except) {
14
+ __defProp(to, key, {
15
+ get: ((k) => from[k]).bind(null, key),
16
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
+ });
18
+ }
19
+ }
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
24
+ value: mod,
25
+ enumerable: true
26
+ }) : target, mod));
27
+
28
+ //#endregion
29
+ let react = require("react");
30
+ react = __toESM(react);
31
+ let react_native = require("react-native");
32
+ let _copilotkit_markdown = require("@copilotkit/markdown");
33
+ let react_jsx_runtime = require("react/jsx-runtime");
34
+
35
+ //#region src/react-native/streaming-markdown-renderer.tsx
36
+ /**
37
+ * Default styles for all built-in node types.
38
+ *
39
+ * @public
40
+ */
41
+ const defaultMarkdownStyles = {
42
+ paragraph: {
43
+ fontSize: 16,
44
+ lineHeight: 24,
45
+ color: "#1a1a1a",
46
+ marginTop: 4,
47
+ marginBottom: 4
48
+ },
49
+ h1: {
50
+ fontSize: 24,
51
+ fontWeight: "bold",
52
+ marginTop: 12,
53
+ marginBottom: 8,
54
+ color: "#111111"
55
+ },
56
+ h2: {
57
+ fontSize: 20,
58
+ fontWeight: "bold",
59
+ marginTop: 10,
60
+ marginBottom: 6,
61
+ color: "#111111"
62
+ },
63
+ h3: {
64
+ fontSize: 18,
65
+ fontWeight: "600",
66
+ marginTop: 8,
67
+ marginBottom: 4,
68
+ color: "#222222"
69
+ },
70
+ h4: {
71
+ fontSize: 16,
72
+ fontWeight: "600",
73
+ marginTop: 6,
74
+ marginBottom: 4,
75
+ color: "#222222"
76
+ },
77
+ h5: {
78
+ fontSize: 14,
79
+ fontWeight: "600",
80
+ marginTop: 4,
81
+ marginBottom: 2,
82
+ color: "#333333"
83
+ },
84
+ h6: {
85
+ fontSize: 13,
86
+ fontWeight: "600",
87
+ marginTop: 4,
88
+ marginBottom: 2,
89
+ color: "#444444"
90
+ },
91
+ strong: { fontWeight: "bold" },
92
+ em: { fontStyle: "italic" },
93
+ strikethrough: { textDecorationLine: "line-through" },
94
+ inlineCode: {
95
+ backgroundColor: "#f0f0f0",
96
+ fontFamily: "monospace",
97
+ fontSize: 14
98
+ },
99
+ codeBlock: {
100
+ backgroundColor: "#f0f0f0",
101
+ borderRadius: 8,
102
+ padding: 12,
103
+ marginVertical: 4
104
+ },
105
+ codeBlockText: {
106
+ fontFamily: "monospace",
107
+ fontSize: 14,
108
+ color: "#1a1a1a"
109
+ },
110
+ blockquote: {
111
+ backgroundColor: "#f5f5f5",
112
+ borderLeftWidth: 4,
113
+ borderLeftColor: "#cccccc",
114
+ paddingLeft: 12,
115
+ marginVertical: 4
116
+ },
117
+ list: {
118
+ marginTop: 4,
119
+ marginBottom: 4
120
+ },
121
+ listItem: {
122
+ flexDirection: "row",
123
+ alignItems: "flex-start"
124
+ },
125
+ listBullet: {
126
+ marginRight: 6,
127
+ fontSize: 16,
128
+ lineHeight: 24
129
+ },
130
+ link: {
131
+ color: "#0066cc",
132
+ textDecorationLine: "underline"
133
+ },
134
+ image: {},
135
+ tableRow: {
136
+ flexDirection: "row",
137
+ borderBottomWidth: 1,
138
+ borderBottomColor: "#e0e0e0"
139
+ },
140
+ tableCell: {
141
+ flex: 1,
142
+ padding: 4
143
+ }
144
+ };
145
+ function renderChildren(node, ctx) {
146
+ return node.children.map((id) => {
147
+ const child = ctx.nodeById.get(id);
148
+ if (!child) return null;
149
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: renderNode(child, ctx) }, id);
150
+ });
151
+ }
152
+ function renderTextContent(node, ctx) {
153
+ return node.children.map((id) => {
154
+ const child = ctx.nodeById.get(id);
155
+ if (!child) return null;
156
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: renderInlineNode(child, ctx) }, id);
157
+ });
158
+ }
159
+ /**
160
+ * Render an inline node (text, strong, em, etc.) as a React Native `<Text>`.
161
+ * Returns `null` for block-level nodes that can't be nested in `<Text>`.
162
+ */
163
+ function renderInlineNode(node, ctx) {
164
+ switch (node.type) {
165
+ case "text": return node.text;
166
+ case "strong": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
167
+ style: ctx.s.strong,
168
+ children: renderTextContent(node, ctx)
169
+ }, node.id);
170
+ case "em": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
171
+ style: ctx.s.em,
172
+ children: renderTextContent(node, ctx)
173
+ }, node.id);
174
+ case "strikethrough": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
175
+ style: ctx.s.strikethrough,
176
+ children: renderTextContent(node, ctx)
177
+ }, node.id);
178
+ case "inline-code": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
179
+ style: ctx.s.inlineCode,
180
+ children: node.text
181
+ }, node.id);
182
+ case "link":
183
+ case "autolink": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
184
+ style: ctx.s.link,
185
+ children: "children" in node ? renderTextContent(node, ctx) : node.text
186
+ }, node.id);
187
+ case "image": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
188
+ style: ctx.s.image,
189
+ children: node.alt
190
+ }, node.id);
191
+ case "soft-break": return "\n";
192
+ case "hard-break": return "\n";
193
+ case "citation": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.Text, {
194
+ style: {
195
+ fontSize: 12,
196
+ verticalAlign: "top"
197
+ },
198
+ children: [
199
+ "[",
200
+ node.number ?? node.idRef,
201
+ "]"
202
+ ]
203
+ }, node.id);
204
+ default:
205
+ if ("text" in node && typeof node.text === "string") return node.text;
206
+ if ("children" in node) return renderTextContent(node, ctx);
207
+ return null;
208
+ }
209
+ }
210
+ function renderNode(node, ctx) {
211
+ switch (node.type) {
212
+ case "document": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: renderChildren(node, ctx) }, node.id);
213
+ case "paragraph": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
214
+ style: ctx.s.paragraph,
215
+ children: renderTextContent(node, ctx)
216
+ }, node.id);
217
+ case "heading": {
218
+ const level = node.level;
219
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
220
+ style: ctx.s[`h${level}`] ?? ctx.s.h6,
221
+ children: renderTextContent(node, ctx)
222
+ }, node.id);
223
+ }
224
+ case "blockquote": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
225
+ style: ctx.s.blockquote,
226
+ children: renderChildren(node, ctx)
227
+ }, node.id);
228
+ case "list": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
229
+ style: ctx.s.list,
230
+ children: node.children.map((itemId, index) => {
231
+ const item = ctx.nodeById.get(itemId);
232
+ if (!item) return null;
233
+ const bullet = node.ordered ? `${(node.start ?? 1) + index}. ` : "• ";
234
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
235
+ style: ctx.s.listItem,
236
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
237
+ style: ctx.s.listBullet,
238
+ children: bullet
239
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
240
+ style: { flex: 1 },
241
+ children: renderChildren(item, ctx)
242
+ })]
243
+ }, itemId);
244
+ })
245
+ }, node.id);
246
+ case "list-item": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
247
+ style: ctx.s.listItem,
248
+ children: renderChildren(node, ctx)
249
+ }, node.id);
250
+ case "code-block": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
251
+ style: ctx.s.codeBlock,
252
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
253
+ style: ctx.s.codeBlockText,
254
+ children: node.text
255
+ })
256
+ }, node.id);
257
+ case "table": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, { children: renderChildren(node, ctx) }, node.id);
258
+ case "table-row": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
259
+ style: ctx.s.tableRow,
260
+ children: renderChildren(node, ctx)
261
+ }, node.id);
262
+ case "table-cell": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
263
+ style: ctx.s.tableCell,
264
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, { children: renderTextContent(node, ctx) })
265
+ }, node.id);
266
+ case "thematic-break": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, { style: {
267
+ borderBottomWidth: 1,
268
+ borderBottomColor: "#e0e0e0",
269
+ marginVertical: 8
270
+ } }, node.id);
271
+ case "text": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, { children: node.text }, node.id);
272
+ case "strong":
273
+ case "em":
274
+ case "strikethrough":
275
+ case "inline-code":
276
+ case "link":
277
+ case "autolink":
278
+ case "image":
279
+ case "soft-break":
280
+ case "hard-break":
281
+ case "citation": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, { children: renderInlineNode(node, ctx) }, node.id);
282
+ default: return null;
283
+ }
284
+ }
285
+ function buildParserState(content, isComplete, animate) {
286
+ const parsed = (0, _copilotkit_markdown.parseStreamingMarkdownChunk)((0, _copilotkit_markdown.createStreamingMarkdownParserState)({
287
+ segmenter: animate,
288
+ enableTables: true,
289
+ enableAutolinks: true
290
+ }), content);
291
+ return isComplete ? (0, _copilotkit_markdown.finalizeStreamingMarkdown)(parsed) : parsed;
292
+ }
293
+ /**
294
+ * React Native streaming markdown renderer powered by the zero-dependency
295
+ * `@copilotkit/markdown` parser.
296
+ *
297
+ * Defaults `segmenter: false` — safe on Hermes which may not ship `Intl.Segmenter`.
298
+ * Pass `animate={true}` only when you have confirmed Segmenter availability.
299
+ *
300
+ * @public
301
+ */
302
+ function StreamingMarkdownRenderer({ content, isComplete = false, style, animate = false }) {
303
+ const mergedStyles = (0, react.useMemo)(() => style ? {
304
+ ...defaultMarkdownStyles,
305
+ ...style
306
+ } : defaultMarkdownStyles, [style]);
307
+ const parserState = (0, react.useMemo)(() => buildParserState(content ?? "", isComplete, animate), [
308
+ content,
309
+ isComplete,
310
+ animate
311
+ ]);
312
+ const nodeById = (0, react.useMemo)(() => {
313
+ const map = /* @__PURE__ */ new Map();
314
+ for (const node of parserState.nodes) map.set(node.id, node);
315
+ return map;
316
+ }, [parserState.nodes]);
317
+ const ctx = (0, react.useMemo)(() => ({
318
+ nodeById,
319
+ s: mergedStyles
320
+ }), [nodeById, mergedStyles]);
321
+ if (parserState.rootId == null) return null;
322
+ const rootNode = nodeById.get(parserState.rootId);
323
+ if (!rootNode) return null;
324
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: renderNode(rootNode, ctx) });
325
+ }
326
+
327
+ //#endregion
328
+ exports.StreamingMarkdownRenderer = StreamingMarkdownRenderer;
329
+ exports.defaultMarkdownStyles = defaultMarkdownStyles;
330
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["Fragment","Text","View"],"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,74 @@
1
+ import React from "react";
2
+
3
+ //#region src/react-native/streaming-markdown-renderer.d.ts
4
+ /**
5
+ * Style-object for the RN streaming markdown renderer.
6
+ * Every key is optional — defaults cover all built-in node types.
7
+ *
8
+ * @public
9
+ */
10
+ type MarkdownStyle = {
11
+ paragraph?: Record<string, unknown>;
12
+ h1?: Record<string, unknown>;
13
+ h2?: Record<string, unknown>;
14
+ h3?: Record<string, unknown>;
15
+ h4?: Record<string, unknown>;
16
+ h5?: Record<string, unknown>;
17
+ h6?: Record<string, unknown>;
18
+ strong?: Record<string, unknown>;
19
+ em?: Record<string, unknown>;
20
+ strikethrough?: Record<string, unknown>;
21
+ inlineCode?: Record<string, unknown>;
22
+ codeBlock?: Record<string, unknown>;
23
+ codeBlockText?: Record<string, unknown>;
24
+ blockquote?: Record<string, unknown>;
25
+ list?: Record<string, unknown>;
26
+ listItem?: Record<string, unknown>;
27
+ listBullet?: Record<string, unknown>;
28
+ link?: Record<string, unknown>;
29
+ image?: Record<string, unknown>;
30
+ tableRow?: Record<string, unknown>;
31
+ tableCell?: Record<string, unknown>;
32
+ };
33
+ /**
34
+ * Default styles for all built-in node types.
35
+ *
36
+ * @public
37
+ */
38
+ declare const defaultMarkdownStyles: MarkdownStyle;
39
+ /**
40
+ * Props for the React Native `StreamingMarkdownRenderer`.
41
+ *
42
+ * @public
43
+ */
44
+ interface StreamingMarkdownRendererProps {
45
+ /** Full markdown source (may grow over time during streaming). */
46
+ content: string;
47
+ /** When true, finalizes the parser state after processing content. */
48
+ isComplete?: boolean;
49
+ /** Style overrides merged with `defaultMarkdownStyles`. */
50
+ style?: MarkdownStyle;
51
+ /**
52
+ * When true, enables `Intl.Segmenter`-based per-token animation.
53
+ * Defaults to `false` — safe on Hermes which may not ship Segmenter.
54
+ */
55
+ animate?: boolean;
56
+ }
57
+ /**
58
+ * React Native streaming markdown renderer powered by the zero-dependency
59
+ * `@copilotkit/markdown` parser.
60
+ *
61
+ * Defaults `segmenter: false` — safe on Hermes which may not ship `Intl.Segmenter`.
62
+ * Pass `animate={true}` only when you have confirmed Segmenter availability.
63
+ *
64
+ * @public
65
+ */
66
+ declare function StreamingMarkdownRenderer({
67
+ content,
68
+ isComplete,
69
+ style,
70
+ animate
71
+ }: StreamingMarkdownRendererProps): React.ReactElement | null;
72
+ //#endregion
73
+ export { type MarkdownStyle, StreamingMarkdownRenderer, type StreamingMarkdownRendererProps, defaultMarkdownStyles };
74
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/react-native/streaming-markdown-renderer.tsx"],"mappings":";;;;;AAuBA;;;;KAAY,aAAA;EACV,SAAA,GAAY,MAAA;EACZ,EAAA,GAAK,MAAA;EACL,EAAA,GAAK,MAAA;EACL,EAAA,GAAK,MAAA;EACL,EAAA,GAAK,MAAA;EACL,EAAA,GAAK,MAAA;EACL,EAAA,GAAK,MAAA;EACL,MAAA,GAAS,MAAA;EACT,EAAA,GAAK,MAAA;EACL,aAAA,GAAgB,MAAA;EAChB,UAAA,GAAa,MAAA;EACb,SAAA,GAAY,MAAA;EACZ,aAAA,GAAgB,MAAA;EAChB,UAAA,GAAa,MAAA;EACb,IAAA,GAAO,MAAA;EACP,QAAA,GAAW,MAAA;EACX,UAAA,GAAa,MAAA;EACb,IAAA,GAAO,MAAA;EACP,KAAA,GAAQ,MAAA;EACR,QAAA,GAAW,MAAA;EACX,SAAA,GAAY,MAAA;AAAA;;;;;;cAQD,qBAAA,EAAuB,aAAA;;;;;;UAkGnB,8BAAA;EAxHV;EA0HL,OAAA;EAzHS;EA2HT,UAAA;EA1HK;EA4HL,KAAA,GAAQ,aAAA;EA3HQ;;;;EAgIhB,OAAA;AAAA;;;;;;;;;;iBAsRc,yBAAA,CAAA;EACd,OAAA;EACA,UAAA;EACA,KAAA;EACA;AAAA,GACC,8BAAA,GAAiC,KAAA,CAAM,YAAA"}
@@ -0,0 +1,74 @@
1
+ import React from "react";
2
+
3
+ //#region src/react-native/streaming-markdown-renderer.d.ts
4
+ /**
5
+ * Style-object for the RN streaming markdown renderer.
6
+ * Every key is optional — defaults cover all built-in node types.
7
+ *
8
+ * @public
9
+ */
10
+ type MarkdownStyle = {
11
+ paragraph?: Record<string, unknown>;
12
+ h1?: Record<string, unknown>;
13
+ h2?: Record<string, unknown>;
14
+ h3?: Record<string, unknown>;
15
+ h4?: Record<string, unknown>;
16
+ h5?: Record<string, unknown>;
17
+ h6?: Record<string, unknown>;
18
+ strong?: Record<string, unknown>;
19
+ em?: Record<string, unknown>;
20
+ strikethrough?: Record<string, unknown>;
21
+ inlineCode?: Record<string, unknown>;
22
+ codeBlock?: Record<string, unknown>;
23
+ codeBlockText?: Record<string, unknown>;
24
+ blockquote?: Record<string, unknown>;
25
+ list?: Record<string, unknown>;
26
+ listItem?: Record<string, unknown>;
27
+ listBullet?: Record<string, unknown>;
28
+ link?: Record<string, unknown>;
29
+ image?: Record<string, unknown>;
30
+ tableRow?: Record<string, unknown>;
31
+ tableCell?: Record<string, unknown>;
32
+ };
33
+ /**
34
+ * Default styles for all built-in node types.
35
+ *
36
+ * @public
37
+ */
38
+ declare const defaultMarkdownStyles: MarkdownStyle;
39
+ /**
40
+ * Props for the React Native `StreamingMarkdownRenderer`.
41
+ *
42
+ * @public
43
+ */
44
+ interface StreamingMarkdownRendererProps {
45
+ /** Full markdown source (may grow over time during streaming). */
46
+ content: string;
47
+ /** When true, finalizes the parser state after processing content. */
48
+ isComplete?: boolean;
49
+ /** Style overrides merged with `defaultMarkdownStyles`. */
50
+ style?: MarkdownStyle;
51
+ /**
52
+ * When true, enables `Intl.Segmenter`-based per-token animation.
53
+ * Defaults to `false` — safe on Hermes which may not ship Segmenter.
54
+ */
55
+ animate?: boolean;
56
+ }
57
+ /**
58
+ * React Native streaming markdown renderer powered by the zero-dependency
59
+ * `@copilotkit/markdown` parser.
60
+ *
61
+ * Defaults `segmenter: false` — safe on Hermes which may not ship `Intl.Segmenter`.
62
+ * Pass `animate={true}` only when you have confirmed Segmenter availability.
63
+ *
64
+ * @public
65
+ */
66
+ declare function StreamingMarkdownRenderer({
67
+ content,
68
+ isComplete,
69
+ style,
70
+ animate
71
+ }: StreamingMarkdownRendererProps): React.ReactElement | null;
72
+ //#endregion
73
+ export { type MarkdownStyle, StreamingMarkdownRenderer, type StreamingMarkdownRendererProps, defaultMarkdownStyles };
74
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/react-native/streaming-markdown-renderer.tsx"],"mappings":";;;;;AAuBA;;;;KAAY,aAAA;EACV,SAAA,GAAY,MAAA;EACZ,EAAA,GAAK,MAAA;EACL,EAAA,GAAK,MAAA;EACL,EAAA,GAAK,MAAA;EACL,EAAA,GAAK,MAAA;EACL,EAAA,GAAK,MAAA;EACL,EAAA,GAAK,MAAA;EACL,MAAA,GAAS,MAAA;EACT,EAAA,GAAK,MAAA;EACL,aAAA,GAAgB,MAAA;EAChB,UAAA,GAAa,MAAA;EACb,SAAA,GAAY,MAAA;EACZ,aAAA,GAAgB,MAAA;EAChB,UAAA,GAAa,MAAA;EACb,IAAA,GAAO,MAAA;EACP,QAAA,GAAW,MAAA;EACX,UAAA,GAAa,MAAA;EACb,IAAA,GAAO,MAAA;EACP,KAAA,GAAQ,MAAA;EACR,QAAA,GAAW,MAAA;EACX,SAAA,GAAY,MAAA;AAAA;;;;;;cAQD,qBAAA,EAAuB,aAAA;;;;;;UAkGnB,8BAAA;EAxHV;EA0HL,OAAA;EAzHS;EA2HT,UAAA;EA1HK;EA4HL,KAAA,GAAQ,aAAA;EA3HQ;;;;EAgIhB,OAAA;AAAA;;;;;;;;;;iBAsRc,yBAAA,CAAA;EACd,OAAA;EACA,UAAA;EACA,KAAA;EACA;AAAA,GACC,8BAAA,GAAiC,KAAA,CAAM,YAAA"}