@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
@@ -1,403 +1,22 @@
1
1
  "use client";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __esm = (fn, res) => function __init() {
5
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
- };
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
10
- };
11
2
 
12
- // src/mdx-client.ts
13
- var mdx_client_exports = {};
14
- __export(mdx_client_exports, {
15
- MDXClient: () => MDXClient,
16
- MDXComponentFactory: () => MDXComponentFactory,
17
- getMDXClient: () => getMDXClient,
18
- getMDXComponentFactory: () => getMDXComponentFactory,
19
- registerInlineMdxModule: () => registerInlineMdxModule,
20
- registerMDXComponents: () => registerMDXComponents
21
- });
22
- import React2 from "react";
23
- import * as ReactJsxRuntime from "react/jsx-runtime";
24
- function assignMdxChildKey(child, index) {
25
- if (child == null) return child;
26
- if (Array.isArray(child)) {
27
- return child.map((entry, subIndex) => assignMdxChildKey(entry, `${index}-${subIndex}`));
28
- }
29
- if (React2.isValidElement(child)) {
30
- if (child.key !== null && child.key !== void 0) {
31
- return child;
32
- }
33
- return React2.cloneElement(child, { key: index });
34
- }
35
- return child;
36
- }
37
- function getMDXClient(compileEndpoint) {
38
- if (!globalMDXClient) {
39
- globalMDXClient = new MDXClient(compileEndpoint);
40
- }
41
- return globalMDXClient;
3
+ // src/code-fence-streaming.ts
4
+ function trimProvisionalFenceTail(raw) {
5
+ if (raw.endsWith(`
6
+ `)) return raw;
7
+ let opening = raw.match(/^ {0,3}(`{3,}|~{3,})[^\n]*\n/);
8
+ if (!opening) return raw;
9
+ let lastNewline = raw.lastIndexOf(`
10
+ `), tail = raw.slice(lastNewline + 1).match(/^ {0,3}(`+|~+)[\t ]*$/);
11
+ return tail && tail[1][0] === opening[1][0] && tail[1].length < opening[1].length ? raw.slice(0, lastNewline) : raw;
42
12
  }
43
- function getMDXComponentFactory(compileEndpoint) {
44
- if (!globalComponentFactory) {
45
- const client = getMDXClient(compileEndpoint);
46
- globalComponentFactory = new MDXComponentFactory(client);
47
- }
48
- return globalComponentFactory;
49
- }
50
- function registerMDXComponents(components, options) {
51
- const factory = getMDXComponentFactory();
52
- factory.registerComponents(components, options);
53
- }
54
- function registerInlineMdxModule(compiled) {
55
- const factory = getMDXComponentFactory();
56
- factory.registerInlineModule({
57
- id: compiled.id,
58
- code: compiled.code,
59
- dependencies: compiled.dependencies ?? []
60
- });
61
- }
62
- var withClassName, MDXClient, MDXComponentFactory, globalMDXClient, globalComponentFactory;
63
- var init_mdx_client = __esm({
64
- "src/mdx-client.ts"() {
65
- "use strict";
66
- withClassName = (tag, className) => {
67
- return (props) => React2.createElement(tag, { className, ...props });
68
- };
69
- MDXClient = class {
70
- constructor(compileEndpoint = "/api/mdx-compile-v2") {
71
- this.cache = /* @__PURE__ */ new Map();
72
- this.inlineModules = /* @__PURE__ */ new Map();
73
- this.compiledCache = /* @__PURE__ */ new Map();
74
- this.compiledInflight = /* @__PURE__ */ new Map();
75
- this.compileEndpoint = compileEndpoint;
76
- }
77
- /**
78
- * Compile MDX block on server
79
- */
80
- async compile(block) {
81
- if (block.type !== "mdx") {
82
- throw new Error("Block is not MDX type");
83
- }
84
- const cacheKey = `${block.id}\0${block.payload.raw ?? ""}`;
85
- const cachedPromise = this.cache.get(cacheKey);
86
- if (cachedPromise) {
87
- return cachedPromise;
88
- }
89
- const compilationPromise = this.doCompile(block);
90
- this.cache.set(cacheKey, compilationPromise);
91
- try {
92
- const result = await compilationPromise;
93
- return result;
94
- } catch (error) {
95
- this.cache.delete(cacheKey);
96
- throw error;
97
- }
98
- }
99
- async getCompiledInternal(ref) {
100
- const inline = this.inlineModules.get(ref.id);
101
- if (inline) {
102
- return this.cloneCompiled(inline);
103
- }
104
- const cached = this.compiledCache.get(ref.id);
105
- if (cached) {
106
- return this.cloneCompiled(cached);
107
- }
108
- const inflight = this.compiledInflight.get(ref.id);
109
- if (inflight) {
110
- const resolved = await inflight;
111
- return this.cloneCompiled(resolved);
112
- }
113
- const fetchPromise = this.fetchCompiled(ref);
114
- this.compiledInflight.set(ref.id, fetchPromise);
115
- try {
116
- const data = await fetchPromise;
117
- this.compiledCache.set(ref.id, data);
118
- return this.cloneCompiled(data);
119
- } finally {
120
- this.compiledInflight.delete(ref.id);
121
- }
122
- }
123
- async getCompiled(ref, options) {
124
- if (options?.signal) {
125
- const inline = this.inlineModules.get(ref.id);
126
- if (inline) {
127
- return this.cloneCompiled(inline);
128
- }
129
- const cached = this.compiledCache.get(ref.id);
130
- if (cached) {
131
- return this.cloneCompiled(cached);
132
- }
133
- const data = await this.fetchCompiled(ref, options);
134
- this.compiledCache.set(ref.id, data);
135
- return this.cloneCompiled(data);
136
- }
137
- return this.getCompiledInternal(ref);
138
- }
139
- /**
140
- * Clear compilation cache
141
- */
142
- clearCache() {
143
- this.cache.clear();
144
- this.compiledCache.clear();
145
- this.compiledInflight.clear();
146
- }
147
- registerInlineModule(compiled) {
148
- this.inlineModules.set(compiled.id, {
149
- ...compiled,
150
- dependencies: Array.isArray(compiled.dependencies) ? [...compiled.dependencies] : []
151
- });
152
- }
153
- clearInlineModules() {
154
- this.inlineModules.clear();
155
- }
156
- /**
157
- * Actual compilation implementation
158
- */
159
- async doCompile(block) {
160
- const response = await fetch(this.compileEndpoint, {
161
- method: "POST",
162
- headers: {
163
- "Content-Type": "application/json"
164
- },
165
- body: JSON.stringify({
166
- content: block.payload.raw,
167
- blockId: block.id
168
- })
169
- });
170
- if (!response.ok) {
171
- const error = await response.json().catch(() => ({ error: "Unknown error" }));
172
- throw new Error(`MDX compilation failed: ${error.error || response.statusText}`);
173
- }
174
- const data = await response.json();
175
- return {
176
- id: data.id,
177
- code: data.code,
178
- dependencies: data.dependencies || [],
179
- cached: data.cached || false
180
- };
181
- }
182
- async fetchCompiled(ref, options) {
183
- const response = await fetch(`${this.compileEndpoint}?id=${ref.id}`, {
184
- signal: options?.signal
185
- });
186
- if (!response.ok) {
187
- throw new Error(`Failed to get compiled MDX: ${response.statusText}`);
188
- }
189
- const data = await response.json();
190
- return {
191
- id: data.id,
192
- code: data.code,
193
- dependencies: data.dependencies || [],
194
- timestamp: data.timestamp
195
- };
196
- }
197
- cloneCompiled(compiled) {
198
- return {
199
- ...compiled,
200
- dependencies: Array.isArray(compiled.dependencies) ? [...compiled.dependencies] : []
201
- };
202
- }
203
- };
204
- MDXComponentFactory = class {
205
- constructor(mdxClient) {
206
- this.components = /* @__PURE__ */ new Map();
207
- this.customComponents = /* @__PURE__ */ new Map();
208
- this.mdxClient = mdxClient;
209
- this.baseComponents = this.createBaseComponents();
210
- }
211
- registerInlineModule(module) {
212
- this.mdxClient.registerInlineModule(module);
213
- this.components.delete(module.id);
214
- }
215
- /**
216
- * Create React component from compiled MDX
217
- */
218
- async createComponent(ref) {
219
- const cached = this.components.get(ref.id);
220
- if (cached) {
221
- return cached;
222
- }
223
- const compiled = await this.mdxClient.getCompiled(ref);
224
- const component = this.evaluateCompiledMDX(compiled);
225
- this.components.set(ref.id, component);
226
- return component;
227
- }
228
- /**
229
- * Safely evaluate compiled MDX code
230
- */
231
- evaluateCompiledMDX(compiled) {
232
- try {
233
- const context = this.createEvaluationContext();
234
- const argNames = Object.keys(context);
235
- const argValues = Object.values(context);
236
- const moduleExports = new Function(...argNames, compiled.code)(...argValues);
237
- const MDXComponent = this.resolveEvaluatedModule(moduleExports);
238
- return (props) => {
239
- const registryComponents = this.getComponents();
240
- const incomingComponents = props?.components;
241
- const mergedComponents = incomingComponents ? { ...registryComponents, ...incomingComponents } : registryComponents;
242
- return React2.createElement(MDXComponent, {
243
- ...props,
244
- components: mergedComponents
245
- });
246
- };
247
- } catch (error) {
248
- console.error("Failed to evaluate MDX:", error);
249
- return () => React2.createElement(
250
- "div",
251
- {
252
- className: "mdx-error"
253
- },
254
- `MDX Error: ${error instanceof Error ? error.message : "Unknown error"}`
255
- );
256
- }
257
- }
258
- /**
259
- * Create safe evaluation context for MDX
260
- */
261
- createEvaluationContext() {
262
- const runtime = ReactJsxRuntime;
263
- const createElementWithChildren = (type, props, key) => {
264
- const baseProps = props ?? {};
265
- const finalProps = key === void 0 || key === null ? baseProps : { ...baseProps, key };
266
- if (Array.isArray(finalProps.children)) {
267
- finalProps.children = finalProps.children.map((child, index) => assignMdxChildKey(child, index));
268
- }
269
- return React2.createElement(type, finalProps);
270
- };
271
- const runtimeJsx = typeof runtime.jsx === "function" ? runtime.jsx.bind(runtime) : createElementWithChildren;
272
- const runtimeJsxs = typeof runtime.jsxs === "function" ? runtime.jsxs.bind(runtime) : createElementWithChildren;
273
- const runtimeJsxDEV = typeof runtime.jsxDEV === "function" ? runtime.jsxDEV.bind(runtime) : (type, props, key, ..._rest) => createElementWithChildren(type, props, key);
274
- const jsxRuntime = {
275
- jsx: runtimeJsx,
276
- jsxs: runtimeJsxs,
277
- jsxDEV: runtimeJsxDEV,
278
- Fragment: runtime.Fragment ?? React2.Fragment
279
- };
280
- return {
281
- __mdx_runtime: jsxRuntime,
282
- React: React2,
283
- Fragment: React2.Fragment,
284
- useState: React2.useState,
285
- useEffect: React2.useEffect,
286
- useMemo: React2.useMemo,
287
- useCallback: React2.useCallback,
288
- useRef: React2.useRef,
289
- useContext: React2.useContext,
290
- useReducer: React2.useReducer,
291
- useLayoutEffect: React2.useLayoutEffect,
292
- console: {
293
- log: console.log,
294
- warn: console.warn,
295
- error: console.error
296
- }
297
- };
298
- }
299
- resolveEvaluatedModule(output) {
300
- if (!output) {
301
- throw new Error("Compiled MDX module returned no exports");
302
- }
303
- if (typeof output === "function") {
304
- return output;
305
- }
306
- if (typeof output.default === "function") {
307
- return output.default;
308
- }
309
- if (typeof output.MDXContent === "function") {
310
- return output.MDXContent;
311
- }
312
- throw new Error("Compiled MDX module did not export a component");
313
- }
314
- getComponents() {
315
- if (this.customComponents.size === 0) {
316
- return { ...this.baseComponents };
317
- }
318
- const merged = { ...this.baseComponents };
319
- for (const [key, component] of this.customComponents) {
320
- merged[key] = component;
321
- }
322
- return merged;
323
- }
324
- /**
325
- * Register or replace custom MDX components
326
- */
327
- registerComponents(components, options) {
328
- if (options?.replace) {
329
- this.customComponents.clear();
330
- }
331
- for (const [key, component] of Object.entries(components)) {
332
- if (!component) continue;
333
- this.customComponents.set(key, component);
334
- }
335
- }
336
- /**
337
- * Get base MDX components
338
- */
339
- createBaseComponents() {
340
- return {
341
- // Standard HTML elements
342
- h1: withClassName("h1", "mdx-h1"),
343
- h2: withClassName("h2", "mdx-h2"),
344
- h3: withClassName("h3", "mdx-h3"),
345
- h4: withClassName("h4", "mdx-h4"),
346
- h5: withClassName("h5", "mdx-h5"),
347
- h6: withClassName("h6", "mdx-h6"),
348
- p: withClassName("p", "mdx-p"),
349
- strong: withClassName("strong", "mdx-strong"),
350
- em: withClassName("em", "mdx-em"),
351
- code: withClassName("code", "mdx-code"),
352
- pre: withClassName("pre", "mdx-pre"),
353
- ul: withClassName("ul", "mdx-ul"),
354
- ol: withClassName("ol", "mdx-ol"),
355
- li: withClassName("li", "mdx-li"),
356
- blockquote: withClassName("blockquote", "mdx-blockquote"),
357
- a: (props) => React2.createElement("a", {
358
- className: "mdx-link",
359
- target: props.href?.startsWith("http") ? "_blank" : void 0,
360
- rel: props.href?.startsWith("http") ? "noopener noreferrer" : void 0,
361
- ...props
362
- }),
363
- img: (props) => React2.createElement("img", { className: "mdx-img", ...props }),
364
- table: withClassName("table", "mdx-table"),
365
- thead: withClassName("thead", "mdx-thead"),
366
- tbody: withClassName("tbody", "mdx-tbody"),
367
- tr: withClassName("tr", "mdx-tr"),
368
- th: withClassName("th", "mdx-th"),
369
- td: withClassName("td", "mdx-td")
370
- };
371
- }
372
- /**
373
- * Clear component cache
374
- */
375
- clearCache() {
376
- this.components.clear();
377
- }
378
- clearCustomComponents() {
379
- this.customComponents.clear();
380
- }
381
- };
382
- globalMDXClient = null;
383
- globalComponentFactory = null;
384
- }
385
- });
386
13
 
387
14
  // src/components/bottom-stick-scroll-area.tsx
388
15
  import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
389
16
  import { jsx, jsxs } from "react/jsx-runtime";
390
- var EPS_BOTTOM_PX = 2;
391
- var EPS_OVERFLOW_PX = 1;
392
- var DETACH_SCROLL_DELTA_PX = 1;
393
- var RETURN_MIN_MS = 180;
394
- var RETURN_MAX_MS = 520;
395
- var RETURN_PX_PER_MS = 2.2;
396
- var RETURN_SETTLE_FRAMES = 2;
17
+ var EPS_BOTTOM_PX = 2, EPS_OVERFLOW_PX = 1, DETACH_SCROLL_DELTA_PX = 1, RETURN_MIN_MS = 180, RETURN_MAX_MS = 520, RETURN_PX_PER_MS = 2.2, RETURN_SETTLE_FRAMES = 2;
397
18
  function clamp01(value) {
398
- if (value < 0) return 0;
399
- if (value > 1) return 1;
400
- return value;
19
+ return value < 0 ? 0 : value > 1 ? 1 : value;
401
20
  }
402
21
  function easeOutCubic(value) {
403
22
  return 1 - (1 - value) ** 3;
@@ -406,14 +25,34 @@ function joinClasses(...parts) {
406
25
  return parts.filter(Boolean).join(" ");
407
26
  }
408
27
  function measure(viewport) {
409
- const scrollTop = viewport.scrollTop;
410
- const scrollHeight = viewport.scrollHeight;
411
- const clientHeight = viewport.clientHeight;
412
- const maxScrollTop = Math.max(0, scrollHeight - clientHeight);
413
- const distanceToBottom = Math.max(0, maxScrollTop - scrollTop);
414
- const isOverflowing = scrollHeight > clientHeight + EPS_OVERFLOW_PX;
28
+ let scrollTop = viewport.scrollTop, scrollHeight = viewport.scrollHeight, clientHeight = viewport.clientHeight, maxScrollTop = Math.max(0, scrollHeight - clientHeight), distanceToBottom = Math.max(0, maxScrollTop - scrollTop), isOverflowing = scrollHeight > clientHeight + EPS_OVERFLOW_PX;
415
29
  return { scrollTop, scrollHeight, clientHeight, maxScrollTop, distanceToBottom, isOverflowing };
416
30
  }
31
+ function isEditableTarget(target) {
32
+ if (!(target instanceof Element)) return !1;
33
+ if (target.closest("input, textarea, select, [role='textbox']")) return !0;
34
+ let contentEditable = target.closest("[contenteditable]");
35
+ return contentEditable !== null && contentEditable.getAttribute("contenteditable")?.toLowerCase() !== "false";
36
+ }
37
+ function isScrollKeyIntent(event) {
38
+ if (event.defaultPrevented || isEditableTarget(event.target)) return !1;
39
+ switch (event.key) {
40
+ case "ArrowDown":
41
+ case "ArrowUp":
42
+ case "PageDown":
43
+ case "PageUp":
44
+ case "Home":
45
+ case "End":
46
+ return !0;
47
+ case " ":
48
+ case "Spacebar":
49
+ return event.target instanceof Element ? event.target.closest(
50
+ "button, input, summary, [role='button'], [role='checkbox'], [role='switch'], [role='radio'], [role='menuitem'], [role='menuitemcheckbox'], [role='menuitemradio']"
51
+ ) === null : !0;
52
+ default:
53
+ return !1;
54
+ }
55
+ }
417
56
  function DefaultJumpButton({ canJump, jumpToBottom }) {
418
57
  return /* @__PURE__ */ jsx(
419
58
  "button",
@@ -434,7 +73,7 @@ function DefaultJumpButton({ canJump, jumpToBottom }) {
434
73
  color: "var(--foreground, #111)",
435
74
  cursor: canJump ? "pointer" : "default"
436
75
  },
437
- children: /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\u2193" })
76
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": !0, children: "\u2193" })
438
77
  }
439
78
  );
440
79
  }
@@ -443,45 +82,23 @@ function BottomStickScrollArea({
443
82
  className,
444
83
  viewportClassName,
445
84
  contentClassName,
446
- showJumpToBottom = true,
85
+ showJumpToBottom = !0,
447
86
  onDebugStateChange,
448
87
  onModeChange,
449
- debugDomAttributes = false,
88
+ debugDomAttributes = !1,
450
89
  renderJumpToBottom,
451
90
  jumpContainerClassName
452
91
  }) {
453
- const viewportRef = useRef(null);
454
- const contentRef = useRef(null);
455
- const modeRef = useRef("STICKY_INSTANT");
456
- const [mode, setMode] = useState("STICKY_INSTANT");
457
- const [isOverflowing, setIsOverflowing] = useState(false);
458
- const [distanceToBottom, setDistanceToBottom] = useState(0);
459
- const prevScrollTopRef = useRef(0);
460
- const lastProgrammaticWriteRef = useRef(null);
461
- const programmaticWriteCountRef = useRef(0);
462
- const pendingStickRafRef = useRef(null);
463
- const stickRequestedRef = useRef(false);
464
- const returnRafRef = useRef(null);
465
- const returnAnimRef = useRef(null);
466
- const setModeBoth = useCallback(
92
+ let viewportRef = useRef(null), contentRef = useRef(null), modeRef = useRef("STICKY_INSTANT"), [mode, setMode] = useState("STICKY_INSTANT"), [isOverflowing, setIsOverflowing] = useState(!1), [distanceToBottom, setDistanceToBottom] = useState(0), [prefersReducedMotion, setPrefersReducedMotion] = useState(!1), prefersReducedMotionRef = useRef(!1), prevScrollTopRef = useRef(0), lastProgrammaticWriteRef = useRef(null), programmaticWriteCountRef = useRef(0), pendingStickRafRef = useRef(null), stickRequestedRef = useRef(!1), returnRafRef = useRef(null), returnAnimRef = useRef(null), setModeBoth = useCallback(
467
93
  (next) => {
468
- modeRef.current = next;
469
- setMode(next);
470
- onModeChange?.(next);
94
+ modeRef.current = next, setMode(next), onModeChange?.(next);
471
95
  },
472
96
  [onModeChange]
473
- );
474
- const updateDebug = useCallback(() => {
475
- const viewport = viewportRef.current;
97
+ ), updateDebug = useCallback(() => {
98
+ let viewport = viewportRef.current;
476
99
  if (!viewport) return;
477
- const m = measure(viewport);
478
- if (debugDomAttributes) {
479
- viewport.dataset.stickyMode = modeRef.current;
480
- viewport.dataset.distanceToBottom = String(m.distanceToBottom);
481
- viewport.dataset.isOverflowing = m.isOverflowing ? "1" : "0";
482
- viewport.dataset.programmaticWrites = String(programmaticWriteCountRef.current);
483
- }
484
- onDebugStateChange?.({
100
+ let m = measure(viewport);
101
+ debugDomAttributes && (viewport.dataset.stickyMode = modeRef.current, viewport.dataset.distanceToBottom = String(m.distanceToBottom), viewport.dataset.isOverflowing = m.isOverflowing ? "1" : "0", viewport.dataset.programmaticWrites = String(programmaticWriteCountRef.current)), onDebugStateChange?.({
485
102
  mode: modeRef.current,
486
103
  isOverflowing: m.isOverflowing,
487
104
  distanceToBottom: m.distanceToBottom,
@@ -490,60 +107,54 @@ function BottomStickScrollArea({
490
107
  scrollHeight: m.scrollHeight,
491
108
  clientHeight: m.clientHeight,
492
109
  programmaticWrites: programmaticWriteCountRef.current
493
- });
494
- setDistanceToBottom(
110
+ }), setDistanceToBottom(
495
111
  (previous) => Math.abs(previous - m.distanceToBottom) <= 0.1 ? previous : m.distanceToBottom
496
112
  );
497
- }, [debugDomAttributes, onDebugStateChange]);
498
- const writeScrollTop = useCallback((nextTop) => {
499
- const viewport = viewportRef.current;
113
+ }, [debugDomAttributes, onDebugStateChange]), writeScrollTop = useCallback((nextTop) => {
114
+ let viewport = viewportRef.current;
115
+ viewport && (viewport.scrollTop = nextTop, programmaticWriteCountRef.current += 1, lastProgrammaticWriteRef.current = { at: performance.now(), top: nextTop });
116
+ }, []), cancelPendingStick = useCallback(() => {
117
+ pendingStickRafRef.current !== null && (cancelAnimationFrame(pendingStickRafRef.current), pendingStickRafRef.current = null), stickRequestedRef.current = !1;
118
+ }, []), cancelReturn = useCallback(() => {
119
+ returnRafRef.current !== null && (cancelAnimationFrame(returnRafRef.current), returnRafRef.current = null), returnAnimRef.current = null;
120
+ }, []), handleReducedMotionChange = useCallback(
121
+ (matches) => {
122
+ if (prefersReducedMotionRef.current !== matches && (prefersReducedMotionRef.current = matches, setPrefersReducedMotion(matches)), !matches || modeRef.current !== "RETURNING_SMOOTH") return;
123
+ cancelPendingStick(), cancelReturn(), setModeBoth("STICKY_INSTANT");
124
+ let viewport = viewportRef.current;
125
+ viewport && (writeScrollTop(measure(viewport).maxScrollTop), prevScrollTopRef.current = viewport.scrollTop), updateDebug();
126
+ },
127
+ [cancelPendingStick, cancelReturn, setModeBoth, updateDebug, writeScrollTop]
128
+ ), reducedMotionChangeHandlerRef = useRef(handleReducedMotionChange);
129
+ reducedMotionChangeHandlerRef.current = handleReducedMotionChange;
130
+ let interruptReturnForUserIntent = useCallback(() => {
131
+ modeRef.current === "RETURNING_SMOOTH" && (cancelPendingStick(), cancelReturn(), setModeBoth("DETACHED"), updateDebug());
132
+ }, [cancelPendingStick, cancelReturn, setModeBoth, updateDebug]), onViewportKeyDown = useCallback(
133
+ (event) => {
134
+ isScrollKeyIntent(event) && interruptReturnForUserIntent();
135
+ },
136
+ [interruptReturnForUserIntent]
137
+ ), stickToBottomInstant = useCallback(() => {
138
+ let viewport = viewportRef.current;
139
+ viewport && (stickRequestedRef.current = !0, pendingStickRafRef.current === null && (pendingStickRafRef.current = requestAnimationFrame(() => {
140
+ if (pendingStickRafRef.current = null, !stickRequestedRef.current || (stickRequestedRef.current = !1, modeRef.current !== "STICKY_INSTANT")) return;
141
+ let m = measure(viewport);
142
+ writeScrollTop(m.maxScrollTop), updateDebug();
143
+ })));
144
+ }, [updateDebug, writeScrollTop]), startReturnToBottomSmooth = useCallback(() => {
145
+ let viewport = viewportRef.current;
500
146
  if (!viewport) return;
501
- viewport.scrollTop = nextTop;
502
- programmaticWriteCountRef.current += 1;
503
- lastProgrammaticWriteRef.current = { at: performance.now(), top: nextTop };
504
- }, []);
505
- const cancelPendingStick = useCallback(() => {
506
- if (pendingStickRafRef.current !== null) {
507
- cancelAnimationFrame(pendingStickRafRef.current);
508
- pendingStickRafRef.current = null;
509
- }
510
- stickRequestedRef.current = false;
511
- }, []);
512
- const cancelReturn = useCallback(() => {
513
- if (returnRafRef.current !== null) {
514
- cancelAnimationFrame(returnRafRef.current);
515
- returnRafRef.current = null;
147
+ if (prefersReducedMotionRef.current) {
148
+ cancelPendingStick(), cancelReturn(), setModeBoth("STICKY_INSTANT"), writeScrollTop(measure(viewport).maxScrollTop), prevScrollTopRef.current = viewport.scrollTop, updateDebug();
149
+ return;
516
150
  }
517
- returnAnimRef.current = null;
518
- }, []);
519
- const stickToBottomInstant = useCallback(() => {
520
- const viewport = viewportRef.current;
521
- if (!viewport) return;
522
- stickRequestedRef.current = true;
523
- if (pendingStickRafRef.current !== null) return;
524
- pendingStickRafRef.current = requestAnimationFrame(() => {
525
- pendingStickRafRef.current = null;
526
- if (!stickRequestedRef.current) return;
527
- stickRequestedRef.current = false;
528
- if (modeRef.current !== "STICKY_INSTANT") return;
529
- const m = measure(viewport);
530
- writeScrollTop(m.maxScrollTop);
531
- updateDebug();
532
- });
533
- }, [updateDebug, writeScrollTop]);
534
- const startReturnToBottomSmooth = useCallback(() => {
535
- const viewport = viewportRef.current;
536
- if (!viewport) return;
537
- cancelPendingStick();
538
- cancelReturn();
539
- const initial = measure(viewport);
151
+ cancelPendingStick(), cancelReturn();
152
+ let initial = measure(viewport);
540
153
  if (initial.distanceToBottom <= EPS_BOTTOM_PX) {
541
- setModeBoth("STICKY_INSTANT");
542
- stickToBottomInstant();
543
- updateDebug();
154
+ setModeBoth("STICKY_INSTANT"), stickToBottomInstant(), updateDebug();
544
155
  return;
545
156
  }
546
- const durationMs = Math.max(
157
+ let durationMs = Math.max(
547
158
  RETURN_MIN_MS,
548
159
  Math.min(RETURN_MAX_MS, initial.distanceToBottom / RETURN_PX_PER_MS)
549
160
  );
@@ -552,118 +163,60 @@ function BottomStickScrollArea({
552
163
  startTop: initial.scrollTop,
553
164
  durationMs,
554
165
  settleFrames: 0
555
- };
556
- setModeBoth("RETURNING_SMOOTH");
557
- const tick = (now2) => {
558
- const viewportCurrent = viewportRef.current;
559
- const anim = returnAnimRef.current;
166
+ }, setModeBoth("RETURNING_SMOOTH");
167
+ let tick = (now) => {
168
+ let viewportCurrent = viewportRef.current, anim = returnAnimRef.current;
560
169
  if (!viewportCurrent || !anim || modeRef.current !== "RETURNING_SMOOTH") {
561
170
  cancelReturn();
562
171
  return;
563
172
  }
564
- const before = measure(viewportCurrent);
565
- const progress = clamp01((now2 - anim.startTime) / anim.durationMs);
566
- const eased = easeOutCubic(progress);
567
- const targetBottom = before.maxScrollTop;
568
- let nextTop = anim.startTop + (targetBottom - anim.startTop) * eased;
569
- if (nextTop < before.scrollTop) {
570
- nextTop = before.scrollTop;
571
- }
572
- writeScrollTop(nextTop);
573
- const after = measure(viewportCurrent);
574
- if (after.distanceToBottom <= EPS_BOTTOM_PX) {
575
- anim.settleFrames += 1;
576
- } else {
577
- anim.settleFrames = 0;
578
- }
579
- const doneByTime = progress >= 1;
580
- const doneBySettle = anim.settleFrames >= RETURN_SETTLE_FRAMES && progress >= 0.6;
173
+ let before = measure(viewportCurrent), progress = clamp01((now - anim.startTime) / anim.durationMs), eased = easeOutCubic(progress), targetBottom = before.maxScrollTop, nextTop = anim.startTop + (targetBottom - anim.startTop) * eased;
174
+ nextTop < before.scrollTop && (nextTop = before.scrollTop), writeScrollTop(nextTop), measure(viewportCurrent).distanceToBottom <= EPS_BOTTOM_PX ? anim.settleFrames += 1 : anim.settleFrames = 0;
175
+ let doneByTime = progress >= 1, doneBySettle = anim.settleFrames >= RETURN_SETTLE_FRAMES && progress >= 0.6;
581
176
  if (doneByTime && doneBySettle) {
582
- cancelReturn();
583
- setModeBoth("STICKY_INSTANT");
584
- stickToBottomInstant();
585
- updateDebug();
177
+ cancelReturn(), setModeBoth("STICKY_INSTANT"), stickToBottomInstant(), updateDebug();
586
178
  return;
587
179
  }
588
- updateDebug();
589
- returnRafRef.current = requestAnimationFrame(tick);
180
+ updateDebug(), returnRafRef.current = requestAnimationFrame(tick);
590
181
  };
591
182
  returnRafRef.current = requestAnimationFrame(tick);
592
- }, [cancelPendingStick, cancelReturn, setModeBoth, stickToBottomInstant, updateDebug, writeScrollTop]);
593
- const onViewportScroll = useCallback(
183
+ }, [cancelPendingStick, cancelReturn, setModeBoth, stickToBottomInstant, updateDebug, writeScrollTop]), onViewportScroll = useCallback(
594
184
  (event) => {
595
- const viewport = event.currentTarget;
596
- const m = measure(viewport);
185
+ let viewport = event.currentTarget, m = measure(viewport);
597
186
  setIsOverflowing((previous) => previous === m.isOverflowing ? previous : m.isOverflowing);
598
- const previousTop = prevScrollTopRef.current;
599
- const delta = m.scrollTop - previousTop;
600
- const lastWrite = lastProgrammaticWriteRef.current;
601
- const wroteRecently = lastWrite !== null && performance.now() - lastWrite.at < 60;
602
- const isLikelyOwnWrite = wroteRecently && lastWrite !== null && Math.abs(m.scrollTop - lastWrite.top) <= 2;
603
- if (modeRef.current === "RETURNING_SMOOTH") {
604
- if (!isLikelyOwnWrite && delta < -DETACH_SCROLL_DELTA_PX) {
605
- cancelReturn();
606
- setModeBoth("DETACHED");
607
- }
608
- } else if (modeRef.current === "STICKY_INSTANT") {
609
- if (!isLikelyOwnWrite && delta < -DETACH_SCROLL_DELTA_PX && m.isOverflowing) {
610
- cancelPendingStick();
611
- setModeBoth("DETACHED");
612
- }
613
- } else if (modeRef.current === "DETACHED") {
614
- if (m.distanceToBottom <= EPS_BOTTOM_PX) {
615
- setModeBoth("STICKY_INSTANT");
616
- stickToBottomInstant();
617
- }
618
- }
619
- prevScrollTopRef.current = m.scrollTop;
620
- updateDebug();
187
+ let previousTop = prevScrollTopRef.current, delta = m.scrollTop - previousTop, lastWrite = lastProgrammaticWriteRef.current, isLikelyOwnWrite = lastWrite !== null && performance.now() - lastWrite.at < 60 && lastWrite !== null && Math.abs(m.scrollTop - lastWrite.top) <= 2;
188
+ modeRef.current === "RETURNING_SMOOTH" ? !isLikelyOwnWrite && delta < -DETACH_SCROLL_DELTA_PX && (cancelReturn(), setModeBoth("DETACHED")) : modeRef.current === "STICKY_INSTANT" ? !isLikelyOwnWrite && delta < -DETACH_SCROLL_DELTA_PX && m.isOverflowing && (cancelPendingStick(), setModeBoth("DETACHED")) : modeRef.current === "DETACHED" && m.distanceToBottom <= EPS_BOTTOM_PX && (setModeBoth("STICKY_INSTANT"), stickToBottomInstant()), prevScrollTopRef.current = m.scrollTop, updateDebug();
621
189
  },
622
190
  [cancelPendingStick, cancelReturn, setModeBoth, stickToBottomInstant, updateDebug]
623
191
  );
624
192
  useEffect(() => {
625
- const viewport = viewportRef.current;
626
- const content = contentRef.current;
193
+ let viewport = viewportRef.current, content = contentRef.current;
627
194
  if (!viewport || !content) return;
628
- const observer = new ResizeObserver(() => {
629
- const m = measure(viewport);
630
- setIsOverflowing((previous) => previous === m.isOverflowing ? previous : m.isOverflowing);
631
- if (modeRef.current === "STICKY_INSTANT") {
632
- stickToBottomInstant();
633
- }
634
- updateDebug();
195
+ let observer = new ResizeObserver(() => {
196
+ let m = measure(viewport);
197
+ setIsOverflowing((previous) => previous === m.isOverflowing ? previous : m.isOverflowing), modeRef.current === "STICKY_INSTANT" && stickToBottomInstant(), updateDebug();
635
198
  });
636
- observer.observe(content);
637
- observer.observe(viewport);
638
- return () => observer.disconnect();
639
- }, [stickToBottomInstant, updateDebug]);
640
- useLayoutEffect(() => {
641
- const viewport = viewportRef.current;
199
+ return observer.observe(content), observer.observe(viewport), () => observer.disconnect();
200
+ }, [stickToBottomInstant, updateDebug]), useLayoutEffect(() => {
201
+ let viewport = viewportRef.current;
642
202
  if (!viewport) return;
643
203
  setModeBoth("STICKY_INSTANT");
644
- const initial = measure(viewport);
645
- writeScrollTop(initial.maxScrollTop);
646
- prevScrollTopRef.current = viewport.scrollTop;
647
- setIsOverflowing(initial.isOverflowing);
648
- setDistanceToBottom(initial.distanceToBottom);
649
- updateDebug();
650
- }, [setModeBoth, updateDebug, writeScrollTop]);
651
- useEffect(() => {
652
- return () => {
653
- cancelPendingStick();
654
- cancelReturn();
655
- };
204
+ let initial = measure(viewport);
205
+ writeScrollTop(initial.maxScrollTop), prevScrollTopRef.current = viewport.scrollTop, setIsOverflowing(initial.isOverflowing), setDistanceToBottom(initial.distanceToBottom), updateDebug();
206
+ }, [setModeBoth, updateDebug, writeScrollTop]), useLayoutEffect(() => {
207
+ if (typeof window > "u" || typeof window.matchMedia != "function") return;
208
+ let mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)"), onChange = () => reducedMotionChangeHandlerRef.current(mediaQuery.matches);
209
+ return onChange(), typeof mediaQuery.addEventListener == "function" ? (mediaQuery.addEventListener("change", onChange), () => mediaQuery.removeEventListener("change", onChange)) : (mediaQuery.addListener(onChange), () => mediaQuery.removeListener(onChange));
210
+ }, []), useEffect(() => () => {
211
+ cancelPendingStick(), cancelReturn();
656
212
  }, [cancelPendingStick, cancelReturn]);
657
- const canJump = isOverflowing && mode === "DETACHED";
658
- const jumpButton = renderJumpToBottom?.({
213
+ let canJump = isOverflowing && mode === "DETACHED", jumpButton = renderJumpToBottom?.({
659
214
  mode,
660
215
  canJump,
661
216
  isOverflowing,
662
217
  distanceToBottom,
663
218
  jumpToBottom: startReturnToBottomSmooth
664
- }) ?? /* @__PURE__ */ jsx(DefaultJumpButton, { canJump, jumpToBottom: startReturnToBottomSmooth });
665
- const jumpContainerClassNameBase = "pointer-events-none absolute z-20";
666
- const jumpContainerStyle = {
219
+ }) ?? /* @__PURE__ */ jsx(DefaultJumpButton, { canJump, jumpToBottom: startReturnToBottomSmooth }), jumpContainerClassNameBase = "pointer-events-none absolute z-20", jumpContainerStyle = {
667
220
  position: "absolute",
668
221
  zIndex: 20,
669
222
  left: 0,
@@ -672,8 +225,8 @@ function BottomStickScrollArea({
672
225
  display: "flex",
673
226
  justifyContent: "center",
674
227
  opacity: canJump ? 1 : 0,
675
- transform: canJump ? "translateY(0px)" : "translateY(4px)",
676
- transition: "opacity 150ms ease, transform 150ms ease",
228
+ transform: prefersReducedMotion ? "none" : canJump ? "translateY(0px)" : "translateY(4px)",
229
+ transition: prefersReducedMotion ? "none" : "opacity 150ms ease, transform 150ms ease",
677
230
  pointerEvents: "none"
678
231
  };
679
232
  return /* @__PURE__ */ jsxs("div", { className: joinClasses("relative h-full w-full overflow-hidden", className), children: [
@@ -683,6 +236,9 @@ function BottomStickScrollArea({
683
236
  ref: viewportRef,
684
237
  className: joinClasses("h-full w-full overflow-auto", viewportClassName),
685
238
  onScroll: onViewportScroll,
239
+ onWheel: interruptReturnForUserIntent,
240
+ onTouchStart: interruptReturnForUserIntent,
241
+ onKeyDown: onViewportKeyDown,
686
242
  "data-testid": "sticky-scroll-viewport",
687
243
  children: /* @__PURE__ */ jsx("div", { ref: contentRef, className: joinClasses("flex min-h-full w-full flex-col", contentClassName), children })
688
244
  }
@@ -699,200 +255,1102 @@ function BottomStickScrollArea({
699
255
  ] });
700
256
  }
701
257
 
702
- // src/components/index.ts
703
- import { createTrustedHTML, sanitizeHTML } from "@stream-mdx/core";
258
+ // src/components/diff-renderer.tsx
259
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
260
+ var DefaultDiffRenderer = ({
261
+ meta,
262
+ renderCode,
263
+ className = "",
264
+ style
265
+ }) => {
266
+ let diffBlocks = Array.isArray(meta?.diffBlocks) ? meta.diffBlocks : null;
267
+ return !diffBlocks || diffBlocks.length === 0 ? /* @__PURE__ */ jsx2(Fragment, { children: renderCode }) : /* @__PURE__ */ jsx2(
268
+ "div",
269
+ {
270
+ className: `stream-mdx-diff-container my-4 rounded-md border border-border bg-muted/20 font-mono text-sm overflow-hidden ${className}`.trim(),
271
+ style,
272
+ children: diffBlocks.map((diffBlock, bIdx) => /* @__PURE__ */ jsxs2("div", { className: "stream-mdx-diff-block", children: [
273
+ (diffBlock.filePath || diffBlock.additions != null || diffBlock.deletions != null) && /* @__PURE__ */ jsxs2("div", { className: "stream-mdx-diff-header flex items-center justify-between border-b border-border bg-muted/40 px-4 py-2 text-xs font-semibold text-muted-foreground", children: [
274
+ /* @__PURE__ */ jsx2("span", { className: "stream-mdx-diff-filepath", children: diffBlock.filePath ?? "diff" }),
275
+ /* @__PURE__ */ jsxs2("span", { className: "stream-mdx-diff-stats flex gap-2", children: [
276
+ diffBlock.additions != null && /* @__PURE__ */ jsxs2("span", { className: "stream-mdx-diff-stat-add text-green-600 dark:text-green-400", children: [
277
+ "+",
278
+ diffBlock.additions
279
+ ] }),
280
+ diffBlock.deletions != null && /* @__PURE__ */ jsxs2("span", { className: "stream-mdx-diff-stat-del text-red-600 dark:text-red-400", children: [
281
+ "-",
282
+ diffBlock.deletions
283
+ ] })
284
+ ] })
285
+ ] }),
286
+ /* @__PURE__ */ jsx2("div", { className: "stream-mdx-diff-lines overflow-x-auto", children: /* @__PURE__ */ jsx2("table", { className: "w-full border-collapse font-mono text-xs", children: /* @__PURE__ */ jsx2("tbody", { children: diffBlock.lines.map((line, lIdx) => {
287
+ let kindClass = `diff-line-${line.kind} ${line.kind === "add" ? "bg-green-500/10 text-green-900 dark:text-green-200" : line.kind === "del" ? "bg-red-500/10 text-red-900 dark:text-red-200" : line.kind === "hunk" ? "bg-blue-500/10 text-blue-800 dark:text-blue-300 font-semibold" : line.kind === "meta" ? "bg-muted/50 text-muted-foreground italic" : "text-foreground"}`;
288
+ return /* @__PURE__ */ jsxs2(
289
+ "tr",
290
+ {
291
+ className: `stream-mdx-diff-row ${kindClass}`,
292
+ "data-diff-kind": line.kind,
293
+ children: [
294
+ /* @__PURE__ */ jsx2("td", { className: "stream-mdx-diff-old-no select-none px-2 py-0.5 text-right opacity-50 w-10", children: line.oldNo != null ? line.oldNo : "" }),
295
+ /* @__PURE__ */ jsx2("td", { className: "stream-mdx-diff-new-no select-none px-2 py-0.5 text-right opacity-50 w-10", children: line.newNo != null ? line.newNo : "" }),
296
+ /* @__PURE__ */ jsx2("td", { className: "stream-mdx-diff-prefix select-none px-1 py-0.5 text-center w-4 font-bold", children: line.kind === "add" ? "+" : line.kind === "del" ? "-" : line.kind === "hunk" ? "@" : " " }),
297
+ /* @__PURE__ */ jsx2("td", { className: "stream-mdx-diff-content px-2 py-0.5 whitespace-pre", children: line.tokens && line.tokens.length > 0 ? line.tokens.map((token, tIdx) => /* @__PURE__ */ jsx2(
298
+ "span",
299
+ {
300
+ style: {
301
+ color: token.color ?? void 0,
302
+ fontStyle: token.fontStyle === 1 || token.fontStyle === 3 ? "italic" : void 0,
303
+ fontWeight: token.fontStyle === 2 || token.fontStyle === 3 ? "bold" : void 0
304
+ },
305
+ children: token.content
306
+ },
307
+ tIdx
308
+ )) : /* @__PURE__ */ jsx2("span", { children: line.raw.replace(/^[+\- ]/, "") }) })
309
+ ]
310
+ },
311
+ lIdx
312
+ );
313
+ }) }) }) })
314
+ ] }, bIdx))
315
+ }
316
+ );
317
+ };
318
+ DefaultDiffRenderer.displayName = "DefaultDiffRenderer";
704
319
 
705
- // src/mdx-hydration-metrics.ts
706
- var entries = /* @__PURE__ */ new Map();
707
- var lastHydrationMs = null;
708
- function now() {
709
- if (typeof performance !== "undefined" && typeof performance.now === "function") {
710
- return performance.now();
711
- }
712
- return Date.now();
713
- }
714
- function markMdxHydrationStart(id) {
715
- if (!id) return;
716
- const entry = entries.get(id) ?? { status: "compiled" };
717
- if (entry.startedAt === void 0) {
718
- entry.startedAt = now();
719
- }
720
- entry.status = "compiled";
721
- entries.set(id, entry);
722
- }
723
- function markMdxHydrated(id) {
724
- if (!id) return;
725
- const entry = entries.get(id) ?? { status: "hydrated" };
726
- if (entry.startedAt === void 0) {
727
- entry.startedAt = now();
728
- }
729
- entry.hydratedAt = now();
730
- entry.status = "hydrated";
731
- entries.set(id, entry);
732
- lastHydrationMs = entry.startedAt ? entry.hydratedAt - entry.startedAt : null;
733
- }
734
- function markMdxHydrationError(id) {
735
- if (!id) return;
736
- const entry = entries.get(id) ?? { status: "error" };
737
- entry.status = "error";
738
- entries.set(id, entry);
320
+ // src/components/katex-math.tsx
321
+ import { createContext, useContext, useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState2 } from "react";
322
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
323
+ var katexPromise = null;
324
+ async function loadKaTeX() {
325
+ return katexPromise || (katexPromise = import("katex").then((mod) => mod && typeof mod == "object" && "default" in mod && mod.default ? mod.default : mod)), katexPromise;
739
326
  }
740
-
741
- // src/mdx-hydration-context.ts
742
- import React from "react";
743
- var MdxHydrationContext = React.createContext({ controller: null });
744
-
745
- // src/mdx-runtime.ts
746
- var mdxRuntimePromise = null;
747
- function loadMdxRuntime() {
748
- if (!mdxRuntimePromise) {
749
- mdxRuntimePromise = Promise.resolve().then(() => (init_mdx_client(), mdx_client_exports));
327
+ var DOCUMENT_POSITION_PRECEDING = 2, DOCUMENT_POSITION_FOLLOWING = 4, DocumentMathMacroScope = class {
328
+ constructor() {
329
+ this.entries = /* @__PURE__ */ new Set();
330
+ this.orderedEntries = [];
331
+ this.macroSnapshots = [];
332
+ this.katex = null;
333
+ this.loadError = null;
334
+ this.loading = !1;
335
+ this.disposed = !1;
750
336
  }
751
- return mdxRuntimePromise;
752
- }
753
-
754
- // src/renderer/use-deferred-render.ts
755
- import { useEffect as useEffect2, useState as useState2 } from "react";
756
- function useDeferredRender(ref, options) {
757
- const enabled = options?.enabled ?? true;
758
- const [shouldRender, setShouldRender] = useState2(!enabled);
759
- useEffect2(() => {
760
- if (!enabled) {
761
- setShouldRender(true);
762
- return;
337
+ register(element, tex, displayMode, complete, publish) {
338
+ let entry = { element, tex, displayMode, complete, publish };
339
+ return this.entries.add(entry), this.refresh(), () => {
340
+ this.entries.delete(entry) && this.refresh();
341
+ };
342
+ }
343
+ dispose() {
344
+ this.disposed = !0, this.entries.clear(), this.orderedEntries = [], this.macroSnapshots = [];
345
+ }
346
+ refresh() {
347
+ if (!this.disposed) {
348
+ if (this.loadError) {
349
+ for (let entry of this.entries)
350
+ entry.publish({ tex: entry.tex, displayMode: entry.displayMode, scope: this, error: this.loadError });
351
+ return;
352
+ }
353
+ if (this.katex) {
354
+ this.recompute(this.katex);
355
+ return;
356
+ }
357
+ this.loading || (this.loading = !0, loadKaTeX().then((katex) => {
358
+ this.disposed || (this.katex = katex, this.refresh());
359
+ }).catch((reason) => {
360
+ if (!this.disposed) {
361
+ this.loadError = reason instanceof Error ? reason : new Error(String(reason));
362
+ for (let entry of this.entries)
363
+ entry.publish({ tex: entry.tex, displayMode: entry.displayMode, scope: this, error: this.loadError });
364
+ }
365
+ }).finally(() => {
366
+ this.loading = !1;
367
+ }));
763
368
  }
764
- const target = ref.current;
765
- if (!target) {
766
- return;
369
+ }
370
+ recompute(katex) {
371
+ let nextEntries = [...this.entries].sort((left, right) => {
372
+ let position = left.element.compareDocumentPosition(right.element);
373
+ return position & DOCUMENT_POSITION_FOLLOWING ? -1 : position & DOCUMENT_POSITION_PRECEDING ? 1 : 0;
374
+ }), unchangedPrefix = 0;
375
+ for (; unchangedPrefix < this.orderedEntries.length && unchangedPrefix < nextEntries.length && this.orderedEntries[unchangedPrefix] === nextEntries[unchangedPrefix]; )
376
+ unchangedPrefix += 1;
377
+ let macros = unchangedPrefix > 0 ? { ...this.macroSnapshots[unchangedPrefix - 1] } : {};
378
+ this.orderedEntries = nextEntries, this.macroSnapshots.length = unchangedPrefix;
379
+ for (let index = unchangedPrefix; index < nextEntries.length; index += 1) {
380
+ let entry = nextEntries[index], preparation = null;
381
+ if (entry.complete) {
382
+ let nextMacros = { ...macros };
383
+ try {
384
+ let html = katex.renderToString(entry.tex, {
385
+ displayMode: entry.displayMode,
386
+ throwOnError: !1,
387
+ trust: !1,
388
+ maxExpand: 1e3,
389
+ macros: nextMacros
390
+ });
391
+ macros = nextMacros, preparation = { tex: entry.tex, displayMode: entry.displayMode, scope: this, html };
392
+ } catch (reason) {
393
+ preparation = {
394
+ tex: entry.tex,
395
+ displayMode: entry.displayMode,
396
+ scope: this,
397
+ error: reason instanceof Error ? reason : new Error(String(reason))
398
+ };
399
+ }
400
+ }
401
+ this.macroSnapshots[index] = { ...macros }, entry.publish(preparation);
767
402
  }
768
- let cancelled = false;
769
- let idleId = null;
770
- let timerId = null;
771
- const scheduleRender = () => {
772
- if (cancelled) return;
773
- setShouldRender(true);
403
+ }
404
+ }, DocumentMathMacroScopeContext = createContext(null), MathExpressionCompletenessContext = createContext(!0), MathEngineOutputView = ({ engine, tex, displayMode }) => {
405
+ let output = useMemo(
406
+ () => engine.render(tex, { displayMode }),
407
+ [engine, engine.id, tex, displayMode]
408
+ );
409
+ return /* @__PURE__ */ jsx3(Fragment2, { children: output });
410
+ };
411
+ function useMathPreparation(tex, displayMode, elementRef, enabled) {
412
+ let scope = useContext(DocumentMathMacroScopeContext), complete = useContext(MathExpressionCompletenessContext), [preparation, setPreparation] = useState2(null);
413
+ return useEffect2(() => {
414
+ if (!enabled) return;
415
+ let active = !0;
416
+ if (scope) {
417
+ let element = elementRef.current;
418
+ return element ? scope.register(element, tex, displayMode, complete, (result) => {
419
+ active && setPreparation(result);
420
+ }) : () => {
421
+ active = !1;
422
+ };
423
+ }
424
+ return (async () => {
425
+ try {
426
+ let html = (await loadKaTeX()).renderToString(tex, {
427
+ displayMode,
428
+ throwOnError: !1,
429
+ trust: !1,
430
+ maxExpand: 1e3
431
+ });
432
+ active && setPreparation({ tex, displayMode, scope: null, html });
433
+ } catch (reason) {
434
+ active && setPreparation({
435
+ tex,
436
+ displayMode,
437
+ scope: null,
438
+ error: reason instanceof Error ? reason : new Error(String(reason))
439
+ });
440
+ }
441
+ })(), () => {
442
+ active = !1;
774
443
  };
775
- const runWithIdle = () => {
776
- if (typeof globalThis.requestIdleCallback === "function") {
777
- idleId = globalThis.requestIdleCallback(scheduleRender, { timeout: options?.idleTimeoutMs ?? 200 });
778
- } else {
779
- timerId = window.setTimeout(scheduleRender, options?.idleTimeoutMs ?? 200);
444
+ }, [tex, displayMode, scope, complete, elementRef, enabled]), scope && !complete ? null : preparation?.tex === tex && preparation.displayMode === displayMode && preparation.scope === scope ? preparation : null;
445
+ }
446
+ var KaTeXInlineMath = ({ tex, className = "", fallback, engine }) => {
447
+ let elementRef = useRef2(null), preparation = useMathPreparation(tex, !1, elementRef, !engine);
448
+ return engine ? /* @__PURE__ */ jsx3("span", { className: `math-inline ${className}`.trim(), "data-tex": tex, children: /* @__PURE__ */ jsx3(MathEngineOutputView, { engine, tex, displayMode: !1 }) }) : preparation && "error" in preparation && fallback ? /* @__PURE__ */ jsx3(Fragment2, { children: fallback(tex, preparation.error) }) : preparation && "html" in preparation ? /* @__PURE__ */ jsx3(
449
+ "span",
450
+ {
451
+ ref: elementRef,
452
+ className: `math-inline katex-inline ${className}`.trim(),
453
+ "data-tex": tex,
454
+ dangerouslySetInnerHTML: { __html: preparation.html }
455
+ }
456
+ ) : /* @__PURE__ */ jsxs3("span", { ref: elementRef, className: `math-inline ${className}`.trim(), "data-tex": tex, children: [
457
+ "$",
458
+ tex,
459
+ "$"
460
+ ] });
461
+ };
462
+ KaTeXInlineMath.displayName = "KaTeXInlineMath";
463
+ var KaTeXBlockMath = ({ tex, className = "", fallback, engine }) => {
464
+ let elementRef = useRef2(null), preparation = useMathPreparation(tex, !0, elementRef, !engine);
465
+ return engine ? /* @__PURE__ */ jsx3(
466
+ "div",
467
+ {
468
+ className: `math-display markdown-math-display ${className}`.trim(),
469
+ "data-tex": tex,
470
+ style: { overflowX: "auto" },
471
+ children: /* @__PURE__ */ jsx3(MathEngineOutputView, { engine, tex, displayMode: !0 })
472
+ }
473
+ ) : preparation && "error" in preparation && fallback ? /* @__PURE__ */ jsx3(Fragment2, { children: fallback(tex, preparation.error) }) : preparation && "html" in preparation ? /* @__PURE__ */ jsx3(
474
+ "div",
475
+ {
476
+ ref: elementRef,
477
+ className: `math-display katex-block markdown-math-display ${className}`.trim(),
478
+ "data-tex": tex,
479
+ style: { overflowX: "auto" },
480
+ dangerouslySetInnerHTML: { __html: preparation.html }
481
+ }
482
+ ) : /* @__PURE__ */ jsx3(
483
+ "div",
484
+ {
485
+ ref: elementRef,
486
+ className: `math-display markdown-math-display ${className}`.trim(),
487
+ "data-tex": tex,
488
+ style: { overflowX: "auto" },
489
+ children: /* @__PURE__ */ jsxs3("span", { className: "math-display-content", children: [
490
+ "$$",
491
+ tex,
492
+ "$$"
493
+ ] })
494
+ }
495
+ );
496
+ };
497
+ KaTeXBlockMath.displayName = "KaTeXBlockMath";
498
+
499
+ // src/components/controls.tsx
500
+ import React2, { useCallback as useCallback2, useState as useState3 } from "react";
501
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
502
+ var DEFAULT_CONTROLS_LABELS = {
503
+ copy: "Copy code",
504
+ copied: "Copied!",
505
+ copyError: "Failed to copy",
506
+ download: "Download snippet",
507
+ downloadCsv: "Download CSV",
508
+ downloadTsv: "Download TSV",
509
+ downloadMarkdown: "Download Markdown",
510
+ copyTsv: "Copy TSV",
511
+ copyMarkdown: "Copy Markdown",
512
+ copyTable: "Copy table",
513
+ fullscreen: "Enter fullscreen",
514
+ exitFullscreen: "Exit fullscreen"
515
+ }, LANGUAGE_EXTENSION_MAP = {
516
+ javascript: "js",
517
+ js: "js",
518
+ mjs: "mjs",
519
+ cjs: "cjs",
520
+ typescript: "ts",
521
+ ts: "ts",
522
+ mts: "mts",
523
+ cts: "cts",
524
+ jsx: "jsx",
525
+ tsx: "tsx",
526
+ python: "py",
527
+ py: "py",
528
+ rust: "rs",
529
+ rs: "rs",
530
+ ruby: "rb",
531
+ rb: "rb",
532
+ go: "go",
533
+ golang: "go",
534
+ c: "c",
535
+ cpp: "cpp",
536
+ "c++": "cpp",
537
+ csharp: "cs",
538
+ "c#": "cs",
539
+ cs: "cs",
540
+ java: "java",
541
+ kotlin: "kt",
542
+ kt: "kt",
543
+ swift: "swift",
544
+ php: "php",
545
+ html: "html",
546
+ css: "css",
547
+ scss: "scss",
548
+ sass: "sass",
549
+ less: "less",
550
+ json: "json",
551
+ jsonc: "jsonc",
552
+ yaml: "yaml",
553
+ yml: "yaml",
554
+ toml: "toml",
555
+ xml: "xml",
556
+ svg: "svg",
557
+ markdown: "md",
558
+ md: "md",
559
+ mdx: "mdx",
560
+ sh: "sh",
561
+ bash: "sh",
562
+ shell: "sh",
563
+ zsh: "sh",
564
+ sql: "sql",
565
+ diff: "diff",
566
+ dockerfile: "dockerfile",
567
+ makefile: "makefile",
568
+ graphql: "graphql",
569
+ gql: "graphql",
570
+ lua: "lua",
571
+ r: "r",
572
+ scala: "scala",
573
+ perl: "pl",
574
+ pl: "pl",
575
+ mermaid: "mmd",
576
+ latex: "tex",
577
+ tex: "tex",
578
+ ini: "ini",
579
+ env: "env",
580
+ text: "txt",
581
+ txt: "txt"
582
+ };
583
+ function getExtensionForLanguage(lang) {
584
+ if (!lang) return "txt";
585
+ let clean = lang.trim().toLowerCase().split(/\s+/)[0] ?? "";
586
+ return clean ? LANGUAGE_EXTENSION_MAP[clean] ? LANGUAGE_EXTENSION_MAP[clean] : /^[a-z0-9]+$/.test(clean) ? clean : "txt" : "txt";
587
+ }
588
+ function getCodeSnippetFilename(lang) {
589
+ return `snippet.${getExtensionForLanguage(lang)}`;
590
+ }
591
+ async function copyToClipboard(text) {
592
+ if (typeof navigator > "u" || !navigator.clipboard?.writeText)
593
+ return !1;
594
+ try {
595
+ return await navigator.clipboard.writeText(text), !0;
596
+ } catch {
597
+ return !1;
598
+ }
599
+ }
600
+ function downloadFile(content, filename, mimeType = "text/plain;charset=utf-8") {
601
+ if (!(typeof window > "u" || typeof document > "u"))
602
+ try {
603
+ let blob = new Blob([content], { type: mimeType }), url = URL.createObjectURL(blob), a = document.createElement("a");
604
+ a.href = url, a.download = filename, a.style.display = "none", document.body.appendChild(a);
605
+ try {
606
+ a.click();
607
+ } finally {
608
+ document.body.removeChild(a), setTimeout(() => {
609
+ try {
610
+ URL.revokeObjectURL(url);
611
+ } catch {
612
+ }
613
+ }, 100);
780
614
  }
615
+ } catch {
616
+ }
617
+ }
618
+ function escapeCsvCell(cell) {
619
+ return /[",\r\n]/.test(cell) ? `"${cell.replace(/"/g, '""')}"` : cell;
620
+ }
621
+ function escapeTsvCell(cell) {
622
+ return cell.replace(/\t/g, " ").replace(/\r?\n/g, " ");
623
+ }
624
+ function tableToCsv(headers, rows) {
625
+ let lines = [];
626
+ headers.length > 0 && lines.push(headers.map(escapeCsvCell).join(","));
627
+ for (let row of rows)
628
+ lines.push(row.map(escapeCsvCell).join(","));
629
+ return lines.join(`
630
+ `);
631
+ }
632
+ function tableToTsv(headers, rows) {
633
+ let lines = [];
634
+ headers.length > 0 && lines.push(headers.map(escapeTsvCell).join(" "));
635
+ for (let row of rows)
636
+ lines.push(row.map(escapeTsvCell).join(" "));
637
+ return lines.join(`
638
+ `);
639
+ }
640
+ function tableToMarkdown(headers, rows, align) {
641
+ if (headers.length === 0 && rows.length === 0) return "";
642
+ let columnCount = Math.max(headers.length, ...rows.map((r) => r.length));
643
+ if (columnCount === 0) return "";
644
+ let padRow = (row) => {
645
+ let padded = [...row];
646
+ for (; padded.length < columnCount; ) padded.push("");
647
+ return padded.map((cell) => cell.replace(/\r?\n/g, " ").replace(/\|/g, "\\|"));
648
+ }, headerLine = `| ${padRow(headers.length > 0 ? headers : Array(columnCount).fill("")).join(" | ")} |`, separatorLine = `| ${Array.from({ length: columnCount }, (_, i) => {
649
+ let a = align?.[i];
650
+ return a === "center" ? ":---:" : a === "right" ? "---:" : a === "left" ? ":---" : "---";
651
+ }).join(" | ")} |`, dataLines = rows.map((row) => `| ${padRow(row).join(" | ")} |`);
652
+ return [headerLine, separatorLine, ...dataLines].join(`
653
+ `);
654
+ }
655
+ function inlineToPlainText(nodes) {
656
+ if (!Array.isArray(nodes) || nodes.length === 0) return "";
657
+ let out = "";
658
+ for (let node of nodes)
659
+ if (node)
660
+ switch (node.kind) {
661
+ case "text":
662
+ case "code":
663
+ out += node.text ?? "";
664
+ break;
665
+ case "strong":
666
+ case "em":
667
+ case "strike":
668
+ out += inlineToPlainText(node.children);
669
+ break;
670
+ case "link":
671
+ out += inlineToPlainText(node.children) || node.title || node.href || "";
672
+ break;
673
+ case "image":
674
+ out += node.alt || node.title || "";
675
+ break;
676
+ case "br":
677
+ out += `
678
+ `;
679
+ break;
680
+ case "html":
681
+ Array.isArray(node.children) && node.children.length > 0 ? out += inlineToPlainText(node.children) : node.raw && (/<br\s*\/?>/i.test(node.raw) ? out += `
682
+ ` : out += node.raw.replace(/<[^>]*>/g, ""));
683
+ break;
684
+ case "math-inline":
685
+ case "math-display":
686
+ out += node.tex ?? "";
687
+ break;
688
+ case "mention":
689
+ out += `@${node.handle ?? ""}`;
690
+ break;
691
+ case "citation":
692
+ out += `[${node.id ?? ""}]`;
693
+ break;
694
+ case "footnote-ref":
695
+ out += `[${node.label ?? ""}]`;
696
+ break;
697
+ case "plugin":
698
+ Array.isArray(node.children) ? out += inlineToPlainText(node.children) : out += node.raw ?? "";
699
+ break;
700
+ default: {
701
+ let generic = node;
702
+ generic && typeof generic == "object" && ("text" in generic && typeof generic.text == "string" ? out += generic.text : "children" in generic && Array.isArray(generic.children) && (out += inlineToPlainText(generic.children)));
703
+ break;
704
+ }
705
+ }
706
+ return out;
707
+ }
708
+ function resolveCodeControls(config) {
709
+ if (!config)
710
+ return { enabled: !1, copy: !1, download: !1, labels: DEFAULT_CONTROLS_LABELS };
711
+ let labels = {
712
+ ...DEFAULT_CONTROLS_LABELS,
713
+ ...typeof config == "object" ? config.labels : void 0
714
+ };
715
+ if (config === !0)
716
+ return { enabled: !0, copy: !0, download: !0, labels };
717
+ let codeOpt = config.code;
718
+ if (!codeOpt)
719
+ return { enabled: !1, copy: !1, download: !1, labels };
720
+ if (codeOpt === !0)
721
+ return { enabled: !0, copy: !0, download: !0, labels };
722
+ let copy = !!codeOpt.copy, download = !!codeOpt.download;
723
+ return { enabled: copy || download, copy, download, labels };
724
+ }
725
+ function resolveTableControls(config) {
726
+ if (!config)
727
+ return {
728
+ enabled: !1,
729
+ copy: !1,
730
+ copyFormats: [],
731
+ download: !1,
732
+ downloadFormats: [],
733
+ labels: DEFAULT_CONTROLS_LABELS
734
+ };
735
+ let labels = {
736
+ ...DEFAULT_CONTROLS_LABELS,
737
+ ...typeof config == "object" ? config.labels : void 0
738
+ };
739
+ if (config === !0)
740
+ return {
741
+ enabled: !0,
742
+ copy: !0,
743
+ copyFormats: ["tsv", "markdown"],
744
+ download: !0,
745
+ downloadFormats: ["csv"],
746
+ labels
747
+ };
748
+ let tableOpt = config.table;
749
+ if (!tableOpt)
750
+ return {
751
+ enabled: !1,
752
+ copy: !1,
753
+ copyFormats: [],
754
+ download: !1,
755
+ downloadFormats: [],
756
+ labels: DEFAULT_CONTROLS_LABELS
781
757
  };
782
- const observer = new IntersectionObserver(
783
- (entries2) => {
784
- for (const entry of entries2) {
785
- if (entry.isIntersecting || entry.intersectionRatio > 0) {
786
- observer.disconnect();
787
- const debounceMs = options?.debounceMs ?? 80;
788
- timerId = window.setTimeout(runWithIdle, debounceMs);
789
- return;
758
+ if (tableOpt === !0)
759
+ return {
760
+ enabled: !0,
761
+ copy: !0,
762
+ copyFormats: ["tsv", "markdown"],
763
+ download: !0,
764
+ downloadFormats: ["csv"],
765
+ labels
766
+ };
767
+ let copyVal = tableOpt.copy, copy = !!copyVal, copyFormats = Array.isArray(copyVal) ? copyVal : copyVal ? ["tsv", "markdown"] : [], downloadVal = tableOpt.download, download = !!downloadVal, downloadFormats = Array.isArray(downloadVal) ? downloadVal : downloadVal ? ["csv"] : [];
768
+ return {
769
+ enabled: copy || download,
770
+ copy,
771
+ copyFormats,
772
+ download,
773
+ downloadFormats,
774
+ labels
775
+ };
776
+ }
777
+ function resolveMermaidControls(config) {
778
+ if (!config)
779
+ return { enabled: !1, copy: !1, fullscreen: !1, labels: DEFAULT_CONTROLS_LABELS };
780
+ let labels = {
781
+ ...DEFAULT_CONTROLS_LABELS,
782
+ ...typeof config == "object" ? config.labels : void 0
783
+ };
784
+ if (config === !0)
785
+ return { enabled: !0, copy: !0, fullscreen: !1, labels };
786
+ let mermaidOpt = config.mermaid;
787
+ if (!mermaidOpt)
788
+ return { enabled: !1, copy: !1, fullscreen: !1, labels };
789
+ if (mermaidOpt === !0)
790
+ return { enabled: !0, copy: !0, fullscreen: !1, labels };
791
+ let copy = !!mermaidOpt.copy, fullscreen = !!mermaidOpt.fullscreen;
792
+ return { enabled: copy || fullscreen, copy, fullscreen, labels };
793
+ }
794
+ function resolveControlsConfig(config) {
795
+ return {
796
+ code: resolveCodeControls(config),
797
+ table: resolveTableControls(config),
798
+ mermaid: resolveMermaidControls(config)
799
+ };
800
+ }
801
+ var CodeControlsBar = ({ code, language, config, className }) => {
802
+ let [copied, setCopied] = useState3(!1), { labels } = config, handleCopy = useCallback2(async () => {
803
+ await copyToClipboard(code) && (setCopied(!0), setTimeout(() => setCopied(!1), 2e3));
804
+ }, [code]), handleDownload = useCallback2(() => {
805
+ let filename = getCodeSnippetFilename(language);
806
+ downloadFile(code, filename);
807
+ }, [code, language]);
808
+ return /* @__PURE__ */ jsxs4(
809
+ "div",
810
+ {
811
+ className: `stream-mdx-controls stream-mdx-code-controls flex items-center justify-end gap-1 px-2 py-1 text-xs select-none ${className ?? ""}`.trim(),
812
+ "data-stream-mdx-controls": "code",
813
+ children: [
814
+ language ? /* @__PURE__ */ jsx4("span", { className: "stream-mdx-code-language mr-auto text-muted-foreground opacity-60 text-[11px] font-mono", children: language }) : null,
815
+ config.copy ? /* @__PURE__ */ jsx4(
816
+ "button",
817
+ {
818
+ type: "button",
819
+ className: "stream-mdx-control stream-mdx-control-copy stream-mdx-control-code-copy inline-flex items-center gap-1 rounded px-2 py-0.5 text-xs hover:bg-muted focus:outline-none",
820
+ "data-stream-mdx-control": "copy",
821
+ "data-stream-mdx-target": "code",
822
+ "data-stream-mdx-action": "copy",
823
+ "aria-label": copied ? labels.copied ?? "Copied!" : labels.copy ?? "Copy code",
824
+ onClick: handleCopy,
825
+ children: copied ? labels.copied ?? "Copied!" : labels.copy ?? "Copy"
826
+ }
827
+ ) : null,
828
+ config.download ? /* @__PURE__ */ jsx4(
829
+ "button",
830
+ {
831
+ type: "button",
832
+ className: "stream-mdx-control stream-mdx-control-download stream-mdx-control-code-download inline-flex items-center gap-1 rounded px-2 py-0.5 text-xs hover:bg-muted focus:outline-none",
833
+ "data-stream-mdx-control": "download",
834
+ "data-stream-mdx-target": "code",
835
+ "data-stream-mdx-action": "download",
836
+ "aria-label": labels.download ?? "Download snippet",
837
+ onClick: handleDownload,
838
+ children: labels.download ?? "Download"
790
839
  }
840
+ ) : null
841
+ ]
842
+ }
843
+ );
844
+ }, TableControlsBar = ({
845
+ headers,
846
+ rows,
847
+ align,
848
+ getTableData,
849
+ getMarkdownSource,
850
+ isFinalized,
851
+ config,
852
+ className
853
+ }) => {
854
+ let [copiedFormat, setCopiedFormat] = useState3(null), copiedFeedbackTimeout = React2.useRef(void 0), mounted = React2.useRef(!0), { labels } = config;
855
+ React2.useEffect(() => (mounted.current = !0, () => {
856
+ mounted.current = !1, window.clearTimeout(copiedFeedbackTimeout.current);
857
+ }), []);
858
+ let handleCopy = useCallback2(
859
+ async (format) => {
860
+ if (!isFinalized) return;
861
+ let text;
862
+ if (format === "markdown") {
863
+ let source = getMarkdownSource?.();
864
+ if (source !== void 0)
865
+ text = source;
866
+ else {
867
+ let data = getTableData?.() ?? { headers, rows, align };
868
+ text = tableToMarkdown(data.headers, data.rows, data.align);
791
869
  }
792
- },
793
- { rootMargin: options?.rootMargin ?? "200px 0px" }
794
- );
795
- observer.observe(target);
796
- return () => {
797
- cancelled = true;
798
- observer.disconnect();
799
- if (idleId !== null && typeof globalThis.cancelIdleCallback === "function") {
800
- globalThis.cancelIdleCallback(idleId);
870
+ } else {
871
+ let data = getTableData?.() ?? { headers, rows, align };
872
+ text = tableToTsv(data.headers, data.rows);
801
873
  }
802
- if (timerId !== null) {
803
- window.clearTimeout(timerId);
874
+ if (await copyToClipboard(text)) {
875
+ if (!mounted.current) return;
876
+ setCopiedFormat(format), window.clearTimeout(copiedFeedbackTimeout.current), copiedFeedbackTimeout.current = window.setTimeout(() => {
877
+ copiedFeedbackTimeout.current = void 0, setCopiedFormat(null);
878
+ }, 2e3);
804
879
  }
805
- };
806
- }, [enabled, options?.debounceMs, options?.idleTimeoutMs, options?.rootMargin, ref]);
807
- return shouldRender;
880
+ },
881
+ [headers, rows, align, getTableData, getMarkdownSource, isFinalized]
882
+ ), handleDownload = useCallback2(
883
+ (format) => {
884
+ if (!isFinalized) return;
885
+ let text = "", filename = "table.csv", mimeType = "text/csv;charset=utf-8";
886
+ if (format === "markdown") {
887
+ let source = getMarkdownSource?.();
888
+ if (source !== void 0)
889
+ text = source;
890
+ else {
891
+ let data = getTableData?.() ?? { headers, rows, align };
892
+ text = tableToMarkdown(data.headers, data.rows, data.align);
893
+ }
894
+ filename = "table.md", mimeType = "text/markdown;charset=utf-8";
895
+ } else if (format === "tsv") {
896
+ let data = getTableData?.() ?? { headers, rows, align };
897
+ text = tableToTsv(data.headers, data.rows), filename = "table.tsv", mimeType = "text/tab-separated-values;charset=utf-8";
898
+ } else {
899
+ let data = getTableData?.() ?? { headers, rows, align };
900
+ text = tableToCsv(data.headers, data.rows);
901
+ }
902
+ downloadFile(text, filename, mimeType);
903
+ },
904
+ [headers, rows, align, getTableData, getMarkdownSource, isFinalized]
905
+ );
906
+ return /* @__PURE__ */ jsxs4(
907
+ "div",
908
+ {
909
+ className: `stream-mdx-controls stream-mdx-table-controls flex items-center justify-end gap-1 px-2 py-1 text-xs select-none ${className ?? ""}`.trim(),
910
+ "data-stream-mdx-controls": "table",
911
+ children: [
912
+ config.copyFormats.map((format) => {
913
+ let isCopied = copiedFormat === format, defaultLabel = format === "markdown" ? "Copy Markdown" : "Copy TSV", labelText = format === "markdown" ? labels.copyMarkdown ?? defaultLabel : labels.copyTsv ?? defaultLabel;
914
+ return /* @__PURE__ */ jsx4(
915
+ "button",
916
+ {
917
+ type: "button",
918
+ disabled: !isFinalized,
919
+ className: `stream-mdx-control stream-mdx-control-copy stream-mdx-control-table-copy stream-mdx-control-copy-${format} inline-flex items-center gap-1 rounded px-2 py-0.5 text-xs hover:bg-muted focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed`,
920
+ "data-stream-mdx-control": "copy",
921
+ "data-stream-mdx-target": "table",
922
+ "data-stream-mdx-format": format,
923
+ "data-stream-mdx-action": `copy-${format}`,
924
+ "data-format": format,
925
+ "aria-label": isCopied ? labels.copied ?? "Copied!" : labelText,
926
+ onClick: () => handleCopy(format),
927
+ children: isCopied ? labels.copied ?? "Copied!" : labelText
928
+ },
929
+ `copy-${format}`
930
+ );
931
+ }),
932
+ config.downloadFormats.map((format) => {
933
+ let defaultLabel = format === "csv" ? "Download CSV" : format === "tsv" ? "Download TSV" : "Download Markdown", labelText = format === "csv" ? labels.downloadCsv ?? defaultLabel : format === "tsv" ? labels.downloadTsv ?? defaultLabel : labels.downloadMarkdown ?? defaultLabel;
934
+ return /* @__PURE__ */ jsx4(
935
+ "button",
936
+ {
937
+ type: "button",
938
+ disabled: !isFinalized,
939
+ className: `stream-mdx-control stream-mdx-control-download stream-mdx-control-table-download stream-mdx-control-download-${format} inline-flex items-center gap-1 rounded px-2 py-0.5 text-xs hover:bg-muted focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed`,
940
+ "data-stream-mdx-control": "download",
941
+ "data-stream-mdx-target": "table",
942
+ "data-stream-mdx-format": format,
943
+ "data-stream-mdx-action": `download-${format}`,
944
+ "data-format": format,
945
+ "aria-label": labelText,
946
+ onClick: () => handleDownload(format),
947
+ children: labelText
948
+ },
949
+ `download-${format}`
950
+ );
951
+ })
952
+ ]
953
+ }
954
+ );
955
+ }, CodeBlockCopyButton = ({
956
+ code,
957
+ labels,
958
+ className,
959
+ ...props
960
+ }) => {
961
+ let [copied, setCopied] = useState3(!1), copyLabel = labels?.copy ?? DEFAULT_CONTROLS_LABELS.copy ?? "Copy code", copiedLabel = labels?.copied ?? DEFAULT_CONTROLS_LABELS.copied ?? "Copied!", handleCopy = useCallback2(
962
+ async (e) => {
963
+ if (props.onClick?.(e), e.defaultPrevented) return;
964
+ await copyToClipboard(code) && (setCopied(!0), setTimeout(() => setCopied(!1), 2e3));
965
+ },
966
+ [code, props.onClick]
967
+ );
968
+ return /* @__PURE__ */ jsx4(
969
+ "button",
970
+ {
971
+ type: "button",
972
+ className: `stream-mdx-control stream-mdx-control-copy stream-mdx-control-code-copy ${className ?? ""}`.trim(),
973
+ "data-stream-mdx-control": "copy",
974
+ "data-stream-mdx-target": "code",
975
+ "data-stream-mdx-action": "copy",
976
+ "aria-label": copied ? copiedLabel : copyLabel,
977
+ ...props,
978
+ onClick: handleCopy,
979
+ children: props.children ?? (copied ? copiedLabel : "Copy")
980
+ }
981
+ );
982
+ }, CodeBlockDownloadButton = ({
983
+ code,
984
+ language,
985
+ filename,
986
+ labels,
987
+ className,
988
+ ...props
989
+ }) => {
990
+ let downloadLabel = labels?.download ?? DEFAULT_CONTROLS_LABELS.download ?? "Download snippet", handleDownload = useCallback2(
991
+ (e) => {
992
+ if (props.onClick?.(e), e.defaultPrevented) return;
993
+ let targetFilename = filename ?? getCodeSnippetFilename(language);
994
+ downloadFile(code, targetFilename);
995
+ },
996
+ [code, language, filename, props.onClick]
997
+ );
998
+ return /* @__PURE__ */ jsx4(
999
+ "button",
1000
+ {
1001
+ type: "button",
1002
+ className: `stream-mdx-control stream-mdx-control-download stream-mdx-control-code-download ${className ?? ""}`.trim(),
1003
+ "data-stream-mdx-control": "download",
1004
+ "data-stream-mdx-target": "code",
1005
+ "data-stream-mdx-action": "download",
1006
+ "aria-label": downloadLabel,
1007
+ ...props,
1008
+ onClick: handleDownload,
1009
+ children: props.children ?? labels?.download ?? "Download"
1010
+ }
1011
+ );
1012
+ };
1013
+
1014
+ // src/animation.ts
1015
+ var BUILTIN_ANIMATION_NAMES = {
1016
+ fadeIn: "stream-mdx-fade-in",
1017
+ blurIn: "stream-mdx-blur-in",
1018
+ slideUp: "stream-mdx-slide-up"
1019
+ }, DEFAULT_ANIMATED_OPTIONS = {
1020
+ animation: "fadeIn",
1021
+ animationName: "stream-mdx-fade-in",
1022
+ duration: 150,
1023
+ durationStr: "150ms",
1024
+ easing: "ease-out",
1025
+ sep: "word",
1026
+ stagger: 20,
1027
+ maxBacklogMs: 320
1028
+ };
1029
+ function resolveAnimatedOptions(prop) {
1030
+ if (!prop) return null;
1031
+ if (prop === !0) return DEFAULT_ANIMATED_OPTIONS;
1032
+ let animation = prop.animation ?? DEFAULT_ANIMATED_OPTIONS.animation, duration = typeof prop.duration == "number" ? prop.duration : DEFAULT_ANIMATED_OPTIONS.duration;
1033
+ return {
1034
+ animation,
1035
+ animationName: BUILTIN_ANIMATION_NAMES[animation] ?? animation,
1036
+ duration,
1037
+ durationStr: `${duration}ms`,
1038
+ easing: prop.easing ?? DEFAULT_ANIMATED_OPTIONS.easing,
1039
+ sep: prop.sep ?? DEFAULT_ANIMATED_OPTIONS.sep,
1040
+ stagger: typeof prop.stagger == "number" ? prop.stagger : DEFAULT_ANIMATED_OPTIONS.stagger,
1041
+ maxBacklogMs: typeof prop.maxBacklogMs == "number" ? prop.maxBacklogMs : DEFAULT_ANIMATED_OPTIONS.maxBacklogMs
1042
+ };
1043
+ }
1044
+ var STREAM_MDX_ANIMATION_CSS = `
1045
+ @keyframes stream-mdx-fade-in {
1046
+ from {
1047
+ opacity: 0;
1048
+ }
1049
+ to {
1050
+ opacity: 1;
1051
+ }
808
1052
  }
809
1053
 
1054
+ @keyframes fadeIn {
1055
+ from {
1056
+ opacity: 0;
1057
+ }
1058
+ to {
1059
+ opacity: 1;
1060
+ }
1061
+ }
1062
+
1063
+ @keyframes stream-mdx-blur-in {
1064
+ from {
1065
+ opacity: 0;
1066
+ filter: blur(4px);
1067
+ }
1068
+ to {
1069
+ opacity: 1;
1070
+ filter: blur(0px);
1071
+ }
1072
+ }
1073
+
1074
+ @keyframes blurIn {
1075
+ from {
1076
+ opacity: 0;
1077
+ filter: blur(4px);
1078
+ }
1079
+ to {
1080
+ opacity: 1;
1081
+ filter: blur(0px);
1082
+ }
1083
+ }
1084
+
1085
+ @keyframes stream-mdx-slide-up {
1086
+ from {
1087
+ opacity: 0;
1088
+ transform: translateY(4px);
1089
+ }
1090
+ to {
1091
+ opacity: 1;
1092
+ transform: translateY(0);
1093
+ }
1094
+ }
1095
+
1096
+ @keyframes slideUp {
1097
+ from {
1098
+ opacity: 0;
1099
+ transform: translateY(4px);
1100
+ }
1101
+ to {
1102
+ opacity: 1;
1103
+ transform: translateY(0);
1104
+ }
1105
+ }
1106
+
1107
+ .stream-mdx-anim {
1108
+ display: inline;
1109
+ animation-name: var(--sm-anim-name, stream-mdx-fade-in);
1110
+ animation-duration: var(--sm-anim-duration, 150ms);
1111
+ animation-timing-function: var(--sm-anim-easing, ease-out);
1112
+ animation-delay: var(--sm-anim-delay, 0ms);
1113
+ animation-fill-mode: both;
1114
+ }
1115
+
1116
+ @media (prefers-reduced-motion: reduce) {
1117
+ .stream-mdx-anim {
1118
+ animation: none !important;
1119
+ }
1120
+ }
1121
+ `.trim(), WHITESPACE_REGEX = /\s/;
1122
+ function splitWordSegments(text) {
1123
+ let result = [], current = "", inWhitespace = !1;
1124
+ for (let char of text) {
1125
+ let isSpace = WHITESPACE_REGEX.test(char);
1126
+ if (isSpace !== inWhitespace && current) {
1127
+ if (isSpace) {
1128
+ current += char, inWhitespace = !0;
1129
+ continue;
1130
+ }
1131
+ result.push(current), current = "";
1132
+ }
1133
+ current += char, inWhitespace = isSpace;
1134
+ }
1135
+ return current && result.push(current), result;
1136
+ }
1137
+ function splitTextSegments(text, sep) {
1138
+ return sep === "char" ? Array.from(text) : splitWordSegments(text);
1139
+ }
1140
+ var AnimationTimeline = class {
1141
+ constructor(options) {
1142
+ this.committedEndTime = 0;
1143
+ this.cursorEndTime = 0;
1144
+ this.passActive = !1;
1145
+ this.nodeStates = /* @__PURE__ */ new Map();
1146
+ this.now = options?.now ?? (() => typeof performance < "u" ? performance.now() : Date.now()), this.maxBacklogMs = options?.maxBacklogMs ?? 320, this.stagger = options?.stagger ?? 20;
1147
+ }
1148
+ updateOptions(options) {
1149
+ typeof options.maxBacklogMs == "number" && (this.maxBacklogMs = options.maxBacklogMs), typeof options.stagger == "number" && (this.stagger = options.stagger);
1150
+ }
1151
+ beginPass(currentTime = this.now()) {
1152
+ this.passActive || (this.passActive = !0, this.cursorEndTime = Math.min(
1153
+ Math.max(this.committedEndTime, currentTime),
1154
+ currentTime + this.maxBacklogMs
1155
+ ), typeof queueMicrotask == "function" ? queueMicrotask(() => this.commitPass()) : setTimeout(() => this.commitPass(), 0));
1156
+ }
1157
+ commitPass() {
1158
+ this.committedEndTime = this.cursorEndTime, this.passActive = !1;
1159
+ }
1160
+ schedule(count, stagger = this.stagger, currentTime = this.now()) {
1161
+ if (this.beginPass(currentTime), count <= 0) return [];
1162
+ let d = Math.max(0, stagger), maxDeadline = currentTime + this.maxBacklogMs, start = Math.min(Math.max(this.cursorEndTime, currentTime), maxDeadline), step = count > 1 ? Math.min(d, Math.max(0, maxDeadline - start) / (count - 1)) : d, baseDelay = Math.max(0, start - currentTime);
1163
+ this.cursorEndTime = Math.min(start + count * step, maxDeadline);
1164
+ let delays = [];
1165
+ for (let i = 0; i < count; i++)
1166
+ delays.push(Math.min(this.maxBacklogMs, Math.round(baseDelay + i * step)));
1167
+ return delays;
1168
+ }
1169
+ getNodeState(key) {
1170
+ let state = this.nodeStates.get(key);
1171
+ return state || (state = { count: 0, delays: [] }, this.nodeStates.set(key, state)), state;
1172
+ }
1173
+ reset() {
1174
+ this.committedEndTime = 0, this.cursorEndTime = 0, this.passActive = !1, this.nodeStates.clear();
1175
+ }
1176
+ releasePrefix(prefix) {
1177
+ let prefixColon = `${prefix}:`;
1178
+ for (let key of this.nodeStates.keys())
1179
+ (key === prefix || key.startsWith(prefixColon)) && this.nodeStates.delete(key);
1180
+ }
1181
+ };
1182
+
810
1183
  // src/components/index.ts
1184
+ import { defaultUrlTransform as defaultUrlTransform3 } from "@stream-mdx/core";
1185
+ import { InlineParser, createTrustedHTML, defaultUrlTransform as defaultUrlTransform4, isForbiddenAttribute as isForbiddenAttribute2, isSafeStyleDeclaration as isSafeStyleDeclaration2, sanitizeHTML, stripCodeFence } from "@stream-mdx/core";
811
1186
  import { removeHeadingMarkers } from "@stream-mdx/core";
812
- import React4 from "react";
1187
+ import React8 from "react";
813
1188
 
814
1189
  // src/utils/inline-html.ts
815
1190
  import React3 from "react";
816
- var BACKTICK_CONTENT = /^`([\s\S]+)`$/;
817
- var DEFAULT_INLINE_HTML_RENDERERS = {
1191
+ import { defaultUrlTransform, isForbiddenAttribute, isSafeStyleDeclaration } from "@stream-mdx/core";
1192
+ function renderHtmlInlineNode(node, children, elements, key, textValue, urlTransform, filterElement, parentTagName, renderPresentation, renderNativeElement) {
1193
+ if (node.isClose || node.tagName === "script" || node.tagName === "style") return null;
1194
+ if (!node.tagName || node.sanitized === "")
1195
+ return React3.createElement(React3.Fragment, { key }, children);
1196
+ let tag = node.tagName.toLowerCase(), props = mapAttributesToProps(node.attributes ?? {}, urlTransform);
1197
+ props.key = key;
1198
+ let renderElement = () => {
1199
+ let nativeView;
1200
+ return renderNativeElement ? nativeView = renderNativeElement(
1201
+ tag,
1202
+ props,
1203
+ node.isSelfClosing ? void 0 : children,
1204
+ key ?? tag
1205
+ ) : tag === "textarea" ? (props.defaultValue = textValue ?? "", nativeView = React3.createElement(elements?.[tag] ?? tag, props)) : nativeView = React3.createElement(elements?.[tag] ?? tag, props, node.isSelfClosing ? void 0 : children), renderPresentation ? renderPresentation(tag, props, nativeView, children, key ?? tag) : nativeView;
1206
+ };
1207
+ return filterElement ? filterElement(
1208
+ { tagName: tag, properties: props },
1209
+ { source: "html", parentTagName },
1210
+ renderElement,
1211
+ () => children
1212
+ ) : renderElement();
1213
+ }
1214
+ function renderHtmlOwnershipTree(nodes, elements, renderBlock, renderInline, renderInlineElement, renderParagraph, urlTransform, filterElement, parentTagName, contentComponents, renderPresentation, parentPath = "html", renderComponentPresentation) {
1215
+ return nodes.map((node, index) => {
1216
+ let nodeKey = `${parentPath}:${index}`;
1217
+ if (node.kind === "text") return node.inline && renderInline ? renderInline(node.inline, parentTagName) : node.rawSource ?? node.text;
1218
+ if (node.kind === "block") return renderBlock(node.block, parentTagName);
1219
+ if (node.kind === "component") {
1220
+ let reg = contentComponents?.[node.name];
1221
+ if (!reg)
1222
+ return React3.createElement(React3.Fragment, { key: nodeKey }, node.rawSource ?? `<${node.name} />`);
1223
+ let result = reg.render({
1224
+ props: node.props,
1225
+ key: index,
1226
+ hasChildren: node.children.length > 0,
1227
+ renderChildren: () => renderHtmlOwnershipTree(
1228
+ node.children,
1229
+ elements,
1230
+ renderBlock,
1231
+ renderInline,
1232
+ renderInlineElement,
1233
+ renderParagraph,
1234
+ urlTransform,
1235
+ filterElement,
1236
+ node.name,
1237
+ contentComponents,
1238
+ renderPresentation,
1239
+ nodeKey,
1240
+ renderComponentPresentation
1241
+ ),
1242
+ status: node.status,
1243
+ diagnostic: node.diagnostic
1244
+ });
1245
+ return result.kind === "invalid" ? React3.createElement(React3.Fragment, { key: nodeKey }, node.rawSource ?? `<${node.name} />`) : result.kind === "suppressed" ? null : renderComponentPresentation ? renderComponentPresentation(
1246
+ node.name,
1247
+ result.element,
1248
+ React3.isValidElement(result.element) ? result.element.props.children : void 0,
1249
+ nodeKey,
1250
+ node.status,
1251
+ node.rawSource
1252
+ ) : result.element;
1253
+ }
1254
+ let tag = node.tagName.toLowerCase(), props = mapAttributesToProps(node.attributes, urlTransform);
1255
+ props.key = nodeKey;
1256
+ let children = renderHtmlOwnershipTree(node.children, elements, renderBlock, renderInline, renderInlineElement, renderParagraph, urlTransform, filterElement, tag, contentComponents, renderPresentation, nodeKey, renderComponentPresentation);
1257
+ if (node.paragraphRoot && renderParagraph) {
1258
+ let paragraph = filterElement ? filterElement(
1259
+ { tagName: "p", properties: props, blockType: "paragraph" },
1260
+ { source: "markdown", parentTagName },
1261
+ () => renderParagraph(children),
1262
+ () => children
1263
+ ) : renderParagraph(children);
1264
+ return React3.createElement(React3.Fragment, { key: nodeKey }, paragraph);
1265
+ }
1266
+ if (node.inlineNode && renderInlineElement)
1267
+ return React3.createElement(React3.Fragment, { key: nodeKey }, renderInlineElement(node.inlineNode, children, parentTagName, nodeKey));
1268
+ let renderElement = () => {
1269
+ let nativeView;
1270
+ if (tag === "textarea")
1271
+ props.defaultValue = node.children.map((child) => child.kind === "text" ? child.text : "").join(""), nativeView = React3.createElement(elements[tag] ?? tag, props);
1272
+ else {
1273
+ let content = tag === "pre" && node.children.every((child) => child.kind === "text" && !child.inline) ? node.children.map((child) => child.kind === "text" ? child.text : "").join("") : children;
1274
+ nativeView = React3.createElement(elements[tag] ?? tag, props, node.children.length ? content : void 0);
1275
+ }
1276
+ return renderPresentation ? renderPresentation(tag, props, nativeView, children, nodeKey) : nativeView;
1277
+ };
1278
+ return filterElement ? filterElement(
1279
+ { tagName: tag, properties: props },
1280
+ { source: "html", parentTagName },
1281
+ renderElement,
1282
+ () => children
1283
+ ) : renderElement();
1284
+ });
1285
+ }
1286
+ var BACKTICK_CONTENT = /^`([\s\S]+)`$/, DEFAULT_INLINE_HTML_RENDERERS = {
818
1287
  kbd: (descriptor, ctx) => {
819
- const trimmed = descriptor.rawInner.trim();
820
- const match = BACKTICK_CONTENT.exec(trimmed);
1288
+ let trimmed = descriptor.rawInner.trim(), match = BACKTICK_CONTENT.exec(trimmed);
821
1289
  if (match) {
822
- const codeText = decodeHtmlEntities(match[1]);
823
- const props = mapAttributesToProps(descriptor.attributes);
824
- if (ctx.key !== void 0 && ctx.key !== null) {
825
- props.key = ctx.key;
826
- }
827
- return React3.createElement("kbd", props, React3.createElement("code", { className: "inline-code" }, codeText));
1290
+ let codeText = decodeHtmlEntities(match[1]), props = mapAttributesToProps(descriptor.attributes);
1291
+ return ctx.key !== void 0 && ctx.key !== null && (props.key = ctx.key), React3.createElement("kbd", props, React3.createElement("code", { className: "inline-code" }, codeText));
828
1292
  }
829
1293
  return ctx.defaultRender();
830
1294
  }
831
1295
  };
832
1296
  function renderInlineHtmlSegment(raw, sanitized, options = {}) {
833
- const descriptor = parseInlineHtmlDescriptor(raw, sanitized);
834
- if (!descriptor) {
1297
+ let descriptor = parseInlineHtmlDescriptor(raw, sanitized);
1298
+ if (!descriptor)
835
1299
  return null;
836
- }
837
- const className = options.className ?? "markdown-inline-html";
838
- const isInlineTag = INLINE_ELEMENTS.has(descriptor.tagName);
839
- const defaultRender = () => {
840
- if (!descriptor.sanitized || descriptor.sanitized.length === 0) {
841
- if (!descriptor.text) {
842
- return null;
843
- }
844
- if (options.key !== void 0 && options.key !== null) {
845
- return React3.createElement(React3.Fragment, { key: options.key }, descriptor.text);
846
- }
847
- return React3.createElement(React3.Fragment, {}, descriptor.text);
848
- }
1300
+ let className = options.className ?? "markdown-inline-html", hasCustomElement = !!options.htmlElements?.[descriptor.tagName], isInlineTag = INLINE_ELEMENTS.has(descriptor.tagName) || hasCustomElement, defaultRender = () => {
1301
+ if (!descriptor.sanitized || descriptor.sanitized.length === 0)
1302
+ return descriptor.text ? options.key !== void 0 && options.key !== null ? React3.createElement(React3.Fragment, { key: options.key }, descriptor.text) : React3.createElement(React3.Fragment, {}, descriptor.text) : null;
849
1303
  if (isInlineTag) {
850
- const parsedElement = renderSanitizedHtmlTree(descriptor.sanitized, options.key);
851
- if (parsedElement) {
1304
+ let parsedElement = renderSanitizedHtmlTree(
1305
+ descriptor.sanitized,
1306
+ options.key,
1307
+ options.htmlElements,
1308
+ options.literalTagContent,
1309
+ options.parseMarkdown
1310
+ );
1311
+ if (parsedElement)
852
1312
  return parsedElement;
853
- }
854
1313
  }
855
- const props = {
1314
+ let customElementComp = options.htmlElements?.[descriptor.tagName];
1315
+ if (customElementComp) {
1316
+ let props2 = mapAttributesToProps(descriptor.attributes, options.urlTransform);
1317
+ return options.key !== void 0 && options.key !== null && (props2.key = options.key), React3.createElement(customElementComp, props2, descriptor.text || descriptor.sanitizedInner || void 0);
1318
+ }
1319
+ let props = {
856
1320
  className,
857
1321
  dangerouslySetInnerHTML: { __html: descriptor.sanitized }
858
1322
  };
859
- if (options.key !== void 0 && options.key !== null) {
860
- props.key = options.key;
861
- }
862
- return React3.createElement("span", props);
1323
+ return options.key !== void 0 && options.key !== null && (props.key = options.key), React3.createElement("span", props);
863
1324
  };
864
- const allRenderers = options.renderers ? { ...DEFAULT_INLINE_HTML_RENDERERS, ...options.renderers } : DEFAULT_INLINE_HTML_RENDERERS;
865
- const renderer = allRenderers[descriptor.tagName];
866
- if (renderer) {
867
- const rendered = renderer(descriptor, { key: options.key, defaultRender });
868
- if (rendered) {
869
- if (options.key !== void 0 && options.key !== null && React3.isValidElement(rendered) && rendered.key === null) {
870
- return React3.cloneElement(rendered, { key: options.key });
871
- }
872
- return rendered;
1325
+ if (!hasCustomElement) {
1326
+ let renderer = (options.renderers ? { ...DEFAULT_INLINE_HTML_RENDERERS, ...options.renderers } : DEFAULT_INLINE_HTML_RENDERERS)[descriptor.tagName];
1327
+ if (renderer) {
1328
+ let rendered = renderer(descriptor, { key: options.key, defaultRender });
1329
+ if (rendered)
1330
+ return options.key !== void 0 && options.key !== null && React3.isValidElement(rendered) && rendered.key === null ? React3.cloneElement(rendered, { key: options.key }) : rendered;
873
1331
  }
874
1332
  }
875
1333
  return defaultRender();
876
1334
  }
877
1335
  function parseInlineHtmlDescriptor(raw, sanitized) {
878
- const normalizedRaw = typeof raw === "string" ? raw.trim() : "";
879
- const normalizedSanitized = typeof sanitized === "string" && sanitized.length > 0 ? sanitized.trim() : normalizedRaw;
880
- if (!normalizedSanitized) {
881
- return null;
882
- }
883
- const match = normalizedSanitized.match(/^<([A-Za-z][\w:-]*)(\s[^>]*)?>([\s\S]*)<\/\1>$/);
884
- if (!match) {
1336
+ let normalizedRaw = typeof raw == "string" ? raw.trim() : "", normalizedSanitized = typeof sanitized == "string" && sanitized.length > 0 ? sanitized.trim() : normalizedRaw;
1337
+ if (!normalizedSanitized)
885
1338
  return null;
1339
+ let pairedMatch = normalizedSanitized.match(/^<([A-Za-z][\w:-]*)((?:\s+[^>]*)?)>([\s\S]*)<\/\1>$/), tagNameRaw, attrString = "", sanitizedInner = "";
1340
+ if (pairedMatch)
1341
+ tagNameRaw = pairedMatch[1], attrString = pairedMatch[2] ?? "", sanitizedInner = pairedMatch[3] ?? "";
1342
+ else {
1343
+ let selfClosingMatch = normalizedSanitized.match(/^<([A-Za-z][\w:-]*)((?:\s+[^>]*)?)\s*(?:\/?>|>)$/) || normalizedRaw.match(/^<([A-Za-z][\w:-]*)((?:\s+[^>]*)?)\s*(?:\/?>|>)$/);
1344
+ if (!selfClosingMatch)
1345
+ return null;
1346
+ tagNameRaw = selfClosingMatch[1], attrString = selfClosingMatch[2] ?? "", sanitizedInner = "";
886
1347
  }
887
- const [, tagNameRaw, attrString = "", sanitizedInner = ""] = match;
888
- const tagName = tagNameRaw.toLowerCase();
889
- const attributes = parseAttributes(attrString);
890
- let rawInner = "";
1348
+ let tagName = tagNameRaw.toLowerCase(), attributes = parseAttributes(attrString), rawInner = "";
891
1349
  if (normalizedRaw) {
892
- const rawMatch = normalizedRaw.match(/^<([A-Za-z][\w:-]*)(\s[^>]*)?>([\s\S]*)<\/\1>$/);
1350
+ let rawMatch = normalizedRaw.match(/^<([A-Za-z][\w:-]*)(\s[^>]*)?>([\s\S]*)<\/\1>$/);
893
1351
  rawInner = rawMatch ? rawMatch[3] ?? "" : normalizedRaw;
894
1352
  }
895
- const text = extractPlainText(rawInner || sanitizedInner);
1353
+ let text = extractPlainText(rawInner || sanitizedInner);
896
1354
  return {
897
1355
  tagName,
898
1356
  attributes,
@@ -904,52 +1362,91 @@ function parseInlineHtmlDescriptor(raw, sanitized) {
904
1362
  };
905
1363
  }
906
1364
  function parseAttributes(input) {
907
- const attrs = {};
1365
+ let attrs = {};
908
1366
  if (!input) return attrs;
909
- const attrPattern = /([A-Za-z_:][\w:.\-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
910
- let match = attrPattern.exec(input);
911
- while (match !== null) {
912
- const name = match[1];
1367
+ let attrPattern = /([A-Za-z_:][\w:.\-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g, match = attrPattern.exec(input);
1368
+ for (; match !== null; ) {
1369
+ let name = match[1];
913
1370
  if (!name) continue;
914
- const value = match[2] ?? match[3] ?? match[4] ?? "";
915
- attrs[name] = value;
916
- match = attrPattern.exec(input);
1371
+ let value = match[2] ?? match[3] ?? match[4] ?? "";
1372
+ attrs[name] = value, match = attrPattern.exec(input);
917
1373
  }
918
1374
  return attrs;
919
1375
  }
920
- function mapAttributesToProps(attrs) {
921
- const props = {};
922
- for (const [key, value] of Object.entries(attrs)) {
923
- if (key === "class") {
924
- props.className = value;
925
- } else if (key === "style") {
926
- props.style = parseStyleAttribute(value);
927
- } else if (key === "tabindex" || key === "tabIndex") {
928
- const normalized = normalizeTabIndex(value);
929
- if (normalized !== void 0) {
930
- props.tabIndex = normalized;
931
- }
932
- } else {
933
- props[key] = value;
934
- }
1376
+ var BOOLEAN_HTML_PROPS = {
1377
+ allowFullScreen: !0,
1378
+ async: !0,
1379
+ autoFocus: !0,
1380
+ autoPlay: !0,
1381
+ checked: !0,
1382
+ controls: !0,
1383
+ default: !0,
1384
+ defer: !0,
1385
+ disabled: !0,
1386
+ formNoValidate: !0,
1387
+ hidden: !0,
1388
+ inert: !0,
1389
+ loop: !0,
1390
+ multiple: !0,
1391
+ muted: !0,
1392
+ noModule: !0,
1393
+ noValidate: !0,
1394
+ open: !0,
1395
+ playsInline: !0,
1396
+ readOnly: !0,
1397
+ required: !0,
1398
+ reversed: !0,
1399
+ selected: !0,
1400
+ itemScope: !0
1401
+ };
1402
+ function mapAttributesToProps(attrs, urlTransform) {
1403
+ let props = {}, transform = urlTransform ?? defaultUrlTransform;
1404
+ for (let [key, value] of Object.entries(attrs)) {
1405
+ let lower = key.toLowerCase();
1406
+ if (!isForbiddenAttribute(lower))
1407
+ if (key === "class")
1408
+ props.className = value;
1409
+ else if (key === "style")
1410
+ props.style = parseStyleAttribute(value);
1411
+ else if (key === "tabindex" || key === "tabIndex") {
1412
+ let normalized = normalizeTabIndex(value);
1413
+ normalized !== void 0 && (props.tabIndex = normalized);
1414
+ } else if (lower === "href") {
1415
+ let safe = transform(value, "href", { source: "html" });
1416
+ safe != null && (props.href = safe);
1417
+ } else if (lower === "src") {
1418
+ let safe = transform(value, "src", { source: "html" });
1419
+ safe != null && (props.src = safe);
1420
+ } else if (lower === "action") {
1421
+ let safe = transform(value, "href", { source: "html" });
1422
+ safe != null && (props.action = safe);
1423
+ } else if (lower === "formaction") {
1424
+ let safe = transform(value, "href", { source: "html" });
1425
+ safe != null && (props.formAction = safe);
1426
+ } else if (lower === "xlink:href" || lower === "xlinkhref") {
1427
+ let safe = transform(value, "href", { source: "html" });
1428
+ safe != null && (props.xlinkHref = safe);
1429
+ } 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;
935
1430
  }
936
1431
  return props;
937
1432
  }
938
1433
  function parseStyleAttribute(value) {
939
- const style = {};
1434
+ let style = {};
940
1435
  if (!value) return style;
941
- const pairs = value.split(";");
942
- for (const pair of pairs) {
1436
+ let pairs = value.split(";");
1437
+ for (let pair of pairs) {
943
1438
  if (!pair.trim()) continue;
944
- const [property, rawVal] = pair.split(":");
945
- if (!property || rawVal === void 0) continue;
946
- const camelProp = property.trim().replace(/-([a-z])/g, (_, char) => char.toUpperCase());
947
- style[camelProp] = rawVal.trim();
1439
+ let separator = pair.indexOf(":");
1440
+ if (separator <= 0) continue;
1441
+ let property = pair.slice(0, separator).trim(), rawVal = pair.slice(separator + 1).trim();
1442
+ if (!isSafeStyleDeclaration(property, rawVal)) continue;
1443
+ let camelProp = property.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
1444
+ style[camelProp] = rawVal;
948
1445
  }
949
1446
  return style;
950
1447
  }
951
1448
  function normalizeTabIndex(value) {
952
- const numeric = Number(value);
1449
+ let numeric = Number(value);
953
1450
  return Number.isNaN(numeric) ? void 0 : numeric;
954
1451
  }
955
1452
  function decodeHtmlEntities(value) {
@@ -957,76 +1454,50 @@ function decodeHtmlEntities(value) {
957
1454
  }
958
1455
  function extractPlainText(value) {
959
1456
  if (!value) return "";
960
- const withoutTags = value.replace(/<\/?[^>]+>/g, "");
1457
+ let withoutTags = value.replace(/<\/?[^>]+>/g, "");
961
1458
  return decodeHtmlEntities(withoutTags);
962
1459
  }
963
- function renderSanitizedHtmlTree(html, key) {
964
- if (typeof DOMParser === "undefined") {
1460
+ var DEFAULT_LITERAL_TAGS = /* @__PURE__ */ new Set(["code", "pre", "script", "style", "textarea"]);
1461
+ function renderSanitizedHtmlTree(html, key, htmlElements, literalTagContent, parseMarkdown) {
1462
+ if (typeof DOMParser > "u")
965
1463
  return null;
966
- }
967
1464
  try {
968
- const parser = new DOMParser();
969
- const doc = parser.parseFromString(html, "text/html");
970
- const body = doc.body;
971
- const nodes = Array.from(body.childNodes);
972
- if (nodes.length === 0) {
1465
+ let body = new DOMParser().parseFromString(html, "text/html").body, nodes = Array.from(body.childNodes);
1466
+ if (nodes.length === 0)
973
1467
  return null;
974
- }
975
- const baseKey = typeof key === "string" || typeof key === "number" ? String(key) : "inline-html";
976
- const children = nodes.map((node, index) => convertDomNode(node, `${baseKey}-${index}`)).filter((child) => child !== null && child !== void 0);
977
- if (children.length === 0) {
1468
+ 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);
1469
+ if (children.length === 0)
978
1470
  return null;
979
- }
980
1471
  if (children.length === 1) {
981
- const [child] = children;
982
- if (React3.isValidElement(child)) {
983
- if (key !== void 0 && key !== null) {
984
- return React3.cloneElement(child, { key });
985
- }
986
- return child;
987
- }
988
- if (typeof child === "string" || typeof child === "number") {
989
- if (key !== void 0 && key !== null) {
990
- return React3.createElement(React3.Fragment, { key }, child);
991
- }
992
- return React3.createElement(React3.Fragment, {}, child);
993
- }
994
- return React3.createElement(React3.Fragment, { key }, child);
1472
+ let [child] = children;
1473
+ return React3.isValidElement(child) ? key != null ? React3.cloneElement(child, { key }) : child : typeof child == "string" || typeof child == "number" ? key != null ? React3.createElement(React3.Fragment, { key }, child) : React3.createElement(React3.Fragment, {}, child) : React3.createElement(React3.Fragment, { key }, child);
995
1474
  }
996
1475
  return React3.createElement(React3.Fragment, { key }, ...children);
997
1476
  } catch {
998
1477
  return null;
999
1478
  }
1000
1479
  }
1001
- function convertDomNode(node, key) {
1480
+ function convertDomNode(node, key, htmlElements, literalTags, parentIsLiteral, parseMarkdown) {
1002
1481
  if (node.nodeType === Node.TEXT_NODE) {
1003
- return node.textContent ?? "";
1482
+ let rawText = node.textContent ?? "";
1483
+ return parentIsLiteral || !parseMarkdown ? rawText : parseMarkdown(rawText);
1004
1484
  }
1005
- if (node.nodeType !== Node.ELEMENT_NODE) {
1485
+ if (node.nodeType !== Node.ELEMENT_NODE)
1006
1486
  return null;
1007
- }
1008
- const element = node;
1009
- const tagName = element.tagName.toLowerCase();
1010
- const attrs = getElementAttributes(element);
1011
- const props = mapAttributesToProps(attrs);
1487
+ let element = node, tagName = element.tagName.toLowerCase(), attrs = getElementAttributes(element), props = mapAttributesToProps(attrs);
1012
1488
  props.key = key;
1013
- const children = [];
1489
+ let isLiteral = parentIsLiteral || (literalTags ? literalTags.has(tagName) : !1), children = [];
1014
1490
  element.childNodes.forEach((child, index) => {
1015
- const converted = convertDomNode(child, `${key}-${index}`);
1016
- if (converted !== null && converted !== void 0) {
1017
- children.push(converted);
1018
- }
1491
+ let converted = convertDomNode(child, `${key}-${index}`, htmlElements, literalTags, isLiteral, parseMarkdown);
1492
+ converted != null && children.push(converted);
1019
1493
  });
1020
- if (children.length === 0) {
1021
- return React3.createElement(tagName, props);
1022
- }
1023
- return React3.createElement(tagName, props, ...children);
1494
+ let customComponent = htmlElements?.[tagName];
1495
+ return customComponent ? children.length === 0 ? React3.createElement(customComponent, props) : React3.createElement(customComponent, props, ...children) : children.length === 0 ? React3.createElement(tagName, props) : React3.createElement(tagName, props, ...children);
1024
1496
  }
1025
1497
  function getElementAttributes(element) {
1026
- const attrs = {};
1027
- for (const attr of Array.from(element.attributes)) {
1498
+ let attrs = {};
1499
+ for (let attr of Array.from(element.attributes))
1028
1500
  attrs[attr.name] = attr.value;
1029
- }
1030
1501
  return attrs;
1031
1502
  }
1032
1503
  var INLINE_ELEMENTS = /* @__PURE__ */ new Set([
@@ -1036,6 +1507,11 @@ var INLINE_ELEMENTS = /* @__PURE__ */ new Set([
1036
1507
  "bdi",
1037
1508
  "bdo",
1038
1509
  "br",
1510
+ "img",
1511
+ "input",
1512
+ "picture",
1513
+ "del",
1514
+ "ins",
1039
1515
  "cite",
1040
1516
  "code",
1041
1517
  "data",
@@ -1080,67 +1556,404 @@ var INLINE_ELEMENTS = /* @__PURE__ */ new Set([
1080
1556
  "mtd"
1081
1557
  ]);
1082
1558
 
1083
- // src/components/link-safety-modal.tsx
1084
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1085
- var DefaultLinkSafetyModal = ({ url, isOpen, isChecking, onClose, onConfirm, onCopy }) => {
1086
- if (!isOpen) {
1087
- return null;
1559
+ // src/components/owned-html.tsx
1560
+ import React4 from "react";
1561
+ import { defaultUrlTransform as defaultUrlTransform2 } from "@stream-mdx/core";
1562
+ function renderOwnedHtmlTree(tree, context) {
1563
+ return renderHtmlOwnershipTree(
1564
+ tree,
1565
+ context.elements,
1566
+ context.renderBlock,
1567
+ context.renderInline,
1568
+ (node, children, parentTagName, key) => {
1569
+ if (node.kind === "strong" || node.kind === "em" || node.kind === "strike" || node.kind === "link") {
1570
+ let component = context.inlineComponents[node.kind], renderElement = () => {
1571
+ let direct;
1572
+ if (node.kind === "link") {
1573
+ if (node.autolink && context.isAutolinkProtocolDisabled(node.href)) return children;
1574
+ let { href, ...linkProps } = node, safeHref = (context.urlTransform ?? defaultUrlTransform2)(href ?? "", "href", { source: "markdown" });
1575
+ direct = component ? React4.createElement(component, {
1576
+ ...linkProps,
1577
+ key,
1578
+ ...safeHref != null ? { href: safeHref } : {},
1579
+ children
1580
+ }) : React4.createElement("a", { key, href: safeHref ?? void 0 }, children);
1581
+ } else {
1582
+ let tag2 = node.kind === "strike" ? "del" : node.kind;
1583
+ direct = component ? React4.createElement(component, { ...node, key, children }) : React4.createElement(tag2, { key }, children);
1584
+ }
1585
+ return context.renderInlinePresentation ? context.renderInlinePresentation(node, direct, key) : direct;
1586
+ };
1587
+ if (!context.filterElement) return renderElement();
1588
+ let tag = node.kind === "strike" ? "del" : node.kind === "link" ? "a" : node.kind, properties = node.kind === "link" ? { href: context.urlTransform?.(node.href ?? "", "href", { source: "markdown" }) ?? node.href, title: node.title } : {};
1589
+ return context.filterElement(
1590
+ { tagName: tag, properties },
1591
+ { source: "markdown", parentTagName },
1592
+ renderElement,
1593
+ () => children
1594
+ );
1595
+ }
1596
+ if (node.kind === "plugin") {
1597
+ let component = context.inlineComponents[node.name] ?? context.inlineComponents.plugin, direct = component ? React4.createElement(component, { ...node.attrs, key, name: node.name, attrs: node.attrs, raw: node.raw, children }) : node.raw;
1598
+ return context.renderInlinePresentation ? context.renderInlinePresentation(node, direct, key, children) : direct;
1599
+ }
1600
+ return context.renderInline([node], parentTagName);
1601
+ },
1602
+ context.renderParagraph,
1603
+ context.urlTransform,
1604
+ context.filterElement,
1605
+ context.parentTagName,
1606
+ context.contentComponents,
1607
+ context.renderHtmlPresentation,
1608
+ void 0,
1609
+ context.renderComponentPresentation
1610
+ );
1611
+ }
1612
+
1613
+ // src/trusted-mdx/native-inline.tsx
1614
+ import React6, { useContext as useContext2 } from "react";
1615
+ import { TrustedMdxNativeChildrenContext } from "@stream-mdx/react/_internal/trusted-mdx-native-children";
1616
+
1617
+ // src/trusted-mdx-boundary.tsx
1618
+ import React5, { createContext as createContext2, useCallback as useCallback3, useEffect as useEffect3, useRef as useRef3, useState as useState4, useSyncExternalStore } from "react";
1619
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1620
+ var EMPTY_PROJECTIONS = Object.freeze({}), EMPTY_COMPONENTS = Object.freeze({}), EMPTY_DOCUMENT_SNAPSHOT = Object.freeze({
1621
+ requestedRevision: 0,
1622
+ projectionRevision: null,
1623
+ renderedRevision: null,
1624
+ status: "idle",
1625
+ error: null,
1626
+ components: EMPTY_COMPONENTS,
1627
+ layout: null,
1628
+ projections: EMPTY_PROJECTIONS
1629
+ }), EMPTY_FEED_SNAPSHOT = Object.freeze({
1630
+ generation: 0,
1631
+ version: 0,
1632
+ generationCause: "initial",
1633
+ pendingSource: null,
1634
+ revision: null
1635
+ });
1636
+ var TrustedMdxProjectionContext = createContext2(null);
1637
+ var TrustedMdxProjectionErrorBoundary = class extends React5.Component {
1638
+ constructor() {
1639
+ super(...arguments);
1640
+ this.state = { error: null };
1088
1641
  }
1089
- return /* @__PURE__ */ jsx2(
1090
- "div",
1091
- {
1092
- className: "stream-mdx-link-modal-backdrop",
1093
- role: "dialog",
1094
- "aria-modal": "true",
1095
- "aria-label": "Link safety confirmation",
1096
- style: {
1097
- position: "fixed",
1098
- inset: 0,
1099
- display: "flex",
1100
- alignItems: "center",
1101
- justifyContent: "center",
1102
- background: "rgba(0, 0, 0, 0.4)",
1103
- zIndex: 9999,
1104
- padding: "24px"
1105
- },
1106
- onClick: onClose,
1107
- children: /* @__PURE__ */ jsxs2(
1108
- "div",
1109
- {
1110
- className: "stream-mdx-link-modal",
1111
- style: {
1112
- width: "min(520px, 100%)",
1113
- borderRadius: 12,
1114
- background: "var(--background, #fff)",
1115
- color: "var(--foreground, #111)",
1116
- border: "1px solid var(--border, rgba(0, 0, 0, 0.1))",
1117
- boxShadow: "0 20px 60px rgba(0, 0, 0, 0.25)",
1118
- padding: 20
1119
- },
1120
- onClick: (event) => event.stopPropagation(),
1121
- children: [
1122
- /* @__PURE__ */ jsx2("div", { style: { fontWeight: 600, marginBottom: 8 }, children: "Open external link?" }),
1123
- /* @__PURE__ */ jsx2("div", { style: { fontSize: 13, opacity: 0.8, wordBreak: "break-all", marginBottom: 16 }, children: url }),
1124
- /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 8, justifyContent: "flex-end" }, children: [
1125
- /* @__PURE__ */ jsx2("button", { type: "button", onClick: onCopy, disabled: isChecking, style: buttonStyle, children: "Copy link" }),
1126
- /* @__PURE__ */ jsx2("button", { type: "button", onClick: onConfirm, disabled: isChecking, style: primaryButtonStyle, children: "Open link" }),
1127
- /* @__PURE__ */ jsx2("button", { type: "button", onClick: onClose, style: buttonStyle, children: "Cancel" })
1128
- ] })
1129
- ]
1130
- }
1131
- )
1642
+ static getDerivedStateFromError(error) {
1643
+ return { error: error instanceof Error ? error : new Error(String(error)) };
1644
+ }
1645
+ componentDidCatch(error) {
1646
+ this.props.revision !== null && this.props.document.reportRenderError(this.props.revision, error);
1647
+ }
1648
+ render() {
1649
+ return this.state.error ? /* @__PURE__ */ jsx5(TrustedMdxProjectionContext.Provider, { value: null, children: this.props.fallback }) : this.props.children;
1650
+ }
1651
+ }, CapturedNativeFrameErrorBoundary = class extends React5.Component {
1652
+ constructor() {
1653
+ super(...arguments);
1654
+ this.state = { error: null };
1655
+ }
1656
+ static getDerivedStateFromError(error) {
1657
+ return { error: error instanceof Error ? error : new Error(String(error)) };
1658
+ }
1659
+ render() {
1660
+ return this.state.error ? /* @__PURE__ */ jsxs5("section", { role: "alert", "data-trusted-mdx-retained-frame-error": "true", children: [
1661
+ /* @__PURE__ */ jsxs5("p", { children: [
1662
+ "Previously committed trusted MDX source generation ",
1663
+ this.props.sourceGeneration,
1664
+ ", document revision ",
1665
+ this.props.documentRevision,
1666
+ "failed to render: ",
1667
+ this.state.error.message
1668
+ ] }),
1669
+ /* @__PURE__ */ jsxs5("details", { children: [
1670
+ /* @__PURE__ */ jsxs5("summary", { children: [
1671
+ "Escaped source for generation ",
1672
+ this.props.sourceGeneration,
1673
+ ", document revision ",
1674
+ this.props.documentRevision
1675
+ ] }),
1676
+ /* @__PURE__ */ jsx5("pre", { children: this.props.source })
1677
+ ] })
1678
+ ] }) : this.props.children;
1679
+ }
1680
+ };
1681
+
1682
+ // src/trusted-mdx-contract.ts
1683
+ function assertTrustedMdxNativeChildContinuations(owners, flowChildren) {
1684
+ if (owners.length !== flowChildren.length)
1685
+ throw new Error("A trusted MDX native child continuation has misaligned owner and source spans.");
1686
+ let continuationOwnerIndex;
1687
+ for (let index = 0; index < owners.length; index++) {
1688
+ let owner = owners[index];
1689
+ if (owner?.kind !== "continuation") {
1690
+ continuationOwnerIndex = void 0;
1691
+ continue;
1132
1692
  }
1133
- );
1693
+ let ownerIndex = owner.ownerIndex, ownerForRun = owners[ownerIndex], previousChild = flowChildren[index - 1], child = flowChildren[index];
1694
+ if (!Number.isSafeInteger(ownerIndex) || ownerIndex < 0 || ownerIndex >= index || (continuationOwnerIndex === void 0 ? ownerIndex !== index - 1 : ownerIndex !== continuationOwnerIndex) || ownerForRun === null || ownerForRun === void 0 || ownerForRun.kind === "continuation" || previousChild?.kind !== "inline" || child?.kind !== "inline" || previousChild.to <= previousChild.from || child.to <= child.from || previousChild.to !== child.from)
1695
+ throw new Error("A trusted MDX native child continuation does not cover one exact contiguous inline run.");
1696
+ continuationOwnerIndex = ownerIndex;
1697
+ }
1698
+ }
1699
+
1700
+ // src/trusted-mdx/native-inline.tsx
1701
+ import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1702
+ function renderTrustedMdxOwner(ownerId, snapshot, source, inline, nativeChildren) {
1703
+ let projection = snapshot.projections[ownerId];
1704
+ if (projection?.kind === "native-child") return;
1705
+ if (projection?.kind === "module") return null;
1706
+ if (projection?.kind === "server-content") {
1707
+ if (!projection.nativeChildren) return projection.content;
1708
+ if (nativeChildren === void 0)
1709
+ throw new Error(`Trusted MDX owner "${ownerId}" has no prepared native children.`);
1710
+ return /* @__PURE__ */ jsx6(TrustedMdxNativeChildrenContext.Provider, { value: nativeChildren, children: projection.content });
1711
+ }
1712
+ if (projection?.kind === "render" && projection.nativeChildren && nativeChildren === void 0)
1713
+ throw new Error(`Trusted MDX owner "${ownerId}" has no prepared native children.`);
1714
+ if (projection?.kind === "render") {
1715
+ let nativeChildrenFactory = projection.rootElementName === void 0 || nativeChildren === void 0 ? void 0 : (fallback) => {
1716
+ let owners = projection.nativeChildOwners, flowChildren = projection.flowChildren;
1717
+ if (!owners || !flowChildren || owners.length !== flowChildren.length || !Array.isArray(nativeChildren) || nativeChildren.length !== owners.length)
1718
+ throw new Error(`Trusted MDX owner "${ownerId}" has misaligned native child owners.`);
1719
+ return assertTrustedMdxNativeChildContinuations(owners, flowChildren), owners.map((owner, index) => {
1720
+ if (owner === null) return fallback(index);
1721
+ if (owner.kind === "continuation") return;
1722
+ let child = nativeChildren[index];
1723
+ if (child === void 0)
1724
+ throw new Error(`Trusted MDX owner "${ownerId}" has no rendered native child "${owner.blockId}".`);
1725
+ return child;
1726
+ });
1727
+ };
1728
+ return /* @__PURE__ */ jsx6(Fragment4, { children: projection.regions.map((Region, index) => {
1729
+ let regionProps = {
1730
+ components: snapshot.components,
1731
+ ...nativeChildrenFactory === void 0 ? {} : { children: nativeChildrenFactory }
1732
+ };
1733
+ return React6.createElement(
1734
+ React6.Fragment,
1735
+ { key: `${ownerId}:${index}` },
1736
+ Region(regionProps)
1737
+ );
1738
+ }) });
1739
+ }
1740
+ let diagnostic = projection?.kind === "unmapped" ? projection.diagnostic : snapshot.error ?? `MDX owner "${ownerId}" has no exact trusted source projection.`, status = projection?.kind === "unmapped" ? "unmapped" : snapshot.status === "error" ? "error" : "pending";
1741
+ return (projection?.kind === "unmapped" && projection.placement !== void 0 ? projection.placement === "inline" : inline) ? /* @__PURE__ */ jsxs6("span", { className: "markdown-mdx-inline", "data-mdx-status": status, "data-mdx-diagnostic": diagnostic, children: [
1742
+ source,
1743
+ /* @__PURE__ */ jsx6("span", { className: "markdown-mdx-diagnostic", role: "note", children: diagnostic })
1744
+ ] }) : /* @__PURE__ */ jsxs6("div", { className: "markdown-mdx-inert", "data-mdx-status": status, "data-mdx-diagnostic": diagnostic, children: [
1745
+ /* @__PURE__ */ jsx6("pre", { children: /* @__PURE__ */ jsx6("code", { children: source }) }),
1746
+ /* @__PURE__ */ jsx6("span", { className: "markdown-mdx-diagnostic", role: "note", children: diagnostic })
1747
+ ] });
1748
+ }
1749
+ function TrustedMdxInlineOwner({ ownerId, source }) {
1750
+ let snapshot = useContext2(TrustedMdxProjectionContext);
1751
+ return snapshot ? /* @__PURE__ */ jsx6(Fragment4, { children: renderTrustedMdxOwner(ownerId, snapshot, source, !0) }) : /* @__PURE__ */ jsx6("span", { className: "markdown-mdx-inline", children: source });
1752
+ }
1753
+
1754
+ // src/renderer/node-presentations.ts
1755
+ import React7 from "react";
1756
+ function renderPresentedNode(presentation, nativeView, context, applyPresentationPropsToCustomElements = !1) {
1757
+ if (!presentation) return nativeView;
1758
+ let prepared = nativeView;
1759
+ return presentation.props && React7.isValidElement(prepared) && (typeof prepared.type == "string" || applyPresentationPropsToCustomElements) && (prepared = React7.cloneElement(
1760
+ prepared,
1761
+ mergeNodePresentationProps(prepared.props, presentation.props)
1762
+ )), "view" in presentation && presentation.view ? React7.createElement(presentation.view, {
1763
+ ...context.viewProps,
1764
+ key: context.key
1765
+ }) : "wrapper" in presentation && presentation.wrapper ? React7.createElement(presentation.wrapper, {
1766
+ key: context.key,
1767
+ children: prepared,
1768
+ metadata: context.metadata,
1769
+ actions: context.actions
1770
+ }) : prepared;
1771
+ }
1772
+ var PRESENTATION_KEY_PATTERNS = [
1773
+ /^[a-z][a-z0-9-]*$/,
1774
+ /^inline:[a-z][a-z0-9-]*$/,
1775
+ /^html:[a-z][a-z0-9-]*(?::[a-z][a-z0-9-]*)?$/,
1776
+ /^component:[A-Za-z][A-Za-z0-9_.-]*$/,
1777
+ /^extension:[A-Za-z][A-Za-z0-9_.-]*$/
1778
+ ], RESERVED_PRESENTATION_PROPS = {
1779
+ className: !0,
1780
+ style: !0,
1781
+ title: !0
1134
1782
  };
1135
- var buttonStyle = {
1783
+ function resolveNodePresentation(presentations, key) {
1784
+ if (!isNodePresentationKey(key))
1785
+ throw new TypeError(`invalid node presentation key: ${key}`);
1786
+ if (!presentations || !Object.prototype.hasOwnProperty.call(presentations, key)) return;
1787
+ let candidate = presentations[key];
1788
+ return validateNodePresentation(key, candidate), candidate;
1789
+ }
1790
+ function mergeNodePresentationProps(nativeProps, decoration) {
1791
+ if (!decoration) return nativeProps;
1792
+ let merged = {};
1793
+ for (let [property, value] of Object.entries(decoration))
1794
+ if (property === "className") {
1795
+ let nativeClass = nativeProps.className;
1796
+ merged.className = typeof nativeClass == "string" && value ? `${nativeClass} ${value}` : value ?? nativeClass;
1797
+ } else property === "style" ? merged.style = { ...nativeProps.style, ...value } : Object.prototype.hasOwnProperty.call(nativeProps, property) || (merged[property] = value);
1798
+ return merged;
1799
+ }
1800
+ function validateNodePresentations(presentations) {
1801
+ if (presentations !== void 0) {
1802
+ if (presentations === null || typeof presentations != "object" || Array.isArray(presentations))
1803
+ throw new TypeError("node presentations must be an object");
1804
+ for (let key of Object.keys(presentations)) {
1805
+ if (!isNodePresentationKey(key))
1806
+ throw new TypeError(`invalid node presentation key: ${key}`);
1807
+ validateNodePresentation(key, presentations[key]);
1808
+ }
1809
+ }
1810
+ }
1811
+ function isNodePresentationKey(key) {
1812
+ return PRESENTATION_KEY_PATTERNS.some((pattern) => pattern.test(key));
1813
+ }
1814
+ function validateNodePresentation(key, candidate) {
1815
+ if (candidate === null || typeof candidate != "object" || Array.isArray(candidate))
1816
+ throw new TypeError(`node presentation for ${key} must be an object`);
1817
+ let presentation = candidate;
1818
+ if ((key === "table-row" || key === "table-cell") && presentation.view !== void 0)
1819
+ throw new TypeError(
1820
+ `node presentation for ${key}: headless table-part views are not supported; use components.table.view with useTableRows`
1821
+ );
1822
+ if ((key === "table-row" || key === "table-cell") && presentation.slots !== void 0)
1823
+ throw new TypeError(`node presentation for ${key} only supports wrapper and props`);
1824
+ if (key.startsWith("component:") && presentation.view !== void 0)
1825
+ throw new TypeError(`node presentation for ${key}: headless views are not supported for restricted content components`);
1826
+ if (presentation.wrapper !== void 0 && presentation.view !== void 0)
1827
+ throw new TypeError(`node presentation for ${key}: wrapper and view are mutually exclusive`);
1828
+ if (presentation.wrapper !== void 0 && !isComponentType(presentation.wrapper))
1829
+ throw new TypeError(`node presentation for ${key} has an invalid wrapper`);
1830
+ if (presentation.view !== void 0 && !isComponentType(presentation.view))
1831
+ throw new TypeError(`node presentation for ${key} has an invalid view`);
1832
+ presentation.props !== void 0 && validatePresentationProps(key, presentation.props), presentation.slots !== void 0 && validatePresentationSlots(key, presentation.slots);
1833
+ for (let property of Object.keys(presentation))
1834
+ if (property !== "props" && property !== "wrapper" && property !== "view" && property !== "slots")
1835
+ throw new TypeError(`node presentation for ${key} has an unknown field: ${property}`);
1836
+ }
1837
+ function isComponentType(value) {
1838
+ return typeof value == "function" || typeof value == "object" && value !== null;
1839
+ }
1840
+ function validatePresentationProps(key, candidate) {
1841
+ if (candidate === null || typeof candidate != "object" || Array.isArray(candidate))
1842
+ throw new TypeError(`node presentation props for ${key} must be an object`);
1843
+ let props = candidate;
1844
+ for (let [property, value] of Object.entries(props)) {
1845
+ let isDataOrAria = /^(data|aria)-[a-z][a-z0-9_.:-]*$/.test(property);
1846
+ if (RESERVED_PRESENTATION_PROPS[property] !== !0 && !isDataOrAria)
1847
+ throw new TypeError(`presentation prop is not allowed: ${property}`);
1848
+ if (property === "style" && (value === null || typeof value != "object" || Array.isArray(value)))
1849
+ throw new TypeError(`presentation style for ${key} must be an object`);
1850
+ }
1851
+ }
1852
+ function validatePresentationSlots(key, candidate) {
1853
+ if (candidate === null || typeof candidate != "object" || Array.isArray(candidate))
1854
+ throw new TypeError(`node presentation slots for ${key} must be an object`);
1855
+ for (let slot of Object.keys(candidate))
1856
+ if (key !== "code" && key !== "table" || slot !== "actions")
1857
+ throw new TypeError(`presentation slot is not supported for ${key}: ${slot}`);
1858
+ }
1859
+
1860
+ // src/renderer/virtualized-table.ts
1861
+ import { useCallback as useCallback4, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef4, useState as useState5 } from "react";
1862
+ import { flushSync } from "react-dom";
1863
+ var DEFAULT_TABLE_VIRTUALIZATION_CONFIG = Object.freeze({
1864
+ enabled: !1,
1865
+ minRows: 40,
1866
+ virtualizeThreshold: 40,
1867
+ estimatedRowHeight: 40,
1868
+ overscan: 8,
1869
+ maxHeight: "600px"
1870
+ });
1871
+ function resolveTableVirtualizationConfig(options) {
1872
+ if (options === !0) return { ...DEFAULT_TABLE_VIRTUALIZATION_CONFIG, enabled: !0 };
1873
+ if (!options) return DEFAULT_TABLE_VIRTUALIZATION_CONFIG;
1874
+ let threshold = options.minRows ?? options.virtualizeThreshold ?? 40, minRows = Number.isFinite(threshold) ? Math.max(1, Math.floor(threshold)) : 40, buffer = options.overscan ?? 8, overscan = Number.isFinite(buffer) ? Math.min(50, Math.max(1, Math.floor(buffer))) : 8, estimate = options.estimatedRowHeight ?? 40;
1875
+ return {
1876
+ enabled: options.enabled ?? !0,
1877
+ minRows,
1878
+ virtualizeThreshold: minRows,
1879
+ estimatedRowHeight: Number.isFinite(estimate) && estimate > 0 ? estimate : 40,
1880
+ overscan,
1881
+ maxHeight: options.maxHeight ?? "600px"
1882
+ };
1883
+ }
1884
+
1885
+ // src/renderer/virtualized-code.tsx
1886
+ import { useCallback as useCallback5, useEffect as useEffect5, useMemo as useMemo3, useRef as useRef5, useState as useState6 } from "react";
1887
+ import { flushSync as flushSync2 } from "react-dom";
1888
+ var DEFAULT_VIRTUALIZED_CODE_CONFIG = {
1889
+ enabled: !0,
1890
+ windowSize: 100,
1891
+ bufferSize: 50,
1892
+ virtualizeThreshold: 200,
1893
+ followTail: !1
1894
+ };
1895
+ function resolveVirtualizedCodeConfig(options) {
1896
+ return {
1897
+ ...DEFAULT_VIRTUALIZED_CODE_CONFIG,
1898
+ ...options,
1899
+ followTail: options?.followTail ?? DEFAULT_VIRTUALIZED_CODE_CONFIG.followTail
1900
+ };
1901
+ }
1902
+
1903
+ // src/components/link-safety-modal.tsx
1904
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1905
+ var DefaultLinkSafetyModal = ({ url, isOpen, isChecking, onClose, onConfirm, onCopy }) => isOpen ? /* @__PURE__ */ jsx7(
1906
+ "div",
1907
+ {
1908
+ className: "stream-mdx-link-modal-backdrop",
1909
+ role: "dialog",
1910
+ "aria-modal": "true",
1911
+ "aria-label": "Link safety confirmation",
1912
+ style: {
1913
+ position: "fixed",
1914
+ inset: 0,
1915
+ display: "flex",
1916
+ alignItems: "center",
1917
+ justifyContent: "center",
1918
+ background: "rgba(0, 0, 0, 0.4)",
1919
+ zIndex: 9999,
1920
+ padding: "24px"
1921
+ },
1922
+ onClick: onClose,
1923
+ children: /* @__PURE__ */ jsxs7(
1924
+ "div",
1925
+ {
1926
+ className: "stream-mdx-link-modal",
1927
+ style: {
1928
+ width: "min(520px, 100%)",
1929
+ borderRadius: 12,
1930
+ background: "var(--background, #fff)",
1931
+ color: "var(--foreground, #111)",
1932
+ border: "1px solid var(--border, rgba(0, 0, 0, 0.1))",
1933
+ boxShadow: "0 20px 60px rgba(0, 0, 0, 0.25)",
1934
+ padding: 20
1935
+ },
1936
+ onClick: (event) => event.stopPropagation(),
1937
+ children: [
1938
+ /* @__PURE__ */ jsx7("div", { style: { fontWeight: 600, marginBottom: 8 }, children: "Open external link?" }),
1939
+ /* @__PURE__ */ jsx7("div", { style: { fontSize: 13, opacity: 0.8, wordBreak: "break-all", marginBottom: 16 }, children: url }),
1940
+ /* @__PURE__ */ jsxs7("div", { style: { display: "flex", gap: 8, justifyContent: "flex-end" }, children: [
1941
+ /* @__PURE__ */ jsx7("button", { type: "button", onClick: onCopy, disabled: isChecking, style: buttonStyle, children: "Copy link" }),
1942
+ /* @__PURE__ */ jsx7("button", { type: "button", onClick: onConfirm, disabled: isChecking, style: primaryButtonStyle, children: "Open link" }),
1943
+ /* @__PURE__ */ jsx7("button", { type: "button", onClick: onClose, style: buttonStyle, children: "Cancel" })
1944
+ ] })
1945
+ ]
1946
+ }
1947
+ )
1948
+ }
1949
+ ) : null, buttonStyle = {
1136
1950
  borderRadius: 8,
1137
1951
  border: "1px solid var(--border, rgba(0, 0, 0, 0.1))",
1138
1952
  padding: "6px 12px",
1139
1953
  background: "var(--background, #fff)",
1140
1954
  color: "inherit",
1141
1955
  fontSize: 13
1142
- };
1143
- var primaryButtonStyle = {
1956
+ }, primaryButtonStyle = {
1144
1957
  ...buttonStyle,
1145
1958
  background: "var(--foreground, #111)",
1146
1959
  color: "var(--background, #fff)",
@@ -1148,120 +1961,295 @@ var primaryButtonStyle = {
1148
1961
  };
1149
1962
 
1150
1963
  // src/components/index.ts
1151
- var MdxRuntimeBoundary = class extends React4.Component {
1152
- constructor() {
1153
- super(...arguments);
1154
- this.state = { hasError: false };
1155
- }
1156
- static getDerivedStateFromError() {
1157
- return { hasError: true };
1158
- }
1159
- componentDidCatch(error) {
1160
- this.props.onError(error);
1161
- }
1162
- componentDidUpdate(prevProps) {
1163
- if (prevProps.resetKey !== this.props.resetKey && this.state.hasError) {
1164
- this.setState({ hasError: false });
1165
- }
1166
- }
1167
- render() {
1168
- if (this.state.hasError) {
1169
- return null;
1170
- }
1171
- return this.props.children;
1172
- }
1173
- };
1174
- function renderInlineNodes(nodes, components) {
1964
+ function presentationText(node) {
1965
+ return typeof node == "string" || typeof node == "number" ? String(node) : Array.isArray(node) ? node.map(presentationText).join("") : React8.isValidElement(node) ? presentationText(node.props.children) : "";
1966
+ }
1967
+ function renderInlineNodes(nodes, components, urlTransform, registry, parentTagName, animationContext) {
1175
1968
  return nodes.map((node, index) => {
1176
- const key = `${node.kind}-${index}`;
1969
+ let key = `${node.kind}-${index}`, itemChildContext = animationContext?.animated && !animationContext.isFinalized ? {
1970
+ ...animationContext,
1971
+ nodeKeyPrefix: animationContext.nodeKeyPrefix ? `${animationContext.nodeKeyPrefix}:${key}` : key
1972
+ } : animationContext, presentInline = (nativeView, renderedChildren) => registry ? registry.renderInlinePresentation(node, nativeView, key, itemChildContext, renderedChildren) : nativeView;
1177
1973
  switch (node.kind) {
1178
1974
  case "text": {
1179
- const textComponent = components.text;
1180
- if (textComponent && textComponent !== defaultInlineComponents.text) {
1181
- return React4.createElement(textComponent, { key, text: node.text });
1975
+ let textComponent = components.text;
1976
+ if (textComponent && textComponent !== defaultInlineComponents.text)
1977
+ return presentInline(React8.createElement(textComponent, { key, text: node.text }));
1978
+ if (animationContext?.animated && !animationContext.isFinalized && animationContext.timeline) {
1979
+ let { animated, timeline, nodeKeyPrefix } = animationContext, nodeKey = nodeKeyPrefix ? `${nodeKeyPrefix}:${key}` : key, segments = splitTextSegments(node.text, animated.sep), state = timeline.getNodeState(nodeKey);
1980
+ if (segments.length > state.count) {
1981
+ let newCount = segments.length - state.count, newDelays = timeline.schedule(newCount, animated.stagger);
1982
+ state.delays.push(...newDelays), state.count = segments.length;
1983
+ } else segments.length < state.count && (state.count = segments.length, state.delays.length = segments.length);
1984
+ let animName = animated.animationName, durationStr = animated.durationStr, spans = segments.map((segment, segmentIndex) => {
1985
+ let delay = state.delays[segmentIndex] ?? 0, animStyle = {
1986
+ "--sm-anim-duration": durationStr,
1987
+ "--sm-anim-easing": animated.easing,
1988
+ "--sm-anim-delay": `${delay}ms`
1989
+ };
1990
+ return animName && (animStyle["--sm-anim-name"] = animName, animStyle.animationName = animName), React8.createElement(
1991
+ "span",
1992
+ {
1993
+ key: segmentIndex,
1994
+ className: "stream-mdx-anim",
1995
+ style: animStyle
1996
+ },
1997
+ segment
1998
+ );
1999
+ });
2000
+ return presentInline(React8.createElement(React8.Fragment, { key }, ...spans));
1182
2001
  }
1183
- return React4.createElement(React4.Fragment, { key, children: node.text });
2002
+ return presentInline(React8.createElement(React8.Fragment, { key, children: node.text }));
1184
2003
  }
1185
- case "strong":
1186
- return React4.createElement(components.strong, {
2004
+ case "strong": {
2005
+ if (!registry?.hasElementFilters())
2006
+ return presentInline(React8.createElement(components.strong, {
2007
+ key,
2008
+ children: renderInlineNodes(node.children, components, urlTransform, registry, "strong", itemChildContext)
2009
+ }));
2010
+ let renderChildren = () => renderInlineNodes(node.children, components, urlTransform, registry, "strong", itemChildContext), renderElement = () => presentInline(React8.createElement(components.strong, {
1187
2011
  key,
1188
- children: renderInlineNodes(node.children, components)
1189
- });
1190
- case "em":
1191
- return React4.createElement(components.em, {
2012
+ children: renderChildren()
2013
+ }));
2014
+ return registry.filterElement(
2015
+ { tagName: "strong", properties: { key }, blockType: void 0 },
2016
+ { source: "markdown", parentTagName },
2017
+ renderElement,
2018
+ renderChildren
2019
+ );
2020
+ }
2021
+ case "em": {
2022
+ if (!registry?.hasElementFilters())
2023
+ return presentInline(React8.createElement(components.em, {
2024
+ key,
2025
+ children: renderInlineNodes(node.children, components, urlTransform, registry, "em", itemChildContext)
2026
+ }));
2027
+ let renderChildren = () => renderInlineNodes(node.children, components, urlTransform, registry, "em", itemChildContext), renderElement = () => presentInline(React8.createElement(components.em, {
1192
2028
  key,
1193
- children: renderInlineNodes(node.children, components)
1194
- });
2029
+ children: renderChildren()
2030
+ }));
2031
+ return registry.filterElement(
2032
+ { tagName: "em", properties: { key }, blockType: void 0 },
2033
+ { source: "markdown", parentTagName },
2034
+ renderElement,
2035
+ renderChildren
2036
+ );
2037
+ }
1195
2038
  case "strike": {
1196
- const StrikeComponent = components.strike ?? ((props) => React4.createElement("del", {}, props.children));
1197
- return React4.createElement(StrikeComponent, {
2039
+ let StrikeComponent = components.strike ?? ((props) => React8.createElement("del", {}, props.children));
2040
+ if (!registry?.hasElementFilters())
2041
+ return presentInline(React8.createElement(StrikeComponent, {
2042
+ key,
2043
+ children: renderInlineNodes(node.children, components, urlTransform, registry, "del", itemChildContext)
2044
+ }));
2045
+ let renderChildren = () => renderInlineNodes(node.children, components, urlTransform, registry, "del", itemChildContext), renderElement = () => presentInline(React8.createElement(StrikeComponent, {
1198
2046
  key,
1199
- children: renderInlineNodes(node.children, components)
1200
- });
2047
+ children: renderChildren()
2048
+ }));
2049
+ return registry.filterElement(
2050
+ { tagName: "del", properties: { key }, blockType: void 0 },
2051
+ { source: "markdown", parentTagName },
2052
+ renderElement,
2053
+ renderChildren
2054
+ );
1201
2055
  }
1202
- case "code":
1203
- return React4.createElement(components.code, { key, text: node.text });
1204
- case "link":
1205
- return React4.createElement(
2056
+ case "code": {
2057
+ if (!registry?.hasElementFilters())
2058
+ return presentInline(React8.createElement(components.code, { key, text: node.text }));
2059
+ let renderChildren = () => node.text, renderElement = () => presentInline(React8.createElement(components.code, { key, text: node.text }));
2060
+ return registry.filterElement(
2061
+ { tagName: "code", properties: { key, text: node.text }, blockType: void 0 },
2062
+ { source: "markdown", parentTagName },
2063
+ renderElement,
2064
+ renderChildren
2065
+ );
2066
+ }
2067
+ case "link": {
2068
+ if (node.autolink && registry?.isAutolinkProtocolDisabled(node.href))
2069
+ return renderInlineNodes(node.children, components, urlTransform, registry, parentTagName, itemChildContext);
2070
+ let safeHref = (urlTransform ?? defaultUrlTransform4)(node.href ?? "", "href", { source: "markdown" });
2071
+ if (!registry?.hasElementFilters())
2072
+ return presentInline(React8.createElement(
2073
+ components.link,
2074
+ {
2075
+ key,
2076
+ ...safeHref != null ? { href: safeHref } : {},
2077
+ title: node.title,
2078
+ children: renderInlineNodes(node.children, components, urlTransform, registry, "a", itemChildContext)
2079
+ }
2080
+ ));
2081
+ let renderChildren = () => renderInlineNodes(node.children, components, urlTransform, registry, "a", itemChildContext), renderElement = () => presentInline(React8.createElement(
1206
2082
  components.link,
1207
2083
  {
1208
2084
  key,
1209
- href: node.href,
2085
+ ...safeHref != null ? { href: safeHref } : {},
1210
2086
  title: node.title,
1211
- children: renderInlineNodes(node.children, components)
2087
+ children: renderChildren()
1212
2088
  }
2089
+ ));
2090
+ return registry.filterElement(
2091
+ { tagName: "a", properties: { key, href: safeHref, title: node.title }, blockType: void 0 },
2092
+ { source: "markdown", parentTagName },
2093
+ renderElement,
2094
+ renderChildren
1213
2095
  );
1214
- case "image":
1215
- return React4.createElement(components.image, {
2096
+ }
2097
+ case "image": {
2098
+ let safeSrc = (urlTransform ?? defaultUrlTransform4)(node.src ?? "", "src", { source: "markdown" });
2099
+ if (!registry?.hasElementFilters())
2100
+ return presentInline(React8.createElement(components.image, {
2101
+ key,
2102
+ ...safeSrc != null ? { src: safeSrc } : {},
2103
+ alt: node.alt ?? "",
2104
+ title: node.title
2105
+ }));
2106
+ let renderElement = () => presentInline(React8.createElement(components.image, {
1216
2107
  key,
1217
- src: node.src,
1218
- alt: node.alt,
2108
+ ...safeSrc != null ? { src: safeSrc } : {},
2109
+ alt: node.alt ?? "",
1219
2110
  title: node.title
1220
- });
1221
- case "br":
1222
- return React4.createElement(React4.Fragment, { key }, React4.createElement(components.br, {}));
2111
+ }));
2112
+ return registry.filterElement(
2113
+ { tagName: "img", properties: { key, src: safeSrc, alt: node.alt ?? "", title: node.title }, blockType: void 0 },
2114
+ { source: "markdown", parentTagName },
2115
+ renderElement,
2116
+ void 0
2117
+ );
2118
+ }
2119
+ case "br": {
2120
+ if (!registry?.hasElementFilters())
2121
+ return presentInline(React8.createElement(
2122
+ React8.Fragment,
2123
+ { key },
2124
+ React8.createElement(components.br, {}),
2125
+ `
2126
+ `
2127
+ ));
2128
+ let renderElement = () => presentInline(React8.createElement(
2129
+ React8.Fragment,
2130
+ { key },
2131
+ React8.createElement(components.br, {}),
2132
+ `
2133
+ `
2134
+ ));
2135
+ return registry.filterElement(
2136
+ { tagName: "br", properties: { key }, blockType: void 0 },
2137
+ { source: "markdown", parentTagName },
2138
+ renderElement,
2139
+ void 0
2140
+ );
2141
+ }
2142
+ case "plugin": {
2143
+ let pluginComponent = components[node.name] ?? components.plugin, hasExtensionPresentation = registry?.getNodePresentation(`extension:${node.name}`) !== void 0, pluginChildren = node.children && (pluginComponent || hasExtensionPresentation) ? renderInlineNodes(node.children, components, urlTransform, registry, parentTagName, itemChildContext) : void 0;
2144
+ return pluginComponent ? presentInline(React8.createElement(pluginComponent, {
2145
+ key,
2146
+ ...node.attrs,
2147
+ name: node.name,
2148
+ attrs: node.attrs,
2149
+ children: pluginChildren,
2150
+ raw: node.raw
2151
+ }), pluginChildren) : hasExtensionPresentation ? presentInline(React8.createElement(React8.Fragment, { key }, pluginChildren ?? node.raw), pluginChildren) : presentInline(React8.createElement(React8.Fragment, { key }, node.raw));
2152
+ }
2153
+ case "trusted-mdx-inline":
2154
+ return React8.createElement(TrustedMdxInlineOwner, { key, ownerId: node.ownerId, source: node.raw });
2155
+ case "html": {
2156
+ let children = node.children ? renderInlineNodes(node.children, components, urlTransform, registry, node.tagName?.toLowerCase(), itemChildContext) : void 0, textValue = node.children?.map((child) => child.kind === "text" ? child.text : "").join(""), htmlRenderer = components.html;
2157
+ return htmlRenderer && !registry?.isDefaultHtmlInlineRenderer(htmlRenderer) ? renderHtmlInlineNode(
2158
+ node,
2159
+ children,
2160
+ void 0,
2161
+ key,
2162
+ textValue,
2163
+ urlTransform,
2164
+ registry?.hasElementFilters() ? (el, ctx, renderElement, renderChildren) => registry.filterElement(el, ctx, renderElement, renderChildren) : void 0,
2165
+ parentTagName,
2166
+ registry ? (tagName, properties, nativeView, htmlChildren, presentationKey) => registry.renderHtmlPresentation(
2167
+ tagName,
2168
+ properties,
2169
+ nativeView,
2170
+ htmlChildren,
2171
+ presentationKey,
2172
+ animationContext?.nodeKeyPrefix,
2173
+ animationContext?.isFinalized,
2174
+ animationContext?.sourceGuard
2175
+ ) : void 0,
2176
+ (tagName, properties, htmlChildren, presentationKey) => React8.createElement(htmlRenderer, {
2177
+ ...node,
2178
+ key: presentationKey,
2179
+ children: htmlChildren,
2180
+ textValue,
2181
+ properties
2182
+ })
2183
+ ) : renderHtmlInlineNode(
2184
+ node,
2185
+ children,
2186
+ void 0,
2187
+ key,
2188
+ textValue,
2189
+ urlTransform,
2190
+ registry?.hasElementFilters() ? (el, ctx, renderElement, renderChildren) => registry.filterElement(el, ctx, renderElement, renderChildren) : void 0,
2191
+ parentTagName,
2192
+ registry ? (tagName, properties, nativeView, htmlChildren, presentationKey) => registry.renderHtmlPresentation(
2193
+ tagName,
2194
+ properties,
2195
+ nativeView,
2196
+ htmlChildren,
2197
+ presentationKey,
2198
+ animationContext?.nodeKeyPrefix,
2199
+ animationContext?.isFinalized,
2200
+ animationContext?.sourceGuard
2201
+ ) : void 0
2202
+ );
2203
+ }
1223
2204
  default: {
1224
- const component = components[node.kind];
2205
+ let component = components[node.kind];
1225
2206
  if (component) {
1226
- return React4.createElement(component, { key, ...node });
2207
+ let engine = node.kind === "math-inline" || node.kind === "math-display" ? registry?.getMathEngine() : void 0;
2208
+ return presentInline(React8.createElement(component, { key, ...node, ...engine ? { engine } : {} }));
1227
2209
  }
1228
- return null;
2210
+ return presentInline(React8.createElement(React8.Fragment, { key }, null));
1229
2211
  }
1230
2212
  }
1231
2213
  });
1232
2214
  }
1233
2215
  var defaultInlineComponents = {
1234
- text: ({ text }) => React4.createElement(React4.Fragment, {}, text),
1235
- strong: ({ children }) => React4.createElement("strong", {}, children),
1236
- em: ({ children }) => React4.createElement("em", {}, children),
1237
- strike: ({ children }) => React4.createElement("del", {}, children),
1238
- code: ({ text }) => React4.createElement(
2216
+ text: ({ text }) => React8.createElement(React8.Fragment, {}, text),
2217
+ strong: ({ children }) => React8.createElement("strong", {}, children),
2218
+ em: ({ children }) => React8.createElement("em", {}, children),
2219
+ strike: ({ children }) => React8.createElement("del", {}, children),
2220
+ code: ({ text }) => React8.createElement(
1239
2221
  "code",
1240
2222
  {
1241
2223
  className: "inline-code"
1242
2224
  },
1243
2225
  text
1244
2226
  ),
1245
- link: ({ href, title, children }) => React4.createElement(
1246
- "a",
1247
- {
1248
- href,
2227
+ link: ({ href, title, children }) => {
2228
+ let safeHref = href == null ? void 0 : defaultUrlTransform4(href, "href", { source: "markdown" });
2229
+ return React8.createElement(
2230
+ "a",
2231
+ {
2232
+ ...safeHref != null ? { href: safeHref } : {},
2233
+ title,
2234
+ className: "markdown-link",
2235
+ target: safeHref?.startsWith("http") ? "_blank" : void 0,
2236
+ rel: safeHref?.startsWith("http") ? "noopener noreferrer" : void 0
2237
+ },
2238
+ children
2239
+ );
2240
+ },
2241
+ image: ({ src, alt, title }) => {
2242
+ let safeSrc = defaultUrlTransform4(src ?? "", "src", { source: "markdown" });
2243
+ return React8.createElement("img", {
2244
+ ...safeSrc != null ? { src: safeSrc } : {},
2245
+ alt,
1249
2246
  title,
1250
- className: "markdown-link",
1251
- target: href?.startsWith("http") ? "_blank" : void 0,
1252
- rel: href?.startsWith("http") ? "noopener noreferrer" : void 0
1253
- },
1254
- children
1255
- ),
1256
- image: ({ src, alt, title }) => React4.createElement("img", {
1257
- src,
1258
- alt,
1259
- title,
1260
- className: "markdown-image"
1261
- }),
1262
- br: () => React4.createElement("br"),
2247
+ className: "markdown-image"
2248
+ });
2249
+ },
2250
+ br: () => React8.createElement("br"),
1263
2251
  // Custom extensible components
1264
- mention: ({ handle }) => React4.createElement(
2252
+ mention: ({ handle }) => React8.createElement(
1265
2253
  "span",
1266
2254
  {
1267
2255
  className: "mention",
@@ -1269,7 +2257,7 @@ var defaultInlineComponents = {
1269
2257
  },
1270
2258
  `@${handle}`
1271
2259
  ),
1272
- citation: ({ id }) => React4.createElement(
2260
+ citation: ({ id }) => React8.createElement(
1273
2261
  "span",
1274
2262
  {
1275
2263
  className: "citation",
@@ -1277,111 +2265,135 @@ var defaultInlineComponents = {
1277
2265
  },
1278
2266
  `[${id}]`
1279
2267
  ),
1280
- "math-inline": ({ tex }) => React4.createElement(
1281
- "span",
1282
- {
1283
- className: "math-inline",
1284
- "data-tex": tex
1285
- },
1286
- `$${tex}$`
1287
- ),
1288
- "math-display": ({ tex }) => React4.createElement(
1289
- "div",
1290
- {
1291
- className: "math-display markdown-math-display",
1292
- "data-tex": tex,
1293
- style: { overflowX: "auto" }
1294
- },
1295
- React4.createElement("span", { className: "math-display-content" }, `$$${tex}$$`)
1296
- ),
2268
+ "math-inline": ({ tex, engine }) => React8.createElement(KaTeXInlineMath, { tex, engine }),
2269
+ "math-display": ({ tex, engine }) => React8.createElement(KaTeXBlockMath, { tex, engine }),
1297
2270
  // Footnote inline reference (superscript anchor)
1298
- "footnote-ref": ({ label, number }) => {
1299
- const n = number ?? "?";
1300
- const href = number ? `#fn:${n}` : void 0;
1301
- const id = number ? `fnref:${n}` : void 0;
1302
- return React4.createElement(
2271
+ "footnote-ref": ({ label, number, occurrence, defined }) => {
2272
+ if (!number || defined === !1) return React8.createElement(React8.Fragment, null, `[^${label}]`);
2273
+ let n = number, href = `#fn:${n}`, id = `fnref:${n}${occurrence && occurrence > 1 ? `:${occurrence}` : ""}`;
2274
+ return React8.createElement(
1303
2275
  "sup",
1304
2276
  { className: "footnote-ref" },
1305
- React4.createElement("a", { href, id, "data-label": label, style: { color: "var(--foreground)", textDecoration: "underline" } }, String(n))
2277
+ React8.createElement("a", { href, id, "data-label": label, style: { color: "var(--foreground)", textDecoration: "underline" } }, String(n))
1306
2278
  );
1307
2279
  }
1308
2280
  };
2281
+ function blockPresentationProps(props) {
2282
+ let decoration = {};
2283
+ for (let [property, value] of Object.entries(props))
2284
+ (property === "className" || property === "style" || property === "title" || property.startsWith("data-") || property.startsWith("aria-")) && (decoration[property] = value);
2285
+ return Object.keys(decoration).length > 0 ? decoration : void 0;
2286
+ }
2287
+ function applyBlockPresentationProps(nativeView, decoration) {
2288
+ if (!decoration) return nativeView;
2289
+ if (Array.isArray(nativeView))
2290
+ return nativeView.map((child) => applyBlockPresentationProps(child, decoration));
2291
+ if (!React8.isValidElement(nativeView)) return nativeView;
2292
+ if (nativeView.type === React8.Fragment) {
2293
+ let children = React8.Children.map(
2294
+ nativeView.props.children,
2295
+ (child) => applyBlockPresentationProps(child, decoration)
2296
+ );
2297
+ return React8.cloneElement(nativeView, void 0, children);
2298
+ }
2299
+ return React8.cloneElement(
2300
+ nativeView,
2301
+ mergeNodePresentationProps(nativeView.props, decoration)
2302
+ );
2303
+ }
1309
2304
  var defaultBlockComponents = {
1310
- paragraph: ({ inlines, raw, meta, children }) => {
1311
- if (children !== void 0) {
1312
- return React4.createElement(
1313
- "p",
1314
- {
1315
- className: "markdown-paragraph"
1316
- },
1317
- children
2305
+ paragraph: (props) => {
2306
+ let { inlines, raw, meta, children } = props, decoration = blockPresentationProps(props);
2307
+ if (children !== void 0)
2308
+ return applyBlockPresentationProps(
2309
+ React8.createElement("p", { className: "markdown-paragraph" }, children),
2310
+ decoration
1318
2311
  );
1319
- }
1320
- const segments = Array.isArray(meta?.mixedSegments) ? meta?.mixedSegments : void 0;
2312
+ let segments = Array.isArray(meta?.mixedSegments) ? meta?.mixedSegments : void 0;
1321
2313
  if (segments && segments.length > 0) {
1322
- const structured = renderParagraphMixedSegments(segments, defaultInlineComponents, DEFAULT_INLINE_HTML_RENDERERS);
1323
- if (structured.length === 1) {
1324
- return structured[0];
1325
- }
1326
- return React4.createElement(React4.Fragment, {}, ...structured);
2314
+ let structured = renderParagraphMixedSegments(segments, defaultInlineComponents, DEFAULT_INLINE_HTML_RENDERERS);
2315
+ return structured.length === 1 ? applyBlockPresentationProps(structured[0], decoration) : applyBlockPresentationProps(
2316
+ React8.createElement(React8.Fragment, {}, ...structured),
2317
+ decoration
2318
+ );
1327
2319
  }
1328
- const filteredInlines = inlines && raw && inlines.length > 0 ? inlines.filter((node) => !(node.kind === "text" && node.text === raw)) : inlines ?? [];
1329
- const effectiveInlines = filteredInlines.length > 0 ? filteredInlines : raw ? [
2320
+ let filteredInlines = inlines && raw && inlines.length > 0 ? inlines.filter((node) => !(node.kind === "text" && node.text === raw)) : inlines ?? [], effectiveInlines = filteredInlines.length > 0 ? filteredInlines : raw ? [
1330
2321
  {
1331
2322
  kind: "text",
1332
2323
  text: raw
1333
2324
  }
1334
2325
  ] : [];
1335
- return React4.createElement(
1336
- "p",
1337
- {
1338
- className: "markdown-paragraph"
1339
- },
1340
- effectiveInlines.length > 0 ? renderInlineNodes(effectiveInlines, defaultInlineComponents) : raw ?? ""
2326
+ return applyBlockPresentationProps(
2327
+ React8.createElement(
2328
+ "p",
2329
+ { className: "markdown-paragraph" },
2330
+ effectiveInlines.length > 0 ? renderInlineNodes(effectiveInlines, defaultInlineComponents) : raw ?? ""
2331
+ ),
2332
+ decoration
1341
2333
  );
1342
2334
  },
1343
- heading: ({ level, inlines, text, meta }) => {
1344
- const tag = `h${level}`;
1345
- const onlyPlainText = Array.isArray(inlines) && inlines.length > 0 && inlines.every((node) => node.kind === "text");
1346
- const children = onlyPlainText ? inlines.map((node) => node.kind === "text" ? node.text : "").join("") : renderInlineNodes(inlines, defaultInlineComponents);
1347
- const headingId = typeof meta?.headingId === "string" && meta.headingId.length > 0 ? meta.headingId : void 0;
1348
- return React4.createElement(
1349
- tag,
1350
- {
1351
- className: `markdown-heading markdown-h${level}`,
1352
- ...text ? { "data-heading-text": text } : {},
1353
- ...headingId ? { id: headingId, "data-heading-id": headingId } : {}
1354
- },
1355
- children
2335
+ heading: (props) => {
2336
+ let { level, inlines, text, meta, children } = props, decoration = blockPresentationProps(props), tag = `h${level}`, onlyPlainText = Array.isArray(inlines) && inlines.length > 0 && inlines.every((node) => node.kind === "text"), content = children !== void 0 ? children : onlyPlainText ? inlines.map((node) => node.kind === "text" ? node.text : "").join("") : renderInlineNodes(inlines, defaultInlineComponents), headingId = typeof meta?.headingId == "string" && meta.headingId.length > 0 ? meta.headingId : void 0;
2337
+ return applyBlockPresentationProps(
2338
+ React8.createElement(
2339
+ tag,
2340
+ {
2341
+ className: `markdown-heading markdown-h${level}`,
2342
+ ...text ? { "data-heading-text": text } : {},
2343
+ ...headingId ? { id: headingId, "data-heading-id": headingId } : {}
2344
+ },
2345
+ content
2346
+ ),
2347
+ decoration
1356
2348
  );
1357
2349
  },
1358
- code: ({ html, meta, lines, lang, preAttrs, codeAttrs }) => {
1359
- const language = typeof lang === "string" ? lang : typeof meta?.lang === "string" ? String(meta.lang) : "text";
1360
- if (html) {
1361
- return React4.createElement("div", {
1362
- className: `markdown-code-block language-${language || "text"}`,
2350
+ code: ({ html, meta, lines, children, lang, preAttrs, codeAttrs }) => {
2351
+ let language = (typeof lang == "string" ? lang : typeof meta?.lang == "string" ? String(meta.lang) : "").trim();
2352
+ if (children !== void 0) {
2353
+ let preAttributes = attrsToProps(preAttrs), codeAttributes = attrsToProps(codeAttrs), preClassName = [preAttributes.className, "markdown-code-block", language ? `language-${language}` : ""].filter(Boolean).join(" "), codeClassName = [codeAttributes.className, language ? `language-${language}` : ""].filter(Boolean).join(" ");
2354
+ return React8.createElement(
2355
+ "div",
2356
+ { className: language ? `markdown-code-block language-${language}` : "markdown-code-block" },
2357
+ React8.createElement(
2358
+ "pre",
2359
+ {
2360
+ ...preAttributes,
2361
+ className: preClassName
2362
+ },
2363
+ React8.createElement(
2364
+ "code",
2365
+ {
2366
+ ...codeAttributes,
2367
+ ...codeClassName ? { className: codeClassName } : {}
2368
+ },
2369
+ children
2370
+ )
2371
+ )
2372
+ );
2373
+ }
2374
+ if (html)
2375
+ return React8.createElement("div", {
2376
+ className: language ? `markdown-code-block language-${language}` : "markdown-code-block",
1363
2377
  /* biome-ignore lint/security/noDangerouslySetInnerHtml: highlighted HTML is generated by our sanitizer */
1364
2378
  dangerouslySetInnerHTML: { __html: html }
1365
2379
  });
1366
- }
1367
- const code = meta?.code || "";
2380
+ let code = meta?.code || "";
1368
2381
  if (lines && lines.length > 0) {
1369
- const preAttributes = attrsToProps(preAttrs);
1370
- const codeAttributes = attrsToProps(codeAttrs);
1371
- return React4.createElement(
2382
+ let preAttributes = attrsToProps(preAttrs), codeAttributes = attrsToProps(codeAttrs), preClassName = [preAttributes.className, "markdown-code-block", language ? `language-${language}` : ""].filter(Boolean).join(" "), codeClassName = [codeAttributes.className, language ? `language-${language}` : ""].filter(Boolean).join(" ");
2383
+ return React8.createElement(
1372
2384
  "pre",
1373
2385
  {
1374
2386
  ...preAttributes,
1375
- className: preAttributes.className ? `${preAttributes.className} markdown-code-block language-${language || "text"}` : `markdown-code-block language-${language || "text"}`
2387
+ className: preClassName
1376
2388
  },
1377
- React4.createElement(
2389
+ React8.createElement(
1378
2390
  "code",
1379
2391
  {
1380
2392
  ...codeAttributes,
1381
- className: codeAttributes.className ? `${codeAttributes.className} language-${language || "text"}` : `language-${language || "text"}`
2393
+ ...codeClassName ? { className: codeClassName } : {}
1382
2394
  },
1383
2395
  lines.map(
1384
- (line) => React4.createElement("span", {
2396
+ (line) => React8.createElement("span", {
1385
2397
  key: line.id,
1386
2398
  className: "line",
1387
2399
  /* biome-ignore lint/security/noDangerouslySetInnerHtml: line HTML is sanitized server-side */
@@ -1391,29 +2403,26 @@ var defaultBlockComponents = {
1391
2403
  )
1392
2404
  );
1393
2405
  }
1394
- return React4.createElement("pre", {
1395
- className: `markdown-code-block language-${language || "text"}`,
2406
+ return React8.createElement("pre", {
2407
+ className: language ? `markdown-code-block language-${language}` : "markdown-code-block",
1396
2408
  children: code
1397
2409
  });
1398
2410
  },
1399
- blockquote: ({ inlines, renderedContent }) => React4.createElement(
2411
+ blockquote: ({ inlines, renderedContent }) => React8.createElement(
1400
2412
  "blockquote",
1401
2413
  {
1402
2414
  className: "markdown-blockquote"
1403
2415
  },
1404
2416
  renderedContent ?? renderInlineNodes(inlines, defaultInlineComponents)
1405
2417
  ),
1406
- hr: (props) => React4.createElement("hr", props),
2418
+ hr: (props) => React8.createElement("hr", props),
1407
2419
  list: ({ ordered, items }) => {
1408
- if (items.length === 0) {
2420
+ if (items.length === 0)
1409
2421
  return null;
1410
- }
1411
- const tag = ordered ? "ol" : "ul";
1412
- const listStyle = ordered ? {
1413
- ["--list-indent"]: `calc(2.5rem + ${String(items.length).length}ch)`
1414
- } : void 0;
1415
- const listItems = items.map(
1416
- (item, index) => React4.createElement(
2422
+ let tag = ordered ? "ol" : "ul", listStyle = ordered ? {
2423
+ "--list-indent": `calc(2.5rem + ${String(items.length).length}ch)`
2424
+ } : void 0, listItems = items.map(
2425
+ (item, index) => React8.createElement(
1417
2426
  "li",
1418
2427
  {
1419
2428
  key: index,
@@ -1424,7 +2433,7 @@ var defaultBlockComponents = {
1424
2433
  renderInlineNodes(item, defaultInlineComponents)
1425
2434
  )
1426
2435
  );
1427
- return React4.createElement(
2436
+ return React8.createElement(
1428
2437
  tag,
1429
2438
  {
1430
2439
  className: `markdown-list ${ordered ? "ordered" : "unordered"}`,
@@ -1433,214 +2442,69 @@ var defaultBlockComponents = {
1433
2442
  listItems
1434
2443
  );
1435
2444
  },
1436
- html: ({ __trustedHtml, elements }) => {
1437
- const raw = typeof __trustedHtml === "string" ? __trustedHtml : __trustedHtml.toString();
1438
- const htmlString = typeof window === "undefined" ? raw : sanitizeHTML(raw);
1439
- if (typeof window !== "undefined" && elements) {
1440
- const content = mapHtmlToReact(htmlString, elements);
1441
- return React4.createElement("div", { className: "markdown-html" }, content);
2445
+ html: ({ __trustedHtml, elements, isSanitized, literalTagContent, children }) => {
2446
+ if (children !== void 0)
2447
+ return React8.createElement("div", { className: "markdown-html" }, children);
2448
+ let raw = typeof __trustedHtml == "string" ? __trustedHtml : __trustedHtml.toString(), htmlString = isSanitized || typeof window > "u" ? raw : sanitizeHTML(raw);
2449
+ if (typeof window < "u" && elements) {
2450
+ let content = mapHtmlToReact(htmlString, elements, literalTagContent);
2451
+ return React8.createElement("div", { className: "markdown-html" }, content);
1442
2452
  }
1443
- return React4.createElement("div", {
2453
+ return React8.createElement("div", {
1444
2454
  className: "markdown-html",
1445
2455
  /* biome-ignore lint/security/noDangerouslySetInnerHtml: htmlString is sanitized before injection */
1446
2456
  dangerouslySetInnerHTML: { __html: htmlString }
1447
2457
  });
1448
2458
  },
1449
- mdx: ({ compiledRef, compiledModule, status, errorMessage }) => {
1450
- const [Comp, setComp] = React4.useState(null);
1451
- const [internalError, setInternalError] = React4.useState(null);
1452
- const [renderError, setRenderError] = React4.useState(null);
1453
- const [retryKey, setRetryKey] = React4.useState(0);
1454
- const hydrationContext = React4.useContext(MdxHydrationContext);
1455
- const hydrationController = hydrationContext?.controller ?? null;
1456
- const hydrationOptions = hydrationContext?.options;
1457
- const containerRef = React4.useRef(null);
1458
- const deferHydration = hydrationOptions?.strategy === "visible";
1459
- const shouldHydrate = useDeferredRender(
1460
- containerRef,
1461
- deferHydration ? {
1462
- enabled: true,
1463
- rootMargin: hydrationOptions?.rootMargin,
1464
- idleTimeoutMs: hydrationOptions?.idleTimeoutMs,
1465
- debounceMs: hydrationOptions?.debounceMs
1466
- } : { enabled: false }
1467
- );
1468
- const resolvedId = compiledModule?.id ?? (compiledRef?.id && compiledRef.id !== "pending" ? compiledRef.id : void 0);
1469
- const handleRetry = React4.useCallback(() => {
1470
- setInternalError(null);
1471
- setRenderError(null);
1472
- setComp(null);
1473
- setRetryKey((prev) => prev + 1);
1474
- }, []);
1475
- const handleRuntimeError = React4.useCallback(
1476
- (error) => {
1477
- const message2 = error instanceof Error ? error.message : String(error);
1478
- setRenderError(message2);
1479
- markMdxHydrationError(resolvedId ?? compiledRef?.id);
1480
- },
1481
- [resolvedId, compiledRef?.id]
1482
- );
1483
- const effectiveStatus = status ? status : resolvedId ? "compiled" : "pending";
1484
- const failureMessage = errorMessage ?? internalError ?? renderError ?? null;
1485
- const moduleDependencies = compiledModule?.dependencies;
1486
- React4.useEffect(() => {
1487
- if (!shouldHydrate) {
1488
- return;
1489
- }
1490
- if (status === "error") {
1491
- markMdxHydrationError(resolvedId ?? compiledRef?.id);
1492
- return;
1493
- }
1494
- let cancelled = false;
1495
- async function ensure() {
1496
- let permit = null;
1497
- try {
1498
- if (status === "error" || !resolvedId || resolvedId === "pending") {
1499
- if (!cancelled) {
1500
- setComp(null);
1501
- setInternalError(null);
1502
- }
1503
- return;
1504
- }
1505
- if (hydrationController) {
1506
- permit = await hydrationController.acquire();
1507
- if (cancelled) {
1508
- permit.release();
1509
- return;
1510
- }
1511
- }
1512
- setInternalError(null);
1513
- setRenderError(null);
1514
- markMdxHydrationStart(resolvedId);
1515
- const { getMDXComponentFactory: getMDXComponentFactory2, registerInlineMdxModule: registerInlineMdxModule2 } = await loadMdxRuntime();
1516
- if (compiledModule?.code) {
1517
- registerInlineMdxModule2({
1518
- id: compiledModule.id,
1519
- code: compiledModule.code,
1520
- dependencies: moduleDependencies ?? []
1521
- });
1522
- }
1523
- const factory = getMDXComponentFactory2();
1524
- const C = await factory.createComponent({ id: resolvedId });
1525
- if (!cancelled) {
1526
- setComp(() => C);
1527
- setInternalError(null);
1528
- markMdxHydrated(resolvedId);
1529
- }
1530
- } catch (error) {
1531
- if (!cancelled) {
1532
- const message2 = error instanceof Error ? error.message : String(error);
1533
- setInternalError(message2);
1534
- markMdxHydrationError(resolvedId);
1535
- }
1536
- } finally {
1537
- permit?.release();
1538
- }
1539
- }
1540
- ensure();
1541
- return () => {
1542
- cancelled = true;
1543
- };
1544
- }, [compiledModule?.id, compiledModule?.code, moduleDependencies, resolvedId, status, shouldHydrate, retryKey]);
1545
- const compileMode = compiledModule?.source === "worker" || compiledRef?.id?.startsWith("worker:") ? "worker" : "server";
1546
- const pendingId = resolvedId && resolvedId !== "pending" ? resolvedId : compiledRef?.id ?? "pending";
1547
- const waitingForVisibility = deferHydration && !shouldHydrate && Boolean(resolvedId);
1548
- const pendingLabel = waitingForVisibility ? "MDX ready (hydrate on view)\u2026" : compileMode === "worker" ? "Compiling MDX (client)\u2026" : "Compiling MDX (server)\u2026";
1549
- const message = failureMessage ?? (compileMode === "worker" ? "MDX compilation failed in client mode. Try switching back to server rendering or restarting the stream." : "MDX compilation failed. Try restarting the stream.");
1550
- const allowRetry = Boolean(internalError || renderError);
1551
- const retryButton = allowRetry ? React4.createElement(
1552
- "button",
1553
- {
1554
- type: "button",
1555
- className: "markdown-mdx-retry",
1556
- onClick: handleRetry
1557
- },
1558
- "Retry hydration"
1559
- ) : null;
1560
- const errorPanel = React4.createElement(
1561
- React4.Fragment,
1562
- null,
1563
- React4.createElement("strong", null, "MDX failed"),
1564
- React4.createElement("div", null, message)
1565
- );
1566
- if (Comp && !failureMessage) {
1567
- return React4.createElement(
1568
- "div",
1569
- {
1570
- className: "markdown-mdx",
1571
- ref: containerRef,
1572
- "data-mdx-ref": resolvedId ?? compiledRef?.id ?? "compiled",
1573
- "data-mdx-status": failureMessage ? "error" : "compiled",
1574
- "data-mdx-mode": compileMode
1575
- },
1576
- React4.createElement(
1577
- MdxRuntimeBoundary,
1578
- { resetKey: retryKey, onError: handleRuntimeError },
1579
- React4.createElement(Comp, {})
1580
- )
1581
- );
1582
- }
1583
- if (failureMessage) {
1584
- return React4.createElement(
1585
- "div",
1586
- {
1587
- className: "markdown-mdx error",
1588
- ref: containerRef,
1589
- "data-mdx-ref": pendingId,
1590
- "data-mdx-status": "error",
1591
- "data-mdx-mode": compileMode
1592
- },
1593
- errorPanel,
1594
- retryButton
1595
- );
1596
- }
1597
- if (!Comp) {
1598
- return React4.createElement(
1599
- "div",
1600
- {
1601
- className: "markdown-mdx",
1602
- ref: containerRef,
1603
- "data-mdx-ref": pendingId,
1604
- "data-mdx-status": "pending",
1605
- "data-mdx-mode": compileMode
1606
- },
1607
- pendingLabel
1608
- );
2459
+ mdx: ({ raw, meta }) => {
2460
+ let originalType = typeof meta?.originalType == "string" ? String(meta.originalType) : void 0, mixedSegments = Array.isArray(meta?.mixedSegments) ? meta.mixedSegments : void 0;
2461
+ if (originalType === "paragraph" && !meta?.mdxStandalone && mixedSegments && mixedSegments.length > 0) {
2462
+ let structured = renderParagraphMixedSegments(mixedSegments, defaultInlineComponents, DEFAULT_INLINE_HTML_RENDERERS);
2463
+ return structured.length === 1 ? structured[0] : React8.createElement(React8.Fragment, {}, ...structured);
1609
2464
  }
2465
+ return React8.createElement(
2466
+ "div",
2467
+ { className: "markdown-mdx-inert", "data-diagnostic": "MDX requires explicit engines.mdx in trusted-mdx mode" },
2468
+ React8.createElement("pre", null, React8.createElement("code", null, raw ?? ""))
2469
+ );
1610
2470
  },
1611
2471
  // Footnotes block rendered at page end
1612
2472
  footnotes: ({ items }) => {
1613
- if (!items || items.length === 0) return React4.createElement(React4.Fragment, null);
1614
- const listItems = items.map(
1615
- (item) => React4.createElement(
2473
+ if (!items || items.length === 0) return React8.createElement(React8.Fragment, null);
2474
+ let listItems = items.map(
2475
+ (item) => React8.createElement(
1616
2476
  "li",
1617
2477
  { key: item.number, id: `fn:${item.number}` },
1618
2478
  renderInlineNodes(item.inlines, defaultInlineComponents),
1619
- " ",
1620
- React4.createElement(
1621
- "a",
1622
- {
1623
- href: `#fnref:${item.number}`,
1624
- className: "footnote-backref",
1625
- "aria-label": "Back to content",
1626
- style: { color: "var(--foreground)", textDecoration: "underline" }
1627
- },
1628
- "\u21A9"
1629
- )
2479
+ ...Array.from({ length: item.refCount ?? 1 }, (_, index) => React8.createElement(
2480
+ React8.Fragment,
2481
+ { key: index },
2482
+ " ",
2483
+ React8.createElement(
2484
+ "a",
2485
+ {
2486
+ href: `#fnref:${item.number}${index > 0 ? `:${index + 1}` : ""}`,
2487
+ className: "footnote-backref",
2488
+ "aria-label": index > 0 ? `Back to content (reference ${index + 1})` : "Back to content",
2489
+ style: { color: "var(--foreground)", textDecoration: "underline" }
2490
+ },
2491
+ "\u21A9",
2492
+ index > 0 ? React8.createElement("sup", null, String(index + 1)) : null
2493
+ )
2494
+ ))
1630
2495
  )
1631
2496
  );
1632
- return React4.createElement("section", { className: "footnotes" }, React4.createElement("hr", {}), React4.createElement("ol", {}, listItems));
2497
+ return React8.createElement("section", { className: "footnotes" }, React8.createElement("hr", {}), React8.createElement("ol", {}, listItems));
1633
2498
  },
1634
2499
  // Footnote definition placeholders (render nothing)
1635
- "footnote-def": () => React4.createElement(React4.Fragment, null),
2500
+ "footnote-def": () => React8.createElement(React8.Fragment, null),
1636
2501
  // Callouts block
1637
2502
  callout: ({ kind, inlines = [] }) => {
1638
- const tone = (kind || "NOTE").toUpperCase();
1639
- const title = tone.charAt(0) + tone.slice(1).toLowerCase();
1640
- return React4.createElement(
2503
+ let tone = (kind || "NOTE").toUpperCase(), title = tone.charAt(0) + tone.slice(1).toLowerCase();
2504
+ return React8.createElement(
1641
2505
  "div",
1642
2506
  { className: `markdown-callout markdown-callout-${tone.toLowerCase()} border rounded p-3 my-3` },
1643
- React4.createElement("div", { className: "font-semibold mb-1" }, title),
2507
+ React8.createElement("div", { className: "font-semibold mb-1" }, title),
1644
2508
  inlines.length > 0 ? renderInlineNodes(inlines, defaultInlineComponents) : null
1645
2509
  );
1646
2510
  },
@@ -1651,11 +2515,9 @@ var defaultBlockComponents = {
1651
2515
  align,
1652
2516
  elements
1653
2517
  }) => {
1654
- const El = getDefaultTableElements(elements);
1655
- const renderCells = (cells, tag, rowIdx) => cells.map((cell, i) => {
1656
- const columnAlign = align?.[i] ?? void 0;
1657
- const cellStyle = columnAlign ? { textAlign: columnAlign } : void 0;
1658
- return React4.createElement(
2518
+ let El = getDefaultTableElements(elements), renderCells = (cells, tag, rowIdx) => cells.map((cell, i) => {
2519
+ let columnAlign = align?.[i] ?? void 0, cellStyle = columnAlign ? { textAlign: columnAlign } : void 0;
2520
+ return React8.createElement(
1659
2521
  tag === "th" ? El.Th : El.Td,
1660
2522
  {
1661
2523
  key: `${rowIdx}-${i}`,
@@ -1666,54 +2528,228 @@ var defaultBlockComponents = {
1666
2528
  renderInlineNodes(cell, defaultInlineComponents)
1667
2529
  );
1668
2530
  });
1669
- return React4.createElement(
2531
+ return React8.createElement(
1670
2532
  El.Table,
1671
2533
  { className: "markdown-table" },
1672
- header && header.length > 0 ? React4.createElement(El.Thead, {}, React4.createElement(El.Tr, {}, renderCells(header, "th", -1))) : null,
1673
- React4.createElement(
2534
+ header && header.length > 0 ? React8.createElement(El.Thead, {}, React8.createElement(El.Tr, {}, renderCells(header, "th", -1))) : null,
2535
+ rows && rows.length > 0 ? React8.createElement(
1674
2536
  El.Tbody,
1675
2537
  {},
1676
- rows.map((row, r) => React4.createElement(El.Tr, { key: r }, renderCells(row, "td", r)))
1677
- )
2538
+ rows.map((row, r) => React8.createElement(El.Tr, { key: r }, renderCells(row, "td", r)))
2539
+ ) : null
1678
2540
  );
1679
2541
  }
1680
- };
1681
- var ComponentRegistry = class {
1682
- constructor(blockComponents = {}, inlineComponents = {}) {
1683
- this.blockComponentMapCache = null;
2542
+ }, ComponentRegistry = class {
2543
+ constructor(options) {
2544
+ this.nodePresentations = {};
2545
+ this.tableVirtualization = DEFAULT_TABLE_VIRTUALIZATION_CONFIG;
2546
+ this.tableVirtualizationListeners = /* @__PURE__ */ new Set();
2547
+ this.codeVirtualization = DEFAULT_VIRTUALIZED_CODE_CONFIG;
2548
+ this.codeVirtualizationListeners = /* @__PURE__ */ new Set();
1684
2549
  this.inlineComponentMapCache = null;
1685
- this.blockComponents = { ...defaultBlockComponents, ...blockComponents };
1686
- this.inlineComponents = { ...defaultInlineComponents, ...inlineComponents };
1687
- this.htmlElements = getDefaultHtmlElements();
1688
- this.tableElements = getDefaultTableElements();
2550
+ this.controls = !1;
2551
+ this.animatedOptions = null;
2552
+ this.animationTimeline = null;
2553
+ this.hasFilterConfig = !1;
2554
+ this.mathEngine = options?.engines?.math, this.mermaidEngine = options?.engines?.mermaid, this.inlineComponents = { ...defaultInlineComponents }, this.htmlElements = getDefaultHtmlElements(), options?.urlTransform && (this.urlTransform = options.urlTransform), options?.contentComponents && (this.contentComponents = options.contentComponents);
2555
+ let defaultHtmlInlineRenderer = (node) => renderHtmlInlineNode(node, node.children, this.htmlElements, void 0, node.textValue, this.urlTransform);
2556
+ this.defaultHtmlInlineRenderer = defaultHtmlInlineRenderer, this.inlineComponents.html = defaultHtmlInlineRenderer, this.tableElements = getDefaultTableElements(), this.setNodePresentations(options?.components), options?.tableVirtualization !== void 0 && this.setTableVirtualization(options.tableVirtualization), options?.codeVirtualization !== void 0 && this.setCodeVirtualization(options.codeVirtualization), options?.controls !== void 0 && this.setControls(options.controls), options?.controlsComponent !== void 0 && this.setControlsComponent(options.controlsComponent), options?.animated !== void 0 && this.setAnimated(options.animated), options && this.setElementFilters(options);
1689
2557
  }
1690
- /**
1691
- * Update block components
1692
- */
1693
- setBlockComponents(components) {
1694
- this.blockComponents = { ...this.blockComponents, ...components };
1695
- this.blockComponentMapCache = null;
2558
+ setLinkSafetyRenderer(renderer) {
2559
+ this.inlineComponents = {
2560
+ ...this.inlineComponents,
2561
+ link: renderer ?? defaultInlineComponents.link
2562
+ }, this.inlineComponentMapCache = null;
1696
2563
  }
1697
- /**
1698
- * Update inline components
1699
- */
1700
- setInlineComponents(components) {
1701
- this.inlineComponents = { ...this.inlineComponents, ...components };
1702
- this.inlineComponentMapCache = null;
2564
+ hasElementFilters() {
2565
+ return this.hasFilterConfig;
2566
+ }
2567
+ /** Replaces the whole filter configuration at once so prop swaps (allowed -> disallowed) never trip the exclusivity check. */
2568
+ setElementFilters(options) {
2569
+ let { allowedElements, disallowedElements, allowElement, unwrapDisallowed, disableAutolinkProtocols } = options;
2570
+ if (allowedElements && disallowedElements)
2571
+ throw new Error("Cannot specify both allowedElements and disallowedElements; expected one or the other");
2572
+ let toTagSet = (tags) => tags ? new Set(tags.map((tag) => tag.trim().toLowerCase())) : void 0;
2573
+ this.allowedElements = toTagSet(allowedElements), this.disallowedElements = toTagSet(disallowedElements), this.allowElement = allowElement, this.unwrapDisallowed = unwrapDisallowed, this.disableAutolinkProtocols = disableAutolinkProtocols ? new Set(disableAutolinkProtocols.map((protocol) => protocol.trim().toLowerCase().replace(/:$/, ""))) : void 0, this.hasFilterConfig = !!(this.allowedElements || this.disallowedElements || this.allowElement);
2574
+ }
2575
+ isAutolinkProtocolDisabled(href) {
2576
+ if (!this.disableAutolinkProtocols || !href) return !1;
2577
+ let match = /^[a-zA-Z][a-zA-Z0-9+.-]*(?=:)/.exec(href.trim());
2578
+ return match ? this.disableAutolinkProtocols.has(match[0].toLowerCase()) : !1;
2579
+ }
2580
+ isElementAllowed(element, context) {
2581
+ let tag = element.tagName.toLowerCase();
2582
+ return !(this.allowedElements && !this.allowedElements.has(tag) || this.disallowedElements && this.disallowedElements.has(tag) || this.allowElement && !this.allowElement(
2583
+ { tagName: tag, properties: element.properties ?? {}, blockType: element.blockType },
2584
+ context
2585
+ ));
2586
+ }
2587
+ filterElement(element, context, renderElement, renderChildren) {
2588
+ if (!this.hasFilterConfig || this.isElementAllowed(element, context))
2589
+ return renderElement();
2590
+ if (this.unwrapDisallowed && renderChildren) {
2591
+ let children = renderChildren();
2592
+ if (children == null) return null;
2593
+ let key = element.properties?.key;
2594
+ return React8.createElement(React8.Fragment, key !== void 0 ? { key } : null, children);
2595
+ }
2596
+ return null;
2597
+ }
2598
+ setUrlTransform(transform) {
2599
+ this.urlTransform = transform;
1703
2600
  }
1704
- /** Update HTML element mapping for html blocks */
1705
- setHtmlElements(map) {
1706
- this.htmlElements = { ...this.htmlElements, ...map };
2601
+ setAnimated(animated) {
2602
+ this.animated = animated, this.animatedOptions = resolveAnimatedOptions(animated), this.animatedOptions ? this.animationTimeline ? this.animationTimeline.updateOptions({
2603
+ maxBacklogMs: this.animatedOptions.maxBacklogMs,
2604
+ stagger: this.animatedOptions.stagger
2605
+ }) : this.animationTimeline = new AnimationTimeline({
2606
+ maxBacklogMs: this.animatedOptions.maxBacklogMs,
2607
+ stagger: this.animatedOptions.stagger
2608
+ }) : (this.animationTimeline && this.animationTimeline.reset(), this.animationTimeline = null);
1707
2609
  }
1708
- /** Update table element mapping for table blocks */
1709
- setTableElements(map) {
1710
- this.tableElements = { ...this.tableElements, ...map };
2610
+ getAnimated() {
2611
+ return this.animated;
2612
+ }
2613
+ getAnimatedOptions() {
2614
+ return this.animatedOptions;
2615
+ }
2616
+ getAnimationTimeline() {
2617
+ return this.animationTimeline;
2618
+ }
2619
+ getRenderInlineContext(isFinalized, blockId, sourceGuard) {
2620
+ let context;
2621
+ return isFinalized ? (blockId && this.animationTimeline && this.animationTimeline.releasePrefix(blockId), context = blockId ? { isFinalized: !0, nodeKeyPrefix: blockId } : void 0) : this.animatedOptions && this.animationTimeline && (context = {
2622
+ isFinalized: !1,
2623
+ animated: this.animatedOptions,
2624
+ timeline: this.animationTimeline,
2625
+ nodeKeyPrefix: blockId
2626
+ }), sourceGuard ? { ...context ?? { isFinalized: isFinalized ?? !1 }, sourceGuard } : context;
2627
+ }
2628
+ resetAnimationTimeline() {
2629
+ this.animationTimeline?.reset();
2630
+ }
2631
+ getUrlTransform() {
2632
+ return this.urlTransform;
2633
+ }
2634
+ releaseFinalizedBlockAnimations(blockId) {
2635
+ this.animationTimeline?.releasePrefix(blockId);
2636
+ }
2637
+ setNodePresentations(presentations) {
2638
+ validateNodePresentations(presentations), this.nodePresentations = presentations ?? {};
2639
+ }
2640
+ getNodePresentation(key) {
2641
+ return resolveNodePresentation(this.nodePresentations, key);
2642
+ }
2643
+ isDefaultHtmlInlineRenderer(renderer) {
2644
+ return !renderer || !this.defaultHtmlInlineRenderer ? !1 : renderer === this.defaultHtmlInlineRenderer;
2645
+ }
2646
+ renderInlinePresentation(node, nativeView, key, context, renderedChildren) {
2647
+ let keyName = node.kind === "plugin" ? `extension:${node.name}` : node.kind === "math-inline" || node.kind === "math-display" ? "inline:math" : `inline:${node.kind}`, presentation = this.getNodePresentation(keyName);
2648
+ if (!presentation) return nativeView;
2649
+ let hasPluginComponent = node.kind === "plugin" && (this.inlineComponents[node.name] !== void 0 || this.inlineComponents.plugin !== void 0), preparedNativeView = node.kind === "plugin" && !hasPluginComponent && renderedChildren !== void 0 ? React8.createElement(React8.Fragment, { key }, renderedChildren) : nativeView, presentedNode = node;
2650
+ if ("view" in presentation && presentation.view) {
2651
+ let transform = this.urlTransform ?? defaultUrlTransform4;
2652
+ node.kind === "link" ? presentedNode = {
2653
+ ...node,
2654
+ href: transform(node.href ?? "", "href", { source: "markdown" }) ?? void 0
2655
+ } : node.kind === "image" && (presentedNode = {
2656
+ ...node,
2657
+ src: transform(node.src ?? "", "src", { source: "markdown" }) ?? ""
2658
+ });
2659
+ }
2660
+ let metadata = Object.freeze({
2661
+ id: `${context?.nodeKeyPrefix ?? "inline"}:${String(key)}`,
2662
+ type: keyName,
2663
+ isFinalized: context?.isFinalized ?? !1
2664
+ }), source = () => (context?.sourceGuard?.(), inlineToPlainText([node])), actions = Object.freeze({
2665
+ readSource: source,
2666
+ copy: () => copyToClipboard(source()),
2667
+ download: () => downloadFile(source(), `${node.kind}.txt`)
2668
+ }), children = node.kind === "math-inline" || node.kind === "math-display" ? nativeView : renderedChildren ?? (React8.isValidElement(preparedNativeView) ? preparedNativeView.props.children : void 0);
2669
+ return renderPresentedNode(presentation, preparedNativeView, {
2670
+ key,
2671
+ metadata,
2672
+ actions,
2673
+ viewProps: { node: presentedNode, children, metadata, actions }
2674
+ });
2675
+ }
2676
+ renderHtmlPresentation(tagName, properties, nativeView, children, key, ownerId, isFinalized = !1, sourceGuard) {
2677
+ let keyName = `html:${tagName.toLowerCase()}`, presentation = this.getNodePresentation(keyName);
2678
+ if (!presentation) return nativeView;
2679
+ let viewProperties = {};
2680
+ for (let [property, value] of Object.entries(properties))
2681
+ property !== "key" && (viewProperties[property] = value);
2682
+ let source = () => (sourceGuard?.(), presentationText(children)), metadata = Object.freeze({
2683
+ id: `${ownerId ?? "html"}:${String(key)}`,
2684
+ type: keyName,
2685
+ isFinalized
2686
+ }), actions = Object.freeze({
2687
+ readSource: source,
2688
+ copy: () => copyToClipboard(source()),
2689
+ download: () => downloadFile(source(), `${tagName.toLowerCase()}.txt`)
2690
+ });
2691
+ return renderPresentedNode(presentation, nativeView, {
2692
+ key,
2693
+ metadata,
2694
+ actions,
2695
+ viewProps: { tagName: tagName.toLowerCase(), properties: viewProperties, children, metadata, actions }
2696
+ });
2697
+ }
2698
+ renderComponentPresentation(name, nativeView, children, key, status, rawSource, ownerId, sourceGuard) {
2699
+ let keyName = `component:${name}`, presentation = this.getNodePresentation(keyName);
2700
+ if (!presentation) return nativeView;
2701
+ if ("view" in presentation && presentation.view)
2702
+ throw new TypeError(`node presentation for ${keyName}: headless views are not supported for restricted content components`);
2703
+ let preparedNativeView = presentation.props ? React8.cloneElement(
2704
+ nativeView,
2705
+ mergeNodePresentationProps(nativeView.props, presentation.props)
2706
+ ) : nativeView;
2707
+ if (!("wrapper" in presentation) || !presentation.wrapper) return preparedNativeView;
2708
+ let source = () => (sourceGuard?.(), rawSource ?? presentationText(children)), metadata = Object.freeze({
2709
+ id: `${ownerId ?? "component"}:${String(key)}`,
2710
+ type: keyName,
2711
+ isFinalized: status === "closed"
2712
+ }), actions = Object.freeze({
2713
+ readSource: source,
2714
+ copy: () => copyToClipboard(source()),
2715
+ download: () => downloadFile(source(), `${name}.txt`)
2716
+ });
2717
+ return React8.createElement(presentation.wrapper, { key, children: preparedNativeView, metadata, actions });
2718
+ }
2719
+ /** Get HTML element mapping */
2720
+ getHtmlElements() {
2721
+ return this.htmlElements;
2722
+ }
2723
+ /** Update literal tag content list */
2724
+ setLiteralTagContent(tags) {
2725
+ this.literalTagContent = tags;
2726
+ }
2727
+ /** Get literal tag content list */
2728
+ getLiteralTagContent() {
2729
+ return this.literalTagContent;
2730
+ }
2731
+ setControls(controls) {
2732
+ this.controls = controls ?? !1;
2733
+ }
2734
+ getControls() {
2735
+ return this.controls;
2736
+ }
2737
+ setControlsComponent(component) {
2738
+ this.controlsComponent = component;
2739
+ }
2740
+ getControlsComponent() {
2741
+ if (this.controlsComponent)
2742
+ return this.controlsComponent;
1711
2743
  }
1712
2744
  /**
1713
2745
  * Get block component
1714
2746
  */
1715
2747
  getBlockComponent(type) {
1716
- return this.blockComponents[type] || this.blockComponents.paragraph;
2748
+ return defaultBlockComponents[type] ?? defaultBlockComponents.paragraph;
2749
+ }
2750
+ getCodeNodeView() {
2751
+ let presentation = this.getNodePresentation("code");
2752
+ return presentation && "view" in presentation ? presentation.view : void 0;
1717
2753
  }
1718
2754
  /**
1719
2755
  * Get inline components
@@ -1721,112 +2757,309 @@ var ComponentRegistry = class {
1721
2757
  getInlineComponents() {
1722
2758
  return this.inlineComponents;
1723
2759
  }
1724
- getBlockComponentMap() {
1725
- if (!this.blockComponentMapCache) {
1726
- this.blockComponentMapCache = { ...this.blockComponents };
1727
- }
1728
- return this.blockComponentMapCache;
2760
+ getMathEngine() {
2761
+ return this.mathEngine;
1729
2762
  }
1730
- getInlineComponentMap() {
1731
- if (!this.inlineComponentMapCache) {
1732
- this.inlineComponentMapCache = { ...this.inlineComponents };
1733
- }
1734
- return this.inlineComponentMapCache;
2763
+ setMermaidEngine(engine) {
2764
+ this.mermaidEngine = engine;
2765
+ }
2766
+ getMermaidEngine() {
2767
+ return this.mermaidEngine;
2768
+ }
2769
+ setContentComponents(contentComponents) {
2770
+ this.contentComponents = contentComponents;
2771
+ }
2772
+ getContentComponents() {
2773
+ return this.contentComponents;
2774
+ }
2775
+ renderHtmlTree(tree, renderBlock = (block) => this.renderBlock(block), paragraph, parentTagName, renderParagraphPresentation, sourceGuard) {
2776
+ return renderOwnedHtmlTree(
2777
+ tree,
2778
+ this.ownedHtmlRenderContext(renderBlock, paragraph, parentTagName, void 0, renderParagraphPresentation, sourceGuard)
2779
+ );
2780
+ }
2781
+ ownedHtmlRenderContext(renderBlock = (block) => this.renderBlock(block), paragraph, parentTagName, inlineContext, renderParagraphPresentation, sourceGuard) {
2782
+ let renderContext = inlineContext ?? (paragraph ? this.getRenderInlineContext(paragraph.isFinalized, paragraph.id, sourceGuard) : void 0);
2783
+ return {
2784
+ elements: this.htmlElements,
2785
+ renderBlock,
2786
+ renderInline: (nodes, parentTagName2) => renderInlineNodes(nodes, this.inlineComponents, this.urlTransform, this, parentTagName2, renderContext),
2787
+ renderInlinePresentation: (node, nativeView, key, children) => this.renderInlinePresentation(node, nativeView, key, renderContext, children),
2788
+ renderHtmlPresentation: (tagName, properties, nativeView, children, key) => this.renderHtmlPresentation(
2789
+ tagName,
2790
+ properties,
2791
+ nativeView,
2792
+ children,
2793
+ key,
2794
+ renderContext?.nodeKeyPrefix ?? String(paragraph?.id ?? parentTagName ?? "html"),
2795
+ renderContext?.isFinalized ?? paragraph?.isFinalized ?? !1,
2796
+ renderContext?.sourceGuard
2797
+ ),
2798
+ renderComponentPresentation: (name, nativeView, children, key, status, rawSource) => this.renderComponentPresentation(
2799
+ name,
2800
+ nativeView,
2801
+ children,
2802
+ key,
2803
+ status,
2804
+ rawSource,
2805
+ renderContext?.nodeKeyPrefix ?? String(paragraph?.id ?? parentTagName ?? "html"),
2806
+ renderContext?.sourceGuard
2807
+ ),
2808
+ inlineComponents: this.inlineComponents,
2809
+ urlTransform: this.urlTransform,
2810
+ isAutolinkProtocolDisabled: (href) => this.isAutolinkProtocolDisabled(href),
2811
+ filterElement: this.hasElementFilters() ? (element, context, renderElement, renderChildren) => this.filterElement(element, context, renderElement, renderChildren) : void 0,
2812
+ parentTagName,
2813
+ contentComponents: this.contentComponents,
2814
+ renderParagraph: paragraph ? (children) => {
2815
+ let nativeView = React8.createElement(this.getBlockComponent("paragraph"), {
2816
+ ...this.getBlockProps(paragraph, sourceGuard),
2817
+ children
2818
+ });
2819
+ return renderParagraphPresentation ? renderParagraphPresentation(nativeView) : nativeView;
2820
+ } : void 0
2821
+ };
1735
2822
  }
1736
2823
  getTableElements() {
1737
2824
  return this.tableElements;
1738
2825
  }
2826
+ subscribeTableVirtualization(listener) {
2827
+ return this.tableVirtualizationListeners.add(listener), () => {
2828
+ this.tableVirtualizationListeners.delete(listener);
2829
+ };
2830
+ }
2831
+ setTableVirtualization(options) {
2832
+ this.tableVirtualization = resolveTableVirtualizationConfig(options);
2833
+ for (let listener of this.tableVirtualizationListeners)
2834
+ listener();
2835
+ }
2836
+ getTableVirtualization() {
2837
+ return this.tableVirtualization;
2838
+ }
2839
+ subscribeCodeVirtualization(listener) {
2840
+ return this.codeVirtualizationListeners.add(listener), () => {
2841
+ this.codeVirtualizationListeners.delete(listener);
2842
+ };
2843
+ }
2844
+ setCodeVirtualization(options) {
2845
+ this.codeVirtualization = resolveVirtualizedCodeConfig(options);
2846
+ for (let listener of this.codeVirtualizationListeners)
2847
+ listener();
2848
+ }
2849
+ getCodeVirtualization() {
2850
+ return this.codeVirtualization;
2851
+ }
1739
2852
  /**
1740
2853
  * Render a block
1741
2854
  */
1742
- renderBlock(block) {
1743
- const Component = this.getBlockComponent(block.type);
1744
- const props = this.getBlockProps(block);
1745
- return React4.createElement(Component, {
1746
- key: block.id,
1747
- ...props
1748
- });
2855
+ renderBlock(block, renderPresentation, sourceGuard) {
2856
+ let meta = block.payload.meta, sourceOwnedHtmlTree = meta?.htmlOwnership === !0 && Array.isArray(meta.htmlTree) ? meta.htmlTree : void 0;
2857
+ if (block.type === "paragraph" && sourceOwnedHtmlTree)
2858
+ return React8.createElement(
2859
+ React8.Fragment,
2860
+ {},
2861
+ this.renderHtmlTree(sourceOwnedHtmlTree, void 0, block, void 0, renderPresentation, sourceGuard)
2862
+ );
2863
+ if (block.type === "paragraph" && meta?.htmlParagraphTree)
2864
+ return React8.createElement(
2865
+ React8.Fragment,
2866
+ {},
2867
+ this.renderHtmlTree(meta.htmlParagraphTree, void 0, block, void 0, renderPresentation, sourceGuard)
2868
+ );
2869
+ let Component = this.getBlockComponent(block.type), props = this.getBlockProps(block, sourceGuard), paragraphGroups = block.type === "paragraph" && Array.isArray(block.payload.meta?.mixedSegments) && Array.isArray(props.children) ? props.children : void 0;
2870
+ paragraphGroups && (props.children = paragraphGroups.flatMap(
2871
+ (group) => React8.isValidElement(group) && group.type === "p" ? React8.Children.toArray(group.props.children) : [group]
2872
+ ));
2873
+ let element = paragraphGroups ? React8.createElement(React8.Fragment, { key: block.id }, ...paragraphGroups.map(
2874
+ (group, index) => React8.isValidElement(group) && group.type === "p" ? React8.createElement(Component, { ...props, key: `${block.id}-${index}`, children: group.props.children }) : group
2875
+ )) : React8.createElement(Component, { key: block.id, ...props }), finalElement = (() => {
2876
+ if (block.type === "code") {
2877
+ let meta2 = block.payload.meta ?? {}, lang = typeof meta2.lang == "string" ? String(meta2.lang) : "", raw = typeof block.payload.raw == "string" ? block.payload.raw : "", metaCode = typeof meta2.code == "string" ? meta2.code : null, normalizedRaw = raw.replace(/\r\n?/g, `
2878
+ `), fenced = stripCodeFence(block.isFinalized ? normalizedRaw : trimProvisionalFenceTail(normalizedRaw)), codeText = metaCode !== null ? metaCode.replace(/\r\n?/g, `
2879
+ `) : fenced.hadFence ? fenced.code : normalizedRaw, codeControls = resolveCodeControls(this.getControls());
2880
+ if (Array.isArray(meta2.diffBlocks) && meta2.diffBlocks.length > 0)
2881
+ return React8.createElement(DefaultDiffRenderer, {
2882
+ key: block.id,
2883
+ meta: meta2,
2884
+ renderCode: element
2885
+ });
2886
+ if (codeControls.enabled) {
2887
+ let ControlsComponent = this.getControlsComponent(), controlsElement = ControlsComponent ? React8.createElement(ControlsComponent, {
2888
+ type: "code",
2889
+ blockId: block.id,
2890
+ code: codeText,
2891
+ language: lang,
2892
+ isFinalized: block.isFinalized,
2893
+ onCopy: () => copyToClipboard(codeText),
2894
+ onDownload: () => downloadFile(codeText, getCodeSnippetFilename(lang)),
2895
+ labels: codeControls.labels
2896
+ }) : React8.createElement(CodeControlsBar, {
2897
+ code: codeText,
2898
+ language: lang,
2899
+ config: codeControls
2900
+ });
2901
+ return React8.createElement("div", { className: "stream-mdx-code-wrapper relative", key: block.id }, controlsElement, element);
2902
+ }
2903
+ }
2904
+ if (block.type === "table") {
2905
+ let tableControls = resolveTableControls(this.getControls());
2906
+ if (tableControls.enabled) {
2907
+ let meta2 = block.payload.meta ?? {}, header = Array.isArray(meta2.header) ? meta2.header.map((cell) => inlineToPlainText(cell)) : [], rows = Array.isArray(meta2.rows) ? meta2.rows.map((r) => r.map((cell) => inlineToPlainText(cell))) : [], align = Array.isArray(meta2.align) ? meta2.align : void 0, isFinalized = !!block.isFinalized, ControlsComponent = this.getControlsComponent(), controlsElement = ControlsComponent ? React8.createElement(ControlsComponent, {
2908
+ type: "table",
2909
+ blockId: block.id,
2910
+ headers: header,
2911
+ rows,
2912
+ align,
2913
+ isFinalized,
2914
+ onCopy: (format) => {
2915
+ if (!isFinalized) return;
2916
+ let text = format === "markdown" ? tableToMarkdown(header, rows, align) : tableToTsv(header, rows);
2917
+ return copyToClipboard(text);
2918
+ },
2919
+ onDownload: (format) => {
2920
+ isFinalized && (format === "tsv" ? downloadFile(tableToTsv(header, rows), "table.tsv", "text/tab-separated-values;charset=utf-8") : format === "markdown" ? downloadFile(tableToMarkdown(header, rows, align), "table.md", "text/markdown;charset=utf-8") : downloadFile(tableToCsv(header, rows), "table.csv", "text/csv;charset=utf-8"));
2921
+ },
2922
+ labels: tableControls.labels
2923
+ }) : React8.createElement(TableControlsBar, {
2924
+ headers: header,
2925
+ rows,
2926
+ align,
2927
+ isFinalized,
2928
+ config: tableControls
2929
+ });
2930
+ return React8.createElement("div", { className: "stream-mdx-table-wrapper relative", key: block.id }, controlsElement, element);
2931
+ }
2932
+ }
2933
+ return element;
2934
+ })();
2935
+ if (this.hasFilterConfig) {
2936
+ let blockTagName = "";
2937
+ switch (block.type) {
2938
+ case "paragraph":
2939
+ blockTagName = "p";
2940
+ break;
2941
+ case "heading": {
2942
+ let meta2 = block.payload.meta ?? {}, levelFromMeta = typeof meta2.headingLevel == "number" ? meta2.headingLevel : void 0, normalizedLevel = Number.isFinite(levelFromMeta) ? Math.min(Math.max(levelFromMeta, 1), 6) : void 0, rawHeading = typeof block.payload.raw == "string" ? block.payload.raw : "";
2943
+ blockTagName = `h${normalizedLevel ?? this.extractHeadingLevel(rawHeading)}`;
2944
+ break;
2945
+ }
2946
+ case "code":
2947
+ blockTagName = "pre";
2948
+ break;
2949
+ case "blockquote":
2950
+ blockTagName = "blockquote";
2951
+ break;
2952
+ case "hr":
2953
+ blockTagName = "hr";
2954
+ break;
2955
+ case "list":
2956
+ blockTagName = block.payload.meta?.ordered ? "ol" : "ul";
2957
+ break;
2958
+ case "table":
2959
+ blockTagName = "table";
2960
+ break;
2961
+ }
2962
+ if (blockTagName) {
2963
+ let renderChildren = () => {
2964
+ if (block.type === "paragraph" || block.type === "heading")
2965
+ return "children" in props ? props.children : void 0;
2966
+ if (block.type === "blockquote")
2967
+ return "renderedContent" in props ? props.renderedContent : void 0;
2968
+ if (block.type === "code") {
2969
+ let meta2 = block.payload.meta;
2970
+ return (meta2 && typeof meta2 == "object" && "code" in meta2 && typeof meta2.code == "string" ? meta2.code : void 0) || block.payload.raw || "";
2971
+ }
2972
+ }, filtered = this.filterElement(
2973
+ { tagName: blockTagName, properties: props, blockType: block.type },
2974
+ { source: "markdown" },
2975
+ () => renderPresentation ? renderPresentation(finalElement) : finalElement,
2976
+ renderChildren
2977
+ );
2978
+ return filtered == null ? React8.createElement(React8.Fragment, { key: block.id }) : React8.isValidElement(filtered) ? filtered : React8.createElement(React8.Fragment, { key: block.id }, filtered);
2979
+ }
2980
+ }
2981
+ let presented = renderPresentation ? renderPresentation(finalElement) : finalElement;
2982
+ return React8.isValidElement(presented) ? presented : React8.createElement(React8.Fragment, { key: block.id }, presented);
1749
2983
  }
1750
2984
  /**
1751
2985
  * Get props for a block based on its type
1752
2986
  */
1753
- getBlockProps(block) {
2987
+ getBlockProps(block, sourceGuard) {
2988
+ let animCtx = this.getRenderInlineContext(block.isFinalized, block.id, sourceGuard);
1754
2989
  switch (block.type) {
1755
2990
  case "heading": {
1756
- const meta = block.payload.meta ?? {};
1757
- const inlineNodes = Array.isArray(block.payload.inline) ? block.payload.inline : [];
1758
- const levelFromMeta = typeof meta.headingLevel === "number" ? meta.headingLevel : void 0;
1759
- const normalizedLevel = Number.isFinite(levelFromMeta) ? Math.min(Math.max(levelFromMeta, 1), 6) : void 0;
1760
- const rawHeading = typeof block.payload.raw === "string" ? block.payload.raw : "";
1761
- const headingText = typeof meta.headingText === "string" && meta.headingText.trim().length > 0 ? meta.headingText : removeHeadingMarkers(rawHeading).trim();
1762
- const level = normalizedLevel ?? this.extractHeadingLevel(rawHeading);
2991
+ let meta = block.payload.meta ?? {}, inlineNodes = Array.isArray(block.payload.inline) ? block.payload.inline : [], levelFromMeta = typeof meta.headingLevel == "number" ? meta.headingLevel : void 0, normalizedLevel = Number.isFinite(levelFromMeta) ? Math.min(Math.max(levelFromMeta, 1), 6) : void 0, rawHeading = typeof block.payload.raw == "string" ? block.payload.raw : "", headingText = typeof meta.headingText == "string" && meta.headingText.trim().length > 0 ? meta.headingText : removeHeadingMarkers(rawHeading).trim(), level = normalizedLevel ?? this.extractHeadingLevel(rawHeading), ownedTree = block.payload.meta?.htmlOwnership === !0 ? block.payload.meta.htmlTree : void 0, ownedRoot = ownedTree?.length === 1 ? ownedTree[0] : void 0, ownedChildren = ownedRoot?.kind === "element" && ownedRoot.tagName === `h${level}` ? ownedRoot.children : void 0, renderedChildren = ownedChildren ? renderOwnedHtmlTree(ownedChildren, this.ownedHtmlRenderContext(void 0, void 0, `h${level}`, animCtx)) : renderInlineNodes(inlineNodes, this.inlineComponents, this.urlTransform, this, `h${level}`, animCtx);
1763
2992
  return {
1764
2993
  level,
1765
2994
  inlines: inlineNodes,
1766
2995
  text: headingText,
1767
- meta
2996
+ meta,
2997
+ children: renderedChildren
1768
2998
  };
1769
2999
  }
1770
- case "paragraph":
3000
+ case "paragraph": {
3001
+ let segments = block.payload.meta?.mixedSegments;
1771
3002
  return {
1772
3003
  inlines: block.payload.inline || [],
1773
3004
  raw: block.payload.raw,
1774
- meta: block.payload.meta
3005
+ meta: block.payload.meta,
3006
+ children: Array.isArray(segments) && segments.length > 0 ? renderMixedParagraphSegments(
3007
+ segments,
3008
+ this.inlineComponents,
3009
+ DEFAULT_INLINE_HTML_RENDERERS,
3010
+ this.htmlElements,
3011
+ this.literalTagContent,
3012
+ this.urlTransform,
3013
+ this,
3014
+ animCtx,
3015
+ block.payload.meta?.mixedHtmlTrees,
3016
+ (tree) => renderOwnedHtmlTree(tree, this.ownedHtmlRenderContext(void 0, void 0, "p", animCtx))
3017
+ ) : renderInlineNodes(block.payload.inline ?? [], this.inlineComponents, this.urlTransform, this, "p", animCtx)
1775
3018
  };
3019
+ }
1776
3020
  case "blockquote":
1777
3021
  return {
1778
- inlines: block.payload.inline || []
3022
+ inlines: block.payload.inline || [],
3023
+ renderedContent: renderInlineNodes(block.payload.inline || [], this.inlineComponents, this.urlTransform, this, "blockquote", animCtx)
1779
3024
  };
1780
3025
  case "hr": {
1781
- const range = block.payload.range;
3026
+ let range = block.payload.range;
1782
3027
  return {
1783
3028
  className: "markdown-hr",
1784
- "data-start": typeof range?.from === "number" ? range.from : void 0,
1785
- "data-end": typeof range?.to === "number" ? range.to : void 0
3029
+ "data-start": typeof range?.from == "number" ? range.from : void 0,
3030
+ "data-end": typeof range?.to == "number" ? range.to : void 0
1786
3031
  };
1787
3032
  }
1788
3033
  case "code":
1789
3034
  return {
1790
3035
  html: block.payload.highlightedHtml,
1791
3036
  meta: block.payload.meta,
1792
- lang: typeof block.payload.meta?.lang === "string" ? String(block.payload.meta?.lang) : void 0
3037
+ lang: typeof block.payload.meta?.lang == "string" ? String(block.payload.meta?.lang) : void 0
1793
3038
  };
1794
3039
  case "list": {
1795
- const items = Array.isArray(block.payload.meta?.items) ? block.payload.meta?.items : [];
3040
+ let items = Array.isArray(block.payload.meta?.items) ? block.payload.meta?.items : [];
1796
3041
  return {
1797
- ordered: Boolean(block.payload.meta?.ordered),
3042
+ ordered: !!block.payload.meta?.ordered,
1798
3043
  items
1799
3044
  };
1800
3045
  }
1801
3046
  case "html": {
1802
- const trusted = block.payload.sanitizedHtml ?? block.payload.raw;
3047
+ let isWorkerSanitized = !!(block.payload.sanitizedHtml || block.payload.meta?.sanitized), content = block.payload.sanitizedHtml ?? block.payload.raw ?? "", htmlTree = block.payload.meta?.htmlTree;
1803
3048
  return {
1804
- // Server render should not depend on DOMPurify (which requires a DOM `window`).
1805
- // In worker-compiled flows, `sanitizedHtml` is already sanitized at the source.
1806
- __trustedHtml: typeof window === "undefined" ? String(trusted ?? "") : createTrustedHTML(String(trusted ?? "")),
1807
- elements: this.htmlElements
3049
+ __trustedHtml: isWorkerSanitized || typeof window > "u" ? String(content) : createTrustedHTML(String(content)),
3050
+ elements: this.htmlElements,
3051
+ isSanitized: isWorkerSanitized,
3052
+ literalTagContent: this.literalTagContent,
3053
+ children: htmlTree ? this.renderHtmlTree(htmlTree, void 0, block) : void 0
1808
3054
  };
1809
3055
  }
1810
3056
  case "mdx":
1811
- return (() => {
1812
- const meta = block.payload.meta;
1813
- const rawStatus = typeof meta?.mdxStatus === "string" ? meta.mdxStatus : void 0;
1814
- const status = rawStatus === "pending" || rawStatus === "compiled" || rawStatus === "error" ? rawStatus : void 0;
1815
- const errorMessage = typeof meta?.mdxError === "string" ? String(meta.mdxError) : void 0;
1816
- const compiledModule = block.payload.compiledMdxModule ?? null;
1817
- const compiledRef = block.payload.compiledMdxRef ?? (compiledModule ? { id: compiledModule.id } : void 0);
1818
- return {
1819
- compiledRef: compiledRef ?? { id: "pending" },
1820
- compiledModule,
1821
- status,
1822
- errorMessage,
1823
- raw: typeof block.payload.raw === "string" ? block.payload.raw : void 0
1824
- };
1825
- })();
3057
+ return {
3058
+ raw: typeof block.payload.raw == "string" ? block.payload.raw : void 0,
3059
+ meta: block.payload.meta
3060
+ };
1826
3061
  case "table": {
1827
- const header = Array.isArray(block.payload.meta?.header) ? block.payload.meta?.header : void 0;
1828
- const rows = Array.isArray(block.payload.meta?.rows) ? block.payload.meta?.rows : [];
1829
- const align = Array.isArray(block.payload.meta?.align) ? block.payload.meta?.align : void 0;
3062
+ let header = Array.isArray(block.payload.meta?.header) ? block.payload.meta?.header : void 0, rows = Array.isArray(block.payload.meta?.rows) ? block.payload.meta?.rows : [], align = Array.isArray(block.payload.meta?.align) ? block.payload.meta?.align : void 0;
1830
3063
  return {
1831
3064
  header,
1832
3065
  rows,
@@ -1834,17 +3067,14 @@ var ComponentRegistry = class {
1834
3067
  elements: this.tableElements
1835
3068
  };
1836
3069
  }
1837
- case "footnotes": {
1838
- const items = Array.isArray(block.payload.meta?.items) ? block.payload.meta?.items : [];
3070
+ case "footnotes":
1839
3071
  return {
1840
- items
3072
+ items: Array.isArray(block.payload.meta?.items) ? block.payload.meta?.items : []
1841
3073
  };
1842
- }
1843
3074
  case "footnote-def":
1844
3075
  return {};
1845
3076
  case "callout": {
1846
- const kind = typeof block.payload.meta?.kind === "string" ? String(block.payload.meta.kind) : void 0;
1847
- const inlineNodes = Array.isArray(block.payload.inline) ? block.payload.inline : [];
3077
+ let kind = typeof block.payload.meta?.kind == "string" ? String(block.payload.meta.kind) : void 0, inlineNodes = Array.isArray(block.payload.inline) ? block.payload.inline : [];
1848
3078
  return {
1849
3079
  kind,
1850
3080
  inlines: inlineNodes
@@ -1861,112 +3091,117 @@ var ComponentRegistry = class {
1861
3091
  * Extract heading level from raw markdown
1862
3092
  */
1863
3093
  extractHeadingLevel(raw) {
1864
- const match = raw.match(/^(#{1,6})\s/);
1865
- if (match) {
1866
- return Math.min(match[1].length, 6);
1867
- }
1868
- return 1;
3094
+ let match = raw.match(/^(#{1,6})\s/);
3095
+ return match ? Math.min(match[1].length, 6) : 1;
1869
3096
  }
1870
3097
  };
1871
3098
  function getDefaultHtmlElements() {
1872
3099
  return {
1873
3100
  // Text semantics
1874
- p: (props) => React4.createElement("p", props),
1875
- strong: (props) => React4.createElement("strong", props),
1876
- em: (props) => React4.createElement("em", props),
1877
- code: (props) => React4.createElement("code", props),
1878
- pre: (props) => React4.createElement("pre", props),
1879
- span: (props) => React4.createElement("span", props),
1880
- br: (props) => React4.createElement("br", props),
1881
- hr: (props) => React4.createElement("hr", props),
3101
+ p: (props) => React8.createElement("p", props),
3102
+ strong: (props) => React8.createElement("strong", props),
3103
+ em: (props) => React8.createElement("em", props),
3104
+ code: (props) => React8.createElement("code", props),
3105
+ pre: (props) => React8.createElement("pre", props),
3106
+ span: (props) => React8.createElement("span", props),
3107
+ br: (props) => React8.createElement("br", props),
3108
+ hr: (props) => React8.createElement("hr", props),
1882
3109
  // Lists
1883
- ul: (props) => React4.createElement("ul", props),
1884
- ol: (props) => React4.createElement("ol", props),
1885
- li: (props) => React4.createElement("li", props),
3110
+ ul: (props) => React8.createElement("ul", props),
3111
+ ol: (props) => React8.createElement("ol", props),
3112
+ li: (props) => React8.createElement("li", props),
1886
3113
  // Links & media
1887
- a: (props) => React4.createElement("a", props),
1888
- img: (props) => React4.createElement("img", props),
3114
+ a: (props) => React8.createElement("a", props),
3115
+ img: (props) => React8.createElement("img", props),
1889
3116
  // Blockquotes
1890
- blockquote: (props) => React4.createElement("blockquote", props),
3117
+ blockquote: (props) => React8.createElement("blockquote", props),
1891
3118
  // Tables
1892
- table: (props) => React4.createElement("table", props),
1893
- thead: (props) => React4.createElement("thead", props),
1894
- tbody: (props) => React4.createElement("tbody", props),
1895
- tr: (props) => React4.createElement("tr", props),
1896
- th: (props) => React4.createElement("th", props),
1897
- td: (props) => React4.createElement("td", props),
3119
+ table: (props) => React8.createElement("table", props),
3120
+ thead: (props) => React8.createElement("thead", props),
3121
+ tbody: (props) => React8.createElement("tbody", props),
3122
+ tr: (props) => React8.createElement("tr", props),
3123
+ th: (props) => React8.createElement("th", props),
3124
+ td: (props) => React8.createElement("td", props),
1898
3125
  // Generic
1899
- div: (props) => React4.createElement("div", props)
3126
+ div: (props) => React8.createElement("div", props)
1900
3127
  };
1901
3128
  }
1902
3129
  function getDefaultTableElements(overrides) {
1903
- const base = {
1904
- Table: (props) => React4.createElement("table", props),
1905
- Thead: (props) => React4.createElement("thead", props),
1906
- Tbody: (props) => React4.createElement("tbody", props),
1907
- Tr: (props) => React4.createElement("tr", props),
1908
- Th: (props) => React4.createElement("th", props),
1909
- Td: (props) => React4.createElement("td", props)
1910
- };
1911
- return { ...base, ...overrides || {} };
1912
- }
1913
- function mapHtmlToReact(html, elements) {
1914
- const parser = new DOMParser();
1915
- const doc = parser.parseFromString(html, "text/html");
1916
- const children = [];
1917
- doc.body.childNodes.forEach((node, index) => {
1918
- const element = toReact(node, elements, `root-${index}`);
1919
- if (element) {
1920
- children.push(element);
1921
- }
1922
- });
1923
- return React4.createElement(React4.Fragment, {}, ...children);
3130
+ return { ...{
3131
+ Table: (props) => React8.createElement("table", props),
3132
+ Thead: (props) => React8.createElement("thead", props),
3133
+ Tbody: (props) => React8.createElement("tbody", props),
3134
+ Tr: (props) => React8.createElement("tr", props),
3135
+ Th: (props) => React8.createElement("th", props),
3136
+ Td: (props) => React8.createElement("td", props)
3137
+ }, ...overrides || {} };
3138
+ }
3139
+ var DEFAULT_LITERAL_TAGS2 = /* @__PURE__ */ new Set(["code", "pre", "script", "style", "textarea"]);
3140
+ function mapHtmlToReact(html, elements, literalTagContent, parseMarkdown) {
3141
+ let ParserClass = typeof DOMParser < "u" ? DOMParser : typeof window < "u" ? window.DOMParser : void 0;
3142
+ if (!ParserClass) return null;
3143
+ let doc = new ParserClass().parseFromString(html, "text/html"), children = [], literalTags = literalTagContent ? /* @__PURE__ */ new Set([...DEFAULT_LITERAL_TAGS2, ...literalTagContent.map((t) => t.toLowerCase())]) : DEFAULT_LITERAL_TAGS2;
3144
+ return doc.body.childNodes.forEach((node, index) => {
3145
+ let element = toReact(node, elements, `root-${index}`, void 0, literalTags, !1, parseMarkdown);
3146
+ element && children.push(element);
3147
+ }), React8.createElement(React8.Fragment, {}, ...children);
1924
3148
  }
1925
- function toReact(node, elements, key) {
3149
+ var TABLE_TEXT_FORBIDDEN_PARENTS = /* @__PURE__ */ new Set(["table", "thead", "tbody", "tfoot", "tr", "colgroup"]);
3150
+ function toReact(node, elements, key, parentTag, literalTags, parentIsLiteral, parseMarkdown) {
1926
3151
  if (node.nodeType === Node.TEXT_NODE) {
1927
- const text = node.textContent ?? "";
1928
- return React4.createElement(React4.Fragment, { key }, text);
3152
+ let text = node.textContent ?? "";
3153
+ if (parentTag && TABLE_TEXT_FORBIDDEN_PARENTS.has(parentTag) && text.trim().length === 0)
3154
+ return null;
3155
+ let content = parentIsLiteral || !parseMarkdown ? text : parseMarkdown(text);
3156
+ return React8.createElement(React8.Fragment, { key }, content);
1929
3157
  }
1930
- if (node.nodeType !== Node.ELEMENT_NODE) {
3158
+ if (node.nodeType !== Node.ELEMENT_NODE)
1931
3159
  return null;
1932
- }
1933
- const el = node;
1934
- const tag = el.tagName.toLowerCase();
1935
- const props = {};
1936
- for (const attr of Array.from(el.attributes)) {
1937
- const name = attr.name === "class" ? "className" : attr.name;
3160
+ let el = node, tag = el.tagName.toLowerCase(), isLiteral = parentIsLiteral || (literalTags ? literalTags.has(tag) : !1), props = {};
3161
+ for (let attr of Array.from(el.attributes)) {
3162
+ let name = attr.name === "class" ? "className" : attr.name;
1938
3163
  props[name] = attr.value;
1939
3164
  }
1940
- const children = [];
3165
+ if (tag === "textarea")
3166
+ return React8.createElement(elements[tag] ?? tag, { ...props, key, defaultValue: el.textContent ?? "" });
3167
+ let children = [];
1941
3168
  el.childNodes.forEach((childNode, childIndex) => {
1942
- const child = toReact(childNode, elements, `${key}-${childIndex}`);
1943
- if (child) {
1944
- children.push(child);
1945
- }
3169
+ let child = toReact(childNode, elements, `${key}-${childIndex}`, tag, literalTags, isLiteral, parseMarkdown);
3170
+ child && children.push(child);
1946
3171
  });
1947
- const component = elements[tag];
1948
- const elementChildren = children.length > 0 ? children : void 0;
1949
- if (component) {
1950
- return React4.createElement(component, { ...props, key }, elementChildren);
1951
- }
1952
- return React4.createElement(tag, { ...props, key }, elementChildren);
3172
+ let component = elements[tag], elementChildren = children.length > 0 ? children : void 0;
3173
+ return component ? React8.createElement(component, { ...props, key }, elementChildren) : React8.createElement(tag, { ...props, key }, elementChildren);
1953
3174
  }
1954
3175
  function attrsToProps(attrs) {
1955
3176
  if (!attrs) return {};
1956
- const result = {};
1957
- for (const [key, value] of Object.entries(attrs)) {
1958
- if (key === "class") {
1959
- result.className = value;
1960
- } else if (key === "style") {
1961
- result.style = parseStyleAttribute2(value);
1962
- } else if (key === "tabindex" || key === "tabIndex") {
1963
- const numericValue = Number(value);
1964
- if (!Number.isNaN(numericValue)) {
1965
- result.tabIndex = numericValue;
1966
- }
1967
- } else {
1968
- result[key] = value;
1969
- }
3177
+ let result = {};
3178
+ for (let [key, value] of Object.entries(attrs)) {
3179
+ let lower = key.toLowerCase();
3180
+ if (!isForbiddenAttribute2(lower))
3181
+ if (key === "class")
3182
+ result.className = value;
3183
+ else if (key === "style")
3184
+ result.style = parseStyleAttribute2(value);
3185
+ else if (key === "tabindex" || key === "tabIndex") {
3186
+ let numericValue = Number(value);
3187
+ Number.isNaN(numericValue) || (result.tabIndex = numericValue);
3188
+ } else if (lower === "href") {
3189
+ let safe = defaultUrlTransform4(value, "href", { source: "html" });
3190
+ safe != null && (result.href = safe);
3191
+ } else if (lower === "src") {
3192
+ let safe = defaultUrlTransform4(value, "src", { source: "html" });
3193
+ safe != null && (result.src = safe);
3194
+ } else if (lower === "action") {
3195
+ let safe = defaultUrlTransform4(value, "href", { source: "html" });
3196
+ safe != null && (result.action = safe);
3197
+ } else if (lower === "formaction") {
3198
+ let safe = defaultUrlTransform4(value, "href", { source: "html" });
3199
+ safe != null && (result.formAction = safe);
3200
+ } else if (lower === "xlink:href" || lower === "xlinkhref") {
3201
+ let safe = defaultUrlTransform4(value, "href", { source: "html" });
3202
+ safe != null && (result.xlinkHref = safe);
3203
+ } else
3204
+ result[key] = value;
1970
3205
  }
1971
3206
  return result;
1972
3207
  }
@@ -1974,48 +3209,36 @@ function escapeHtml(value) {
1974
3209
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
1975
3210
  }
1976
3211
  function parseStyleAttribute2(value) {
1977
- const style = {};
3212
+ let style = {};
1978
3213
  if (!value) return style;
1979
- const parts = value.split(";");
1980
- for (const part of parts) {
3214
+ let parts = value.split(";");
3215
+ for (let part of parts) {
1981
3216
  if (!part.trim()) continue;
1982
- const [prop, val] = part.split(":");
1983
- if (!prop || !val) continue;
1984
- const camelProp = prop.trim().replace(/-([a-z])/g, (_, char) => char.toUpperCase());
1985
- style[camelProp] = val.trim();
3217
+ let separator = part.indexOf(":");
3218
+ if (separator <= 0) continue;
3219
+ let prop = part.slice(0, separator).trim(), val = part.slice(separator + 1).trim();
3220
+ if (!isSafeStyleDeclaration2(prop, val)) continue;
3221
+ let cssProperty = prop.startsWith("--") ? prop : prop.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
3222
+ style[cssProperty] = val;
1986
3223
  }
1987
3224
  return style;
1988
3225
  }
1989
- function renderParagraphMixedSegments(segments, inlineComponents, inlineHtmlRenderers) {
1990
- const result = [];
1991
- let inlineBuffer = [];
1992
- let inlineGroupIndex = 0;
1993
- const pushRenderedNodes = (nodes, target, baseKey) => {
3226
+ function renderParagraphMixedSegments(segments, inlineComponents, inlineHtmlRenderers, htmlElements, literalTagContent, urlTransform) {
3227
+ return renderMixedParagraphSegments(segments, inlineComponents, inlineHtmlRenderers, htmlElements, literalTagContent, urlTransform);
3228
+ }
3229
+ function renderMixedParagraphSegments(segments, inlineComponents, inlineHtmlRenderers, htmlElements, literalTagContent, urlTransform, registry, animationContext, htmlTrees, renderOwnedHtml) {
3230
+ let result = [], inlineBuffer = [], inlineGroupIndex = 0, pushRenderedNodes = (nodes, target, baseKey) => {
1994
3231
  nodes.forEach((node, idx) => {
1995
- if (node === null || node === void 0) return;
1996
- const key = `${baseKey}-${idx}`;
1997
- if (React4.isValidElement(node)) {
1998
- target.push(node.key === key ? node : React4.cloneElement(node, { key }));
1999
- } else if (typeof node === "string" || typeof node === "number") {
2000
- target.push(React4.createElement(React4.Fragment, { key }, node));
2001
- } else {
2002
- target.push(React4.createElement(React4.Fragment, { key }, node));
2003
- }
3232
+ if (node == null) return;
3233
+ let key = `${baseKey}-${idx}`;
3234
+ React8.isValidElement(node) ? target.push(node.key === key ? node : React8.cloneElement(node, { key })) : typeof node == "string" || typeof node == "number" ? target.push(React8.createElement(React8.Fragment, { key }, node)) : target.push(React8.createElement(React8.Fragment, { key }, node));
2004
3235
  });
2005
- };
2006
- const ensureArray = (value) => {
2007
- if (value === null || value === void 0) {
2008
- return [];
2009
- }
2010
- return Array.isArray(value) ? value : [value];
2011
- };
2012
- const flushInline = () => {
2013
- if (inlineBuffer.length === 0) {
3236
+ }, ensureArray = (value) => value == null ? [] : Array.isArray(value) ? value : [value], flushInline = () => {
3237
+ if (inlineBuffer.length === 0)
2014
3238
  return;
2015
- }
2016
- const key = `paragraph-inline-group-${inlineGroupIndex++}`;
3239
+ let key = `paragraph-inline-group-${inlineGroupIndex++}`;
2017
3240
  result.push(
2018
- React4.createElement(
3241
+ React8.createElement(
2019
3242
  "p",
2020
3243
  {
2021
3244
  key,
@@ -2023,109 +3246,90 @@ function renderParagraphMixedSegments(segments, inlineComponents, inlineHtmlRend
2023
3246
  },
2024
3247
  inlineBuffer
2025
3248
  )
2026
- );
2027
- inlineBuffer = [];
3249
+ ), inlineBuffer = [];
2028
3250
  };
2029
- segments.forEach((segment, index) => {
2030
- const key = `paragraph-segment-${index}`;
3251
+ return segments.forEach((segment, index) => {
3252
+ let key = `paragraph-segment-${index}`;
2031
3253
  switch (segment.kind) {
2032
3254
  case "text": {
2033
- const inlineNodes = Array.isArray(segment.inline) ? segment.inline : [];
3255
+ let inlineNodes = Array.isArray(segment.inline) ? segment.inline : [];
2034
3256
  if (inlineNodes.length === 0) {
2035
- if (segment.value) {
2036
- inlineBuffer.push(React4.createElement(React4.Fragment, { key }, segment.value));
2037
- }
3257
+ segment.value && inlineBuffer.push(React8.createElement(React8.Fragment, { key }, segment.value));
2038
3258
  break;
2039
3259
  }
2040
- let chunk = [];
2041
- const pushChunk = (chunkNodes, chunkKey) => {
3260
+ let chunk = [], pushChunk = (chunkNodes, chunkKey) => {
2042
3261
  if (chunkNodes.length === 0) return;
2043
- const rendered = renderInlineNodes(chunkNodes, inlineComponents);
3262
+ let rendered = renderInlineNodes(chunkNodes, inlineComponents, urlTransform, registry, "p", animationContext);
2044
3263
  pushRenderedNodes(ensureArray(rendered), inlineBuffer, chunkKey);
2045
3264
  };
2046
3265
  inlineNodes.forEach((inlineNode, inlineIdx) => {
2047
3266
  if (inlineNode.kind === "math-display") {
2048
- pushChunk(chunk, `${key}-chunk-${inlineIdx}`);
2049
- chunk = [];
2050
- flushInline();
2051
- const rendered = renderInlineNodes([inlineNode], inlineComponents);
3267
+ pushChunk(chunk, `${key}-chunk-${inlineIdx}`), chunk = [], flushInline();
3268
+ let rendered = renderInlineNodes([inlineNode], inlineComponents, urlTransform, registry, "p", animationContext);
2052
3269
  pushRenderedNodes(ensureArray(rendered), result, `${key}-math-${inlineIdx}`);
2053
- } else {
3270
+ } else
2054
3271
  chunk.push(inlineNode);
2055
- }
2056
- });
2057
- pushChunk(chunk, `${key}-chunk-tail`);
3272
+ }), pushChunk(chunk, `${key}-chunk-tail`);
2058
3273
  break;
2059
3274
  }
2060
3275
  case "mdx": {
2061
- const status = segment.status ?? "pending";
2062
- let element;
2063
- if (status === "compiled") {
2064
- element = React4.createElement("span", { className: "markdown-mdx-inline", "data-mdx-status": "compiled" });
2065
- } else if (status === "error") {
2066
- const message = segment.value || "MDX error";
2067
- element = React4.createElement("span", { className: "markdown-mdx-inline text-destructive", "data-mdx-status": "error" }, message);
2068
- } else {
2069
- element = React4.createElement("span", { className: "markdown-mdx-inline", "data-mdx-status": status }, segment.value);
2070
- }
2071
- inlineBuffer.push(React4.createElement(React4.Fragment, { key }, element));
3276
+ let element = React8.createElement("span", { className: "markdown-mdx-inline" }, segment.value);
3277
+ inlineBuffer.push(React8.createElement(React8.Fragment, { key }, element));
2072
3278
  break;
2073
3279
  }
2074
3280
  case "html": {
2075
- const html = segment.sanitized ?? segment.value;
2076
- const isBlockLevel = isBlockLevelHtml(html);
2077
- const element = renderInlineHtmlSegment(segment.value, segment.sanitized, {
3281
+ let html = segment.sanitized ?? segment.value, isBlockLevel = isBlockLevelHtml(html);
3282
+ if (registry && htmlTrees?.[index] !== void 0) {
3283
+ let rendered = renderOwnedHtml ? renderOwnedHtml(htmlTrees[index]) : registry.renderHtmlTree(htmlTrees[index]);
3284
+ isBlockLevel ? (flushInline(), pushRenderedNodes(ensureArray(rendered), result, key)) : pushRenderedNodes(ensureArray(rendered), inlineBuffer, key);
3285
+ break;
3286
+ }
3287
+ let parseMarkdown = (text) => !text || !text.includes("*") && !text.includes("_") && !text.includes("[") && !text.includes("`") && !text.includes("#") ? text : renderInlineNodes(new InlineParser().parse(text), inlineComponents, urlTransform, registry, "p", animationContext), element = renderInlineHtmlSegment(segment.value, segment.sanitized, {
2078
3288
  key,
2079
- renderers: inlineHtmlRenderers
3289
+ renderers: inlineHtmlRenderers,
3290
+ htmlElements,
3291
+ literalTagContent,
3292
+ urlTransform,
3293
+ parseMarkdown
2080
3294
  });
2081
- if (isBlockLevel) {
2082
- flushInline();
2083
- if (element) {
2084
- result.push(element);
2085
- } else if (html) {
2086
- result.push(
2087
- React4.createElement("div", {
2088
- key,
2089
- className: "markdown-inline-html-block",
2090
- dangerouslySetInnerHTML: { __html: html }
2091
- })
2092
- );
2093
- }
2094
- } else if (element) {
2095
- inlineBuffer.push(element);
2096
- }
3295
+ isBlockLevel ? (flushInline(), element ? result.push(element) : html && result.push(
3296
+ React8.createElement("div", {
3297
+ key,
3298
+ className: "markdown-inline-html-block",
3299
+ dangerouslySetInnerHTML: { __html: html }
3300
+ })
3301
+ )) : element ? inlineBuffer.push(element) : html && inlineBuffer.push(
3302
+ React8.createElement("span", {
3303
+ key,
3304
+ className: "markdown-inline-html",
3305
+ dangerouslySetInnerHTML: { __html: html }
3306
+ })
3307
+ );
2097
3308
  break;
2098
3309
  }
2099
3310
  default:
2100
3311
  break;
2101
3312
  }
2102
- });
2103
- flushInline();
2104
- if (result.length === 0) {
2105
- return [
2106
- React4.createElement(
2107
- "p",
2108
- {
2109
- key: "paragraph-inline-group-0",
2110
- className: "markdown-paragraph"
2111
- },
2112
- inlineBuffer
2113
- )
2114
- ];
2115
- }
2116
- return result;
3313
+ }), flushInline(), result.length === 0 ? [
3314
+ React8.createElement(
3315
+ "p",
3316
+ {
3317
+ key: "paragraph-inline-group-0",
3318
+ className: "markdown-paragraph"
3319
+ },
3320
+ inlineBuffer
3321
+ )
3322
+ ] : result;
2117
3323
  }
2118
3324
  function isBlockLevelHtml(html) {
2119
- if (!html) return false;
2120
- const trimmed = html.trim();
2121
- if (!trimmed.startsWith("<")) {
2122
- return false;
2123
- }
2124
- const match = trimmed.match(/^<([A-Za-z][\w:-]*)\b/);
2125
- if (!match) {
2126
- return false;
2127
- }
2128
- const tag = match[1].toLowerCase();
3325
+ if (!html) return !1;
3326
+ let trimmed = html.trim();
3327
+ if (!trimmed.startsWith("<"))
3328
+ return !1;
3329
+ let match = trimmed.match(/^<([A-Za-z][\w:-]*)\b/);
3330
+ if (!match)
3331
+ return !1;
3332
+ let tag = match[1].toLowerCase();
2129
3333
  return BLOCK_LEVEL_TAGS.has(tag);
2130
3334
  }
2131
3335
  var BLOCK_LEVEL_TAGS = /* @__PURE__ */ new Set([
@@ -2161,12 +3365,45 @@ var BLOCK_LEVEL_TAGS = /* @__PURE__ */ new Set([
2161
3365
  "math"
2162
3366
  ]);
2163
3367
  export {
3368
+ AnimationTimeline,
2164
3369
  BottomStickScrollArea,
3370
+ CodeBlockCopyButton,
3371
+ CodeBlockDownloadButton,
3372
+ CodeControlsBar,
2165
3373
  ComponentRegistry,
3374
+ DEFAULT_ANIMATED_OPTIONS,
3375
+ DEFAULT_CONTROLS_LABELS,
3376
+ DefaultDiffRenderer,
2166
3377
  DefaultLinkSafetyModal,
2167
- defaultBlockComponents,
3378
+ DocumentMathMacroScope,
3379
+ DocumentMathMacroScopeContext,
3380
+ KaTeXBlockMath,
3381
+ KaTeXInlineMath,
3382
+ LANGUAGE_EXTENSION_MAP,
3383
+ MathExpressionCompletenessContext,
3384
+ STREAM_MDX_ANIMATION_CSS,
3385
+ TableControlsBar,
3386
+ copyToClipboard,
2168
3387
  defaultInlineComponents,
3388
+ defaultUrlTransform3 as defaultUrlTransform,
3389
+ downloadFile,
3390
+ escapeCsvCell,
3391
+ escapeTsvCell,
3392
+ getCodeSnippetFilename,
3393
+ getExtensionForLanguage,
3394
+ inlineToPlainText,
3395
+ loadKaTeX,
2169
3396
  mapHtmlToReact,
2170
3397
  renderInlineNodes,
2171
- renderParagraphMixedSegments
3398
+ renderParagraphMixedSegments,
3399
+ resolveAnimatedOptions,
3400
+ resolveCodeControls,
3401
+ resolveControlsConfig,
3402
+ resolveMermaidControls,
3403
+ resolveTableControls,
3404
+ splitTextSegments,
3405
+ splitWordSegments,
3406
+ tableToCsv,
3407
+ tableToMarkdown,
3408
+ tableToTsv
2172
3409
  };