@stream-mdx/react 0.4.0 → 0.5.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 +14 -4
- package/README.md +65 -15
- package/dist/components/bottom-stick-scroll-area.cjs +344 -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 +320 -0
- package/dist/components/index.cjs +503 -172
- package/dist/components/index.d.cts +3 -1
- package/dist/components/index.d.ts +3 -1
- package/dist/components/index.mjs +350 -22
- package/dist/{index-D2MYusAM.d.cts → index-BVhp_pcF.d.ts} +3 -0
- package/dist/{index-D2MYusAM.d.ts → index-EaeouYp2.d.cts} +3 -0
- package/dist/index.cjs +1472 -486
- package/dist/index.d.cts +6 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.mjs +1256 -272
- package/dist/mdx-client.cjs +1 -1
- package/dist/mdx-client.mjs +1 -1
- package/dist/mdx-coordinator.cjs +28 -7
- package/dist/mdx-coordinator.d.cts +2 -2
- package/dist/mdx-coordinator.d.ts +2 -2
- package/dist/mdx-coordinator.mjs +28 -7
- package/dist/renderer/node-views.cjs +271 -26
- package/dist/renderer/node-views.d.cts +3 -1
- package/dist/renderer/node-views.d.ts +3 -1
- package/dist/renderer/node-views.mjs +272 -27
- package/dist/renderer/patch-batching.cjs +2 -0
- 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-commit-scheduler.cjs +82 -30
- package/dist/renderer/patch-commit-scheduler.d.cts +15 -3
- package/dist/renderer/patch-commit-scheduler.d.ts +15 -3
- package/dist/renderer/patch-commit-scheduler.mjs +84 -30
- package/dist/renderer/store.cjs +382 -36
- package/dist/renderer/store.d.cts +3 -0
- package/dist/renderer/store.d.ts +3 -0
- package/dist/renderer/store.mjs +382 -36
- package/dist/renderer.cjs +758 -114
- package/dist/renderer.d.cts +3 -1
- package/dist/renderer.d.ts +3 -1
- package/dist/renderer.mjs +760 -116
- package/dist/server.cjs +669 -71
- package/dist/server.d.cts +5 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.mjs +670 -72
- package/dist/{streaming-markdown-DOc2uLiP.d.ts → streaming-markdown-CEI9eDZm.d.ts} +3 -1
- package/dist/{streaming-markdown-D-JcByd9.d.cts → streaming-markdown-DRisClXb.d.cts} +3 -1
- package/dist/streaming-markdown.cjs +788 -121
- package/dist/streaming-markdown.d.cts +4 -2
- package/dist/streaming-markdown.d.ts +4 -2
- package/dist/streaming-markdown.mjs +790 -123
- package/dist/utils/inline-html.d.cts +3 -1
- package/dist/utils/inline-html.d.ts +3 -1
- package/package.json +14 -3
- package/shadcn/README.md +28 -0
- package/shadcn/bottom-stick-scroll-area.tsx +358 -0
package/dist/index.mjs
CHANGED
|
@@ -81,7 +81,7 @@ var init_mdx_client = __esm({
|
|
|
81
81
|
if (block.type !== "mdx") {
|
|
82
82
|
throw new Error("Block is not MDX type");
|
|
83
83
|
}
|
|
84
|
-
const cacheKey = block.id
|
|
84
|
+
const cacheKey = `${block.id}\0${block.payload.raw ?? ""}`;
|
|
85
85
|
const cachedPromise = this.cache.get(cacheKey);
|
|
86
86
|
if (cachedPromise) {
|
|
87
87
|
return cachedPromise;
|
|
@@ -384,6 +384,321 @@ var init_mdx_client = __esm({
|
|
|
384
384
|
}
|
|
385
385
|
});
|
|
386
386
|
|
|
387
|
+
// src/components/bottom-stick-scroll-area.tsx
|
|
388
|
+
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
389
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
390
|
+
var EPS_BOTTOM_PX = 2;
|
|
391
|
+
var EPS_OVERFLOW_PX = 1;
|
|
392
|
+
var DETACH_SCROLL_DELTA_PX = 1;
|
|
393
|
+
var RETURN_MIN_MS = 180;
|
|
394
|
+
var RETURN_MAX_MS = 520;
|
|
395
|
+
var RETURN_PX_PER_MS = 2.2;
|
|
396
|
+
var RETURN_SETTLE_FRAMES = 2;
|
|
397
|
+
function clamp01(value) {
|
|
398
|
+
if (value < 0) return 0;
|
|
399
|
+
if (value > 1) return 1;
|
|
400
|
+
return value;
|
|
401
|
+
}
|
|
402
|
+
function easeOutCubic(value) {
|
|
403
|
+
return 1 - (1 - value) ** 3;
|
|
404
|
+
}
|
|
405
|
+
function joinClasses(...parts) {
|
|
406
|
+
return parts.filter(Boolean).join(" ");
|
|
407
|
+
}
|
|
408
|
+
function measure(viewport) {
|
|
409
|
+
const scrollTop = viewport.scrollTop;
|
|
410
|
+
const scrollHeight = viewport.scrollHeight;
|
|
411
|
+
const clientHeight = viewport.clientHeight;
|
|
412
|
+
const maxScrollTop = Math.max(0, scrollHeight - clientHeight);
|
|
413
|
+
const distanceToBottom = Math.max(0, maxScrollTop - scrollTop);
|
|
414
|
+
const isOverflowing = scrollHeight > clientHeight + EPS_OVERFLOW_PX;
|
|
415
|
+
return { scrollTop, scrollHeight, clientHeight, maxScrollTop, distanceToBottom, isOverflowing };
|
|
416
|
+
}
|
|
417
|
+
function DefaultJumpButton({ canJump, jumpToBottom }) {
|
|
418
|
+
return /* @__PURE__ */ jsx(
|
|
419
|
+
"button",
|
|
420
|
+
{
|
|
421
|
+
type: "button",
|
|
422
|
+
onClick: jumpToBottom,
|
|
423
|
+
"aria-label": "Scroll to bottom",
|
|
424
|
+
style: {
|
|
425
|
+
pointerEvents: canJump ? "auto" : "none",
|
|
426
|
+
borderRadius: 9999,
|
|
427
|
+
border: "1px solid color-mix(in srgb, currentColor 20%, transparent)",
|
|
428
|
+
width: 40,
|
|
429
|
+
height: 40,
|
|
430
|
+
display: "grid",
|
|
431
|
+
placeItems: "center",
|
|
432
|
+
boxShadow: "0 8px 20px rgba(0,0,0,0.18)",
|
|
433
|
+
background: "color-mix(in srgb, var(--background, #fff) 92%, transparent)",
|
|
434
|
+
color: "var(--foreground, #111)",
|
|
435
|
+
cursor: canJump ? "pointer" : "default"
|
|
436
|
+
},
|
|
437
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\u2193" })
|
|
438
|
+
}
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
function BottomStickScrollArea({
|
|
442
|
+
children,
|
|
443
|
+
className,
|
|
444
|
+
viewportClassName,
|
|
445
|
+
contentClassName,
|
|
446
|
+
showJumpToBottom = true,
|
|
447
|
+
onDebugStateChange,
|
|
448
|
+
onModeChange,
|
|
449
|
+
debugDomAttributes = false,
|
|
450
|
+
renderJumpToBottom,
|
|
451
|
+
jumpContainerClassName
|
|
452
|
+
}) {
|
|
453
|
+
const viewportRef = useRef(null);
|
|
454
|
+
const contentRef = useRef(null);
|
|
455
|
+
const modeRef = useRef("STICKY_INSTANT");
|
|
456
|
+
const [mode, setMode] = useState("STICKY_INSTANT");
|
|
457
|
+
const [isOverflowing, setIsOverflowing] = useState(false);
|
|
458
|
+
const [distanceToBottom, setDistanceToBottom] = useState(0);
|
|
459
|
+
const prevScrollTopRef = useRef(0);
|
|
460
|
+
const lastProgrammaticWriteRef = useRef(null);
|
|
461
|
+
const programmaticWriteCountRef = useRef(0);
|
|
462
|
+
const pendingStickRafRef = useRef(null);
|
|
463
|
+
const stickRequestedRef = useRef(false);
|
|
464
|
+
const returnRafRef = useRef(null);
|
|
465
|
+
const returnAnimRef = useRef(null);
|
|
466
|
+
const setModeBoth = useCallback(
|
|
467
|
+
(next) => {
|
|
468
|
+
modeRef.current = next;
|
|
469
|
+
setMode(next);
|
|
470
|
+
onModeChange?.(next);
|
|
471
|
+
},
|
|
472
|
+
[onModeChange]
|
|
473
|
+
);
|
|
474
|
+
const updateDebug = useCallback(() => {
|
|
475
|
+
const viewport = viewportRef.current;
|
|
476
|
+
if (!viewport) return;
|
|
477
|
+
const m = measure(viewport);
|
|
478
|
+
if (debugDomAttributes) {
|
|
479
|
+
viewport.dataset.stickyMode = modeRef.current;
|
|
480
|
+
viewport.dataset.distanceToBottom = String(m.distanceToBottom);
|
|
481
|
+
viewport.dataset.isOverflowing = m.isOverflowing ? "1" : "0";
|
|
482
|
+
viewport.dataset.programmaticWrites = String(programmaticWriteCountRef.current);
|
|
483
|
+
}
|
|
484
|
+
onDebugStateChange?.({
|
|
485
|
+
mode: modeRef.current,
|
|
486
|
+
isOverflowing: m.isOverflowing,
|
|
487
|
+
distanceToBottom: m.distanceToBottom,
|
|
488
|
+
scrollTop: m.scrollTop,
|
|
489
|
+
maxScrollTop: m.maxScrollTop,
|
|
490
|
+
scrollHeight: m.scrollHeight,
|
|
491
|
+
clientHeight: m.clientHeight,
|
|
492
|
+
programmaticWrites: programmaticWriteCountRef.current
|
|
493
|
+
});
|
|
494
|
+
setDistanceToBottom(
|
|
495
|
+
(previous) => Math.abs(previous - m.distanceToBottom) <= 0.1 ? previous : m.distanceToBottom
|
|
496
|
+
);
|
|
497
|
+
}, [debugDomAttributes, onDebugStateChange]);
|
|
498
|
+
const writeScrollTop = useCallback((nextTop) => {
|
|
499
|
+
const viewport = viewportRef.current;
|
|
500
|
+
if (!viewport) return;
|
|
501
|
+
viewport.scrollTop = nextTop;
|
|
502
|
+
programmaticWriteCountRef.current += 1;
|
|
503
|
+
lastProgrammaticWriteRef.current = { at: performance.now(), top: nextTop };
|
|
504
|
+
}, []);
|
|
505
|
+
const cancelPendingStick = useCallback(() => {
|
|
506
|
+
if (pendingStickRafRef.current !== null) {
|
|
507
|
+
cancelAnimationFrame(pendingStickRafRef.current);
|
|
508
|
+
pendingStickRafRef.current = null;
|
|
509
|
+
}
|
|
510
|
+
stickRequestedRef.current = false;
|
|
511
|
+
}, []);
|
|
512
|
+
const cancelReturn = useCallback(() => {
|
|
513
|
+
if (returnRafRef.current !== null) {
|
|
514
|
+
cancelAnimationFrame(returnRafRef.current);
|
|
515
|
+
returnRafRef.current = null;
|
|
516
|
+
}
|
|
517
|
+
returnAnimRef.current = null;
|
|
518
|
+
}, []);
|
|
519
|
+
const stickToBottomInstant = useCallback(() => {
|
|
520
|
+
const viewport = viewportRef.current;
|
|
521
|
+
if (!viewport) return;
|
|
522
|
+
stickRequestedRef.current = true;
|
|
523
|
+
if (pendingStickRafRef.current !== null) return;
|
|
524
|
+
pendingStickRafRef.current = requestAnimationFrame(() => {
|
|
525
|
+
pendingStickRafRef.current = null;
|
|
526
|
+
if (!stickRequestedRef.current) return;
|
|
527
|
+
stickRequestedRef.current = false;
|
|
528
|
+
if (modeRef.current !== "STICKY_INSTANT") return;
|
|
529
|
+
const m = measure(viewport);
|
|
530
|
+
writeScrollTop(m.maxScrollTop);
|
|
531
|
+
updateDebug();
|
|
532
|
+
});
|
|
533
|
+
}, [updateDebug, writeScrollTop]);
|
|
534
|
+
const startReturnToBottomSmooth = useCallback(() => {
|
|
535
|
+
const viewport = viewportRef.current;
|
|
536
|
+
if (!viewport) return;
|
|
537
|
+
cancelPendingStick();
|
|
538
|
+
cancelReturn();
|
|
539
|
+
const initial = measure(viewport);
|
|
540
|
+
if (initial.distanceToBottom <= EPS_BOTTOM_PX) {
|
|
541
|
+
setModeBoth("STICKY_INSTANT");
|
|
542
|
+
stickToBottomInstant();
|
|
543
|
+
updateDebug();
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
const durationMs = Math.max(
|
|
547
|
+
RETURN_MIN_MS,
|
|
548
|
+
Math.min(RETURN_MAX_MS, initial.distanceToBottom / RETURN_PX_PER_MS)
|
|
549
|
+
);
|
|
550
|
+
returnAnimRef.current = {
|
|
551
|
+
startTime: performance.now(),
|
|
552
|
+
startTop: initial.scrollTop,
|
|
553
|
+
durationMs,
|
|
554
|
+
settleFrames: 0
|
|
555
|
+
};
|
|
556
|
+
setModeBoth("RETURNING_SMOOTH");
|
|
557
|
+
const tick = (now2) => {
|
|
558
|
+
const viewportCurrent = viewportRef.current;
|
|
559
|
+
const anim = returnAnimRef.current;
|
|
560
|
+
if (!viewportCurrent || !anim || modeRef.current !== "RETURNING_SMOOTH") {
|
|
561
|
+
cancelReturn();
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
const before = measure(viewportCurrent);
|
|
565
|
+
const progress = clamp01((now2 - anim.startTime) / anim.durationMs);
|
|
566
|
+
const eased = easeOutCubic(progress);
|
|
567
|
+
const targetBottom = before.maxScrollTop;
|
|
568
|
+
let nextTop = anim.startTop + (targetBottom - anim.startTop) * eased;
|
|
569
|
+
if (nextTop < before.scrollTop) {
|
|
570
|
+
nextTop = before.scrollTop;
|
|
571
|
+
}
|
|
572
|
+
writeScrollTop(nextTop);
|
|
573
|
+
const after = measure(viewportCurrent);
|
|
574
|
+
if (after.distanceToBottom <= EPS_BOTTOM_PX) {
|
|
575
|
+
anim.settleFrames += 1;
|
|
576
|
+
} else {
|
|
577
|
+
anim.settleFrames = 0;
|
|
578
|
+
}
|
|
579
|
+
const doneByTime = progress >= 1;
|
|
580
|
+
const doneBySettle = anim.settleFrames >= RETURN_SETTLE_FRAMES && progress >= 0.6;
|
|
581
|
+
if (doneByTime && doneBySettle) {
|
|
582
|
+
cancelReturn();
|
|
583
|
+
setModeBoth("STICKY_INSTANT");
|
|
584
|
+
stickToBottomInstant();
|
|
585
|
+
updateDebug();
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
updateDebug();
|
|
589
|
+
returnRafRef.current = requestAnimationFrame(tick);
|
|
590
|
+
};
|
|
591
|
+
returnRafRef.current = requestAnimationFrame(tick);
|
|
592
|
+
}, [cancelPendingStick, cancelReturn, setModeBoth, stickToBottomInstant, updateDebug, writeScrollTop]);
|
|
593
|
+
const onViewportScroll = useCallback(
|
|
594
|
+
(event) => {
|
|
595
|
+
const viewport = event.currentTarget;
|
|
596
|
+
const m = measure(viewport);
|
|
597
|
+
setIsOverflowing((previous) => previous === m.isOverflowing ? previous : m.isOverflowing);
|
|
598
|
+
const previousTop = prevScrollTopRef.current;
|
|
599
|
+
const delta = m.scrollTop - previousTop;
|
|
600
|
+
const lastWrite = lastProgrammaticWriteRef.current;
|
|
601
|
+
const wroteRecently = lastWrite !== null && performance.now() - lastWrite.at < 60;
|
|
602
|
+
const isLikelyOwnWrite = wroteRecently && lastWrite !== null && Math.abs(m.scrollTop - lastWrite.top) <= 2;
|
|
603
|
+
if (modeRef.current === "RETURNING_SMOOTH") {
|
|
604
|
+
if (!isLikelyOwnWrite && delta < -DETACH_SCROLL_DELTA_PX) {
|
|
605
|
+
cancelReturn();
|
|
606
|
+
setModeBoth("DETACHED");
|
|
607
|
+
}
|
|
608
|
+
} else if (modeRef.current === "STICKY_INSTANT") {
|
|
609
|
+
if (!isLikelyOwnWrite && delta < -DETACH_SCROLL_DELTA_PX && m.isOverflowing) {
|
|
610
|
+
cancelPendingStick();
|
|
611
|
+
setModeBoth("DETACHED");
|
|
612
|
+
}
|
|
613
|
+
} else if (modeRef.current === "DETACHED") {
|
|
614
|
+
if (m.distanceToBottom <= EPS_BOTTOM_PX) {
|
|
615
|
+
setModeBoth("STICKY_INSTANT");
|
|
616
|
+
stickToBottomInstant();
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
prevScrollTopRef.current = m.scrollTop;
|
|
620
|
+
updateDebug();
|
|
621
|
+
},
|
|
622
|
+
[cancelPendingStick, cancelReturn, setModeBoth, stickToBottomInstant, updateDebug]
|
|
623
|
+
);
|
|
624
|
+
useEffect(() => {
|
|
625
|
+
const viewport = viewportRef.current;
|
|
626
|
+
const content = contentRef.current;
|
|
627
|
+
if (!viewport || !content) return;
|
|
628
|
+
const observer = new ResizeObserver(() => {
|
|
629
|
+
const m = measure(viewport);
|
|
630
|
+
setIsOverflowing((previous) => previous === m.isOverflowing ? previous : m.isOverflowing);
|
|
631
|
+
if (modeRef.current === "STICKY_INSTANT") {
|
|
632
|
+
stickToBottomInstant();
|
|
633
|
+
}
|
|
634
|
+
updateDebug();
|
|
635
|
+
});
|
|
636
|
+
observer.observe(content);
|
|
637
|
+
observer.observe(viewport);
|
|
638
|
+
return () => observer.disconnect();
|
|
639
|
+
}, [stickToBottomInstant, updateDebug]);
|
|
640
|
+
useLayoutEffect(() => {
|
|
641
|
+
const viewport = viewportRef.current;
|
|
642
|
+
if (!viewport) return;
|
|
643
|
+
setModeBoth("STICKY_INSTANT");
|
|
644
|
+
const initial = measure(viewport);
|
|
645
|
+
writeScrollTop(initial.maxScrollTop);
|
|
646
|
+
prevScrollTopRef.current = viewport.scrollTop;
|
|
647
|
+
setIsOverflowing(initial.isOverflowing);
|
|
648
|
+
setDistanceToBottom(initial.distanceToBottom);
|
|
649
|
+
updateDebug();
|
|
650
|
+
}, [setModeBoth, updateDebug, writeScrollTop]);
|
|
651
|
+
useEffect(() => {
|
|
652
|
+
return () => {
|
|
653
|
+
cancelPendingStick();
|
|
654
|
+
cancelReturn();
|
|
655
|
+
};
|
|
656
|
+
}, [cancelPendingStick, cancelReturn]);
|
|
657
|
+
const canJump = isOverflowing && mode === "DETACHED";
|
|
658
|
+
const jumpButton = renderJumpToBottom?.({
|
|
659
|
+
mode,
|
|
660
|
+
canJump,
|
|
661
|
+
isOverflowing,
|
|
662
|
+
distanceToBottom,
|
|
663
|
+
jumpToBottom: startReturnToBottomSmooth
|
|
664
|
+
}) ?? /* @__PURE__ */ jsx(DefaultJumpButton, { canJump, jumpToBottom: startReturnToBottomSmooth });
|
|
665
|
+
const jumpContainerClassNameBase = "pointer-events-none absolute z-20";
|
|
666
|
+
const jumpContainerStyle = {
|
|
667
|
+
position: "absolute",
|
|
668
|
+
zIndex: 20,
|
|
669
|
+
left: 0,
|
|
670
|
+
right: 0,
|
|
671
|
+
bottom: 12,
|
|
672
|
+
display: "flex",
|
|
673
|
+
justifyContent: "center",
|
|
674
|
+
opacity: canJump ? 1 : 0,
|
|
675
|
+
transform: canJump ? "translateY(0px)" : "translateY(4px)",
|
|
676
|
+
transition: "opacity 150ms ease, transform 150ms ease",
|
|
677
|
+
pointerEvents: "none"
|
|
678
|
+
};
|
|
679
|
+
return /* @__PURE__ */ jsxs("div", { className: joinClasses("relative h-full w-full overflow-hidden", className), children: [
|
|
680
|
+
/* @__PURE__ */ jsx(
|
|
681
|
+
"div",
|
|
682
|
+
{
|
|
683
|
+
ref: viewportRef,
|
|
684
|
+
className: joinClasses("h-full w-full overflow-auto", viewportClassName),
|
|
685
|
+
onScroll: onViewportScroll,
|
|
686
|
+
"data-testid": "sticky-scroll-viewport",
|
|
687
|
+
children: /* @__PURE__ */ jsx("div", { ref: contentRef, className: joinClasses("flex min-h-full w-full flex-col", contentClassName), children })
|
|
688
|
+
}
|
|
689
|
+
),
|
|
690
|
+
showJumpToBottom ? /* @__PURE__ */ jsx(
|
|
691
|
+
"div",
|
|
692
|
+
{
|
|
693
|
+
className: joinClasses(jumpContainerClassNameBase, jumpContainerClassName),
|
|
694
|
+
style: jumpContainerStyle,
|
|
695
|
+
"aria-hidden": !canJump,
|
|
696
|
+
children: /* @__PURE__ */ jsx("div", { className: canJump ? "pointer-events-auto" : "pointer-events-none", children: jumpButton })
|
|
697
|
+
}
|
|
698
|
+
) : null
|
|
699
|
+
] });
|
|
700
|
+
}
|
|
701
|
+
|
|
387
702
|
// src/components/index.ts
|
|
388
703
|
import { createTrustedHTML, sanitizeHTML } from "@stream-mdx/core";
|
|
389
704
|
|
|
@@ -619,11 +934,11 @@ function prefetchMdxRuntime() {
|
|
|
619
934
|
}
|
|
620
935
|
|
|
621
936
|
// src/renderer/use-deferred-render.ts
|
|
622
|
-
import { useEffect, useState } from "react";
|
|
937
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
623
938
|
function useDeferredRender(ref, options) {
|
|
624
939
|
const enabled = options?.enabled ?? true;
|
|
625
|
-
const [shouldRender, setShouldRender] =
|
|
626
|
-
|
|
940
|
+
const [shouldRender, setShouldRender] = useState2(!enabled);
|
|
941
|
+
useEffect2(() => {
|
|
627
942
|
if (!enabled) {
|
|
628
943
|
setShouldRender(true);
|
|
629
944
|
return;
|
|
@@ -948,12 +1263,12 @@ var INLINE_ELEMENTS = /* @__PURE__ */ new Set([
|
|
|
948
1263
|
]);
|
|
949
1264
|
|
|
950
1265
|
// src/components/link-safety-modal.tsx
|
|
951
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1266
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
952
1267
|
var DefaultLinkSafetyModal = ({ url, isOpen, isChecking, onClose, onConfirm, onCopy }) => {
|
|
953
1268
|
if (!isOpen) {
|
|
954
1269
|
return null;
|
|
955
1270
|
}
|
|
956
|
-
return /* @__PURE__ */
|
|
1271
|
+
return /* @__PURE__ */ jsx2(
|
|
957
1272
|
"div",
|
|
958
1273
|
{
|
|
959
1274
|
className: "stream-mdx-link-modal-backdrop",
|
|
@@ -971,7 +1286,7 @@ var DefaultLinkSafetyModal = ({ url, isOpen, isChecking, onClose, onConfirm, onC
|
|
|
971
1286
|
padding: "24px"
|
|
972
1287
|
},
|
|
973
1288
|
onClick: onClose,
|
|
974
|
-
children: /* @__PURE__ */
|
|
1289
|
+
children: /* @__PURE__ */ jsxs2(
|
|
975
1290
|
"div",
|
|
976
1291
|
{
|
|
977
1292
|
className: "stream-mdx-link-modal",
|
|
@@ -986,12 +1301,12 @@ var DefaultLinkSafetyModal = ({ url, isOpen, isChecking, onClose, onConfirm, onC
|
|
|
986
1301
|
},
|
|
987
1302
|
onClick: (event) => event.stopPropagation(),
|
|
988
1303
|
children: [
|
|
989
|
-
/* @__PURE__ */
|
|
990
|
-
/* @__PURE__ */
|
|
991
|
-
/* @__PURE__ */
|
|
992
|
-
/* @__PURE__ */
|
|
993
|
-
/* @__PURE__ */
|
|
994
|
-
/* @__PURE__ */
|
|
1304
|
+
/* @__PURE__ */ jsx2("div", { style: { fontWeight: 600, marginBottom: 8 }, children: "Open external link?" }),
|
|
1305
|
+
/* @__PURE__ */ jsx2("div", { style: { fontSize: 13, opacity: 0.8, wordBreak: "break-all", marginBottom: 16 }, children: url }),
|
|
1306
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 8, justifyContent: "flex-end" }, children: [
|
|
1307
|
+
/* @__PURE__ */ jsx2("button", { type: "button", onClick: onCopy, disabled: isChecking, style: buttonStyle, children: "Copy link" }),
|
|
1308
|
+
/* @__PURE__ */ jsx2("button", { type: "button", onClick: onConfirm, disabled: isChecking, style: primaryButtonStyle, children: "Open link" }),
|
|
1309
|
+
/* @__PURE__ */ jsx2("button", { type: "button", onClick: onClose, style: buttonStyle, children: "Cancel" })
|
|
995
1310
|
] })
|
|
996
1311
|
]
|
|
997
1312
|
}
|
|
@@ -1166,7 +1481,11 @@ var defaultInlineComponents = {
|
|
|
1166
1481
|
const n = number ?? "?";
|
|
1167
1482
|
const href = number ? `#fn:${n}` : void 0;
|
|
1168
1483
|
const id = number ? `fnref:${n}` : void 0;
|
|
1169
|
-
return React4.createElement(
|
|
1484
|
+
return React4.createElement(
|
|
1485
|
+
"sup",
|
|
1486
|
+
{ className: "footnote-ref" },
|
|
1487
|
+
React4.createElement("a", { href, id, "data-label": label, style: { color: "var(--foreground)", textDecoration: "underline" } }, String(n))
|
|
1488
|
+
);
|
|
1170
1489
|
}
|
|
1171
1490
|
};
|
|
1172
1491
|
var defaultBlockComponents = {
|
|
@@ -1309,7 +1628,7 @@ var defaultBlockComponents = {
|
|
|
1309
1628
|
dangerouslySetInnerHTML: { __html: htmlString }
|
|
1310
1629
|
});
|
|
1311
1630
|
},
|
|
1312
|
-
mdx: ({ compiledRef, compiledModule, status, errorMessage
|
|
1631
|
+
mdx: ({ compiledRef, compiledModule, status, errorMessage }) => {
|
|
1313
1632
|
const [Comp, setComp] = React4.useState(null);
|
|
1314
1633
|
const [internalError, setInternalError] = React4.useState(null);
|
|
1315
1634
|
const [renderError, setRenderError] = React4.useState(null);
|
|
@@ -1410,7 +1729,6 @@ var defaultBlockComponents = {
|
|
|
1410
1729
|
const waitingForVisibility = deferHydration && !shouldHydrate && Boolean(resolvedId);
|
|
1411
1730
|
const pendingLabel = waitingForVisibility ? "MDX ready (hydrate on view)\u2026" : compileMode === "worker" ? "Compiling MDX (client)\u2026" : "Compiling MDX (server)\u2026";
|
|
1412
1731
|
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.");
|
|
1413
|
-
const rawFallback = typeof raw === "string" && raw.trim().length > 0 ? React4.createElement("pre", { className: "markdown-mdx-fallback" }, raw) : null;
|
|
1414
1732
|
const allowRetry = Boolean(internalError || renderError);
|
|
1415
1733
|
const retryButton = allowRetry ? React4.createElement(
|
|
1416
1734
|
"button",
|
|
@@ -1422,9 +1740,10 @@ var defaultBlockComponents = {
|
|
|
1422
1740
|
"Retry hydration"
|
|
1423
1741
|
) : null;
|
|
1424
1742
|
const errorPanel = React4.createElement(
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
React4.createElement(
|
|
1743
|
+
React4.Fragment,
|
|
1744
|
+
null,
|
|
1745
|
+
React4.createElement("strong", null, "MDX failed"),
|
|
1746
|
+
React4.createElement("div", null, message)
|
|
1428
1747
|
);
|
|
1429
1748
|
if (Comp && !failureMessage) {
|
|
1430
1749
|
return React4.createElement(
|
|
@@ -1447,14 +1766,13 @@ var defaultBlockComponents = {
|
|
|
1447
1766
|
return React4.createElement(
|
|
1448
1767
|
"div",
|
|
1449
1768
|
{
|
|
1450
|
-
className: "markdown-mdx",
|
|
1769
|
+
className: "markdown-mdx error",
|
|
1451
1770
|
ref: containerRef,
|
|
1452
1771
|
"data-mdx-ref": pendingId,
|
|
1453
1772
|
"data-mdx-status": "error",
|
|
1454
1773
|
"data-mdx-mode": compileMode
|
|
1455
1774
|
},
|
|
1456
1775
|
errorPanel,
|
|
1457
|
-
rawFallback,
|
|
1458
1776
|
retryButton
|
|
1459
1777
|
);
|
|
1460
1778
|
}
|
|
@@ -1481,7 +1799,16 @@ var defaultBlockComponents = {
|
|
|
1481
1799
|
{ key: item.number, id: `fn:${item.number}` },
|
|
1482
1800
|
renderInlineNodes(item.inlines, defaultInlineComponents),
|
|
1483
1801
|
" ",
|
|
1484
|
-
React4.createElement(
|
|
1802
|
+
React4.createElement(
|
|
1803
|
+
"a",
|
|
1804
|
+
{
|
|
1805
|
+
href: `#fnref:${item.number}`,
|
|
1806
|
+
className: "footnote-backref",
|
|
1807
|
+
"aria-label": "Back to content",
|
|
1808
|
+
style: { color: "var(--foreground)", textDecoration: "underline" }
|
|
1809
|
+
},
|
|
1810
|
+
"\u21A9"
|
|
1811
|
+
)
|
|
1485
1812
|
)
|
|
1486
1813
|
);
|
|
1487
1814
|
return React4.createElement("section", { className: "footnotes" }, React4.createElement("hr", {}), React4.createElement("ol", {}, listItems));
|
|
@@ -2021,19 +2348,20 @@ init_mdx_client();
|
|
|
2021
2348
|
|
|
2022
2349
|
// src/mdx-coordinator.ts
|
|
2023
2350
|
init_mdx_client();
|
|
2024
|
-
import { useCallback, useEffect as
|
|
2351
|
+
import { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2, useState as useState3 } from "react";
|
|
2025
2352
|
function useMdxCoordinator(blocks, compileEndpoint, options) {
|
|
2026
|
-
const mdxClientRef =
|
|
2353
|
+
const mdxClientRef = useRef2(getMDXClient(compileEndpoint));
|
|
2027
2354
|
const mode = options?.mode ?? "server";
|
|
2028
|
-
const [compiledMap, setCompiledMap] =
|
|
2029
|
-
const blockSignatureRef =
|
|
2030
|
-
const
|
|
2355
|
+
const [compiledMap, setCompiledMap] = useState3(/* @__PURE__ */ new Map());
|
|
2356
|
+
const blockSignatureRef = useRef2(/* @__PURE__ */ new Map());
|
|
2357
|
+
const failedSignatureRef = useRef2(/* @__PURE__ */ new Map());
|
|
2358
|
+
const applyCompiledRef = useCallback2(
|
|
2031
2359
|
(block, compiledId) => {
|
|
2032
2360
|
if (mode === "worker") {
|
|
2033
2361
|
return;
|
|
2034
2362
|
}
|
|
2035
2363
|
if (options?.workerClient) {
|
|
2036
|
-
options.workerClient.setMdxCompiled(block.id, compiledId);
|
|
2364
|
+
options.workerClient.setMdxCompiled(block.id, compiledId, block.payload.raw ?? "");
|
|
2037
2365
|
return;
|
|
2038
2366
|
}
|
|
2039
2367
|
const store = options?.store;
|
|
@@ -2044,6 +2372,9 @@ function useMdxCoordinator(blocks, compileEndpoint, options) {
|
|
|
2044
2372
|
const index = currentBlocks.findIndex((candidate) => candidate.id === block.id);
|
|
2045
2373
|
if (index === -1) return;
|
|
2046
2374
|
const current = currentBlocks[index];
|
|
2375
|
+
if ((current.payload.raw ?? "") !== (block.payload.raw ?? "")) {
|
|
2376
|
+
return;
|
|
2377
|
+
}
|
|
2047
2378
|
if (current.payload.compiledMdxRef?.id === compiledId) {
|
|
2048
2379
|
return;
|
|
2049
2380
|
}
|
|
@@ -2069,11 +2400,17 @@ function useMdxCoordinator(blocks, compileEndpoint, options) {
|
|
|
2069
2400
|
},
|
|
2070
2401
|
[options?.workerClient, options?.store, mode]
|
|
2071
2402
|
);
|
|
2072
|
-
|
|
2403
|
+
useEffect3(() => {
|
|
2073
2404
|
if (mode === "worker") {
|
|
2074
2405
|
return;
|
|
2075
2406
|
}
|
|
2076
|
-
const targets = blocks.filter((b) =>
|
|
2407
|
+
const targets = blocks.filter((b) => {
|
|
2408
|
+
if (b.type !== "mdx" || !b.isFinalized || b.payload.compiledMdxRef || compiledMap.has(b.id)) {
|
|
2409
|
+
return false;
|
|
2410
|
+
}
|
|
2411
|
+
const raw = b.payload.raw ?? "";
|
|
2412
|
+
return failedSignatureRef.current.get(b.id) !== raw;
|
|
2413
|
+
});
|
|
2077
2414
|
if (targets.length === 0) return;
|
|
2078
2415
|
let cancelled = false;
|
|
2079
2416
|
(async () => {
|
|
@@ -2092,22 +2429,29 @@ function useMdxCoordinator(blocks, compileEndpoint, options) {
|
|
|
2092
2429
|
next.set(block.id, compiled.id);
|
|
2093
2430
|
return next;
|
|
2094
2431
|
});
|
|
2432
|
+
failedSignatureRef.current.delete(block.id);
|
|
2095
2433
|
applyCompiledRef(block, compiled.id);
|
|
2096
2434
|
} catch (e) {
|
|
2097
2435
|
console.warn("MDX compile failed for block", block.id, e);
|
|
2436
|
+
failedSignatureRef.current.set(block.id, block.payload.raw ?? "");
|
|
2098
2437
|
if (options?.workerClient) {
|
|
2099
|
-
options.workerClient.setMdxError(block.id, e instanceof Error ? e.message : String(e));
|
|
2438
|
+
options.workerClient.setMdxError(block.id, e instanceof Error ? e.message : String(e), block.payload.raw ?? "");
|
|
2100
2439
|
} else if (options?.store) {
|
|
2440
|
+
const currentBlocks = options.store.getBlocks();
|
|
2441
|
+
const current = currentBlocks.find((candidate) => candidate.id === block.id);
|
|
2442
|
+
if (!current || (current.payload.raw ?? "") !== (block.payload.raw ?? "")) {
|
|
2443
|
+
continue;
|
|
2444
|
+
}
|
|
2101
2445
|
options.store.applyPatches([
|
|
2102
2446
|
{
|
|
2103
2447
|
op: "setProps",
|
|
2104
2448
|
at: { blockId: block.id, nodeId: block.id },
|
|
2105
2449
|
props: {
|
|
2106
2450
|
block: {
|
|
2107
|
-
...
|
|
2451
|
+
...current,
|
|
2108
2452
|
payload: {
|
|
2109
|
-
...
|
|
2110
|
-
meta: { ...
|
|
2453
|
+
...current.payload,
|
|
2454
|
+
meta: { ...current.payload.meta ?? {}, mdxStatus: "error", mdxError: e instanceof Error ? e.message : String(e) }
|
|
2111
2455
|
}
|
|
2112
2456
|
}
|
|
2113
2457
|
}
|
|
@@ -2121,7 +2465,7 @@ function useMdxCoordinator(blocks, compileEndpoint, options) {
|
|
|
2121
2465
|
cancelled = true;
|
|
2122
2466
|
};
|
|
2123
2467
|
}, [blocks, compiledMap, applyCompiledRef, options?.workerClient, options?.store, mode]);
|
|
2124
|
-
|
|
2468
|
+
useEffect3(() => {
|
|
2125
2469
|
if (mode === "worker") {
|
|
2126
2470
|
return;
|
|
2127
2471
|
}
|
|
@@ -2140,6 +2484,7 @@ function useMdxCoordinator(blocks, compileEndpoint, options) {
|
|
|
2140
2484
|
const currentSignature = candidate.payload.raw ?? "";
|
|
2141
2485
|
if (previousSignature !== void 0 && previousSignature !== currentSignature) {
|
|
2142
2486
|
next.delete(blockId);
|
|
2487
|
+
failedSignatureRef.current.delete(blockId);
|
|
2143
2488
|
mutated = true;
|
|
2144
2489
|
}
|
|
2145
2490
|
}
|
|
@@ -2149,11 +2494,14 @@ function useMdxCoordinator(blocks, compileEndpoint, options) {
|
|
|
2149
2494
|
for (const block of blocks) {
|
|
2150
2495
|
if (block.type === "mdx") {
|
|
2151
2496
|
signatureMap.set(block.id, block.payload.raw ?? "");
|
|
2497
|
+
if (!block.isFinalized || block.payload.compiledMdxRef) {
|
|
2498
|
+
failedSignatureRef.current.delete(block.id);
|
|
2499
|
+
}
|
|
2152
2500
|
}
|
|
2153
2501
|
}
|
|
2154
2502
|
blockSignatureRef.current = signatureMap;
|
|
2155
2503
|
}, [blocks, mode]);
|
|
2156
|
-
const derivedBlocks =
|
|
2504
|
+
const derivedBlocks = useMemo2(() => {
|
|
2157
2505
|
if (mode === "worker") {
|
|
2158
2506
|
return blocks;
|
|
2159
2507
|
}
|
|
@@ -2336,7 +2684,7 @@ async function prefetchMdxBundle(request) {
|
|
|
2336
2684
|
}
|
|
2337
2685
|
|
|
2338
2686
|
// src/math/display-wrapper.tsx
|
|
2339
|
-
import { jsx as
|
|
2687
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
2340
2688
|
var BASE_CLASS = "katex-block-wrapper my-2";
|
|
2341
2689
|
var SCROLL_ROOT_CLASS = "katex-scroll relative overflow-x-hidden w-full max-w-full";
|
|
2342
2690
|
var VIEWPORT_CLASS = "katex-scroll-viewport h-full w-full rounded-[inherit]";
|
|
@@ -2351,14 +2699,14 @@ function combineClassNames(base, extra) {
|
|
|
2351
2699
|
}
|
|
2352
2700
|
function DisplayMathWrapper({ children, className = "" }) {
|
|
2353
2701
|
const wrapperClass = combineClassNames(BASE_CLASS, className);
|
|
2354
|
-
return /* @__PURE__ */
|
|
2702
|
+
return /* @__PURE__ */ jsx3("div", { className: wrapperClass, children: /* @__PURE__ */ jsx3("div", { dir: "ltr", className: SCROLL_ROOT_CLASS, children: /* @__PURE__ */ jsx3("div", { className: VIEWPORT_CLASS, style: VIEWPORT_STYLE, children: /* @__PURE__ */ jsx3("div", { style: SHIM_STYLE, children }) }) }) });
|
|
2355
2703
|
}
|
|
2356
2704
|
function renderDisplayMathWithHtml(html, className) {
|
|
2357
|
-
return /* @__PURE__ */
|
|
2705
|
+
return /* @__PURE__ */ jsx3(DisplayMathWrapper, { className, children: /* @__PURE__ */ jsx3("div", { className: "katex-block", dangerouslySetInnerHTML: { __html: html } }) });
|
|
2358
2706
|
}
|
|
2359
2707
|
|
|
2360
2708
|
// src/renderer.tsx
|
|
2361
|
-
import React9, { useCallback as
|
|
2709
|
+
import React9, { useCallback as useCallback4, useEffect as useEffect5, useRef as useRef4, useState as useState5 } from "react";
|
|
2362
2710
|
import { createDefaultWorker, releaseDefaultWorker } from "@stream-mdx/worker";
|
|
2363
2711
|
init_mdx_client();
|
|
2364
2712
|
|
|
@@ -2370,7 +2718,10 @@ function useCodeHighlightRequester() {
|
|
|
2370
2718
|
}
|
|
2371
2719
|
|
|
2372
2720
|
// src/renderer/patch-batching.ts
|
|
2373
|
-
import { isHeavyPatch, splitPatchBatch } from "@stream-mdx/core/perf/patch-batching";
|
|
2721
|
+
import { getPatchKind, isHeavyPatch, splitPatchBatch } from "@stream-mdx/core/perf/patch-batching";
|
|
2722
|
+
|
|
2723
|
+
// src/renderer/patch-commit-scheduler.ts
|
|
2724
|
+
import { getPatchKind as getPatchKind2 } from "@stream-mdx/core/perf/patch-batching";
|
|
2374
2725
|
|
|
2375
2726
|
// src/renderer/patch-coalescing.ts
|
|
2376
2727
|
import {
|
|
@@ -2388,6 +2739,9 @@ var COALESCING_DURATION_ACTIVATE_MS = 6;
|
|
|
2388
2739
|
var COALESCING_DURATION_DEACTIVATE_MS = 4;
|
|
2389
2740
|
var RETAIN_TOUCHED_IN_HISTORY = typeof process !== "undefined" && process.env ? process.env.NODE_ENV !== "production" : true;
|
|
2390
2741
|
var EMPTY_TOUCHED_SET = /* @__PURE__ */ new Set();
|
|
2742
|
+
function shouldSkipCoalescing(patches) {
|
|
2743
|
+
return patches.length <= 1;
|
|
2744
|
+
}
|
|
2391
2745
|
function getDefaultNow() {
|
|
2392
2746
|
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
|
2393
2747
|
return () => performance.now();
|
|
@@ -2414,8 +2768,9 @@ function getDefaultCancelRaf() {
|
|
|
2414
2768
|
}
|
|
2415
2769
|
var PatchCommitScheduler = class {
|
|
2416
2770
|
constructor(params) {
|
|
2417
|
-
this.
|
|
2418
|
-
this.
|
|
2771
|
+
this.semanticQueue = [];
|
|
2772
|
+
this.enrichmentHighQueue = [];
|
|
2773
|
+
this.enrichmentLowQueue = [];
|
|
2419
2774
|
this.scheduled = false;
|
|
2420
2775
|
this.flushing = false;
|
|
2421
2776
|
this.scheduledHandle = null;
|
|
@@ -2427,6 +2782,7 @@ var PatchCommitScheduler = class {
|
|
|
2427
2782
|
this.scheduleToken = 0;
|
|
2428
2783
|
this.coalescingDurationSamples = [];
|
|
2429
2784
|
this.adaptiveBudgetActive = false;
|
|
2785
|
+
this.flushCount = 0;
|
|
2430
2786
|
this.store = params.store;
|
|
2431
2787
|
this.onFlush = params.onFlush;
|
|
2432
2788
|
this.frameBudgetMs = Math.max(1, params.options?.frameBudgetMs ?? 10);
|
|
@@ -2442,6 +2798,8 @@ var PatchCommitScheduler = class {
|
|
|
2442
2798
|
this.maxLowPriorityBatchesPerFlush = params.options?.maxLowPriorityBatchesPerFlush ?? 2;
|
|
2443
2799
|
this.urgentQueueThreshold = Math.max(1, params.options?.urgentQueueThreshold ?? 4);
|
|
2444
2800
|
this.historyLimit = Math.max(1, params.options?.historyLimit ?? 200);
|
|
2801
|
+
this.startupMicrotaskFlushes = Math.max(0, Math.floor(params.options?.startupMicrotaskFlushes ?? 0));
|
|
2802
|
+
this.adaptiveBudgeting = params.options?.adaptiveBudgeting ?? true;
|
|
2445
2803
|
const requestedBatch = params.options?.batch;
|
|
2446
2804
|
if (requestedBatch === "microtask") {
|
|
2447
2805
|
this.batchStrategy = "microtask";
|
|
@@ -2468,19 +2826,23 @@ var PatchCommitScheduler = class {
|
|
|
2468
2826
|
patches: input.patches,
|
|
2469
2827
|
meta: input.meta ?? {},
|
|
2470
2828
|
receivedAt: input.meta?.receivedAt ?? this.now(),
|
|
2829
|
+
kind: input.meta?.kind === "semantic" || input.meta?.kind === "enrichment" ? input.meta.kind : input.patches.some((patch) => getPatchKind2(patch) === "semantic") ? "semantic" : "enrichment",
|
|
2471
2830
|
priority: input.meta?.priority === "low" ? "low" : "high"
|
|
2472
2831
|
};
|
|
2473
|
-
if (batch.
|
|
2474
|
-
|
|
2832
|
+
if (batch.kind === "semantic") {
|
|
2833
|
+
batch.priority = "high";
|
|
2834
|
+
this.semanticQueue.push(batch);
|
|
2835
|
+
} else if (batch.priority === "low") {
|
|
2836
|
+
this.enrichmentLowQueue.push(batch);
|
|
2475
2837
|
} else {
|
|
2476
|
-
this.
|
|
2838
|
+
this.enrichmentHighQueue.push(batch);
|
|
2477
2839
|
}
|
|
2478
2840
|
if (!this.paused) {
|
|
2479
2841
|
this.schedule();
|
|
2480
2842
|
}
|
|
2481
2843
|
}
|
|
2482
2844
|
flushAll() {
|
|
2483
|
-
if (this.
|
|
2845
|
+
if (this.semanticQueue.length === 0 && this.enrichmentHighQueue.length === 0 && this.enrichmentLowQueue.length === 0 && !this.flushing) {
|
|
2484
2846
|
return null;
|
|
2485
2847
|
}
|
|
2486
2848
|
this.cancelScheduled();
|
|
@@ -2490,9 +2852,11 @@ var PatchCommitScheduler = class {
|
|
|
2490
2852
|
}
|
|
2491
2853
|
clear() {
|
|
2492
2854
|
this.cancelScheduled();
|
|
2493
|
-
this.
|
|
2494
|
-
this.
|
|
2855
|
+
this.semanticQueue = [];
|
|
2856
|
+
this.enrichmentHighQueue = [];
|
|
2857
|
+
this.enrichmentLowQueue = [];
|
|
2495
2858
|
this.flushing = false;
|
|
2859
|
+
this.flushCount = 0;
|
|
2496
2860
|
this.coalescingDurationSamples = [];
|
|
2497
2861
|
this.adaptiveBudgetActive = false;
|
|
2498
2862
|
this.adaptiveHighBatchCap = void 0;
|
|
@@ -2500,10 +2864,10 @@ var PatchCommitScheduler = class {
|
|
|
2500
2864
|
this.maybeResolveIdle();
|
|
2501
2865
|
}
|
|
2502
2866
|
getPendingCount() {
|
|
2503
|
-
return this.
|
|
2867
|
+
return this.semanticQueue.length + this.enrichmentHighQueue.length + this.enrichmentLowQueue.length;
|
|
2504
2868
|
}
|
|
2505
2869
|
isIdle() {
|
|
2506
|
-
return !this.flushing && !this.scheduled && this.
|
|
2870
|
+
return !this.flushing && !this.scheduled && this.semanticQueue.length === 0 && this.enrichmentHighQueue.length === 0 && this.enrichmentLowQueue.length === 0;
|
|
2507
2871
|
}
|
|
2508
2872
|
awaitIdle() {
|
|
2509
2873
|
if (this.isIdle()) {
|
|
@@ -2543,7 +2907,8 @@ var PatchCommitScheduler = class {
|
|
|
2543
2907
|
this.runFlush(this.frameBudgetMs, false);
|
|
2544
2908
|
this.maybeResolveIdle();
|
|
2545
2909
|
};
|
|
2546
|
-
|
|
2910
|
+
const useStartupMicrotask = this.batchStrategy !== "microtask" && this.startupMicrotaskFlushes > 0 && this.flushCount < this.startupMicrotaskFlushes && typeof queueMicrotask === "function";
|
|
2911
|
+
if ((this.batchStrategy === "microtask" || useStartupMicrotask) && typeof queueMicrotask === "function") {
|
|
2547
2912
|
this.scheduledViaRaf = false;
|
|
2548
2913
|
this.scheduledHandle = token;
|
|
2549
2914
|
queueMicrotask(execute);
|
|
@@ -2573,12 +2938,14 @@ var PatchCommitScheduler = class {
|
|
|
2573
2938
|
if (this.paused && !manual) {
|
|
2574
2939
|
return null;
|
|
2575
2940
|
}
|
|
2576
|
-
if (this.
|
|
2941
|
+
if (this.semanticQueue.length === 0 && this.enrichmentHighQueue.length === 0 && this.enrichmentLowQueue.length === 0) {
|
|
2577
2942
|
return null;
|
|
2578
2943
|
}
|
|
2579
2944
|
this.flushing = true;
|
|
2580
2945
|
const startedAt = this.now();
|
|
2581
|
-
const
|
|
2946
|
+
const initialSemanticQueueSize = this.semanticQueue.length;
|
|
2947
|
+
const initialEnrichmentQueueSize = this.enrichmentHighQueue.length + this.enrichmentLowQueue.length;
|
|
2948
|
+
const initialQueueSize = initialSemanticQueueSize + initialEnrichmentQueueSize;
|
|
2582
2949
|
const batches = [];
|
|
2583
2950
|
let totalInputPatches = 0;
|
|
2584
2951
|
let totalAppliedPatches = 0;
|
|
@@ -2593,7 +2960,15 @@ var PatchCommitScheduler = class {
|
|
|
2593
2960
|
consumed += 1;
|
|
2594
2961
|
const applyStart = this.now();
|
|
2595
2962
|
const queueDelayMs = Math.max(0, applyStart - next.receivedAt);
|
|
2596
|
-
|
|
2963
|
+
let coalesced;
|
|
2964
|
+
let coalescingMetrics;
|
|
2965
|
+
if (shouldSkipCoalescing(next.patches)) {
|
|
2966
|
+
coalesced = next.patches;
|
|
2967
|
+
} else {
|
|
2968
|
+
const result = coalescePatchesWithMetrics(next.patches, DEFAULT_COALESCE_CONFIG);
|
|
2969
|
+
coalesced = result.patches;
|
|
2970
|
+
coalescingMetrics = result.metrics;
|
|
2971
|
+
}
|
|
2597
2972
|
const touched = this.store.applyPatches(coalesced, {
|
|
2598
2973
|
coalesced: true,
|
|
2599
2974
|
metrics: coalescingMetrics
|
|
@@ -2613,6 +2988,7 @@ var PatchCommitScheduler = class {
|
|
|
2613
2988
|
receivedAt: next.receivedAt,
|
|
2614
2989
|
appliedAt: applyStart,
|
|
2615
2990
|
priority: next.priority,
|
|
2991
|
+
kind: next.kind,
|
|
2616
2992
|
coalescing: coalescingMetrics
|
|
2617
2993
|
});
|
|
2618
2994
|
if (maxBatches && batches.length - startingBatchCount >= maxBatches) {
|
|
@@ -2629,27 +3005,32 @@ var PatchCommitScheduler = class {
|
|
|
2629
3005
|
queue.splice(0, consumed);
|
|
2630
3006
|
}
|
|
2631
3007
|
};
|
|
2632
|
-
|
|
3008
|
+
processQueue(this.semanticQueue, void 0, Number.POSITIVE_INFINITY);
|
|
3009
|
+
const initialHighQueueSize = this.enrichmentHighQueue.length;
|
|
2633
3010
|
const configuredHighLimit = manual || !this.maxBatchesPerFlush ? void 0 : initialHighQueueSize > this.maxBatchesPerFlush ? void 0 : this.maxBatchesPerFlush;
|
|
2634
|
-
const highBatchLimit = this.adaptiveHighBatchCap ?? configuredHighLimit;
|
|
2635
|
-
processQueue(this.
|
|
3011
|
+
const highBatchLimit = this.adaptiveBudgeting ? this.adaptiveHighBatchCap ?? configuredHighLimit : configuredHighLimit;
|
|
3012
|
+
processQueue(this.enrichmentHighQueue, highBatchLimit, budgetMs);
|
|
2636
3013
|
if (manual) {
|
|
2637
|
-
processQueue(this.
|
|
2638
|
-
} else if (this.
|
|
3014
|
+
processQueue(this.enrichmentLowQueue, void 0, Number.POSITIVE_INFINITY);
|
|
3015
|
+
} else if (this.enrichmentLowQueue.length > 0) {
|
|
2639
3016
|
elapsed = this.now() - startedAt;
|
|
2640
3017
|
const budgetForLow = Math.max(0, this.lowPriorityFrameBudgetMs - elapsed);
|
|
2641
|
-
|
|
2642
|
-
|
|
3018
|
+
const processedHigherPriorityWork = batches.length > 0;
|
|
3019
|
+
if (budgetForLow > 0 || !processedHigherPriorityWork) {
|
|
3020
|
+
const initialLowQueueSize = this.enrichmentLowQueue.length;
|
|
2643
3021
|
const configuredLowLimit = manual || !this.maxLowPriorityBatchesPerFlush ? void 0 : initialLowQueueSize > this.maxLowPriorityBatchesPerFlush ? void 0 : this.maxLowPriorityBatchesPerFlush;
|
|
2644
|
-
const lowBatchLimit = this.adaptiveLowBatchCap ?? configuredLowLimit;
|
|
2645
|
-
processQueue(this.
|
|
3022
|
+
const lowBatchLimit = this.adaptiveBudgeting ? this.adaptiveLowBatchCap ?? configuredLowLimit : configuredLowLimit;
|
|
3023
|
+
processQueue(this.enrichmentLowQueue, lowBatchLimit, budgetForLow);
|
|
2646
3024
|
}
|
|
2647
3025
|
}
|
|
2648
3026
|
this.flushing = false;
|
|
2649
3027
|
const completedAt = this.now();
|
|
2650
3028
|
const totalDurationMs = completedAt - startedAt;
|
|
2651
|
-
const
|
|
3029
|
+
const remainingSemantic = this.semanticQueue.length;
|
|
3030
|
+
const remainingEnrichment = this.enrichmentHighQueue.length + this.enrichmentLowQueue.length;
|
|
3031
|
+
const remaining = remainingSemantic + remainingEnrichment;
|
|
2652
3032
|
if (batches.length > 0) {
|
|
3033
|
+
this.flushCount += 1;
|
|
2653
3034
|
try {
|
|
2654
3035
|
this.onFlush({
|
|
2655
3036
|
batches,
|
|
@@ -2657,7 +3038,11 @@ var PatchCommitScheduler = class {
|
|
|
2657
3038
|
totalAppliedPatches,
|
|
2658
3039
|
totalDurationMs,
|
|
2659
3040
|
remainingQueueSize: remaining,
|
|
3041
|
+
remainingSemanticQueueSize: remainingSemantic,
|
|
3042
|
+
remainingEnrichmentQueueSize: remainingEnrichment,
|
|
2660
3043
|
queueDepthBefore: initialQueueSize,
|
|
3044
|
+
semanticQueueDepthBefore: initialSemanticQueueSize,
|
|
3045
|
+
enrichmentQueueDepthBefore: initialEnrichmentQueueSize,
|
|
2661
3046
|
flushStartedAt: startedAt,
|
|
2662
3047
|
flushCompletedAt: completedAt
|
|
2663
3048
|
});
|
|
@@ -2668,21 +3053,27 @@ var PatchCommitScheduler = class {
|
|
|
2668
3053
|
if (remaining > 0 && !this.paused) {
|
|
2669
3054
|
this.schedule();
|
|
2670
3055
|
}
|
|
2671
|
-
const coalescingStats = this.computeCoalescingDurationStats();
|
|
2672
|
-
this.
|
|
2673
|
-
|
|
3056
|
+
const coalescingStats = this.adaptiveBudgeting ? this.computeCoalescingDurationStats() : { sampleCount: this.coalescingDurationSamples.length, p95: null };
|
|
3057
|
+
if (this.adaptiveBudgeting) {
|
|
3058
|
+
this.updateAdaptiveBudget(coalescingStats.p95);
|
|
3059
|
+
}
|
|
3060
|
+
const adaptiveState = this.adaptiveBudgeting ? this.snapshotAdaptiveBudget(coalescingStats.p95 ?? null) : void 0;
|
|
2674
3061
|
const flushResult = batches.length > 0 ? {
|
|
2675
3062
|
batches,
|
|
2676
3063
|
totalPatches: totalInputPatches,
|
|
2677
3064
|
totalAppliedPatches,
|
|
2678
3065
|
totalDurationMs,
|
|
2679
3066
|
remainingQueueSize: remaining,
|
|
3067
|
+
remainingSemanticQueueSize: remainingSemantic,
|
|
3068
|
+
remainingEnrichmentQueueSize: remainingEnrichment,
|
|
2680
3069
|
queueDepthBefore: initialQueueSize,
|
|
3070
|
+
semanticQueueDepthBefore: initialSemanticQueueSize,
|
|
3071
|
+
enrichmentQueueDepthBefore: initialEnrichmentQueueSize,
|
|
2681
3072
|
flushStartedAt: startedAt,
|
|
2682
3073
|
flushCompletedAt: completedAt,
|
|
2683
3074
|
coalescingDurationP95: coalescingStats.p95 ?? void 0,
|
|
2684
3075
|
coalescingDurationSampleCount: coalescingStats.sampleCount,
|
|
2685
|
-
adaptiveBudgetActive: adaptiveState
|
|
3076
|
+
adaptiveBudgetActive: adaptiveState?.active,
|
|
2686
3077
|
adaptiveBudgetState: adaptiveState
|
|
2687
3078
|
} : null;
|
|
2688
3079
|
if (flushResult) {
|
|
@@ -2718,6 +3109,9 @@ var PatchCommitScheduler = class {
|
|
|
2718
3109
|
};
|
|
2719
3110
|
}
|
|
2720
3111
|
updateAdaptiveBudget(p95) {
|
|
3112
|
+
if (!this.adaptiveBudgeting) {
|
|
3113
|
+
return;
|
|
3114
|
+
}
|
|
2721
3115
|
if (p95 !== null && p95 > COALESCING_DURATION_ACTIVATE_MS) {
|
|
2722
3116
|
if (!this.adaptiveBudgetActive) {
|
|
2723
3117
|
this.adaptiveBudgetActive = true;
|
|
@@ -2791,11 +3185,13 @@ var PatchCommitScheduler = class {
|
|
|
2791
3185
|
}
|
|
2792
3186
|
restart() {
|
|
2793
3187
|
this.cancelScheduled();
|
|
2794
|
-
this.
|
|
2795
|
-
this.
|
|
3188
|
+
this.semanticQueue = [];
|
|
3189
|
+
this.enrichmentHighQueue = [];
|
|
3190
|
+
this.enrichmentLowQueue = [];
|
|
2796
3191
|
this.flushing = false;
|
|
2797
3192
|
this.sequence = 0;
|
|
2798
3193
|
this.history = [];
|
|
3194
|
+
this.flushCount = 0;
|
|
2799
3195
|
this.scheduleToken++;
|
|
2800
3196
|
this.paused = false;
|
|
2801
3197
|
this.coalescingDurationSamples = [];
|
|
@@ -2842,6 +3238,12 @@ var PatchCommitScheduler = class {
|
|
|
2842
3238
|
if (typeof options.historyLimit !== "undefined") {
|
|
2843
3239
|
this.setHistoryLimit(options.historyLimit);
|
|
2844
3240
|
}
|
|
3241
|
+
if (typeof options.startupMicrotaskFlushes !== "undefined") {
|
|
3242
|
+
this.startupMicrotaskFlushes = Math.max(0, Math.floor(options.startupMicrotaskFlushes));
|
|
3243
|
+
}
|
|
3244
|
+
if (typeof options.adaptiveBudgeting !== "undefined") {
|
|
3245
|
+
this.adaptiveBudgeting = options.adaptiveBudgeting;
|
|
3246
|
+
}
|
|
2845
3247
|
if (typeof options.batch !== "undefined") {
|
|
2846
3248
|
const requestedBatch = options.batch;
|
|
2847
3249
|
if (requestedBatch === "microtask") {
|
|
@@ -2876,6 +3278,7 @@ import {
|
|
|
2876
3278
|
sanitizeHTML as sanitizeHTML2,
|
|
2877
3279
|
PATCH_ROOT_ID
|
|
2878
3280
|
} from "@stream-mdx/core";
|
|
3281
|
+
import { getPatchKind as getPatchKind3 } from "@stream-mdx/core/perf/patch-batching";
|
|
2879
3282
|
|
|
2880
3283
|
// src/renderer/list-utils.ts
|
|
2881
3284
|
function updateNodeDepth(node, depth) {
|
|
@@ -2971,12 +3374,28 @@ function snapshotToBlock(node) {
|
|
|
2971
3374
|
}
|
|
2972
3375
|
return null;
|
|
2973
3376
|
}
|
|
2974
|
-
var
|
|
2975
|
-
var
|
|
3377
|
+
var nodeSnapshotCacheByMap = /* @__PURE__ */ new WeakMap();
|
|
3378
|
+
var childrenSnapshotCacheByMap = /* @__PURE__ */ new WeakMap();
|
|
2976
3379
|
var NODE_SNAPSHOT_CACHE_LIMIT = 5e4;
|
|
2977
3380
|
var CHILDREN_SNAPSHOT_CACHE_LIMIT = 5e4;
|
|
2978
3381
|
var NODE_SNAPSHOT_CACHE_BUFFER = Math.max(200, Math.floor(NODE_SNAPSHOT_CACHE_LIMIT * 0.1));
|
|
2979
3382
|
var CHILDREN_SNAPSHOT_CACHE_BUFFER = Math.max(200, Math.floor(CHILDREN_SNAPSHOT_CACHE_LIMIT * 0.1));
|
|
3383
|
+
function getNodeSnapshotCacheForMap(map) {
|
|
3384
|
+
let cache = nodeSnapshotCacheByMap.get(map);
|
|
3385
|
+
if (!cache) {
|
|
3386
|
+
cache = /* @__PURE__ */ new Map();
|
|
3387
|
+
nodeSnapshotCacheByMap.set(map, cache);
|
|
3388
|
+
}
|
|
3389
|
+
return cache;
|
|
3390
|
+
}
|
|
3391
|
+
function getChildrenSnapshotCacheForMap(map) {
|
|
3392
|
+
let cache = childrenSnapshotCacheByMap.get(map);
|
|
3393
|
+
if (!cache) {
|
|
3394
|
+
cache = /* @__PURE__ */ new Map();
|
|
3395
|
+
childrenSnapshotCacheByMap.set(map, cache);
|
|
3396
|
+
}
|
|
3397
|
+
return cache;
|
|
3398
|
+
}
|
|
2980
3399
|
function pruneCache(cache, max, buffer) {
|
|
2981
3400
|
if (cache.size <= max + buffer) return;
|
|
2982
3401
|
let remaining = cache.size - max;
|
|
@@ -2986,6 +3405,14 @@ function pruneCache(cache, max, buffer) {
|
|
|
2986
3405
|
if (remaining <= 0) break;
|
|
2987
3406
|
}
|
|
2988
3407
|
}
|
|
3408
|
+
function deleteSnapshotCacheEntry(map, id) {
|
|
3409
|
+
getNodeSnapshotCacheForMap(map).delete(id);
|
|
3410
|
+
getChildrenSnapshotCacheForMap(map).delete(id);
|
|
3411
|
+
}
|
|
3412
|
+
function clearSnapshotCaches(map) {
|
|
3413
|
+
getNodeSnapshotCacheForMap(map).clear();
|
|
3414
|
+
getChildrenSnapshotCacheForMap(map).clear();
|
|
3415
|
+
}
|
|
2989
3416
|
var EMPTY_CHILDREN = Object.freeze([]);
|
|
2990
3417
|
var EMPTY_NODE_SNAPSHOT = Object.freeze({ version: -1, node: void 0 });
|
|
2991
3418
|
var EMPTY_CHILDREN_SNAPSHOT = Object.freeze({
|
|
@@ -3153,9 +3580,57 @@ function createRootRecord() {
|
|
|
3153
3580
|
parentId: null,
|
|
3154
3581
|
children: [],
|
|
3155
3582
|
props: {},
|
|
3156
|
-
version: 0
|
|
3583
|
+
version: 0,
|
|
3584
|
+
blockEpoch: 0
|
|
3157
3585
|
};
|
|
3158
3586
|
}
|
|
3587
|
+
function readNumericEpoch(value) {
|
|
3588
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
3589
|
+
return void 0;
|
|
3590
|
+
}
|
|
3591
|
+
return value;
|
|
3592
|
+
}
|
|
3593
|
+
function readSnapshotBlockEpoch(snapshot) {
|
|
3594
|
+
return readNumericEpoch(snapshot.meta?.blockEpoch);
|
|
3595
|
+
}
|
|
3596
|
+
function readPatchBlockEpoch(patch) {
|
|
3597
|
+
if (patch.op === "setHTML") {
|
|
3598
|
+
return readNumericEpoch(patch.patchMeta?.blockEpoch);
|
|
3599
|
+
}
|
|
3600
|
+
return readNumericEpoch(patch.meta?.blockEpoch);
|
|
3601
|
+
}
|
|
3602
|
+
function readPatchParseEpoch(patch) {
|
|
3603
|
+
if (patch.op === "setHTML") {
|
|
3604
|
+
return readNumericEpoch(patch.patchMeta?.parseEpoch);
|
|
3605
|
+
}
|
|
3606
|
+
return readNumericEpoch(patch.meta?.parseEpoch);
|
|
3607
|
+
}
|
|
3608
|
+
function readPatchTx(patch) {
|
|
3609
|
+
if (patch.op === "setHTML") {
|
|
3610
|
+
return readNumericEpoch(patch.patchMeta?.tx);
|
|
3611
|
+
}
|
|
3612
|
+
return readNumericEpoch(patch.meta?.tx);
|
|
3613
|
+
}
|
|
3614
|
+
function assignSubtreeBlockEpoch(map, rootId, blockEpoch, touched) {
|
|
3615
|
+
const root = map.get(rootId);
|
|
3616
|
+
if (!root) return;
|
|
3617
|
+
const stack = [root];
|
|
3618
|
+
while (stack.length > 0) {
|
|
3619
|
+
const node = stack.pop();
|
|
3620
|
+
if (!node) continue;
|
|
3621
|
+
if (node.blockEpoch !== blockEpoch) {
|
|
3622
|
+
node.blockEpoch = blockEpoch;
|
|
3623
|
+
node.version += 1;
|
|
3624
|
+
touched?.add(node.id);
|
|
3625
|
+
}
|
|
3626
|
+
for (const childId of node.children) {
|
|
3627
|
+
const child = map.get(childId);
|
|
3628
|
+
if (child) {
|
|
3629
|
+
stack.push(child);
|
|
3630
|
+
}
|
|
3631
|
+
}
|
|
3632
|
+
}
|
|
3633
|
+
}
|
|
3159
3634
|
function ensureArray(value) {
|
|
3160
3635
|
return Array.isArray(value) ? value : [];
|
|
3161
3636
|
}
|
|
@@ -3215,7 +3690,7 @@ function escapeHtml2(value) {
|
|
|
3215
3690
|
}
|
|
3216
3691
|
function stripOuterLineSpan(html) {
|
|
3217
3692
|
if (!html) return null;
|
|
3218
|
-
const openTagMatch = html.match(/<span[^>]*>/i);
|
|
3693
|
+
const openTagMatch = html.match(/<span[^>]*class="[^"]*\bline\b[^"]*"[^>]*>/i);
|
|
3219
3694
|
if (!openTagMatch) {
|
|
3220
3695
|
return null;
|
|
3221
3696
|
}
|
|
@@ -3264,8 +3739,7 @@ function normalizeCodeBlockChildren(nodes, parent, touched) {
|
|
|
3264
3739
|
if (node.type !== "code-line") {
|
|
3265
3740
|
anomalies.push(`type-mismatch:${node.id}:${node.type}`);
|
|
3266
3741
|
nodes.delete(node.id);
|
|
3267
|
-
|
|
3268
|
-
childrenSnapshotCache.delete(node.id);
|
|
3742
|
+
deleteSnapshotCacheEntry(nodes, node.id);
|
|
3269
3743
|
touched.add(node.id);
|
|
3270
3744
|
continue;
|
|
3271
3745
|
}
|
|
@@ -3309,16 +3783,14 @@ function normalizeCodeBlockChildren(nodes, parent, touched) {
|
|
|
3309
3783
|
const existing = nodes.get(desiredId);
|
|
3310
3784
|
if (existing && existing !== node) {
|
|
3311
3785
|
nodes.delete(desiredId);
|
|
3312
|
-
|
|
3313
|
-
childrenSnapshotCache.delete(desiredId);
|
|
3786
|
+
deleteSnapshotCacheEntry(nodes, desiredId);
|
|
3314
3787
|
touched.add(desiredId);
|
|
3315
3788
|
mutated = true;
|
|
3316
3789
|
}
|
|
3317
3790
|
if (node.id !== desiredId) {
|
|
3318
3791
|
const previousId = node.id;
|
|
3319
3792
|
nodes.delete(node.id);
|
|
3320
|
-
|
|
3321
|
-
childrenSnapshotCache.delete(previousId);
|
|
3793
|
+
deleteSnapshotCacheEntry(nodes, previousId);
|
|
3322
3794
|
node.id = desiredId;
|
|
3323
3795
|
nodes.set(desiredId, node);
|
|
3324
3796
|
touched.add(desiredId);
|
|
@@ -3349,8 +3821,7 @@ function normalizeCodeBlockChildren(nodes, parent, touched) {
|
|
|
3349
3821
|
for (const [id, record] of nodes) {
|
|
3350
3822
|
if (record.parentId === parent.id && record.type === "code-line" && !allowed.has(id)) {
|
|
3351
3823
|
nodes.delete(id);
|
|
3352
|
-
|
|
3353
|
-
childrenSnapshotCache.delete(id);
|
|
3824
|
+
deleteSnapshotCacheEntry(nodes, id);
|
|
3354
3825
|
touched.add(id);
|
|
3355
3826
|
mutated = true;
|
|
3356
3827
|
}
|
|
@@ -3434,8 +3905,10 @@ function normalizeCodeLineProps(incoming, previous) {
|
|
|
3434
3905
|
}
|
|
3435
3906
|
function createCodeLineProps(index, text, highlight, tokens) {
|
|
3436
3907
|
const safeText = typeof text === "string" ? text : "";
|
|
3437
|
-
const
|
|
3438
|
-
const
|
|
3908
|
+
const hasIncomingHighlight = typeof highlight === "string" && highlight.trim().length > 0;
|
|
3909
|
+
const sanitized = hasIncomingHighlight ? sanitizeLineInnerHtml(highlight, safeText) : null;
|
|
3910
|
+
const hasRenderableTokens = tokens !== void 0 && tokens !== null;
|
|
3911
|
+
const html = sanitized && sanitized.length >= safeText.length ? sanitized : hasRenderableTokens ? null : escapeHtml2(safeText);
|
|
3439
3912
|
const props = {
|
|
3440
3913
|
index,
|
|
3441
3914
|
text: safeText,
|
|
@@ -3546,6 +4019,18 @@ function validateCodeBlockChildren(nodes, parent) {
|
|
|
3546
4019
|
issues.push({ kind: "dangling-node", id });
|
|
3547
4020
|
}
|
|
3548
4021
|
}
|
|
4022
|
+
if (parent.block?.isFinalized) {
|
|
4023
|
+
const snapshot = createBlockSnapshot(cloneBlock(parent.block));
|
|
4024
|
+
const expectedChildren = ensureArray(snapshot.children).filter((child) => child.type === "code-line");
|
|
4025
|
+
if (expectedChildren.length !== parent.children.length) {
|
|
4026
|
+
issues.push({
|
|
4027
|
+
kind: "line-count-mismatch",
|
|
4028
|
+
id: parent.id,
|
|
4029
|
+
expected: expectedChildren.length,
|
|
4030
|
+
actual: parent.children.length
|
|
4031
|
+
});
|
|
4032
|
+
}
|
|
4033
|
+
}
|
|
3549
4034
|
return { ok: issues.length === 0, issues };
|
|
3550
4035
|
}
|
|
3551
4036
|
function rebuildCodeBlockFromSnapshot(nodes, parent, touched, issues) {
|
|
@@ -3562,7 +4047,7 @@ function rebuildCodeBlockFromSnapshot(nodes, parent, touched, issues) {
|
|
|
3562
4047
|
}
|
|
3563
4048
|
const snapshot = createBlockSnapshot(cloneBlock(parent.block));
|
|
3564
4049
|
removeSubtree(nodes, parent.id, touched);
|
|
3565
|
-
const inserted = insertSnapshotAt(nodes, ancestor, index, snapshot);
|
|
4050
|
+
const inserted = insertSnapshotAt(nodes, ancestor, index, snapshot, touched, parent.blockEpoch);
|
|
3566
4051
|
if (!inserted) {
|
|
3567
4052
|
return false;
|
|
3568
4053
|
}
|
|
@@ -3585,7 +4070,55 @@ function arraysEqual(a, b) {
|
|
|
3585
4070
|
}
|
|
3586
4071
|
return true;
|
|
3587
4072
|
}
|
|
3588
|
-
function
|
|
4073
|
+
function expectedCodeLineId(parentId, index) {
|
|
4074
|
+
return `${parentId}::line:${index}`;
|
|
4075
|
+
}
|
|
4076
|
+
function collectStoreInvariantViolations(nodes) {
|
|
4077
|
+
const violations = [];
|
|
4078
|
+
for (const [id, node] of nodes) {
|
|
4079
|
+
if (node.type === "__root__") continue;
|
|
4080
|
+
if (node.children.length > 1) {
|
|
4081
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4082
|
+
for (const childId of node.children) {
|
|
4083
|
+
if (seen.has(childId)) {
|
|
4084
|
+
violations.push(`duplicate child id:${id}:${childId}`);
|
|
4085
|
+
} else {
|
|
4086
|
+
seen.add(childId);
|
|
4087
|
+
}
|
|
4088
|
+
}
|
|
4089
|
+
}
|
|
4090
|
+
if (node.type === "list") {
|
|
4091
|
+
const parent = node.parentId ? nodes.get(node.parentId) : void 0;
|
|
4092
|
+
if (parent?.type === "list-item" && node.children.length === 0) {
|
|
4093
|
+
violations.push(`empty nested list:${id}`);
|
|
4094
|
+
}
|
|
4095
|
+
}
|
|
4096
|
+
if (node.type === "code") {
|
|
4097
|
+
for (let index = 0; index < node.children.length; index += 1) {
|
|
4098
|
+
const childId = node.children[index];
|
|
4099
|
+
const child = nodes.get(childId);
|
|
4100
|
+
if (!child) {
|
|
4101
|
+
violations.push(`missing code-line node:${node.id}:${childId}`);
|
|
4102
|
+
continue;
|
|
4103
|
+
}
|
|
4104
|
+
if (child.type !== "code-line") {
|
|
4105
|
+
violations.push(`non-code child in code block:${node.id}:${child.id}:${child.type}`);
|
|
4106
|
+
continue;
|
|
4107
|
+
}
|
|
4108
|
+
const expectedId = expectedCodeLineId(node.id, index);
|
|
4109
|
+
if (child.id !== expectedId) {
|
|
4110
|
+
violations.push(`code-line id mismatch:${node.id}:${child.id}:${expectedId}`);
|
|
4111
|
+
}
|
|
4112
|
+
const indexProp = typeof child.props?.index === "number" ? child.props.index : null;
|
|
4113
|
+
if (indexProp !== index) {
|
|
4114
|
+
violations.push(`code-line index mismatch:${node.id}:${child.id}:${indexProp}:${index}`);
|
|
4115
|
+
}
|
|
4116
|
+
}
|
|
4117
|
+
}
|
|
4118
|
+
}
|
|
4119
|
+
return violations;
|
|
4120
|
+
}
|
|
4121
|
+
function buildNodeFromSnapshot(map, snapshot, parentId, blockEpoch) {
|
|
3589
4122
|
const record = {
|
|
3590
4123
|
id: snapshot.id,
|
|
3591
4124
|
type: snapshot.type,
|
|
@@ -3595,6 +4128,7 @@ function buildNodeFromSnapshot(map, snapshot, parentId) {
|
|
|
3595
4128
|
meta: snapshot.meta ? { ...snapshot.meta } : void 0,
|
|
3596
4129
|
range: snapshot.range ? { ...snapshot.range } : void 0,
|
|
3597
4130
|
version: 0,
|
|
4131
|
+
blockEpoch,
|
|
3598
4132
|
block: snapshotToBlock(snapshot) ?? void 0
|
|
3599
4133
|
};
|
|
3600
4134
|
if (record.type === "code") {
|
|
@@ -3603,7 +4137,7 @@ function buildNodeFromSnapshot(map, snapshot, parentId) {
|
|
|
3603
4137
|
map.set(record.id, record);
|
|
3604
4138
|
const childSnapshots = ensureArray(snapshot.children);
|
|
3605
4139
|
for (const child of childSnapshots) {
|
|
3606
|
-
const childRecord = buildNodeFromSnapshot(map, child, record.id);
|
|
4140
|
+
const childRecord = buildNodeFromSnapshot(map, child, record.id, blockEpoch);
|
|
3607
4141
|
record.children.push(childRecord.id);
|
|
3608
4142
|
}
|
|
3609
4143
|
return record;
|
|
@@ -3631,8 +4165,7 @@ function removeSubtree(map, id, touched) {
|
|
|
3631
4165
|
}
|
|
3632
4166
|
}
|
|
3633
4167
|
map.delete(node.id);
|
|
3634
|
-
|
|
3635
|
-
childrenSnapshotCache.delete(node.id);
|
|
4168
|
+
deleteSnapshotCacheEntry(map, node.id);
|
|
3636
4169
|
touched.add(node.id);
|
|
3637
4170
|
for (const childId of node.children) {
|
|
3638
4171
|
const child = map.get(childId);
|
|
@@ -3664,13 +4197,13 @@ function resolveParent(map, path) {
|
|
|
3664
4197
|
}
|
|
3665
4198
|
return map.get(path.blockId);
|
|
3666
4199
|
}
|
|
3667
|
-
function insertSnapshotAt(map, parent, index, snapshot, touched) {
|
|
4200
|
+
function insertSnapshotAt(map, parent, index, snapshot, touched, blockEpoch) {
|
|
3668
4201
|
if (!parent) return null;
|
|
3669
4202
|
const existingIndex = parent.children.indexOf(snapshot.id);
|
|
3670
4203
|
if (existingIndex !== -1) {
|
|
3671
4204
|
removeSubtree(map, parent.children[existingIndex], touched ?? /* @__PURE__ */ new Set());
|
|
3672
4205
|
}
|
|
3673
|
-
const record = buildNodeFromSnapshot(map, snapshot, parent.id);
|
|
4206
|
+
const record = buildNodeFromSnapshot(map, snapshot, parent.id, blockEpoch ?? readSnapshotBlockEpoch(snapshot) ?? parent.blockEpoch);
|
|
3674
4207
|
const insertedIds = [];
|
|
3675
4208
|
const queue = [record];
|
|
3676
4209
|
while (queue.length > 0) {
|
|
@@ -3688,13 +4221,13 @@ function insertSnapshotAt(map, parent, index, snapshot, touched) {
|
|
|
3688
4221
|
ensureUniqueChildren(parent, touched);
|
|
3689
4222
|
return { record, insertedIds };
|
|
3690
4223
|
}
|
|
3691
|
-
function replaceSnapshotAt(map, parent, index, snapshot, touched) {
|
|
4224
|
+
function replaceSnapshotAt(map, parent, index, snapshot, touched, blockEpoch) {
|
|
3692
4225
|
if (!parent) return;
|
|
3693
4226
|
if (index < 0 || index >= parent.children.length) return;
|
|
3694
4227
|
const targetId = parent.children[index];
|
|
3695
4228
|
parent.children.splice(index, 1);
|
|
3696
4229
|
removeSubtree(map, targetId, touched);
|
|
3697
|
-
const inserted = insertSnapshotAt(map, parent, index, snapshot, touched);
|
|
4230
|
+
const inserted = insertSnapshotAt(map, parent, index, snapshot, touched, blockEpoch);
|
|
3698
4231
|
if (inserted) {
|
|
3699
4232
|
for (const id of inserted.insertedIds) {
|
|
3700
4233
|
touched.add(id);
|
|
@@ -3714,6 +4247,24 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3714
4247
|
const listeners = /* @__PURE__ */ new Set();
|
|
3715
4248
|
let notifyScheduled = false;
|
|
3716
4249
|
let lastCoalescingMetrics = null;
|
|
4250
|
+
let invariantViolations = [];
|
|
4251
|
+
let transientDiagnostics = [];
|
|
4252
|
+
let nextBlockEpoch = 1;
|
|
4253
|
+
const debugCounters = {
|
|
4254
|
+
appendLineGuardRejected: 0,
|
|
4255
|
+
staleEpochRejected: 0,
|
|
4256
|
+
storeInvariantViolationCount: 0
|
|
4257
|
+
};
|
|
4258
|
+
const allocateBlockEpoch = (preferred) => {
|
|
4259
|
+
const resolved = readNumericEpoch(preferred);
|
|
4260
|
+
if (resolved !== void 0) {
|
|
4261
|
+
nextBlockEpoch = Math.max(nextBlockEpoch, resolved + 1);
|
|
4262
|
+
return resolved;
|
|
4263
|
+
}
|
|
4264
|
+
const epoch = nextBlockEpoch;
|
|
4265
|
+
nextBlockEpoch += 1;
|
|
4266
|
+
return epoch;
|
|
4267
|
+
};
|
|
3717
4268
|
const getRaf = () => {
|
|
3718
4269
|
if (typeof globalThis !== "undefined" && typeof globalThis.requestAnimationFrame === "function") {
|
|
3719
4270
|
return globalThis.requestAnimationFrame;
|
|
@@ -3745,9 +4296,12 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3745
4296
|
}
|
|
3746
4297
|
}
|
|
3747
4298
|
}
|
|
4299
|
+
function appendDiagnostic(message) {
|
|
4300
|
+
transientDiagnostics = [...transientDiagnostics, message];
|
|
4301
|
+
invariantViolations = [...invariantViolations, message];
|
|
4302
|
+
}
|
|
3748
4303
|
function rebuildFromBlocks(blocks) {
|
|
3749
|
-
|
|
3750
|
-
childrenSnapshotCache.clear();
|
|
4304
|
+
clearSnapshotCaches(nodes);
|
|
3751
4305
|
nodes = /* @__PURE__ */ new Map();
|
|
3752
4306
|
const root = createRootRecord();
|
|
3753
4307
|
nodes.set(root.id, root);
|
|
@@ -3756,9 +4310,12 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3756
4310
|
for (let i = 0; i < blocks.length; i++) {
|
|
3757
4311
|
const block = cloneBlock(blocks[i]);
|
|
3758
4312
|
const snapshot = createBlockSnapshot(block);
|
|
3759
|
-
insertSnapshotAt(nodes, root, root.children.length, snapshot);
|
|
4313
|
+
insertSnapshotAt(nodes, root, root.children.length, snapshot, void 0, allocateBlockEpoch(readSnapshotBlockEpoch(snapshot)));
|
|
3760
4314
|
}
|
|
3761
4315
|
normalizeAllListDepths(nodes, /* @__PURE__ */ new Set(), PATCH_ROOT_ID);
|
|
4316
|
+
transientDiagnostics = [];
|
|
4317
|
+
invariantViolations = collectStoreInvariantViolations(nodes);
|
|
4318
|
+
debugCounters.storeInvariantViolationCount += invariantViolations.length;
|
|
3762
4319
|
version++;
|
|
3763
4320
|
blocksDirty = true;
|
|
3764
4321
|
scheduleNotify();
|
|
@@ -3823,11 +4380,57 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3823
4380
|
listDepthDirty = true;
|
|
3824
4381
|
}
|
|
3825
4382
|
};
|
|
3826
|
-
const
|
|
4383
|
+
const semanticTxEpochs = /* @__PURE__ */ new Map();
|
|
4384
|
+
const resolveBlockEpochTarget = (patch, at) => {
|
|
4385
|
+
if ((patch.op === "insertChild" || patch.op === "replaceChild") && at.blockId === PATCH_ROOT_ID) {
|
|
4386
|
+
const nodeId = patch.node?.id;
|
|
4387
|
+
return nodeId ? nodes.get(nodeId) : void 0;
|
|
4388
|
+
}
|
|
4389
|
+
return nodes.get(at.blockId) ?? (at.nodeId ? nodes.get(at.nodeId) : void 0);
|
|
4390
|
+
};
|
|
4391
|
+
const rejectStaleEpochPatch = (patch, at) => {
|
|
4392
|
+
const expectedBlockEpoch = readPatchBlockEpoch(patch);
|
|
4393
|
+
const patchTx = readPatchTx(patch);
|
|
4394
|
+
if (expectedBlockEpoch === void 0) {
|
|
4395
|
+
return false;
|
|
4396
|
+
}
|
|
4397
|
+
if (getPatchKind3(patch) !== "semantic" || !at) {
|
|
4398
|
+
return false;
|
|
4399
|
+
}
|
|
4400
|
+
const target = resolveBlockEpochTarget(patch, at);
|
|
4401
|
+
if (!target || target.blockEpoch === expectedBlockEpoch) {
|
|
4402
|
+
return false;
|
|
4403
|
+
}
|
|
4404
|
+
const txEpoch = at.blockId && patchTx !== void 0 ? semanticTxEpochs.get(at.blockId) : void 0;
|
|
4405
|
+
if (txEpoch && txEpoch.tx === patchTx && txEpoch.blockEpoch === target.blockEpoch) {
|
|
4406
|
+
return false;
|
|
4407
|
+
}
|
|
4408
|
+
debugCounters.staleEpochRejected += 1;
|
|
4409
|
+
appendDiagnostic(
|
|
4410
|
+
`stale epoch rejected:${patch.op}:${target.id}:expected=${expectedBlockEpoch}:actual=${target.blockEpoch}`
|
|
4411
|
+
);
|
|
4412
|
+
return true;
|
|
4413
|
+
};
|
|
4414
|
+
const advanceBlockEpoch = (blockId, touchedSet, preferredEpoch, tx) => {
|
|
4415
|
+
if (!blockId || blockId === PATCH_ROOT_ID) {
|
|
4416
|
+
return null;
|
|
4417
|
+
}
|
|
4418
|
+
const blockRoot = nodes.get(blockId);
|
|
4419
|
+
if (!blockRoot) {
|
|
4420
|
+
return null;
|
|
4421
|
+
}
|
|
4422
|
+
const nextEpoch = allocateBlockEpoch(preferredEpoch);
|
|
4423
|
+
assignSubtreeBlockEpoch(nodes, blockRoot.id, nextEpoch, touchedSet);
|
|
4424
|
+
if (tx !== void 0) {
|
|
4425
|
+
semanticTxEpochs.set(blockRoot.id, { tx, blockEpoch: nextEpoch });
|
|
4426
|
+
}
|
|
4427
|
+
return nextEpoch;
|
|
4428
|
+
};
|
|
4429
|
+
const applyPropsUpdate = (at, props, preferredEpoch, tx, semanticUpdate = false) => {
|
|
3827
4430
|
const perfStartLocal = perfEnabled ? getPerfNow() : 0;
|
|
3828
4431
|
const targetId = at.nodeId ?? at.blockId;
|
|
3829
4432
|
if (!targetId) return;
|
|
3830
|
-
|
|
4433
|
+
let target = nodes.get(targetId);
|
|
3831
4434
|
if (!target) return;
|
|
3832
4435
|
const parentType = target.parentId ? nodes.get(target.parentId)?.type : void 0;
|
|
3833
4436
|
if (debugListPatches && (isListRelated(target.type) || isListRelated(parentType))) {
|
|
@@ -3854,6 +4457,9 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3854
4457
|
propsChanged = true;
|
|
3855
4458
|
}
|
|
3856
4459
|
if (propsChanged) {
|
|
4460
|
+
if (semanticUpdate) {
|
|
4461
|
+
advanceBlockEpoch(at.blockId, touched, preferredEpoch, tx);
|
|
4462
|
+
}
|
|
3857
4463
|
target.version++;
|
|
3858
4464
|
touched.add(target.id);
|
|
3859
4465
|
const parent = target.parentId ? nodes.get(target.parentId) : void 0;
|
|
@@ -3917,16 +4523,56 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3917
4523
|
}
|
|
3918
4524
|
}
|
|
3919
4525
|
let blockChanged = false;
|
|
4526
|
+
let typeChanged = false;
|
|
4527
|
+
let rebuiltFromFinalizedBlock = false;
|
|
4528
|
+
let blockEpochAdvanced = false;
|
|
3920
4529
|
const incomingBlock = props?.block;
|
|
3921
4530
|
if (incomingBlock && typeof incomingBlock === "object") {
|
|
3922
4531
|
target.block = cloneBlock(incomingBlock);
|
|
4532
|
+
const previousType = target.type;
|
|
4533
|
+
const incomingType = typeof target.block.type === "string" ? target.block.type : target.type;
|
|
4534
|
+
if (incomingType !== target.type) {
|
|
4535
|
+
target.type = incomingType;
|
|
4536
|
+
typeChanged = true;
|
|
4537
|
+
if (isListRelated(previousType) || isListRelated(target.type)) {
|
|
4538
|
+
markListDepthDirty(target.id);
|
|
4539
|
+
}
|
|
4540
|
+
}
|
|
3923
4541
|
if (target.type === "code") {
|
|
3924
4542
|
applyCodeBlockMetadata(target);
|
|
3925
4543
|
}
|
|
4544
|
+
if (semanticUpdate) {
|
|
4545
|
+
advanceBlockEpoch(at.blockId, touched, preferredEpoch, tx);
|
|
4546
|
+
blockEpochAdvanced = true;
|
|
4547
|
+
}
|
|
4548
|
+
const shouldRebuildFinalizedTree = !at.nodeId && target.id === at.blockId && Boolean(target.block?.isFinalized) && target.type !== "code" && Boolean(target.parentId);
|
|
4549
|
+
if (shouldRebuildFinalizedTree) {
|
|
4550
|
+
const parent = target.parentId ? nodes.get(target.parentId) : void 0;
|
|
4551
|
+
const index = parent ? parent.children.indexOf(target.id) : -1;
|
|
4552
|
+
if (parent && index !== -1) {
|
|
4553
|
+
const snapshot = createBlockSnapshot(cloneBlock(target.block));
|
|
4554
|
+
replaceSnapshotAt(nodes, parent, index, snapshot, touched, target.blockEpoch);
|
|
4555
|
+
mutatedBlocks = true;
|
|
4556
|
+
blockChanged = true;
|
|
4557
|
+
rebuiltFromFinalizedBlock = true;
|
|
4558
|
+
const rebuilt = nodes.get(target.id);
|
|
4559
|
+
if (isListRelated(previousType) || isListRelated(rebuilt?.type)) {
|
|
4560
|
+
markListDepthDirty(target.id);
|
|
4561
|
+
}
|
|
4562
|
+
target = rebuilt ?? target;
|
|
4563
|
+
}
|
|
4564
|
+
}
|
|
3926
4565
|
mutatedBlocks = true;
|
|
3927
4566
|
blockChanged = true;
|
|
3928
4567
|
}
|
|
3929
|
-
if (
|
|
4568
|
+
if (rebuiltFromFinalizedBlock) {
|
|
4569
|
+
return;
|
|
4570
|
+
}
|
|
4571
|
+
if (propsChanged || blockChanged || typeChanged) {
|
|
4572
|
+
if (semanticUpdate && !blockEpochAdvanced) {
|
|
4573
|
+
advanceBlockEpoch(at.blockId, touched, preferredEpoch, tx);
|
|
4574
|
+
blockEpochAdvanced = true;
|
|
4575
|
+
}
|
|
3930
4576
|
target.version++;
|
|
3931
4577
|
touched.add(target.id);
|
|
3932
4578
|
let parentForNormalization;
|
|
@@ -3969,13 +4615,22 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3969
4615
|
const applyPatch = (patch) => {
|
|
3970
4616
|
switch (patch.op) {
|
|
3971
4617
|
case "insertChild": {
|
|
4618
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3972
4619
|
const parent = resolveParent(nodes, patch.at);
|
|
3973
|
-
const inserted = insertSnapshotAt(
|
|
4620
|
+
const inserted = insertSnapshotAt(
|
|
4621
|
+
nodes,
|
|
4622
|
+
parent,
|
|
4623
|
+
patch.index,
|
|
4624
|
+
patch.node,
|
|
4625
|
+
touched,
|
|
4626
|
+
allocateBlockEpoch(readPatchParseEpoch(patch) ?? readSnapshotBlockEpoch(patch.node))
|
|
4627
|
+
);
|
|
3974
4628
|
if (inserted) {
|
|
3975
4629
|
for (const id of inserted.insertedIds) {
|
|
3976
4630
|
touched.add(id);
|
|
3977
4631
|
}
|
|
3978
4632
|
mutatedBlocks = true;
|
|
4633
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
3979
4634
|
if (isListRelated(inserted.record.type) || isListRelated(parent?.type)) {
|
|
3980
4635
|
markListDepthDirty(inserted.record.id);
|
|
3981
4636
|
if (parent) {
|
|
@@ -3995,6 +4650,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3995
4650
|
break;
|
|
3996
4651
|
}
|
|
3997
4652
|
case "deleteChild": {
|
|
4653
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3998
4654
|
const parent = resolveParent(nodes, patch.at);
|
|
3999
4655
|
if (!parent) break;
|
|
4000
4656
|
if (patch.index < 0 || patch.index >= parent.children.length) break;
|
|
@@ -4006,6 +4662,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
4006
4662
|
touched.add(parent.id);
|
|
4007
4663
|
ensureUniqueChildren(parent, touched);
|
|
4008
4664
|
mutatedBlocks = true;
|
|
4665
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
4009
4666
|
if (isListRelated(parent.type) || isListRelated(removedNode?.type)) {
|
|
4010
4667
|
markListDepthDirty(parent.id);
|
|
4011
4668
|
}
|
|
@@ -4022,11 +4679,20 @@ function createRendererStore(initialBlocks = []) {
|
|
|
4022
4679
|
break;
|
|
4023
4680
|
}
|
|
4024
4681
|
case "replaceChild": {
|
|
4682
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
4025
4683
|
const parent = resolveParent(nodes, patch.at);
|
|
4026
4684
|
if (!parent) break;
|
|
4027
|
-
replaceSnapshotAt(
|
|
4685
|
+
replaceSnapshotAt(
|
|
4686
|
+
nodes,
|
|
4687
|
+
parent,
|
|
4688
|
+
patch.index,
|
|
4689
|
+
patch.node,
|
|
4690
|
+
touched,
|
|
4691
|
+
allocateBlockEpoch(readPatchParseEpoch(patch) ?? readSnapshotBlockEpoch(patch.node))
|
|
4692
|
+
);
|
|
4028
4693
|
touched.add(parent.id);
|
|
4029
4694
|
mutatedBlocks = true;
|
|
4695
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
4030
4696
|
if (isListRelated(parent.type)) {
|
|
4031
4697
|
markListDepthDirty(parent.id);
|
|
4032
4698
|
}
|
|
@@ -4040,18 +4706,33 @@ function createRendererStore(initialBlocks = []) {
|
|
|
4040
4706
|
break;
|
|
4041
4707
|
}
|
|
4042
4708
|
case "setProps": {
|
|
4043
|
-
|
|
4709
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
4710
|
+
applyPropsUpdate(patch.at, patch.props, readPatchParseEpoch(patch), readPatchTx(patch), getPatchKind3(patch) === "semantic");
|
|
4044
4711
|
break;
|
|
4045
4712
|
}
|
|
4046
4713
|
case "setPropsBatch": {
|
|
4047
4714
|
const entries2 = Array.isArray(patch.entries) ? patch.entries : [];
|
|
4048
4715
|
for (const entry of entries2) {
|
|
4049
4716
|
if (!entry || !entry.at) continue;
|
|
4050
|
-
|
|
4717
|
+
const entryPatch = {
|
|
4718
|
+
op: "setProps",
|
|
4719
|
+
at: entry.at,
|
|
4720
|
+
props: entry.props,
|
|
4721
|
+
meta: entry.meta ?? patch.meta
|
|
4722
|
+
};
|
|
4723
|
+
if (rejectStaleEpochPatch(entryPatch, entry.at)) continue;
|
|
4724
|
+
applyPropsUpdate(
|
|
4725
|
+
entry.at,
|
|
4726
|
+
entry.props,
|
|
4727
|
+
readPatchParseEpoch(entryPatch),
|
|
4728
|
+
readPatchTx(entryPatch),
|
|
4729
|
+
getPatchKind3(entryPatch) === "semantic"
|
|
4730
|
+
);
|
|
4051
4731
|
}
|
|
4052
4732
|
break;
|
|
4053
4733
|
}
|
|
4054
4734
|
case "finalize": {
|
|
4735
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
4055
4736
|
const target = nodes.get(patch.at.nodeId ?? patch.at.blockId);
|
|
4056
4737
|
if (!target || !target.block) break;
|
|
4057
4738
|
if (!target.block.isFinalized) {
|
|
@@ -4060,6 +4741,17 @@ function createRendererStore(initialBlocks = []) {
|
|
|
4060
4741
|
target.version++;
|
|
4061
4742
|
touched.add(target.id);
|
|
4062
4743
|
mutatedBlocks = true;
|
|
4744
|
+
if (!patch.at.nodeId && target.id === patch.at.blockId && target.type !== "code" && target.parentId) {
|
|
4745
|
+
const parent = nodes.get(target.parentId);
|
|
4746
|
+
const index = parent ? parent.children.indexOf(target.id) : -1;
|
|
4747
|
+
if (parent && index !== -1) {
|
|
4748
|
+
const snapshot = createBlockSnapshot(cloneBlock(target.block));
|
|
4749
|
+
replaceSnapshotAt(nodes, parent, index, snapshot, touched, target.blockEpoch);
|
|
4750
|
+
if (isListRelated(target.type) || isListRelated(snapshot.type)) {
|
|
4751
|
+
markListDepthDirty(target.id);
|
|
4752
|
+
}
|
|
4753
|
+
}
|
|
4754
|
+
}
|
|
4063
4755
|
}
|
|
4064
4756
|
if (isListRelated(target.type)) {
|
|
4065
4757
|
markListDepthDirty(target.id);
|
|
@@ -4073,6 +4765,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
4073
4765
|
break;
|
|
4074
4766
|
}
|
|
4075
4767
|
case "reorder": {
|
|
4768
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
4076
4769
|
const parent = resolveParent(nodes, patch.at);
|
|
4077
4770
|
if (!parent) break;
|
|
4078
4771
|
const length = parent.children.length;
|
|
@@ -4087,6 +4780,9 @@ function createRendererStore(initialBlocks = []) {
|
|
|
4087
4780
|
parent.children.splice(to, 0, ...moved);
|
|
4088
4781
|
parent.version++;
|
|
4089
4782
|
touched.add(parent.id);
|
|
4783
|
+
if (getPatchKind3(patch) === "semantic") {
|
|
4784
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
4785
|
+
}
|
|
4090
4786
|
if (isListRelated(parent.type)) {
|
|
4091
4787
|
markListDepthDirty(parent.id);
|
|
4092
4788
|
}
|
|
@@ -4102,15 +4798,31 @@ function createRendererStore(initialBlocks = []) {
|
|
|
4102
4798
|
break;
|
|
4103
4799
|
}
|
|
4104
4800
|
case "appendLines": {
|
|
4801
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
4105
4802
|
const parent = resolveParent(nodes, patch.at);
|
|
4106
4803
|
if (!parent) break;
|
|
4107
|
-
|
|
4804
|
+
if (parent.type !== "code") {
|
|
4805
|
+
debugCounters.appendLineGuardRejected += 1;
|
|
4806
|
+
appendDiagnostic(`appendLines target not code:${parent.id}:${parent.type}`);
|
|
4807
|
+
break;
|
|
4808
|
+
}
|
|
4809
|
+
const requestedStartIndex = Math.max(0, patch.startIndex);
|
|
4810
|
+
const startIndex = Math.max(0, Math.min(requestedStartIndex, parent.children.length));
|
|
4108
4811
|
const lineCount = patch.lines?.length ?? 0;
|
|
4109
4812
|
if (lineCount === 0) break;
|
|
4813
|
+
const prefixMatches = parent.children.every((childId, index) => childId === expectedCodeLineId(parent.id, index));
|
|
4814
|
+
const isStrictTailAppend = requestedStartIndex === parent.children.length;
|
|
4815
|
+
if (!isStrictTailAppend || !prefixMatches) {
|
|
4816
|
+
debugCounters.appendLineGuardRejected += 1;
|
|
4817
|
+
appendDiagnostic(
|
|
4818
|
+
`appendLines guard rejected:${parent.id}:requestedStart=${requestedStartIndex}:childCount=${parent.children.length}:prefixMatches=${prefixMatches}`
|
|
4819
|
+
);
|
|
4820
|
+
break;
|
|
4821
|
+
}
|
|
4110
4822
|
const originalChildren = parent.children.slice();
|
|
4111
4823
|
const insertedIds = [];
|
|
4112
4824
|
const insertedSet = /* @__PURE__ */ new Set();
|
|
4113
|
-
const isTrailingAppend =
|
|
4825
|
+
const isTrailingAppend = true;
|
|
4114
4826
|
let parentChildrenChanged = false;
|
|
4115
4827
|
let codeLinesMutated = false;
|
|
4116
4828
|
for (let offset = 0; offset < lineCount; offset++) {
|
|
@@ -4152,7 +4864,8 @@ function createRendererStore(initialBlocks = []) {
|
|
|
4152
4864
|
parentId: parent.id,
|
|
4153
4865
|
children: [],
|
|
4154
4866
|
props: nextLineProps,
|
|
4155
|
-
version: 0
|
|
4867
|
+
version: 0,
|
|
4868
|
+
blockEpoch: parent.blockEpoch
|
|
4156
4869
|
};
|
|
4157
4870
|
nodes.set(lineId, record);
|
|
4158
4871
|
touched.add(lineId);
|
|
@@ -4202,6 +4915,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
4202
4915
|
break;
|
|
4203
4916
|
}
|
|
4204
4917
|
case "setHTML": {
|
|
4918
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
4205
4919
|
const target = nodes.get(patch.at.nodeId ?? patch.at.blockId);
|
|
4206
4920
|
if (!target) break;
|
|
4207
4921
|
const sanitized = patch.sanitized ? patch.html : sanitizeHTML2(patch.html);
|
|
@@ -4244,6 +4958,30 @@ function createRendererStore(initialBlocks = []) {
|
|
|
4244
4958
|
applyPatch(patch);
|
|
4245
4959
|
}
|
|
4246
4960
|
}
|
|
4961
|
+
const finalizedTableRoots = /* @__PURE__ */ new Set();
|
|
4962
|
+
for (const touchedId of touched) {
|
|
4963
|
+
let cursor = nodes.get(touchedId);
|
|
4964
|
+
while (cursor && cursor.id !== PATCH_ROOT_ID) {
|
|
4965
|
+
if (cursor.type === "table" && cursor.block?.isFinalized && cursor.parentId) {
|
|
4966
|
+
finalizedTableRoots.add(cursor.id);
|
|
4967
|
+
break;
|
|
4968
|
+
}
|
|
4969
|
+
cursor = cursor.parentId ? nodes.get(cursor.parentId) : void 0;
|
|
4970
|
+
}
|
|
4971
|
+
}
|
|
4972
|
+
if (finalizedTableRoots.size > 0) {
|
|
4973
|
+
for (const tableId of finalizedTableRoots) {
|
|
4974
|
+
const tableNode = nodes.get(tableId);
|
|
4975
|
+
if (!tableNode || !tableNode.block || !tableNode.parentId) continue;
|
|
4976
|
+
const parent = nodes.get(tableNode.parentId);
|
|
4977
|
+
if (!parent) continue;
|
|
4978
|
+
const index = parent.children.indexOf(tableNode.id);
|
|
4979
|
+
if (index === -1) continue;
|
|
4980
|
+
const snapshot = createBlockSnapshot(cloneBlock(tableNode.block));
|
|
4981
|
+
replaceSnapshotAt(nodes, parent, index, snapshot, touched, tableNode.blockEpoch);
|
|
4982
|
+
mutatedBlocks = true;
|
|
4983
|
+
}
|
|
4984
|
+
}
|
|
4247
4985
|
if (mutatedBlocks) {
|
|
4248
4986
|
blocksDirty = true;
|
|
4249
4987
|
}
|
|
@@ -4264,6 +5002,8 @@ function createRendererStore(initialBlocks = []) {
|
|
|
4264
5002
|
normalizeListDepthsForIds(nodes, touched, listDepthDirtyNodes, PATCH_ROOT_ID);
|
|
4265
5003
|
}
|
|
4266
5004
|
}
|
|
5005
|
+
invariantViolations = [...collectStoreInvariantViolations(nodes), ...transientDiagnostics];
|
|
5006
|
+
debugCounters.storeInvariantViolationCount += invariantViolations.length;
|
|
4267
5007
|
if (touched.size > 0 || mutatedBlocks) {
|
|
4268
5008
|
version++;
|
|
4269
5009
|
scheduleNotify();
|
|
@@ -4312,6 +5052,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
4312
5052
|
if (!record) {
|
|
4313
5053
|
return EMPTY_NODE_SNAPSHOT;
|
|
4314
5054
|
}
|
|
5055
|
+
const nodeSnapshotCache = getNodeSnapshotCacheForMap(nodes);
|
|
4315
5056
|
const cached = nodeSnapshotCache.get(id);
|
|
4316
5057
|
if (cached && cached.version === record.version && cached.node === record) {
|
|
4317
5058
|
return cached;
|
|
@@ -4331,6 +5072,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
4331
5072
|
if (!record) {
|
|
4332
5073
|
return EMPTY_CHILDREN_SNAPSHOT;
|
|
4333
5074
|
}
|
|
5075
|
+
const childrenSnapshotCache = getChildrenSnapshotCacheForMap(nodes);
|
|
4334
5076
|
const cached = childrenSnapshotCache.get(id);
|
|
4335
5077
|
if (cached && cached.version === record.version) {
|
|
4336
5078
|
return cached;
|
|
@@ -4340,6 +5082,12 @@ function createRendererStore(initialBlocks = []) {
|
|
|
4340
5082
|
pruneCache(childrenSnapshotCache, CHILDREN_SNAPSHOT_CACHE_LIMIT, CHILDREN_SNAPSHOT_CACHE_BUFFER);
|
|
4341
5083
|
return snapshot;
|
|
4342
5084
|
},
|
|
5085
|
+
getInvariantViolations() {
|
|
5086
|
+
return invariantViolations.slice();
|
|
5087
|
+
},
|
|
5088
|
+
getDebugCounters() {
|
|
5089
|
+
return { ...debugCounters };
|
|
5090
|
+
},
|
|
4343
5091
|
getLastCoalescingMetrics() {
|
|
4344
5092
|
return lastCoalescingMetrics;
|
|
4345
5093
|
},
|
|
@@ -4354,11 +5102,11 @@ function createRendererStore(initialBlocks = []) {
|
|
|
4354
5102
|
}
|
|
4355
5103
|
|
|
4356
5104
|
// src/renderer/blocks-renderer.tsx
|
|
4357
|
-
import React8, { useMemo as
|
|
5105
|
+
import React8, { useMemo as useMemo5 } from "react";
|
|
4358
5106
|
import { getBlockKey, PATCH_ROOT_ID as PATCH_ROOT_ID2 } from "@stream-mdx/core";
|
|
4359
5107
|
|
|
4360
5108
|
// src/renderer/hooks.ts
|
|
4361
|
-
import { useMemo as
|
|
5109
|
+
import { useMemo as useMemo3, useSyncExternalStore } from "react";
|
|
4362
5110
|
function useRendererBlocks(store) {
|
|
4363
5111
|
return useSyncExternalStore(
|
|
4364
5112
|
store.subscribe,
|
|
@@ -4367,14 +5115,14 @@ function useRendererBlocks(store) {
|
|
|
4367
5115
|
);
|
|
4368
5116
|
}
|
|
4369
5117
|
function useRendererNode(store, id) {
|
|
4370
|
-
const selector =
|
|
5118
|
+
const selector = useMemo3(() => {
|
|
4371
5119
|
return () => store.getNodeWithVersion(id);
|
|
4372
5120
|
}, [store, id]);
|
|
4373
5121
|
const snapshot = useSyncExternalStore(store.subscribe, selector, selector);
|
|
4374
5122
|
return snapshot.node;
|
|
4375
5123
|
}
|
|
4376
5124
|
function useRendererChildren(store, id) {
|
|
4377
|
-
const selector =
|
|
5125
|
+
const selector = useMemo3(() => {
|
|
4378
5126
|
return () => store.getChildrenWithVersion(id);
|
|
4379
5127
|
}, [store, id]);
|
|
4380
5128
|
const snapshot = useSyncExternalStore(store.subscribe, selector, selector);
|
|
@@ -4382,7 +5130,7 @@ function useRendererChildren(store, id) {
|
|
|
4382
5130
|
}
|
|
4383
5131
|
|
|
4384
5132
|
// src/renderer/node-views.tsx
|
|
4385
|
-
import { stripCodeFence } from "@stream-mdx/core";
|
|
5133
|
+
import { getDefaultCodeWrapperAttributes as getDefaultCodeWrapperAttributes2, stripCodeFence } from "@stream-mdx/core";
|
|
4386
5134
|
import React7 from "react";
|
|
4387
5135
|
|
|
4388
5136
|
// src/renderer/deferred-render-context.tsx
|
|
@@ -4390,7 +5138,7 @@ import React6 from "react";
|
|
|
4390
5138
|
var DeferredRenderContext = React6.createContext(null);
|
|
4391
5139
|
|
|
4392
5140
|
// src/renderer/virtualized-code.tsx
|
|
4393
|
-
import { useCallback as
|
|
5141
|
+
import { useCallback as useCallback3, useEffect as useEffect4, useMemo as useMemo4, useRef as useRef3, useState as useState4 } from "react";
|
|
4394
5142
|
var DEFAULT_VIRTUALIZED_CODE_CONFIG = {
|
|
4395
5143
|
enabled: true,
|
|
4396
5144
|
windowSize: 100,
|
|
@@ -4430,11 +5178,11 @@ function calculateCodeWindow(lines, scrollTop, containerHeight, lineHeight, conf
|
|
|
4430
5178
|
};
|
|
4431
5179
|
}
|
|
4432
5180
|
function useVirtualizedCode(lines, config = DEFAULT_VIRTUALIZED_CODE_CONFIG) {
|
|
4433
|
-
const containerRef =
|
|
4434
|
-
const [scrollTop, setScrollTop] =
|
|
4435
|
-
const [containerHeight, setContainerHeight] =
|
|
4436
|
-
const lineHeightRef =
|
|
4437
|
-
|
|
5181
|
+
const containerRef = useRef3(null);
|
|
5182
|
+
const [scrollTop, setScrollTop] = useState4(0);
|
|
5183
|
+
const [containerHeight, setContainerHeight] = useState4(0);
|
|
5184
|
+
const lineHeightRef = useRef3(20);
|
|
5185
|
+
useEffect4(() => {
|
|
4438
5186
|
if (!containerRef.current || lines.length === 0) return;
|
|
4439
5187
|
const timeoutId = setTimeout(() => {
|
|
4440
5188
|
if (!containerRef.current) return;
|
|
@@ -4448,12 +5196,12 @@ function useVirtualizedCode(lines, config = DEFAULT_VIRTUALIZED_CODE_CONFIG) {
|
|
|
4448
5196
|
}, 0);
|
|
4449
5197
|
return () => clearTimeout(timeoutId);
|
|
4450
5198
|
}, [lines.length]);
|
|
4451
|
-
const handleScroll =
|
|
5199
|
+
const handleScroll = useCallback3((e) => {
|
|
4452
5200
|
const target = e.currentTarget;
|
|
4453
5201
|
setScrollTop(target.scrollTop);
|
|
4454
5202
|
setContainerHeight(target.clientHeight);
|
|
4455
5203
|
}, []);
|
|
4456
|
-
|
|
5204
|
+
useEffect4(() => {
|
|
4457
5205
|
if (!containerRef.current) return;
|
|
4458
5206
|
const resizeObserver = new ResizeObserver((entries2) => {
|
|
4459
5207
|
for (const entry of entries2) {
|
|
@@ -4463,10 +5211,10 @@ function useVirtualizedCode(lines, config = DEFAULT_VIRTUALIZED_CODE_CONFIG) {
|
|
|
4463
5211
|
resizeObserver.observe(containerRef.current);
|
|
4464
5212
|
return () => resizeObserver.disconnect();
|
|
4465
5213
|
}, []);
|
|
4466
|
-
const window2 =
|
|
5214
|
+
const window2 = useMemo4(() => {
|
|
4467
5215
|
return calculateCodeWindow(lines, scrollTop, containerHeight, lineHeightRef.current, config);
|
|
4468
5216
|
}, [lines, scrollTop, containerHeight, config]);
|
|
4469
|
-
const scrollToLine =
|
|
5217
|
+
const scrollToLine = useCallback3((lineIndex) => {
|
|
4470
5218
|
if (!containerRef.current) return;
|
|
4471
5219
|
const targetScrollTop = lineIndex * lineHeightRef.current;
|
|
4472
5220
|
containerRef.current.scrollTop = targetScrollTop;
|
|
@@ -4483,26 +5231,26 @@ function useVirtualizedCode(lines, config = DEFAULT_VIRTUALIZED_CODE_CONFIG) {
|
|
|
4483
5231
|
}
|
|
4484
5232
|
|
|
4485
5233
|
// src/renderer/node-views.tsx
|
|
4486
|
-
import { jsx as
|
|
5234
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
4487
5235
|
var BlockNodeRenderer = ({ store, blockId, registry }) => {
|
|
4488
5236
|
const node = useRendererNode(store, blockId);
|
|
4489
5237
|
const block = node?.block;
|
|
4490
5238
|
if (!node || !block) return null;
|
|
4491
5239
|
switch (block.type) {
|
|
4492
5240
|
case "paragraph":
|
|
4493
|
-
return /* @__PURE__ */
|
|
5241
|
+
return /* @__PURE__ */ jsx4(ParagraphBlockView, { store, blockId: block.id, registry });
|
|
4494
5242
|
case "blockquote":
|
|
4495
|
-
return /* @__PURE__ */
|
|
5243
|
+
return /* @__PURE__ */ jsx4(BlockquoteBlockView, { store, blockId: block.id, registry });
|
|
4496
5244
|
case "list":
|
|
4497
|
-
return /* @__PURE__ */
|
|
5245
|
+
return /* @__PURE__ */ jsx4(ListBlockView, { store, blockId: block.id, registry, depth: 0 });
|
|
4498
5246
|
case "table":
|
|
4499
|
-
return /* @__PURE__ */
|
|
5247
|
+
return /* @__PURE__ */ jsx4(TableBlockView, { store, blockId: block.id, registry });
|
|
4500
5248
|
case "code":
|
|
4501
|
-
return /* @__PURE__ */
|
|
5249
|
+
return /* @__PURE__ */ jsx4(CodeBlockView, { store, blockId: block.id, registry });
|
|
4502
5250
|
case "html":
|
|
4503
|
-
return /* @__PURE__ */
|
|
5251
|
+
return /* @__PURE__ */ jsx4(HtmlBlockView, { store, blockId: block.id, registry });
|
|
4504
5252
|
case "mdx":
|
|
4505
|
-
return /* @__PURE__ */
|
|
5253
|
+
return /* @__PURE__ */ jsx4(MdxBlockView, { store, blockId: block.id, registry });
|
|
4506
5254
|
default:
|
|
4507
5255
|
return registry.renderBlock(block);
|
|
4508
5256
|
}
|
|
@@ -4522,7 +5270,7 @@ var ParagraphBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
4522
5270
|
if (segments2.length > 0) {
|
|
4523
5271
|
const allowMixedStreaming = Boolean(meta.allowMixedStreaming);
|
|
4524
5272
|
if (!allowMixedStreaming) {
|
|
4525
|
-
return /* @__PURE__ */
|
|
5273
|
+
return /* @__PURE__ */ jsx4("p", { className: "markdown-paragraph streaming-partial", children: raw });
|
|
4526
5274
|
}
|
|
4527
5275
|
const structured = renderParagraphMixedSegments(segments2, inlineComponents, DEFAULT_INLINE_HTML_RENDERERS);
|
|
4528
5276
|
if (structured.length === 1) {
|
|
@@ -4549,15 +5297,15 @@ var ParagraphBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
4549
5297
|
}
|
|
4550
5298
|
return structured;
|
|
4551
5299
|
}
|
|
4552
|
-
return /* @__PURE__ */
|
|
5300
|
+
return /* @__PURE__ */ jsx4("p", { className: "markdown-paragraph streaming-partial", children: renderInlineNodes(inlineNodes2, inlineComponents) });
|
|
4553
5301
|
}
|
|
4554
|
-
return /* @__PURE__ */
|
|
5302
|
+
return /* @__PURE__ */ jsx4("p", { className: "markdown-paragraph streaming-partial", children: raw });
|
|
4555
5303
|
}
|
|
4556
5304
|
const propsBlock = node.props?.block;
|
|
4557
5305
|
const inlineStatus = propsBlock?.payload?.meta?.inlineStatus ?? block.payload.meta?.inlineStatus ?? node.props?.inlineStatus;
|
|
4558
5306
|
if (inlineStatus && inlineStatus !== "complete") {
|
|
4559
5307
|
const raw = typeof block.payload.raw === "string" ? block.payload.raw : "";
|
|
4560
|
-
return /* @__PURE__ */
|
|
5308
|
+
return /* @__PURE__ */ jsx4("p", { className: "markdown-paragraph", children: raw });
|
|
4561
5309
|
}
|
|
4562
5310
|
const segments = Array.isArray(block.payload.meta?.mixedSegments) ? block.payload.meta.mixedSegments : void 0;
|
|
4563
5311
|
if (segments && segments.length > 0) {
|
|
@@ -4592,17 +5340,17 @@ var ParagraphBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
4592
5340
|
meta: block.payload.meta
|
|
4593
5341
|
});
|
|
4594
5342
|
if (childIds.length > 0) {
|
|
4595
|
-
const renderedChildren = childIds.map((childId) => /* @__PURE__ */
|
|
5343
|
+
const renderedChildren = childIds.map((childId) => /* @__PURE__ */ jsx4(MixedSegmentView, { store, nodeId: childId, inlineComponents }, childId));
|
|
4596
5344
|
if (React7.isValidElement(baseElement)) {
|
|
4597
5345
|
const { children: _ignored, className = "markdown-paragraph", inlines: _inlines, raw: _raw, meta: _meta, ...rest } = baseElement.props ?? {};
|
|
4598
5346
|
return React7.createElement("p", { ...rest, className }, renderedChildren);
|
|
4599
5347
|
}
|
|
4600
|
-
return /* @__PURE__ */
|
|
5348
|
+
return /* @__PURE__ */ jsx4("p", { className: "markdown-paragraph", children: renderedChildren });
|
|
4601
5349
|
}
|
|
4602
5350
|
if (React7.isValidElement(baseElement)) {
|
|
4603
5351
|
return baseElement;
|
|
4604
5352
|
}
|
|
4605
|
-
return /* @__PURE__ */
|
|
5353
|
+
return /* @__PURE__ */ jsx4("p", { className: "markdown-paragraph", children: renderInlineNodes(block.payload.inline ?? [], inlineComponents) });
|
|
4606
5354
|
});
|
|
4607
5355
|
ParagraphBlockView.displayName = "ParagraphBlockView";
|
|
4608
5356
|
var BlockquoteBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
@@ -4623,9 +5371,9 @@ var BlockquoteBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
4623
5371
|
return lines.map((line, idx) => {
|
|
4624
5372
|
const key = `${keyPrefix}${offset}`;
|
|
4625
5373
|
offset += line.length + 1;
|
|
4626
|
-
return /* @__PURE__ */
|
|
5374
|
+
return /* @__PURE__ */ jsxs3("span", { className: "markdown-blockquote-line", children: [
|
|
4627
5375
|
line,
|
|
4628
|
-
idx < lastIndex ? /* @__PURE__ */
|
|
5376
|
+
idx < lastIndex ? /* @__PURE__ */ jsx4("br", {}) : null
|
|
4629
5377
|
] }, key);
|
|
4630
5378
|
});
|
|
4631
5379
|
};
|
|
@@ -4663,16 +5411,16 @@ var BlockquoteBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
4663
5411
|
}
|
|
4664
5412
|
case "mdx":
|
|
4665
5413
|
elements.push(
|
|
4666
|
-
/* @__PURE__ */
|
|
5414
|
+
/* @__PURE__ */ jsx4("span", { "data-mdx-status": segment.status ?? "pending", children: segment.value }, `blockquote-mdx-${block.id}-${segmentIndex}`)
|
|
4667
5415
|
);
|
|
4668
5416
|
break;
|
|
4669
5417
|
default: {
|
|
4670
5418
|
const inline = renderInlineContent(segment.inline, `blockquote-text-inline-${block.id}-${segmentIndex}-`);
|
|
4671
5419
|
if (inline) {
|
|
4672
|
-
elements.push(/* @__PURE__ */
|
|
5420
|
+
elements.push(/* @__PURE__ */ jsx4(React7.Fragment, { children: inline }, `blockquote-inline-${block.id}-${segmentIndex}`));
|
|
4673
5421
|
} else {
|
|
4674
5422
|
elements.push(
|
|
4675
|
-
/* @__PURE__ */
|
|
5423
|
+
/* @__PURE__ */ jsx4(React7.Fragment, { children: renderTextWithBreaks(segment.value, `blockquote-text-${block.id}-${segmentIndex}-`) }, `blockquote-text-${block.id}-${segmentIndex}`)
|
|
4676
5424
|
);
|
|
4677
5425
|
}
|
|
4678
5426
|
break;
|
|
@@ -4689,9 +5437,9 @@ var BlockquoteBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
4689
5437
|
const streamingContent = mixedSegmentElements.length ? mixedSegmentElements : inlineElements ? inlineElements : fallbackElements;
|
|
4690
5438
|
const shouldShowStreaming = !block.isFinalized && (!streamingContent || Array.isArray(streamingContent) && streamingContent.length === 0);
|
|
4691
5439
|
const className = shouldShowStreaming ? "markdown-blockquote streaming-partial" : "markdown-blockquote";
|
|
4692
|
-
return /* @__PURE__ */
|
|
5440
|
+
return /* @__PURE__ */ jsx4("blockquote", { className, children: streamingContent });
|
|
4693
5441
|
}
|
|
4694
|
-
const childContent = childIds.map((childId) => /* @__PURE__ */
|
|
5442
|
+
const childContent = childIds.map((childId) => /* @__PURE__ */ jsx4(MixedSegmentView, { store, nodeId: childId, inlineComponents }, childId));
|
|
4695
5443
|
const renderedContent = (() => {
|
|
4696
5444
|
if (mixedSegmentElements.length > 0) {
|
|
4697
5445
|
return mixedSegmentElements;
|
|
@@ -4722,7 +5470,7 @@ var BlockquoteBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
4722
5470
|
if (React7.isValidElement(baseElement)) {
|
|
4723
5471
|
return baseElement;
|
|
4724
5472
|
}
|
|
4725
|
-
return /* @__PURE__ */
|
|
5473
|
+
return /* @__PURE__ */ jsx4("blockquote", { className: "markdown-blockquote", children: renderedContent });
|
|
4726
5474
|
});
|
|
4727
5475
|
BlockquoteBlockView.displayName = "BlockquoteBlockView";
|
|
4728
5476
|
var MixedSegmentView = React7.memo(({ store, nodeId, inlineComponents }) => {
|
|
@@ -4765,13 +5513,13 @@ var MixedSegmentView = React7.memo(({ store, nodeId, inlineComponents }) => {
|
|
|
4765
5513
|
const status = node.props?.status ?? "pending";
|
|
4766
5514
|
const raw = typeof node.props?.raw === "string" ? node.props?.raw : "";
|
|
4767
5515
|
if (status === "compiled") {
|
|
4768
|
-
return /* @__PURE__ */
|
|
5516
|
+
return /* @__PURE__ */ jsx4("span", { className: "markdown-mdx-inline", "data-mdx-status": "compiled" });
|
|
4769
5517
|
}
|
|
4770
5518
|
if (status === "error") {
|
|
4771
5519
|
const message = raw || "MDX error";
|
|
4772
|
-
return /* @__PURE__ */
|
|
5520
|
+
return /* @__PURE__ */ jsx4("span", { className: "markdown-mdx-inline text-destructive", "data-mdx-status": "error", children: message });
|
|
4773
5521
|
}
|
|
4774
|
-
return /* @__PURE__ */
|
|
5522
|
+
return /* @__PURE__ */ jsx4("span", { className: "markdown-mdx-inline", "data-mdx-status": status, children: status === "compiled" ? "" : raw });
|
|
4775
5523
|
}
|
|
4776
5524
|
default:
|
|
4777
5525
|
return null;
|
|
@@ -4824,8 +5572,10 @@ var ListBlockView = React7.memo(
|
|
|
4824
5572
|
isFinalized: block?.isFinalized ?? false
|
|
4825
5573
|
});
|
|
4826
5574
|
}, [listDebugEnabled, blockId, depth, ordered, childIds, listItemIds, store, block?.isFinalized]);
|
|
4827
|
-
const listStyle = React7.useMemo(() => {
|
|
4828
|
-
if (!ordered || listItemIds.length === 0)
|
|
5575
|
+
const { listStyle, markerDigits } = React7.useMemo(() => {
|
|
5576
|
+
if (!ordered || listItemIds.length === 0) {
|
|
5577
|
+
return { listStyle: void 0, markerDigits: 1 };
|
|
5578
|
+
}
|
|
4829
5579
|
let maxDigits = 1;
|
|
4830
5580
|
listItemIds.forEach((childId, index) => {
|
|
4831
5581
|
const childNode = store.getNode(childId);
|
|
@@ -4837,20 +5587,26 @@ var ListBlockView = React7.memo(
|
|
|
4837
5587
|
const digits = digitMatch ? digitMatch.length : text.length;
|
|
4838
5588
|
if (digits > maxDigits) maxDigits = digits;
|
|
4839
5589
|
});
|
|
4840
|
-
const baseIndent = depth === 0 ? "
|
|
5590
|
+
const baseIndent = depth === 0 ? "2rem" : depth === 1 ? "1.75rem" : "1.5rem";
|
|
5591
|
+
const extraDigits = Math.max(0, maxDigits - 1);
|
|
4841
5592
|
return {
|
|
4842
|
-
|
|
5593
|
+
markerDigits: maxDigits,
|
|
5594
|
+
listStyle: {
|
|
5595
|
+
["--list-indent"]: extraDigits > 0 ? `calc(${baseIndent} + ${extraDigits}ch)` : baseIndent,
|
|
5596
|
+
["--list-marker-digits"]: String(maxDigits)
|
|
5597
|
+
}
|
|
4843
5598
|
};
|
|
4844
5599
|
}, [ordered, listItemIds, store, depth]);
|
|
4845
5600
|
if (listItemIds.length === 0) return null;
|
|
4846
|
-
return /* @__PURE__ */
|
|
5601
|
+
return /* @__PURE__ */ jsx4(
|
|
4847
5602
|
Tag,
|
|
4848
5603
|
{
|
|
4849
5604
|
className: `markdown-list ${ordered ? "ordered" : "unordered"}`,
|
|
4850
5605
|
"data-list-depth": depth,
|
|
5606
|
+
"data-marker-digits": ordered ? markerDigits : void 0,
|
|
4851
5607
|
"data-list-id": listDebugEnabled ? blockId : void 0,
|
|
4852
5608
|
style: listStyle,
|
|
4853
|
-
children: listItemIds.map((childId, index) => /* @__PURE__ */
|
|
5609
|
+
children: listItemIds.map((childId, index) => /* @__PURE__ */ jsx4(
|
|
4854
5610
|
ListItemView,
|
|
4855
5611
|
{
|
|
4856
5612
|
store,
|
|
@@ -4898,7 +5654,7 @@ var ListItemView = React7.memo(({ store, nodeId, inlineComponents, registry, ord
|
|
|
4898
5654
|
return [segments, structural];
|
|
4899
5655
|
}, [childIds, store]);
|
|
4900
5656
|
const segmentElements = React7.useMemo(() => {
|
|
4901
|
-
return segmentChildIds.map((childId) => /* @__PURE__ */
|
|
5657
|
+
return segmentChildIds.map((childId) => /* @__PURE__ */ jsx4(MixedSegmentView, { store, nodeId: childId, inlineComponents }, childId));
|
|
4902
5658
|
}, [segmentChildIds, store, inlineComponents]);
|
|
4903
5659
|
const primaryContent = React7.useMemo(() => {
|
|
4904
5660
|
if (segmentChildIds.length > 0) {
|
|
@@ -4913,12 +5669,12 @@ var ListItemView = React7.memo(({ store, nodeId, inlineComponents, registry, ord
|
|
|
4913
5669
|
switch (childNode.type) {
|
|
4914
5670
|
case "paragraph": {
|
|
4915
5671
|
const childInline = childNode.props?.inline ?? [];
|
|
4916
|
-
return /* @__PURE__ */
|
|
5672
|
+
return /* @__PURE__ */ jsx4("p", { className: "markdown-list-item-paragraph", children: renderInlineNodes(childInline, inlineComponents) }, childId);
|
|
4917
5673
|
}
|
|
4918
5674
|
case "list":
|
|
4919
|
-
return /* @__PURE__ */
|
|
5675
|
+
return /* @__PURE__ */ jsx4(ListBlockView, { store, blockId: childId, registry, depth: depth + 1 }, childId);
|
|
4920
5676
|
default:
|
|
4921
|
-
return /* @__PURE__ */
|
|
5677
|
+
return /* @__PURE__ */ jsx4(BlockNodeRenderer, { store, blockId: childId, registry }, childId);
|
|
4922
5678
|
}
|
|
4923
5679
|
});
|
|
4924
5680
|
}, [contentChildIds, store, inlineComponents, registry, depth]);
|
|
@@ -4960,7 +5716,7 @@ var ListItemView = React7.memo(({ store, nodeId, inlineComponents, registry, ord
|
|
|
4960
5716
|
store,
|
|
4961
5717
|
block?.isFinalized
|
|
4962
5718
|
]);
|
|
4963
|
-
return /* @__PURE__ */
|
|
5719
|
+
return /* @__PURE__ */ jsxs3(
|
|
4964
5720
|
"li",
|
|
4965
5721
|
{
|
|
4966
5722
|
className: `markdown-list-item${isTask ? " markdown-list-item-task" : ""}`,
|
|
@@ -4968,11 +5724,11 @@ var ListItemView = React7.memo(({ store, nodeId, inlineComponents, registry, ord
|
|
|
4968
5724
|
"data-list-depth": depth,
|
|
4969
5725
|
"data-list-item-id": listDebugEnabled ? nodeId : void 0,
|
|
4970
5726
|
children: [
|
|
4971
|
-
isTask ? /* @__PURE__ */
|
|
4972
|
-
/* @__PURE__ */
|
|
4973
|
-
/* @__PURE__ */
|
|
5727
|
+
isTask ? /* @__PURE__ */ jsxs3("div", { className: "markdown-task", children: [
|
|
5728
|
+
/* @__PURE__ */ jsx4("input", { type: "checkbox", className: "markdown-task-checkbox", checked: isChecked, readOnly: true, disabled: true, tabIndex: -1, "aria-checked": isChecked }),
|
|
5729
|
+
/* @__PURE__ */ jsx4("span", { className: "markdown-task-content", children: primaryContent })
|
|
4974
5730
|
] }) : primaryContent,
|
|
4975
|
-
hasChildren ? /* @__PURE__ */
|
|
5731
|
+
hasChildren ? /* @__PURE__ */ jsx4("div", { className: "markdown-list-item-children", children: filteredChildren }) : null
|
|
4976
5732
|
]
|
|
4977
5733
|
}
|
|
4978
5734
|
);
|
|
@@ -4981,7 +5737,7 @@ ListItemView.displayName = "ListItemView";
|
|
|
4981
5737
|
var TableBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
4982
5738
|
const tableElements = registry.getTableElements();
|
|
4983
5739
|
const childIds = useRendererChildren(store, blockId);
|
|
4984
|
-
return /* @__PURE__ */
|
|
5740
|
+
return /* @__PURE__ */ jsx4(tableElements.Table, { className: "markdown-table w-full caption-bottom text-base", children: childIds.map((sectionId) => /* @__PURE__ */ jsx4(TableSectionView, { store, nodeId: sectionId, registry }, sectionId)) });
|
|
4985
5741
|
});
|
|
4986
5742
|
TableBlockView.displayName = "TableBlockView";
|
|
4987
5743
|
var TableSectionView = React7.memo(({ store, nodeId, registry }) => {
|
|
@@ -4990,11 +5746,11 @@ var TableSectionView = React7.memo(({ store, nodeId, registry }) => {
|
|
|
4990
5746
|
const tableElements = registry.getTableElements();
|
|
4991
5747
|
if (node.type === "table-header") {
|
|
4992
5748
|
const childIds = useRendererChildren(store, nodeId);
|
|
4993
|
-
return /* @__PURE__ */
|
|
5749
|
+
return /* @__PURE__ */ jsx4(tableElements.Thead, { children: /* @__PURE__ */ jsx4(tableElements.Tr, { children: childIds.map((cellId) => /* @__PURE__ */ jsx4(TableCellView, { store, nodeId: cellId, registry }, cellId)) }) });
|
|
4994
5750
|
}
|
|
4995
5751
|
if (node.type === "table-body") {
|
|
4996
5752
|
const rowIds = useRendererChildren(store, nodeId);
|
|
4997
|
-
return /* @__PURE__ */
|
|
5753
|
+
return /* @__PURE__ */ jsx4(tableElements.Tbody, { children: rowIds.map((rowId) => /* @__PURE__ */ jsx4(TableRowView, { store, nodeId: rowId, registry }, rowId)) });
|
|
4998
5754
|
}
|
|
4999
5755
|
return null;
|
|
5000
5756
|
});
|
|
@@ -5002,7 +5758,7 @@ TableSectionView.displayName = "TableSectionView";
|
|
|
5002
5758
|
var TableRowView = React7.memo(({ store, nodeId, registry }) => {
|
|
5003
5759
|
const tableElements = registry.getTableElements();
|
|
5004
5760
|
const cellIds = useRendererChildren(store, nodeId);
|
|
5005
|
-
return /* @__PURE__ */
|
|
5761
|
+
return /* @__PURE__ */ jsx4(tableElements.Tr, { children: cellIds.map((cellId) => /* @__PURE__ */ jsx4(TableCellView, { store, nodeId: cellId, registry }, cellId)) });
|
|
5006
5762
|
});
|
|
5007
5763
|
TableRowView.displayName = "TableRowView";
|
|
5008
5764
|
var TableCellView = React7.memo(({ store, nodeId, registry }) => {
|
|
@@ -5015,7 +5771,7 @@ var TableCellView = React7.memo(({ store, nodeId, registry }) => {
|
|
|
5015
5771
|
const align = node.props?.align;
|
|
5016
5772
|
const content = renderInlineNodes(inline, inlineComponents);
|
|
5017
5773
|
const alignProps = align ? { align } : void 0;
|
|
5018
|
-
return /* @__PURE__ */
|
|
5774
|
+
return /* @__PURE__ */ jsx4(Tag, { ...alignProps, children: content });
|
|
5019
5775
|
});
|
|
5020
5776
|
TableCellView.displayName = "TableCellView";
|
|
5021
5777
|
var CodeBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
@@ -5029,6 +5785,7 @@ var CodeBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
5029
5785
|
deferredConfig ? { ...deferredConfig, enabled: true } : { enabled: false }
|
|
5030
5786
|
);
|
|
5031
5787
|
if (!node || !node.block) return null;
|
|
5788
|
+
const blockIsFinalized = node.block.isFinalized;
|
|
5032
5789
|
const nodeVersion = node.version;
|
|
5033
5790
|
const lines = React7.useMemo(() => {
|
|
5034
5791
|
const seenIds = /* @__PURE__ */ new Set();
|
|
@@ -5059,13 +5816,25 @@ var CodeBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
5059
5816
|
const lang = typeof node.props?.lang === "string" ? node.props?.lang : node.block.payload.meta?.lang;
|
|
5060
5817
|
const preAttrs = node.props?.preAttrs ?? void 0;
|
|
5061
5818
|
const codeAttrs = node.props?.codeAttrs ?? void 0;
|
|
5819
|
+
const blockMeta = node.block.payload.meta ?? void 0;
|
|
5820
|
+
const lazyEnabled = Boolean(blockMeta?.lazyTokenization);
|
|
5821
|
+
const lazyTokenizedUntil = typeof blockMeta?.lazyTokenizedUntil === "number" ? blockMeta.lazyTokenizedUntil : 0;
|
|
5822
|
+
const lazyHighlightedLines = Array.isArray(blockMeta?.highlightedLines) ? blockMeta.highlightedLines.length : 0;
|
|
5823
|
+
const lazyTokenLines = Array.isArray(blockMeta?.tokenLines) ? blockMeta.tokenLines.length : 0;
|
|
5824
|
+
const lazySourceTextLineCount = React7.useMemo(() => {
|
|
5825
|
+
const raw = typeof node.block?.payload.raw === "string" ? node.block.payload.raw : "";
|
|
5826
|
+
const metaCode = typeof blockMeta?.code === "string" ? blockMeta.code : null;
|
|
5827
|
+
const sourceText = resolveCodeSourceText(raw, metaCode);
|
|
5828
|
+
if (sourceText.length === 0) return 0;
|
|
5829
|
+
return sourceText.split("\n").length;
|
|
5830
|
+
}, [blockMeta, node.block?.payload.raw]);
|
|
5831
|
+
const totalLazyLineCount = Math.max(lines.length, lazyHighlightedLines, lazyTokenLines, lazySourceTextLineCount);
|
|
5062
5832
|
const virtualizationConfig = DEFAULT_VIRTUALIZED_CODE_CONFIG;
|
|
5063
5833
|
const virtualizationDisabled = typeof process !== "undefined" && typeof process.env === "object" && process.env.STREAM_MDX_DISABLE_VIRTUALIZED_CODE === "true";
|
|
5064
|
-
const
|
|
5834
|
+
const canVirtualize = node.block.isFinalized && !lazyEnabled;
|
|
5835
|
+
const shouldVirtualize = canVirtualize && !virtualizationDisabled && virtualizationConfig.enabled && lines.length >= virtualizationConfig.virtualizeThreshold;
|
|
5065
5836
|
const virtualization = useVirtualizedCode(lines, shouldVirtualize ? virtualizationConfig : { ...virtualizationConfig, enabled: false });
|
|
5066
5837
|
const highlightRequester = useCodeHighlightRequester();
|
|
5067
|
-
const lazyEnabled = Boolean(node.block.payload.meta?.lazyTokenization);
|
|
5068
|
-
const lazyTokenizedUntil = typeof node.block.payload.meta?.lazyTokenizedUntil === "number" ? node.block.payload.meta.lazyTokenizedUntil : 0;
|
|
5069
5838
|
const lastRangeRef = React7.useRef(null);
|
|
5070
5839
|
const rafRef = React7.useRef(null);
|
|
5071
5840
|
const idleRef = React7.useRef(null);
|
|
@@ -5146,30 +5915,112 @@ var CodeBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
5146
5915
|
virtualization.window.startIndex,
|
|
5147
5916
|
virtualization.window.endIndex
|
|
5148
5917
|
]);
|
|
5149
|
-
|
|
5150
|
-
if (
|
|
5151
|
-
|
|
5918
|
+
React7.useEffect(() => {
|
|
5919
|
+
if (shouldVirtualize || !blockIsFinalized || !lazyEnabled || !highlightRequester) return;
|
|
5920
|
+
if (totalLazyLineCount <= 0 || lazyTokenizedUntil >= totalLazyLineCount) return;
|
|
5921
|
+
const nextRange = {
|
|
5922
|
+
visibleStart: 0,
|
|
5923
|
+
visibleEnd: totalLazyLineCount,
|
|
5924
|
+
prefetchStart: 0,
|
|
5925
|
+
prefetchEnd: totalLazyLineCount,
|
|
5926
|
+
tokenizedUntil: lazyTokenizedUntil
|
|
5927
|
+
};
|
|
5928
|
+
const last = lastRangeRef.current;
|
|
5929
|
+
if (last && last.visibleStart === nextRange.visibleStart && last.visibleEnd === nextRange.visibleEnd && last.prefetchStart === nextRange.prefetchStart && last.prefetchEnd === nextRange.prefetchEnd && last.tokenizedUntil === nextRange.tokenizedUntil) {
|
|
5930
|
+
return;
|
|
5152
5931
|
}
|
|
5932
|
+
lastRangeRef.current = nextRange;
|
|
5933
|
+
if (rafRef.current !== null && typeof cancelAnimationFrame === "function") {
|
|
5934
|
+
cancelAnimationFrame(rafRef.current);
|
|
5935
|
+
}
|
|
5936
|
+
const requestFullHighlight = () => {
|
|
5937
|
+
highlightRequester({
|
|
5938
|
+
blockId,
|
|
5939
|
+
startLine: 0,
|
|
5940
|
+
endLine: totalLazyLineCount,
|
|
5941
|
+
priority: "visible",
|
|
5942
|
+
reason: "finalize-full"
|
|
5943
|
+
});
|
|
5944
|
+
rafRef.current = null;
|
|
5945
|
+
};
|
|
5946
|
+
if (typeof requestAnimationFrame === "function") {
|
|
5947
|
+
rafRef.current = requestAnimationFrame(requestFullHighlight);
|
|
5948
|
+
} else {
|
|
5949
|
+
requestFullHighlight();
|
|
5950
|
+
}
|
|
5951
|
+
}, [blockId, blockIsFinalized, highlightRequester, lazyEnabled, lazyTokenizedUntil, shouldVirtualize, totalLazyLineCount]);
|
|
5952
|
+
const highlightedHtml = React7.useMemo(() => {
|
|
5953
|
+
const blockHtml = node.block?.payload.highlightedHtml ?? "";
|
|
5954
|
+
const raw = typeof node.block?.payload.raw === "string" ? node.block.payload.raw : "";
|
|
5955
|
+
const metaCode = typeof node.block?.payload.meta?.code === "string" ? (node.block?.payload.meta).code : null;
|
|
5956
|
+
const sourceText = resolveCodeSourceText(raw, metaCode);
|
|
5957
|
+
const sourceEndsWithNewline = sourceText.endsWith("\n");
|
|
5958
|
+
const sourceLines = sourceText.length > 0 ? sourceText.split("\n") : [];
|
|
5959
|
+
const rawFallbackLines = buildCodeFallbackLines(raw);
|
|
5960
|
+
const deterministicWrapperAttrs = getDefaultCodeWrapperAttributes2(lang);
|
|
5961
|
+
const composedPreAttrs = deterministicWrapperAttrs.preAttrs;
|
|
5962
|
+
const composedCodeAttrs = deterministicWrapperAttrs.codeAttrs;
|
|
5963
|
+
const shouldAppendTerminalNewline = (renderedLines) => {
|
|
5964
|
+
if (!sourceEndsWithNewline || renderedLines.length === 0 || lines.length === 0) {
|
|
5965
|
+
return false;
|
|
5966
|
+
}
|
|
5967
|
+
const lastRendered = renderedLines[renderedLines.length - 1];
|
|
5968
|
+
const lastKnown = lines[lines.length - 1];
|
|
5969
|
+
if (!lastRendered || !lastKnown || lastRendered.index !== lastKnown.index || lastRendered.text === "") {
|
|
5970
|
+
return false;
|
|
5971
|
+
}
|
|
5972
|
+
const expectedRenderedLineCount = Math.max(0, sourceLines.length - 1);
|
|
5973
|
+
const expectedLastRenderedLine = sourceLines.length >= 2 ? sourceLines[sourceLines.length - 2] ?? "" : "";
|
|
5974
|
+
return renderedLines.length === expectedRenderedLineCount && lastRendered.text === expectedLastRenderedLine;
|
|
5975
|
+
};
|
|
5153
5976
|
if (lines.length > 0) {
|
|
5154
5977
|
const hasLineHtml = lines.some((line) => typeof line.html === "string" && line.html.length > 0);
|
|
5155
|
-
if (!hasLineHtml &&
|
|
5156
|
-
return
|
|
5978
|
+
if (!hasLineHtml && blockHtml) {
|
|
5979
|
+
return blockHtml;
|
|
5157
5980
|
}
|
|
5158
5981
|
if (shouldVirtualize) {
|
|
5159
|
-
return composeHighlightedHtml(
|
|
5982
|
+
return composeHighlightedHtml(
|
|
5983
|
+
virtualization.window.visibleLines,
|
|
5984
|
+
composedPreAttrs,
|
|
5985
|
+
composedCodeAttrs,
|
|
5986
|
+
shouldAppendTerminalNewline(virtualization.window.visibleLines)
|
|
5987
|
+
);
|
|
5160
5988
|
}
|
|
5161
|
-
return composeHighlightedHtml(lines,
|
|
5989
|
+
return composeHighlightedHtml(lines, composedPreAttrs, composedCodeAttrs, shouldAppendTerminalNewline(lines));
|
|
5990
|
+
}
|
|
5991
|
+
if (!shouldVirtualize && blockHtml) {
|
|
5992
|
+
const hasHighlightedLines = blockHtml.includes('class="line"');
|
|
5993
|
+
if (!hasHighlightedLines && rawFallbackLines.length > 0) {
|
|
5994
|
+
return composeHighlightedHtml(
|
|
5995
|
+
rawFallbackLines,
|
|
5996
|
+
composedPreAttrs,
|
|
5997
|
+
composedCodeAttrs,
|
|
5998
|
+
sourceEndsWithNewline && rawFallbackLines[rawFallbackLines.length - 1]?.text !== ""
|
|
5999
|
+
);
|
|
6000
|
+
}
|
|
6001
|
+
return blockHtml;
|
|
5162
6002
|
}
|
|
5163
|
-
const blockHtml = node.block?.payload.highlightedHtml ?? "";
|
|
5164
6003
|
if (blockHtml?.trim().match(/^```[\w-]*\s*$/)) {
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
6004
|
+
if (rawFallbackLines.length > 0) {
|
|
6005
|
+
return composeHighlightedHtml(
|
|
6006
|
+
rawFallbackLines,
|
|
6007
|
+
composedPreAttrs,
|
|
6008
|
+
composedCodeAttrs,
|
|
6009
|
+
sourceEndsWithNewline && rawFallbackLines[rawFallbackLines.length - 1]?.text !== ""
|
|
6010
|
+
);
|
|
5168
6011
|
}
|
|
5169
6012
|
}
|
|
6013
|
+
if (!blockHtml && rawFallbackLines.length > 0) {
|
|
6014
|
+
return composeHighlightedHtml(
|
|
6015
|
+
rawFallbackLines,
|
|
6016
|
+
composedPreAttrs,
|
|
6017
|
+
composedCodeAttrs,
|
|
6018
|
+
sourceEndsWithNewline && rawFallbackLines[rawFallbackLines.length - 1]?.text !== ""
|
|
6019
|
+
);
|
|
6020
|
+
}
|
|
5170
6021
|
return blockHtml;
|
|
5171
|
-
}, [shouldVirtualize, node.block?.payload.highlightedHtml,
|
|
5172
|
-
const rendered = /* @__PURE__ */
|
|
6022
|
+
}, [blockIsFinalized, shouldVirtualize, node.block?.payload.highlightedHtml, node.block?.payload.meta, lines, lang, virtualization.window.visibleLines, node.block?.payload.raw]);
|
|
6023
|
+
const rendered = /* @__PURE__ */ jsx4(
|
|
5173
6024
|
CodeComponent,
|
|
5174
6025
|
{
|
|
5175
6026
|
html: highlightedHtml,
|
|
@@ -5180,20 +6031,26 @@ var CodeBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
5180
6031
|
codeAttrs
|
|
5181
6032
|
}
|
|
5182
6033
|
);
|
|
6034
|
+
const effectiveLineCount = React7.useMemo(() => {
|
|
6035
|
+
if (lines.length > 0) {
|
|
6036
|
+
return lines.length;
|
|
6037
|
+
}
|
|
6038
|
+
return 1;
|
|
6039
|
+
}, [lines.length]);
|
|
5183
6040
|
const codeFrameClass = "not-prose flex flex-col rounded-lg border border-input pt-1 font-mono text-sm";
|
|
5184
6041
|
const codeMetricsAttrs = {
|
|
5185
6042
|
"data-code-block": "true",
|
|
5186
6043
|
"data-block-id": blockId,
|
|
5187
6044
|
"data-code-virtualized": shouldVirtualize ? "true" : "false",
|
|
5188
|
-
"data-code-total-lines": String(
|
|
5189
|
-
"data-code-mounted-lines": String(shouldVirtualize ? virtualization.window.mountedLines :
|
|
6045
|
+
"data-code-total-lines": String(effectiveLineCount),
|
|
6046
|
+
"data-code-mounted-lines": String(shouldVirtualize ? virtualization.window.mountedLines : effectiveLineCount),
|
|
5190
6047
|
"data-code-window-size": String(virtualization.config.windowSize)
|
|
5191
6048
|
};
|
|
5192
6049
|
const codeView = shouldVirtualize ? (() => {
|
|
5193
6050
|
const { containerRef, window: window2, handleScroll, lineHeight } = virtualization;
|
|
5194
6051
|
const spacerTop = window2.startIndex * lineHeight;
|
|
5195
6052
|
const spacerBottom = (window2.totalLines - window2.endIndex) * lineHeight;
|
|
5196
|
-
return /* @__PURE__ */
|
|
6053
|
+
return /* @__PURE__ */ jsx4("pre", { className: codeFrameClass, ...codeMetricsAttrs, children: /* @__PURE__ */ jsxs3(
|
|
5197
6054
|
"div",
|
|
5198
6055
|
{
|
|
5199
6056
|
ref: containerRef,
|
|
@@ -5201,13 +6058,13 @@ var CodeBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
5201
6058
|
style: { overflowY: "auto", overflowX: "hidden", maxHeight: "600px" },
|
|
5202
6059
|
onScroll: handleScroll,
|
|
5203
6060
|
children: [
|
|
5204
|
-
/* @__PURE__ */
|
|
6061
|
+
/* @__PURE__ */ jsx4("div", { style: { height: spacerTop }, "aria-hidden": "true" }),
|
|
5205
6062
|
rendered,
|
|
5206
|
-
/* @__PURE__ */
|
|
6063
|
+
/* @__PURE__ */ jsx4("div", { style: { height: spacerBottom }, "aria-hidden": "true" })
|
|
5207
6064
|
]
|
|
5208
6065
|
}
|
|
5209
6066
|
) });
|
|
5210
|
-
})() : /* @__PURE__ */
|
|
6067
|
+
})() : /* @__PURE__ */ jsx4("pre", { className: codeFrameClass, ...codeMetricsAttrs, children: rendered });
|
|
5211
6068
|
const blockComponentMap = registry.getBlockComponentMap();
|
|
5212
6069
|
const MermaidComponent = Object.prototype.hasOwnProperty.call(blockComponentMap, "mermaid") ? blockComponentMap.mermaid : null;
|
|
5213
6070
|
if ((lang ?? "").toLowerCase() === "mermaid" && MermaidComponent) {
|
|
@@ -5215,7 +6072,7 @@ var CodeBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
5215
6072
|
const fenced = stripCodeFence(raw);
|
|
5216
6073
|
const code = fenced.hadFence ? fenced.code : raw;
|
|
5217
6074
|
if (deferredConfig) {
|
|
5218
|
-
return /* @__PURE__ */
|
|
6075
|
+
return /* @__PURE__ */ jsx4("div", { ref: deferredRef, children: shouldRenderDeferred ? React7.createElement(MermaidComponent, {
|
|
5219
6076
|
code,
|
|
5220
6077
|
renderCode: codeView,
|
|
5221
6078
|
meta: node.block.payload.meta,
|
|
@@ -5232,21 +6089,152 @@ var CodeBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
5232
6089
|
return codeView;
|
|
5233
6090
|
});
|
|
5234
6091
|
CodeBlockView.displayName = "CodeBlockView";
|
|
5235
|
-
function composeHighlightedHtml(lines, preAttrs, codeAttrs) {
|
|
6092
|
+
function composeHighlightedHtml(lines, preAttrs, codeAttrs, appendTerminalNewline = false) {
|
|
5236
6093
|
const lineMarkup = lines.map((line) => {
|
|
5237
|
-
const content = line.html ?? escapeHtml3(line.text);
|
|
6094
|
+
const content = line.html ?? renderTokenLineHtml(line.tokens) ?? escapeHtml3(line.text);
|
|
5238
6095
|
const dataLine = Number.isFinite(line.index) ? ` data-line="${line.index + 1}"` : "";
|
|
5239
6096
|
return `<span class="line"${dataLine}>${content}</span>`;
|
|
5240
6097
|
}).join("\n");
|
|
5241
6098
|
const preAttr = attrsToString(preAttrs);
|
|
5242
6099
|
const codeAttr = attrsToString(codeAttrs);
|
|
5243
|
-
return `<pre${preAttr}><code${codeAttr}>${lineMarkup}
|
|
5244
|
-
|
|
6100
|
+
return `<pre${preAttr}><code${codeAttr}>${lineMarkup}${appendTerminalNewline ? "\n" : ""}</code></pre>`;
|
|
6101
|
+
}
|
|
6102
|
+
var TOKEN_FONT_STYLE_ITALIC = 1;
|
|
6103
|
+
var TOKEN_FONT_STYLE_BOLD = 2;
|
|
6104
|
+
var TOKEN_FONT_STYLE_UNDERLINE = 4;
|
|
6105
|
+
var TOKEN_FONT_STYLE_STRIKETHROUGH = 8;
|
|
6106
|
+
function renderTokenLineHtml(tokens) {
|
|
6107
|
+
if (!tokens || !Array.isArray(tokens.spans)) {
|
|
6108
|
+
return null;
|
|
6109
|
+
}
|
|
6110
|
+
return mergeRenderableTokenSpans(tokens.spans).map((span) => renderTokenSpanHtml(span)).join("");
|
|
6111
|
+
}
|
|
6112
|
+
function renderTokenSpanHtml(span) {
|
|
6113
|
+
const dark = span.v?.dark;
|
|
6114
|
+
const light = span.v?.light;
|
|
6115
|
+
const single = span.s;
|
|
6116
|
+
const styles = [];
|
|
6117
|
+
if (dark?.fg) {
|
|
6118
|
+
styles.push(`--shiki-dark:${dark.fg}`);
|
|
6119
|
+
}
|
|
6120
|
+
if (light?.fg) {
|
|
6121
|
+
styles.push(`--shiki-light:${light.fg}`);
|
|
6122
|
+
}
|
|
6123
|
+
if (!light?.fg && !dark?.fg && single?.fg) {
|
|
6124
|
+
styles.push(`color:${single.fg}`);
|
|
6125
|
+
}
|
|
6126
|
+
const fontStyle = light?.fs ?? dark?.fs ?? single?.fs;
|
|
6127
|
+
if (typeof fontStyle === "number" && fontStyle > 0) {
|
|
6128
|
+
if (fontStyle & TOKEN_FONT_STYLE_ITALIC) {
|
|
6129
|
+
styles.push("font-style: italic");
|
|
6130
|
+
}
|
|
6131
|
+
if (fontStyle & TOKEN_FONT_STYLE_BOLD) {
|
|
6132
|
+
styles.push("font-weight: bold");
|
|
6133
|
+
}
|
|
6134
|
+
const decorations = [];
|
|
6135
|
+
if (fontStyle & TOKEN_FONT_STYLE_UNDERLINE) {
|
|
6136
|
+
decorations.push("underline");
|
|
6137
|
+
}
|
|
6138
|
+
if (fontStyle & TOKEN_FONT_STYLE_STRIKETHROUGH) {
|
|
6139
|
+
decorations.push("line-through");
|
|
6140
|
+
}
|
|
6141
|
+
if (decorations.length > 0) {
|
|
6142
|
+
styles.push(`text-decoration: ${decorations.join(" ")}`);
|
|
6143
|
+
}
|
|
6144
|
+
}
|
|
6145
|
+
const content = escapeHtml3(span.t ?? "");
|
|
6146
|
+
if (styles.length === 0) {
|
|
6147
|
+
return content;
|
|
6148
|
+
}
|
|
6149
|
+
return `<span style="${styles.join(";")}">${content}</span>`;
|
|
6150
|
+
}
|
|
6151
|
+
function mergeRenderableTokenSpans(spans) {
|
|
6152
|
+
if (spans.length <= 1) {
|
|
6153
|
+
return spans.slice();
|
|
6154
|
+
}
|
|
6155
|
+
const merged = [];
|
|
6156
|
+
let pendingWhitespace = "";
|
|
6157
|
+
for (const span of spans) {
|
|
6158
|
+
const text = typeof span.t === "string" ? span.t : "";
|
|
6159
|
+
if (/^[\t ]+$/.test(text)) {
|
|
6160
|
+
pendingWhitespace += text;
|
|
6161
|
+
continue;
|
|
6162
|
+
}
|
|
6163
|
+
const nextSpan = pendingWhitespace ? { ...span, t: `${pendingWhitespace}${text}` } : span;
|
|
6164
|
+
pendingWhitespace = "";
|
|
6165
|
+
const previous = merged[merged.length - 1];
|
|
6166
|
+
if (previous && sameTokenSpanStyle(previous, nextSpan)) {
|
|
6167
|
+
previous.t += nextSpan.t;
|
|
6168
|
+
} else {
|
|
6169
|
+
merged.push({ ...nextSpan });
|
|
6170
|
+
}
|
|
6171
|
+
}
|
|
6172
|
+
if (pendingWhitespace) {
|
|
6173
|
+
const previous = merged[merged.length - 1];
|
|
6174
|
+
if (previous) {
|
|
6175
|
+
previous.t += pendingWhitespace;
|
|
6176
|
+
} else {
|
|
6177
|
+
merged.push({ t: pendingWhitespace });
|
|
6178
|
+
}
|
|
6179
|
+
}
|
|
6180
|
+
return merged;
|
|
6181
|
+
}
|
|
6182
|
+
function sameTokenSpanStyle(a, b) {
|
|
6183
|
+
const variantKeys = /* @__PURE__ */ new Set([
|
|
6184
|
+
...Object.keys(a.v ?? {}),
|
|
6185
|
+
...Object.keys(b.v ?? {})
|
|
6186
|
+
]);
|
|
6187
|
+
for (const key of variantKeys) {
|
|
6188
|
+
const aStyle = a.v?.[key];
|
|
6189
|
+
const bStyle = b.v?.[key];
|
|
6190
|
+
if ((aStyle?.fg ?? null) !== (bStyle?.fg ?? null)) return false;
|
|
6191
|
+
if ((aStyle?.bg ?? null) !== (bStyle?.bg ?? null)) return false;
|
|
6192
|
+
if ((aStyle?.fs ?? null) !== (bStyle?.fs ?? null)) return false;
|
|
6193
|
+
}
|
|
6194
|
+
if ((a.s?.fg ?? null) !== (b.s?.fg ?? null)) return false;
|
|
6195
|
+
if ((a.s?.bg ?? null) !== (b.s?.bg ?? null)) return false;
|
|
6196
|
+
if ((a.s?.fs ?? null) !== (b.s?.fs ?? null)) return false;
|
|
6197
|
+
return true;
|
|
6198
|
+
}
|
|
6199
|
+
function resolveCodeSourceText(raw, metaCode) {
|
|
6200
|
+
if (metaCode !== null) {
|
|
6201
|
+
return metaCode.replace(/\r\n?/g, "\n");
|
|
6202
|
+
}
|
|
6203
|
+
if (!raw) return "";
|
|
6204
|
+
const normalized = raw.replace(/\r\n?/g, "\n");
|
|
6205
|
+
const fenced = stripCodeFence(normalized);
|
|
6206
|
+
return fenced.hadFence ? fenced.code : normalized;
|
|
5245
6207
|
}
|
|
5246
6208
|
function attrsToString(attrs) {
|
|
5247
6209
|
if (!attrs) return "";
|
|
5248
6210
|
return Object.entries(attrs).map(([key, value]) => ` ${key}="${escapeAttribute(value)}"`).join("");
|
|
5249
6211
|
}
|
|
6212
|
+
function buildCodeFallbackLines(raw) {
|
|
6213
|
+
const normalized = normalizeCodeFallbackRaw(raw);
|
|
6214
|
+
if (normalized.length === 0) {
|
|
6215
|
+
if (/^\s*```[^\n]*\n?\s*$/.test(raw)) {
|
|
6216
|
+
return [{ id: "temp-0", index: 0, text: "", html: null }];
|
|
6217
|
+
}
|
|
6218
|
+
return [];
|
|
6219
|
+
}
|
|
6220
|
+
return normalized.split("\n").map((line, index) => ({
|
|
6221
|
+
id: `temp-${index}`,
|
|
6222
|
+
index,
|
|
6223
|
+
text: line,
|
|
6224
|
+
html: null
|
|
6225
|
+
}));
|
|
6226
|
+
}
|
|
6227
|
+
function normalizeCodeFallbackRaw(raw) {
|
|
6228
|
+
if (!raw) return "";
|
|
6229
|
+
const normalized = raw.replace(/\r\n?/g, "\n");
|
|
6230
|
+
const fenced = stripCodeFence(normalized);
|
|
6231
|
+
if (!fenced.hadFence) {
|
|
6232
|
+
return normalized.replace(/\n+$/, "");
|
|
6233
|
+
}
|
|
6234
|
+
let code = fenced.code;
|
|
6235
|
+
code = code.replace(/\n+$/, "");
|
|
6236
|
+
return code;
|
|
6237
|
+
}
|
|
5250
6238
|
function escapeHtml3(value) {
|
|
5251
6239
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
5252
6240
|
}
|
|
@@ -5267,7 +6255,7 @@ var MarkdownBlocksRenderer = React8.memo(({ blocks, componentRegistry, className
|
|
|
5267
6255
|
React8.createElement(StoreBackedBlocks, { store, componentRegistry })
|
|
5268
6256
|
);
|
|
5269
6257
|
}
|
|
5270
|
-
const renderedBlocks =
|
|
6258
|
+
const renderedBlocks = useMemo5(() => {
|
|
5271
6259
|
return blocks.map((block) => {
|
|
5272
6260
|
const key = getBlockKey(block);
|
|
5273
6261
|
return React8.createElement(BlockRenderer, {
|
|
@@ -5300,7 +6288,7 @@ var StoreBackedBlocks = React8.memo(
|
|
|
5300
6288
|
);
|
|
5301
6289
|
StoreBackedBlocks.displayName = "StoreBackedBlocks";
|
|
5302
6290
|
var BlockRenderer = React8.memo(({ block, componentRegistry, isFinalized }) => {
|
|
5303
|
-
const element =
|
|
6291
|
+
const element = useMemo5(() => {
|
|
5304
6292
|
return componentRegistry.renderBlock(block);
|
|
5305
6293
|
}, [block, componentRegistry]);
|
|
5306
6294
|
const className = `markdown-block markdown-block-${block.type} ${isFinalized ? "finalized" : "dirty"}`;
|
|
@@ -5370,7 +6358,9 @@ var MarkdownRenderer = class {
|
|
|
5370
6358
|
lowPriorityFrameBudgetMs: this.config.performance?.lowPriorityFrameBudgetMs,
|
|
5371
6359
|
urgentQueueThreshold: this.config.performance?.urgentQueueThreshold,
|
|
5372
6360
|
batch: this.config.performance?.batch,
|
|
5373
|
-
historyLimit: this.config.performance?.historyLimit
|
|
6361
|
+
historyLimit: this.config.performance?.historyLimit,
|
|
6362
|
+
startupMicrotaskFlushes: this.config.performance?.startupMicrotaskFlushes,
|
|
6363
|
+
adaptiveBudgeting: this.config.performance?.adaptiveBudgeting
|
|
5374
6364
|
}
|
|
5375
6365
|
});
|
|
5376
6366
|
}
|
|
@@ -5564,18 +6554,8 @@ var MarkdownRenderer = class {
|
|
|
5564
6554
|
const receivedAt = typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
5565
6555
|
const batches = splitPatchBatch(message.patches);
|
|
5566
6556
|
batches.forEach((batch, index) => {
|
|
5567
|
-
const
|
|
5568
|
-
|
|
5569
|
-
case "insertChild":
|
|
5570
|
-
case "replaceChild":
|
|
5571
|
-
case "deleteChild":
|
|
5572
|
-
case "reorder":
|
|
5573
|
-
return true;
|
|
5574
|
-
default:
|
|
5575
|
-
return false;
|
|
5576
|
-
}
|
|
5577
|
-
});
|
|
5578
|
-
const priority = hasStructural ? "high" : batch.some(isHeavyPatch) ? "low" : "high";
|
|
6557
|
+
const hasSemantic = batch.some((patch) => getPatchKind(patch) === "semantic");
|
|
6558
|
+
const priority = hasSemantic ? "high" : batch.some(isHeavyPatch) ? "low" : "high";
|
|
5579
6559
|
this.patchScheduler.enqueue({
|
|
5580
6560
|
patches: batch,
|
|
5581
6561
|
meta: {
|
|
@@ -5712,10 +6692,10 @@ var MarkdownRenderer = class {
|
|
|
5712
6692
|
}
|
|
5713
6693
|
};
|
|
5714
6694
|
function useMarkdownRenderer(config = {}) {
|
|
5715
|
-
const [renderer] =
|
|
5716
|
-
const [blocks, setBlocks] =
|
|
5717
|
-
const workerRef =
|
|
5718
|
-
|
|
6695
|
+
const [renderer] = useState5(() => new MarkdownRenderer(config));
|
|
6696
|
+
const [blocks, setBlocks] = useState5([]);
|
|
6697
|
+
const workerRef = useRef4(null);
|
|
6698
|
+
useEffect5(() => {
|
|
5719
6699
|
if (!workerRef.current) {
|
|
5720
6700
|
const fallbackFactory = () => new Worker("/workers/markdown-worker.js", { type: "module", name: "markdown-v2" });
|
|
5721
6701
|
const worker = createDefaultWorker() ?? fallbackFactory();
|
|
@@ -5730,41 +6710,41 @@ function useMarkdownRenderer(config = {}) {
|
|
|
5730
6710
|
}
|
|
5731
6711
|
};
|
|
5732
6712
|
}, [renderer]);
|
|
5733
|
-
|
|
6713
|
+
useEffect5(() => {
|
|
5734
6714
|
const unsubscribe = renderer.onUpdate(setBlocks);
|
|
5735
6715
|
return unsubscribe;
|
|
5736
6716
|
}, [renderer]);
|
|
5737
6717
|
const mdxComponents = config.mdx?.components;
|
|
5738
|
-
|
|
6718
|
+
useEffect5(() => {
|
|
5739
6719
|
if (mdxComponents && Object.keys(mdxComponents).length > 0) {
|
|
5740
6720
|
renderer.setMdxComponents(mdxComponents);
|
|
5741
6721
|
}
|
|
5742
6722
|
}, [renderer, mdxComponents]);
|
|
5743
|
-
const append =
|
|
6723
|
+
const append = useCallback4(
|
|
5744
6724
|
(text) => {
|
|
5745
6725
|
renderer.append(text);
|
|
5746
6726
|
},
|
|
5747
6727
|
[renderer]
|
|
5748
6728
|
);
|
|
5749
|
-
const renderStatic =
|
|
6729
|
+
const renderStatic = useCallback4(
|
|
5750
6730
|
(text) => {
|
|
5751
6731
|
return renderer.renderStatic(text);
|
|
5752
6732
|
},
|
|
5753
6733
|
[renderer]
|
|
5754
6734
|
);
|
|
5755
|
-
const setBlockComponents =
|
|
6735
|
+
const setBlockComponents = useCallback4(
|
|
5756
6736
|
(components) => {
|
|
5757
6737
|
renderer.setBlockComponents(components);
|
|
5758
6738
|
},
|
|
5759
6739
|
[renderer]
|
|
5760
6740
|
);
|
|
5761
|
-
const setInlineComponents =
|
|
6741
|
+
const setInlineComponents = useCallback4(
|
|
5762
6742
|
(components) => {
|
|
5763
6743
|
renderer.setInlineComponents(components);
|
|
5764
6744
|
},
|
|
5765
6745
|
[renderer]
|
|
5766
6746
|
);
|
|
5767
|
-
const setMdxComponents =
|
|
6747
|
+
const setMdxComponents = useCallback4(
|
|
5768
6748
|
(components) => {
|
|
5769
6749
|
renderer.setMdxComponents(components);
|
|
5770
6750
|
},
|
|
@@ -5783,13 +6763,13 @@ function useMarkdownRenderer(config = {}) {
|
|
|
5783
6763
|
}
|
|
5784
6764
|
var MarkdownRenderer2 = ({ config, className, onBlocksChange, children }) => {
|
|
5785
6765
|
const api = useMarkdownRenderer(config);
|
|
5786
|
-
const highlightRequester =
|
|
6766
|
+
const highlightRequester = useCallback4(
|
|
5787
6767
|
(request) => {
|
|
5788
6768
|
api.renderer.requestCodeHighlightRange(request);
|
|
5789
6769
|
},
|
|
5790
6770
|
[api.renderer]
|
|
5791
6771
|
);
|
|
5792
|
-
|
|
6772
|
+
useEffect5(() => {
|
|
5793
6773
|
if (onBlocksChange) {
|
|
5794
6774
|
onBlocksChange(api.blocks);
|
|
5795
6775
|
}
|
|
@@ -5813,9 +6793,9 @@ function createMarkdownRenderer(config = {}) {
|
|
|
5813
6793
|
}
|
|
5814
6794
|
|
|
5815
6795
|
// src/streaming-markdown.tsx
|
|
5816
|
-
import React10, { forwardRef, useCallback as
|
|
6796
|
+
import React10, { forwardRef, useCallback as useCallback5, useEffect as useEffect6, useImperativeHandle, useMemo as useMemo6, useRef as useRef5, useState as useState6 } from "react";
|
|
5817
6797
|
import { createDefaultWorker as createDefaultWorker2, releaseDefaultWorker as releaseDefaultWorker2 } from "@stream-mdx/worker";
|
|
5818
|
-
import { jsx as
|
|
6798
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
5819
6799
|
var EMPTY_BLOCKS = [];
|
|
5820
6800
|
function createConfigSignature(input) {
|
|
5821
6801
|
return JSON.stringify(input);
|
|
@@ -5827,13 +6807,13 @@ var MdxCoordinatorBridge = ({ store, mode }) => {
|
|
|
5827
6807
|
};
|
|
5828
6808
|
var MdxPrefetchBridge = ({ store }) => {
|
|
5829
6809
|
const blocks = useRendererBlocks(store);
|
|
5830
|
-
const prefetchedRuntimeRef =
|
|
5831
|
-
const trackedIdsRef =
|
|
5832
|
-
const queueRef =
|
|
6810
|
+
const prefetchedRuntimeRef = useRef5(false);
|
|
6811
|
+
const trackedIdsRef = useRef5(/* @__PURE__ */ new Set());
|
|
6812
|
+
const queueRef = useRef5(null);
|
|
5833
6813
|
if (!queueRef.current) {
|
|
5834
6814
|
queueRef.current = new MdxPrefetchQueue();
|
|
5835
6815
|
}
|
|
5836
|
-
|
|
6816
|
+
useEffect6(() => {
|
|
5837
6817
|
const queue = queueRef.current;
|
|
5838
6818
|
if (!queue) return;
|
|
5839
6819
|
const nextIds = /* @__PURE__ */ new Map();
|
|
@@ -5871,7 +6851,7 @@ var MdxPrefetchBridge = ({ store }) => {
|
|
|
5871
6851
|
}
|
|
5872
6852
|
trackedIdsRef.current = new Set(nextIds.keys());
|
|
5873
6853
|
}, [blocks]);
|
|
5874
|
-
|
|
6854
|
+
useEffect6(() => {
|
|
5875
6855
|
return () => {
|
|
5876
6856
|
queueRef.current?.cancelAll();
|
|
5877
6857
|
};
|
|
@@ -5945,7 +6925,7 @@ function StreamingMarkdownComponent({
|
|
|
5945
6925
|
const effectiveScheduling = scheduling ?? DEFAULT_SCHEDULING;
|
|
5946
6926
|
const adaptiveSwitchEnabled = effectiveScheduling.batch === "microtask" && (scheduling?.adaptiveSwitch ?? true);
|
|
5947
6927
|
const adaptiveQueueThreshold = scheduling?.adaptiveQueueThreshold ?? (typeof effectiveScheduling.maxBatchesPerFlush === "number" ? effectiveScheduling.maxBatchesPerFlush : DEFAULT_ADAPTIVE_QUEUE_THRESHOLD);
|
|
5948
|
-
const configSignature =
|
|
6928
|
+
const configSignature = useMemo6(
|
|
5949
6929
|
() => createConfigSignature({
|
|
5950
6930
|
features,
|
|
5951
6931
|
prewarm: prewarmLangs,
|
|
@@ -5956,16 +6936,16 @@ function StreamingMarkdownComponent({
|
|
|
5956
6936
|
}),
|
|
5957
6937
|
[features, prewarmLangs, effectiveScheduling, mdxCompileMode, mdxComponents, mdxHydration]
|
|
5958
6938
|
);
|
|
5959
|
-
const mdxHydrationController =
|
|
5960
|
-
const mdxHydrationContextValue =
|
|
6939
|
+
const mdxHydrationController = useMemo6(() => createMdxHydrationController(mdxHydration), [mdxHydration]);
|
|
6940
|
+
const mdxHydrationContextValue = useMemo6(
|
|
5961
6941
|
() => ({
|
|
5962
6942
|
controller: mdxHydrationController,
|
|
5963
6943
|
options: mdxHydration
|
|
5964
6944
|
}),
|
|
5965
6945
|
[mdxHydrationController, mdxHydration]
|
|
5966
6946
|
);
|
|
5967
|
-
const rendererRef =
|
|
5968
|
-
const [session, setSession] =
|
|
6947
|
+
const rendererRef = useRef5();
|
|
6948
|
+
const [session, setSession] = useState6(0);
|
|
5969
6949
|
const rendererKey = `${configSignature}:${session}`;
|
|
5970
6950
|
const historyLimit = effectiveScheduling.historyLimit ?? DEFAULT_HISTORY_LIMIT;
|
|
5971
6951
|
if (!rendererRef.current || rendererRef.current.signature !== rendererKey) {
|
|
@@ -5984,7 +6964,9 @@ function StreamingMarkdownComponent({
|
|
|
5984
6964
|
lowPriorityFrameBudgetMs: effectiveScheduling.lowPriorityFrameBudgetMs,
|
|
5985
6965
|
urgentQueueThreshold: effectiveScheduling.urgentQueueThreshold,
|
|
5986
6966
|
batch: effectiveScheduling.batch,
|
|
5987
|
-
historyLimit
|
|
6967
|
+
historyLimit,
|
|
6968
|
+
startupMicrotaskFlushes: effectiveScheduling.startupMicrotaskFlushes,
|
|
6969
|
+
adaptiveBudgeting: effectiveScheduling.adaptiveBudgeting
|
|
5988
6970
|
},
|
|
5989
6971
|
mdx: mdxConfig
|
|
5990
6972
|
};
|
|
@@ -5994,7 +6976,7 @@ function StreamingMarkdownComponent({
|
|
|
5994
6976
|
};
|
|
5995
6977
|
}
|
|
5996
6978
|
const renderer = rendererRef.current.renderer;
|
|
5997
|
-
const highlightRequester =
|
|
6979
|
+
const highlightRequester = useCallback5(
|
|
5998
6980
|
(request) => {
|
|
5999
6981
|
renderer.requestCodeHighlightRange(request);
|
|
6000
6982
|
},
|
|
@@ -6002,15 +6984,15 @@ function StreamingMarkdownComponent({
|
|
|
6002
6984
|
);
|
|
6003
6985
|
const store = renderer.getStore();
|
|
6004
6986
|
const blocks = useRendererBlocks(store);
|
|
6005
|
-
const adaptiveSwitchedRef =
|
|
6006
|
-
const adaptiveFirstFlushRef =
|
|
6987
|
+
const adaptiveSwitchedRef = useRef5(false);
|
|
6988
|
+
const adaptiveFirstFlushRef = useRef5(false);
|
|
6007
6989
|
const mdxMode = mdxCompileMode ?? "server";
|
|
6008
|
-
const [workerReady, setWorkerReady] =
|
|
6009
|
-
const workerReadyRef =
|
|
6010
|
-
const [streamStatus, setStreamStatus] =
|
|
6011
|
-
const lastMetricsRef =
|
|
6012
|
-
const patchHistoryRef =
|
|
6013
|
-
|
|
6990
|
+
const [workerReady, setWorkerReady] = useState6(false);
|
|
6991
|
+
const workerReadyRef = useRef5(false);
|
|
6992
|
+
const [streamStatus, setStreamStatus] = useState6("idle");
|
|
6993
|
+
const lastMetricsRef = useRef5(null);
|
|
6994
|
+
const patchHistoryRef = useRef5([]);
|
|
6995
|
+
useEffect6(() => {
|
|
6014
6996
|
if (typeof window === "undefined" || typeof PerformanceObserver === "undefined") {
|
|
6015
6997
|
return void 0;
|
|
6016
6998
|
}
|
|
@@ -6034,27 +7016,27 @@ function StreamingMarkdownComponent({
|
|
|
6034
7016
|
observer?.disconnect();
|
|
6035
7017
|
};
|
|
6036
7018
|
}, []);
|
|
6037
|
-
const previousTextRef =
|
|
6038
|
-
|
|
7019
|
+
const previousTextRef = useRef5();
|
|
7020
|
+
useEffect6(() => {
|
|
6039
7021
|
if (text !== void 0 && text !== previousTextRef.current) {
|
|
6040
7022
|
previousTextRef.current = text;
|
|
6041
7023
|
setSession((prev) => prev + 1);
|
|
6042
7024
|
}
|
|
6043
7025
|
}, [text]);
|
|
6044
|
-
const previousStreamRef =
|
|
6045
|
-
|
|
7026
|
+
const previousStreamRef = useRef5();
|
|
7027
|
+
useEffect6(() => {
|
|
6046
7028
|
if (stream && stream !== previousStreamRef.current) {
|
|
6047
7029
|
previousStreamRef.current = stream;
|
|
6048
7030
|
setSession((prev) => prev + 1);
|
|
6049
7031
|
}
|
|
6050
7032
|
}, [stream]);
|
|
6051
7033
|
const linkSafetyEnabled = Boolean(linkSafety?.enabled);
|
|
6052
|
-
const [linkModalState, setLinkModalState] =
|
|
7034
|
+
const [linkModalState, setLinkModalState] = useState6({
|
|
6053
7035
|
url: "",
|
|
6054
7036
|
isOpen: false,
|
|
6055
7037
|
isChecking: false
|
|
6056
7038
|
});
|
|
6057
|
-
const openLink =
|
|
7039
|
+
const openLink = useMemo6(() => {
|
|
6058
7040
|
return (url) => {
|
|
6059
7041
|
if (typeof window === "undefined") return;
|
|
6060
7042
|
if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
@@ -6064,7 +7046,7 @@ function StreamingMarkdownComponent({
|
|
|
6064
7046
|
}
|
|
6065
7047
|
};
|
|
6066
7048
|
}, []);
|
|
6067
|
-
const handleLinkClick =
|
|
7049
|
+
const handleLinkClick = useMemo6(() => {
|
|
6068
7050
|
return async (url) => {
|
|
6069
7051
|
if (!linkSafetyEnabled) {
|
|
6070
7052
|
openLink(url);
|
|
@@ -6086,10 +7068,10 @@ function StreamingMarkdownComponent({
|
|
|
6086
7068
|
setLinkModalState({ url, isOpen: true, isChecking: false });
|
|
6087
7069
|
};
|
|
6088
7070
|
}, [linkSafety, linkSafetyEnabled, openLink]);
|
|
6089
|
-
const handleLinkClose =
|
|
7071
|
+
const handleLinkClose = useMemo6(() => {
|
|
6090
7072
|
return () => setLinkModalState((prev) => ({ ...prev, isOpen: false }));
|
|
6091
7073
|
}, []);
|
|
6092
|
-
const handleLinkConfirm =
|
|
7074
|
+
const handleLinkConfirm = useMemo6(() => {
|
|
6093
7075
|
return () => {
|
|
6094
7076
|
const url = linkModalState.url;
|
|
6095
7077
|
setLinkModalState((prev) => ({ ...prev, isOpen: false }));
|
|
@@ -6098,7 +7080,7 @@ function StreamingMarkdownComponent({
|
|
|
6098
7080
|
}
|
|
6099
7081
|
};
|
|
6100
7082
|
}, [linkModalState.url, openLink]);
|
|
6101
|
-
const handleLinkCopy =
|
|
7083
|
+
const handleLinkCopy = useMemo6(() => {
|
|
6102
7084
|
return () => {
|
|
6103
7085
|
const url = linkModalState.url;
|
|
6104
7086
|
if (!url || typeof navigator === "undefined") return;
|
|
@@ -6119,7 +7101,7 @@ function StreamingMarkdownComponent({
|
|
|
6119
7101
|
}
|
|
6120
7102
|
};
|
|
6121
7103
|
}, [linkModalState.url]);
|
|
6122
|
-
const resolvedInlineComponents =
|
|
7104
|
+
const resolvedInlineComponents = useMemo6(() => {
|
|
6123
7105
|
if (!linkSafetyEnabled) {
|
|
6124
7106
|
return inlineComponents;
|
|
6125
7107
|
}
|
|
@@ -6146,14 +7128,14 @@ function StreamingMarkdownComponent({
|
|
|
6146
7128
|
};
|
|
6147
7129
|
return { ...inlineComponents ?? {}, link: LinkComponent };
|
|
6148
7130
|
}, [handleLinkClick, inlineComponents, linkSafetyEnabled]);
|
|
6149
|
-
|
|
7131
|
+
useEffect6(() => {
|
|
6150
7132
|
setStreamStatus("idle");
|
|
6151
7133
|
}, [session]);
|
|
6152
|
-
|
|
7134
|
+
useEffect6(() => {
|
|
6153
7135
|
adaptiveSwitchedRef.current = false;
|
|
6154
7136
|
adaptiveFirstFlushRef.current = false;
|
|
6155
7137
|
}, [renderer]);
|
|
6156
|
-
|
|
7138
|
+
useEffect6(() => {
|
|
6157
7139
|
if (!adaptiveSwitchEnabled) return void 0;
|
|
6158
7140
|
const unsubscribe = renderer.addFlushListener((result) => {
|
|
6159
7141
|
if (adaptiveSwitchedRef.current) return;
|
|
@@ -6175,12 +7157,12 @@ function StreamingMarkdownComponent({
|
|
|
6175
7157
|
});
|
|
6176
7158
|
return unsubscribe;
|
|
6177
7159
|
}, [renderer, adaptiveSwitchEnabled, adaptiveQueueThreshold]);
|
|
6178
|
-
|
|
7160
|
+
useEffect6(() => {
|
|
6179
7161
|
lastMetricsRef.current = null;
|
|
6180
7162
|
patchHistoryRef.current = [];
|
|
6181
7163
|
void renderer;
|
|
6182
7164
|
}, [renderer]);
|
|
6183
|
-
|
|
7165
|
+
useEffect6(() => {
|
|
6184
7166
|
if (components) {
|
|
6185
7167
|
renderer.setBlockComponents(components);
|
|
6186
7168
|
}
|
|
@@ -6199,7 +7181,7 @@ function StreamingMarkdownComponent({
|
|
|
6199
7181
|
renderer.getComponentRegistry().setHtmlElements(htmlElements);
|
|
6200
7182
|
}
|
|
6201
7183
|
}, [renderer, components, mdxComponents, inlineComponents, resolvedInlineComponents, tableElements, htmlElements]);
|
|
6202
|
-
|
|
7184
|
+
useEffect6(() => {
|
|
6203
7185
|
const removeListener = renderer.addFlushListener((result) => {
|
|
6204
7186
|
const metrics = summarizeFlush(result);
|
|
6205
7187
|
lastMetricsRef.current = metrics;
|
|
@@ -6217,12 +7199,12 @@ function StreamingMarkdownComponent({
|
|
|
6217
7199
|
});
|
|
6218
7200
|
return removeListener;
|
|
6219
7201
|
}, [renderer, historyLimit, onMetrics]);
|
|
6220
|
-
|
|
7202
|
+
useEffect6(() => {
|
|
6221
7203
|
if (patchHistoryRef.current.length > historyLimit) {
|
|
6222
7204
|
patchHistoryRef.current.splice(0, patchHistoryRef.current.length - historyLimit);
|
|
6223
7205
|
}
|
|
6224
7206
|
}, [historyLimit]);
|
|
6225
|
-
|
|
7207
|
+
useEffect6(() => {
|
|
6226
7208
|
const restartToken = session;
|
|
6227
7209
|
void restartToken;
|
|
6228
7210
|
if (process.env.NODE_ENV !== "production" && DEBUG_WORKER) {
|
|
@@ -6278,7 +7260,7 @@ function StreamingMarkdownComponent({
|
|
|
6278
7260
|
}
|
|
6279
7261
|
};
|
|
6280
7262
|
}, [renderer, workerSource, session, onError, managedWorker]);
|
|
6281
|
-
|
|
7263
|
+
useEffect6(() => {
|
|
6282
7264
|
const restartToken = session;
|
|
6283
7265
|
void restartToken;
|
|
6284
7266
|
let cancelled = false;
|
|
@@ -6395,8 +7377,8 @@ function StreamingMarkdownComponent({
|
|
|
6395
7377
|
}),
|
|
6396
7378
|
[renderer, store]
|
|
6397
7379
|
);
|
|
6398
|
-
const hasActiveBlocks =
|
|
6399
|
-
const caretValue =
|
|
7380
|
+
const hasActiveBlocks = useMemo6(() => blocks.some((block) => !block.isFinalized), [blocks]);
|
|
7381
|
+
const caretValue = useMemo6(() => {
|
|
6400
7382
|
if (!caret) {
|
|
6401
7383
|
return null;
|
|
6402
7384
|
}
|
|
@@ -6417,7 +7399,7 @@ function StreamingMarkdownComponent({
|
|
|
6417
7399
|
...style ?? {},
|
|
6418
7400
|
["--stream-mdx-caret"]: JSON.stringify(caretValue)
|
|
6419
7401
|
} : style;
|
|
6420
|
-
const deferredConfig =
|
|
7402
|
+
const deferredConfig = useMemo6(() => {
|
|
6421
7403
|
if (!deferHeavyBlocks) {
|
|
6422
7404
|
return null;
|
|
6423
7405
|
}
|
|
@@ -6434,10 +7416,10 @@ function StreamingMarkdownComponent({
|
|
|
6434
7416
|
onConfirm: handleLinkConfirm,
|
|
6435
7417
|
onCopy: handleLinkCopy
|
|
6436
7418
|
}) : null;
|
|
6437
|
-
return /* @__PURE__ */
|
|
6438
|
-
/* @__PURE__ */
|
|
6439
|
-
mdxMode === "server" ? /* @__PURE__ */
|
|
6440
|
-
/* @__PURE__ */
|
|
7419
|
+
return /* @__PURE__ */ jsx5(MdxHydrationContext.Provider, { value: mdxHydrationContextValue, children: /* @__PURE__ */ jsxs4(DeferredRenderContext.Provider, { value: deferredConfig, children: [
|
|
7420
|
+
/* @__PURE__ */ jsx5(MdxPrefetchBridge, { store }),
|
|
7421
|
+
mdxMode === "server" ? /* @__PURE__ */ jsx5(MdxCoordinatorBridge, { store, mode: mdxMode }) : null,
|
|
7422
|
+
/* @__PURE__ */ jsx5(CodeHighlightRequestContext.Provider, { value: highlightRequester, children: /* @__PURE__ */ jsx5(
|
|
6441
7423
|
MarkdownBlocksRenderer,
|
|
6442
7424
|
{
|
|
6443
7425
|
blocks: EMPTY_BLOCKS,
|
|
@@ -6556,6 +7538,7 @@ function percentile2(values, ratio) {
|
|
|
6556
7538
|
return sorted[index];
|
|
6557
7539
|
}
|
|
6558
7540
|
export {
|
|
7541
|
+
BottomStickScrollArea,
|
|
6559
7542
|
ComponentRegistry,
|
|
6560
7543
|
DEFAULT_COALESCE_CONFIG,
|
|
6561
7544
|
DEFAULT_VIRTUALIZED_CODE_CONFIG,
|
|
@@ -6581,6 +7564,7 @@ export {
|
|
|
6581
7564
|
defaultInlineComponents,
|
|
6582
7565
|
getMDXClient,
|
|
6583
7566
|
getMDXComponentFactory,
|
|
7567
|
+
getPatchKind,
|
|
6584
7568
|
isHeavyPatch,
|
|
6585
7569
|
isListPatchDebugEnabled,
|
|
6586
7570
|
mapHtmlToReact,
|