@copilotkit/markdown 2.0.0-rc.20 → 2.0.0-rc.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -7
- package/dist/dom/index.cjs +255 -0
- package/dist/dom/index.cjs.map +1 -0
- package/dist/dom/index.d.cts +93 -0
- package/dist/dom/index.d.cts.map +1 -0
- package/dist/dom/index.d.mts +93 -0
- package/dist/dom/index.d.mts.map +1 -0
- package/dist/dom/index.mjs +254 -0
- package/dist/dom/index.mjs.map +1 -0
- package/dist/index.cjs +522 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +271 -4
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +271 -4
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +512 -12
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.cjs +66 -458
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +13 -22
- package/dist/react/index.d.cts.map +1 -1
- package/dist/react/index.d.mts +13 -22
- package/dist/react/index.d.mts.map +1 -1
- package/dist/react/index.mjs +67 -459
- package/dist/react/index.mjs.map +1 -1
- package/dist/react-native/index.cjs.map +1 -1
- package/dist/react-native/index.d.cts.map +1 -1
- package/dist/react-native/index.d.mts.map +1 -1
- package/dist/react-native/index.mjs.map +1 -1
- package/dist/vue/index.cjs +86 -199
- package/dist/vue/index.cjs.map +1 -1
- package/dist/vue/index.d.cts +46 -16
- package/dist/vue/index.d.cts.map +1 -1
- package/dist/vue/index.d.mts +46 -16
- package/dist/vue/index.d.mts.map +1 -1
- package/dist/vue/index.mjs +88 -201
- package/dist/vue/index.mjs.map +1 -1
- package/package.json +6 -2
package/dist/react/index.cjs
CHANGED
|
@@ -1,68 +1,9 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
let react = require("react");
|
|
3
2
|
let _copilotkit_markdown = require("@copilotkit/markdown");
|
|
3
|
+
let react = require("react");
|
|
4
4
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
5
5
|
|
|
6
6
|
//#region src/react/use-streaming-markdown-parser.tsx
|
|
7
|
-
const DEFAULT_OPTIONS = {
|
|
8
|
-
segmenter: true,
|
|
9
|
-
enableTables: true,
|
|
10
|
-
enableAutolinks: true
|
|
11
|
-
};
|
|
12
|
-
function normalizeOptions(options) {
|
|
13
|
-
return {
|
|
14
|
-
segmenter: options?.segmenter ?? DEFAULT_OPTIONS.segmenter,
|
|
15
|
-
enableTables: options?.enableTables ?? DEFAULT_OPTIONS.enableTables,
|
|
16
|
-
enableAutolinks: options?.enableAutolinks ?? DEFAULT_OPTIONS.enableAutolinks
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
function getSegmenterKey(segmenter) {
|
|
20
|
-
if (segmenter === true || segmenter === false) return String(segmenter);
|
|
21
|
-
return `object:${segmenter.locale ?? ""}:${segmenter.granularity ?? "word"}`;
|
|
22
|
-
}
|
|
23
|
-
function getOptionsKey(options) {
|
|
24
|
-
return `${getSegmenterKey(options.segmenter)}|tables:${String(options.enableTables)}|autolinks:${String(options.enableAutolinks)}`;
|
|
25
|
-
}
|
|
26
|
-
function parseFullText(text, options, isCompleteInput) {
|
|
27
|
-
const initialState = (0, _copilotkit_markdown.createStreamingMarkdownParserState)(options);
|
|
28
|
-
const parsedState = text.length > 0 ? (0, _copilotkit_markdown.parseStreamingMarkdownChunk)(initialState, text) : initialState;
|
|
29
|
-
return isCompleteInput ? (0, _copilotkit_markdown.finalizeStreamingMarkdown)(parsedState) : parsedState;
|
|
30
|
-
}
|
|
31
|
-
function createSession(text, options, optionsKey, isCompleteInput) {
|
|
32
|
-
return {
|
|
33
|
-
parserState: parseFullText(text, options, isCompleteInput),
|
|
34
|
-
text,
|
|
35
|
-
optionsKey,
|
|
36
|
-
isCompleteInput
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
function resolveNextSession(previous, text, options, optionsKey, isCompleteInput) {
|
|
40
|
-
const optionsChanged = previous.optionsKey !== optionsKey;
|
|
41
|
-
const completionChanged = previous.isCompleteInput !== isCompleteInput;
|
|
42
|
-
if (optionsChanged) return createSession(text, options, optionsKey, isCompleteInput);
|
|
43
|
-
const textChanged = text !== previous.text;
|
|
44
|
-
if (!textChanged && !completionChanged) return previous;
|
|
45
|
-
if (!textChanged && completionChanged) {
|
|
46
|
-
const parserState = isCompleteInput ? (0, _copilotkit_markdown.finalizeStreamingMarkdown)(previous.parserState) : (0, _copilotkit_markdown.parseStreamingMarkdownChunk)(previous.parserState, "");
|
|
47
|
-
return {
|
|
48
|
-
...previous,
|
|
49
|
-
parserState,
|
|
50
|
-
isCompleteInput
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
let nextParserState;
|
|
54
|
-
if (text.startsWith(previous.text)) {
|
|
55
|
-
const suffix = text.slice(previous.text.length);
|
|
56
|
-
nextParserState = suffix.length > 0 ? (0, _copilotkit_markdown.parseStreamingMarkdownChunk)(previous.parserState, suffix) : previous.parserState;
|
|
57
|
-
} else nextParserState = parseFullText(text, options, false);
|
|
58
|
-
if (isCompleteInput) nextParserState = (0, _copilotkit_markdown.finalizeStreamingMarkdown)(nextParserState);
|
|
59
|
-
return {
|
|
60
|
-
parserState: nextParserState,
|
|
61
|
-
text,
|
|
62
|
-
optionsKey,
|
|
63
|
-
isCompleteInput
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
7
|
/**
|
|
67
8
|
* Internal prop-driven hook for streaming markdown parsing in React.
|
|
68
9
|
*
|
|
@@ -73,42 +14,19 @@ function resolveNextSession(previous, text, options, optionsKey, isCompleteInput
|
|
|
73
14
|
*/
|
|
74
15
|
function useStreamingMarkdownParser(text, options, isCompleteInput = false) {
|
|
75
16
|
const sessionRef = (0, react.useRef)(null);
|
|
76
|
-
const segmenter = options?.segmenter;
|
|
77
|
-
const segmenterKind = typeof segmenter === "object" && segmenter !== null ? "object" : String(segmenter ?? true);
|
|
78
|
-
const segmenterLocale = typeof segmenter === "object" && segmenter !== null ? segmenter.locale ?? "" : "";
|
|
79
|
-
const segmenterGranularity = typeof segmenter === "object" && segmenter !== null ? segmenter.granularity ?? "word" : "";
|
|
80
|
-
const normalizedOptions = (0, react.useMemo)(() => normalizeOptions(options), [
|
|
81
|
-
options?.enableAutolinks,
|
|
82
|
-
options?.enableTables,
|
|
83
|
-
segmenterKind,
|
|
84
|
-
segmenterLocale,
|
|
85
|
-
segmenterGranularity
|
|
86
|
-
]);
|
|
87
|
-
const optionsKey = getOptionsKey(normalizedOptions);
|
|
88
17
|
return (0, react.useMemo)(() => {
|
|
89
|
-
const next =
|
|
18
|
+
const next = (0, _copilotkit_markdown.updateStreamingMarkdownParserSession)(sessionRef.current, text, options, isCompleteInput);
|
|
90
19
|
sessionRef.current = next;
|
|
91
20
|
return next;
|
|
92
21
|
}, [
|
|
93
22
|
text,
|
|
94
|
-
|
|
95
|
-
optionsKey,
|
|
23
|
+
options,
|
|
96
24
|
isCompleteInput
|
|
97
25
|
]).parserState;
|
|
98
26
|
}
|
|
99
27
|
|
|
100
28
|
//#endregion
|
|
101
29
|
//#region src/react/streaming-markdown-renderer.tsx
|
|
102
|
-
const SAFE_HREF = /^(https?:|mailto:|tel:|#|\/|\.\/|\.\.\/)/i;
|
|
103
|
-
const SAFE_IMG_SRC = /^(https?:|data:image\/(?!svg)|\/|\.\/|\.\.\/)/i;
|
|
104
|
-
function sanitizeHref(href) {
|
|
105
|
-
if (!href) return void 0;
|
|
106
|
-
return SAFE_HREF.test(href.trim()) ? href : void 0;
|
|
107
|
-
}
|
|
108
|
-
function sanitizeImgSrc(src) {
|
|
109
|
-
if (!src) return void 0;
|
|
110
|
-
return SAFE_IMG_SRC.test(src.trim()) ? src : void 0;
|
|
111
|
-
}
|
|
112
30
|
/**
|
|
113
31
|
* Helper for creating typed streaming markdown node renderer maps.
|
|
114
32
|
*
|
|
@@ -117,128 +35,10 @@ function sanitizeImgSrc(src) {
|
|
|
117
35
|
function createStreamingMarkdownNodeRenderers(renderers) {
|
|
118
36
|
return renderers;
|
|
119
37
|
}
|
|
120
|
-
const WORD_JOINER = "";
|
|
121
|
-
const DEFAULT_ROOT_CLASS = "cpk-streaming-markdown-root";
|
|
122
|
-
const DEFAULT_CITATION_CLASS = "cpk-streaming-markdown-citation";
|
|
123
|
-
const DEFAULT_CITATION_LABEL_CLASS = "cpk-streaming-markdown-citation-label";
|
|
124
|
-
const DEFAULT_STYLES = `
|
|
125
|
-
.${DEFAULT_ROOT_CLASS} .cpk-streaming-markdown-segment {
|
|
126
|
-
opacity: 1;
|
|
127
|
-
transition: opacity 400ms ease-out;
|
|
128
|
-
@starting-style {
|
|
129
|
-
opacity: 0;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
.${DEFAULT_ROOT_CLASS} .${DEFAULT_CITATION_CLASS} {
|
|
134
|
-
vertical-align: baseline;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
.${DEFAULT_ROOT_CLASS} .${DEFAULT_CITATION_LABEL_CLASS} {
|
|
138
|
-
display: inline-flex;
|
|
139
|
-
align-items: center;
|
|
140
|
-
justify-content: center;
|
|
141
|
-
inline-size: 1.4em;
|
|
142
|
-
block-size: 1.4em;
|
|
143
|
-
border-radius: 999px;
|
|
144
|
-
border: 1px solid hsl(0 0% 50% / 0.35);
|
|
145
|
-
background-color: hsl(0 0% 50% / 0.16);
|
|
146
|
-
color: inherit;
|
|
147
|
-
font-size: 0.7em;
|
|
148
|
-
line-height: 1;
|
|
149
|
-
font-variant-numeric: tabular-nums;
|
|
150
|
-
text-decoration: none;
|
|
151
|
-
transform: translateY(-0.15em);
|
|
152
|
-
}
|
|
153
|
-
`;
|
|
154
|
-
const DEFAULT_STYLES_FALLBACK = `
|
|
155
|
-
.${DEFAULT_ROOT_CLASS} .cpk-streaming-markdown-segment {
|
|
156
|
-
opacity: 1;
|
|
157
|
-
transition: opacity 400ms ease-out;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
.${DEFAULT_ROOT_CLASS} .${DEFAULT_CITATION_CLASS} {
|
|
161
|
-
vertical-align: baseline;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
.${DEFAULT_ROOT_CLASS} .${DEFAULT_CITATION_LABEL_CLASS} {
|
|
165
|
-
display: inline-flex;
|
|
166
|
-
align-items: center;
|
|
167
|
-
justify-content: center;
|
|
168
|
-
inline-size: 1.4em;
|
|
169
|
-
block-size: 1.4em;
|
|
170
|
-
border-radius: 999px;
|
|
171
|
-
border: 1px solid hsl(0 0% 50% / 0.35);
|
|
172
|
-
background-color: hsl(0 0% 50% / 0.16);
|
|
173
|
-
color: inherit;
|
|
174
|
-
font-size: 0.7em;
|
|
175
|
-
line-height: 1;
|
|
176
|
-
font-variant-numeric: tabular-nums;
|
|
177
|
-
text-decoration: none;
|
|
178
|
-
transform: translateY(-0.15em);
|
|
179
|
-
}
|
|
180
|
-
`;
|
|
181
|
-
const NODE_TYPE_TO_RENDERER_KEY = {
|
|
182
|
-
document: "document",
|
|
183
|
-
paragraph: "paragraph",
|
|
184
|
-
heading: "heading",
|
|
185
|
-
blockquote: "blockquote",
|
|
186
|
-
list: "list",
|
|
187
|
-
"list-item": "listItem",
|
|
188
|
-
"code-block": "codeBlock",
|
|
189
|
-
table: "table",
|
|
190
|
-
"table-row": "tableRow",
|
|
191
|
-
"table-cell": "tableCell",
|
|
192
|
-
"thematic-break": "thematicBreak",
|
|
193
|
-
text: "text",
|
|
194
|
-
em: "em",
|
|
195
|
-
strong: "strong",
|
|
196
|
-
strikethrough: "strikethrough",
|
|
197
|
-
"inline-code": "inlineCode",
|
|
198
|
-
"soft-break": "softBreak",
|
|
199
|
-
"hard-break": "hardBreak",
|
|
200
|
-
image: "image",
|
|
201
|
-
link: "link",
|
|
202
|
-
autolink: "autolink",
|
|
203
|
-
citation: "citation"
|
|
204
|
-
};
|
|
205
|
-
function renderWithOverride(node, context, defaultNode, children = null, citation) {
|
|
206
|
-
const rendererKey = NODE_TYPE_TO_RENDERER_KEY[node.type];
|
|
207
|
-
const renderer = context.nodeRenderers?.[rendererKey] ?? context.nodeRenderers?.node;
|
|
208
|
-
if (!renderer) return defaultNode;
|
|
209
|
-
return renderer({
|
|
210
|
-
node,
|
|
211
|
-
children,
|
|
212
|
-
defaultNode,
|
|
213
|
-
citation
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
function renderChildren(node, context) {
|
|
217
|
-
return node.children.map((childId) => {
|
|
218
|
-
const childNode = context.nodeById.get(childId);
|
|
219
|
-
if (!childNode) return null;
|
|
220
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: renderNode(childNode, context) }, childId);
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
function renderCaret(nodeId, context) {
|
|
224
|
-
if (context.caretTargetNodeId !== nodeId) return null;
|
|
225
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: context.caretNode }, `caret-${nodeId}`);
|
|
226
|
-
}
|
|
227
38
|
function renderDefaultCaret() {
|
|
228
39
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
"data-streaming-markdown-caret": true,
|
|
232
|
-
style: {
|
|
233
|
-
display: "inline-block",
|
|
234
|
-
width: "0.48em",
|
|
235
|
-
height: "0.48em",
|
|
236
|
-
marginInlineStart: "0.08em",
|
|
237
|
-
verticalAlign: "-0.08em",
|
|
238
|
-
borderRadius: "999px",
|
|
239
|
-
backgroundColor: "currentColor",
|
|
240
|
-
opacity: .55
|
|
241
|
-
}
|
|
40
|
+
..._copilotkit_markdown.STREAMING_MARKDOWN_CARET_ATTRS,
|
|
41
|
+
style: _copilotkit_markdown.STREAMING_MARKDOWN_CARET_STYLE
|
|
242
42
|
});
|
|
243
43
|
}
|
|
244
44
|
function resolveCaretNode(caret, props) {
|
|
@@ -247,289 +47,97 @@ function resolveCaretNode(caret, props) {
|
|
|
247
47
|
if (typeof caret === "function") return caret(props);
|
|
248
48
|
return caret;
|
|
249
49
|
}
|
|
250
|
-
function
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
return node.segments.map((segment) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
259
|
-
className: "cpk-streaming-markdown-segment",
|
|
260
|
-
"data-streaming-markdown-segment-kind": segment.kind,
|
|
261
|
-
"data-streaming-markdown-whitespace": String(segment.isWhitespace),
|
|
262
|
-
children: segment.noBreakBefore ? `${WORD_JOINER}${segment.text}` : segment.text
|
|
263
|
-
}, `segment-${node.id}-${segment.start}-${segment.kind}`));
|
|
264
|
-
}
|
|
265
|
-
function handleLinkClick(context, node, url) {
|
|
266
|
-
return (event) => {
|
|
267
|
-
context.onLinkClickRef.current?.(event, url, node);
|
|
50
|
+
function toReactProps(element, context) {
|
|
51
|
+
const props = { key: element.key };
|
|
52
|
+
const entries = Object.entries(element.attrs);
|
|
53
|
+
for (const [name, value] of entries) props[name === "class" ? "className" : name] = value;
|
|
54
|
+
if (element.tag === "input") props.readOnly = true;
|
|
55
|
+
const action = element.action;
|
|
56
|
+
if (action?.type === "link") props.onClick = (event) => {
|
|
57
|
+
context.onLinkClickRef.current?.(event, action.url, action.node);
|
|
268
58
|
};
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
const number = node.number ?? context.citations.numbers[node.idRef] ?? node.idRef;
|
|
272
|
-
const definition = context.citations.definitions[node.idRef];
|
|
273
|
-
return {
|
|
274
|
-
id: node.idRef,
|
|
275
|
-
number,
|
|
276
|
-
definition
|
|
59
|
+
if (action?.type === "citation") props.onClick = (event) => {
|
|
60
|
+
context.onCitationClickRef.current?.(event, action.citation, action.node);
|
|
277
61
|
};
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
"
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
},
|
|
305
|
-
children: label
|
|
306
|
-
})
|
|
307
|
-
}, node.id);
|
|
308
|
-
}
|
|
309
|
-
function renderContainerNode(node, context) {
|
|
310
|
-
const children = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [renderChildren(node, context), renderCaret(node.id, context)] });
|
|
311
|
-
if (node.type === "document") return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children }, node.id), children);
|
|
312
|
-
if (node.type === "paragraph") return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
313
|
-
"data-streaming-markdown-node": node.type,
|
|
314
|
-
"data-node-open": String(!node.closed),
|
|
315
|
-
children
|
|
316
|
-
}, node.id), children);
|
|
317
|
-
if (node.type === "heading") {
|
|
318
|
-
const headingTag = `h${node.level}`;
|
|
319
|
-
return renderWithOverride(node, context, headingTag === "h1" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
|
|
320
|
-
"data-streaming-markdown-node": node.type,
|
|
321
|
-
"data-node-open": String(!node.closed),
|
|
322
|
-
children
|
|
323
|
-
}, node.id) : headingTag === "h2" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
324
|
-
"data-streaming-markdown-node": node.type,
|
|
325
|
-
"data-node-open": String(!node.closed),
|
|
326
|
-
children
|
|
327
|
-
}, node.id) : headingTag === "h3" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
328
|
-
"data-streaming-markdown-node": node.type,
|
|
329
|
-
"data-node-open": String(!node.closed),
|
|
330
|
-
children
|
|
331
|
-
}, node.id) : headingTag === "h4" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
332
|
-
"data-streaming-markdown-node": node.type,
|
|
333
|
-
"data-node-open": String(!node.closed),
|
|
334
|
-
children
|
|
335
|
-
}, node.id) : headingTag === "h5" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h5", {
|
|
336
|
-
"data-streaming-markdown-node": node.type,
|
|
337
|
-
"data-node-open": String(!node.closed),
|
|
338
|
-
children
|
|
339
|
-
}, node.id) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h6", {
|
|
340
|
-
"data-streaming-markdown-node": node.type,
|
|
341
|
-
"data-node-open": String(!node.closed),
|
|
342
|
-
children
|
|
343
|
-
}, node.id), children);
|
|
344
|
-
}
|
|
345
|
-
if (node.type === "blockquote") return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("blockquote", {
|
|
346
|
-
"data-streaming-markdown-node": node.type,
|
|
347
|
-
"data-node-open": String(!node.closed),
|
|
348
|
-
children
|
|
349
|
-
}, node.id), children);
|
|
350
|
-
if (node.type === "list") {
|
|
351
|
-
if (node.ordered) return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ol", {
|
|
352
|
-
start: node.start ?? void 0,
|
|
353
|
-
"data-streaming-markdown-node": node.type,
|
|
354
|
-
"data-node-open": String(!node.closed),
|
|
355
|
-
"data-list-tight": String(node.tight),
|
|
356
|
-
children
|
|
357
|
-
}, node.id), children);
|
|
358
|
-
return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
359
|
-
"data-streaming-markdown-node": node.type,
|
|
360
|
-
"data-node-open": String(!node.closed),
|
|
361
|
-
"data-list-tight": String(node.tight),
|
|
362
|
-
children
|
|
363
|
-
}, node.id), children);
|
|
364
|
-
}
|
|
365
|
-
if (node.type === "list-item") return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
366
|
-
"data-streaming-markdown-node": node.type,
|
|
367
|
-
"data-node-open": String(!node.closed),
|
|
368
|
-
children
|
|
369
|
-
}, node.id), children);
|
|
370
|
-
if (node.type === "table") return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("table", {
|
|
371
|
-
"data-streaming-markdown-node": node.type,
|
|
372
|
-
"data-node-open": String(!node.closed),
|
|
373
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children })
|
|
374
|
-
}, node.id), children);
|
|
375
|
-
if (node.type === "table-row") return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", {
|
|
376
|
-
"data-streaming-markdown-node": node.type,
|
|
377
|
-
"data-node-open": String(!node.closed),
|
|
378
|
-
children
|
|
379
|
-
}, node.id), children);
|
|
380
|
-
if (node.type === "table-cell") {
|
|
381
|
-
const parent = node.parentId == null ? void 0 : context.nodeById.get(node.parentId);
|
|
382
|
-
if (parent?.type === "table-row" && parent.isHeader) return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
|
|
383
|
-
"data-streaming-markdown-node": node.type,
|
|
384
|
-
"data-node-open": String(!node.closed),
|
|
385
|
-
children
|
|
386
|
-
}, node.id), children);
|
|
387
|
-
return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
|
|
388
|
-
"data-streaming-markdown-node": node.type,
|
|
389
|
-
"data-node-open": String(!node.closed),
|
|
390
|
-
children
|
|
391
|
-
}, node.id), children);
|
|
62
|
+
return props;
|
|
63
|
+
}
|
|
64
|
+
const VOID_TAGS = new Set([
|
|
65
|
+
"br",
|
|
66
|
+
"hr",
|
|
67
|
+
"img",
|
|
68
|
+
"input"
|
|
69
|
+
]);
|
|
70
|
+
function renderList(children, context, slot) {
|
|
71
|
+
return children.map((child) => renderChild(child, context, slot));
|
|
72
|
+
}
|
|
73
|
+
/** Unwraps single-entry lists so overrides see `"text"` rather than `["text"]`. */
|
|
74
|
+
function collapse(nodes) {
|
|
75
|
+
return nodes.length === 1 ? nodes[0] : nodes;
|
|
76
|
+
}
|
|
77
|
+
function renderChild(child, context, slot) {
|
|
78
|
+
switch (child.kind) {
|
|
79
|
+
case "node": return renderRenderNode(child, context);
|
|
80
|
+
case "element": {
|
|
81
|
+
const props = toReactProps(child, context);
|
|
82
|
+
return VOID_TAGS.has(child.tag) ? (0, react.createElement)(child.tag, props) : (0, react.createElement)(child.tag, props, ...renderList(child.children, context, slot));
|
|
83
|
+
}
|
|
84
|
+
case "text": return child.text;
|
|
85
|
+
case "caret": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: context.caretNode }, child.key);
|
|
86
|
+
case "slot": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: slot }, child.key);
|
|
87
|
+
default: return child;
|
|
392
88
|
}
|
|
393
|
-
if (node.type === "em") return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("em", {
|
|
394
|
-
"data-streaming-markdown-node": node.type,
|
|
395
|
-
"data-node-open": String(!node.closed),
|
|
396
|
-
children
|
|
397
|
-
}, node.id), children);
|
|
398
|
-
if (node.type === "strong") return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
399
|
-
"data-streaming-markdown-node": node.type,
|
|
400
|
-
"data-node-open": String(!node.closed),
|
|
401
|
-
children
|
|
402
|
-
}, node.id), children);
|
|
403
|
-
if (node.type === "strikethrough") return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("s", {
|
|
404
|
-
"data-streaming-markdown-node": node.type,
|
|
405
|
-
"data-node-open": String(!node.closed),
|
|
406
|
-
children
|
|
407
|
-
}, node.id), children);
|
|
408
|
-
const href = sanitizeHref(node.url);
|
|
409
|
-
return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
410
|
-
href,
|
|
411
|
-
target: "_blank",
|
|
412
|
-
rel: "noopener noreferrer",
|
|
413
|
-
title: node.title,
|
|
414
|
-
onClick: href ? handleLinkClick(context, node, href) : void 0,
|
|
415
|
-
"data-streaming-markdown-node": node.type,
|
|
416
|
-
"data-node-open": String(!node.closed),
|
|
417
|
-
children
|
|
418
|
-
}, node.id), children);
|
|
419
89
|
}
|
|
420
|
-
function renderNode
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
},
|
|
430
|
-
if (node.type === "thematic-break") return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("hr", {
|
|
431
|
-
"data-streaming-markdown-node": node.type,
|
|
432
|
-
"data-node-open": String(!node.closed)
|
|
433
|
-
}, node.id));
|
|
434
|
-
if (node.type === "text") {
|
|
435
|
-
const children = renderTextSegments(node);
|
|
436
|
-
return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children }, node.id), children);
|
|
437
|
-
}
|
|
438
|
-
if (node.type === "inline-code") return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
439
|
-
"data-streaming-markdown-node": node.type,
|
|
440
|
-
"data-node-open": String(!node.closed),
|
|
441
|
-
children: node.text
|
|
442
|
-
}, node.id), node.text);
|
|
443
|
-
if (node.type === "soft-break") {
|
|
444
|
-
const children = "\n";
|
|
445
|
-
return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children }, node.id), children);
|
|
446
|
-
}
|
|
447
|
-
if (node.type === "hard-break") return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("br", {
|
|
448
|
-
"data-streaming-markdown-node": node.type,
|
|
449
|
-
"data-node-open": String(!node.closed)
|
|
450
|
-
}, node.id));
|
|
451
|
-
if (node.type === "image") return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
452
|
-
src: sanitizeImgSrc(node.url),
|
|
453
|
-
alt: node.alt,
|
|
454
|
-
title: node.title,
|
|
455
|
-
"data-streaming-markdown-node": node.type,
|
|
456
|
-
"data-node-open": String(!node.closed)
|
|
457
|
-
}, node.id));
|
|
458
|
-
if (node.type === "autolink") {
|
|
459
|
-
const href = sanitizeHref(node.url);
|
|
460
|
-
return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
461
|
-
href,
|
|
462
|
-
target: "_blank",
|
|
463
|
-
rel: "noopener noreferrer",
|
|
464
|
-
onClick: href ? handleLinkClick(context, node, href) : void 0,
|
|
465
|
-
"data-streaming-markdown-node": node.type,
|
|
466
|
-
"data-node-open": String(!node.closed),
|
|
467
|
-
children: node.text
|
|
468
|
-
}, node.id), node.text);
|
|
469
|
-
}
|
|
470
|
-
const citation = getCitationRenderData(node, context);
|
|
471
|
-
return renderWithOverride(node, context, renderDefaultCitation(node, context, citation), null, citation);
|
|
90
|
+
function renderRenderNode(renderNode, context) {
|
|
91
|
+
const children = renderNode.children === null ? null : collapse(renderList(renderNode.children, context, null));
|
|
92
|
+
const defaultNode = collapse(renderList(renderNode.output, context, children));
|
|
93
|
+
const renderer = context.nodeRenderers?.[renderNode.rendererKey] ?? context.nodeRenderers?.node;
|
|
94
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: renderer ? renderer({
|
|
95
|
+
node: renderNode.node,
|
|
96
|
+
children,
|
|
97
|
+
defaultNode,
|
|
98
|
+
citation: renderNode.citation
|
|
99
|
+
}) : defaultNode }, renderNode.key);
|
|
472
100
|
}
|
|
473
101
|
/**
|
|
474
102
|
* React renderer for streaming markdown parser output.
|
|
475
103
|
*
|
|
476
104
|
* @public
|
|
477
105
|
*/
|
|
478
|
-
function StreamingMarkdownRenderer({ children, options, isComplete = false, caret, className, onLinkClick, onCitationClick, nodeRenderers }) {
|
|
106
|
+
function StreamingMarkdownRenderer({ children, options, isComplete = false, caret, className, onLinkClick, onCitationClick, nodeRenderers, nodeClassNames }) {
|
|
479
107
|
const parserState = useStreamingMarkdownParser(children ?? "", options, isComplete);
|
|
480
108
|
const onLinkClickRef = (0, react.useRef)(onLinkClick);
|
|
481
109
|
const onCitationClickRef = (0, react.useRef)(onCitationClick);
|
|
482
110
|
onLinkClickRef.current = onLinkClick;
|
|
483
111
|
onCitationClickRef.current = onCitationClick;
|
|
484
|
-
const
|
|
485
|
-
const map = /* @__PURE__ */ new Map();
|
|
486
|
-
for (const node of parserState.nodes) map.set(node.id, node);
|
|
487
|
-
return map;
|
|
488
|
-
}, [parserState.nodes]);
|
|
489
|
-
const context = (0, react.useMemo)(() => {
|
|
490
|
-
const openNode = findDeepestOpenRenderableNode(parserState.stack, nodeById);
|
|
112
|
+
const content = (0, react.useMemo)(() => {
|
|
491
113
|
const caretNode = resolveCaretNode(caret, {
|
|
492
114
|
isComplete: parserState.isComplete,
|
|
493
|
-
openNode
|
|
115
|
+
openNode: (0, _copilotkit_markdown.findStreamingMarkdownOpenNode)(parserState)
|
|
494
116
|
});
|
|
495
|
-
const
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
117
|
+
const tree = (0, _copilotkit_markdown.buildStreamingMarkdownRenderTree)(parserState, {
|
|
118
|
+
caret: caretNode != null,
|
|
119
|
+
nodeClassNames
|
|
120
|
+
});
|
|
121
|
+
if (!tree.root) return null;
|
|
122
|
+
return renderRenderNode(tree.root, {
|
|
499
123
|
onLinkClickRef,
|
|
500
124
|
onCitationClickRef,
|
|
501
125
|
nodeRenderers,
|
|
502
|
-
caretTargetNodeId,
|
|
503
126
|
caretNode
|
|
504
|
-
};
|
|
127
|
+
});
|
|
505
128
|
}, [
|
|
506
|
-
|
|
507
|
-
parserState.citations,
|
|
508
|
-
parserState.isComplete,
|
|
509
|
-
parserState.stack,
|
|
129
|
+
parserState,
|
|
510
130
|
nodeRenderers,
|
|
131
|
+
nodeClassNames,
|
|
511
132
|
caret
|
|
512
133
|
]);
|
|
513
|
-
const
|
|
514
|
-
|
|
515
|
-
const styleText = typeof navigator !== "undefined" && /jsdom/i.test(navigator.userAgent) ? DEFAULT_STYLES_FALLBACK : DEFAULT_STYLES;
|
|
516
|
-
if (!rootNode) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: styleText }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
517
|
-
className: rootClassName,
|
|
518
|
-
"data-streaming-markdown-root": true
|
|
519
|
-
})] });
|
|
520
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: styleText }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
134
|
+
const rootClassName = className ? `${_copilotkit_markdown.STREAMING_MARKDOWN_ROOT_CLASS} ${className}` : _copilotkit_markdown.STREAMING_MARKDOWN_ROOT_CLASS;
|
|
135
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: (0, _copilotkit_markdown.getStreamingMarkdownStyles)() }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
521
136
|
className: rootClassName,
|
|
522
137
|
"data-streaming-markdown-root": true,
|
|
523
|
-
children:
|
|
138
|
+
children: content
|
|
524
139
|
})] });
|
|
525
140
|
}
|
|
526
|
-
function findDeepestOpenRenderableNode(stack, nodeById) {
|
|
527
|
-
for (let index = stack.length - 1; index >= 0; index -= 1) {
|
|
528
|
-
const candidate = nodeById.get(stack[index]) ?? null;
|
|
529
|
-
if (candidate && candidate.type !== "document") return candidate;
|
|
530
|
-
}
|
|
531
|
-
return null;
|
|
532
|
-
}
|
|
533
141
|
|
|
534
142
|
//#endregion
|
|
535
143
|
exports.StreamingMarkdownRenderer = StreamingMarkdownRenderer;
|