@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
@@ -0,0 +1,358 @@
1
+ "use client";
2
+
3
+ /**
4
+ * ShadCN-style drop-in component.
5
+ *
6
+ * Copy this file into your app (for example: `components/ui/bottom-stick-scroll-area.tsx`)
7
+ * and adjust import paths for `Button`, `ScrollBar`, and `cn` as needed.
8
+ */
9
+
10
+ import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
11
+ import { ChevronDown } from "lucide-react";
12
+ import type { ReactNode, UIEvent } from "react";
13
+ import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
14
+
15
+ import { Button } from "@/components/ui/button";
16
+ import { ScrollBar } from "@/components/ui/scroll-area";
17
+ import { cn } from "@/lib/utils";
18
+
19
+ export type BottomStickMode = "STICKY_INSTANT" | "DETACHED" | "RETURNING_SMOOTH";
20
+
21
+ export type BottomStickDebugState = {
22
+ mode: BottomStickMode;
23
+ isOverflowing: boolean;
24
+ distanceToBottom: number;
25
+ scrollTop: number;
26
+ maxScrollTop: number;
27
+ scrollHeight: number;
28
+ clientHeight: number;
29
+ programmaticWrites: number;
30
+ };
31
+
32
+ export type BottomStickScrollAreaProps = {
33
+ children: ReactNode;
34
+ className?: string;
35
+ contentClassName?: string;
36
+ showScrollBar?: boolean;
37
+ showJumpToBottom?: boolean;
38
+ onDebugStateChange?: (state: BottomStickDebugState) => void;
39
+ debugDomAttributes?: boolean;
40
+ };
41
+
42
+ const EPS_BOTTOM_PX = 2;
43
+ const EPS_OVERFLOW_PX = 1;
44
+ const DETACH_SCROLL_DELTA_PX = 4;
45
+ const RETURN_MIN_MS = 180;
46
+ const RETURN_MAX_MS = 520;
47
+ const RETURN_PX_PER_MS = 2.2;
48
+ const RETURN_SETTLE_FRAMES = 2;
49
+
50
+ function clamp01(value: number) {
51
+ if (value < 0) return 0;
52
+ if (value > 1) return 1;
53
+ return value;
54
+ }
55
+
56
+ function easeOutCubic(value: number) {
57
+ return 1 - (1 - value) ** 3;
58
+ }
59
+
60
+ function measure(viewport: HTMLDivElement) {
61
+ const scrollTop = viewport.scrollTop;
62
+ const scrollHeight = viewport.scrollHeight;
63
+ const clientHeight = viewport.clientHeight;
64
+ const maxScrollTop = Math.max(0, scrollHeight - clientHeight);
65
+ const distanceToBottom = Math.max(0, maxScrollTop - scrollTop);
66
+ const isOverflowing = scrollHeight > clientHeight + EPS_OVERFLOW_PX;
67
+
68
+ return { scrollTop, scrollHeight, clientHeight, maxScrollTop, distanceToBottom, isOverflowing };
69
+ }
70
+
71
+ export function BottomStickScrollArea({
72
+ children,
73
+ className,
74
+ contentClassName,
75
+ showScrollBar = true,
76
+ showJumpToBottom = true,
77
+ onDebugStateChange,
78
+ debugDomAttributes = false,
79
+ }: BottomStickScrollAreaProps) {
80
+ const viewportRef = useRef<HTMLDivElement>(null);
81
+ const contentRef = useRef<HTMLDivElement>(null);
82
+
83
+ const modeRef = useRef<BottomStickMode>("STICKY_INSTANT");
84
+ const [mode, setMode] = useState<BottomStickMode>("STICKY_INSTANT");
85
+ const [isOverflowing, setIsOverflowing] = useState(false);
86
+
87
+ const prevScrollTopRef = useRef(0);
88
+ const lastProgrammaticWriteRef = useRef<{ at: number; top: number } | null>(null);
89
+ const programmaticWriteCountRef = useRef(0);
90
+
91
+ const pendingStickRafRef = useRef<number | null>(null);
92
+ const stickRequestedRef = useRef(false);
93
+
94
+ const returnRafRef = useRef<number | null>(null);
95
+ const returnAnimRef = useRef<{
96
+ startTime: number;
97
+ startTop: number;
98
+ durationMs: number;
99
+ settleFrames: number;
100
+ } | null>(null);
101
+
102
+ const setModeBoth = useCallback((next: BottomStickMode) => {
103
+ modeRef.current = next;
104
+ setMode(next);
105
+ }, []);
106
+
107
+ const updateDebug = useCallback(() => {
108
+ const viewport = viewportRef.current;
109
+ if (!viewport) return;
110
+
111
+ const m = measure(viewport);
112
+ if (debugDomAttributes) {
113
+ viewport.dataset.stickyMode = modeRef.current;
114
+ viewport.dataset.distanceToBottom = String(m.distanceToBottom);
115
+ viewport.dataset.isOverflowing = m.isOverflowing ? "1" : "0";
116
+ viewport.dataset.programmaticWrites = String(programmaticWriteCountRef.current);
117
+ }
118
+ onDebugStateChange?.({
119
+ mode: modeRef.current,
120
+ isOverflowing: m.isOverflowing,
121
+ distanceToBottom: m.distanceToBottom,
122
+ scrollTop: m.scrollTop,
123
+ maxScrollTop: m.maxScrollTop,
124
+ scrollHeight: m.scrollHeight,
125
+ clientHeight: m.clientHeight,
126
+ programmaticWrites: programmaticWriteCountRef.current,
127
+ });
128
+ }, [debugDomAttributes, onDebugStateChange]);
129
+
130
+ const writeScrollTop = useCallback((nextTop: number) => {
131
+ const viewport = viewportRef.current;
132
+ if (!viewport) return;
133
+ viewport.scrollTop = nextTop;
134
+ programmaticWriteCountRef.current += 1;
135
+ lastProgrammaticWriteRef.current = { at: performance.now(), top: nextTop };
136
+ }, []);
137
+
138
+ const cancelPendingStick = useCallback(() => {
139
+ if (pendingStickRafRef.current !== null) {
140
+ cancelAnimationFrame(pendingStickRafRef.current);
141
+ pendingStickRafRef.current = null;
142
+ }
143
+ stickRequestedRef.current = false;
144
+ }, []);
145
+
146
+ const cancelReturn = useCallback(() => {
147
+ if (returnRafRef.current !== null) {
148
+ cancelAnimationFrame(returnRafRef.current);
149
+ returnRafRef.current = null;
150
+ }
151
+ returnAnimRef.current = null;
152
+ }, []);
153
+
154
+ const stickToBottomInstant = useCallback(() => {
155
+ const viewport = viewportRef.current;
156
+ if (!viewport) return;
157
+
158
+ stickRequestedRef.current = true;
159
+ if (pendingStickRafRef.current !== null) return;
160
+
161
+ pendingStickRafRef.current = requestAnimationFrame(() => {
162
+ pendingStickRafRef.current = null;
163
+ if (!stickRequestedRef.current) return;
164
+ stickRequestedRef.current = false;
165
+
166
+ if (modeRef.current !== "STICKY_INSTANT") return;
167
+ const m = measure(viewport);
168
+ writeScrollTop(m.maxScrollTop);
169
+ updateDebug();
170
+ });
171
+ }, [updateDebug, writeScrollTop]);
172
+
173
+ const startReturnToBottomSmooth = useCallback(() => {
174
+ const viewport = viewportRef.current;
175
+ if (!viewport) return;
176
+
177
+ cancelPendingStick();
178
+ cancelReturn();
179
+
180
+ const initial = measure(viewport);
181
+ if (initial.distanceToBottom <= EPS_BOTTOM_PX) {
182
+ setModeBoth("STICKY_INSTANT");
183
+ stickToBottomInstant();
184
+ updateDebug();
185
+ return;
186
+ }
187
+
188
+ const durationMs = Math.max(
189
+ RETURN_MIN_MS,
190
+ Math.min(RETURN_MAX_MS, initial.distanceToBottom / RETURN_PX_PER_MS),
191
+ );
192
+
193
+ returnAnimRef.current = {
194
+ startTime: performance.now(),
195
+ startTop: initial.scrollTop,
196
+ durationMs,
197
+ settleFrames: 0,
198
+ };
199
+ setModeBoth("RETURNING_SMOOTH");
200
+
201
+ const tick = (now: number) => {
202
+ const viewportCurrent = viewportRef.current;
203
+ const anim = returnAnimRef.current;
204
+ if (!viewportCurrent || !anim || modeRef.current !== "RETURNING_SMOOTH") {
205
+ cancelReturn();
206
+ return;
207
+ }
208
+
209
+ const before = measure(viewportCurrent);
210
+ const progress = clamp01((now - anim.startTime) / anim.durationMs);
211
+ const eased = easeOutCubic(progress);
212
+ const targetBottom = before.maxScrollTop;
213
+ let nextTop = anim.startTop + (targetBottom - anim.startTop) * eased;
214
+
215
+ if (nextTop < before.scrollTop) {
216
+ nextTop = before.scrollTop;
217
+ }
218
+
219
+ writeScrollTop(nextTop);
220
+
221
+ const after = measure(viewportCurrent);
222
+ if (after.distanceToBottom <= EPS_BOTTOM_PX) {
223
+ anim.settleFrames += 1;
224
+ } else {
225
+ anim.settleFrames = 0;
226
+ }
227
+
228
+ const doneByTime = progress >= 1;
229
+ const doneBySettle = anim.settleFrames >= RETURN_SETTLE_FRAMES && progress >= 0.6;
230
+ if (doneByTime && doneBySettle) {
231
+ cancelReturn();
232
+ setModeBoth("STICKY_INSTANT");
233
+ stickToBottomInstant();
234
+ updateDebug();
235
+ return;
236
+ }
237
+
238
+ updateDebug();
239
+ returnRafRef.current = requestAnimationFrame(tick);
240
+ };
241
+
242
+ returnRafRef.current = requestAnimationFrame(tick);
243
+ }, [cancelPendingStick, cancelReturn, setModeBoth, stickToBottomInstant, updateDebug, writeScrollTop]);
244
+
245
+ const onViewportScroll = useCallback(
246
+ (event: UIEvent<HTMLDivElement>) => {
247
+ const viewport = event.currentTarget;
248
+ const m = measure(viewport);
249
+
250
+ setIsOverflowing((previous) => (previous === m.isOverflowing ? previous : m.isOverflowing));
251
+
252
+ const previousTop = prevScrollTopRef.current;
253
+ const delta = m.scrollTop - previousTop;
254
+
255
+ const lastWrite = lastProgrammaticWriteRef.current;
256
+ const wroteRecently = lastWrite !== null && performance.now() - lastWrite.at < 60;
257
+ const isLikelyOwnWrite = wroteRecently && lastWrite !== null && Math.abs(m.scrollTop - lastWrite.top) <= 2;
258
+
259
+ if (modeRef.current === "RETURNING_SMOOTH") {
260
+ if (!isLikelyOwnWrite && delta < -DETACH_SCROLL_DELTA_PX) {
261
+ cancelReturn();
262
+ setModeBoth("DETACHED");
263
+ }
264
+ } else if (modeRef.current === "STICKY_INSTANT") {
265
+ if (!isLikelyOwnWrite && delta < -DETACH_SCROLL_DELTA_PX && m.isOverflowing) {
266
+ cancelPendingStick();
267
+ setModeBoth("DETACHED");
268
+ }
269
+ } else if (modeRef.current === "DETACHED") {
270
+ if (m.distanceToBottom <= EPS_BOTTOM_PX) {
271
+ setModeBoth("STICKY_INSTANT");
272
+ stickToBottomInstant();
273
+ }
274
+ }
275
+
276
+ prevScrollTopRef.current = m.scrollTop;
277
+ updateDebug();
278
+ },
279
+ [cancelPendingStick, cancelReturn, setModeBoth, stickToBottomInstant, updateDebug],
280
+ );
281
+
282
+ useEffect(() => {
283
+ const viewport = viewportRef.current;
284
+ const content = contentRef.current;
285
+ if (!viewport || !content) return;
286
+
287
+ const observer = new ResizeObserver(() => {
288
+ const m = measure(viewport);
289
+ setIsOverflowing((previous) => (previous === m.isOverflowing ? previous : m.isOverflowing));
290
+
291
+ if (modeRef.current === "STICKY_INSTANT") {
292
+ stickToBottomInstant();
293
+ }
294
+
295
+ updateDebug();
296
+ });
297
+
298
+ observer.observe(content);
299
+ observer.observe(viewport);
300
+ return () => observer.disconnect();
301
+ }, [stickToBottomInstant, updateDebug]);
302
+
303
+ useLayoutEffect(() => {
304
+ const viewport = viewportRef.current;
305
+ if (!viewport) return;
306
+
307
+ setModeBoth("STICKY_INSTANT");
308
+ const initial = measure(viewport);
309
+ writeScrollTop(initial.maxScrollTop);
310
+ prevScrollTopRef.current = viewport.scrollTop;
311
+ setIsOverflowing(initial.isOverflowing);
312
+ updateDebug();
313
+ }, [setModeBoth, updateDebug, writeScrollTop]);
314
+
315
+ useEffect(() => {
316
+ return () => {
317
+ cancelPendingStick();
318
+ cancelReturn();
319
+ };
320
+ }, [cancelPendingStick, cancelReturn]);
321
+
322
+ const showJumpButton = showJumpToBottom && isOverflowing && mode === "DETACHED";
323
+
324
+ return (
325
+ <ScrollAreaPrimitive.Root className={cn("relative h-full w-full overflow-hidden", className)}>
326
+ <ScrollAreaPrimitive.Viewport
327
+ ref={viewportRef}
328
+ className="h-full w-full rounded-[inherit]"
329
+ onScroll={onViewportScroll}
330
+ data-testid="sticky-scroll-viewport"
331
+ >
332
+ <div ref={contentRef} className={cn("flex min-h-full w-full flex-col", contentClassName)}>
333
+ {children}
334
+ </div>
335
+ </ScrollAreaPrimitive.Viewport>
336
+
337
+ {showJumpToBottom ? (
338
+ <div className="pointer-events-none absolute inset-x-0 bottom-3 z-20 flex justify-center">
339
+ <Button
340
+ type="button"
341
+ variant="secondary"
342
+ onClick={startReturnToBottomSmooth}
343
+ data-testid="sticky-scroll-jump"
344
+ className={cn(
345
+ "z-10 h-10 w-10 rounded-full p-0 shadow-base shadow-secondary transition-all duration-150",
346
+ showJumpButton ? "translate-y-0 opacity-100 pointer-events-auto" : "translate-y-1 opacity-0 pointer-events-none",
347
+ )}
348
+ aria-label="Scroll to bottom"
349
+ >
350
+ <ChevronDown className="h-4 w-4 text-primary" />
351
+ </Button>
352
+ </div>
353
+ ) : null}
354
+
355
+ <ScrollBar className={cn(showScrollBar ? "opacity-100" : "opacity-0")} orientation="vertical" />
356
+ </ScrollAreaPrimitive.Root>
357
+ );
358
+ }
@@ -1,248 +0,0 @@
1
- import { InlineNode, TokenLineV1, CompiledMdxModule, InlineHtmlDescriptor, Block, LazyTokenizationPriority, FormatAnticipationConfig, CodeHighlightingMode, CodeHighlightOutputMode, MixedContentSegment } from '@stream-mdx/core';
2
- import React from 'react';
3
-
4
- type GenericComponent = React.ComponentType<any>;
5
- interface TableElements {
6
- Table: GenericComponent;
7
- Thead: GenericComponent;
8
- Tbody: GenericComponent;
9
- Tr: GenericComponent;
10
- Th: GenericComponent;
11
- Td: GenericComponent;
12
- }
13
- type HtmlElements = Record<string, GenericComponent>;
14
- type InlineHtmlRenderer = (descriptor: InlineHtmlDescriptor, context: {
15
- key?: React.Key;
16
- defaultRender: () => React.ReactElement | null;
17
- }) => React.ReactElement | null;
18
- type InlineHtmlRendererMap = Record<string, InlineHtmlRenderer>;
19
- interface BlockComponents {
20
- paragraph: React.FC<{
21
- inlines: InlineNode[];
22
- raw?: string;
23
- meta?: Record<string, unknown>;
24
- children?: React.ReactNode;
25
- }>;
26
- heading: React.FC<{
27
- level: 1 | 2 | 3 | 4 | 5 | 6;
28
- inlines: InlineNode[];
29
- text?: string;
30
- meta?: Record<string, unknown>;
31
- }>;
32
- code: React.FC<{
33
- html: string;
34
- meta?: Record<string, unknown>;
35
- lines?: ReadonlyArray<{
36
- id: string;
37
- index: number;
38
- text: string;
39
- html?: string | null;
40
- tokens?: TokenLineV1 | null;
41
- }>;
42
- lang?: string;
43
- preAttrs?: Record<string, string>;
44
- codeAttrs?: Record<string, string>;
45
- }>;
46
- blockquote: React.FC<{
47
- inlines: InlineNode[];
48
- renderedContent?: React.ReactNode;
49
- }>;
50
- list: React.FC<{
51
- ordered: boolean;
52
- items: InlineNode[][];
53
- }>;
54
- html: React.FC<{
55
- __trustedHtml: TrustedHTML | string;
56
- elements?: Record<string, GenericComponent>;
57
- }>;
58
- mdx: React.FC<{
59
- compiledRef?: {
60
- id: string;
61
- };
62
- compiledModule?: CompiledMdxModule | null;
63
- status?: "pending" | "compiled" | "error";
64
- errorMessage?: string;
65
- raw?: string;
66
- }>;
67
- hr: React.FC<React.HTMLAttributes<HTMLHRElement>>;
68
- table: React.FC<{
69
- header?: InlineNode[][];
70
- rows: InlineNode[][][];
71
- align?: Array<"left" | "center" | "right" | null>;
72
- elements?: Partial<TableElements>;
73
- }>;
74
- [k: string]: GenericComponent;
75
- }
76
- type InlineComponents = Record<string, GenericComponent> & {
77
- text: React.FC<{
78
- text: string;
79
- }>;
80
- strong: React.FC<{
81
- children: React.ReactNode;
82
- }>;
83
- em: React.FC<{
84
- children: React.ReactNode;
85
- }>;
86
- strike?: React.FC<{
87
- children: React.ReactNode;
88
- }>;
89
- code: React.FC<{
90
- text: string;
91
- }>;
92
- link: React.FC<{
93
- href?: string;
94
- title?: string;
95
- children: React.ReactNode;
96
- }>;
97
- image: React.FC<{
98
- src: string;
99
- alt?: string;
100
- title?: string;
101
- }>;
102
- br: React.FC<Record<string, never>>;
103
- };
104
- interface RendererConfig {
105
- themes?: {
106
- light: string;
107
- dark: string;
108
- };
109
- highlight?: {
110
- browserEngine?: "js" | "wasm";
111
- serverEngine?: "wasm";
112
- langs?: string[];
113
- };
114
- sanitization?: {
115
- schemaId?: string;
116
- };
117
- mdx?: {
118
- enabled?: boolean;
119
- compileEndpoint?: string;
120
- compileStrategy?: "server" | "worker";
121
- components?: Record<string, GenericComponent>;
122
- };
123
- plugins?: {
124
- footnotes?: boolean;
125
- html?: boolean;
126
- mdx?: boolean;
127
- tables?: boolean;
128
- callouts?: boolean;
129
- math?: boolean;
130
- formatAnticipation?: FormatAnticipationConfig;
131
- codeHighlighting?: CodeHighlightingMode;
132
- outputMode?: CodeHighlightOutputMode;
133
- liveCodeHighlighting?: boolean;
134
- liveTokenization?: boolean;
135
- emitHighlightTokens?: boolean;
136
- emitDiffBlocks?: boolean;
137
- };
138
- performance?: {
139
- frameBudgetMs?: number;
140
- flushTimeoutMs?: number;
141
- maxBatchesPerFlush?: number;
142
- maxLowPriorityBatchesPerFlush?: number;
143
- lowPriorityFrameBudgetMs?: number;
144
- urgentQueueThreshold?: number;
145
- batch?: "rAF" | "microtask" | "timeout";
146
- historyLimit?: number;
147
- };
148
- }
149
- interface RendererStore {
150
- reset(blocks: Block[]): void;
151
- getBlocks(): ReadonlyArray<Block>;
152
- getVersion(): number;
153
- subscribe(listener: () => void): () => void;
154
- }
155
- type CodeHighlightRangeRequest = {
156
- blockId: string;
157
- startLine: number;
158
- endLine: number;
159
- priority?: LazyTokenizationPriority;
160
- };
161
- interface Renderer {
162
- attachWorker(worker: Worker, options?: {
163
- skipInit?: boolean;
164
- }): void;
165
- append(text: string): void;
166
- renderStatic(text: string): Promise<Block[]>;
167
- onUpdate(cb: (blocks: ReadonlyArray<Block>) => void): () => void;
168
- setBlockComponents(map: Partial<BlockComponents>): void;
169
- setInlineComponents(map: Partial<InlineComponents>): void;
170
- setMdxComponents(map: Record<string, GenericComponent>): void;
171
- getComponentRegistry(): ComponentRegistry;
172
- getStore(): RendererStore;
173
- requestCodeHighlightRange(request: CodeHighlightRangeRequest): void;
174
- }
175
-
176
- type LinkSafetyModalProps = {
177
- url: string;
178
- isOpen: boolean;
179
- isChecking?: boolean;
180
- onClose: () => void;
181
- onConfirm: () => void;
182
- onCopy: () => void;
183
- };
184
- declare const DefaultLinkSafetyModal: React.FC<LinkSafetyModalProps>;
185
-
186
- /**
187
- * Render inline nodes to React elements
188
- */
189
- declare function renderInlineNodes(nodes: InlineNode[], components: InlineComponents): React.ReactNode;
190
- /**
191
- * Default inline components
192
- */
193
- declare const defaultInlineComponents: InlineComponents;
194
- /**
195
- * Default block components
196
- */
197
- declare const defaultBlockComponents: BlockComponents;
198
- /**
199
- * Component registry that allows customization
200
- */
201
- declare class ComponentRegistry {
202
- private blockComponents;
203
- private inlineComponents;
204
- private htmlElements;
205
- private tableElements;
206
- private blockComponentMapCache;
207
- private inlineComponentMapCache;
208
- constructor(blockComponents?: Partial<BlockComponents>, inlineComponents?: Partial<InlineComponents>);
209
- /**
210
- * Update block components
211
- */
212
- setBlockComponents(components: Partial<BlockComponents>): void;
213
- /**
214
- * Update inline components
215
- */
216
- setInlineComponents(components: Partial<InlineComponents>): void;
217
- /** Update HTML element mapping for html blocks */
218
- setHtmlElements(map: Partial<HtmlElements>): void;
219
- /** Update table element mapping for table blocks */
220
- setTableElements(map: Partial<TableElements>): void;
221
- /**
222
- * Get block component
223
- */
224
- getBlockComponent(type: string): React.ComponentType<Record<string, unknown>>;
225
- /**
226
- * Get inline components
227
- */
228
- getInlineComponents(): InlineComponents;
229
- getBlockComponentMap(): BlockComponents;
230
- getInlineComponentMap(): InlineComponents;
231
- getTableElements(): TableElements;
232
- /**
233
- * Render a block
234
- */
235
- renderBlock(block: Block): React.ReactElement;
236
- /**
237
- * Get props for a block based on its type
238
- */
239
- private getBlockProps;
240
- /**
241
- * Extract heading level from raw markdown
242
- */
243
- private extractHeadingLevel;
244
- }
245
- declare function mapHtmlToReact(html: string, elements: HtmlElements): React.ReactNode;
246
- declare function renderParagraphMixedSegments(segments: MixedContentSegment[], inlineComponents: InlineComponents, inlineHtmlRenderers: InlineHtmlRendererMap): React.ReactNode[];
247
-
248
- export { type BlockComponents as B, ComponentRegistry as C, DefaultLinkSafetyModal as D, type HtmlElements as H, type InlineHtmlRendererMap as I, type LinkSafetyModalProps as L, type Renderer as R, type TableElements as T, type InlineComponents as a, type InlineHtmlRenderer as b, type RendererConfig as c, defaultInlineComponents as d, defaultBlockComponents as e, renderParagraphMixedSegments as f, type CodeHighlightRangeRequest as g, mapHtmlToReact as m, renderInlineNodes as r };