@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.
Files changed (57) hide show
  1. package/CHANGELOG.md +14 -4
  2. package/README.md +65 -15
  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 +503 -172
  8. package/dist/components/index.d.cts +3 -1
  9. package/dist/components/index.d.ts +3 -1
  10. package/dist/components/index.mjs +350 -22
  11. package/dist/{index-D2MYusAM.d.cts → index-BVhp_pcF.d.ts} +3 -0
  12. package/dist/{index-D2MYusAM.d.ts → index-EaeouYp2.d.cts} +3 -0
  13. package/dist/index.cjs +1472 -486
  14. package/dist/index.d.cts +6 -4
  15. package/dist/index.d.ts +6 -4
  16. package/dist/index.mjs +1256 -272
  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 +271 -26
  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 +272 -27
  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 +758 -114
  40. package/dist/renderer.d.cts +3 -1
  41. package/dist/renderer.d.ts +3 -1
  42. package/dist/renderer.mjs +760 -116
  43. package/dist/server.cjs +669 -71
  44. package/dist/server.d.cts +5 -0
  45. package/dist/server.d.ts +5 -0
  46. package/dist/server.mjs +670 -72
  47. package/dist/{streaming-markdown-DOc2uLiP.d.ts → streaming-markdown-CEI9eDZm.d.ts} +3 -1
  48. package/dist/{streaming-markdown-D-JcByd9.d.cts → streaming-markdown-DRisClXb.d.cts} +3 -1
  49. package/dist/streaming-markdown.cjs +788 -121
  50. package/dist/streaming-markdown.d.cts +4 -2
  51. package/dist/streaming-markdown.d.ts +4 -2
  52. package/dist/streaming-markdown.mjs +790 -123
  53. package/dist/utils/inline-html.d.cts +3 -1
  54. package/dist/utils/inline-html.d.ts +3 -1
  55. package/package.json +14 -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"
