@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.
- package/CHANGELOG.md +385 -4
- package/README.md +141 -16
- package/dist/blocks-renderer-DAOBFBfi.d.ts +29 -0
- package/dist/blocks-renderer-DQEL1kJW.d.cts +29 -0
- package/dist/components/bottom-stick-scroll-area.cjs +268 -0
- package/dist/components/bottom-stick-scroll-area.d.cts +36 -0
- package/dist/components/bottom-stick-scroll-area.d.ts +36 -0
- package/dist/components/bottom-stick-scroll-area.mjs +249 -0
- package/dist/components/diff-renderer.cjs +86 -0
- package/dist/components/diff-renderer.d.cts +11 -0
- package/dist/components/diff-renderer.d.ts +11 -0
- package/dist/components/diff-renderer.mjs +66 -0
- package/dist/components/index.cjs +2879 -1295
- package/dist/components/index.d.cts +9 -2
- package/dist/components/index.d.ts +9 -2
- package/dist/components/index.mjs +2842 -1277
- package/dist/components/katex-math.cjs +220 -0
- package/dist/components/katex-math.d.cts +10 -0
- package/dist/components/katex-math.d.ts +10 -0
- package/dist/components/katex-math.mjs +188 -0
- package/dist/contexts/math-tracker.cjs +240 -521
- package/dist/contexts/math-tracker.mjs +235 -513
- package/dist/index-Cmne1yUK.d.cts +723 -0
- package/dist/index-D7dyyu3q.d.ts +723 -0
- package/dist/index.cjs +13180 -5640
- package/dist/index.d.cts +72 -40
- package/dist/index.d.ts +72 -40
- package/dist/index.mjs +12587 -5038
- package/dist/math/display-wrapper.cjs +7 -15
- package/dist/math/display-wrapper.d.cts +2 -2
- package/dist/math/display-wrapper.d.ts +2 -2
- package/dist/math/display-wrapper.mjs +2 -6
- package/dist/node-views-Bpc6Gkgl.d.cts +13 -0
- package/dist/node-views-DpnYdaAS.d.ts +13 -0
- package/dist/renderer/hooks.cjs +35 -20
- package/dist/renderer/hooks.d.cts +22 -1
- package/dist/renderer/hooks.d.ts +22 -1
- package/dist/renderer/hooks.mjs +27 -12
- package/dist/renderer/patch-batching.cjs +7 -8
- package/dist/renderer/patch-batching.d.cts +1 -1
- package/dist/renderer/patch-batching.d.ts +1 -1
- package/dist/renderer/patch-batching.mjs +2 -1
- package/dist/renderer/patch-coalescing.cjs +5 -8
- package/dist/renderer/patch-commit-scheduler.cjs +160 -326
- package/dist/renderer/patch-commit-scheduler.d.cts +28 -4
- package/dist/renderer/patch-commit-scheduler.d.ts +28 -4
- package/dist/renderer/patch-commit-scheduler.mjs +157 -318
- package/dist/renderer/store.cjs +3847 -1099
- package/dist/renderer/store.d.cts +111 -3
- package/dist/renderer/store.d.ts +111 -3
- package/dist/renderer/store.mjs +3847 -1085
- package/dist/renderer/virtualized-code.cjs +415 -71
- package/dist/renderer/virtualized-code.d.cts +24 -23
- package/dist/renderer/virtualized-code.d.ts +24 -23
- package/dist/renderer/virtualized-code.mjs +409 -62
- package/dist/renderer.cjs +10939 -3974
- package/dist/renderer.d.cts +100 -29
- package/dist/renderer.d.ts +100 -29
- package/dist/renderer.mjs +10711 -3697
- package/dist/server-regions-CPLHGli0.d.cts +32 -0
- package/dist/server-regions-mUhyoKi7.d.ts +32 -0
- package/dist/server.cjs +10286 -3365
- package/dist/server.d.cts +17 -247
- package/dist/server.d.ts +17 -247
- package/dist/server.mjs +10565 -3619
- package/dist/{streaming-markdown-DOc2uLiP.d.ts → streaming-markdown-yELbJxyH.d.ts} +51 -55
- package/dist/{streaming-markdown-D-JcByd9.d.cts → streaming-markdown-zVwFuaJG.d.cts} +51 -55
- package/dist/streaming-markdown.cjs +11828 -4879
- package/dist/streaming-markdown.d.cts +9 -2
- package/dist/streaming-markdown.d.ts +9 -2
- package/dist/streaming-markdown.mjs +11820 -4821
- package/dist/trusted-mdx/index.cjs +833 -0
- package/dist/trusted-mdx/index.d.cts +11 -0
- package/dist/trusted-mdx/index.d.ts +11 -0
- package/dist/trusted-mdx/index.mjs +807 -0
- package/dist/trusted-mdx/native-children-slot.cjs +45 -0
- package/dist/trusted-mdx/native-children-slot.d.cts +11 -0
- package/dist/trusted-mdx/native-children-slot.d.ts +11 -0
- package/dist/trusted-mdx/native-children-slot.mjs +24 -0
- package/dist/trusted-mdx/server.cjs +752 -0
- package/dist/trusted-mdx/server.d.cts +24 -0
- package/dist/trusted-mdx/server.d.ts +24 -0
- package/dist/trusted-mdx/server.mjs +724 -0
- package/dist/trusted-mdx-contract-ElKpkDI5.d.cts +113 -0
- package/dist/trusted-mdx-contract-ElKpkDI5.d.ts +113 -0
- package/dist/utils/inline-html.cjs +246 -147
- package/dist/utils/inline-html.d.cts +39 -6
- package/dist/utils/inline-html.d.ts +39 -6
- package/dist/utils/inline-html.mjs +237 -134
- package/package.json +52 -18
- package/shadcn/README.md +28 -0
- package/shadcn/bottom-stick-scroll-area.tsx +358 -0
- package/dist/index-D2MYusAM.d.cts +0 -248
- package/dist/index-D2MYusAM.d.ts +0 -248
- package/dist/mdx-client.cjs +0 -408
- package/dist/mdx-client.d.cts +0 -113
- package/dist/mdx-client.d.ts +0 -113
- package/dist/mdx-client.mjs +0 -369
- package/dist/mdx-coordinator.cjs +0 -563
- package/dist/mdx-coordinator.d.cts +0 -21
- package/dist/mdx-coordinator.d.ts +0 -21
- package/dist/mdx-coordinator.mjs +0 -529
- package/dist/renderer/node-views.cjs +0 -1642
- package/dist/renderer/node-views.d.cts +0 -12
- package/dist/renderer/node-views.d.ts +0 -12
- 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 };
|