@stream-mdx/react 0.5.0 → 1.0.0

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.
Files changed (99) hide show
  1. package/CHANGELOG.md +371 -0
  2. package/README.md +79 -4
  3. package/dist/blocks-renderer-DAOBFBfi.d.ts +29 -0
  4. package/dist/blocks-renderer-DQEL1kJW.d.cts +29 -0
  5. package/dist/components/bottom-stick-scroll-area.cjs +117 -193
  6. package/dist/components/bottom-stick-scroll-area.mjs +112 -183
  7. package/dist/components/diff-renderer.cjs +86 -0
  8. package/dist/components/diff-renderer.d.cts +11 -0
  9. package/dist/components/diff-renderer.d.ts +11 -0
  10. package/dist/components/diff-renderer.mjs +66 -0
  11. package/dist/components/index.cjs +2761 -1508
  12. package/dist/components/index.d.cts +7 -2
  13. package/dist/components/index.d.ts +7 -2
  14. package/dist/components/index.mjs +2730 -1493
  15. package/dist/components/katex-math.cjs +220 -0
  16. package/dist/components/katex-math.d.cts +10 -0
  17. package/dist/components/katex-math.d.ts +10 -0
  18. package/dist/components/katex-math.mjs +188 -0
  19. package/dist/contexts/math-tracker.cjs +240 -521
  20. package/dist/contexts/math-tracker.mjs +235 -513
  21. package/dist/index-Cmne1yUK.d.cts +723 -0
  22. package/dist/index-D7dyyu3q.d.ts +723 -0
  23. package/dist/index.cjs +13029 -6475
  24. package/dist/index.d.cts +69 -39
  25. package/dist/index.d.ts +69 -39
  26. package/dist/index.mjs +13007 -6442
  27. package/dist/math/display-wrapper.cjs +7 -15
  28. package/dist/math/display-wrapper.d.cts +2 -2
  29. package/dist/math/display-wrapper.d.ts +2 -2
  30. package/dist/math/display-wrapper.mjs +2 -6
  31. package/dist/node-views-Bpc6Gkgl.d.cts +13 -0
  32. package/dist/node-views-DpnYdaAS.d.ts +13 -0
  33. package/dist/renderer/hooks.cjs +35 -20
  34. package/dist/renderer/hooks.d.cts +22 -1
  35. package/dist/renderer/hooks.d.ts +22 -1
  36. package/dist/renderer/hooks.mjs +27 -12
  37. package/dist/renderer/patch-batching.cjs +5 -8
  38. package/dist/renderer/patch-coalescing.cjs +5 -8
  39. package/dist/renderer/patch-commit-scheduler.cjs +138 -356
  40. package/dist/renderer/patch-commit-scheduler.d.cts +13 -1
  41. package/dist/renderer/patch-commit-scheduler.d.ts +13 -1
  42. package/dist/renderer/patch-commit-scheduler.mjs +133 -348
  43. package/dist/renderer/store.cjs +3775 -1373
  44. package/dist/renderer/store.d.cts +108 -3
  45. package/dist/renderer/store.d.ts +108 -3
  46. package/dist/renderer/store.mjs +3778 -1362
  47. package/dist/renderer/virtualized-code.cjs +415 -71
  48. package/dist/renderer/virtualized-code.d.cts +24 -23
  49. package/dist/renderer/virtualized-code.d.ts +24 -23
  50. package/dist/renderer/virtualized-code.mjs +409 -62
  51. package/dist/renderer.cjs +10655 -4334
  52. package/dist/renderer.d.cts +98 -29
  53. package/dist/renderer.d.ts +98 -29
  54. package/dist/renderer.mjs +10582 -4212
  55. package/dist/server-regions-CPLHGli0.d.cts +32 -0
  56. package/dist/server-regions-mUhyoKi7.d.ts +32 -0
  57. package/dist/server.cjs +10195 -3872
  58. package/dist/server.d.cts +17 -252
  59. package/dist/server.d.ts +17 -252
  60. package/dist/server.mjs +9997 -3649
  61. package/dist/{streaming-markdown-CEI9eDZm.d.ts → streaming-markdown-yELbJxyH.d.ts} +49 -55
  62. package/dist/{streaming-markdown-DRisClXb.d.cts → streaming-markdown-zVwFuaJG.d.cts} +49 -55
  63. package/dist/streaming-markdown.cjs +11660 -5378
  64. package/dist/streaming-markdown.d.cts +7 -2
  65. package/dist/streaming-markdown.d.ts +7 -2
  66. package/dist/streaming-markdown.mjs +11679 -5347
  67. package/dist/trusted-mdx/index.cjs +833 -0
  68. package/dist/trusted-mdx/index.d.cts +11 -0
  69. package/dist/trusted-mdx/index.d.ts +11 -0
  70. package/dist/trusted-mdx/index.mjs +807 -0
  71. package/dist/trusted-mdx/native-children-slot.cjs +45 -0
  72. package/dist/trusted-mdx/native-children-slot.d.cts +11 -0
  73. package/dist/trusted-mdx/native-children-slot.d.ts +11 -0
  74. package/dist/trusted-mdx/native-children-slot.mjs +24 -0
  75. package/dist/trusted-mdx/server.cjs +752 -0
  76. package/dist/trusted-mdx/server.d.cts +24 -0
  77. package/dist/trusted-mdx/server.d.ts +24 -0
  78. package/dist/trusted-mdx/server.mjs +724 -0
  79. package/dist/trusted-mdx-contract-ElKpkDI5.d.cts +113 -0
  80. package/dist/trusted-mdx-contract-ElKpkDI5.d.ts +113 -0
  81. package/dist/utils/inline-html.cjs +246 -147
  82. package/dist/utils/inline-html.d.cts +37 -6
  83. package/dist/utils/inline-html.d.ts +37 -6
  84. package/dist/utils/inline-html.mjs +237 -134
  85. package/package.json +41 -18
  86. package/dist/index-BVhp_pcF.d.ts +0 -251
  87. package/dist/index-EaeouYp2.d.cts +0 -251
  88. package/dist/mdx-client.cjs +0 -408
  89. package/dist/mdx-client.d.cts +0 -113
  90. package/dist/mdx-client.d.ts +0 -113
  91. package/dist/mdx-client.mjs +0 -369
  92. package/dist/mdx-coordinator.cjs +0 -584
  93. package/dist/mdx-coordinator.d.cts +0 -21
  94. package/dist/mdx-coordinator.d.ts +0 -21
  95. package/dist/mdx-coordinator.mjs +0 -550
  96. package/dist/renderer/node-views.cjs +0 -1887
  97. package/dist/renderer/node-views.d.cts +0 -14
  98. package/dist/renderer/node-views.d.ts +0 -14
  99. package/dist/renderer/node-views.mjs +0 -1861
