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