@ant-design/agentic-ui 2.16.0 → 2.16.1
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/MarkdownEditor/editor/elements/Code.js +11 -6
- package/dist/MarkdownEditor/editor/elements/Table/ReadonlyTableComponent.js +15 -3
- package/dist/MarkdownEditor/editor/elements/Table/SimpleTable.js +17 -2
- package/dist/MarkdownEditor/editor/elements/Table/Table.js +131 -5
- package/dist/MarkdownEditor/editor/parser/parserMarkdownToSlateNode.d.ts +100 -1
- package/dist/MarkdownEditor/editor/parser/parserMarkdownToSlateNode.js +781 -240
- package/dist/MarkdownEditor/editor/types/Table.d.ts +1 -0
- package/dist/MarkdownEditor/editor/utils/findMatchingClose.d.ts +36 -0
- package/dist/MarkdownEditor/editor/utils/findMatchingClose.js +158 -0
- package/dist/MarkdownEditor/editor/utils/markdownToHtml.d.ts +41 -2
- package/dist/MarkdownEditor/editor/utils/markdownToHtml.js +159 -7
- package/dist/Plugins/chart/AreaChart/index.d.ts +12 -0
- package/dist/Plugins/chart/AreaChart/index.js +14 -188
- package/dist/Plugins/chart/BarChart/index.d.ts +2 -0
- package/dist/Plugins/chart/BarChart/index.js +3 -12
- package/dist/Plugins/chart/ChartMark/Container.js +5 -2
- package/dist/Plugins/chart/ChartRender.d.ts +1 -0
- package/dist/Plugins/chart/ChartRender.js +104 -43
- package/dist/Plugins/chart/DonutChart/index.js +4 -2
- package/dist/Plugins/chart/DonutChart/types.d.ts +2 -0
- package/dist/Plugins/chart/FunnelChart/index.d.ts +2 -0
- package/dist/Plugins/chart/FunnelChart/index.js +4 -2
- package/dist/Plugins/chart/LineChart/index.d.ts +2 -0
- package/dist/Plugins/chart/LineChart/index.js +17 -162
- package/dist/Plugins/chart/RadarChart/index.d.ts +2 -0
- package/dist/Plugins/chart/RadarChart/index.js +8 -4
- package/dist/Plugins/chart/ScatterChart/index.d.ts +2 -0
- package/dist/Plugins/chart/ScatterChart/index.js +8 -4
- package/dist/Plugins/chart/components/ChartContainer/ChartContainer.d.ts +1 -0
- package/dist/Plugins/chart/components/ChartFilter/ChartFilter.d.ts +1 -1
- package/dist/Plugins/chart/components/ChartFilter/ChartFilter.js +210 -16
- package/dist/Plugins/chart/components/ChartToolBar/ChartToolBar.d.ts +2 -0
- package/dist/Plugins/chart/components/ChartToolBar/ChartToolBar.js +9 -2
- package/dist/Plugins/chart/components/ChartToolBar/style.js +3 -1
- package/dist/Plugins/chart/hooks/index.d.ts +10 -0
- package/dist/Plugins/chart/hooks/index.js +8 -0
- package/dist/Plugins/chart/hooks/useChartDataFilter.d.ts +46 -0
- package/dist/Plugins/chart/hooks/useChartDataFilter.js +182 -0
- package/dist/Plugins/chart/hooks/useChartStatistics.d.ts +17 -0
- package/dist/Plugins/chart/hooks/useChartStatistics.js +25 -0
- package/dist/Plugins/chart/hooks/useChartTheme.d.ts +20 -0
- package/dist/Plugins/chart/hooks/useChartTheme.js +30 -0
- package/dist/Plugins/chart/hooks/useResponsiveSize.d.ts +23 -0
- package/dist/Plugins/chart/hooks/useResponsiveSize.js +94 -0
- package/dist/Plugins/chart/index.js +92 -8
- package/dist/Plugins/chart/utils/registerChart.d.ts +35 -0
- package/dist/Plugins/chart/utils/registerChart.js +54 -0
- package/dist/Plugins/chart/utils.d.ts +19 -0
- package/dist/Plugins/chart/utils.js +27 -0
- package/dist/Plugins/code/components/CodeRenderer.js +53 -2
- package/dist/Plugins/code/components/CodeToolbar.js +22 -3
- package/dist/Plugins/mermaid/Mermaid.js +66 -66
- package/package.json +1 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 注册 Chart.js 基础组件
|
|
3
|
+
*
|
|
4
|
+
* 用于注册图表所需的基础 Chart.js 组件,包括坐标轴、图例、工具提示等。
|
|
5
|
+
* 使用单例模式确保只注册一次。
|
|
6
|
+
*
|
|
7
|
+
* @param {string[]} components - 要注册的组件名称数组
|
|
8
|
+
* @param {Function} registerFn - 注册函数,接收 ChartJS 作为参数
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* registerChartComponents('line-chart', () => {
|
|
13
|
+
* ChartJS.register(
|
|
14
|
+
* CategoryScale,
|
|
15
|
+
* LinearScale,
|
|
16
|
+
* PointElement,
|
|
17
|
+
* LineElement,
|
|
18
|
+
* Filler,
|
|
19
|
+
* Tooltip,
|
|
20
|
+
* Legend,
|
|
21
|
+
* );
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @since 1.0.0
|
|
26
|
+
*/
|
|
27
|
+
export declare const registerChartComponents: (componentName: string, registerFn: () => void) => void;
|
|
28
|
+
/**
|
|
29
|
+
* 注册折线图/面积图所需的组件
|
|
30
|
+
*/
|
|
31
|
+
export declare const registerLineChartComponents: () => void;
|
|
32
|
+
/**
|
|
33
|
+
* 注册柱状图所需的组件
|
|
34
|
+
*/
|
|
35
|
+
export declare const registerBarChartComponents: () => void;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { BarElement, CategoryScale, Chart as ChartJS, Filler, Legend, LinearScale, LineElement, PointElement, Tooltip } from "chart.js";
|
|
2
|
+
/**
|
|
3
|
+
* Chart.js 组件注册状态映射
|
|
4
|
+
* 用于跟踪哪些 Chart.js 组件已经被注册,避免重复注册
|
|
5
|
+
*/ var registeredComponents = new Set();
|
|
6
|
+
/**
|
|
7
|
+
* 注册 Chart.js 基础组件
|
|
8
|
+
*
|
|
9
|
+
* 用于注册图表所需的基础 Chart.js 组件,包括坐标轴、图例、工具提示等。
|
|
10
|
+
* 使用单例模式确保只注册一次。
|
|
11
|
+
*
|
|
12
|
+
* @param {string[]} components - 要注册的组件名称数组
|
|
13
|
+
* @param {Function} registerFn - 注册函数,接收 ChartJS 作为参数
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* registerChartComponents('line-chart', () => {
|
|
18
|
+
* ChartJS.register(
|
|
19
|
+
* CategoryScale,
|
|
20
|
+
* LinearScale,
|
|
21
|
+
* PointElement,
|
|
22
|
+
* LineElement,
|
|
23
|
+
* Filler,
|
|
24
|
+
* Tooltip,
|
|
25
|
+
* Legend,
|
|
26
|
+
* );
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @since 1.0.0
|
|
31
|
+
*/ export var registerChartComponents = function(componentName, registerFn) {
|
|
32
|
+
if (registeredComponents.has(componentName)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (typeof window === 'undefined') {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
registerFn();
|
|
39
|
+
registeredComponents.add(componentName);
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* 注册折线图/面积图所需的组件
|
|
43
|
+
*/ export var registerLineChartComponents = function() {
|
|
44
|
+
registerChartComponents('line-chart', function() {
|
|
45
|
+
ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Filler, Tooltip, Legend);
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* 注册柱状图所需的组件
|
|
50
|
+
*/ export var registerBarChartComponents = function() {
|
|
51
|
+
registerChartComponents('bar-chart', function() {
|
|
52
|
+
ChartJS.register(CategoryScale, LinearScale, BarElement, Tooltip, Legend);
|
|
53
|
+
});
|
|
54
|
+
};
|
|
@@ -286,3 +286,22 @@ export declare const getDataHash: (data: any[]) => string;
|
|
|
286
286
|
* @since 1.0.0
|
|
287
287
|
*/
|
|
288
288
|
export declare const isConfigEqual: (config1: any, config2: any) => boolean;
|
|
289
|
+
/**
|
|
290
|
+
* 将十六进制颜色转换为带透明度的 RGBA 字符串
|
|
291
|
+
*
|
|
292
|
+
* 支持3位和6位十六进制颜色格式,并添加透明度。
|
|
293
|
+
*
|
|
294
|
+
* @param {string} hex - 十六进制颜色值(如 '#ff0000' 或 '#f00')
|
|
295
|
+
* @param {number} alpha - 透明度值(0-1之间)
|
|
296
|
+
* @returns {string} RGBA 颜色字符串
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* ```typescript
|
|
300
|
+
* hexToRgba('#ff0000', 0.5); // 'rgba(255, 0, 0, 0.5)'
|
|
301
|
+
* hexToRgba('#f00', 0.8); // 'rgba(255, 0, 0, 0.8)'
|
|
302
|
+
* ```
|
|
303
|
+
*
|
|
304
|
+
* @since 1.0.0
|
|
305
|
+
*/
|
|
306
|
+
export declare const hexToRgba: (hex: string, alpha: number) => string;
|
|
307
|
+
export { registerChartComponents, registerLineChartComponents, registerBarChartComponents, } from './utils/registerChart';
|
|
@@ -436,3 +436,30 @@ var intl = new Intl.NumberFormat('en-US', {
|
|
|
436
436
|
}
|
|
437
437
|
return true;
|
|
438
438
|
};
|
|
439
|
+
/**
|
|
440
|
+
* 将十六进制颜色转换为带透明度的 RGBA 字符串
|
|
441
|
+
*
|
|
442
|
+
* 支持3位和6位十六进制颜色格式,并添加透明度。
|
|
443
|
+
*
|
|
444
|
+
* @param {string} hex - 十六进制颜色值(如 '#ff0000' 或 '#f00')
|
|
445
|
+
* @param {number} alpha - 透明度值(0-1之间)
|
|
446
|
+
* @returns {string} RGBA 颜色字符串
|
|
447
|
+
*
|
|
448
|
+
* @example
|
|
449
|
+
* ```typescript
|
|
450
|
+
* hexToRgba('#ff0000', 0.5); // 'rgba(255, 0, 0, 0.5)'
|
|
451
|
+
* hexToRgba('#f00', 0.8); // 'rgba(255, 0, 0, 0.8)'
|
|
452
|
+
* ```
|
|
453
|
+
*
|
|
454
|
+
* @since 1.0.0
|
|
455
|
+
*/ export var hexToRgba = function(hex, alpha) {
|
|
456
|
+
var sanitized = hex.replace('#', '');
|
|
457
|
+
var isShort = sanitized.length === 3;
|
|
458
|
+
var r = parseInt(isShort ? sanitized[0] + sanitized[0] : sanitized.slice(0, 2), 16);
|
|
459
|
+
var g = parseInt(isShort ? sanitized[1] + sanitized[1] : sanitized.slice(2, 4), 16);
|
|
460
|
+
var b = parseInt(isShort ? sanitized[2] + sanitized[2] : sanitized.slice(4, 6), 16);
|
|
461
|
+
var a = Math.max(0, Math.min(1, alpha));
|
|
462
|
+
return "rgba(".concat(r, ", ").concat(g, ", ").concat(b, ", ").concat(a, ")");
|
|
463
|
+
};
|
|
464
|
+
// 导出 Chart.js 注册相关函数
|
|
465
|
+
export { registerChartComponents, registerLineChartComponents, registerBarChartComponents } from "./utils/registerChart";
|
|
@@ -64,6 +64,30 @@ function _object_spread(target) {
|
|
|
64
64
|
}
|
|
65
65
|
return target;
|
|
66
66
|
}
|
|
67
|
+
function ownKeys(object, enumerableOnly) {
|
|
68
|
+
var keys = Object.keys(object);
|
|
69
|
+
if (Object.getOwnPropertySymbols) {
|
|
70
|
+
var symbols = Object.getOwnPropertySymbols(object);
|
|
71
|
+
if (enumerableOnly) {
|
|
72
|
+
symbols = symbols.filter(function(sym) {
|
|
73
|
+
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
keys.push.apply(keys, symbols);
|
|
77
|
+
}
|
|
78
|
+
return keys;
|
|
79
|
+
}
|
|
80
|
+
function _object_spread_props(target, source) {
|
|
81
|
+
source = source != null ? source : {};
|
|
82
|
+
if (Object.getOwnPropertyDescriptors) {
|
|
83
|
+
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
|
84
|
+
} else {
|
|
85
|
+
ownKeys(Object(source)).forEach(function(key) {
|
|
86
|
+
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return target;
|
|
90
|
+
}
|
|
67
91
|
function _sliced_to_array(arr, i) {
|
|
68
92
|
return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
|
|
69
93
|
}
|
|
@@ -76,7 +100,7 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
76
100
|
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
|
|
77
101
|
}
|
|
78
102
|
import { ConfigProvider, theme as antdTheme } from "antd";
|
|
79
|
-
import React, { useMemo, useState } from "react";
|
|
103
|
+
import React, { useEffect, useMemo, useState } from "react";
|
|
80
104
|
import { MarkdownEditor } from "../../../MarkdownEditor";
|
|
81
105
|
import { useEditorStore } from "../../../MarkdownEditor/editor/store";
|
|
82
106
|
import { useCodeEditorState, useRenderConditions, useToolbarConfig } from "../hooks";
|
|
@@ -94,7 +118,7 @@ import { AceEditor, AceEditorContainer, CodeContainer, CodeToolbar, HtmlPreview,
|
|
|
94
118
|
* - 响应式布局适配
|
|
95
119
|
* - 支持代码框选中状态管理
|
|
96
120
|
*/ export function CodeRenderer(props) {
|
|
97
|
-
var _editorProps_codeProps;
|
|
121
|
+
var _props_element_otherProps, _props_element, _props_element_otherProps1, _props_element1, _editorProps_codeProps;
|
|
98
122
|
var _useEditorStore = useEditorStore(), editorProps = _useEditorStore.editorProps, readonly = _useEditorStore.readonly;
|
|
99
123
|
// 使用状态管理Hook
|
|
100
124
|
var _useCodeEditorState = useCodeEditorState(props.element), state = _useCodeEditorState.state, update = _useCodeEditorState.update, path = _useCodeEditorState.path, handleCloseClick = _useCodeEditorState.handleCloseClick, handleHtmlPreviewClose = _useCodeEditorState.handleHtmlPreviewClose, handleShowBorderChange = _useCodeEditorState.handleShowBorderChange, handleHideChange = _useCodeEditorState.handleHideChange;
|
|
@@ -133,6 +157,33 @@ import { AceEditor, AceEditorContainer, CodeContainer, CodeToolbar, HtmlPreview,
|
|
|
133
157
|
onViewModeToggle: handleViewModeToggle,
|
|
134
158
|
viewMode: viewMode
|
|
135
159
|
}).toolbarProps;
|
|
160
|
+
// 检查代码块是否未闭合
|
|
161
|
+
var isUnclosed = ((_props_element = props.element) === null || _props_element === void 0 ? void 0 : (_props_element_otherProps = _props_element.otherProps) === null || _props_element_otherProps === void 0 ? void 0 : _props_element_otherProps.finish) === false;
|
|
162
|
+
// 5 秒超时机制:如果代码块未闭合,5 秒后自动设置为完成
|
|
163
|
+
useEffect(function() {
|
|
164
|
+
if (isUnclosed && !readonly) {
|
|
165
|
+
var timer = setTimeout(function() {
|
|
166
|
+
var _props_element_otherProps, _props_element;
|
|
167
|
+
// 检查 finish 是否仍然是 false(可能已经被其他逻辑更新)
|
|
168
|
+
if (((_props_element = props.element) === null || _props_element === void 0 ? void 0 : (_props_element_otherProps = _props_element.otherProps) === null || _props_element_otherProps === void 0 ? void 0 : _props_element_otherProps.finish) === false) {
|
|
169
|
+
var _props_element1;
|
|
170
|
+
update({
|
|
171
|
+
otherProps: _object_spread_props(_object_spread({}, (_props_element1 = props.element) === null || _props_element1 === void 0 ? void 0 : _props_element1.otherProps), {
|
|
172
|
+
finish: true
|
|
173
|
+
})
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}, 5000); // 5 秒超时
|
|
177
|
+
return function() {
|
|
178
|
+
clearTimeout(timer);
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
}, [
|
|
182
|
+
isUnclosed,
|
|
183
|
+
readonly,
|
|
184
|
+
(_props_element1 = props.element) === null || _props_element1 === void 0 ? void 0 : (_props_element_otherProps1 = _props_element1.otherProps) === null || _props_element_otherProps1 === void 0 ? void 0 : _props_element_otherProps1.finish,
|
|
185
|
+
update
|
|
186
|
+
]);
|
|
136
187
|
// 渲染组件
|
|
137
188
|
return useMemo(function() {
|
|
138
189
|
// 隐藏配置型 HTML 代码块
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
import { ChevronsUpDown, Copy, Moon } from "@sofa-design/icons";
|
|
7
7
|
import { message, Segmented } from "antd";
|
|
8
8
|
import copy from "copy-to-clipboard";
|
|
9
|
-
import React, { useContext } from "react";
|
|
9
|
+
import React, { useContext, useMemo } from "react";
|
|
10
10
|
import { ActionIconBox } from "../../../Components/ActionIconBox";
|
|
11
|
+
import { Loading } from "../../../Components/Loading";
|
|
11
12
|
import { I18nContext } from "../../../I18n";
|
|
12
13
|
import { langIconMap } from "../langIconMap";
|
|
13
14
|
import { LanguageSelector } from "./LanguageSelector";
|
|
@@ -40,10 +41,17 @@ import { LoadImage } from "./LoadImage";
|
|
|
40
41
|
* />
|
|
41
42
|
* ```
|
|
42
43
|
*/ export var CodeToolbar = function(props) {
|
|
43
|
-
var _element_language, _element_language1, _i18n_locale, _i18n_locale1;
|
|
44
|
+
var _element_otherProps, _element_language, _element_language1, _i18n_locale, _i18n_locale1;
|
|
44
45
|
// 获取国际化上下文
|
|
45
46
|
var i18n = useContext(I18nContext);
|
|
46
47
|
var element = props.element, readonly = props.readonly, onCloseClick = props.onCloseClick, languageSelectorProps = props.languageSelectorProps, onViewModeToggle = props.onViewModeToggle, theme = props.theme, isExpanded = props.isExpanded, onExpandToggle = props.onExpandToggle, setTheme = props.setTheme, _props_viewMode = props.viewMode, viewMode = _props_viewMode === void 0 ? 'code' : _props_viewMode;
|
|
48
|
+
// 检查代码块是否未闭合 - 使用 useMemo 确保正确响应变化
|
|
49
|
+
var isUnclosed = useMemo(function() {
|
|
50
|
+
var _element_otherProps;
|
|
51
|
+
return (element === null || element === void 0 ? void 0 : (_element_otherProps = element.otherProps) === null || _element_otherProps === void 0 ? void 0 : _element_otherProps.finish) === false;
|
|
52
|
+
}, [
|
|
53
|
+
element === null || element === void 0 ? void 0 : (_element_otherProps = element.otherProps) === null || _element_otherProps === void 0 ? void 0 : _element_otherProps.finish
|
|
54
|
+
]);
|
|
47
55
|
return /*#__PURE__*/ React.createElement("div", {
|
|
48
56
|
"data-testid": "code-toolbar",
|
|
49
57
|
contentEditable: false,
|
|
@@ -72,6 +80,12 @@ import { LoadImage } from "./LoadImage";
|
|
|
72
80
|
userSelect: 'none',
|
|
73
81
|
borderBottom: isExpanded ? theme === 'chaos' ? '1px solid #161616' : '1px solid var(--color-gray-border-light)' : 'none'
|
|
74
82
|
}
|
|
83
|
+
}, /*#__PURE__*/ React.createElement("div", {
|
|
84
|
+
style: {
|
|
85
|
+
display: 'flex',
|
|
86
|
+
alignItems: 'center',
|
|
87
|
+
gap: 8
|
|
88
|
+
}
|
|
75
89
|
}, readonly ? // 只读模式:仅显示当前语言信息
|
|
76
90
|
/*#__PURE__*/ React.createElement("div", {
|
|
77
91
|
style: {
|
|
@@ -98,7 +112,12 @@ import { LoadImage } from "./LoadImage";
|
|
|
98
112
|
},
|
|
99
113
|
src: langIconMap.get(((_element_language1 = element.language) === null || _element_language1 === void 0 ? void 0 : _element_language1.toLowerCase()) || '')
|
|
100
114
|
})), /*#__PURE__*/ React.createElement("div", null, element.language ? /*#__PURE__*/ React.createElement("span", null, element.katex ? 'Formula' : element.language === 'html' && element.render ? 'Html Renderer' : element.language) : /*#__PURE__*/ React.createElement("span", null, 'plain text'))) : // 非只读模式:显示语言选择器
|
|
101
|
-
/*#__PURE__*/ React.createElement(LanguageSelector, languageSelectorProps), /*#__PURE__*/ React.createElement(
|
|
115
|
+
/*#__PURE__*/ React.createElement(LanguageSelector, languageSelectorProps), isUnclosed && /*#__PURE__*/ React.createElement(Loading, {
|
|
116
|
+
style: {
|
|
117
|
+
fontSize: '14px',
|
|
118
|
+
flexShrink: 0
|
|
119
|
+
}
|
|
120
|
+
})), /*#__PURE__*/ React.createElement("div", {
|
|
102
121
|
style: {
|
|
103
122
|
display: 'flex',
|
|
104
123
|
gap: 5,
|
|
@@ -171,6 +171,7 @@ function _ts_generator(thisArg, body) {
|
|
|
171
171
|
import React, { lazy, Suspense, useEffect, useMemo, useRef } from "react";
|
|
172
172
|
import { useGetSetState } from "react-use";
|
|
173
173
|
import { useIntersectionOnce } from "../../Hooks/useIntersectionOnce";
|
|
174
|
+
import { isCodeBlockLikelyComplete } from "../../MarkdownEditor/editor/utils/findMatchingClose";
|
|
174
175
|
var mermaidLoader = null;
|
|
175
176
|
/**
|
|
176
177
|
* 加载 Mermaid 库
|
|
@@ -214,27 +215,7 @@ var mermaidLoader = null;
|
|
|
214
215
|
* 检查 Mermaid 代码是否可能完整
|
|
215
216
|
* 用于流式输入时判断是否应该尝试渲染
|
|
216
217
|
*/ var isCodeLikelyComplete = function(code) {
|
|
217
|
-
|
|
218
|
-
if (!trimmed) return false;
|
|
219
|
-
// 检查是否包含基本的 Mermaid 图表类型关键字
|
|
220
|
-
var hasChartType = trimmed.includes('graph') || trimmed.includes('sequenceDiagram') || trimmed.includes('gantt') || trimmed.includes('pie') || trimmed.includes('classDiagram') || trimmed.includes('stateDiagram') || trimmed.includes('erDiagram') || trimmed.includes('journey') || trimmed.includes('gitgraph') || trimmed.includes('flowchart');
|
|
221
|
-
if (!hasChartType) return false;
|
|
222
|
-
// 检查基本结构完整性(简单启发式检查)
|
|
223
|
-
// 如果代码很短,可能是正在输入中
|
|
224
|
-
if (trimmed.length < 10) return false;
|
|
225
|
-
// 检查是否以常见的不完整模式结尾
|
|
226
|
-
var incompletePatterns = [
|
|
227
|
-
/graph\s*$/i,
|
|
228
|
-
/-->?\s*$/,
|
|
229
|
-
/\[.*$/,
|
|
230
|
-
/\(.*$/,
|
|
231
|
-
/{.*$/
|
|
232
|
-
];
|
|
233
|
-
// 如果匹配不完整模式,可能还在输入中
|
|
234
|
-
var endsWithIncomplete = incompletePatterns.some(function(pattern) {
|
|
235
|
-
return pattern.test(trimmed);
|
|
236
|
-
});
|
|
237
|
-
return !endsWithIncomplete;
|
|
218
|
+
return isCodeBlockLikelyComplete(code, 'mermaid');
|
|
238
219
|
};
|
|
239
220
|
var MermaidRendererImpl = function(props) {
|
|
240
221
|
var _props_element;
|
|
@@ -307,9 +288,9 @@ var MermaidRendererImpl = function(props) {
|
|
|
307
288
|
// 检查代码是否可能完整
|
|
308
289
|
var likelyComplete = isCodeLikelyComplete(nextCode);
|
|
309
290
|
// 防抖延迟:根据代码变化频率动态调整
|
|
310
|
-
//
|
|
311
|
-
var baseDelay =
|
|
312
|
-
var typingDelay = changeCountRef.current > 3 ?
|
|
291
|
+
// 如果代码变化频繁(流式输入),使用更长的延迟以减少抖动
|
|
292
|
+
var baseDelay = 500; // 增加基础延迟
|
|
293
|
+
var typingDelay = changeCountRef.current > 3 ? 1500 : 1200; // 频繁变化时延长到 1.5 秒
|
|
313
294
|
var delay = currentState.code ? likelyComplete ? baseDelay : typingDelay : 0;
|
|
314
295
|
// 第一层防抖:检测代码变化
|
|
315
296
|
timer.current = window.setTimeout(function() {
|
|
@@ -321,10 +302,10 @@ var MermaidRendererImpl = function(props) {
|
|
|
321
302
|
return;
|
|
322
303
|
}
|
|
323
304
|
// 第二层防抖:实际渲染
|
|
324
|
-
//
|
|
325
|
-
var finalDelay = likelyComplete ?
|
|
305
|
+
// 如果代码可能不完整,再等待一段时间,增加延迟以减少抖动
|
|
306
|
+
var finalDelay = likelyComplete ? 200 : 800; // 增加延迟时间
|
|
326
307
|
renderTimer.current = window.setTimeout(/*#__PURE__*/ _async_to_generator(function() {
|
|
327
|
-
var _mermaidRef_current, api, _tmp, trimmedCode, svg,
|
|
308
|
+
var _mermaidRef_current, api, _tmp, trimmedCode, svg, container, error, api1, finalCode, parseError, tempElement;
|
|
328
309
|
return _ts_generator(this, function(_state) {
|
|
329
310
|
switch(_state.label){
|
|
330
311
|
case 0:
|
|
@@ -376,46 +357,62 @@ var MermaidRendererImpl = function(props) {
|
|
|
376
357
|
case 4:
|
|
377
358
|
svg = _state.sent().svg;
|
|
378
359
|
if (divRef.current) {
|
|
379
|
-
//
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
//
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
//
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
360
|
+
// 使用更平滑的更新方式,避免抖动
|
|
361
|
+
// 先设置透明度,然后更新内容,最后恢复透明度
|
|
362
|
+
container = divRef.current;
|
|
363
|
+
// 如果已有内容,先淡出
|
|
364
|
+
if (container.children.length > 0) {
|
|
365
|
+
container.style.opacity = '0';
|
|
366
|
+
container.style.transition = 'opacity 0.2s ease-in-out';
|
|
367
|
+
}
|
|
368
|
+
// 使用 requestAnimationFrame 确保平滑更新
|
|
369
|
+
requestAnimationFrame(function() {
|
|
370
|
+
// 清理旧内容
|
|
371
|
+
container.innerHTML = '';
|
|
372
|
+
// 创建隔离的容器包装 SVG
|
|
373
|
+
var wrapper = document.createElement('div');
|
|
374
|
+
wrapper.style.cssText = "\n position: relative;\n width: 100%;\n max-width: 100%;\n overflow: hidden;\n isolation: isolate;\n contain: layout style paint;\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 200px; /* 保持最小高度,避免尺寸抖动 */\n ";
|
|
375
|
+
// 解析 SVG 并添加隔离属性
|
|
376
|
+
var parser = new DOMParser();
|
|
377
|
+
var svgDoc = parser.parseFromString(svg, 'image/svg+xml');
|
|
378
|
+
var svgElement = svgDoc.querySelector('svg');
|
|
379
|
+
if (svgElement) {
|
|
380
|
+
// 确保 SVG 不会溢出
|
|
381
|
+
var existingStyle = svgElement.getAttribute('style') || '';
|
|
382
|
+
var newStyle = "".concat(existingStyle, "; max-width: 100%; height: auto; overflow: hidden;").trim();
|
|
383
|
+
svgElement.setAttribute('style', newStyle);
|
|
384
|
+
// 添加隔离属性和类名
|
|
385
|
+
svgElement.setAttribute('data-mermaid-svg', 'true');
|
|
386
|
+
svgElement.setAttribute('class', (svgElement.getAttribute('class') || '') + ' mermaid-isolated');
|
|
387
|
+
// 限制 SVG 内部元素的样式影响范围
|
|
388
|
+
var allElements = svgElement.querySelectorAll('*');
|
|
389
|
+
allElements.forEach(function(el) {
|
|
390
|
+
// 确保内部元素不会影响外部
|
|
391
|
+
if (el instanceof SVGElement) {
|
|
392
|
+
el.setAttribute('data-mermaid-internal', 'true');
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
wrapper.appendChild(svgElement);
|
|
414
396
|
} else {
|
|
415
|
-
|
|
397
|
+
// 如果解析失败,直接使用原始 SVG,但添加包装
|
|
398
|
+
var tempDiv = document.createElement('div');
|
|
399
|
+
tempDiv.innerHTML = svg;
|
|
400
|
+
var extractedSvg = tempDiv.querySelector('svg');
|
|
401
|
+
if (extractedSvg) {
|
|
402
|
+
extractedSvg.setAttribute('style', 'max-width: 100%; height: auto; overflow: hidden;');
|
|
403
|
+
extractedSvg.setAttribute('data-mermaid-svg', 'true');
|
|
404
|
+
wrapper.appendChild(extractedSvg);
|
|
405
|
+
} else {
|
|
406
|
+
wrapper.innerHTML = svg;
|
|
407
|
+
}
|
|
416
408
|
}
|
|
417
|
-
|
|
418
|
-
|
|
409
|
+
container.appendChild(wrapper);
|
|
410
|
+
// 恢复透明度,实现淡入效果
|
|
411
|
+
requestAnimationFrame(function() {
|
|
412
|
+
container.style.opacity = '1';
|
|
413
|
+
container.style.transition = 'opacity 0.3s ease-in-out';
|
|
414
|
+
});
|
|
415
|
+
});
|
|
419
416
|
}
|
|
420
417
|
// 渲染成功,重置状态
|
|
421
418
|
setState({
|
|
@@ -566,6 +563,7 @@ var MermaidRendererImpl = function(props) {
|
|
|
566
563
|
style: {
|
|
567
564
|
width: '100%',
|
|
568
565
|
maxWidth: '100%',
|
|
566
|
+
minHeight: '200px',
|
|
569
567
|
display: 'flex',
|
|
570
568
|
justifyContent: 'center',
|
|
571
569
|
visibility: snapshot.code && !snapshot.error ? 'visible' : 'hidden',
|
|
@@ -575,7 +573,9 @@ var MermaidRendererImpl = function(props) {
|
|
|
575
573
|
contain: 'layout style paint',
|
|
576
574
|
overflow: 'hidden',
|
|
577
575
|
// 防止 SVG 样式影响外部
|
|
578
|
-
pointerEvents: snapshot.code && !snapshot.error ? 'auto' : 'none'
|
|
576
|
+
pointerEvents: snapshot.code && !snapshot.error ? 'auto' : 'none',
|
|
577
|
+
// 添加过渡效果,使更新更平滑
|
|
578
|
+
transition: 'opacity 0.3s ease-in-out, min-height 0.2s ease-in-out'
|
|
579
579
|
},
|
|
580
580
|
// 使用 data 属性标记,方便样式隔离
|
|
581
581
|
"data-mermaid-container": "true"
|