@copilotkit/markdown 2.0.0-rc.19 → 2.0.0-rc.21

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,254 @@
1
+ import { STREAMING_MARKDOWN_CARET_ATTRS, STREAMING_MARKDOWN_CARET_STYLE, STREAMING_MARKDOWN_ROOT_CLASS, buildStreamingMarkdownRenderTree, getStreamingMarkdownStyles, updateStreamingMarkdownParserSession } from "@copilotkit/markdown";
2
+
3
+ //#region src/dom/streaming-markdown-dom-renderer.ts
4
+ function toKebabCase(property) {
5
+ return property.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
6
+ }
7
+ const CARET_STYLE = Object.entries(STREAMING_MARKDOWN_CARET_STYLE).map(([property, value]) => `${toKebabCase(property)}:${value}`).join(";");
8
+ function caretElement(key) {
9
+ return {
10
+ kind: "element",
11
+ key,
12
+ tag: "span",
13
+ attrs: {
14
+ ...STREAMING_MARKDOWN_CARET_ATTRS,
15
+ style: CARET_STYLE
16
+ },
17
+ children: []
18
+ };
19
+ }
20
+ function prefixed(prefix, children) {
21
+ return children.map((child) => ({
22
+ ...child,
23
+ key: `${prefix}:${child.key}`
24
+ }));
25
+ }
26
+ function toVChildren(children, context, slot) {
27
+ return children.flatMap((child) => {
28
+ switch (child.kind) {
29
+ case "node": return toVNode(child, context);
30
+ case "element": {
31
+ const element = {
32
+ kind: "element",
33
+ key: child.key,
34
+ tag: child.tag,
35
+ attrs: child.attrs,
36
+ children: toVChildren(child.children, context, slot)
37
+ };
38
+ return child.action ? [{
39
+ ...element,
40
+ action: child.action
41
+ }] : [element];
42
+ }
43
+ case "text": return [{
44
+ kind: "text",
45
+ key: child.key,
46
+ text: child.text
47
+ }];
48
+ case "caret": return [caretElement(child.key)];
49
+ case "slot": return slot;
50
+ default: return child;
51
+ }
52
+ });
53
+ }
54
+ function renderOverride(renderNode, renderer, context) {
55
+ const cached = context.overrideCache.get(renderNode.node);
56
+ if (cached?.renderer === renderer && !renderNode.containsCaret) return cached.dom;
57
+ const doc = context.document;
58
+ const materialize = (entries) => entries.map((entry) => createDom(entry, doc));
59
+ const children = renderNode.children ? materialize(toVChildren(renderNode.children, context, [])) : null;
60
+ const defaultNodes = materialize(toVChildren(renderNode.output, context, renderNode.children ? toVChildren(renderNode.children, context, []) : []));
61
+ const defaultNode = defaultNodes.length === 1 ? defaultNodes[0] : wrapInFragment(defaultNodes, doc);
62
+ const dom = renderer({
63
+ node: renderNode.node,
64
+ children,
65
+ defaultNode,
66
+ citation: renderNode.citation,
67
+ document: doc
68
+ });
69
+ context.overrideCache.set(renderNode.node, {
70
+ renderer,
71
+ dom
72
+ });
73
+ return dom;
74
+ }
75
+ function wrapInFragment(nodes, doc) {
76
+ if (nodes.length === 0) return null;
77
+ const fragment = doc.createDocumentFragment();
78
+ for (const node of nodes) fragment.appendChild(node);
79
+ return fragment;
80
+ }
81
+ function toVNode(renderNode, context) {
82
+ const renderer = context.nodeRenderers?.[renderNode.rendererKey] ?? context.nodeRenderers?.node;
83
+ if (renderer) {
84
+ const dom = renderOverride(renderNode, renderer, context);
85
+ return dom ? [{
86
+ kind: "raw",
87
+ key: renderNode.key,
88
+ dom
89
+ }] : [];
90
+ }
91
+ const slot = renderNode.children ? toVChildren(renderNode.children, context, []) : [];
92
+ return prefixed(renderNode.key, toVChildren(renderNode.output, context, slot));
93
+ }
94
+ function setAttributes(element, next, previous) {
95
+ const previousNames = Object.keys(previous);
96
+ for (const name of previousNames) if (!(name in next)) element.removeAttribute(name);
97
+ const entries = Object.entries(next);
98
+ for (const [name, value] of entries) if (previous[name] !== value) element.setAttribute(name, value === true ? "" : value);
99
+ }
100
+ function createDom(child, doc) {
101
+ switch (child.kind) {
102
+ case "raw": return child.dom;
103
+ case "text":
104
+ child.dom = doc.createTextNode(child.text);
105
+ return child.dom;
106
+ case "element": {
107
+ const element = doc.createElement(child.tag);
108
+ setAttributes(element, child.attrs, {});
109
+ for (const entry of child.children) element.appendChild(createDom(entry, doc));
110
+ child.dom = element;
111
+ return element;
112
+ }
113
+ default: return child;
114
+ }
115
+ }
116
+ /** Updates `previous`'s DOM to match `next` and returns it, or `null` if incompatible. */
117
+ function patchDom(previous, next, doc) {
118
+ if (previous.kind === "text" && next.kind === "text" && previous.dom) {
119
+ if (previous.text !== next.text) previous.dom.data = next.text;
120
+ next.dom = previous.dom;
121
+ return next.dom;
122
+ }
123
+ if (previous.kind === "raw" && next.kind === "raw") return previous.dom === next.dom ? next.dom : null;
124
+ if (!(previous.kind === "element" && next.kind === "element" && previous.tag === next.tag && previous.dom !== void 0)) return null;
125
+ const element = previous.dom;
126
+ if (!element) return null;
127
+ setAttributes(element, next.attrs, previous.attrs);
128
+ patchChildren(element, previous.children, next.children, doc);
129
+ next.dom = element;
130
+ return element;
131
+ }
132
+ function patchChildren(parent, previous, next, doc) {
133
+ const unused = new Map(previous.map((child) => [child.key, child]));
134
+ let cursor = parent.firstChild;
135
+ for (const child of next) {
136
+ const match = unused.get(child.key);
137
+ const reused = match ? patchDom(match, child, doc) : null;
138
+ if (match && reused) unused.delete(child.key);
139
+ const dom = reused ?? createDom(child, doc);
140
+ if (dom === cursor) cursor = cursor.nextSibling;
141
+ else parent.insertBefore(dom, cursor);
142
+ }
143
+ const leftovers = Array.from(unused.values());
144
+ for (const child of leftovers) {
145
+ const dom = child.dom;
146
+ if (dom && dom.parentNode === parent) parent.removeChild(dom);
147
+ }
148
+ }
149
+ function removeAllChildren(parent) {
150
+ while (parent.firstChild) parent.removeChild(parent.firstChild);
151
+ }
152
+ function collectActions(children, actions) {
153
+ for (const child of children) {
154
+ if (child.kind !== "element" || !child.dom) continue;
155
+ if (child.action) actions.set(child.dom, child.action);
156
+ collectActions(child.children, actions);
157
+ }
158
+ }
159
+ /**
160
+ * Creates a framework-free streaming markdown renderer that draws into
161
+ * `container`. It parses incrementally, renders the same render tree as the
162
+ * React and Vue renderers (same markup, URL sanitization, caret, citations,
163
+ * and per-token fade-in), and patches the DOM by key so text that is already
164
+ * on screen keeps its nodes and does not animate again.
165
+ *
166
+ * Creates nodes with `container.ownerDocument`, so it works with server DOMs
167
+ * that have no global `document`.
168
+ *
169
+ * @param container - Element the renderer owns. Its children are replaced.
170
+ * @returns `render(props)` to draw the latest props, and `destroy()` to remove
171
+ * the output and the click listener.
172
+ *
173
+ * @example
174
+ * ```ts
175
+ * const renderer = createStreamingMarkdownDomRenderer(element);
176
+ * renderer.render({ content: "**Hi**", caret: true });
177
+ * renderer.render({ content: "**Hi** there", isComplete: true });
178
+ * renderer.destroy();
179
+ * ```
180
+ * @public
181
+ */
182
+ function createStreamingMarkdownDomRenderer(container) {
183
+ const doc = container.ownerDocument;
184
+ let session = null;
185
+ let props = { content: "" };
186
+ let styleElement = null;
187
+ let rootElement = null;
188
+ let previousChildren = [];
189
+ let actions = /* @__PURE__ */ new WeakMap();
190
+ const overrideCache = /* @__PURE__ */ new WeakMap();
191
+ const onClick = (event) => {
192
+ let target = event.target instanceof Node ? event.target : null;
193
+ while (target && target !== container) {
194
+ const action = actions.get(target);
195
+ if (action?.type === "link") {
196
+ props.onLinkClick?.(event, action.url, action.node);
197
+ return;
198
+ }
199
+ if (action?.type === "citation") {
200
+ props.onCitationClick?.(event, action.citation, action.node);
201
+ return;
202
+ }
203
+ target = target.parentNode;
204
+ }
205
+ };
206
+ container.addEventListener("click", onClick);
207
+ function render(nextProps) {
208
+ props = nextProps;
209
+ session = updateStreamingMarkdownParserSession(session, nextProps.content, nextProps.options, nextProps.isComplete ?? false);
210
+ const state = session.parserState;
211
+ const tree = buildStreamingMarkdownRenderTree(state, {
212
+ caret: nextProps.caret === true,
213
+ nodeClassNames: nextProps.nodeClassNames
214
+ });
215
+ if (!styleElement || !rootElement || rootElement.parentNode !== container) {
216
+ styleElement = doc.createElement("style");
217
+ rootElement = doc.createElement("div");
218
+ rootElement.setAttribute("data-streaming-markdown-root", "");
219
+ previousChildren = [];
220
+ removeAllChildren(container);
221
+ container.appendChild(styleElement);
222
+ container.appendChild(rootElement);
223
+ }
224
+ const styles = getStreamingMarkdownStyles();
225
+ if (styleElement.textContent !== styles) styleElement.textContent = styles;
226
+ const rootClass = nextProps.className ? `${STREAMING_MARKDOWN_ROOT_CLASS} ${nextProps.className}` : STREAMING_MARKDOWN_ROOT_CLASS;
227
+ if (rootElement.className !== rootClass) rootElement.className = rootClass;
228
+ const nextChildren = tree.root ? toVNode(tree.root, {
229
+ document: doc,
230
+ nodeRenderers: nextProps.nodeRenderers,
231
+ overrideCache
232
+ }) : [];
233
+ patchChildren(rootElement, previousChildren, nextChildren, doc);
234
+ previousChildren = nextChildren;
235
+ actions = /* @__PURE__ */ new WeakMap();
236
+ collectActions(nextChildren, actions);
237
+ }
238
+ function destroy() {
239
+ container.removeEventListener("click", onClick);
240
+ removeAllChildren(container);
241
+ session = null;
242
+ styleElement = null;
243
+ rootElement = null;
244
+ previousChildren = [];
245
+ }
246
+ return {
247
+ render,
248
+ destroy
249
+ };
250
+ }
251
+
252
+ //#endregion
253
+ export { createStreamingMarkdownDomRenderer };
254
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/dom/streaming-markdown-dom-renderer.ts"],"sourcesContent":["import {\n STREAMING_MARKDOWN_CARET_ATTRS,\n STREAMING_MARKDOWN_CARET_STYLE,\n STREAMING_MARKDOWN_ROOT_CLASS,\n buildStreamingMarkdownRenderTree,\n getStreamingMarkdownStyles,\n updateStreamingMarkdownParserSession,\n} from \"@copilotkit/markdown\";\nimport type {\n StreamingMarkdownAstNode,\n StreamingMarkdownCitationRenderData,\n StreamingMarkdownNodeClassNames,\n StreamingMarkdownNodeRendererKey,\n StreamingMarkdownParserOptions,\n StreamingMarkdownParserSession,\n StreamingMarkdownRenderAction,\n StreamingMarkdownRenderChild,\n StreamingMarkdownRenderNode,\n} from \"@copilotkit/markdown\";\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Props supplied to a custom DOM node renderer.\n *\n * @public\n */\nexport interface StreamingMarkdownDomNodeRendererProps {\n /** The immutable AST node being rendered. */\n node: StreamingMarkdownAstNode;\n /** Freshly rendered child content for container nodes; `null` for leaves. */\n children: Node[] | null;\n /** Freshly rendered default element for this node. */\n defaultNode: Node | null;\n /** Citation metadata when rendering a citation node. */\n citation?: StreamingMarkdownCitationRenderData;\n /** Document to create nodes with (the container's owner document). */\n document: Document;\n}\n\n/**\n * Custom renderer for one node type. Return the node to insert, or `null`\n * to render nothing.\n *\n * @public\n */\nexport type StreamingMarkdownDomNodeRenderer = (\n props: StreamingMarkdownDomNodeRendererProps,\n) => Node | null;\n\n/**\n * Custom DOM renderers keyed by camelCase node names (`node` is a catch-all).\n *\n * @public\n */\nexport type StreamingMarkdownDomNodeRenderers = Partial<\n Record<StreamingMarkdownNodeRendererKey, StreamingMarkdownDomNodeRenderer>\n>;\n\n/**\n * Inputs for one render. Pass the full set every time, like component props.\n *\n * @public\n */\nexport interface StreamingMarkdownDomRenderProps {\n /** Full markdown source that grows over time. */\n content: string;\n /** `true` once the source is final; hides the caret. */\n isComplete?: boolean;\n /** Parser option overrides. */\n options?: Partial<StreamingMarkdownParserOptions>;\n /** Render the default streaming caret inside the deepest open node. */\n caret?: boolean;\n /** Extra class on the root element. */\n className?: string;\n /** Called when a link or autolink is clicked. */\n onLinkClick?: (\n event: MouseEvent,\n url: string,\n node: StreamingMarkdownAstNode,\n ) => void;\n /** Called when a citation reference with a URL is clicked. */\n onCitationClick?: (\n event: MouseEvent,\n citation: StreamingMarkdownCitationRenderData,\n node: StreamingMarkdownAstNode,\n ) => void;\n /** Custom renderers keyed by node type. */\n nodeRenderers?: StreamingMarkdownDomNodeRenderers;\n /** Extra classes for the default element of a node type. */\n nodeClassNames?: StreamingMarkdownNodeClassNames;\n}\n\n// ---------------------------------------------------------------------------\n// Virtual nodes\n// ---------------------------------------------------------------------------\n\ntype VElement = {\n kind: \"element\";\n key: string;\n tag: string;\n attrs: Readonly<Record<string, string | true>>;\n action?: StreamingMarkdownRenderAction;\n children: VChild[];\n dom?: Element;\n};\ntype VText = { kind: \"text\"; key: string; text: string; dom?: Text };\ntype VRaw = { kind: \"raw\"; key: string; dom: Node };\ntype VChild = VElement | VText | VRaw;\n\ntype BuildContext = {\n document: Document;\n nodeRenderers: StreamingMarkdownDomNodeRenderers | undefined;\n overrideCache: WeakMap<\n StreamingMarkdownAstNode,\n { renderer: StreamingMarkdownDomNodeRenderer; dom: Node | null }\n >;\n};\n\nfunction toKebabCase(property: string) {\n return property.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);\n}\n\nconst CARET_STYLE = Object.entries(STREAMING_MARKDOWN_CARET_STYLE)\n .map(([property, value]) => `${toKebabCase(property)}:${value}`)\n .join(\";\");\n\nfunction caretElement(key: string): VElement {\n return {\n kind: \"element\",\n key,\n tag: \"span\",\n attrs: { ...STREAMING_MARKDOWN_CARET_ATTRS, style: CARET_STYLE },\n children: [],\n };\n}\n\nfunction prefixed(prefix: string, children: VChild[]) {\n return children.map((child) => ({ ...child, key: `${prefix}:${child.key}` }));\n}\n\nfunction toVChildren(\n children: StreamingMarkdownRenderChild[],\n context: BuildContext,\n slot: VChild[],\n): VChild[] {\n return children.flatMap((child) => {\n switch (child.kind) {\n case \"node\":\n return toVNode(child, context);\n case \"element\": {\n const element: VElement = {\n kind: \"element\",\n key: child.key,\n tag: child.tag,\n attrs: child.attrs,\n children: toVChildren(child.children, context, slot),\n };\n return child.action\n ? [{ ...element, action: child.action }]\n : [element];\n }\n case \"text\":\n return [{ kind: \"text\", key: child.key, text: child.text }];\n case \"caret\":\n return [caretElement(child.key)];\n case \"slot\":\n return slot;\n default: {\n const unreachable: never = child;\n return unreachable;\n }\n }\n });\n}\n\nfunction renderOverride(\n renderNode: StreamingMarkdownRenderNode,\n renderer: StreamingMarkdownDomNodeRenderer,\n context: BuildContext,\n) {\n // AST nodes keep their identity while unchanged, so an override's output can\n // be reused unless the caret (which is not part of the node) moves inside it.\n const cached = context.overrideCache.get(renderNode.node);\n if (cached?.renderer === renderer && !renderNode.containsCaret) {\n return cached.dom;\n }\n\n const doc = context.document;\n const materialize = (entries: VChild[]) =>\n entries.map((entry) => createDom(entry, doc));\n const children = renderNode.children\n ? materialize(toVChildren(renderNode.children, context, []))\n : null;\n const defaultNodes = materialize(\n toVChildren(\n renderNode.output,\n context,\n renderNode.children ? toVChildren(renderNode.children, context, []) : [],\n ),\n );\n const defaultNode =\n defaultNodes.length === 1\n ? defaultNodes[0]\n : wrapInFragment(defaultNodes, doc);\n\n const dom = renderer({\n node: renderNode.node,\n children,\n defaultNode,\n citation: renderNode.citation,\n document: doc,\n });\n context.overrideCache.set(renderNode.node, { renderer, dom });\n return dom;\n}\n\nfunction wrapInFragment(nodes: Node[], doc: Document) {\n if (nodes.length === 0) return null;\n const fragment = doc.createDocumentFragment();\n for (const node of nodes) fragment.appendChild(node);\n return fragment;\n}\n\nfunction toVNode(\n renderNode: StreamingMarkdownRenderNode,\n context: BuildContext,\n): VChild[] {\n const renderer =\n context.nodeRenderers?.[renderNode.rendererKey] ??\n context.nodeRenderers?.node;\n if (renderer) {\n const dom = renderOverride(renderNode, renderer, context);\n return dom ? [{ kind: \"raw\", key: renderNode.key, dom }] : [];\n }\n\n const slot = renderNode.children\n ? toVChildren(renderNode.children, context, [])\n : [];\n return prefixed(\n renderNode.key,\n toVChildren(renderNode.output, context, slot),\n );\n}\n\n// ---------------------------------------------------------------------------\n// DOM creation and keyed patching\n// ---------------------------------------------------------------------------\n\nfunction setAttributes(\n element: Element,\n next: Readonly<Record<string, string | true>>,\n previous: Readonly<Record<string, string | true>>,\n) {\n const previousNames = Object.keys(previous);\n for (const name of previousNames) {\n if (!(name in next)) element.removeAttribute(name);\n }\n const entries = Object.entries(next);\n for (const [name, value] of entries) {\n if (previous[name] !== value) {\n element.setAttribute(name, value === true ? \"\" : value);\n }\n }\n}\n\nfunction createDom(child: VChild, doc: Document): Node {\n switch (child.kind) {\n case \"raw\":\n return child.dom;\n case \"text\": {\n child.dom = doc.createTextNode(child.text);\n return child.dom;\n }\n case \"element\": {\n const element = doc.createElement(child.tag);\n setAttributes(element, child.attrs, {});\n for (const entry of child.children) {\n element.appendChild(createDom(entry, doc));\n }\n child.dom = element;\n return element;\n }\n default: {\n const unreachable: never = child;\n return unreachable;\n }\n }\n}\n\n/** Updates `previous`'s DOM to match `next` and returns it, or `null` if incompatible. */\nfunction patchDom(previous: VChild, next: VChild, doc: Document): Node | null {\n if (previous.kind === \"text\" && next.kind === \"text\" && previous.dom) {\n if (previous.text !== next.text) previous.dom.data = next.text;\n next.dom = previous.dom;\n return next.dom;\n }\n if (previous.kind === \"raw\" && next.kind === \"raw\") {\n return previous.dom === next.dom ? next.dom : null;\n }\n const sameElement =\n previous.kind === \"element\" &&\n next.kind === \"element\" &&\n previous.tag === next.tag &&\n previous.dom !== undefined;\n if (!sameElement) {\n return null;\n }\n const element = previous.dom;\n if (!element) return null;\n setAttributes(element, next.attrs, previous.attrs);\n patchChildren(element, previous.children, next.children, doc);\n next.dom = element;\n return element;\n}\n\nfunction patchChildren(\n parent: Node,\n previous: VChild[],\n next: VChild[],\n doc: Document,\n) {\n const unused = new Map(previous.map((child) => [child.key, child]));\n let cursor: Node | null = parent.firstChild;\n\n for (const child of next) {\n const match = unused.get(child.key);\n const reused = match ? patchDom(match, child, doc) : null;\n if (match && reused) unused.delete(child.key);\n const dom = reused ?? createDom(child, doc);\n\n if (dom === cursor) {\n cursor = cursor.nextSibling;\n } else {\n parent.insertBefore(dom, cursor);\n }\n }\n\n const leftovers = Array.from(unused.values());\n for (const child of leftovers) {\n const dom = child.dom;\n if (dom && dom.parentNode === parent) parent.removeChild(dom);\n }\n}\n\n// Server DOMs (domino) lack replaceChildren(), so clear by hand.\nfunction removeAllChildren(parent: Node) {\n while (parent.firstChild) parent.removeChild(parent.firstChild);\n}\n\nfunction collectActions(\n children: VChild[],\n actions: WeakMap<Node, StreamingMarkdownRenderAction>,\n) {\n for (const child of children) {\n if (child.kind !== \"element\" || !child.dom) continue;\n if (child.action) actions.set(child.dom, child.action);\n collectActions(child.children, actions);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Renderer\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a framework-free streaming markdown renderer that draws into\n * `container`. It parses incrementally, renders the same render tree as the\n * React and Vue renderers (same markup, URL sanitization, caret, citations,\n * and per-token fade-in), and patches the DOM by key so text that is already\n * on screen keeps its nodes and does not animate again.\n *\n * Creates nodes with `container.ownerDocument`, so it works with server DOMs\n * that have no global `document`.\n *\n * @param container - Element the renderer owns. Its children are replaced.\n * @returns `render(props)` to draw the latest props, and `destroy()` to remove\n * the output and the click listener.\n *\n * @example\n * ```ts\n * const renderer = createStreamingMarkdownDomRenderer(element);\n * renderer.render({ content: \"**Hi**\", caret: true });\n * renderer.render({ content: \"**Hi** there\", isComplete: true });\n * renderer.destroy();\n * ```\n * @public\n */\nexport function createStreamingMarkdownDomRenderer(container: HTMLElement) {\n const doc = container.ownerDocument;\n let session: StreamingMarkdownParserSession | null = null;\n let props: StreamingMarkdownDomRenderProps = { content: \"\" };\n let styleElement: HTMLStyleElement | null = null;\n let rootElement: HTMLDivElement | null = null;\n let previousChildren: VChild[] = [];\n let actions = new WeakMap<Node, StreamingMarkdownRenderAction>();\n const overrideCache: BuildContext[\"overrideCache\"] = new WeakMap();\n\n // One delegated listener; actions are looked up per click so callbacks and\n // links always reflect the latest render.\n const onClick = (event: MouseEvent) => {\n let target = event.target instanceof Node ? event.target : null;\n while (target && target !== container) {\n const action = actions.get(target);\n if (action?.type === \"link\") {\n props.onLinkClick?.(event, action.url, action.node);\n return;\n }\n if (action?.type === \"citation\") {\n props.onCitationClick?.(event, action.citation, action.node);\n return;\n }\n target = target.parentNode;\n }\n };\n container.addEventListener(\"click\", onClick);\n\n function render(nextProps: StreamingMarkdownDomRenderProps) {\n props = nextProps;\n session = updateStreamingMarkdownParserSession(\n session,\n nextProps.content,\n nextProps.options,\n nextProps.isComplete ?? false,\n );\n const state = session.parserState;\n const tree = buildStreamingMarkdownRenderTree(state, {\n caret: nextProps.caret === true,\n nodeClassNames: nextProps.nodeClassNames,\n });\n\n if (!styleElement || !rootElement || rootElement.parentNode !== container) {\n styleElement = doc.createElement(\"style\");\n rootElement = doc.createElement(\"div\");\n rootElement.setAttribute(\"data-streaming-markdown-root\", \"\");\n previousChildren = [];\n removeAllChildren(container);\n container.appendChild(styleElement);\n container.appendChild(rootElement);\n }\n const styles = getStreamingMarkdownStyles();\n if (styleElement.textContent !== styles) styleElement.textContent = styles;\n const rootClass = nextProps.className\n ? `${STREAMING_MARKDOWN_ROOT_CLASS} ${nextProps.className}`\n : STREAMING_MARKDOWN_ROOT_CLASS;\n if (rootElement.className !== rootClass) rootElement.className = rootClass;\n\n const nextChildren = tree.root\n ? toVNode(tree.root, {\n document: doc,\n nodeRenderers: nextProps.nodeRenderers,\n overrideCache,\n })\n : [];\n patchChildren(rootElement, previousChildren, nextChildren, doc);\n previousChildren = nextChildren;\n actions = new WeakMap();\n collectActions(nextChildren, actions);\n }\n\n function destroy() {\n container.removeEventListener(\"click\", onClick);\n removeAllChildren(container);\n session = null;\n styleElement = null;\n rootElement = null;\n previousChildren = [];\n }\n\n return { render, destroy };\n}\n\n/**\n * Renderer returned by {@link createStreamingMarkdownDomRenderer}.\n * @public\n */\nexport type StreamingMarkdownDomRenderer = ReturnType<\n typeof createStreamingMarkdownDomRenderer\n>;\n"],"mappings":"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"}