@copilotkit/markdown 0.0.1 → 2.0.0-rc.13
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/LICENSE +21 -0
- package/README.md +23 -2
- package/dist/index.cjs +2023 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +361 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +361 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2018 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react/index.cjs +538 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +190 -0
- package/dist/react/index.d.cts.map +1 -0
- package/dist/react/index.d.mts +190 -0
- package/dist/react/index.d.mts.map +1 -0
- package/dist/react/index.mjs +535 -0
- package/dist/react/index.mjs.map +1 -0
- package/dist/react-native/index.cjs +330 -0
- package/dist/react-native/index.cjs.map +1 -0
- package/dist/react-native/index.d.cts +74 -0
- package/dist/react-native/index.d.cts.map +1 -0
- package/dist/react-native/index.d.mts +74 -0
- package/dist/react-native/index.d.mts.map +1 -0
- package/dist/react-native/index.mjs +300 -0
- package/dist/react-native/index.mjs.map +1 -0
- package/dist/vue/index.cjs +256 -0
- package/dist/vue/index.cjs.map +1 -0
- package/dist/vue/index.d.cts +116 -0
- package/dist/vue/index.d.cts.map +1 -0
- package/dist/vue/index.d.mts +116 -0
- package/dist/vue/index.d.mts.map +1 -0
- package/dist/vue/index.mjs +255 -0
- package/dist/vue/index.mjs.map +1 -0
- package/package.json +75 -2
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
let react = require("react");
|
|
3
|
+
let _copilotkit_markdown = require("@copilotkit/markdown");
|
|
4
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
5
|
+
|
|
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
|
+
/**
|
|
67
|
+
* Internal prop-driven hook for streaming markdown parsing in React.
|
|
68
|
+
*
|
|
69
|
+
* @param text - Full markdown text that typically grows over time.
|
|
70
|
+
* @param options - Optional parser option overrides.
|
|
71
|
+
* @param isCompleteInput - When true, finalizes the parse state for the current text.
|
|
72
|
+
* @returns The current immutable streaming markdown parser state.
|
|
73
|
+
*/
|
|
74
|
+
function useStreamingMarkdownParser(text, options, isCompleteInput = false) {
|
|
75
|
+
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
|
+
return (0, react.useMemo)(() => {
|
|
89
|
+
const next = resolveNextSession(sessionRef.current ?? createSession(text, normalizedOptions, optionsKey, isCompleteInput), text, normalizedOptions, optionsKey, isCompleteInput);
|
|
90
|
+
sessionRef.current = next;
|
|
91
|
+
return next;
|
|
92
|
+
}, [
|
|
93
|
+
text,
|
|
94
|
+
normalizedOptions,
|
|
95
|
+
optionsKey,
|
|
96
|
+
isCompleteInput
|
|
97
|
+
]).parserState;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
//#endregion
|
|
101
|
+
//#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
|
+
/**
|
|
113
|
+
* Helper for creating typed streaming markdown node renderer maps.
|
|
114
|
+
*
|
|
115
|
+
* @public
|
|
116
|
+
*/
|
|
117
|
+
function createStreamingMarkdownNodeRenderers(renderers) {
|
|
118
|
+
return renderers;
|
|
119
|
+
}
|
|
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
|
+
function renderDefaultCaret() {
|
|
228
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
229
|
+
"aria-hidden": true,
|
|
230
|
+
className: "cpk-streaming-markdown-caret",
|
|
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
|
+
}
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
function resolveCaretNode(caret, props) {
|
|
245
|
+
if (caret === void 0 || caret === false || caret === null) return null;
|
|
246
|
+
if (caret === true) return renderDefaultCaret();
|
|
247
|
+
if (typeof caret === "function") return caret(props);
|
|
248
|
+
return caret;
|
|
249
|
+
}
|
|
250
|
+
function renderTextSegments(node) {
|
|
251
|
+
if (node.text.length === 0) return null;
|
|
252
|
+
if (node.segments.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
253
|
+
className: "cpk-streaming-markdown-segment",
|
|
254
|
+
"data-streaming-markdown-segment-kind": "full",
|
|
255
|
+
"data-streaming-markdown-whitespace": "false",
|
|
256
|
+
children: node.text
|
|
257
|
+
}, `segment-${node.id}-full`);
|
|
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);
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
function getCitationRenderData(node, context) {
|
|
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
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
function renderDefaultCitation(node, context, citation) {
|
|
280
|
+
const label = String(citation.number);
|
|
281
|
+
const href = sanitizeHref(citation.definition?.url);
|
|
282
|
+
if (!href) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("sup", {
|
|
283
|
+
className: DEFAULT_CITATION_CLASS,
|
|
284
|
+
"data-streaming-markdown-node": node.type,
|
|
285
|
+
"data-node-open": String(!node.closed),
|
|
286
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
287
|
+
role: "doc-noteref",
|
|
288
|
+
className: DEFAULT_CITATION_LABEL_CLASS,
|
|
289
|
+
children: label
|
|
290
|
+
})
|
|
291
|
+
}, node.id);
|
|
292
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("sup", {
|
|
293
|
+
className: DEFAULT_CITATION_CLASS,
|
|
294
|
+
"data-streaming-markdown-node": node.type,
|
|
295
|
+
"data-node-open": String(!node.closed),
|
|
296
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
297
|
+
href,
|
|
298
|
+
target: "_blank",
|
|
299
|
+
rel: "noopener noreferrer",
|
|
300
|
+
role: "doc-noteref",
|
|
301
|
+
className: DEFAULT_CITATION_LABEL_CLASS,
|
|
302
|
+
onClick: (event) => {
|
|
303
|
+
context.onCitationClickRef.current?.(event, citation, node);
|
|
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);
|
|
392
|
+
}
|
|
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
|
+
}
|
|
420
|
+
function renderNode(node, context) {
|
|
421
|
+
if (node.type === "document" || node.type === "paragraph" || node.type === "heading" || node.type === "blockquote" || node.type === "list" || node.type === "list-item" || node.type === "table" || node.type === "table-row" || node.type === "table-cell" || node.type === "em" || node.type === "strong" || node.type === "strikethrough" || node.type === "link") return renderContainerNode(node, context);
|
|
422
|
+
if (node.type === "code-block") return renderWithOverride(node, context, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
423
|
+
"data-streaming-markdown-node": node.type,
|
|
424
|
+
"data-node-open": String(!node.closed),
|
|
425
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("code", {
|
|
426
|
+
"data-code-info": node.info ?? void 0,
|
|
427
|
+
children: [node.text, renderCaret(node.id, context)]
|
|
428
|
+
})
|
|
429
|
+
}, node.id));
|
|
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);
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* React renderer for streaming markdown parser output.
|
|
475
|
+
*
|
|
476
|
+
* @public
|
|
477
|
+
*/
|
|
478
|
+
function StreamingMarkdownRenderer({ children, options, isComplete = false, caret, className, onLinkClick, onCitationClick, nodeRenderers }) {
|
|
479
|
+
const parserState = useStreamingMarkdownParser(children ?? "", options, isComplete);
|
|
480
|
+
const onLinkClickRef = (0, react.useRef)(onLinkClick);
|
|
481
|
+
const onCitationClickRef = (0, react.useRef)(onCitationClick);
|
|
482
|
+
onLinkClickRef.current = onLinkClick;
|
|
483
|
+
onCitationClickRef.current = onCitationClick;
|
|
484
|
+
const nodeById = (0, react.useMemo)(() => {
|
|
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);
|
|
491
|
+
const caretNode = resolveCaretNode(caret, {
|
|
492
|
+
isComplete: parserState.isComplete,
|
|
493
|
+
openNode
|
|
494
|
+
});
|
|
495
|
+
const caretTargetNodeId = !parserState.isComplete && openNode != null && caretNode != null ? openNode.id : null;
|
|
496
|
+
return {
|
|
497
|
+
nodeById,
|
|
498
|
+
citations: parserState.citations,
|
|
499
|
+
onLinkClickRef,
|
|
500
|
+
onCitationClickRef,
|
|
501
|
+
nodeRenderers,
|
|
502
|
+
caretTargetNodeId,
|
|
503
|
+
caretNode
|
|
504
|
+
};
|
|
505
|
+
}, [
|
|
506
|
+
nodeById,
|
|
507
|
+
parserState.citations,
|
|
508
|
+
parserState.isComplete,
|
|
509
|
+
parserState.stack,
|
|
510
|
+
nodeRenderers,
|
|
511
|
+
caret
|
|
512
|
+
]);
|
|
513
|
+
const rootNode = parserState.rootId == null ? void 0 : nodeById.get(parserState.rootId);
|
|
514
|
+
const rootClassName = className ? `${DEFAULT_ROOT_CLASS} ${className}` : DEFAULT_ROOT_CLASS;
|
|
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", {
|
|
521
|
+
className: rootClassName,
|
|
522
|
+
"data-streaming-markdown-root": true,
|
|
523
|
+
children: renderNode(rootNode, context)
|
|
524
|
+
})] });
|
|
525
|
+
}
|
|
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
|
+
|
|
534
|
+
//#endregion
|
|
535
|
+
exports.StreamingMarkdownRenderer = StreamingMarkdownRenderer;
|
|
536
|
+
exports.createStreamingMarkdownNodeRenderers = createStreamingMarkdownNodeRenderers;
|
|
537
|
+
exports.useStreamingMarkdownParser = useStreamingMarkdownParser;
|
|
538
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["Fragment"],"sources":["../../src/react/use-streaming-markdown-parser.tsx","../../src/react/streaming-markdown-renderer.tsx"],"sourcesContent":["import {\n createStreamingMarkdownParserState,\n finalizeStreamingMarkdown,\n parseStreamingMarkdownChunk,\n} from \"@copilotkit/markdown\";\nimport type {\n StreamingMarkdownParserOptions,\n StreamingMarkdownParserState,\n} from \"@copilotkit/markdown\";\nimport { useMemo, useRef } from \"react\";\n\ninterface StreamingMarkdownParserSession {\n parserState: StreamingMarkdownParserState;\n text: string;\n optionsKey: string;\n isCompleteInput: boolean;\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 getSegmenterKey(\n segmenter: StreamingMarkdownParserOptions[\"segmenter\"],\n): string {\n if (segmenter === true || segmenter === false) {\n return String(segmenter);\n }\n\n const locale = segmenter.locale ?? \"\";\n const granularity = segmenter.granularity ?? \"word\";\n return `object:${locale}:${granularity}`;\n}\n\nfunction getOptionsKey(options: StreamingMarkdownParserOptions): string {\n return `${getSegmenterKey(options.segmenter)}|tables:${String(options.enableTables)}|autolinks:${String(options.enableAutolinks)}`;\n}\n\nfunction parseFullText(\n text: string,\n options: StreamingMarkdownParserOptions,\n isCompleteInput: boolean,\n): StreamingMarkdownParserState {\n const initialState = createStreamingMarkdownParserState(options);\n const parsedState =\n text.length > 0\n ? parseStreamingMarkdownChunk(initialState, text)\n : initialState;\n\n return isCompleteInput ? finalizeStreamingMarkdown(parsedState) : parsedState;\n}\n\nfunction createSession(\n text: string,\n options: StreamingMarkdownParserOptions,\n optionsKey: string,\n isCompleteInput: boolean,\n): StreamingMarkdownParserSession {\n return {\n parserState: parseFullText(text, options, isCompleteInput),\n text,\n optionsKey,\n isCompleteInput,\n };\n}\n\nfunction resolveNextSession(\n previous: StreamingMarkdownParserSession,\n text: string,\n options: StreamingMarkdownParserOptions,\n optionsKey: string,\n isCompleteInput: boolean,\n): StreamingMarkdownParserSession {\n const optionsChanged = previous.optionsKey !== optionsKey;\n const completionChanged = previous.isCompleteInput !== isCompleteInput;\n\n if (optionsChanged) {\n return createSession(text, options, optionsKey, isCompleteInput);\n }\n\n const textChanged = text !== previous.text;\n if (!textChanged && !completionChanged) {\n return previous;\n }\n\n if (!textChanged && completionChanged) {\n const parserState = isCompleteInput\n ? finalizeStreamingMarkdown(previous.parserState)\n : parseStreamingMarkdownChunk(previous.parserState, \"\");\n\n return {\n ...previous,\n parserState,\n isCompleteInput,\n };\n }\n\n let nextParserState: StreamingMarkdownParserState;\n\n if (text.startsWith(previous.text)) {\n const suffix = text.slice(previous.text.length);\n nextParserState =\n suffix.length > 0\n ? parseStreamingMarkdownChunk(previous.parserState, suffix)\n : previous.parserState;\n } else {\n nextParserState = parseFullText(text, options, false);\n }\n\n if (isCompleteInput) {\n nextParserState = finalizeStreamingMarkdown(nextParserState);\n }\n\n return {\n parserState: nextParserState,\n text,\n optionsKey,\n isCompleteInput,\n };\n}\n\n/**\n * Internal prop-driven hook for streaming markdown parsing in React.\n *\n * @param text - Full markdown text that typically grows over time.\n * @param options - Optional parser option overrides.\n * @param isCompleteInput - When true, finalizes the parse state for the current text.\n * @returns The current immutable streaming markdown parser state.\n */\nexport function useStreamingMarkdownParser(\n text: string,\n options?: Partial<StreamingMarkdownParserOptions>,\n isCompleteInput = false,\n): StreamingMarkdownParserState {\n const sessionRef = useRef<StreamingMarkdownParserSession | null>(null);\n const segmenter = options?.segmenter;\n const segmenterKind =\n typeof segmenter === \"object\" && segmenter !== null\n ? \"object\"\n : String(segmenter ?? true);\n const segmenterLocale =\n typeof segmenter === \"object\" && segmenter !== null\n ? (segmenter.locale ?? \"\")\n : \"\";\n const segmenterGranularity =\n typeof segmenter === \"object\" && segmenter !== null\n ? (segmenter.granularity ?? \"word\")\n : \"\";\n const normalizedOptions = useMemo(\n () => normalizeOptions(options),\n [\n options?.enableAutolinks,\n options?.enableTables,\n segmenterKind,\n segmenterLocale,\n segmenterGranularity,\n ],\n );\n const optionsKey = getOptionsKey(normalizedOptions);\n\n const session = useMemo(() => {\n const previous =\n sessionRef.current ??\n createSession(text, normalizedOptions, optionsKey, isCompleteInput);\n\n const next = resolveNextSession(\n previous,\n text,\n normalizedOptions,\n optionsKey,\n isCompleteInput,\n );\n\n sessionRef.current = next;\n return next;\n }, [text, normalizedOptions, optionsKey, isCompleteInput]);\n\n return session.parserState;\n}\n","import type {\n CitationDefinition,\n CitationState,\n StreamingMarkdownAstNode,\n StreamingMarkdownNodeType,\n StreamingMarkdownParserOptions,\n TextSegment,\n} from \"@copilotkit/markdown\";\nimport { Fragment, useMemo, useRef } from \"react\";\nimport type { MouseEvent, ReactNode } from \"react\";\nimport { useStreamingMarkdownParser } from \"./use-streaming-markdown-parser\";\n\n// URL allowlists for link/image rendering — mirrors the Vue renderer so both\n// frameworks honor the documented XSS guarantee (only http(s), mailto, tel,\n// relative, anchor, and non-SVG data:image/* URLs are allowed). Anything else\n// (javascript:, data:text/html, data:image/svg+xml, vbscript:, …) is dropped.\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 * Metadata available when a citation node is rendered.\n *\n * @public\n */\nexport interface StreamingMarkdownCitationRenderData {\n id: string;\n number: number | string;\n definition?: CitationDefinition;\n}\n\n/**\n * Props for the `StreamingMarkdownRenderer` component.\n *\n * @public\n */\nexport interface StreamingMarkdownRendererProps {\n /**\n * Full markdown source that grows over time.\n */\n children: string;\n\n /**\n * Optional parser option overrides.\n */\n options?: Partial<StreamingMarkdownParserOptions>;\n\n /**\n * When `true`, finalizes the parser state after applying the latest text.\n */\n isComplete?: boolean;\n\n /**\n * Caret rendering behavior for streaming output.\n *\n * - `false`/`undefined`: no caret\n * - `true`: render the default caret\n * - `ReactNode`: render a custom caret node\n * - function: render a custom caret node from parser state\n */\n caret?: StreamingMarkdownCaret;\n\n /**\n * Optional class applied to the root element.\n */\n className?: string;\n\n /**\n * Called when a link or autolink is clicked.\n */\n onLinkClick?: (\n event: MouseEvent<HTMLAnchorElement>,\n url: string,\n node: StreamingMarkdownAstNode,\n ) => void;\n\n /**\n * Called when a citation reference is clicked.\n */\n onCitationClick?: (\n event: MouseEvent<HTMLAnchorElement>,\n citation: StreamingMarkdownCitationRenderData,\n node: StreamingMarkdownAstNode,\n ) => void;\n\n /**\n * Optional custom renderers keyed by streaming markdown node type.\n */\n nodeRenderers?: StreamingMarkdownNodeRenderers;\n}\n\n/**\n * Props supplied to a custom node renderer.\n *\n * @public\n */\nexport interface StreamingMarkdownNodeRendererProps<\n TNode extends StreamingMarkdownAstNode = StreamingMarkdownAstNode,\n> {\n /**\n * The immutable AST node being rendered.\n */\n node: TNode;\n\n /**\n * Already-rendered child content for container nodes.\n */\n children: ReactNode;\n\n /**\n * Default element tree produced by `StreamingMarkdownRenderer` for this node.\n */\n defaultNode: ReactNode;\n\n /**\n * Citation metadata when rendering a citation node.\n */\n citation?: StreamingMarkdownCitationRenderData;\n}\n\n/**\n * Custom renderer callback for a specific streaming markdown node.\n *\n * @public\n */\nexport type StreamingMarkdownNodeRenderer<\n TNode extends StreamingMarkdownAstNode = StreamingMarkdownAstNode,\n> = (props: StreamingMarkdownNodeRendererProps<TNode>) => ReactNode;\n\n/**\n * Render context supplied to caret renderer callbacks.\n *\n * @public\n */\nexport interface StreamingMarkdownCaretRenderProps {\n /**\n * Whether the parser state is complete for the current source text.\n */\n isComplete: boolean;\n\n /**\n * The deepest currently open AST node, if any.\n */\n openNode: StreamingMarkdownAstNode | null;\n}\n\n/**\n * Callback type for custom caret renderers.\n *\n * @public\n */\nexport type StreamingMarkdownCaretRenderer = (\n props: StreamingMarkdownCaretRenderProps,\n) => ReactNode;\n\n/**\n * Supported caret prop values.\n *\n * @public\n */\nexport type StreamingMarkdownCaret =\n | boolean\n | ReactNode\n | StreamingMarkdownCaretRenderer;\n\ntype StreamingMarkdownNodeOfType<TNodeType extends StreamingMarkdownNodeType> =\n Extract<StreamingMarkdownAstNode, { type: TNodeType }>;\n\n/**\n * Supported key names for `nodeRenderers`.\n *\n * @public\n */\nexport type StreamingMarkdownNodeRendererKey =\n | \"node\"\n | \"document\"\n | \"paragraph\"\n | \"heading\"\n | \"blockquote\"\n | \"list\"\n | \"listItem\"\n | \"codeBlock\"\n | \"table\"\n | \"tableRow\"\n | \"tableCell\"\n | \"thematicBreak\"\n | \"text\"\n | \"em\"\n | \"strong\"\n | \"strikethrough\"\n | \"inlineCode\"\n | \"softBreak\"\n | \"hardBreak\"\n | \"image\"\n | \"link\"\n | \"autolink\"\n | \"citation\";\n\ntype StreamingMarkdownNodeByRendererKey = {\n node: StreamingMarkdownAstNode;\n document: StreamingMarkdownNodeOfType<\"document\">;\n paragraph: StreamingMarkdownNodeOfType<\"paragraph\">;\n heading: StreamingMarkdownNodeOfType<\"heading\">;\n blockquote: StreamingMarkdownNodeOfType<\"blockquote\">;\n list: StreamingMarkdownNodeOfType<\"list\">;\n listItem: StreamingMarkdownNodeOfType<\"list-item\">;\n codeBlock: StreamingMarkdownNodeOfType<\"code-block\">;\n table: StreamingMarkdownNodeOfType<\"table\">;\n tableRow: StreamingMarkdownNodeOfType<\"table-row\">;\n tableCell: StreamingMarkdownNodeOfType<\"table-cell\">;\n thematicBreak: StreamingMarkdownNodeOfType<\"thematic-break\">;\n text: StreamingMarkdownNodeOfType<\"text\">;\n em: StreamingMarkdownNodeOfType<\"em\">;\n strong: StreamingMarkdownNodeOfType<\"strong\">;\n strikethrough: StreamingMarkdownNodeOfType<\"strikethrough\">;\n inlineCode: StreamingMarkdownNodeOfType<\"inline-code\">;\n softBreak: StreamingMarkdownNodeOfType<\"soft-break\">;\n hardBreak: StreamingMarkdownNodeOfType<\"hard-break\">;\n image: StreamingMarkdownNodeOfType<\"image\">;\n link: StreamingMarkdownNodeOfType<\"link\">;\n autolink: StreamingMarkdownNodeOfType<\"autolink\">;\n citation: StreamingMarkdownNodeOfType<\"citation\">;\n};\n\n/**\n * Custom renderers keyed by camelCase node names.\n *\n * @public\n */\nexport type StreamingMarkdownNodeRenderers = Partial<{\n [TKey in StreamingMarkdownNodeRendererKey]: StreamingMarkdownNodeRenderer<\n StreamingMarkdownNodeByRendererKey[TKey]\n >;\n}>;\n\n/**\n * Helper for creating typed streaming markdown node renderer maps.\n *\n * @public\n */\nexport function createStreamingMarkdownNodeRenderers<\n T extends StreamingMarkdownNodeRenderers,\n>(renderers: T): T {\n return renderers;\n}\n\ntype RenderContext = {\n nodeById: Map<number, StreamingMarkdownAstNode>;\n citations: CitationState;\n onLinkClickRef: { current: StreamingMarkdownRendererProps[\"onLinkClick\"] };\n onCitationClickRef: {\n current: StreamingMarkdownRendererProps[\"onCitationClick\"];\n };\n nodeRenderers?: StreamingMarkdownNodeRenderers;\n caretTargetNodeId: number | null;\n caretNode: ReactNode;\n};\n\ntype StreamingMarkdownTextNode = Extract<\n StreamingMarkdownAstNode,\n { type: \"text\" }\n>;\ntype StreamingMarkdownCitationNode = Extract<\n StreamingMarkdownAstNode,\n { type: \"citation\" }\n>;\n\nconst WORD_JOINER = \"\\u2060\";\nconst DEFAULT_ROOT_CLASS = \"cpk-streaming-markdown-root\";\nconst DEFAULT_CITATION_CLASS = \"cpk-streaming-markdown-citation\";\nconst DEFAULT_CITATION_LABEL_CLASS = \"cpk-streaming-markdown-citation-label\";\nconst DEFAULT_STYLES = `\n .${DEFAULT_ROOT_CLASS} .cpk-streaming-markdown-segment {\n opacity: 1;\n transition: opacity 400ms ease-out;\n @starting-style {\n opacity: 0;\n }\n }\n\n .${DEFAULT_ROOT_CLASS} .${DEFAULT_CITATION_CLASS} {\n vertical-align: baseline;\n }\n\n .${DEFAULT_ROOT_CLASS} .${DEFAULT_CITATION_LABEL_CLASS} {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n inline-size: 1.4em;\n block-size: 1.4em;\n border-radius: 999px;\n border: 1px solid hsl(0 0% 50% / 0.35);\n background-color: hsl(0 0% 50% / 0.16);\n color: inherit;\n font-size: 0.7em;\n line-height: 1;\n font-variant-numeric: tabular-nums;\n text-decoration: none;\n transform: translateY(-0.15em);\n }\n`;\n\nconst DEFAULT_STYLES_FALLBACK = `\n .${DEFAULT_ROOT_CLASS} .cpk-streaming-markdown-segment {\n opacity: 1;\n transition: opacity 400ms ease-out;\n }\n\n .${DEFAULT_ROOT_CLASS} .${DEFAULT_CITATION_CLASS} {\n vertical-align: baseline;\n }\n\n .${DEFAULT_ROOT_CLASS} .${DEFAULT_CITATION_LABEL_CLASS} {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n inline-size: 1.4em;\n block-size: 1.4em;\n border-radius: 999px;\n border: 1px solid hsl(0 0% 50% / 0.35);\n background-color: hsl(0 0% 50% / 0.16);\n color: inherit;\n font-size: 0.7em;\n line-height: 1;\n font-variant-numeric: tabular-nums;\n text-decoration: none;\n transform: translateY(-0.15em);\n }\n`;\n\ntype ContainerNodeType = Extract<\n StreamingMarkdownNodeType,\n | \"document\"\n | \"paragraph\"\n | \"heading\"\n | \"blockquote\"\n | \"list\"\n | \"list-item\"\n | \"table\"\n | \"table-row\"\n | \"table-cell\"\n | \"em\"\n | \"strong\"\n | \"strikethrough\"\n | \"link\"\n>;\n\nconst NODE_TYPE_TO_RENDERER_KEY: Record<\n StreamingMarkdownNodeType,\n StreamingMarkdownNodeRendererKey\n> = {\n document: \"document\",\n paragraph: \"paragraph\",\n heading: \"heading\",\n blockquote: \"blockquote\",\n list: \"list\",\n \"list-item\": \"listItem\",\n \"code-block\": \"codeBlock\",\n table: \"table\",\n \"table-row\": \"tableRow\",\n \"table-cell\": \"tableCell\",\n \"thematic-break\": \"thematicBreak\",\n text: \"text\",\n em: \"em\",\n strong: \"strong\",\n strikethrough: \"strikethrough\",\n \"inline-code\": \"inlineCode\",\n \"soft-break\": \"softBreak\",\n \"hard-break\": \"hardBreak\",\n image: \"image\",\n link: \"link\",\n autolink: \"autolink\",\n citation: \"citation\",\n};\n\nfunction renderWithOverride<TNode extends StreamingMarkdownAstNode>(\n node: TNode,\n context: RenderContext,\n defaultNode: ReactNode,\n children: ReactNode = null,\n citation?: StreamingMarkdownCitationRenderData,\n): ReactNode {\n const rendererKey = NODE_TYPE_TO_RENDERER_KEY[node.type];\n const renderer = (context.nodeRenderers?.[rendererKey] ??\n context.nodeRenderers?.node) as\n | StreamingMarkdownNodeRenderer<TNode>\n | undefined;\n\n if (!renderer) {\n return defaultNode;\n }\n\n return renderer({\n node,\n children,\n defaultNode,\n citation,\n });\n}\n\nfunction renderChildren(\n node: { children: number[] },\n context: RenderContext,\n): ReactNode {\n return node.children.map((childId) => {\n const childNode = context.nodeById.get(childId);\n\n if (!childNode) {\n return null;\n }\n\n return <Fragment key={childId}>{renderNode(childNode, context)}</Fragment>;\n });\n}\n\nfunction renderCaret(nodeId: number, context: RenderContext): ReactNode {\n if (context.caretTargetNodeId !== nodeId) {\n return null;\n }\n\n return <Fragment key={`caret-${nodeId}`}>{context.caretNode}</Fragment>;\n}\n\nfunction renderDefaultCaret(): ReactNode {\n return (\n <span\n aria-hidden\n className=\"cpk-streaming-markdown-caret\"\n data-streaming-markdown-caret\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\nfunction resolveCaretNode(\n caret: StreamingMarkdownCaret | undefined,\n props: StreamingMarkdownCaretRenderProps,\n): ReactNode {\n if (caret === undefined || caret === false || caret === null) {\n return null;\n }\n\n if (caret === true) {\n return renderDefaultCaret();\n }\n\n if (typeof caret === \"function\") {\n return caret(props);\n }\n\n return caret;\n}\n\nfunction renderTextSegments(node: StreamingMarkdownTextNode): ReactNode {\n if (node.text.length === 0) {\n return null;\n }\n\n if (node.segments.length === 0) {\n return (\n <span\n key={`segment-${node.id}-full`}\n className=\"cpk-streaming-markdown-segment\"\n data-streaming-markdown-segment-kind=\"full\"\n data-streaming-markdown-whitespace=\"false\"\n >\n {node.text}\n </span>\n );\n }\n\n return node.segments.map((segment: TextSegment) => (\n <span\n key={`segment-${node.id}-${segment.start}-${segment.kind}`}\n className=\"cpk-streaming-markdown-segment\"\n data-streaming-markdown-segment-kind={segment.kind}\n data-streaming-markdown-whitespace={String(segment.isWhitespace)}\n >\n {segment.noBreakBefore ? `${WORD_JOINER}${segment.text}` : segment.text}\n </span>\n ));\n}\n\nfunction handleLinkClick(\n context: RenderContext,\n node: StreamingMarkdownAstNode,\n url: string,\n) {\n return (event: MouseEvent<HTMLAnchorElement>) => {\n context.onLinkClickRef.current?.(event, url, node);\n };\n}\n\nfunction getCitationRenderData(\n node: StreamingMarkdownCitationNode,\n context: RenderContext,\n): StreamingMarkdownCitationRenderData {\n const number =\n node.number ?? context.citations.numbers[node.idRef] ?? node.idRef;\n const definition = context.citations.definitions[node.idRef];\n return {\n id: node.idRef,\n number,\n definition,\n } satisfies StreamingMarkdownCitationRenderData;\n}\n\nfunction renderDefaultCitation(\n node: StreamingMarkdownCitationNode,\n context: RenderContext,\n citation: StreamingMarkdownCitationRenderData,\n): ReactNode {\n const label = String(citation.number);\n const href = sanitizeHref(citation.definition?.url);\n\n if (!href) {\n return (\n <sup\n key={node.id}\n className={DEFAULT_CITATION_CLASS}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n <span role=\"doc-noteref\" className={DEFAULT_CITATION_LABEL_CLASS}>\n {label}\n </span>\n </sup>\n );\n }\n\n return (\n <sup\n key={node.id}\n className={DEFAULT_CITATION_CLASS}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n role=\"doc-noteref\"\n className={DEFAULT_CITATION_LABEL_CLASS}\n onClick={(event) => {\n context.onCitationClickRef.current?.(event, citation, node);\n }}\n >\n {label}\n </a>\n </sup>\n );\n}\n\nfunction renderContainerNode(\n node: Extract<StreamingMarkdownAstNode, { type: ContainerNodeType }>,\n context: RenderContext,\n): ReactNode {\n const children = (\n <>\n {renderChildren(node, context)}\n {renderCaret(node.id, context)}\n </>\n );\n\n if (node.type === \"document\") {\n return renderWithOverride(\n node,\n context,\n <Fragment key={node.id}>{children}</Fragment>,\n children,\n );\n }\n\n if (node.type === \"paragraph\") {\n const defaultNode = (\n <p\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n {children}\n </p>\n );\n return renderWithOverride(node, context, defaultNode, children);\n }\n\n if (node.type === \"heading\") {\n const headingTag = `h${node.level}` as const;\n const defaultNode =\n headingTag === \"h1\" ? (\n <h1\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n {children}\n </h1>\n ) : headingTag === \"h2\" ? (\n <h2\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n {children}\n </h2>\n ) : headingTag === \"h3\" ? (\n <h3\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n {children}\n </h3>\n ) : headingTag === \"h4\" ? (\n <h4\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n {children}\n </h4>\n ) : headingTag === \"h5\" ? (\n <h5\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n {children}\n </h5>\n ) : (\n <h6\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n {children}\n </h6>\n );\n return renderWithOverride(node, context, defaultNode, children);\n }\n\n if (node.type === \"blockquote\") {\n const defaultNode = (\n <blockquote\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n {children}\n </blockquote>\n );\n return renderWithOverride(node, context, defaultNode, children);\n }\n\n if (node.type === \"list\") {\n if (node.ordered) {\n const defaultNode = (\n <ol\n key={node.id}\n start={node.start ?? undefined}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n data-list-tight={String(node.tight)}\n >\n {children}\n </ol>\n );\n return renderWithOverride(node, context, defaultNode, children);\n }\n\n const defaultNode = (\n <ul\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n data-list-tight={String(node.tight)}\n >\n {children}\n </ul>\n );\n return renderWithOverride(node, context, defaultNode, children);\n }\n\n if (node.type === \"list-item\") {\n const defaultNode = (\n <li\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n {children}\n </li>\n );\n return renderWithOverride(node, context, defaultNode, children);\n }\n\n if (node.type === \"table\") {\n const defaultNode = (\n <table\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n <tbody>{children}</tbody>\n </table>\n );\n return renderWithOverride(node, context, defaultNode, children);\n }\n\n if (node.type === \"table-row\") {\n const defaultNode = (\n <tr\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n {children}\n </tr>\n );\n return renderWithOverride(node, context, defaultNode, children);\n }\n\n if (node.type === \"table-cell\") {\n const parent =\n node.parentId == null ? undefined : context.nodeById.get(node.parentId);\n const isHeaderRow = parent?.type === \"table-row\" && parent.isHeader;\n if (isHeaderRow) {\n const defaultNode = (\n <th\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n {children}\n </th>\n );\n return renderWithOverride(node, context, defaultNode, children);\n }\n\n const defaultNode = (\n <td\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n {children}\n </td>\n );\n return renderWithOverride(node, context, defaultNode, children);\n }\n\n if (node.type === \"em\") {\n const defaultNode = (\n <em\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n {children}\n </em>\n );\n return renderWithOverride(node, context, defaultNode, children);\n }\n\n if (node.type === \"strong\") {\n const defaultNode = (\n <strong\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n {children}\n </strong>\n );\n return renderWithOverride(node, context, defaultNode, children);\n }\n\n if (node.type === \"strikethrough\") {\n const defaultNode = (\n <s\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n {children}\n </s>\n );\n return renderWithOverride(node, context, defaultNode, children);\n }\n\n const href = sanitizeHref(node.url);\n const defaultNode = (\n <a\n key={node.id}\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n title={node.title}\n onClick={href ? handleLinkClick(context, node, href) : undefined}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n {children}\n </a>\n );\n return renderWithOverride(node, context, defaultNode, children);\n}\n\nfunction renderNode(\n node: StreamingMarkdownAstNode,\n context: RenderContext,\n): ReactNode {\n if (\n node.type === \"document\" ||\n node.type === \"paragraph\" ||\n node.type === \"heading\" ||\n node.type === \"blockquote\" ||\n node.type === \"list\" ||\n node.type === \"list-item\" ||\n node.type === \"table\" ||\n node.type === \"table-row\" ||\n node.type === \"table-cell\" ||\n node.type === \"em\" ||\n node.type === \"strong\" ||\n node.type === \"strikethrough\" ||\n node.type === \"link\"\n ) {\n return renderContainerNode(node, context);\n }\n\n if (node.type === \"code-block\") {\n const defaultNode = (\n <pre\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n <code data-code-info={node.info ?? undefined}>\n {node.text}\n {renderCaret(node.id, context)}\n </code>\n </pre>\n );\n return renderWithOverride(node, context, defaultNode);\n }\n\n if (node.type === \"thematic-break\") {\n const defaultNode = (\n <hr\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n />\n );\n return renderWithOverride(node, context, defaultNode);\n }\n\n if (node.type === \"text\") {\n const children = renderTextSegments(node);\n const defaultNode = <Fragment key={node.id}>{children}</Fragment>;\n return renderWithOverride(node, context, defaultNode, children);\n }\n\n if (node.type === \"inline-code\") {\n const defaultNode = (\n <code\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n {node.text}\n </code>\n );\n return renderWithOverride(node, context, defaultNode, node.text);\n }\n\n if (node.type === \"soft-break\") {\n const children = \"\\n\";\n const defaultNode = <Fragment key={node.id}>{children}</Fragment>;\n return renderWithOverride(node, context, defaultNode, children);\n }\n\n if (node.type === \"hard-break\") {\n const defaultNode = (\n <br\n key={node.id}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n />\n );\n return renderWithOverride(node, context, defaultNode);\n }\n\n if (node.type === \"image\") {\n const defaultNode = (\n <img\n key={node.id}\n src={sanitizeImgSrc(node.url)}\n alt={node.alt}\n title={node.title}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n />\n );\n return renderWithOverride(node, context, defaultNode);\n }\n\n if (node.type === \"autolink\") {\n const href = sanitizeHref(node.url);\n const defaultNode = (\n <a\n key={node.id}\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={href ? handleLinkClick(context, node, href) : undefined}\n data-streaming-markdown-node={node.type}\n data-node-open={String(!node.closed)}\n >\n {node.text}\n </a>\n );\n return renderWithOverride(node, context, defaultNode, node.text);\n }\n\n const citation = getCitationRenderData(node, context);\n const defaultNode = renderDefaultCitation(node, context, citation);\n return renderWithOverride(node, context, defaultNode, null, citation);\n}\n\n/**\n * React renderer for streaming markdown parser output.\n *\n * @public\n */\nexport function StreamingMarkdownRenderer({\n children,\n options,\n isComplete = false,\n caret,\n className,\n onLinkClick,\n onCitationClick,\n nodeRenderers,\n}: StreamingMarkdownRendererProps) {\n const text = children ?? \"\";\n const parserState = useStreamingMarkdownParser(text, options, isComplete);\n const onLinkClickRef =\n useRef<StreamingMarkdownRendererProps[\"onLinkClick\"]>(onLinkClick);\n const onCitationClickRef =\n useRef<StreamingMarkdownRendererProps[\"onCitationClick\"]>(onCitationClick);\n onLinkClickRef.current = onLinkClick;\n onCitationClickRef.current = onCitationClick;\n\n const nodeById = useMemo(() => {\n const map = new Map<number, StreamingMarkdownAstNode>();\n\n for (const node of parserState.nodes) {\n map.set(node.id, node);\n }\n\n return map;\n }, [parserState.nodes]);\n\n const context = useMemo(() => {\n const openNode = findDeepestOpenRenderableNode(parserState.stack, nodeById);\n const caretNode = resolveCaretNode(caret, {\n isComplete: parserState.isComplete,\n openNode,\n });\n const caretTargetNodeId =\n !parserState.isComplete && openNode != null && caretNode != null\n ? openNode.id\n : null;\n\n return {\n nodeById,\n citations: parserState.citations,\n onLinkClickRef,\n onCitationClickRef,\n nodeRenderers,\n caretTargetNodeId,\n caretNode,\n };\n }, [\n nodeById,\n parserState.citations,\n parserState.isComplete,\n parserState.stack,\n nodeRenderers,\n caret,\n ]);\n\n const rootNode =\n parserState.rootId == null ? undefined : nodeById.get(parserState.rootId);\n const rootClassName = className\n ? `${DEFAULT_ROOT_CLASS} ${className}`\n : DEFAULT_ROOT_CLASS;\n const styleText =\n typeof navigator !== \"undefined\" && /jsdom/i.test(navigator.userAgent)\n ? DEFAULT_STYLES_FALLBACK\n : DEFAULT_STYLES;\n\n if (!rootNode) {\n return (\n <>\n <style>{styleText}</style>\n <div className={rootClassName} data-streaming-markdown-root />\n </>\n );\n }\n\n return (\n <>\n <style>{styleText}</style>\n <div className={rootClassName} data-streaming-markdown-root>\n {renderNode(rootNode, context)}\n </div>\n </>\n );\n}\n\nfunction findDeepestOpenRenderableNode(\n stack: number[],\n nodeById: Map<number, StreamingMarkdownAstNode>,\n): StreamingMarkdownAstNode | null {\n for (let index = stack.length - 1; index >= 0; index -= 1) {\n const candidate = nodeById.get(stack[index]) ?? null;\n if (candidate && candidate.type !== \"document\") {\n return candidate;\n }\n }\n\n return null;\n}\n"],"mappings":"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"}
|