@@ -2,86 +2,169 @@
2
2
 
3
3
  // src/utils/inline-html.ts
4
4
  import React from "react";
5
- var BACKTICK_CONTENT = /^`([\s\S]+)`$/;
6
- var DEFAULT_INLINE_HTML_RENDERERS = {
5
+ import { defaultUrlTransform, isForbiddenAttribute, isSafeStyleDeclaration } from "@stream-mdx/core";
6
+ function renderHtmlInlineNode(node, children, elements, key, textValue, urlTransform, filterElement, parentTagName, renderPresentation, renderNativeElement) {
7
+ if (node.isClose || node.tagName === "script" || node.tagName === "style") return null;
8
+ if (!node.tagName || node.sanitized === "")
9
+ return React.createElement(React.Fragment, { key }, children);
10
+ let tag = node.tagName.toLowerCase(), props = mapAttributesToProps(node.attributes ?? {}, urlTransform);
11
+ props.key = key;
12
+ let renderElement = () => {
13
+ let nativeView;
14
+ return renderNativeElement ? nativeView = renderNativeElement(
15
+ tag,
16
+ props,
17
+ node.isSelfClosing ? void 0 : children,
18
+ key ?? tag
19
+ ) : tag === "textarea" ? (props.defaultValue = textValue ?? "", nativeView = React.createElement(elements?.[tag] ?? tag, props)) : nativeView = React.createElement(elements?.[tag] ?? tag, props, node.isSelfClosing ? void 0 : children), renderPresentation ? renderPresentation(tag, props, nativeView, children, key ?? tag) : nativeView;
20
+ };
21
+ return filterElement ? filterElement(
22
+ { tagName: tag, properties: props },
23
+ { source: "html", parentTagName },
24
+ renderElement,
25
+ () => children
26
+ ) : renderElement();
27
+ }
28
+ function renderHtmlOwnershipTree(nodes, elements, renderBlock, renderInline, renderInlineElement, renderParagraph, urlTransform, filterElement, parentTagName, contentComponents, renderPresentation, parentPath = "html", renderComponentPresentation) {
29
+ return nodes.map((node, index) => {
30
+ let nodeKey = `${parentPath}:${index}`;
31
+ if (node.kind === "text") return node.inline && renderInline ? renderInline(node.inline, parentTagName) : node.rawSource ?? node.text;
32
+ if (node.kind === "block") return renderBlock(node.block, parentTagName);
33
+ if (node.kind === "component") {
34
+ let reg = contentComponents?.[node.name];
35
+ if (!reg)
36
+ return React.createElement(React.Fragment, { key: nodeKey }, node.rawSource ?? `<${node.name} />`);
37
+ let result = reg.render({
38
+ props: node.props,
39
+ key: index,
40
+ hasChildren: node.children.length > 0,
41
+ renderChildren: () => renderHtmlOwnershipTree(
42
+ node.children,
43
+ elements,
44
+ renderBlock,
45
+ renderInline,
46
+ renderInlineElement,
47
+ renderParagraph,
48
+ urlTransform,
49
+ filterElement,
50
+ node.name,
51
+ contentComponents,
52
+ renderPresentation,
53
+ nodeKey,
54
+ renderComponentPresentation
55
+ ),
56
+ status: node.status,
57
+ diagnostic: node.diagnostic
58
+ });
59
+ return result.kind === "invalid" ? React.createElement(React.Fragment, { key: nodeKey }, node.rawSource ?? `<${node.name} />`) : result.kind === "suppressed" ? null : renderComponentPresentation ? renderComponentPresentation(
60
+ node.name,
61
+ result.element,
62
+ React.isValidElement(result.element) ? result.element.props.children : void 0,
63
+ nodeKey,
64
+ node.status,
65
+ node.rawSource
66
+ ) : result.element;
67
+ }
68
+ let tag = node.tagName.toLowerCase(), props = mapAttributesToProps(node.attributes, urlTransform);
69
+ props.key = nodeKey;
70
+ let children = renderHtmlOwnershipTree(node.children, elements, renderBlock, renderInline, renderInlineElement, renderParagraph, urlTransform, filterElement, tag, contentComponents, renderPresentation, nodeKey, renderComponentPresentation);
71
+ if (node.paragraphRoot && renderParagraph) {
72
+ let paragraph = filterElement ? filterElement(
73
+ { tagName: "p", properties: props, blockType: "paragraph" },
74
+ { source: "markdown", parentTagName },
75
+ () => renderParagraph(children),
76
+ () => children
77
+ ) : renderParagraph(children);
78
+ return React.createElement(React.Fragment, { key: nodeKey }, paragraph);
79
+ }
80
+ if (node.inlineNode && renderInlineElement)
81
+ return React.createElement(React.Fragment, { key: nodeKey }, renderInlineElement(node.inlineNode, children, parentTagName, nodeKey));
82
+ let renderElement = () => {
83
+ let nativeView;
84
+ if (tag === "textarea")
85
+ props.defaultValue = node.children.map((child) => child.kind === "text" ? child.text : "").join(""), nativeView = React.createElement(elements[tag] ?? tag, props);
86
+ else {
87
+ let content = tag === "pre" && node.children.every((child) => child.kind === "text" && !child.inline) ? node.children.map((child) => child.kind === "text" ? child.text : "").join("") : children;
88
+ nativeView = React.createElement(elements[tag] ?? tag, props, node.children.length ? content : void 0);
89
+ }
90
+ return renderPresentation ? renderPresentation(tag, props, nativeView, children, nodeKey) : nativeView;
91
+ };
92
+ return filterElement ? filterElement(
93
+ { tagName: tag, properties: props },
94
+ { source: "html", parentTagName },
95
+ renderElement,
96
+ () => children
97
+ ) : renderElement();
98
+ });
99
+ }
100
+ var BACKTICK_CONTENT = /^`([\s\S]+)`$/, DEFAULT_INLINE_HTML_RENDERERS = {
7
101
  kbd: (descriptor, ctx) => {
8
- const trimmed = descriptor.rawInner.trim();
9
- const match = BACKTICK_CONTENT.exec(trimmed);
102
+ let trimmed = descriptor.rawInner.trim(), match = BACKTICK_CONTENT.exec(trimmed);
10
103
  if (match) {
11
- const codeText = decodeHtmlEntities(match[1]);
12
- const props = mapAttributesToProps(descriptor.attributes);
13
- if (ctx.key !== void 0 && ctx.key !== null) {
14
- props.key = ctx.key;
15
- }
16
- return React.createElement("kbd", props, React.createElement("code", { className: "inline-code" }, codeText));
104
+ let codeText = decodeHtmlEntities(match[1]), props = mapAttributesToProps(descriptor.attributes);
105
+ return ctx.key !== void 0 && ctx.key !== null && (props.key = ctx.key), React.createElement("kbd", props, React.createElement("code", { className: "inline-code" }, codeText));
17
106
  }
18
107
  return ctx.defaultRender();
19
108
  }
20
109
  };
21
110
  function renderInlineHtmlSegment(raw, sanitized, options = {}) {
22
- const descriptor = parseInlineHtmlDescriptor(raw, sanitized);
23
- if (!descriptor) {
111
+ let descriptor = parseInlineHtmlDescriptor(raw, sanitized);
112
+ if (!descriptor)
24
113
  return null;
25
- }
26
- const className = options.className ?? "markdown-inline-html";
27
- const isInlineTag = INLINE_ELEMENTS.has(descriptor.tagName);
28
- const defaultRender = () => {
29
- if (!descriptor.sanitized || descriptor.sanitized.length === 0) {
30
- if (!descriptor.text) {
31
- return null;
32
- }
33
- if (options.key !== void 0 && options.key !== null) {
34
- return React.createElement(React.Fragment, { key: options.key }, descriptor.text);
35
- }
36
- return React.createElement(React.Fragment, {}, descriptor.text);
37
- }
114
+ let className = options.className ?? "markdown-inline-html", hasCustomElement = !!options.htmlElements?.[descriptor.tagName], isInlineTag = INLINE_ELEMENTS.has(descriptor.tagName) || hasCustomElement, defaultRender = () => {
115
+ if (!descriptor.sanitized || descriptor.sanitized.length === 0)
116
+ return descriptor.text ? options.key !== void 0 && options.key !== null ? React.createElement(React.Fragment, { key: options.key }, descriptor.text) : React.createElement(React.Fragment, {}, descriptor.text) : null;
38
117
  if (isInlineTag) {
39
- const parsedElement = renderSanitizedHtmlTree(descriptor.sanitized, options.key);
40
- if (parsedElement) {
118
+ let parsedElement = renderSanitizedHtmlTree(
119
+ descriptor.sanitized,
120
+ options.key,
121
+ options.htmlElements,
122
+ options.literalTagContent,
123
+ options.parseMarkdown
124
+ );
125
+ if (parsedElement)
41
126
  return parsedElement;
42
- }
43
127
  }
44
- const props = {
128
+ let customElementComp = options.htmlElements?.[descriptor.tagName];
129
+ if (customElementComp) {
130
+ let props2 = mapAttributesToProps(descriptor.attributes, options.urlTransform);
131
+ return options.key !== void 0 && options.key !== null && (props2.key = options.key), React.createElement(customElementComp, props2, descriptor.text || descriptor.sanitizedInner || void 0);
132
+ }
133
+ let props = {
45
134
  className,
46
135
  dangerouslySetInnerHTML: { __html: descriptor.sanitized }
47
136
  };
48
- if (options.key !== void 0 && options.key !== null) {
49
- props.key = options.key;
50
- }
51
- return React.createElement("span", props);
137
+ return options.key !== void 0 && options.key !== null && (props.key = options.key), React.createElement("span", props);
52
138
  };
53
- const allRenderers = options.renderers ? { ...DEFAULT_INLINE_HTML_RENDERERS, ...options.renderers } : DEFAULT_INLINE_HTML_RENDERERS;
54
- const renderer = allRenderers[descriptor.tagName];
55
- if (renderer) {
56
- const rendered = renderer(descriptor, { key: options.key, defaultRender });
57
- if (rendered) {
58
- if (options.key !== void 0 && options.key !== null && React.isValidElement(rendered) && rendered.key === null) {
59
- return React.cloneElement(rendered, { key: options.key });
60
- }
61
- return rendered;
139
+ if (!hasCustomElement) {
140
+ let renderer = (options.renderers ? { ...DEFAULT_INLINE_HTML_RENDERERS, ...options.renderers } : DEFAULT_INLINE_HTML_RENDERERS)[descriptor.tagName];
141
+ if (renderer) {
142
+ let rendered = renderer(descriptor, { key: options.key, defaultRender });
143
+ if (rendered)
144
+ return options.key !== void 0 && options.key !== null && React.isValidElement(rendered) && rendered.key === null ? React.cloneElement(rendered, { key: options.key }) : rendered;
62
145
  }
63
146
  }
64
147
  return defaultRender();
65
148
  }
66
149
  function parseInlineHtmlDescriptor(raw, sanitized) {
67
- const normalizedRaw = typeof raw === "string" ? raw.trim() : "";
68
- const normalizedSanitized = typeof sanitized === "string" && sanitized.length > 0 ? sanitized.trim() : normalizedRaw;
69
- if (!normalizedSanitized) {
70
- return null;
71
- }
72
- const match = normalizedSanitized.match(/^<([A-Za-z][\w:-]*)(\s[^>]*)?>([\s\S]*)<\/\1>$/);
73
- if (!match) {
150
+ let normalizedRaw = typeof raw == "string" ? raw.trim() : "", normalizedSanitized = typeof sanitized == "string" && sanitized.length > 0 ? sanitized.trim() : normalizedRaw;
151
+ if (!normalizedSanitized)
74
152
  return null;
153
+ let pairedMatch = normalizedSanitized.match(/^<([A-Za-z][\w:-]*)((?:\s+[^>]*)?)>([\s\S]*)<\/\1>$/), tagNameRaw, attrString = "", sanitizedInner = "";
154
+ if (pairedMatch)
155
+ tagNameRaw = pairedMatch[1], attrString = pairedMatch[2] ?? "", sanitizedInner = pairedMatch[3] ?? "";
156
+ else {
157
+ let selfClosingMatch = normalizedSanitized.match(/^<([A-Za-z][\w:-]*)((?:\s+[^>]*)?)\s*(?:\/?>|>)$/) || normalizedRaw.match(/^<([A-Za-z][\w:-]*)((?:\s+[^>]*)?)\s*(?:\/?>|>)$/);
158
+ if (!selfClosingMatch)
159
+ return null;
160
+ tagNameRaw = selfClosingMatch[1], attrString = selfClosingMatch[2] ?? "", sanitizedInner = "";
75
161
  }
76
- const [, tagNameRaw, attrString = "", sanitizedInner = ""] = match;
77
- const tagName = tagNameRaw.toLowerCase();
78
- const attributes = parseAttributes(attrString);
79
- let rawInner = "";
162
+ let tagName = tagNameRaw.toLowerCase(), attributes = parseAttributes(attrString), rawInner = "";
80
163
  if (normalizedRaw) {
81
- const rawMatch = normalizedRaw.match(/^<([A-Za-z][\w:-]*)(\s[^>]*)?>([\s\S]*)<\/\1>$/);
164
+ let rawMatch = normalizedRaw.match(/^<([A-Za-z][\w:-]*)(\s[^>]*)?>([\s\S]*)<\/\1>$/);
82
165
  rawInner = rawMatch ? rawMatch[3] ?? "" : normalizedRaw;
83
166
  }
84
- const text = extractPlainText(rawInner || sanitizedInner);
167
+ let text = extractPlainText(rawInner || sanitizedInner);
85
168
  return {
86
169
  tagName,
87
170
  attributes,
@@ -93,52 +176,91 @@ function parseInlineHtmlDescriptor(raw, sanitized) {
93
176
  };
94
177
  }
95
178
  function parseAttributes(input) {
96
- const attrs = {};
179
+ let attrs = {};
97
180
  if (!input) return attrs;
98
- const attrPattern = /([A-Za-z_:][\w:.\-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
99
- let match = attrPattern.exec(input);
100
- while (match !== null) {
101
- const name = match[1];
181
+ let attrPattern = /([A-Za-z_:][\w:.\-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g, match = attrPattern.exec(input);
182
+ for (; match !== null; ) {
183
+ let name = match[1];
102
184
  if (!name) continue;
103
- const value = match[2] ?? match[3] ?? match[4] ?? "";
104
- attrs[name] = value;
105
- match = attrPattern.exec(input);
185
+ let value = match[2] ?? match[3] ?? match[4] ?? "";
186
+ attrs[name] = value, match = attrPattern.exec(input);
106
187
  }
107
188
  return attrs;
108
189
  }
109
- function mapAttributesToProps(attrs) {
110
- const props = {};
111
- for (const [key, value] of Object.entries(attrs)) {
112
- if (key === "class") {
113
- props.className = value;
114
- } else if (key === "style") {
115
- props.style = parseStyleAttribute(value);
116
- } else if (key === "tabindex" || key === "tabIndex") {
117
- const normalized = normalizeTabIndex(value);
118
- if (normalized !== void 0) {
119
- props.tabIndex = normalized;
120
- }
121
- } else {
122
- props[key] = value;
123
- }
190
+ var BOOLEAN_HTML_PROPS = {
191
+ allowFullScreen: !0,
192
+ async: !0,
193
+ autoFocus: !0,
194
+ autoPlay: !0,
195
+ checked: !0,
196
+ controls: !0,
197
+ default: !0,
198
+ defer: !0,
199
+ disabled: !0,
200
+ formNoValidate: !0,
201
+ hidden: !0,
202
+ inert: !0,
203
+ loop: !0,
204
+ multiple: !0,
205
+ muted: !0,
206
+ noModule: !0,
207
+ noValidate: !0,
208
+ open: !0,
209
+ playsInline: !0,
210
+ readOnly: !0,
211
+ required: !0,
212
+ reversed: !0,
213
+ selected: !0,
214
+ itemScope: !0
215
+ };
216
+ function mapAttributesToProps(attrs, urlTransform) {
217
+ let props = {}, transform = urlTransform ?? defaultUrlTransform;
218
+ for (let [key, value] of Object.entries(attrs)) {
219
+ let lower = key.toLowerCase();
220
+ if (!isForbiddenAttribute(lower))
221
+ if (key === "class")
222
+ props.className = value;
223
+ else if (key === "style")
224
+ props.style = parseStyleAttribute(value);
225
+ else if (key === "tabindex" || key === "tabIndex") {
226
+ let normalized = normalizeTabIndex(value);
227
+ normalized !== void 0 && (props.tabIndex = normalized);
228
+ } else if (lower === "href") {
229
+ let safe = transform(value, "href", { source: "html" });
230
+ safe != null && (props.href = safe);
231
+ } else if (lower === "src") {
232
+ let safe = transform(value, "src", { source: "html" });
233
+ safe != null && (props.src = safe);
234
+ } else if (lower === "action") {
235
+ let safe = transform(value, "href", { source: "html" });
236
+ safe != null && (props.action = safe);
237
+ } else if (lower === "formaction") {
238
+ let safe = transform(value, "href", { source: "html" });
239
+ safe != null && (props.formAction = safe);
240
+ } else if (lower === "xlink:href" || lower === "xlinkhref") {
241
+ let safe = transform(value, "href", { source: "html" });
242
+ safe != null && (props.xlinkHref = safe);
243
+ } else /^(?:data|aria)[A-Z]/.test(key) ? props[key.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)] = value : BOOLEAN_HTML_PROPS[key] ? props[key] = !0 : props[key] = value;
124
244
  }
125
245
  return props;
126
246
  }
127
247
  function parseStyleAttribute(value) {
128
- const style = {};
248
+ let style = {};
129
249
  if (!value) return style;
130
- const pairs = value.split(";");
131
- for (const pair of pairs) {
250
+ let pairs = value.split(";");
251
+ for (let pair of pairs) {
132
252
  if (!pair.trim()) continue;
133
- const [property, rawVal] = pair.split(":");
134
- if (!property || rawVal === void 0) continue;
135
- const camelProp = property.trim().replace(/-([a-z])/g, (_, char) => char.toUpperCase());
136
- style[camelProp] = rawVal.trim();
253
+ let separator = pair.indexOf(":");
254
+ if (separator <= 0) continue;
255
+ let property = pair.slice(0, separator).trim(), rawVal = pair.slice(separator + 1).trim();
256
+ if (!isSafeStyleDeclaration(property, rawVal)) continue;
257
+ let camelProp = property.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
258
+ style[camelProp] = rawVal;
137
259
  }
138
260
  return style;
139
261
  }
140
262
  function normalizeTabIndex(value) {
141
- const numeric = Number(value);
263
+ let numeric = Number(value);
142
264
  return Number.isNaN(numeric) ? void 0 : numeric;
143
265
  }
144
266
  function decodeHtmlEntities(value) {
@@ -146,76 +268,50 @@ function decodeHtmlEntities(value) {
146
268
  }
147
269
  function extractPlainText(value) {
148
270
  if (!value) return "";
149
- const withoutTags = value.replace(/<\/?[^>]+>/g, "");
271
+ let withoutTags = value.replace(/<\/?[^>]+>/g, "");
150
272
  return decodeHtmlEntities(withoutTags);
151
273
  }
152
- function renderSanitizedHtmlTree(html, key) {
153
- if (typeof DOMParser === "undefined") {
274
+ var DEFAULT_LITERAL_TAGS = /* @__PURE__ */ new Set(["code", "pre", "script", "style", "textarea"]);
275
+ function renderSanitizedHtmlTree(html, key, htmlElements, literalTagContent, parseMarkdown) {
276
+ if (typeof DOMParser > "u")
154
277
  return null;
155
- }
156
278
  try {
157
- const parser = new DOMParser();
158
- const doc = parser.parseFromString(html, "text/html");
159
- const body = doc.body;
160
- const nodes = Array.from(body.childNodes);
161
- if (nodes.length === 0) {
279
+ let body = new DOMParser().parseFromString(html, "text/html").body, nodes = Array.from(body.childNodes);
280
+ if (nodes.length === 0)
162
281
  return null;
163
- }
164
- const baseKey = typeof key === "string" || typeof key === "number" ? String(key) : "inline-html";
165
- const children = nodes.map((node, index) => convertDomNode(node, `${baseKey}-${index}`)).filter((child) => child !== null && child !== void 0);
166
- if (children.length === 0) {
282
+ let literalTags = literalTagContent ? /* @__PURE__ */ new Set([...DEFAULT_LITERAL_TAGS, ...literalTagContent.map((t) => t.toLowerCase())]) : DEFAULT_LITERAL_TAGS, baseKey = typeof key == "string" || typeof key == "number" ? String(key) : "inline-html", children = nodes.map((node, index) => convertDomNode(node, `${baseKey}-${index}`, htmlElements, literalTags, !1, parseMarkdown)).filter((child) => child != null);
283
+ if (children.length === 0)
167
284
  return null;
168
- }
169
285
  if (children.length === 1) {
170
- const [child] = children;
171
- if (React.isValidElement(child)) {
172
- if (key !== void 0 && key !== null) {
173
- return React.cloneElement(child, { key });
174
- }
175
- return child;
176
- }
177
- if (typeof child === "string" || typeof child === "number") {
178
- if (key !== void 0 && key !== null) {
179
- return React.createElement(React.Fragment, { key }, child);
180
- }
181
- return React.createElement(React.Fragment, {}, child);
182
- }
183
- return React.createElement(React.Fragment, { key }, child);
286
+ let [child] = children;
287
+ return React.isValidElement(child) ? key != null ? React.cloneElement(child, { key }) : child : typeof child == "string" || typeof child == "number" ? key != null ? React.createElement(React.Fragment, { key }, child) : React.createElement(React.Fragment, {}, child) : React.createElement(React.Fragment, { key }, child);
184
288
  }
185
289
  return React.createElement(React.Fragment, { key }, ...children);
186
290
  } catch {
187
291
  return null;
188
292
  }
189
293
  }
190
- function convertDomNode(node, key) {
294
+ function convertDomNode(node, key, htmlElements, literalTags, parentIsLiteral, parseMarkdown) {
191
295
  if (node.nodeType === Node.TEXT_NODE) {
192
- return node.textContent ?? "";
296
+ let rawText = node.textContent ?? "";
297
+ return parentIsLiteral || !parseMarkdown ? rawText : parseMarkdown(rawText);
193
298
  }
194
- if (node.nodeType !== Node.ELEMENT_NODE) {
299
+ if (node.nodeType !== Node.ELEMENT_NODE)
195
300
  return null;
196
- }
197
- const element = node;
198
- const tagName = element.tagName.toLowerCase();
199
- const attrs = getElementAttributes(element);
200
- const props = mapAttributesToProps(attrs);
301
+ let element = node, tagName = element.tagName.toLowerCase(), attrs = getElementAttributes(element), props = mapAttributesToProps(attrs);
201
302
  props.key = key;
202
- const children = [];
303
+ let isLiteral = parentIsLiteral || (literalTags ? literalTags.has(tagName) : !1), children = [];
203
304
  element.childNodes.forEach((child, index) => {
204
- const converted = convertDomNode(child, `${key}-${index}`);
205
- if (converted !== null && converted !== void 0) {
206
- children.push(converted);
207
- }
305
+ let converted = convertDomNode(child, `${key}-${index}`, htmlElements, literalTags, isLiteral, parseMarkdown);
306
+ converted != null && children.push(converted);
208
307
  });
209
- if (children.length === 0) {
210
- return React.createElement(tagName, props);
211
- }
212
- return React.createElement(tagName, props, ...children);
308
+ let customComponent = htmlElements?.[tagName];
309
+ return customComponent ? children.length === 0 ? React.createElement(customComponent, props) : React.createElement(customComponent, props, ...children) : children.length === 0 ? React.createElement(tagName, props) : React.createElement(tagName, props, ...children);
213
310
  }
214
311
  function getElementAttributes(element) {
215
- const attrs = {};
216
- for (const attr of Array.from(element.attributes)) {
312
+ let attrs = {};
313
+ for (let attr of Array.from(element.attributes))
217
314
  attrs[attr.name] = attr.value;
218
- }
219
315
  return attrs;
220
316
  }
221
317
  var INLINE_ELEMENTS = /* @__PURE__ */ new Set([
@@ -225,6 +321,11 @@ var INLINE_ELEMENTS = /* @__PURE__ */ new Set([
225
321
  "bdi",
226
322
  "bdo",
227
323
  "br",
324
+ "img",
325
+ "input",
326
+ "picture",
327
+ "del",
328
+ "ins",
228
329
  "cite",
229
330
  "code",
230
331
  "data",
@@ -270,5 +371,7 @@ var INLINE_ELEMENTS = /* @__PURE__ */ new Set([
270
371
  ]);
271
372
  export {
272
373
  DEFAULT_INLINE_HTML_RENDERERS,
374
+ renderHtmlInlineNode,
375
+ renderHtmlOwnershipTree,
273
376
  renderInlineHtmlSegment
274
377
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-mdx/react",
3
- "version": "0.5.0",
3
+ "version": "1.0.0",
4
4
  "description": "React renderer, scheduler, and worker wiring for the Streaming Markdown V2 pipeline",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -41,10 +41,20 @@
41
41
  "import": "./dist/components/bottom-stick-scroll-area.mjs",
42
42
  "require": "./dist/components/bottom-stick-scroll-area.cjs"
43
43
  },
44
+ "./components/diff-renderer": {
45
+ "types": "./dist/components/diff-renderer.d.ts",
46
+ "import": "./dist/components/diff-renderer.mjs",
47
+ "require": "./dist/components/diff-renderer.cjs"
48
+ },
49
+ "./components/katex-math": {
50
+ "types": "./dist/components/katex-math.d.ts",
51
+ "import": "./dist/components/katex-math.mjs",
52
+ "require": "./dist/components/katex-math.cjs"
53
+ },
44
54
  "./renderer": {
45
- "types": "./dist/renderer/index.d.ts",
46
- "import": "./dist/renderer/index.mjs",
47
- "require": "./dist/renderer/index.cjs"
55
+ "types": "./dist/renderer.d.ts",
56
+ "import": "./dist/renderer.mjs",
57
+ "require": "./dist/renderer.cjs"
48
58
  },
49
59
  "./renderer/patch-commit-scheduler": {
50
60
  "types": "./dist/renderer/patch-commit-scheduler.d.ts",
@@ -66,16 +76,6 @@
66
76
  "import": "./dist/renderer/store.mjs",
67
77
  "require": "./dist/renderer/store.cjs"
68
78
  },
69
- "./mdx-client": {
70
- "types": "./dist/mdx-client.d.ts",
71
- "import": "./dist/mdx-client.mjs",
72
- "require": "./dist/mdx-client.cjs"
73
- },
74
- "./mdx-coordinator": {
75
- "types": "./dist/mdx-coordinator.d.ts",
76
- "import": "./dist/mdx-coordinator.mjs",
77
- "require": "./dist/mdx-coordinator.cjs"
78
- },
79
79
  "./math/display-wrapper": {
80
80
  "types": "./dist/math/display-wrapper.d.ts",
81
81
  "import": "./dist/math/display-wrapper.mjs",
@@ -85,6 +85,21 @@
85
85
  "types": "./dist/contexts/math-tracker.d.ts",
86
86
  "import": "./dist/contexts/math-tracker.mjs",
87
87
  "require": "./dist/contexts/math-tracker.cjs"
88
+ },
89
+ "./trusted-mdx/server": {
90
+ "types": "./dist/trusted-mdx/server.d.ts",
91
+ "import": "./dist/trusted-mdx/server.mjs",
92
+ "require": "./dist/trusted-mdx/server.cjs"
93
+ },
94
+ "./_internal/trusted-mdx-native-children": {
95
+ "types": "./dist/trusted-mdx/native-children-slot.d.ts",
96
+ "import": "./dist/trusted-mdx/native-children-slot.mjs",
97
+ "require": "./dist/trusted-mdx/native-children-slot.cjs"
98
+ },
99
+ "./trusted-mdx": {
100
+ "types": "./dist/trusted-mdx/index.d.ts",
101
+ "import": "./dist/trusted-mdx/index.mjs",
102
+ "require": "./dist/trusted-mdx/index.cjs"
88
103
  }
89
104
  },
90
105
  "files": [
@@ -95,20 +110,28 @@
95
110
  ],
96
111
  "sideEffects": false,
97
112
  "scripts": {
98
- "build": "tsup",
113
+ "build": "npm run clean && tsup",
99
114
  "test": "tsx ../../scripts/run-tests.ts __tests__",
100
115
  "clean": "rm -rf dist",
101
116
  "prepack": "npm run build"
102
117
  },
103
118
  "dependencies": {
104
- "@stream-mdx/core": "0.5.0",
105
- "@stream-mdx/worker": "0.5.0"
119
+ "@stream-mdx/core": "1.0.0",
120
+ "@stream-mdx/protocol": "1.0.0",
121
+ "@stream-mdx/worker": "1.0.0"
106
122
  },
107
123
  "devDependencies": {
108
- "jsdom": "^26.0.0"
124
+ "jsdom": "^26.0.0",
125
+ "postcss": "^8.4.31"
109
126
  },
110
127
  "peerDependencies": {
128
+ "katex": "^0.16.0",
111
129
  "react": ">=18.2.0",
112
130
  "react-dom": ">=18.2.0"
131
+ },
132
+ "peerDependenciesMeta": {
133
+ "katex": {
134
+ "optional": true
135
+ }
113
136
  }
114
137
  }