@@ -1059,7 +1381,7 @@ var defaultBlockComponents = {
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
1383
  const headingId = typeof meta?.headingId === "string" && meta.headingId.length > 0 ? meta.headingId : void 0;
1062
- return import_react5.default.createElement(
1384
+ return import_react6.default.createElement(
1063
1385
  tag,
1064
1386
  {
1065
1387
  className: `markdown-heading markdown-h${level}`,
@@ -1072,7 +1394,7 @@ var defaultBlockComponents = {
1072
1394
  code: ({ html, meta, lines, lang, preAttrs, codeAttrs }) => {
1073
1395
  const language = typeof lang === "string" ? lang : typeof meta?.lang === "string" ? String(meta.lang) : "text";
1074
1396
  if (html) {
1075
- return import_react5.default.createElement("div", {
1397
+ return import_react6.default.createElement("div", {
1076
1398
  className: `markdown-code-block language-${language || "text"}`,
1077
1399
  /* biome-ignore lint/security/noDangerouslySetInnerHtml: highlighted HTML is generated by our sanitizer */
1078
1400
  dangerouslySetInnerHTML: { __html: html }
@@ -1082,20 +1404,20 @@ var defaultBlockComponents = {
1082
1404
  if (lines && lines.length > 0) {
1083
1405
  const preAttributes = attrsToProps(preAttrs);
1084
1406
  const codeAttributes = attrsToProps(codeAttrs);
1085
- return import_react5.default.createElement(
1407
+ return import_react6.default.createElement(
1086
1408
  "pre",
1087
1409
  {
1088
1410
  ...preAttributes,
1089
1411
  className: preAttributes.className ? `${preAttributes.className} markdown-code-block language-${language || "text"}` : `markdown-code-block language-${language || "text"}`
1090
1412
  },
1091
- import_react5.default.createElement(
1413
+ import_react6.default.createElement(
1092
1414
  "code",
1093
1415
  {
1094
1416
  ...codeAttributes,
1095
1417
  className: codeAttributes.className ? `${codeAttributes.className} language-${language || "text"}` : `language-${language || "text"}`
1096
1418
  },
1097
1419
  lines.map(
1098
- (line) => import_react5.default.createElement("span", {
1420
+ (line) => import_react6.default.createElement("span", {
1099
1421
  key: line.id,
1100
1422
  className: "line",
1101
1423
  /* biome-ignore lint/security/noDangerouslySetInnerHtml: line HTML is sanitized server-side */
@@ -1105,19 +1427,19 @@ var defaultBlockComponents = {
1105
1427
  )
1106
1428
  );
1107
1429
  }
1108
- return import_react5.default.createElement("pre", {
1430
+ return import_react6.default.createElement("pre", {
1109
1431
  className: `markdown-code-block language-${language || "text"}`,
1110
1432
  children: code
1111
1433
  });
1112
1434
  },
1113
- blockquote: ({ inlines, renderedContent }) => import_react5.default.createElement(
1435
+ blockquote: ({ inlines, renderedContent }) => import_react6.default.createElement(
1114
1436
  "blockquote",
1115
1437
  {
1116
1438
  className: "markdown-blockquote"
1117
1439
  },
1118
1440
  renderedContent ?? renderInlineNodes(inlines, defaultInlineComponents)
1119
1441
  ),
1120
- hr: (props) => import_react5.default.createElement("hr", props),
1442
+ hr: (props) => import_react6.default.createElement("hr", props),
1121
1443
  list: ({ ordered, items }) => {
1122
1444
  if (items.length === 0) {
1123
1445
  return null;
@@ -1127,7 +1449,7 @@ var defaultBlockComponents = {
1127
1449
  ["--list-indent"]: `calc(2.5rem + ${String(items.length).length}ch)`
1128
1450
  } : void 0;
1129
1451
  const listItems = items.map(
1130
- (item, index) => import_react5.default.createElement(
1452
+ (item, index) => import_react6.default.createElement(
1131
1453
  "li",
1132
1454
  {
1133
1455
  key: index,
@@ -1138,7 +1460,7 @@ var defaultBlockComponents = {
1138
1460
  renderInlineNodes(item, defaultInlineComponents)
1139
1461
  )
1140
1462
  );
1141
- return import_react5.default.createElement(
1463
+ return import_react6.default.createElement(
1142
1464
  tag,
1143
1465
  {
1144
1466
  className: `markdown-list ${ordered ? "ordered" : "unordered"}`,
@@ -1152,23 +1474,23 @@ var defaultBlockComponents = {
1152
1474
  const htmlString = typeof window === "undefined" ? raw : (0, import_core.sanitizeHTML)(raw);
1153
1475
  if (typeof window !== "undefined" && elements) {
1154
1476
  const content = mapHtmlToReact(htmlString, elements);
1155
- return import_react5.default.createElement("div", { className: "markdown-html" }, content);
1477
+ return import_react6.default.createElement("div", { className: "markdown-html" }, content);
1156
1478
  }
1157
- return import_react5.default.createElement("div", {
1479
+ return import_react6.default.createElement("div", {
1158
1480
  className: "markdown-html",
1159
1481
  /* biome-ignore lint/security/noDangerouslySetInnerHtml: htmlString is sanitized before injection */
1160
1482
  dangerouslySetInnerHTML: { __html: htmlString }
1161
1483
  });
1162
1484
  },
1163
- mdx: ({ compiledRef, compiledModule, status, errorMessage, raw }) => {
1164
- const [Comp, setComp] = import_react5.default.useState(null);
1165
- const [internalError, setInternalError] = import_react5.default.useState(null);
1166
- const [renderError, setRenderError] = import_react5.default.useState(null);
1167
- const [retryKey, setRetryKey] = import_react5.default.useState(0);
1168
- 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);
1169
1491
  const hydrationController = hydrationContext?.controller ?? null;
1170
1492
  const hydrationOptions = hydrationContext?.options;
1171
- const containerRef = import_react5.default.useRef(null);
1493
+ const containerRef = import_react6.default.useRef(null);
1172
1494
  const deferHydration = hydrationOptions?.strategy === "visible";
1173
1495
  const shouldHydrate = useDeferredRender(
1174
1496
  containerRef,
@@ -1180,13 +1502,13 @@ var defaultBlockComponents = {
1180
1502
  } : { enabled: false }
1181
1503
  );
1182
1504
  const resolvedId = compiledModule?.id ?? (compiledRef?.id && compiledRef.id !== "pending" ? compiledRef.id : void 0);
1183
- const handleRetry = import_react5.default.useCallback(() => {
1505
+ const handleRetry = import_react6.default.useCallback(() => {
1184
1506
  setInternalError(null);
1185
1507
  setRenderError(null);
1186
1508
  setComp(null);
1187
1509
  setRetryKey((prev) => prev + 1);
1188
1510
  }, []);
1189
- const handleRuntimeError = import_react5.default.useCallback(
1511
+ const handleRuntimeError = import_react6.default.useCallback(
1190
1512
  (error) => {
1191
1513
  const message2 = error instanceof Error ? error.message : String(error);
1192
1514
  setRenderError(message2);
@@ -1197,7 +1519,7 @@ var defaultBlockComponents = {
1197
1519
  const effectiveStatus = status ? status : resolvedId ? "compiled" : "pending";
1198
1520
  const failureMessage = errorMessage ?? internalError ?? renderError ?? null;
1199
1521
  const moduleDependencies = compiledModule?.dependencies;
1200
- import_react5.default.useEffect(() => {
1522
+ import_react6.default.useEffect(() => {
1201
1523
  if (!shouldHydrate) {
1202
1524
  return;
1203
1525
  }
@@ -1261,9 +1583,8 @@ var defaultBlockComponents = {
1261
1583
  const waitingForVisibility = deferHydration && !shouldHydrate && Boolean(resolvedId);
1262
1584
  const pendingLabel = waitingForVisibility ? "MDX ready (hydrate on view)\u2026" : compileMode === "worker" ? "Compiling MDX (client)\u2026" : "Compiling MDX (server)\u2026";
1263
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.");
1264
- const rawFallback = typeof raw === "string" && raw.trim().length > 0 ? import_react5.default.createElement("pre", { className: "markdown-mdx-fallback" }, raw) : null;
1265
1586
  const allowRetry = Boolean(internalError || renderError);
1266
- const retryButton = allowRetry ? import_react5.default.createElement(
1587
+ const retryButton = allowRetry ? import_react6.default.createElement(
1267
1588
  "button",
1268
1589
  {
1269
1590
  type: "button",
@@ -1272,13 +1593,14 @@ var defaultBlockComponents = {
1272
1593
  },
1273
1594
  "Retry hydration"
1274
1595
  ) : null;
1275
- const errorPanel = import_react5.default.createElement(
1276
- "div",
1277
- { className: "markdown-mdx-error" },
1278
- 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)
1279
1601
  );
1280
1602
  if (Comp && !failureMessage) {
1281
- return import_react5.default.createElement(
1603
+ return import_react6.default.createElement(
1282
1604
  "div",
1283
1605
  {
1284
1606
  className: "markdown-mdx",
@@ -1287,30 +1609,29 @@ var defaultBlockComponents = {
1287
1609
  "data-mdx-status": failureMessage ? "error" : "compiled",
1288
1610
  "data-mdx-mode": compileMode
1289
1611
  },
1290
- import_react5.default.createElement(
1612
+ import_react6.default.createElement(
1291
1613
  MdxRuntimeBoundary,
1292
1614
  { resetKey: retryKey, onError: handleRuntimeError },
1293
- import_react5.default.createElement(Comp, {})
1615
+ import_react6.default.createElement(Comp, {})
1294
1616
  )
1295
1617
  );
1296
1618
  }
1297
1619
  if (failureMessage) {
1298
- return import_react5.default.createElement(
1620
+ return import_react6.default.createElement(
1299
1621
  "div",
1300
1622
  {
1301
- className: "markdown-mdx",
1623
+ className: "markdown-mdx error",
1302
1624
  ref: containerRef,
1303
1625
  "data-mdx-ref": pendingId,
1304
1626
  "data-mdx-status": "error",
1305
1627
  "data-mdx-mode": compileMode
1306
1628
  },
1307
1629
  errorPanel,
1308
- rawFallback,
1309
1630
  retryButton
1310
1631
  );
1311
1632
  }
1312
1633
  if (!Comp) {
1313
- return import_react5.default.createElement(
1634
+ return import_react6.default.createElement(
1314
1635
  "div",
1315
1636
  {
1316
1637
  className: "markdown-mdx",
@@ -1325,28 +1646,37 @@ var defaultBlockComponents = {
1325
1646
  },
1326
1647
  // Footnotes block rendered at page end
1327
1648
  footnotes: ({ items }) => {
1328
- 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);
1329
1650
  const listItems = items.map(
1330
- (item) => import_react5.default.createElement(
1651
+ (item) => import_react6.default.createElement(
1331
1652
  "li",
1332
1653
  { key: item.number, id: `fn:${item.number}` },
1333
1654
  renderInlineNodes(item.inlines, defaultInlineComponents),
1334
1655
  " ",
1335
- 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
+ )
1336
1666
  )
1337
1667
  );
1338
- 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));
1339
1669
  },
1340
1670
  // Footnote definition placeholders (render nothing)
1341
- "footnote-def": () => import_react5.default.createElement(import_react5.default.Fragment, null),
1671
+ "footnote-def": () => import_react6.default.createElement(import_react6.default.Fragment, null),
1342
1672
  // Callouts block
1343
1673
  callout: ({ kind, inlines = [] }) => {
1344
1674
  const tone = (kind || "NOTE").toUpperCase();
1345
1675
  const title = tone.charAt(0) + tone.slice(1).toLowerCase();
1346
- return import_react5.default.createElement(
1676
+ return import_react6.default.createElement(
1347
1677
  "div",
1348
1678
  { className: `markdown-callout markdown-callout-${tone.toLowerCase()} border rounded p-3 my-3` },
1349
- import_react5.default.createElement("div", { className: "font-semibold mb-1" }, title),
1679
+ import_react6.default.createElement("div", { className: "font-semibold mb-1" }, title),
1350
1680
  inlines.length > 0 ? renderInlineNodes(inlines, defaultInlineComponents) : null
1351
1681
  );
1352
1682
  },
@@ -1361,7 +1691,7 @@ var defaultBlockComponents = {
1361
1691
  const renderCells = (cells, tag, rowIdx) => cells.map((cell, i) => {
1362
1692
  const columnAlign = align?.[i] ?? void 0;
1363
1693
  const cellStyle = columnAlign ? { textAlign: columnAlign } : void 0;
1364
- return import_react5.default.createElement(
1694
+ return import_react6.default.createElement(
1365
1695
  tag === "th" ? El.Th : El.Td,
1366
1696
  {
1367
1697
  key: `${rowIdx}-${i}`,
@@ -1372,14 +1702,14 @@ var defaultBlockComponents = {
1372
1702
  renderInlineNodes(cell, defaultInlineComponents)
1373
1703
  );
1374
1704
  });
1375
- return import_react5.default.createElement(
1705
+ return import_react6.default.createElement(
1376
1706
  El.Table,
1377
1707
  { className: "markdown-table" },
1378
- header && header.length > 0 ? import_react5.default.createElement(El.Thead, {}, import_react5.default.createElement(El.Tr, {}, renderCells(header, "th", -1))) : null,
1379
- 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(
1380
1710
  El.Tbody,
1381
1711
  {},
1382
- 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)))
1383
1713
  )
1384
1714
  );
1385
1715
  }
@@ -1448,7 +1778,7 @@ var ComponentRegistry = class {
1448
1778
  renderBlock(block) {
1449
1779
  const Component = this.getBlockComponent(block.type);
1450
1780
  const props = this.getBlockProps(block);
1451
- return import_react5.default.createElement(Component, {
1781
+ return import_react6.default.createElement(Component, {
1452
1782
  key: block.id,
1453
1783
  ...props
1454
1784
  });
@@ -1577,42 +1907,42 @@ var ComponentRegistry = class {
1577
1907
  function getDefaultHtmlElements() {
1578
1908
  return {
1579
1909
  // Text semantics
1580
- p: (props) => import_react5.default.createElement("p", props),
1581
- strong: (props) => import_react5.default.createElement("strong", props),
1582
- em: (props) => import_react5.default.createElement("em", props),
1583
- code: (props) => import_react5.default.createElement("code", props),
1584
- pre: (props) => import_react5.default.createElement("pre", props),
1585
- span: (props) => import_react5.default.createElement("span", props),
1586
- br: (props) => import_react5.default.createElement("br", props),
1587
- 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),
1588
1918
  // Lists
1589
- ul: (props) => import_react5.default.createElement("ul", props),
1590
- ol: (props) => import_react5.default.createElement("ol", props),
1591
- 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),
1592
1922
  // Links & media
1593
- a: (props) => import_react5.default.createElement("a", props),
1594
- 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),
1595
1925
  // Blockquotes
1596
- blockquote: (props) => import_react5.default.createElement("blockquote", props),
1926
+ blockquote: (props) => import_react6.default.createElement("blockquote", props),
1597
1927
  // Tables
1598
- table: (props) => import_react5.default.createElement("table", props),
1599
- thead: (props) => import_react5.default.createElement("thead", props),
1600
- tbody: (props) => import_react5.default.createElement("tbody", props),
1601
- tr: (props) => import_react5.default.createElement("tr", props),
1602
- th: (props) => import_react5.default.createElement("th", props),
1603
- 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),
1604
1934
  // Generic
1605
- div: (props) => import_react5.default.createElement("div", props)
1935
+ div: (props) => import_react6.default.createElement("div", props)
1606
1936
  };
1607
1937
  }
1608
1938
  function getDefaultTableElements(overrides) {
1609
1939
  const base = {
1610
- Table: (props) => import_react5.default.createElement("table", props),
1611
- Thead: (props) => import_react5.default.createElement("thead", props),
1612
- Tbody: (props) => import_react5.default.createElement("tbody", props),
1613
- Tr: (props) => import_react5.default.createElement("tr", props),
1614
- Th: (props) => import_react5.default.createElement("th", props),
1615
- 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)
1616
1946
  };
1617
1947
  return { ...base, ...overrides || {} };
1618
1948
  }
@@ -1626,12 +1956,12 @@ function mapHtmlToReact(html, elements) {
1626
1956
  children.push(element);
1627
1957
  }
1628
1958
  });
1629
- return import_react5.default.createElement(import_react5.default.Fragment, {}, ...children);
1959
+ return import_react6.default.createElement(import_react6.default.Fragment, {}, ...children);
1630
1960
  }
1631
1961
  function toReact(node, elements, key) {
1632
1962
  if (node.nodeType === Node.TEXT_NODE) {
1633
1963
  const text = node.textContent ?? "";
1634
- return import_react5.default.createElement(import_react5.default.Fragment, { key }, text);
1964
+ return import_react6.default.createElement(import_react6.default.Fragment, { key }, text);
1635
1965
  }
1636
1966
  if (node.nodeType !== Node.ELEMENT_NODE) {
1637
1967
  return null;
@@ -1653,9 +1983,9 @@ function toReact(node, elements, key) {
1653
1983
  const component = elements[tag];
1654
1984
  const elementChildren = children.length > 0 ? children : void 0;
1655
1985
  if (component) {
1656
- return import_react5.default.createElement(component, { ...props, key }, elementChildren);
1986
+ return import_react6.default.createElement(component, { ...props, key }, elementChildren);
1657
1987
  }
1658
- return import_react5.default.createElement(tag, { ...props, key }, elementChildren);
1988
+ return import_react6.default.createElement(tag, { ...props, key }, elementChildren);
1659
1989
  }
1660
1990
  function attrsToProps(attrs) {
1661
1991
  if (!attrs) return {};
@@ -1700,12 +2030,12 @@ function renderParagraphMixedSegments(segments, inlineComponents, inlineHtmlRend
1700
2030
  nodes.forEach((node, idx) => {
1701
2031
  if (node === null || node === void 0) return;
1702
2032
  const key = `${baseKey}-${idx}`;
1703
- if (import_react5.default.isValidElement(node)) {
1704
- 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 }));
1705
2035
  } else if (typeof node === "string" || typeof node === "number") {
1706
- 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));
1707
2037
  } else {
1708
- 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));
1709
2039
  }
1710
2040
  });
1711
2041
  };
@@ -1721,7 +2051,7 @@ function renderParagraphMixedSegments(segments, inlineComponents, inlineHtmlRend
1721
2051
  }
1722
2052
  const key = `paragraph-inline-group-${inlineGroupIndex++}`;
1723
2053
  result.push(
1724
- import_react5.default.createElement(
2054
+ import_react6.default.createElement(
1725
2055
  "p",
1726
2056
  {
1727
2057
  key,
@@ -1739,7 +2069,7 @@ function renderParagraphMixedSegments(segments, inlineComponents, inlineHtmlRend
1739
2069
  const inlineNodes = Array.isArray(segment.inline) ? segment.inline : [];
1740
2070
  if (inlineNodes.length === 0) {
1741
2071
  if (segment.value) {
1742
- 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));
1743
2073
  }
1744
2074
  break;
1745
2075
  }
@@ -1767,14 +2097,14 @@ function renderParagraphMixedSegments(segments, inlineComponents, inlineHtmlRend
1767
2097
  const status = segment.status ?? "pending";
1768
2098
  let element;
1769
2099
  if (status === "compiled") {
1770
- 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" });
1771
2101
  } else if (status === "error") {
1772
2102
  const message = segment.value || "MDX error";
1773
- 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);
1774
2104
  } else {
1775
- 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);
1776
2106
  }
1777
- 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));
1778
2108
  break;
1779
2109
  }
1780
2110
  case "html": {
@@ -1790,7 +2120,7 @@ function renderParagraphMixedSegments(segments, inlineComponents, inlineHtmlRend
1790
2120
  result.push(element);
1791
2121
  } else if (html) {
1792
2122
  result.push(
1793
- import_react5.default.createElement("div", {
2123
+ import_react6.default.createElement("div", {
1794
2124
  key,
1795
2125
  className: "markdown-inline-html-block",
1796
2126
  dangerouslySetInnerHTML: { __html: html }
@@ -1809,7 +2139,7 @@ function renderParagraphMixedSegments(segments, inlineComponents, inlineHtmlRend
1809
2139
  flushInline();
1810
2140
  if (result.length === 0) {
1811
2141
  return [
1812
- import_react5.default.createElement(
2142
+ import_react6.default.createElement(
1813
2143
  "p",
1814
2144
  {
1815
2145
  key: "paragraph-inline-group-0",
@@ -1868,6 +2198,7 @@ var BLOCK_LEVEL_TAGS = /* @__PURE__ */ new Set([
1868
2198
  ]);
1869
2199
  // Annotate the CommonJS export names for ESM import in node:
1870
2200
  0 && (module.exports = {
2201
+ BottomStickScrollArea,
1871
2202
  ComponentRegistry,
1872
2203
  DefaultLinkSafetyModal,
1873
2204
  defaultBlockComponents,