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