@stream-mdx/react 0.3.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.
Files changed (57) hide show
  1. package/CHANGELOG.md +14 -4
  2. package/README.md +65 -14
  3. package/dist/components/bottom-stick-scroll-area.cjs +344 -0
  4. package/dist/components/bottom-stick-scroll-area.d.cts +36 -0
  5. package/dist/components/bottom-stick-scroll-area.d.ts +36 -0
  6. package/dist/components/bottom-stick-scroll-area.mjs +320 -0
  7. package/dist/components/index.cjs +511 -176
  8. package/dist/components/index.d.cts +3 -1
  9. package/dist/components/index.d.ts +3 -1
  10. package/dist/components/index.mjs +358 -26
  11. package/dist/{index-D7px9jug.d.cts → index-BVhp_pcF.d.ts} +4 -1
  12. package/dist/{index-D7px9jug.d.ts → index-EaeouYp2.d.cts} +4 -1
  13. package/dist/index.cjs +2146 -1145
  14. package/dist/index.d.cts +6 -4
  15. package/dist/index.d.ts +6 -4
  16. package/dist/index.mjs +3835 -2836
  17. package/dist/mdx-client.cjs +1 -1
  18. package/dist/mdx-client.mjs +1 -1
  19. package/dist/mdx-coordinator.cjs +28 -7
  20. package/dist/mdx-coordinator.d.cts +2 -2
  21. package/dist/mdx-coordinator.d.ts +2 -2
  22. package/dist/mdx-coordinator.mjs +28 -7
  23. package/dist/renderer/node-views.cjs +273 -24
  24. package/dist/renderer/node-views.d.cts +3 -1
  25. package/dist/renderer/node-views.d.ts +3 -1
  26. package/dist/renderer/node-views.mjs +274 -25
  27. package/dist/renderer/patch-batching.cjs +2 -0
  28. package/dist/renderer/patch-batching.d.cts +1 -1
  29. package/dist/renderer/patch-batching.d.ts +1 -1
  30. package/dist/renderer/patch-batching.mjs +2 -1
  31. package/dist/renderer/patch-commit-scheduler.cjs +82 -30
  32. package/dist/renderer/patch-commit-scheduler.d.cts +15 -3
  33. package/dist/renderer/patch-commit-scheduler.d.ts +15 -3
  34. package/dist/renderer/patch-commit-scheduler.mjs +84 -30
  35. package/dist/renderer/store.cjs +382 -36
  36. package/dist/renderer/store.d.cts +3 -0
  37. package/dist/renderer/store.d.ts +3 -0
  38. package/dist/renderer/store.mjs +382 -36
  39. package/dist/renderer.cjs +3386 -2727
  40. package/dist/renderer.d.cts +15 -12
  41. package/dist/renderer.d.ts +15 -12
  42. package/dist/renderer.mjs +3410 -2751
  43. package/dist/server.cjs +4842 -0
  44. package/dist/server.d.cts +254 -0
  45. package/dist/server.d.ts +254 -0
  46. package/dist/server.mjs +4824 -0
  47. package/dist/{streaming-markdown-Dp1IDgMT.d.ts → streaming-markdown-CEI9eDZm.d.ts} +3 -1
  48. package/dist/{streaming-markdown-DSC4L0xR.d.cts → streaming-markdown-DRisClXb.d.cts} +3 -1
  49. package/dist/streaming-markdown.cjs +3476 -2794
  50. package/dist/streaming-markdown.d.cts +4 -2
  51. package/dist/streaming-markdown.d.ts +4 -2
  52. package/dist/streaming-markdown.mjs +3436 -2754
  53. package/dist/utils/inline-html.d.cts +3 -1
  54. package/dist/utils/inline-html.d.ts +3 -1
  55. package/package.json +19 -3
  56. package/shadcn/README.md +28 -0
  57. package/shadcn/bottom-stick-scroll-area.tsx +358 -0
@@ -46,11 +46,11 @@ function assignMdxChildKey(child, index) {
46
46
  if (Array.isArray(child)) {
47
47
  return child.map((entry, subIndex) => assignMdxChildKey(entry, `${index}-${subIndex}`));
48
48
  }
49
- if (import_react2.default.isValidElement(child)) {
49
+ if (import_react3.default.isValidElement(child)) {
50
50
  if (child.key !== null && child.key !== void 0) {
51
51
  return child;
52
52
  }
53
- return import_react2.default.cloneElement(child, { key: index });
53
+ return import_react3.default.cloneElement(child, { key: index });
54
54
  }
55
55
  return child;
56
56
  }
@@ -79,14 +79,14 @@ function registerInlineMdxModule(compiled) {
79
79
  dependencies: compiled.dependencies ?? []
80
80
  });
81
81
  }
