react-ai-renderer 0.1.21 → 0.1.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import React__default, { useState, useEffect, useMemo, useRef, useCallback } from 'react';
2
+ import React__default, { useState, useMemo, useEffect, useRef, useCallback } from 'react';
3
3
  import * as runtime from 'react/jsx-runtime';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
5
  import RemarkMath from 'remark-math';
@@ -316,22 +316,18 @@ var MDXStreamingParser = /** @class */function () {
316
316
  MDXStreamingParser.prototype.isComponentRegistered = function (name) {
317
317
  return this.registeredComponents.has(name);
318
318
  };
319
- MDXStreamingParser.prototype.parse = function (messageId, input) {
319
+ MDXStreamingParser.prototype.parse = function (_messageId, input) {
320
320
  var e_1, _a, e_2, _b, e_3, _c;
321
- // 获取或创建该消息的解析状态
322
- var state = this.messages.get(messageId);
323
- if (!state) {
324
- state = {
325
- position: 0,
326
- stack: [],
327
- buffer: '',
328
- pendingClosingTag: undefined,
329
- pendingOpeningTag: undefined
330
- };
331
- this.messages.set(messageId, state);
332
- }
321
+ // 每次对完整 content 从零解析,保证流式增量与组件 remount 后全量重解析结果一致
322
+ var state = {
323
+ position: 0,
324
+ stack: [],
325
+ buffer: '',
326
+ pendingClosingTag: undefined,
327
+ pendingOpeningTag: undefined
328
+ };
333
329
  var result = [];
334
- var i = state.position;
330
+ var i = 0;
335
331
  // 如果有暂存的不完整闭合标签,先尝试与当前输入合并处理
336
332
  if (state.pendingClosingTag) {
337
333
  var combinedInput = state.pendingClosingTag + input;
@@ -479,13 +475,11 @@ var MDXStreamingParser = /** @class */function () {
479
475
  // 如果部分标签是栈顶组件名的前缀,说明可能是不完整的闭合标签
480
476
  if (topComponentName.startsWith(partialTag) || partialTag.length === 0) {
481
477
  state.pendingClosingTag = input.slice(i);
482
- this.messages.set(messageId, state);
483
478
  break;
484
479
  }
485
480
  }
486
481
  // 否则,可能是其他不完整的标签,暂存起来
487
482
  state.pendingClosingTag = input.slice(i);
488
- this.messages.set(messageId, state);
489
483
  break;
490
484
  }
491
485
  var tagName = input.slice(i + 2, closeTagEnd);
@@ -531,7 +525,6 @@ var MDXStreamingParser = /** @class */function () {
531
525
  // 暂存起来,不添加到文本内容
532
526
  if (topComponentName.startsWith(tagName) && tagName.length < topComponentName.length) {
533
527
  state.pendingClosingTag = input.slice(i, closeTagEnd + 1);
534
- this.messages.set(messageId, state);
535
528
  break;
536
529
  }
537
530
  }
@@ -579,12 +572,10 @@ var MDXStreamingParser = /** @class */function () {
579
572
  // 找到了部分标签,暂存起来
580
573
  var partialTagEnd = i + tagEndMatch[0].length - 1;
581
574
  state.pendingOpeningTag = input.slice(i, partialTagEnd);
582
- this.messages.set(messageId, state);
583
575
  break;
584
576
  } else {
585
577
  // 标签完全不完整,暂存整个片段
586
578
  state.pendingOpeningTag = input.slice(i);
587
- this.messages.set(messageId, state);
588
579
  break;
589
580
  }
590
581
  } else {
@@ -622,18 +613,12 @@ var MDXStreamingParser = /** @class */function () {
622
613
  props = _k.props,
623
614
  endIndex = _k.endIndex,
624
615
  selfClosing = _k.selfClosing;
625
- // 检测组件是否完整:
626
- // 1. 自闭合组件一定是完整的
627
- // 2. 非自闭合组件:如果有 props 且不在 stack 中(已闭合),则是完整的
628
- // 对于流式渲染,如果 props 为空且不是自闭合,说明组件可能还在解析中
629
- var hasProps = props && Object.keys(props).length > 0;
630
- var isComplete = selfClosing || hasProps;
631
616
  var component = {
632
617
  type: "component",
633
618
  value: componentName,
634
619
  props: props || {},
635
620
  selfClosing: selfClosing,
636
- isComplete: isComplete // 自闭合一定完整,非自闭合取决于是否有 props
621
+ isComplete: selfClosing
637
622
  };
638
623
  if (!selfClosing) {
639
624
  state.stack.push(component);
@@ -701,9 +686,35 @@ var MDXStreamingParser = /** @class */function () {
701
686
  state.stack.forEach(function (component) {
702
687
  component.isComplete = false;
703
688
  });
704
- state.position = i;
705
- // 保存状态
706
- this.messages.set(messageId, state);
689
+ // 流式未闭合的根组件可能只在 stack 中,补进 result 供 loader 渲染
690
+ if (state.stack.length > 0) {
691
+ var root_1 = state.stack[0];
692
+ var already = result.some(function (item) {
693
+ return item.type === 'component' && item.value === root_1.value;
694
+ });
695
+ if (!already) {
696
+ result.push(root_1);
697
+ }
698
+ }
699
+ // 流式未闭合的开始标签(尚未入 stack)也产出占位组件,供 loader 渲染
700
+ if (state.pendingOpeningTag) {
701
+ var tagMatch = state.pendingOpeningTag.match(/^<([A-Z][A-Za-z0-9]*)/);
702
+ if (tagMatch && this.isComponentRegistered(tagMatch[1])) {
703
+ var name_1 = tagMatch[1];
704
+ var already = result.some(function (item) {
705
+ return item.type === 'component' && item.value === name_1;
706
+ });
707
+ if (!already) {
708
+ result.push({
709
+ type: 'component',
710
+ value: name_1,
711
+ props: {},
712
+ selfClosing: false,
713
+ isComplete: false
714
+ });
715
+ }
716
+ }
717
+ }
707
718
  return result;
708
719
  };
709
720
  MDXStreamingParser.prototype.findComponentClose = function (input, startIndex) {
@@ -805,33 +816,37 @@ var MDXStreamingParser = /** @class */function () {
805
816
  // 处理 JSON 值(对象或数组)
806
817
  var startChar = input[j];
807
818
  var startBracket = j;
808
- // 使用局部变量跟踪属性值内部的括号嵌套
809
819
  var localBracketCount = 0;
810
820
  var localSquareBracketCount = 0;
811
821
  var inValueQuote = false;
812
822
  var valueQuoteChar = '';
823
+ var inBacktick = false;
824
+ var closingStack = [];
813
825
  if (startChar === '{') {
814
826
  localBracketCount = 1;
827
+ closingStack.push('}');
815
828
  } else {
816
829
  localSquareBracketCount = 1;
830
+ closingStack.push(']');
817
831
  }
818
832
  j++;
819
- // 同时跟踪花括号和方括号的嵌套
820
833
  while (j < input.length && (localBracketCount > 0 || localSquareBracketCount > 0)) {
821
- if (input[j] === '"' || input[j] === "'") {
822
- // 在字符串内,跳过整个字符串
834
+ if (input[j] === '`' && !inValueQuote) {
835
+ inBacktick = !inBacktick;
836
+ j++;
837
+ } else if (inBacktick) {
838
+ j++;
839
+ } else if (input[j] === '"' || input[j] === "'") {
823
840
  if (!inValueQuote) {
824
841
  inValueQuote = true;
825
842
  valueQuoteChar = input[j];
826
843
  } else if (input[j] === valueQuoteChar) {
827
- // 检查是否是转义的引号
828
844
  var escapeCount = 0;
829
845
  var k = j - 1;
830
846
  while (k >= 0 && input[k] === '\\') {
831
847
  escapeCount++;
832
848
  k--;
833
849
  }
834
- // 如果是偶数个反斜杠,说明引号没有被转义
835
850
  if (escapeCount % 2 === 0) {
836
851
  inValueQuote = false;
837
852
  }
@@ -839,15 +854,23 @@ var MDXStreamingParser = /** @class */function () {
839
854
  j++;
840
855
  } else if (input[j] === '{' && !inValueQuote) {
841
856
  localBracketCount++;
857
+ closingStack.push('}');
842
858
  j++;
843
859
  } else if (input[j] === '}' && !inValueQuote) {
844
860
  localBracketCount--;
861
+ if (closingStack.length > 0 && closingStack[closingStack.length - 1] === '}') {
862
+ closingStack.pop();
863
+ }
845
864
  j++;
846
865
  } else if (input[j] === '[' && !inValueQuote) {
847
866
  localSquareBracketCount++;
867
+ closingStack.push(']');
848
868
  j++;
849
869
  } else if (input[j] === ']' && !inValueQuote) {
850
870
  localSquareBracketCount--;
871
+ if (closingStack.length > 0 && closingStack[closingStack.length - 1] === ']') {
872
+ closingStack.pop();
873
+ }
851
874
  j++;
852
875
  } else {
853
876
  j++;
@@ -855,31 +878,46 @@ var MDXStreamingParser = /** @class */function () {
855
878
  }
856
879
  var rawValue = input.slice(startBracket, j);
857
880
  value = input.slice(startBracket + 1, j - 1);
881
+ // 流式修复:输入未结束但括号未闭合,尝试关闭不完整的表达式
882
+ if (j >= input.length && closingStack.length > 0) {
883
+ var healed = rawValue;
884
+ if (inBacktick) healed += '`';
885
+ if (inValueQuote) healed += valueQuoteChar;
886
+ healed += closingStack.reverse().join('');
887
+ // 剥离外层 JSX 表达式括号 {{ → {,用 (...) 包裹强制表达式上下文
888
+ var inner = healed.slice(1, -1);
889
+ try {
890
+ props[propName] = new Function('return (' + inner + ')')();
891
+ } catch (_a) {
892
+ try {
893
+ var jv = inner.replace(/`([^`]*)`/g, function (_, p1) {
894
+ return JSON.stringify(p1);
895
+ }).replace(/'([^'\\]*(\\.[^'\\]*)*)'/g, function (m) {
896
+ var s = m.slice(1, -1).replace(/\\/g, '\\\\').replace(/"/g, '\\"');
897
+ return "\"".concat(s, "\"");
898
+ }).replace(/([{,]\s*)([\p{L}_$][\p{L}\p{N}_$]*)\s*:/gu, '$1"$2":');
899
+ props[propName] = JSON.parse(jv);
900
+ } catch (_b) {
901
+ // 修复失败,不设置 prop,组件以骨架态渲染
902
+ }
903
+ }
904
+ i = j;
905
+ continue;
906
+ }
858
907
  try {
859
- // 直接使用 Function 构造器来评估 JavaScript 表达式
860
- // 这比手动转换 JavaScript 对象字面量为 JSON 更可靠
861
908
  props[propName] = new Function('return ' + rawValue)();
862
909
  } catch (e) {
863
- // 如果 Function 构造器失败,尝试手动转换并解析为 JSON
864
910
  try {
865
- // 将 JavaScript 对象字面量转换为有效的 JSON
866
- // 1. 将单引号字符串转换为双引号字符串
867
911
  var jsonValue = value.replace(/'([^'\\]*(\\.[^'\\]*)*)'/g, function (match) {
868
- // 将单引号内容转换为双引号,并转义内部的双引号和反斜杠
869
912
  var inner = match.slice(1, -1).replace(/\\/g, '\\\\').replace(/"/g, '\\"');
870
913
  return "\"".concat(inner, "\"");
871
914
  });
872
- // 2. 为对象键名添加引号(如果还没有引号)
873
- // 修复:使用 \p{L} 匹配 Unicode 字母(包括中文),使用 u 标志
874
915
  jsonValue = jsonValue.replace(/([{,]\s*)([\p{L}_$][\p{L}\p{N}_$]*)\s*:/gu, '$1"$2":');
875
- // 3. 处理属性值中的模板字符串
876
916
  jsonValue = jsonValue.replace(/`([^`]*)`/g, function (match, p1) {
877
917
  return JSON.stringify(p1);
878
918
  });
879
- // 4. 尝试解析为 JSON
880
919
  props[propName] = JSON.parse(jsonValue);
881
920
  } catch (jsonError) {
882
- // 如果都失败了,保持原值
883
921
  props[propName] = value;
884
922
  }
885
923
  }
@@ -39558,18 +39596,64 @@ function requireZTouch () {
39558
39596
  var _zTouch = _interopRequireDefault(requireZTouch());
39559
39597
  } (prism$1));
39560
39598
 
39561
- var themes = {
39599
+ var CODE_THEME_MAP = {
39600
+ github: "ghcolors",
39601
+ atom: "atom-dark",
39602
+ "atom-dark": "atom-dark",
39603
+ "atom-light": "atom-light",
39604
+ dracula: "dracula",
39605
+ "one-dark": "one-dark",
39606
+ "one-light": "one-light",
39607
+ nord: "nord",
39608
+ "material-dark": "material-dark",
39609
+ "material-light": "material-light",
39610
+ "solarized-light": "solarizedlight",
39611
+ "solarized-dark": "solarized-dark-atom",
39612
+ okaidia: "okaidia",
39613
+ tomorrow: "tomorrow",
39614
+ coy: "coy",
39615
+ "vsc-dark-plus": "vsc-dark-plus",
39616
+ vs: "vs",
39617
+ ghcolors: "ghcolors",
39618
+ prism: "prism",
39619
+ twilight: "twilight",
39620
+ "duotone-dark": "duotone-dark",
39621
+ "duotone-light": "duotone-light",
39622
+ "night-owl": "night-owl",
39623
+ darcula: "darcula",
39624
+ "gruvbox-dark": "gruvbox-dark",
39625
+ "gruvbox-light": "gruvbox-light"
39626
+ };
39627
+ // 预置的默认主题
39628
+ var DEFAULT_THEMES = {
39562
39629
  dark: prism$1.vscDarkPlus,
39563
39630
  light: prism$1.vs
39564
39631
  };
39632
+ /**
39633
+ * 根据 codeTheme 名称加载对应的 prism 样式
39634
+ */
39635
+ function loadCodeStyle(codeTheme) {
39636
+ // 先查映射表
39637
+ var moduleName = CODE_THEME_MAP[codeTheme] || codeTheme;
39638
+ try {
39639
+ // 使用 require 动态加载 prism 样式模块
39640
+ var styles = require("react-syntax-highlighter/dist/cjs/styles/prism/".concat(moduleName));
39641
+ return styles.default || styles;
39642
+ } catch (_a) {
39643
+ // 加载失败时回退到默认暗色主题
39644
+ return prism$1.vscDarkPlus;
39645
+ }
39646
+ }
39565
39647
  var CodeHighlight = function (_a) {
39566
39648
  var textContent = _a.textContent,
39567
39649
  _b = _a.language,
39568
39650
  language = _b === void 0 ? "txt" : _b,
39569
- darkMode = _a.darkMode;
39570
- var _c = __read(useState(false), 2),
39571
- showCopy = _c[0],
39572
- setShowCopy = _c[1];
39651
+ _c = _a.theme,
39652
+ theme = _c === void 0 ? "dark" : _c,
39653
+ codeTheme = _a.codeTheme;
39654
+ var _d = __read(useState(false), 2),
39655
+ showCopy = _d[0],
39656
+ setShowCopy = _d[1];
39573
39657
  var copyToClipboard = function (text) {
39574
39658
  return __awaiter(void 0, void 0, void 0, function () {
39575
39659
  var textarea;
@@ -39633,6 +39717,11 @@ var CodeHighlight = function (_a) {
39633
39717
  }, Date.now())
39634
39718
  });
39635
39719
  }
39720
+ // 根据 codeTheme / theme 计算最终的代码高亮样式
39721
+ var syntaxStyle = useMemo(function () {
39722
+ if (codeTheme) return loadCodeStyle(codeTheme);
39723
+ return DEFAULT_THEMES[theme] || DEFAULT_THEMES.dark;
39724
+ }, [codeTheme, theme]);
39636
39725
  return /*#__PURE__*/jsxs("div", {
39637
39726
  style: {
39638
39727
  position: "relative"
@@ -39643,7 +39732,7 @@ var CodeHighlight = function (_a) {
39643
39732
  right: "10px",
39644
39733
  top: "5px",
39645
39734
  zIndex: 1,
39646
- background: darkMode ? "#555" : "#333",
39735
+ background: theme === "light" ? "#e8e8e8" : "#555",
39647
39736
  color: "#fff",
39648
39737
  border: "none",
39649
39738
  padding: "4px 8px",
@@ -39663,7 +39752,7 @@ var CodeHighlight = function (_a) {
39663
39752
  },
39664
39753
  children: showCopy ? "点击复制" : "复制"
39665
39754
  }), /*#__PURE__*/jsx(SyntaxHighlighter, {
39666
- style: themes.dark,
39755
+ style: syntaxStyle,
39667
39756
  language: language,
39668
39757
  PreTag: "div",
39669
39758
  children: String(textContent).replace(/\n$/, "")
@@ -39789,44 +39878,48 @@ var AudioComponent = function (_a) {
39789
39878
  }), "\u4F60\u7684\u6D4F\u89C8\u5668\u4E0D\u652F\u6301 audio \u6807\u7B7E"]
39790
39879
  });
39791
39880
  };
39792
- // 代码组件
39793
- var CodeComponent = function (props) {
39794
- var children = props.children,
39795
- className = props.className;
39796
- props.node;
39797
- var rest = __rest(props, ["children", "className", "node"]);
39798
- var match = /language-(\w+)/.exec(className || "");
39799
- String(children).replace(/\n$/, '');
39800
- var extractText = function (children) {
39801
- return React__default.Children.toArray(children).reduce(function (acc, child) {
39802
- if (typeof child === 'string') {
39803
- return acc + child;
39804
- } else if (/*#__PURE__*/React__default.isValidElement(child) && child.props && child.props.children) {
39805
- return acc + extractText(child.props.children);
39881
+ // 代码组件(支持 theme 和 codeTheme 透传)
39882
+ var createCodeComponent = function (theme, codeTheme) {
39883
+ var CodeComponent = function (props) {
39884
+ var children = props.children,
39885
+ className = props.className;
39886
+ props.node;
39887
+ var rest = __rest(props, ["children", "className", "node"]);
39888
+ var match = /language-(\w+)/.exec(className || "");
39889
+ var extractText = function (children) {
39890
+ return React__default.Children.toArray(children).reduce(function (acc, child) {
39891
+ if (typeof child === 'string') {
39892
+ return acc + child;
39893
+ } else if (/*#__PURE__*/React__default.isValidElement(child) && child.props && child.props.children) {
39894
+ return acc + extractText(child.props.children);
39895
+ }
39896
+ return acc;
39897
+ }, '');
39898
+ };
39899
+ var content = extractText(children);
39900
+ // 增强语言检测逻辑,检查内容中是否包含mermaid特征
39901
+ var language = match ? match[1] : "txt";
39902
+ // 如果内容包含mermaid特征且语言未正确识别,则强制设置为mermaid
39903
+ if (!match || match[1] !== "mermaid") {
39904
+ var trimmedContent = content.trim();
39905
+ if (trimmedContent.startsWith('graph') || trimmedContent.startsWith('flowchart') || trimmedContent.startsWith('sequenceDiagram') || trimmedContent.startsWith('gantt') || trimmedContent.startsWith('classDiagram') || trimmedContent.startsWith('stateDiagram') || trimmedContent.startsWith('pie') || trimmedContent.startsWith('erDiagram') || trimmedContent.startsWith('journey') || trimmedContent.startsWith('requirementDiagram') || trimmedContent.startsWith('gitGraph')) {
39906
+ language = "mermaid";
39806
39907
  }
39807
- return acc;
39808
- }, '');
39908
+ }
39909
+ return language !== "txt" ? /*#__PURE__*/jsx(CodeHighlight, {
39910
+ ...rest,
39911
+ language: language,
39912
+ textContent: content,
39913
+ theme: theme,
39914
+ codeTheme: codeTheme,
39915
+ children: content
39916
+ }) : /*#__PURE__*/jsx("code", {
39917
+ className: className,
39918
+ ...props,
39919
+ children: content
39920
+ });
39809
39921
  };
39810
- var content = extractText(children);
39811
- // 增强语言检测逻辑,检查内容中是否包含mermaid特征
39812
- var language = match ? match[1] : "txt";
39813
- // 如果内容包含mermaid特征且语言未正确识别,则强制设置为mermaid
39814
- if (!match || match[1] !== "mermaid") {
39815
- var trimmedContent = content.trim();
39816
- if (trimmedContent.startsWith('graph') || trimmedContent.startsWith('flowchart') || trimmedContent.startsWith('sequenceDiagram') || trimmedContent.startsWith('gantt') || trimmedContent.startsWith('classDiagram') || trimmedContent.startsWith('stateDiagram') || trimmedContent.startsWith('pie') || trimmedContent.startsWith('erDiagram') || trimmedContent.startsWith('journey') || trimmedContent.startsWith('requirementDiagram') || trimmedContent.startsWith('gitGraph')) {
39817
- language = "mermaid";
39818
- }
39819
- }
39820
- return language !== "txt" ? /*#__PURE__*/jsx(CodeHighlight, {
39821
- ...rest,
39822
- language: language,
39823
- textContent: content,
39824
- children: content
39825
- }) : /*#__PURE__*/jsx("code", {
39826
- className: className,
39827
- ...props,
39828
- children: content
39829
- });
39922
+ return CodeComponent;
39830
39923
  };
39831
39924
  // 段落组件
39832
39925
  var PComponent = function (pProps) {
@@ -39854,16 +39947,23 @@ var PreComponent = function (props) {
39854
39947
  ...props
39855
39948
  });
39856
39949
  };
39857
- var BuiltInComponents = {
39858
- _THINK: Think,
39859
- // _TOOL_CALL: ToolCall,
39860
- pre: PreComponent,
39861
- code: CodeComponent,
39862
- p: PComponent,
39863
- a: AComponent,
39864
- video: VideoComponent,
39865
- audio: AudioComponent
39866
- };
39950
+ /**
39951
+ * 创建带主题配置的内置组件集合
39952
+ * @param theme 整体主题 (dark / light / 自定义)
39953
+ * @param codeTheme 代码语法主题 (github / atom / 自定义)
39954
+ */
39955
+ function createBuiltInComponents(theme, codeTheme) {
39956
+ var themedCode = createCodeComponent(theme, codeTheme);
39957
+ return {
39958
+ _THINK: Think,
39959
+ pre: PreComponent,
39960
+ code: themedCode,
39961
+ p: PComponent,
39962
+ a: AComponent,
39963
+ video: VideoComponent,
39964
+ audio: AudioComponent
39965
+ };
39966
+ }
39867
39967
 
39868
39968
  var ErrorBoundary = /** @class */function (_super) {
39869
39969
  __extends(ErrorBoundary, _super);
@@ -59390,15 +59490,9 @@ var FallbackView = /** @class */function (_super) {
59390
59490
  function isEnhancedComponentConfig(value) {
59391
59491
  return typeof value === 'object' && value !== null && 'value' in value && typeof value.value !== 'undefined';
59392
59492
  }
59393
- /**
59394
- * 从组件值中提取实际的组件
59395
- */
59396
59493
  function extractComponent(value) {
59397
59494
  return isEnhancedComponentConfig(value) ? value.value : value;
59398
59495
  }
59399
- /**
59400
- * 将 components 转换为 ComponentHandler 数组
59401
- */
59402
59496
  function convertComponentsToHandlers(components, componentHandlers) {
59403
59497
  var e_1, _a;
59404
59498
  var handlers = [];
@@ -59420,7 +59514,8 @@ function convertComponentsToHandlers(components, componentHandlers) {
59420
59514
  onRenderProcess: config.onRenderProcess,
59421
59515
  onRenderFinished: config.onRenderFinished,
59422
59516
  loader: config.loader,
59423
- label: config.label
59517
+ label: config.label,
59518
+ streamable: config.streamable
59424
59519
  });
59425
59520
  } else {
59426
59521
  handlers.push({
@@ -59450,6 +59545,59 @@ function convertComponentsToHandlers(components, componentHandlers) {
59450
59545
  }
59451
59546
  return handlers;
59452
59547
  }
59548
+ function buildLoaderShellFromParsed(parsedData, allComponentHandlers, layoutProps) {
59549
+ if (!parsedData.length) return null;
59550
+ var nodes = [];
59551
+ var _loop_2 = function (i) {
59552
+ var item = parsedData[i];
59553
+ if (item.type === 'text') {
59554
+ var t = String(item.value || '').trim();
59555
+ if (t) {
59556
+ nodes.push(/*#__PURE__*/React__default.createElement('div', {
59557
+ key: "sync-txt-".concat(i),
59558
+ style: {
59559
+ whiteSpace: 'pre-wrap'
59560
+ }
59561
+ }, t));
59562
+ }
59563
+ return "continue";
59564
+ }
59565
+ if (item.type !== 'component' || item.isComplete === true) return "continue";
59566
+ var handler = allComponentHandlers.find(function (c) {
59567
+ return c.name === item.value;
59568
+ });
59569
+ if (!(handler === null || handler === void 0 ? void 0 : handler.loader)) return "continue";
59570
+ var displayName = handler.label || item.value;
59571
+ nodes.push(/*#__PURE__*/React__default.createElement(ComponentPlaceholder, {
59572
+ key: "sync-loader-".concat(item.value, "-").concat(i),
59573
+ componentName: displayName,
59574
+ loader: handler.loader
59575
+ }));
59576
+ };
59577
+ for (var i = 0; i < parsedData.length; i++) {
59578
+ _loop_2(i);
59579
+ }
59580
+ if (!nodes.length) return null;
59581
+ return /*#__PURE__*/React__default.createElement(MdxLayout, __assign(__assign({}, layoutProps), {
59582
+ children: React__default.createElement.apply(React__default, __spreadArray([React__default.Fragment, null], __read(nodes), false))
59583
+ }));
59584
+ }
59585
+ function parsedStructureSignature(parsedData) {
59586
+ return parsedData.map(function (p) {
59587
+ if (p.type === 'text') return "t:".concat(String(p.value || '').length);
59588
+ return "c:".concat(p.value, ":").concat(p.isComplete === true ? '1' : '0');
59589
+ }).join('|');
59590
+ }
59591
+ function hasPendingLoaderComponents(parsedData, handlers) {
59592
+ return parsedData.some(function (item) {
59593
+ if (item.type !== 'component' || item.isComplete === true) return false;
59594
+ var handler = handlers.find(function (h) {
59595
+ return h.name === item.value;
59596
+ });
59597
+ if (handler === null || handler === void 0 ? void 0 : handler.streamable) return false;
59598
+ return Boolean(handler === null || handler === void 0 ? void 0 : handler.loader);
59599
+ });
59600
+ }
59453
59601
  function ReactAIRenderer(_a) {
59454
59602
  var _this = this;
59455
59603
  var content = _a.content,
@@ -59462,14 +59610,19 @@ function ReactAIRenderer(_a) {
59462
59610
  componentHandlers = _d === void 0 ? [] : _d,
59463
59611
  useGithubStyles = _a.useGithubStyles,
59464
59612
  mdxLayoutClassName = _a.mdxLayoutClassName,
59465
- mdxLayoutStyle = _a.mdxLayoutStyle;
59466
- var _e = __read(useState(null), 2),
59467
- component = _e[0],
59468
- setComponent = _e[1];
59613
+ mdxLayoutStyle = _a.mdxLayoutStyle,
59614
+ _e = _a.theme,
59615
+ theme = _e === void 0 ? "dark" : _e,
59616
+ codeTheme = _a.codeTheme;
59617
+ var _f = __read(useState(null), 2),
59618
+ component = _f[0],
59619
+ setComponent = _f[1];
59469
59620
  var fallbackErrorRef = useRef({
59470
59621
  hasError: false
59471
59622
  });
59472
59623
  var completedComponentsCacheRef = useRef(new Map());
59624
+ var parserRef = useRef(null);
59625
+ var lastLoaderSigRef = useRef('');
59473
59626
  var isBrowser = typeof window !== 'undefined';
59474
59627
  content = content || children || '';
59475
59628
  var normalizedComponents = components ? Object.fromEntries(Object.entries(components).filter(function (_a) {
@@ -59483,11 +59636,26 @@ function ReactAIRenderer(_a) {
59483
59636
  value = _b[1];
59484
59637
  return [name, extractComponent(value)];
59485
59638
  })) : {};
59486
- var allComponents = __assign(__assign({}, BuiltInComponents), normalizedComponents);
59639
+ // 根据 theme / codeTheme 创建带主题配置的内置组件
59640
+ var themedBuiltInComponents = useMemo(function () {
59641
+ return createBuiltInComponents(theme, codeTheme);
59642
+ }, [theme, codeTheme]);
59643
+ var allComponents = __assign(__assign({}, themedBuiltInComponents), normalizedComponents);
59487
59644
  var allComponentHandlers = __spreadArray(__spreadArray([], __read(components ? convertComponentsToHandlers(components, componentHandlers) : []), false), __read(componentHandlers), false);
59488
- var parser = new MDXStreamingParser(allComponentHandlers);
59645
+ if (!parserRef.current) {
59646
+ parserRef.current = new MDXStreamingParser(allComponentHandlers);
59647
+ }
59648
+ var parser = parserRef.current;
59489
59649
  var mdxContent = content || '';
59490
- // FallbackView 错误状态变化时的回调
59650
+ var handlersRef = useRef(allComponentHandlers);
59651
+ handlersRef.current = allComponentHandlers;
59652
+ var layoutProps = useMemo(function () {
59653
+ return {
59654
+ useGithubStyles: useGithubStyles,
59655
+ className: mdxLayoutClassName,
59656
+ style: mdxLayoutStyle
59657
+ };
59658
+ }, [useGithubStyles, mdxLayoutClassName, mdxLayoutStyle]);
59491
59659
  var handleFallbackErrorChange = function (hasError, error) {
59492
59660
  fallbackErrorRef.current = {
59493
59661
  hasError: hasError,
@@ -59496,17 +59664,32 @@ function ReactAIRenderer(_a) {
59496
59664
  };
59497
59665
  useEffect(function () {
59498
59666
  if (!isBrowser) return;
59667
+ var cancelled = false;
59499
59668
  var parseMDX = function () {
59500
59669
  return __awaiter(_this, void 0, void 0, function () {
59501
- var ThinkComponent, ResultComponent, protectedContent, _a, thinkContent, resultContent, parsedData, parsedComponents, currentComponentCount, cacheKeys, cacheKeys_1, cacheKeys_1_1, key, indexMatch, index, finalComponent, fallbackComponent, _loop_2, i, MDXComponent, parsedDataLength, lastItem;
59670
+ var protectedContent, _a, thinkContent, resultContent, parsedData_1, loaderSig, shell, ThinkComponent, ResultComponent, parsedData, parsedComponents, currentComponentCount, cacheKeys, cacheKeys_1, cacheKeys_1_1, key, indexMatch, index, finalComponent, fallbackComponent, _loop_3, i, MDXComponent, parsedDataLength, lastItem;
59502
59671
  var e_2, _b;
59503
59672
  return __generator(this, function (_c) {
59504
59673
  switch (_c.label) {
59505
59674
  case 0:
59506
- ThinkComponent = null;
59507
- ResultComponent = null;
59508
59675
  protectedContent = protectSpecialSyntax(mdxContent);
59509
59676
  _a = remarkThinkUpdate(protectedContent), thinkContent = _a.thinkContent, resultContent = _a.resultContent;
59677
+ if (resultContent) {
59678
+ resultContent = fixMDXContent(resultContent);
59679
+ parsedData_1 = parser.parse('magic', resultContent);
59680
+ loaderSig = parsedStructureSignature(parsedData_1);
59681
+ if (hasPendingLoaderComponents(parsedData_1, handlersRef.current)) {
59682
+ if (loaderSig !== lastLoaderSigRef.current) {
59683
+ lastLoaderSigRef.current = loaderSig;
59684
+ shell = buildLoaderShellFromParsed(parsedData_1, handlersRef.current, layoutProps);
59685
+ if (shell && !cancelled) setComponent(shell);
59686
+ }
59687
+ return [2 /*return*/];
59688
+ }
59689
+ lastLoaderSigRef.current = '';
59690
+ }
59691
+ ThinkComponent = null;
59692
+ ResultComponent = null;
59510
59693
  if (!thinkContent) return [3 /*break*/, 2];
59511
59694
  return [4 /*yield*/, renderMdx(thinkContent, scope, allComponents)];
59512
59695
  case 1:
@@ -59515,7 +59698,6 @@ function ReactAIRenderer(_a) {
59515
59698
  case 2:
59516
59699
  parsedData = [];
59517
59700
  if (!resultContent) return [3 /*break*/, 8];
59518
- resultContent = fixMDXContent(resultContent);
59519
59701
  parsedData = parser.parse('magic', resultContent);
59520
59702
  return [4 /*yield*/, Promise.all(parsedData.map(function (item) {
59521
59703
  return parseComponentRecursively(allComponentHandlers, item, scope);
@@ -59531,7 +59713,6 @@ function ReactAIRenderer(_a) {
59531
59713
  if (indexMatch) {
59532
59714
  index = parseInt(indexMatch[1], 10);
59533
59715
  if (index >= currentComponentCount) {
59534
- // 如果索引超出当前组件数量,删除缓存
59535
59716
  completedComponentsCacheRef.current.delete(key);
59536
59717
  }
59537
59718
  }
@@ -59549,8 +59730,8 @@ function ReactAIRenderer(_a) {
59549
59730
  }
59550
59731
  finalComponent = [];
59551
59732
  fallbackComponent = [];
59552
- _loop_2 = function (i) {
59553
- var item, currentParsedItem, _result, placeholderForFallback, componentNameMatch, componentName_1, componentHandler, displayName, cacheKey;
59733
+ _loop_3 = function (i) {
59734
+ var item, currentParsedItem, _result, placeholderForFallback, componentNameMatch, componentName_1, componentHandler, displayName, cacheKey, cacheKey;
59554
59735
  return __generator(this, function (_d) {
59555
59736
  switch (_d.label) {
59556
59737
  case 0:
@@ -59563,10 +59744,10 @@ function ReactAIRenderer(_a) {
59563
59744
  case 1:
59564
59745
  _result = _d.sent();
59565
59746
  finalComponent.push(_result);
59566
- return [3 /*break*/, 11];
59747
+ return [3 /*break*/, 14];
59567
59748
  case 2:
59568
59749
  componentNameMatch = item.value.match(/<([A-Z][A-Za-z0-9]*)/);
59569
- if (!componentNameMatch) return [3 /*break*/, 9];
59750
+ if (!componentNameMatch) return [3 /*break*/, 12];
59570
59751
  componentName_1 = componentNameMatch[1];
59571
59752
  componentHandler = allComponentHandlers.find(function (c) {
59572
59753
  return c.name === componentName_1;
@@ -59580,18 +59761,22 @@ function ReactAIRenderer(_a) {
59580
59761
  loader: componentHandler === null || componentHandler === void 0 ? void 0 : componentHandler.loader,
59581
59762
  key: "fallback-loader-".concat(componentName_1)
59582
59763
  });
59583
- if (!(currentParsedItem.isComplete === true || !(componentHandler === null || componentHandler === void 0 ? void 0 : componentHandler.loader))) return [3 /*break*/, 6];
59764
+ if (!(currentParsedItem.isComplete === true || !(componentHandler === null || componentHandler === void 0 ? void 0 : componentHandler.loader))) return [3 /*break*/, 7];
59584
59765
  cacheKey = "mdx-component-".concat(componentName_1, "-").concat(i);
59585
59766
  if (!completedComponentsCacheRef.current.has(cacheKey)) return [3 /*break*/, 3];
59586
- // 使用缓存的组件
59587
59767
  _result = completedComponentsCacheRef.current.get(cacheKey);
59588
- return [3 /*break*/, 5];
59768
+ return [3 /*break*/, 6];
59589
59769
  case 3:
59590
- return [4 /*yield*/, renderMdx(item.value, scope, allComponents)];
59770
+ if (!(componentHandler === null || componentHandler === void 0 ? void 0 : componentHandler.streamable)) return [3 /*break*/, 4];
59771
+ _result = /*#__PURE__*/React__default.createElement(componentHandler.component, __assign(__assign({}, currentParsedItem.props), {
59772
+ key: cacheKey
59773
+ }));
59774
+ completedComponentsCacheRef.current.set(cacheKey, _result);
59775
+ return [3 /*break*/, 6];
59591
59776
  case 4:
59592
- // 缓存不存在,调用 renderMdx 并存入缓存
59777
+ return [4 /*yield*/, renderMdx(item.value, scope, allComponents)];
59778
+ case 5:
59593
59779
  _result = _d.sent();
59594
- // 为组件设置 key,确保 React 能正确识别
59595
59780
  if (/*#__PURE__*/React__default.isValidElement(_result)) {
59596
59781
  _result = /*#__PURE__*/React__default.cloneElement(_result, {
59597
59782
  key: cacheKey
@@ -59601,30 +59786,38 @@ function ReactAIRenderer(_a) {
59601
59786
  key: cacheKey
59602
59787
  }, _result);
59603
59788
  }
59604
- // 存入缓存
59605
59789
  completedComponentsCacheRef.current.set(cacheKey, _result);
59606
- _d.label = 5;
59607
- case 5:
59608
- finalComponent.push(_result);
59609
- return [3 /*break*/, 8];
59790
+ _d.label = 6;
59610
59791
  case 6:
59611
- return [4 /*yield*/, renderMdx(item.value, scope, allComponents)];
59792
+ finalComponent.push(_result);
59793
+ return [3 /*break*/, 11];
59612
59794
  case 7:
59613
- // 组件未完成,正常渲染
59614
- _result = _d.sent();
59615
- finalComponent.push(placeholderForFallback);
59616
- _d.label = 8;
59795
+ if (!(componentHandler === null || componentHandler === void 0 ? void 0 : componentHandler.streamable)) return [3 /*break*/, 8];
59796
+ cacheKey = "mdx-component-".concat(componentName_1, "-").concat(i);
59797
+ _result = /*#__PURE__*/React__default.createElement(componentHandler.component, __assign(__assign({}, currentParsedItem.props), {
59798
+ key: cacheKey
59799
+ }));
59800
+ finalComponent.push(_result);
59801
+ return [3 /*break*/, 11];
59617
59802
  case 8:
59803
+ if (!placeholderForFallback) return [3 /*break*/, 9];
59804
+ finalComponent.push(placeholderForFallback);
59618
59805
  return [3 /*break*/, 11];
59619
59806
  case 9:
59620
59807
  return [4 /*yield*/, renderMdx(item.value, scope, allComponents)];
59621
59808
  case 10:
59622
- // 没有匹配到组件名,正常渲染
59623
59809
  _result = _d.sent();
59624
59810
  finalComponent.push(_result);
59625
59811
  _d.label = 11;
59626
59812
  case 11:
59627
- // fallbackComponent 应该是 finalComponent 的前 i 个元素 + 当前 item 的 loader
59813
+ return [3 /*break*/, 14];
59814
+ case 12:
59815
+ return [4 /*yield*/, renderMdx(item.value, scope, allComponents)];
59816
+ case 13:
59817
+ _result = _d.sent();
59818
+ finalComponent.push(_result);
59819
+ _d.label = 14;
59820
+ case 14:
59628
59821
  fallbackComponent.length = 0;
59629
59822
  fallbackComponent.push.apply(fallbackComponent, __spreadArray([], __read(finalComponent.slice(0, i)), false));
59630
59823
  if (placeholderForFallback) {
@@ -59638,7 +59831,7 @@ function ReactAIRenderer(_a) {
59638
59831
  _c.label = 4;
59639
59832
  case 4:
59640
59833
  if (!(i < parsedComponents.length)) return [3 /*break*/, 7];
59641
- return [5 /*yield**/, _loop_2(i)];
59834
+ return [5 /*yield**/, _loop_3(i)];
59642
59835
  case 5:
59643
59836
  _c.sent();
59644
59837
  _c.label = 6;
@@ -59661,13 +59854,13 @@ function ReactAIRenderer(_a) {
59661
59854
  MDXComponent = /*#__PURE__*/jsxs(React__default.Fragment, {
59662
59855
  children: [ThinkComponent, ResultComponent]
59663
59856
  });
59857
+ if (cancelled) return [2 /*return*/];
59664
59858
  if (!fallbackErrorRef.current.hasError) {
59665
59859
  setComponent(MDXComponent);
59666
59860
  } else {
59667
59861
  parsedDataLength = parsedData.length;
59668
59862
  if (parsedDataLength > 0) {
59669
59863
  lastItem = parsedData[parsedDataLength - 1];
59670
- // 如果最后一个组件是完整的,强制更新
59671
59864
  if (lastItem.isComplete === true) {
59672
59865
  setComponent(MDXComponent);
59673
59866
  } else if (lastItem.type === 'text') {
@@ -59681,7 +59874,10 @@ function ReactAIRenderer(_a) {
59681
59874
  });
59682
59875
  };
59683
59876
  parseMDX();
59684
- }, [content]);
59877
+ return function () {
59878
+ cancelled = true;
59879
+ };
59880
+ }, [content, theme, codeTheme]);
59685
59881
  if (!isBrowser) {
59686
59882
  return null;
59687
59883
  }