82
- var import_react2, ReactJsxRuntime, withClassName, MDXClient, MDXComponentFactory, globalMDXClient, globalComponentFactory;
82
+ var import_react3, ReactJsxRuntime, withClassName, MDXClient, MDXComponentFactory, globalMDXClient, globalComponentFactory;
83
83
  var init_mdx_client = __esm({
84
84
  "src/mdx-client.ts"() {
85
85
  "use strict";
86
- import_react2 = __toESM(require("react"), 1);
86
+ import_react3 = __toESM(require("react"), 1);
87
87
  ReactJsxRuntime = __toESM(require("react/jsx-runtime"), 1);
88
88
  withClassName = (tag, className) => {
89
- return (props) => import_react2.default.createElement(tag, { className, ...props });
89
+ return (props) => import_react3.default.createElement(tag, { className, ...props });
90
90
  };
91
91
  MDXClient = class {
92
92
  constructor(compileEndpoint = "/api/mdx-compile-v2") {
@@ -103,7 +103,7 @@ var init_mdx_client = __esm({
103
103
  if (block.type !== "mdx") {
104
104
  throw new Error("Block is not MDX type");
105
105
  }
106
- const cacheKey = block.id;
106
+ const cacheKey = `${block.id}\0${block.payload.raw ?? ""}`;
107
107
  const cachedPromise = this.cache.get(cacheKey);
108
108
  if (cachedPromise) {
109
109
  return cachedPromise;
@@ -261,14 +261,14 @@ var init_mdx_client = __esm({
261
261
  const registryComponents = this.getComponents();
262
262
  const incomingComponents = props?.components;
263
263
  const mergedComponents = incomingComponents ? { ...registryComponents, ...incomingComponents } : registryComponents;
264
- return import_react2.default.createElement(MDXComponent, {
264
+ return import_react3.default.createElement(MDXComponent, {
265
265
  ...props,
266
266
  components: mergedComponents
267
267
  });
268
268
  };
269
269
  } catch (error) {
270
270
  console.error("Failed to evaluate MDX:", error);
271
- return () => import_react2.default.createElement(
271
+ return () => import_react3.default.createElement(
272
272
  "div",
273
273
  {
274
274
  className: "mdx-error"
@@ -288,7 +288,7 @@ var init_mdx_client = __esm({
288
288
  if (Array.isArray(finalProps.children)) {
289
289
  finalProps.children = finalProps.children.map((child, index) => assignMdxChildKey(child, index));
290
290
  }
291
- return import_react2.default.createElement(type, finalProps);
291
+ return import_react3.default.createElement(type, finalProps);
292
292
  };
293
293
  const runtimeJsx = typeof runtime.jsx === "function" ? runtime.jsx.bind(runtime) : createElementWithChildren;
294
294
  const runtimeJsxs = typeof runtime.jsxs === "function" ? runtime.jsxs.bind(runtime) : createElementWithChildren;
@@ -297,20 +297,20 @@ var init_mdx_client = __esm({
297
297
  jsx: runtimeJsx,
298
298
  jsxs: runtimeJsxs,
299
299
  jsxDEV: runtimeJsxDEV,
300
- Fragment: runtime.Fragment ?? import_react2.default.Fragment
300
+ Fragment: runtime.Fragment ?? import_react3.default.Fragment
301
301
  };
302
302
  return {
303
303
  __mdx_runtime: jsxRuntime,
304
- React: import_react2.default,
305
- Fragment: import_react2.default.Fragment,
306
- useState: import_react2.default.useState,
307
- useEffect: import_react2.default.useEffect,
308
- useMemo: import_react2.default.useMemo,
309
- useCallback: import_react2.default.useCallback,
310
- useRef: import_react2.default.useRef,
311
- useContext: import_react2.default.useContext,
312
- useReducer: import_react2.default.useReducer,
313
- useLayoutEffect: import_react2.default.useLayoutEffect,
304
+ React: import_react3.default,
305
+ Fragment: import_react3.default.Fragment,
306
+ useState: import_react3.default.useState,
307
+ useEffect: import_react3.default.useEffect,
308
+ useMemo: import_react3.default.useMemo,
309
+ useCallback: import_react3.default.useCallback,
310
+ useRef: import_react3.default.useRef,
311
+ useContext: import_react3.default.useContext,
312
+ useReducer: import_react3.default.useReducer,
313
+ useLayoutEffect: import_react3.default.useLayoutEffect,
314
314
  console: {
315
315
  log: console.log,
316
316
  warn: console.warn,
@@ -376,13 +376,13 @@ var init_mdx_client = __esm({
376
376
  ol: withClassName("ol", "mdx-ol"),
377
377
  li: withClassName("li", "mdx-li"),
378
378
  blockquote: withClassName("blockquote", "mdx-blockquote"),
379
- a: (props) => import_react2.default.createElement("a", {
379
+ a: (props) => import_react3.default.createElement("a", {
380
380
  className: "mdx-link",
381
381
  target: props.href?.startsWith("http") ? "_blank" : void 0,
382
382
  rel: props.href?.startsWith("http") ? "noopener noreferrer" : void 0,
383
383
  ...props
384
384
  }),
385
- img: (props) => import_react2.default.createElement("img", { className: "mdx-img", ...props }),
385
+ img: (props) => import_react3.default.createElement("img", { className: "mdx-img", ...props }),
386
386
  table: withClassName("table", "mdx-table"),
387
387
  thead: withClassName("thead", "mdx-thead"),
388
388
  tbody: withClassName("tbody", "mdx-tbody"),
@@ -409,6 +409,7 @@ var init_mdx_client = __esm({
409
409
  // src/components/index.ts
410
410
  var components_exports = {};
411
411
  __export(components_exports, {
412
+ BottomStickScrollArea: () => BottomStickScrollArea,
412
413
  ComponentRegistry: () => ComponentRegistry,
413
414
  DefaultLinkSafetyModal: () => DefaultLinkSafetyModal,
414
415
  defaultBlockComponents: () => defaultBlockComponents,
@@ -418,6 +419,323 @@ __export(components_exports, {
418
419
  renderParagraphMixedSegments: () => renderParagraphMixedSegments
419
420
  });
420
421
  module.exports = __toCommonJS(components_exports);
422
+
423
+ // src/components/bottom-stick-scroll-area.tsx
424
+ var import_react = require("react");
425
+ var import_jsx_runtime = require("react/jsx-runtime");
426
+ var EPS_BOTTOM_PX = 2;
427
+ var EPS_OVERFLOW_PX = 1;
428
+ var DETACH_SCROLL_DELTA_PX = 1;
429
+ var RETURN_MIN_MS = 180;
430
+ var RETURN_MAX_MS = 520;
431
+ var RETURN_PX_PER_MS = 2.2;
432
+ var RETURN_SETTLE_FRAMES = 2;
433
+ function clamp01(value) {
434
+ if (value < 0) return 0;
435
+ if (value > 1) return 1;
436
+ return value;
437
+ }
438
+ function easeOutCubic(value) {
439
+ return 1 - (1 - value) ** 3;
440
+ }
441
+ function joinClasses(...parts) {
442
+ return parts.filter(Boolean).join(" ");
443
+ }
444
+ function measure(viewport) {
445
+ const scrollTop = viewport.scrollTop;
446
+ const scrollHeight = viewport.scrollHeight;
447
+ const clientHeight = viewport.clientHeight;
448
+ const maxScrollTop = Math.max(0, scrollHeight - clientHeight);
449
+ const distanceToBottom = Math.max(0, maxScrollTop - scrollTop);
450
+ const isOverflowing = scrollHeight > clientHeight + EPS_OVERFLOW_PX;
451
+ return { scrollTop, scrollHeight, clientHeight, maxScrollTop, distanceToBottom, isOverflowing };
452
+ }
453
+ function DefaultJumpButton({ canJump, jumpToBottom }) {
454
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
455
+ "button",
456
+ {
457
+ type: "button",
458
+ onClick: jumpToBottom,
459
+ "aria-label": "Scroll to bottom",
460
+ style: {
461
+ pointerEvents: canJump ? "auto" : "none",
462
+ borderRadius: 9999,
463
+ border: "1px solid color-mix(in srgb, currentColor 20%, transparent)",
464
+ width: 40,
465
+ height: 40,
466
+ display: "grid",
467
+ placeItems: "center",
468
+ boxShadow: "0 8px 20px rgba(0,0,0,0.18)",
469
+ background: "color-mix(in srgb, var(--background, #fff) 92%, transparent)",
470
+ color: "var(--foreground, #111)",
471
+ cursor: canJump ? "pointer" : "default"
472
+ },
473
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": true, children: "\u2193" })
474
+ }
475
+ );
476
+ }
477
+ function BottomStickScrollArea({
478
+ children,
479
+ className,
480
+ viewportClassName,
481
+ contentClassName,
482
+ showJumpToBottom = true,
483
+ onDebugStateChange,
484
+ onModeChange,
485
+ debugDomAttributes = false,
486
+ renderJumpToBottom,
487
+ jumpContainerClassName
488
+ }) {
489
+ const viewportRef = (0, import_react.useRef)(null);
490
+ const contentRef = (0, import_react.useRef)(null);
491
+ const modeRef = (0, import_react.useRef)("STICKY_INSTANT");
492
+ const [mode, setMode] = (0, import_react.useState)("STICKY_INSTANT");
493
+ const [isOverflowing, setIsOverflowing] = (0, import_react.useState)(false);
494
+ const [distanceToBottom, setDistanceToBottom] = (0, import_react.useState)(0);
495
+ const prevScrollTopRef = (0, import_react.useRef)(0);
496
+ const lastProgrammaticWriteRef = (0, import_react.useRef)(null);
497
+ const programmaticWriteCountRef = (0, import_react.useRef)(0);
498
+ const pendingStickRafRef = (0, import_react.useRef)(null);
499
+ const stickRequestedRef = (0, import_react.useRef)(false);
500
+ const returnRafRef = (0, import_react.useRef)(null);
501
+ const returnAnimRef = (0, import_react.useRef)(null);
502
+ const setModeBoth = (0, import_react.useCallback)(
503
+ (next) => {
504
+ modeRef.current = next;
505
+ setMode(next);
506
+ onModeChange?.(next);
507
+ },
508
+ [onModeChange]
509
+ );
510
+ const updateDebug = (0, import_react.useCallback)(() => {
511
+ const viewport = viewportRef.current;
512
+ if (!viewport) return;
513
+ const m = measure(viewport);
514
+ if (debugDomAttributes) {
515
+ viewport.dataset.stickyMode = modeRef.current;
516
+ viewport.dataset.distanceToBottom = String(m.distanceToBottom);
517
+ viewport.dataset.isOverflowing = m.isOverflowing ? "1" : "0";
518
+ viewport.dataset.programmaticWrites = String(programmaticWriteCountRef.current);
519
+ }
520
+ onDebugStateChange?.({
521
+ mode: modeRef.current,
522
+ isOverflowing: m.isOverflowing,
523
+ distanceToBottom: m.distanceToBottom,
524
+ scrollTop: m.scrollTop,
525
+ maxScrollTop: m.maxScrollTop,
526
+ scrollHeight: m.scrollHeight,
527
+ clientHeight: m.clientHeight,
528
+ programmaticWrites: programmaticWriteCountRef.current
529
+ });
530
+ setDistanceToBottom(
531
+ (previous) => Math.abs(previous - m.distanceToBottom) <= 0.1 ? previous : m.distanceToBottom
532
+ );
533
+ }, [debugDomAttributes, onDebugStateChange]);
534
+ const writeScrollTop = (0, import_react.useCallback)((nextTop) => {
535
+ const viewport = viewportRef.current;
536
+ if (!viewport) return;
537
+ viewport.scrollTop = nextTop;
538
+ programmaticWriteCountRef.current += 1;
539
+ lastProgrammaticWriteRef.current = { at: performance.now(), top: nextTop };
540
+ }, []);
541
+ const cancelPendingStick = (0, import_react.useCallback)(() => {
542
+ if (pendingStickRafRef.current !== null) {
543
+ cancelAnimationFrame(pendingStickRafRef.current);
544
+ pendingStickRafRef.current = null;
545
+ }
546
+ stickRequestedRef.current = false;
547
+ }, []);
548
+ const cancelReturn = (0, import_react.useCallback)(() => {
549
+ if (returnRafRef.current !== null) {
550
+ cancelAnimationFrame(returnRafRef.current);
551
+ returnRafRef.current = null;
552
+ }
553
+ returnAnimRef.current = null;
554
+ }, []);
555
+ const stickToBottomInstant = (0, import_react.useCallback)(() => {
556
+ const viewport = viewportRef.current;
557
+ if (!viewport) return;
558
+ stickRequestedRef.current = true;
559
+ if (pendingStickRafRef.current !== null) return;
560
+ pendingStickRafRef.current = requestAnimationFrame(() => {
561
+ pendingStickRafRef.current = null;
562
+ if (!stickRequestedRef.current) return;
563
+ stickRequestedRef.current = false;
564
+ if (modeRef.current !== "STICKY_INSTANT") return;
565
+ const m = measure(viewport);
566
+ writeScrollTop(m.maxScrollTop);
567
+ updateDebug();
568
+ });
569
+ }, [updateDebug, writeScrollTop]);
570
+ const startReturnToBottomSmooth = (0, import_react.useCallback)(() => {
571
+ const viewport = viewportRef.current;
572
+ if (!viewport) return;
573
+ cancelPendingStick();
574
+ cancelReturn();
575
+ const initial = measure(viewport);
576
+ if (initial.distanceToBottom <= EPS_BOTTOM_PX) {
577
+ setModeBoth("STICKY_INSTANT");
578
+ stickToBottomInstant();
579
+ updateDebug();
580
+ return;
581
+ }
582
+ const durationMs = Math.max(
583
+ RETURN_MIN_MS,
584
+ Math.min(RETURN_MAX_MS, initial.distanceToBottom / RETURN_PX_PER_MS)
585
+ );
586
+ returnAnimRef.current = {
587
+ startTime: performance.now(),
588
+ startTop: initial.scrollTop,
589
+ durationMs,
590
+ settleFrames: 0
591
+ };
592
+ setModeBoth("RETURNING_SMOOTH");
593
+ const tick = (now2) => {
594
+ const viewportCurrent = viewportRef.current;
595
+ const anim = returnAnimRef.current;
596
+ if (!viewportCurrent || !anim || modeRef.current !== "RETURNING_SMOOTH") {
597
+ cancelReturn();
598
+ return;
599
+ }
600
+ const before = measure(viewportCurrent);
601
+ const progress = clamp01((now2 - anim.startTime) / anim.durationMs);
602
+ const eased = easeOutCubic(progress);
603
+ const targetBottom = before.maxScrollTop;
604
+ let nextTop = anim.startTop + (targetBottom - anim.startTop) * eased;
605
+ if (nextTop < before.scrollTop) {
606
+ nextTop = before.scrollTop;
607
+ }
608
+ writeScrollTop(nextTop);
609
+ const after = measure(viewportCurrent);
610
+ if (after.distanceToBottom <= EPS_BOTTOM_PX) {
611
+ anim.settleFrames += 1;
612
+ } else {
613
+ anim.settleFrames = 0;
614
+ }
615
+ const doneByTime = progress >= 1;
616
+ const doneBySettle = anim.settleFrames >= RETURN_SETTLE_FRAMES && progress >= 0.6;
617
+ if (doneByTime && doneBySettle) {
618
+ cancelReturn();
619
+ setModeBoth("STICKY_INSTANT");
620
+ stickToBottomInstant();
621
+ updateDebug();
622
+ return;
623
+ }
624
+ updateDebug();
625
+ returnRafRef.current = requestAnimationFrame(tick);
626
+ };
627
+ returnRafRef.current = requestAnimationFrame(tick);
628
+ }, [cancelPendingStick, cancelReturn, setModeBoth, stickToBottomInstant, updateDebug, writeScrollTop]);
629
+ const onViewportScroll = (0, import_react.useCallback)(
630
+ (event) => {
631
+ const viewport = event.currentTarget;
632
+ const m = measure(viewport);
633
+ setIsOverflowing((previous) => previous === m.isOverflowing ? previous : m.isOverflowing);
634
+ const previousTop = prevScrollTopRef.current;
635
+ const delta = m.scrollTop - previousTop;
636
+ const lastWrite = lastProgrammaticWriteRef.current;
637
+ const wroteRecently = lastWrite !== null && performance.now() - lastWrite.at < 60;
638
+ const isLikelyOwnWrite = wroteRecently && lastWrite !== null && Math.abs(m.scrollTop - lastWrite.top) <= 2;
639
+ if (modeRef.current === "RETURNING_SMOOTH") {
640
+ if (!isLikelyOwnWrite && delta < -DETACH_SCROLL_DELTA_PX) {
641
+ cancelReturn();
642
+ setModeBoth("DETACHED");
643
+ }
644
+ } else if (modeRef.current === "STICKY_INSTANT") {
645
+ if (!isLikelyOwnWrite && delta < -DETACH_SCROLL_DELTA_PX && m.isOverflowing) {
646
+ cancelPendingStick();
647
+ setModeBoth("DETACHED");
648
+ }
649
+ } else if (modeRef.current === "DETACHED") {
650
+ if (m.distanceToBottom <= EPS_BOTTOM_PX) {
651
+ setModeBoth("STICKY_INSTANT");
652
+ stickToBottomInstant();
653
+ }
654
+ }
655
+ prevScrollTopRef.current = m.scrollTop;
656
+ updateDebug();
657
+ },
658
+ [cancelPendingStick, cancelReturn, setModeBoth, stickToBottomInstant, updateDebug]
659
+ );
660
+ (0, import_react.useEffect)(() => {
661
+ const viewport = viewportRef.current;
662
+ const content = contentRef.current;
663
+ if (!viewport || !content) return;
664
+ const observer = new ResizeObserver(() => {
665
+ const m = measure(viewport);
666
+ setIsOverflowing((previous) => previous === m.isOverflowing ? previous : m.isOverflowing);
667
+ if (modeRef.current === "STICKY_INSTANT") {
668
+ stickToBottomInstant();
669
+ }
670
+ updateDebug();
671
+ });
672
+ observer.observe(content);
673
+ observer.observe(viewport);
674
+ return () => observer.disconnect();
675
+ }, [stickToBottomInstant, updateDebug]);
676
+ (0, import_react.useLayoutEffect)(() => {
677
+ const viewport = viewportRef.current;
678
+ if (!viewport) return;
679
+ setModeBoth("STICKY_INSTANT");
680
+ const initial = measure(viewport);
681
+ writeScrollTop(initial.maxScrollTop);
682
+ prevScrollTopRef.current = viewport.scrollTop;
683
+ setIsOverflowing(initial.isOverflowing);
684
+ setDistanceToBottom(initial.distanceToBottom);
685
+ updateDebug();
686
+ }, [setModeBoth, updateDebug, writeScrollTop]);
687
+ (0, import_react.useEffect)(() => {
688
+ return () => {
689
+ cancelPendingStick();
690
+ cancelReturn();
691
+ };
692
+ }, [cancelPendingStick, cancelReturn]);
693
+ const canJump = isOverflowing && mode === "DETACHED";
694
+ const jumpButton = renderJumpToBottom?.({
695
+ mode,
696
+ canJump,
697
+ isOverflowing,
698
+ distanceToBottom,
699
+ jumpToBottom: startReturnToBottomSmooth
700
+ }) ?? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DefaultJumpButton, { canJump, jumpToBottom: startReturnToBottomSmooth });
701
+ const jumpContainerClassNameBase = "pointer-events-none absolute z-20";
702
+ const jumpContainerStyle = {
703
+ position: "absolute",
704
+ zIndex: 20,
705
+ left: 0,
706
+ right: 0,
707
+ bottom: 12,
708
+ display: "flex",
709
+ justifyContent: "center",
710
+ opacity: canJump ? 1 : 0,
711
+ transform: canJump ? "translateY(0px)" : "translateY(4px)",
712
+ transition: "opacity 150ms ease, transform 150ms ease",
713
+ pointerEvents: "none"
714
+ };
715
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: joinClasses("relative h-full w-full overflow-hidden", className), children: [
716
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
717
+ "div",
718
+ {
719
+ ref: viewportRef,
720
+ className: joinClasses("h-full w-full overflow-auto", viewportClassName),
721
+ onScroll: onViewportScroll,
722
+ "data-testid": "sticky-scroll-viewport",
723
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: contentRef, className: joinClasses("flex min-h-full w-full flex-col", contentClassName), children })
724
+ }
725
+ ),
726
+ showJumpToBottom ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
727
+ "div",
728
+ {
729
+ className: joinClasses(jumpContainerClassNameBase, jumpContainerClassName),
730
+ style: jumpContainerStyle,
731
+ "aria-hidden": !canJump,
732
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: canJump ? "pointer-events-auto" : "pointer-events-none", children: jumpButton })
733
+ }
734
+ ) : null
735
+ ] });
736
+ }
737
+
738
+ // src/components/index.ts
421
739
  var import_core = require("@stream-mdx/core");
422
740
 
423
741
  // src/mdx-hydration-metrics.ts
@@ -457,8 +775,8 @@ function markMdxHydrationError(id) {
457
775
  }
458
776
 
459
777
  // src/mdx-hydration-context.ts
460
- var import_react = __toESM(require("react"), 1);
461
- var MdxHydrationContext = import_react.default.createContext({ controller: null });
778
+ var import_react2 = __toESM(require("react"), 1);
779
+ var MdxHydrationContext = import_react2.default.createContext({ controller: null });
462
780
 
463
781
  // src/mdx-runtime.ts
464
782
  var mdxRuntimePromise = null;
@@ -470,11 +788,11 @@ function loadMdxRuntime() {
470
788
  }
471
789
 
472
790
  // src/renderer/use-deferred-render.ts
473
- var import_react3 = require("react");
791
+ var import_react4 = require("react");
474
792
  function useDeferredRender(ref, options) {
475
793
  const enabled = options?.enabled ?? true;
476
- const [shouldRender, setShouldRender] = (0, import_react3.useState)(!enabled);
477
- (0, import_react3.useEffect)(() => {
794
+ const [shouldRender, setShouldRender] = (0, import_react4.useState)(!enabled);
795
+ (0, import_react4.useEffect)(() => {
478
796
  if (!enabled) {
479
797
  setShouldRender(true);
480
798
  return;
@@ -527,10 +845,10 @@ function useDeferredRender(ref, options) {
527
845
 
528
846
  // src/components/index.ts
529
847
  var import_core2 = require("@stream-mdx/core");
530
- var import_react5 = __toESM(require("react"), 1);
848
+ var import_react6 = __toESM(require("react"), 1);
531
849
 
532
850
  // src/utils/inline-html.ts
533
- var import_react4 = __toESM(require("react"), 1);
851
+ var import_react5 = __toESM(require("react"), 1);
534
852
  var BACKTICK_CONTENT = /^`([\s\S]+)`$/;
535
853
  var DEFAULT_INLINE_HTML_RENDERERS = {
536
854
  kbd: (descriptor, ctx) => {
@@ -542,7 +860,7 @@ var DEFAULT_INLINE_HTML_RENDERERS = {
542
860
  if (ctx.key !== void 0 && ctx.key !== null) {
543
861
  props.key = ctx.key;
544
862
  }
545
- return import_react4.default.createElement("kbd", props, import_react4.default.createElement("code", { className: "inline-code" }, codeText));
863
+ return import_react5.default.createElement("kbd", props, import_react5.default.createElement("code", { className: "inline-code" }, codeText));
546
864
  }
547
865
  return ctx.defaultRender();
548
866
  }
@@ -560,9 +878,9 @@ function renderInlineHtmlSegment(raw, sanitized, options = {}) {
560
878
  return null;
561
879
  }
562
880
  if (options.key !== void 0 && options.key !== null) {
563
- return import_react4.default.createElement(import_react4.default.Fragment, { key: options.key }, descriptor.text);
881
+ return import_react5.default.createElement(import_react5.default.Fragment, { key: options.key }, descriptor.text);
564
882
  }
565
- return import_react4.default.createElement(import_react4.default.Fragment, {}, descriptor.text);
883
+ return import_react5.default.createElement(import_react5.default.Fragment, {}, descriptor.text);
566
884
  }
567
885
  if (isInlineTag) {
568
886
  const parsedElement = renderSanitizedHtmlTree(descriptor.sanitized, options.key);
@@ -577,15 +895,15 @@ function renderInlineHtmlSegment(raw, sanitized, options = {}) {
577
895
  if (options.key !== void 0 && options.key !== null) {
578
896
  props.key = options.key;
579
897
  }
580
- return import_react4.default.createElement("span", props);
898
+ return import_react5.default.createElement("span", props);
581
899
  };
582
900
  const allRenderers = options.renderers ? { ...DEFAULT_INLINE_HTML_RENDERERS, ...options.renderers } : DEFAULT_INLINE_HTML_RENDERERS;
583
901
  const renderer = allRenderers[descriptor.tagName];
584
902
  if (renderer) {
585
903
  const rendered = renderer(descriptor, { key: options.key, defaultRender });
586
904
  if (rendered) {
587
- if (options.key !== void 0 && options.key !== null && import_react4.default.isValidElement(rendered) && rendered.key === null) {
588
- return import_react4.default.cloneElement(rendered, { key: options.key });
905
+ if (options.key !== void 0 && options.key !== null && import_react5.default.isValidElement(rendered) && rendered.key === null) {
906
+ return import_react5.default.cloneElement(rendered, { key: options.key });
589
907
  }
590
908
  return rendered;
591
909
  }
@@ -697,21 +1015,21 @@ function renderSanitizedHtmlTree(html, key) {
697
1015
  }
698
1016
  if (children.length === 1) {
699
1017
  const [child] = children;
700
- if (import_react4.default.isValidElement(child)) {
1018
+ if (import_react5.default.isValidElement(child)) {
701
1019
  if (key !== void 0 && key !== null) {
702
- return import_react4.default.cloneElement(child, { key });
1020
+ return import_react5.default.cloneElement(child, { key });
703
1021
  }
704
1022
  return child;
705
1023
  }
706
1024
  if (typeof child === "string" || typeof child === "number") {
707
1025
  if (key !== void 0 && key !== null) {
708
- return import_react4.default.createElement(import_react4.default.Fragment, { key }, child);
1026
+ return import_react5.default.createElement(import_react5.default.Fragment, { key }, child);
709
1027
  }
710
- return import_react4.default.createElement(import_react4.default.Fragment, {}, child);
1028
+ return import_react5.default.createElement(import_react5.default.Fragment, {}, child);
711
1029
  }
712
- return import_react4.default.createElement(import_react4.default.Fragment, { key }, child);
1030
+ return import_react5.default.createElement(import_react5.default.Fragment, { key }, child);
713
1031
  }
714
- return import_react4.default.createElement(import_react4.default.Fragment, { key }, ...children);
1032
+ return import_react5.default.createElement(import_react5.default.Fragment, { key }, ...children);
715
1033
  } catch {
716
1034
  return null;
717
1035
  }
@@ -736,9 +1054,9 @@ function convertDomNode(node, key) {
736
1054
  }
737
1055
  });
738
1056
  if (children.length === 0) {
739
- return import_react4.default.createElement(tagName, props);
1057
+ return import_react5.default.createElement(tagName, props);
740
1058
  }
741
- return import_react4.default.createElement(tagName, props, ...children);
1059
+ return import_react5.default.createElement(tagName, props, ...children);
742
1060
  }
743
1061
  function getElementAttributes(element) {
744
1062
  const attrs = {};
@@ -799,12 +1117,12 @@ var INLINE_ELEMENTS = /* @__PURE__ */ new Set([
799
1117
  ]);
800
1118
 
801
1119
  // src/components/link-safety-modal.tsx
802
- var import_jsx_runtime = require("react/jsx-runtime");
1120
+ var import_jsx_runtime2 = require("react/jsx-runtime");
803
1121
  var DefaultLinkSafetyModal = ({ url, isOpen, isChecking, onClose, onConfirm, onCopy }) => {
804
1122
  if (!isOpen) {
805
1123
  return null;
806
1124
  }
807
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1125
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
808
1126
  "div",
809
1127
  {
810
1128
  className: "stream-mdx-link-modal-backdrop",
@@ -822,7 +1140,7 @@ var DefaultLinkSafetyModal = ({ url, isOpen, isChecking, onClose, onConfirm, onC
822
1140
  padding: "24px"
823
1141
  },
824
1142
  onClick: onClose,
825
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1143
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
826
1144
  "div",
827
1145
  {
828
1146
  className: "stream-mdx-link-modal",
@@ -837,12 +1155,12 @@ var DefaultLinkSafetyModal = ({ url, isOpen, isChecking, onClose, onConfirm, onC
837
1155
  },
838
1156
  onClick: (event) => event.stopPropagation(),
839
1157
  children: [
840
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontWeight: 600, marginBottom: 8 }, children: "Open external link?" }),
841
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 13, opacity: 0.8, wordBreak: "break-all", marginBottom: 16 }, children: url }),
842
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: 8, justifyContent: "flex-end" }, children: [
843
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: onCopy, disabled: isChecking, style: buttonStyle, children: "Copy link" }),
844
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: onConfirm, disabled: isChecking, style: primaryButtonStyle, children: "Open link" }),
845
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: onClose, style: buttonStyle, children: "Cancel" })
1158
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontWeight: 600, marginBottom: 8 }, children: "Open external link?" }),
1159
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: 13, opacity: 0.8, wordBreak: "break-all", marginBottom: 16 }, children: url }),
1160
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: 8, justifyContent: "flex-end" }, children: [
1161
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", onClick: onCopy, disabled: isChecking, style: buttonStyle, children: "Copy link" }),
1162
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", onClick: onConfirm, disabled: isChecking, style: primaryButtonStyle, children: "Open link" }),
1163
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", onClick: onClose, style: buttonStyle, children: "Cancel" })
846
1164
  ] })
847
1165
  ]
848
1166
  }
@@ -866,7 +1184,7 @@ var primaryButtonStyle = {
866
1184
  };
867
1185
 
868
1186
  // src/components/index.ts
869
- var MdxRuntimeBoundary = class extends import_react5.default.Component {
1187
+ var MdxRuntimeBoundary = class extends import_react6.default.Component {
870
1188
  constructor() {
871
1189
  super(...arguments);
872
1190
  this.state = { hasError: false };
@@ -896,31 +1214,31 @@ function renderInlineNodes(nodes, components) {
896
1214
  case "text": {
897
1215
  const textComponent = components.text;
898
1216
  if (textComponent && textComponent !== defaultInlineComponents.text) {
899
- return import_react5.default.createElement(textComponent, { key, text: node.text });
1217
+ return import_react6.default.createElement(textComponent, { key, text: node.text });
900
1218
  }
901
- return import_react5.default.createElement(import_react5.default.Fragment, { key, children: node.text });
1219
+ return import_react6.default.createElement(import_react6.default.Fragment, { key, children: node.text });
902
1220
  }
903
1221
  case "strong":
904
- return import_react5.default.createElement(components.strong, {
1222
+ return import_react6.default.createElement(components.strong, {
905
1223
  key,
906
1224
  children: renderInlineNodes(node.children, components)
907
1225
  });
908
1226
  case "em":
909
- return import_react5.default.createElement(components.em, {
1227
+ return import_react6.default.createElement(components.em, {
910
1228
  key,
911
1229
  children: renderInlineNodes(node.children, components)
912
1230
  });
913
1231
  case "strike": {
914
- const StrikeComponent = components.strike ?? ((props) => import_react5.default.createElement("del", {}, props.children));
915
- return import_react5.default.createElement(StrikeComponent, {
1232
+ const StrikeComponent = components.strike ?? ((props) => import_react6.default.createElement("del", {}, props.children));
1233
+ return import_react6.default.createElement(StrikeComponent, {
916
1234
  key,
917
1235
  children: renderInlineNodes(node.children, components)
918
1236
  });
919
1237
  }
920
1238
  case "code":
921
- return import_react5.default.createElement(components.code, { key, text: node.text });
1239
+ return import_react6.default.createElement(components.code, { key, text: node.text });
922
1240
  case "link":
923
- return import_react5.default.createElement(
1241
+ return import_react6.default.createElement(
924
1242
  components.link,
925
1243
  {
926
1244
  key,
@@ -930,18 +1248,18 @@ function renderInlineNodes(nodes, components) {
930
1248
  }
931
1249
  );
932
1250
  case "image":
933
- return import_react5.default.createElement(components.image, {
1251
+ return import_react6.default.createElement(components.image, {
934
1252
  key,
935
1253
  src: node.src,
936
1254
  alt: node.alt,
937
1255
  title: node.title
938
1256
  });
939
1257
  case "br":
940
- return import_react5.default.createElement(import_react5.default.Fragment, { key }, import_react5.default.createElement(components.br, {}));
1258
+ return import_react6.default.createElement(import_react6.default.Fragment, { key }, import_react6.default.createElement(components.br, {}));
941
1259
  default: {
942
1260
  const component = components[node.kind];
943
1261
  if (component) {
944
- return import_react5.default.createElement(component, { key, ...node });
1262
+ return import_react6.default.createElement(component, { key, ...node });
945
1263
  }
946
1264
  return null;
947
1265
  }
@@ -949,18 +1267,18 @@ function renderInlineNodes(nodes, components) {
949
1267
  });
950
1268
  }
951
1269
  var defaultInlineComponents = {
952
- text: ({ text }) => import_react5.default.createElement(import_react5.default.Fragment, {}, text),
953
- strong: ({ children }) => import_react5.default.createElement("strong", {}, children),
954
- em: ({ children }) => import_react5.default.createElement("em", {}, children),
955
- strike: ({ children }) => import_react5.default.createElement("del", {}, children),
956
- code: ({ text }) => import_react5.default.createElement(
1270
+ text: ({ text }) => import_react6.default.createElement(import_react6.default.Fragment, {}, text),
1271
+ strong: ({ children }) => import_react6.default.createElement("strong", {}, children),
1272
+ em: ({ children }) => import_react6.default.createElement("em", {}, children),
1273
+ strike: ({ children }) => import_react6.default.createElement("del", {}, children),
1274
+ code: ({ text }) => import_react6.default.createElement(
957
1275
  "code",
958
1276
  {
959
1277
  className: "inline-code"
960
1278
  },
961
1279
  text
962
1280
  ),
963
- link: ({ href, title, children }) => import_react5.default.createElement(
1281
+ link: ({ href, title, children }) => import_react6.default.createElement(
964
1282
  "a",
965
1283
  {
966
1284
  href,
@@ -971,15 +1289,15 @@ var defaultInlineComponents = {
971
1289
  },
972
1290
  children
973
1291
  ),
974
- image: ({ src, alt, title }) => import_react5.default.createElement("img", {
1292
+ image: ({ src, alt, title }) => import_react6.default.createElement("img", {
975
1293
  src,
976
1294
  alt,
977
1295
  title,
978
1296
  className: "markdown-image"
979
1297
  }),
980
- br: () => import_react5.default.createElement("br"),
1298
+ br: () => import_react6.default.createElement("br"),
981
1299
  // Custom extensible components
982
- mention: ({ handle }) => import_react5.default.createElement(
1300
+ mention: ({ handle }) => import_react6.default.createElement(
983
1301
  "span",
984
1302
  {
985
1303
  className: "mention",
@@ -987,7 +1305,7 @@ var defaultInlineComponents = {
987
1305
  },
988
1306
  `@${handle}`
989
1307
  ),
990
- citation: ({ id }) => import_react5.default.createElement(
1308
+ citation: ({ id }) => import_react6.default.createElement(
991
1309
  "span",
992
1310
  {
993
1311
  className: "citation",
@@ -995,7 +1313,7 @@ var defaultInlineComponents = {
995
1313
  },
996
1314
  `[${id}]`
997
1315
  ),
998
- "math-inline": ({ tex }) => import_react5.default.createElement(
1316
+ "math-inline": ({ tex }) => import_react6.default.createElement(
999
1317
  "span",
1000
1318
  {
1001
1319
  className: "math-inline",
@@ -1003,27 +1321,31 @@ var defaultInlineComponents = {
1003
1321
  },
1004
1322
  `$${tex}$`
1005
1323
  ),
1006
- "math-display": ({ tex }) => import_react5.default.createElement(
1324
+ "math-display": ({ tex }) => import_react6.default.createElement(
1007
1325
  "div",
1008
1326
  {
1009
1327
  className: "math-display markdown-math-display",
1010
1328
  "data-tex": tex,
1011
1329
  style: { overflowX: "auto" }
1012
1330
  },
1013
- import_react5.default.createElement("span", { className: "math-display-content" }, `$$${tex}$$`)
1331
+ import_react6.default.createElement("span", { className: "math-display-content" }, `$$${tex}$$`)
1014
1332
  ),
1015
1333
  // Footnote inline reference (superscript anchor)
1016
1334
  "footnote-ref": ({ label, number }) => {
1017
1335
  const n = number ?? "?";
1018
1336
  const href = number ? `#fn:${n}` : void 0;
1019
1337
  const id = number ? `fnref:${n}` : void 0;
1020
- return import_react5.default.createElement("sup", { className: "footnote-ref" }, import_react5.default.createElement("a", { href, id, "data-label": label }, String(n)));
1338
+ return import_react6.default.createElement(
1339
+ "sup",
1340
+ { className: "footnote-ref" },
1341
+ import_react6.default.createElement("a", { href, id, "data-label": label, style: { color: "var(--foreground)", textDecoration: "underline" } }, String(n))
1342
+ );
1021
1343
  }
1022
1344
  };
1023
1345
  var defaultBlockComponents = {
1024
1346
  paragraph: ({ inlines, raw, meta, children }) => {
1025
1347
  if (children !== void 0) {
1026
- return import_react5.default.createElement(
1348
+ return import_react6.default.createElement(
1027
1349
  "p",
1028
1350
  {
1029
1351
  className: "markdown-paragraph"
@@ -1037,7 +1359,7 @@ var defaultBlockComponents = {
1037
1359
  if (structured.length === 1) {
1038
1360
  return structured[0];
1039
1361
  }
1040
- return import_react5.default.createElement(import_react5.default.Fragment, {}, ...structured);
1362
+ return import_react6.default.createElement(import_react6.default.Fragment, {}, ...structured);
1041
1363
  }
1042
1364
  const filteredInlines = inlines && raw && inlines.length > 0 ? inlines.filter((node) => !(node.kind === "text" && node.text === raw)) : inlines ?? [];
1043
1365
  const effectiveInlines = filteredInlines.length > 0 ? filteredInlines : raw ? [
@@ -1046,7 +1368,7 @@ var defaultBlockComponents = {
1046
1368
  text: raw
1047
1369
  }
1048
1370
  ] : [];
1049
- return import_react5.default.createElement(
1371
+ return import_react6.default.createElement(
1050
1372
  "p",
1051
1373
  {
1052
1374
  className: "markdown-paragraph"
@@ -1054,15 +1376,17 @@ var defaultBlockComponents = {
1054
1376
  effectiveInlines.length > 0 ? renderInlineNodes(effectiveInlines, defaultInlineComponents) : raw ?? ""
1055
1377
  );
1056
1378
  },
1057
- heading: ({ level, inlines, text }) => {
1379
+ heading: ({ level, inlines, text, meta }) => {
1058
1380
  const tag = `h${level}`;
1059
1381
  const onlyPlainText = Array.isArray(inlines) && inlines.length > 0 && inlines.every((node) => node.kind === "text");
1060
1382
  const children = onlyPlainText ? inlines.map((node) => node.kind === "text" ? node.text : "").join("") : renderInlineNodes(inlines, defaultInlineComponents);
1061
- return import_react5.default.createElement(
1383
+ const headingId = typeof meta?.headingId === "string" && meta.headingId.length > 0 ? meta.headingId : void 0;
1384
+ return import_react6.default.createElement(
1062
1385
  tag,
1063
1386
  {
1064
1387
  className: `markdown-heading markdown-h${level}`,
1065
- ...text ? { "data-heading-text": text } : {}
1388
+ ...text ? { "data-heading-text": text } : {},
1389
+ ...headingId ? { id: headingId, "data-heading-id": headingId } : {}
1066
1390
  },
1067
1391
  children
1068
1392
  );
@@ -1070,7 +1394,7 @@ var defaultBlockComponents = {
1070
1394
  code: ({ html, meta, lines, lang, preAttrs, codeAttrs }) => {
1071
1395
  const language = typeof lang === "string" ? lang : typeof meta?.lang === "string" ? String(meta.lang) : "text";
1072
1396
  if (html) {
1073
- return import_react5.default.createElement("div", {
1397
+ return import_react6.default.createElement("div", {
1074
1398
  className: `markdown-code-block language-${language || "text"}`,
1075
1399
  /* biome-ignore lint/security/noDangerouslySetInnerHtml: highlighted HTML is generated by our sanitizer */
1076
1400
  dangerouslySetInnerHTML: { __html: html }
@@ -1080,20 +1404,20 @@ var defaultBlockComponents = {
1080
1404
  if (lines && lines.length > 0) {
1081
1405
  const preAttributes = attrsToProps(preAttrs);
1082
1406
  const codeAttributes = attrsToProps(codeAttrs);
1083
- return import_react5.default.createElement(
1407
+ return import_react6.default.createElement(
1084
1408
  "pre",
1085
1409
  {
1086
1410
  ...preAttributes,
1087
1411
  className: preAttributes.className ? `${preAttributes.className} markdown-code-block language-${language || "text"}` : `markdown-code-block language-${language || "text"}`
1088
1412
  },
1089
- import_react5.default.createElement(
1413
+ import_react6.default.createElement(
1090
1414
  "code",
1091
1415
  {
1092
1416
  ...codeAttributes,
1093
1417
  className: codeAttributes.className ? `${codeAttributes.className} language-${language || "text"}` : `language-${language || "text"}`
1094
1418
  },
1095
1419
  lines.map(
1096
- (line) => import_react5.default.createElement("span", {
1420
+ (line) => import_react6.default.createElement("span", {
1097
1421
  key: line.id,
1098
1422
  className: "line",
1099
1423
  /* biome-ignore lint/security/noDangerouslySetInnerHtml: line HTML is sanitized server-side */
@@ -1103,19 +1427,19 @@ var defaultBlockComponents = {
1103
1427
  )
1104
1428
  );
1105
1429
  }
1106
- return import_react5.default.createElement("pre", {
1430
+ return import_react6.default.createElement("pre", {
1107
1431
  className: `markdown-code-block language-${language || "text"}`,
1108
1432
  children: code
1109
1433
  });
1110
1434
  },
1111
- blockquote: ({ inlines, renderedContent }) => import_react5.default.createElement(
1435
+ blockquote: ({ inlines, renderedContent }) => import_react6.default.createElement(
1112
1436
  "blockquote",
1113
1437
  {
1114
1438
  className: "markdown-blockquote"
1115
1439
  },
1116
1440
  renderedContent ?? renderInlineNodes(inlines, defaultInlineComponents)
1117
1441
  ),
1118
- hr: (props) => import_react5.default.createElement("hr", props),
1442
+ hr: (props) => import_react6.default.createElement("hr", props),
1119
1443
  list: ({ ordered, items }) => {
1120
1444
  if (items.length === 0) {
1121
1445
  return null;
@@ -1125,7 +1449,7 @@ var defaultBlockComponents = {
1125
1449
  ["--list-indent"]: `calc(2.5rem + ${String(items.length).length}ch)`
1126
1450
  } : void 0;
1127
1451
  const listItems = items.map(
1128
- (item, index) => import_react5.default.createElement(
1452
+ (item, index) => import_react6.default.createElement(
1129
1453
  "li",
1130
1454
  {
1131
1455
  key: index,
@@ -1136,7 +1460,7 @@ var defaultBlockComponents = {
1136
1460
  renderInlineNodes(item, defaultInlineComponents)
1137
1461
  )
1138
1462
  );
1139
- return import_react5.default.createElement(
1463
+ return import_react6.default.createElement(
1140
1464
  tag,
1141
1465
  {
1142
1466
  className: `markdown-list ${ordered ? "ordered" : "unordered"}`,
@@ -1147,26 +1471,26 @@ var defaultBlockComponents = {
1147
1471
  },
1148
1472
  html: ({ __trustedHtml, elements }) => {
1149
1473
  const raw = typeof __trustedHtml === "string" ? __trustedHtml : __trustedHtml.toString();
1150
- const htmlString = (0, import_core.sanitizeHTML)(raw);
1474
+ const htmlString = typeof window === "undefined" ? raw : (0, import_core.sanitizeHTML)(raw);
1151
1475
  if (typeof window !== "undefined" && elements) {
1152
1476
  const content = mapHtmlToReact(htmlString, elements);
1153
- return import_react5.default.createElement("div", { className: "markdown-html" }, content);
1477
+ return import_react6.default.createElement("div", { className: "markdown-html" }, content);
1154
1478
  }
1155
- return import_react5.default.createElement("div", {
1479
+ return import_react6.default.createElement("div", {
1156
1480
  className: "markdown-html",
1157
1481
  /* biome-ignore lint/security/noDangerouslySetInnerHtml: htmlString is sanitized before injection */
1158
1482
  dangerouslySetInnerHTML: { __html: htmlString }
1159
1483
  });
1160
1484
  },
1161
- mdx: ({ compiledRef, compiledModule, status, errorMessage, raw }) => {
1162
- const [Comp, setComp] = import_react5.default.useState(null);
1163
- const [internalError, setInternalError] = import_react5.default.useState(null);
1164
- const [renderError, setRenderError] = import_react5.default.useState(null);
1165
- const [retryKey, setRetryKey] = import_react5.default.useState(0);
1166
- const hydrationContext = import_react5.default.useContext(MdxHydrationContext);
1485
+ mdx: ({ compiledRef, compiledModule, status, errorMessage }) => {
1486
+ const [Comp, setComp] = import_react6.default.useState(null);
1487
+ const [internalError, setInternalError] = import_react6.default.useState(null);
1488
+ const [renderError, setRenderError] = import_react6.default.useState(null);
1489
+ const [retryKey, setRetryKey] = import_react6.default.useState(0);
1490
+ const hydrationContext = import_react6.default.useContext(MdxHydrationContext);
1167
1491
  const hydrationController = hydrationContext?.controller ?? null;
1168
1492
  const hydrationOptions = hydrationContext?.options;
1169
- const containerRef = import_react5.default.useRef(null);
1493
+ const containerRef = import_react6.default.useRef(null);
1170
1494
  const deferHydration = hydrationOptions?.strategy === "visible";
1171
1495
  const shouldHydrate = useDeferredRender(
1172
1496
  containerRef,
@@ -1178,13 +1502,13 @@ var defaultBlockComponents = {
1178
1502
  } : { enabled: false }
1179
1503
  );
1180
1504
  const resolvedId = compiledModule?.id ?? (compiledRef?.id && compiledRef.id !== "pending" ? compiledRef.id : void 0);
1181
- const handleRetry = import_react5.default.useCallback(() => {
1505
+ const handleRetry = import_react6.default.useCallback(() => {
1182
1506
  setInternalError(null);
1183
1507
  setRenderError(null);
1184
1508
  setComp(null);
1185
1509
  setRetryKey((prev) => prev + 1);
1186
1510
  }, []);
1187
- const handleRuntimeError = import_react5.default.useCallback(
1511
+ const handleRuntimeError = import_react6.default.useCallback(
1188
1512
  (error) => {
1189
1513
  const message2 = error instanceof Error ? error.message : String(error);
1190
1514
  setRenderError(message2);
@@ -1195,7 +1519,7 @@ var defaultBlockComponents = {
1195
1519
  const effectiveStatus = status ? status : resolvedId ? "compiled" : "pending";
1196
1520
  const failureMessage = errorMessage ?? internalError ?? renderError ?? null;
1197
1521
  const moduleDependencies = compiledModule?.dependencies;
1198
- import_react5.default.useEffect(() => {
1522
+ import_react6.default.useEffect(() => {
1199
1523
  if (!shouldHydrate) {
1200
1524
  return;
1201
1525
  }
@@ -1259,9 +1583,8 @@ var defaultBlockComponents = {
1259
1583
  const waitingForVisibility = deferHydration && !shouldHydrate && Boolean(resolvedId);
1260
1584
  const pendingLabel = waitingForVisibility ? "MDX ready (hydrate on view)\u2026" : compileMode === "worker" ? "Compiling MDX (client)\u2026" : "Compiling MDX (server)\u2026";
1261
1585
  const message = failureMessage ?? (compileMode === "worker" ? "MDX compilation failed in client mode. Try switching back to server rendering or restarting the stream." : "MDX compilation failed. Try restarting the stream.");
1262
- const rawFallback = typeof raw === "string" && raw.trim().length > 0 ? import_react5.default.createElement("pre", { className: "markdown-mdx-fallback" }, raw) : null;
1263
1586
  const allowRetry = Boolean(internalError || renderError);
1264
- const retryButton = allowRetry ? import_react5.default.createElement(
1587
+ const retryButton = allowRetry ? import_react6.default.createElement(
1265
1588
  "button",
1266
1589
  {
1267
1590
  type: "button",
@@ -1270,13 +1593,14 @@ var defaultBlockComponents = {
1270
1593
  },
1271
1594
  "Retry hydration"
1272
1595
  ) : null;
1273
- const errorPanel = import_react5.default.createElement(
1274
- "div",
1275
- { className: "markdown-mdx-error" },
1276
- import_react5.default.createElement(import_react5.default.Fragment, null, import_react5.default.createElement("strong", null, "MDX failed"), import_react5.default.createElement("div", null, message))
1596
+ const errorPanel = import_react6.default.createElement(
1597
+ import_react6.default.Fragment,
1598
+ null,
1599
+ import_react6.default.createElement("strong", null, "MDX failed"),
1600
+ import_react6.default.createElement("div", null, message)
1277
1601
  );
1278
1602
  if (Comp && !failureMessage) {
1279
- return import_react5.default.createElement(
1603
+ return import_react6.default.createElement(
1280
1604
  "div",
1281
1605
  {
1282
1606
  className: "markdown-mdx",
@@ -1285,30 +1609,29 @@ var defaultBlockComponents = {
1285
1609
  "data-mdx-status": failureMessage ? "error" : "compiled",
1286
1610
  "data-mdx-mode": compileMode
1287
1611
  },
1288
- import_react5.default.createElement(
1612
+ import_react6.default.createElement(
1289
1613
  MdxRuntimeBoundary,
1290
1614
  { resetKey: retryKey, onError: handleRuntimeError },
1291
- import_react5.default.createElement(Comp, {})
1615
+ import_react6.default.createElement(Comp, {})
1292
1616
  )
1293
1617
  );
1294
1618
  }
1295
1619
  if (failureMessage) {
1296
- return import_react5.default.createElement(
1620
+ return import_react6.default.createElement(
1297
1621
  "div",
1298
1622
  {
1299
- className: "markdown-mdx",
1623
+ className: "markdown-mdx error",
1300
1624
  ref: containerRef,
1301
1625
  "data-mdx-ref": pendingId,
1302
1626
  "data-mdx-status": "error",
1303
1627
  "data-mdx-mode": compileMode
1304
1628
  },
1305
1629
  errorPanel,
1306
- rawFallback,
1307
1630
  retryButton
1308
1631
  );
1309
1632
  }
1310
1633
  if (!Comp) {
1311
- return import_react5.default.createElement(
1634
+ return import_react6.default.createElement(
1312
1635
  "div",
1313
1636
  {
1314
1637
  className: "markdown-mdx",
@@ -1323,28 +1646,37 @@ var defaultBlockComponents = {
1323
1646
  },
1324
1647
  // Footnotes block rendered at page end
1325
1648
  footnotes: ({ items }) => {
1326
- if (!items || items.length === 0) return import_react5.default.createElement(import_react5.default.Fragment, null);
1649
+ if (!items || items.length === 0) return import_react6.default.createElement(import_react6.default.Fragment, null);
1327
1650
  const listItems = items.map(
1328
- (item) => import_react5.default.createElement(
1651
+ (item) => import_react6.default.createElement(
1329
1652
  "li",
1330
1653
  { key: item.number, id: `fn:${item.number}` },
1331
1654
  renderInlineNodes(item.inlines, defaultInlineComponents),
1332
1655
  " ",
1333
- import_react5.default.createElement("a", { href: `#fnref:${item.number}`, className: "footnote-backref", "aria-label": "Back to content" }, "\u21A9")
1656
+ import_react6.default.createElement(
1657
+ "a",
1658
+ {
1659
+ href: `#fnref:${item.number}`,
1660
+ className: "footnote-backref",
1661
+ "aria-label": "Back to content",
1662
+ style: { color: "var(--foreground)", textDecoration: "underline" }
1663
+ },
1664
+ "\u21A9"
1665
+ )
1334
1666
  )
1335
1667
  );
1336
- return import_react5.default.createElement("section", { className: "footnotes" }, import_react5.default.createElement("hr", {}), import_react5.default.createElement("ol", {}, listItems));
1668
+ return import_react6.default.createElement("section", { className: "footnotes" }, import_react6.default.createElement("hr", {}), import_react6.default.createElement("ol", {}, listItems));
1337
1669
  },
1338
1670
  // Footnote definition placeholders (render nothing)
1339
- "footnote-def": () => import_react5.default.createElement(import_react5.default.Fragment, null),
1671
+ "footnote-def": () => import_react6.default.createElement(import_react6.default.Fragment, null),
1340
1672
  // Callouts block
1341
1673
  callout: ({ kind, inlines = [] }) => {
1342
1674
  const tone = (kind || "NOTE").toUpperCase();
1343
1675
  const title = tone.charAt(0) + tone.slice(1).toLowerCase();
1344
- return import_react5.default.createElement(
1676
+ return import_react6.default.createElement(
1345
1677
  "div",
1346
1678
  { className: `markdown-callout markdown-callout-${tone.toLowerCase()} border rounded p-3 my-3` },
1347
- import_react5.default.createElement("div", { className: "font-semibold mb-1" }, title),
1679
+ import_react6.default.createElement("div", { className: "font-semibold mb-1" }, title),
1348
1680
  inlines.length > 0 ? renderInlineNodes(inlines, defaultInlineComponents) : null
1349
1681
  );
1350
1682
  },
@@ -1359,7 +1691,7 @@ var defaultBlockComponents = {
1359
1691
  const renderCells = (cells, tag, rowIdx) => cells.map((cell, i) => {
1360
1692
  const columnAlign = align?.[i] ?? void 0;
1361
1693
  const cellStyle = columnAlign ? { textAlign: columnAlign } : void 0;
1362
- return import_react5.default.createElement(
1694
+ return import_react6.default.createElement(
1363
1695
  tag === "th" ? El.Th : El.Td,
1364
1696
  {
1365
1697
  key: `${rowIdx}-${i}`,
@@ -1370,14 +1702,14 @@ var defaultBlockComponents = {
1370
1702
  renderInlineNodes(cell, defaultInlineComponents)
1371
1703
  );
1372
1704
  });
1373
- return import_react5.default.createElement(
1705
+ return import_react6.default.createElement(
1374
1706
  El.Table,
1375
1707
  { className: "markdown-table" },
1376
- header && header.length > 0 ? import_react5.default.createElement(El.Thead, {}, import_react5.default.createElement(El.Tr, {}, renderCells(header, "th", -1))) : null,
1377
- import_react5.default.createElement(
1708
+ header && header.length > 0 ? import_react6.default.createElement(El.Thead, {}, import_react6.default.createElement(El.Tr, {}, renderCells(header, "th", -1))) : null,
1709
+ import_react6.default.createElement(
1378
1710
  El.Tbody,
1379
1711
  {},
1380
- rows.map((row, r) => import_react5.default.createElement(El.Tr, { key: r }, renderCells(row, "td", r)))
1712
+ rows.map((row, r) => import_react6.default.createElement(El.Tr, { key: r }, renderCells(row, "td", r)))
1381
1713
  )
1382
1714
  );
1383
1715
  }
@@ -1446,7 +1778,7 @@ var ComponentRegistry = class {
1446
1778
  renderBlock(block) {
1447
1779
  const Component = this.getBlockComponent(block.type);
1448
1780
  const props = this.getBlockProps(block);
1449
- return import_react5.default.createElement(Component, {
1781
+ return import_react6.default.createElement(Component, {
1450
1782
  key: block.id,
1451
1783
  ...props
1452
1784
  });
@@ -1505,7 +1837,9 @@ var ComponentRegistry = class {
1505
1837
  case "html": {
1506
1838
  const trusted = block.payload.sanitizedHtml ?? block.payload.raw;
1507
1839
  return {
1508
- __trustedHtml: (0, import_core.createTrustedHTML)(trusted),
1840
+ // Server render should not depend on DOMPurify (which requires a DOM `window`).
1841
+ // In worker-compiled flows, `sanitizedHtml` is already sanitized at the source.
1842
+ __trustedHtml: typeof window === "undefined" ? String(trusted ?? "") : (0, import_core.createTrustedHTML)(String(trusted ?? "")),
1509
1843
  elements: this.htmlElements
1510
1844
  };
1511
1845
  }
@@ -1573,42 +1907,42 @@ var ComponentRegistry = class {
1573
1907
  function getDefaultHtmlElements() {
1574
1908
  return {
1575
1909
  // Text semantics
1576
- p: (props) => import_react5.default.createElement("p", props),
1577
- strong: (props) => import_react5.default.createElement("strong", props),
1578
- em: (props) => import_react5.default.createElement("em", props),
1579
- code: (props) => import_react5.default.createElement("code", props),
1580
- pre: (props) => import_react5.default.createElement("pre", props),
1581
- span: (props) => import_react5.default.createElement("span", props),
1582
- br: (props) => import_react5.default.createElement("br", props),
1583
- hr: (props) => import_react5.default.createElement("hr", props),
1910
+ p: (props) => import_react6.default.createElement("p", props),
1911
+ strong: (props) => import_react6.default.createElement("strong", props),
1912
+ em: (props) => import_react6.default.createElement("em", props),
1913
+ code: (props) => import_react6.default.createElement("code", props),
1914
+ pre: (props) => import_react6.default.createElement("pre", props),
1915
+ span: (props) => import_react6.default.createElement("span", props),
1916
+ br: (props) => import_react6.default.createElement("br", props),
1917
+ hr: (props) => import_react6.default.createElement("hr", props),
1584
1918
  // Lists
1585
- ul: (props) => import_react5.default.createElement("ul", props),
1586
- ol: (props) => import_react5.default.createElement("ol", props),
1587
- li: (props) => import_react5.default.createElement("li", props),
1919
+ ul: (props) => import_react6.default.createElement("ul", props),
1920
+ ol: (props) => import_react6.default.createElement("ol", props),
1921
+ li: (props) => import_react6.default.createElement("li", props),
1588
1922
  // Links & media
1589
- a: (props) => import_react5.default.createElement("a", props),
1590
- img: (props) => import_react5.default.createElement("img", props),
1923
+ a: (props) => import_react6.default.createElement("a", props),
1924
+ img: (props) => import_react6.default.createElement("img", props),
1591
1925
  // Blockquotes
1592
- blockquote: (props) => import_react5.default.createElement("blockquote", props),
1926
+ blockquote: (props) => import_react6.default.createElement("blockquote", props),
1593
1927
  // Tables
1594
- table: (props) => import_react5.default.createElement("table", props),
1595
- thead: (props) => import_react5.default.createElement("thead", props),
1596
- tbody: (props) => import_react5.default.createElement("tbody", props),
1597
- tr: (props) => import_react5.default.createElement("tr", props),
1598
- th: (props) => import_react5.default.createElement("th", props),
1599
- td: (props) => import_react5.default.createElement("td", props),
1928
+ table: (props) => import_react6.default.createElement("table", props),
1929
+ thead: (props) => import_react6.default.createElement("thead", props),
1930
+ tbody: (props) => import_react6.default.createElement("tbody", props),
1931
+ tr: (props) => import_react6.default.createElement("tr", props),
1932
+ th: (props) => import_react6.default.createElement("th", props),
1933
+ td: (props) => import_react6.default.createElement("td", props),
1600
1934
  // Generic
1601
- div: (props) => import_react5.default.createElement("div", props)
1935
+ div: (props) => import_react6.default.createElement("div", props)
1602
1936
  };
1603
1937
  }
1604
1938
  function getDefaultTableElements(overrides) {
1605
1939
  const base = {
1606
- Table: (props) => import_react5.default.createElement("table", props),
1607
- Thead: (props) => import_react5.default.createElement("thead", props),
1608
- Tbody: (props) => import_react5.default.createElement("tbody", props),
1609
- Tr: (props) => import_react5.default.createElement("tr", props),
1610
- Th: (props) => import_react5.default.createElement("th", props),
1611
- Td: (props) => import_react5.default.createElement("td", props)
1940
+ Table: (props) => import_react6.default.createElement("table", props),
1941
+ Thead: (props) => import_react6.default.createElement("thead", props),
1942
+ Tbody: (props) => import_react6.default.createElement("tbody", props),
1943
+ Tr: (props) => import_react6.default.createElement("tr", props),
1944
+ Th: (props) => import_react6.default.createElement("th", props),
1945
+ Td: (props) => import_react6.default.createElement("td", props)
1612
1946
  };
1613
1947
  return { ...base, ...overrides || {} };
1614
1948
  }
@@ -1622,12 +1956,12 @@ function mapHtmlToReact(html, elements) {
1622
1956
  children.push(element);
1623
1957
  }
1624
1958
  });
1625
- return import_react5.default.createElement(import_react5.default.Fragment, {}, ...children);
1959
+ return import_react6.default.createElement(import_react6.default.Fragment, {}, ...children);
1626
1960
  }
1627
1961
  function toReact(node, elements, key) {
1628
1962
  if (node.nodeType === Node.TEXT_NODE) {
1629
1963
  const text = node.textContent ?? "";
1630
- return import_react5.default.createElement(import_react5.default.Fragment, { key }, text);
1964
+ return import_react6.default.createElement(import_react6.default.Fragment, { key }, text);
1631
1965
  }
1632
1966
  if (node.nodeType !== Node.ELEMENT_NODE) {
1633
1967
  return null;
@@ -1649,9 +1983,9 @@ function toReact(node, elements, key) {
1649
1983
  const component = elements[tag];
1650
1984
  const elementChildren = children.length > 0 ? children : void 0;
1651
1985
  if (component) {
1652
- return import_react5.default.createElement(component, { ...props, key }, elementChildren);
1986
+ return import_react6.default.createElement(component, { ...props, key }, elementChildren);
1653
1987
  }
1654
- return import_react5.default.createElement(tag, { ...props, key }, elementChildren);
1988
+ return import_react6.default.createElement(tag, { ...props, key }, elementChildren);
1655
1989
  }
1656
1990
  function attrsToProps(attrs) {
1657
1991
  if (!attrs) return {};
@@ -1696,12 +2030,12 @@ function renderParagraphMixedSegments(segments, inlineComponents, inlineHtmlRend
1696
2030
  nodes.forEach((node, idx) => {
1697
2031
  if (node === null || node === void 0) return;
1698
2032
  const key = `${baseKey}-${idx}`;
1699
- if (import_react5.default.isValidElement(node)) {
1700
- target.push(node.key === key ? node : import_react5.default.cloneElement(node, { key }));
2033
+ if (import_react6.default.isValidElement(node)) {
2034
+ target.push(node.key === key ? node : import_react6.default.cloneElement(node, { key }));
1701
2035
  } else if (typeof node === "string" || typeof node === "number") {
1702
- target.push(import_react5.default.createElement(import_react5.default.Fragment, { key }, node));
2036
+ target.push(import_react6.default.createElement(import_react6.default.Fragment, { key }, node));
1703
2037
  } else {
1704
- target.push(import_react5.default.createElement(import_react5.default.Fragment, { key }, node));
2038
+ target.push(import_react6.default.createElement(import_react6.default.Fragment, { key }, node));
1705
2039
  }
1706
2040
  });
1707
2041
  };
@@ -1717,7 +2051,7 @@ function renderParagraphMixedSegments(segments, inlineComponents, inlineHtmlRend
1717
2051
  }
1718
2052
  const key = `paragraph-inline-group-${inlineGroupIndex++}`;
1719
2053
  result.push(
1720
- import_react5.default.createElement(
2054
+ import_react6.default.createElement(
1721
2055
  "p",
1722
2056
  {
1723
2057
  key,
@@ -1735,7 +2069,7 @@ function renderParagraphMixedSegments(segments, inlineComponents, inlineHtmlRend
1735
2069
  const inlineNodes = Array.isArray(segment.inline) ? segment.inline : [];
1736
2070
  if (inlineNodes.length === 0) {
1737
2071
  if (segment.value) {
1738
- inlineBuffer.push(import_react5.default.createElement(import_react5.default.Fragment, { key }, segment.value));
2072
+ inlineBuffer.push(import_react6.default.createElement(import_react6.default.Fragment, { key }, segment.value));
1739
2073
  }
1740
2074
  break;
1741
2075
  }
@@ -1763,14 +2097,14 @@ function renderParagraphMixedSegments(segments, inlineComponents, inlineHtmlRend
1763
2097
  const status = segment.status ?? "pending";
1764
2098
  let element;
1765
2099
  if (status === "compiled") {
1766
- element = import_react5.default.createElement("span", { className: "markdown-mdx-inline", "data-mdx-status": "compiled" });
2100
+ element = import_react6.default.createElement("span", { className: "markdown-mdx-inline", "data-mdx-status": "compiled" });
1767
2101
  } else if (status === "error") {
1768
2102
  const message = segment.value || "MDX error";
1769
- element = import_react5.default.createElement("span", { className: "markdown-mdx-inline text-destructive", "data-mdx-status": "error" }, message);
2103
+ element = import_react6.default.createElement("span", { className: "markdown-mdx-inline text-destructive", "data-mdx-status": "error" }, message);
1770
2104
  } else {
1771
- element = import_react5.default.createElement("span", { className: "markdown-mdx-inline", "data-mdx-status": status }, segment.value);
2105
+ element = import_react6.default.createElement("span", { className: "markdown-mdx-inline", "data-mdx-status": status }, segment.value);
1772
2106
  }
1773
- inlineBuffer.push(import_react5.default.createElement(import_react5.default.Fragment, { key }, element));
2107
+ inlineBuffer.push(import_react6.default.createElement(import_react6.default.Fragment, { key }, element));
1774
2108
  break;
1775
2109
  }
1776
2110
  case "html": {
@@ -1786,7 +2120,7 @@ function renderParagraphMixedSegments(segments, inlineComponents, inlineHtmlRend
1786
2120
  result.push(element);
1787
2121
  } else if (html) {
1788
2122
  result.push(
1789
- import_react5.default.createElement("div", {
2123
+ import_react6.default.createElement("div", {
1790
2124
  key,
1791
2125
  className: "markdown-inline-html-block",
1792
2126
  dangerouslySetInnerHTML: { __html: html }
@@ -1805,7 +2139,7 @@ function renderParagraphMixedSegments(segments, inlineComponents, inlineHtmlRend
1805
2139
  flushInline();
1806
2140
  if (result.length === 0) {
1807
2141
  return [
1808
- import_react5.default.createElement(
2142
+ import_react6.default.createElement(
1809
2143
  "p",
1810
2144
  {
1811
2145
  key: "paragraph-inline-group-0",
@@ -1864,6 +2198,7 @@ var BLOCK_LEVEL_TAGS = /* @__PURE__ */ new Set([
1864
2198
  ]);
1865
2199
  // Annotate the CommonJS export names for ESM import in node:
1866
2200
  0 && (module.exports = {
2201
+ BottomStickScrollArea,
1867
2202
  ComponentRegistry,
1868
2203
  DefaultLinkSafetyModal,
1869
2204
  defaultBlockComponents,