@ant-design/agentic-ui 2.23.0 → 2.24.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/Bubble/BubbleBeforeNode.js +9 -9
- package/dist/Bubble/List/PureBubbleList.js +16 -2
- package/dist/Bubble/List/index.js +17 -2
- package/dist/MarkdownEditor/editor/elements/index.js +50 -1
- package/dist/MarkdownEditor/editor/parser/parse/parseHtml.js +40 -6
- package/dist/MarkdownEditor/editor/parser/parse/parseTable.js +2 -6
- package/dist/MarkdownEditor/editor/parser/parseCache.d.ts +53 -0
- package/dist/MarkdownEditor/editor/parser/parseCache.js +355 -0
- package/dist/MarkdownEditor/editor/parser/parserMarkdownToSlateNode.d.ts +3 -2
- package/dist/MarkdownEditor/editor/parser/parserMarkdownToSlateNode.js +8 -0
- package/dist/MarkdownEditor/editor/tools/ToolBar/ReadonlyBaseBar.js +2 -1
- package/dist/MarkdownEditor/el.d.ts +7 -0
- package/dist/MarkdownEditor/types.d.ts +5 -0
- package/dist/MarkdownInputField/MarkdownInputField.js +5 -0
- package/dist/Plugins/chart/hooks/index.d.ts +1 -1
- package/dist/Plugins/chart/utils.d.ts +1 -1
- package/dist/Plugins/chart/utils.js +1 -1
- package/package.json +1 -1
|
@@ -71,15 +71,15 @@ var canRenderThoughtChain = function(placement, role, thoughtChainEnabled) {
|
|
|
71
71
|
if (thoughtChainEnabled === false) return false;
|
|
72
72
|
return true;
|
|
73
73
|
};
|
|
74
|
-
/**
|
|
75
|
-
* BubbleBeforeNode 组件
|
|
76
|
-
*
|
|
77
|
-
* 在聊天气泡之前渲染思维链或任务列表,显示AI的思考过程
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* ```tsx
|
|
81
|
-
* <BubbleBeforeNode bubble={bubbleData} />
|
|
82
|
-
* ```
|
|
74
|
+
/**
|
|
75
|
+
* BubbleBeforeNode 组件
|
|
76
|
+
*
|
|
77
|
+
* 在聊天气泡之前渲染思维链或任务列表,显示AI的思考过程
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```tsx
|
|
81
|
+
* <BubbleBeforeNode bubble={bubbleData} />
|
|
82
|
+
* ```
|
|
83
83
|
*/ export var BubbleBeforeNode = function(param) {
|
|
84
84
|
var bubble = param.bubble, className = param.className, style = param.style;
|
|
85
85
|
var _context_thoughtChain, _originData_extra, _context_thoughtChain1, _context_thoughtChain2;
|
|
@@ -51,11 +51,13 @@ function _object_spread_props(target, source) {
|
|
|
51
51
|
return target;
|
|
52
52
|
}
|
|
53
53
|
import SkeletonList from "./SkeletonList";
|
|
54
|
-
import { useContext, useMemo } from "react";
|
|
54
|
+
import { useContext, useMemo, useRef } from "react";
|
|
55
55
|
import { ConfigProvider } from "antd";
|
|
56
56
|
import cx from "classnames";
|
|
57
|
+
import { nanoid } from "nanoid";
|
|
57
58
|
import React from "react";
|
|
58
59
|
import { BubbleConfigContext } from "../BubbleConfigProvide";
|
|
60
|
+
import { LOADING_FLAT } from "../MessagesContent";
|
|
59
61
|
import { PureAIBubble, PureUserBubble } from "../PureBubble";
|
|
60
62
|
import { useStyle } from "./style";
|
|
61
63
|
export var PureBubbleList = function(props) {
|
|
@@ -71,6 +73,8 @@ export var PureBubbleList = function(props) {
|
|
|
71
73
|
}, [
|
|
72
74
|
JSON.stringify(props.style)
|
|
73
75
|
]);
|
|
76
|
+
// 为 loading 项生成唯一的 key,使用 ref 缓存以确保稳定性
|
|
77
|
+
var loadingKeysRef = useRef(new Map());
|
|
74
78
|
var listDom = useMemo(function() {
|
|
75
79
|
return bubbleList.map(function(item, index) {
|
|
76
80
|
var placement = item.role === 'user' ? 'right' : 'left';
|
|
@@ -78,8 +82,18 @@ export var PureBubbleList = function(props) {
|
|
|
78
82
|
var isLast = index === bubbleList.length - 1;
|
|
79
83
|
item.isLatest = isLast;
|
|
80
84
|
item.isLast = isLast;
|
|
85
|
+
// 如果 id 是 LOADING_FLAT,使用 uuid 作为 key
|
|
86
|
+
// 使用 index 和 createAt 的组合作为缓存 key,确保同一项在重新渲染时保持相同的 key
|
|
87
|
+
var itemKey = item.id;
|
|
88
|
+
if (item.id === LOADING_FLAT) {
|
|
89
|
+
var cacheKey = "".concat(index, "-").concat(item.createAt || Date.now());
|
|
90
|
+
if (!loadingKeysRef.current.has(cacheKey)) {
|
|
91
|
+
loadingKeysRef.current.set(cacheKey, nanoid());
|
|
92
|
+
}
|
|
93
|
+
itemKey = loadingKeysRef.current.get(cacheKey);
|
|
94
|
+
}
|
|
81
95
|
return /*#__PURE__*/ React.createElement(BubbleComponent, {
|
|
82
|
-
key:
|
|
96
|
+
key: itemKey,
|
|
83
97
|
"data-id": item.id,
|
|
84
98
|
avatar: _object_spread({}, placement === 'right' ? userMeta : assistantMeta, item.meta),
|
|
85
99
|
preMessage: bubbleList[index - 1],
|
|
@@ -52,12 +52,14 @@ function _object_spread_props(target, source) {
|
|
|
52
52
|
}
|
|
53
53
|
import SkeletonList from "./SkeletonList";
|
|
54
54
|
export { PureBubbleList } from "./PureBubbleList";
|
|
55
|
-
import { useContext, useMemo } from "react";
|
|
55
|
+
import { useContext, useMemo, useRef } from "react";
|
|
56
56
|
import { ConfigProvider } from "antd";
|
|
57
57
|
import cx from "classnames";
|
|
58
|
+
import { nanoid } from "nanoid";
|
|
58
59
|
import React from "react";
|
|
59
60
|
import { Bubble } from "../Bubble";
|
|
60
61
|
import { BubbleConfigContext } from "../BubbleConfigProvide";
|
|
62
|
+
import { LOADING_FLAT } from "../MessagesContent";
|
|
61
63
|
import { useStyle } from "./style";
|
|
62
64
|
/**
|
|
63
65
|
* BubbleList 组件 - 聊天气泡列表组件
|
|
@@ -130,6 +132,9 @@ import { useStyle } from "./style";
|
|
|
130
132
|
}, [
|
|
131
133
|
JSON.stringify(props.style)
|
|
132
134
|
]);
|
|
135
|
+
// 为 loading 项生成唯一的 key,使用 ref 缓存以确保稳定性
|
|
136
|
+
// 使用 item 的唯一标识(index + createAt)作为缓存 key
|
|
137
|
+
var loadingKeysRef = useRef(new Map());
|
|
133
138
|
var bubbleListDom = useMemo(function() {
|
|
134
139
|
return bubbleList.map(function(item, index) {
|
|
135
140
|
var _props_bubbleRenderConfig;
|
|
@@ -138,8 +143,18 @@ import { useStyle } from "./style";
|
|
|
138
143
|
// 保持向后兼容性,设置isLatest
|
|
139
144
|
item.isLatest = isLast;
|
|
140
145
|
item.isLast = isLast;
|
|
146
|
+
// 如果 id 是 LOADING_FLAT,使用 uuid 作为 key
|
|
147
|
+
// 使用 index 和 createAt 的组合作为缓存 key,确保同一项在重新渲染时保持相同的 key
|
|
148
|
+
var itemKey = item.id;
|
|
149
|
+
if (item.id === LOADING_FLAT) {
|
|
150
|
+
var cacheKey = "".concat(index, "-").concat(item.createAt || Date.now());
|
|
151
|
+
if (!loadingKeysRef.current.has(cacheKey)) {
|
|
152
|
+
loadingKeysRef.current.set(cacheKey, nanoid());
|
|
153
|
+
}
|
|
154
|
+
itemKey = loadingKeysRef.current.get(cacheKey);
|
|
155
|
+
}
|
|
141
156
|
return /*#__PURE__*/ React.createElement(Bubble, {
|
|
142
|
-
key:
|
|
157
|
+
key: itemKey,
|
|
143
158
|
"data-id": item.id,
|
|
144
159
|
avatar: _object_spread({}, item.role === 'user' ? userMeta : assistantMeta, item.meta),
|
|
145
160
|
preMessage: bubbleList[index - 1],
|
|
@@ -52,10 +52,11 @@ function _object_spread_props(target, source) {
|
|
|
52
52
|
}
|
|
53
53
|
import { ConfigProvider } from "antd";
|
|
54
54
|
import classNames from "classnames";
|
|
55
|
-
import React, { useContext } from "react";
|
|
55
|
+
import React, { useContext, useRef } from "react";
|
|
56
56
|
import { Editor, Path, Transforms } from "slate";
|
|
57
57
|
import { ReactEditor } from "slate-react";
|
|
58
58
|
import { I18nContext } from "../../../I18n";
|
|
59
|
+
import { isMobileDevice } from "../../../MarkdownInputField/AttachmentButton/utils";
|
|
59
60
|
import { useEditorStore } from "../store";
|
|
60
61
|
import { EditorUtils } from "../utils/editorUtils";
|
|
61
62
|
import { Blockquote } from "./Blockquote";
|
|
@@ -407,6 +408,46 @@ var MLeafComponent = function(props) {
|
|
|
407
408
|
}
|
|
408
409
|
} catch (e) {}
|
|
409
410
|
};
|
|
411
|
+
var handleFncOpen = function() {
|
|
412
|
+
var _props_fncProps;
|
|
413
|
+
if ((_props_fncProps = props.fncProps) === null || _props_fncProps === void 0 ? void 0 : _props_fncProps.onOriginUrlClick) {
|
|
414
|
+
props.fncProps.onOriginUrlClick(leaf === null || leaf === void 0 ? void 0 : leaf.identifier);
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
var isMobile = isMobileDevice();
|
|
418
|
+
var hasFnc = leaf.fnc || leaf.identifier;
|
|
419
|
+
// 长按处理:用于手机端打开 fnc
|
|
420
|
+
var longPressTimerRef = useRef(null);
|
|
421
|
+
var touchStartTimeRef = useRef(0);
|
|
422
|
+
var isLongPressRef = useRef(false);
|
|
423
|
+
var handleTouchStart = function() {
|
|
424
|
+
if (!hasFnc) return;
|
|
425
|
+
isLongPressRef.current = false;
|
|
426
|
+
touchStartTimeRef.current = Date.now();
|
|
427
|
+
longPressTimerRef.current = setTimeout(function() {
|
|
428
|
+
isLongPressRef.current = true;
|
|
429
|
+
handleFncOpen();
|
|
430
|
+
}, 500); // 500ms 长按时间
|
|
431
|
+
};
|
|
432
|
+
var handleTouchEnd = function(e) {
|
|
433
|
+
if (!hasFnc) return;
|
|
434
|
+
if (longPressTimerRef.current) {
|
|
435
|
+
clearTimeout(longPressTimerRef.current);
|
|
436
|
+
longPressTimerRef.current = null;
|
|
437
|
+
}
|
|
438
|
+
// 如果是短按(小于 500ms),在手机上阻止默认行为
|
|
439
|
+
var touchDuration = Date.now() - touchStartTimeRef.current;
|
|
440
|
+
if (touchDuration < 500 && isMobile) {
|
|
441
|
+
e.preventDefault();
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
var handleTouchCancel = function() {
|
|
445
|
+
if (longPressTimerRef.current) {
|
|
446
|
+
clearTimeout(longPressTimerRef.current);
|
|
447
|
+
longPressTimerRef.current = null;
|
|
448
|
+
}
|
|
449
|
+
isLongPressRef.current = false;
|
|
450
|
+
};
|
|
410
451
|
var _obj;
|
|
411
452
|
var fncClassName = classNames(prefixClassName === null || prefixClassName === void 0 ? void 0 : prefixClassName.trim(), props.hashId, (_obj = {}, _define_property(_obj, "".concat(mdEditorBaseClass, "-fnc"), leaf.fnc), _define_property(_obj, "".concat(mdEditorBaseClass, "-fnd"), leaf.fnd), _define_property(_obj, "".concat(mdEditorBaseClass, "-comment"), leaf.comment), _obj));
|
|
412
453
|
var dom = /*#__PURE__*/ React.createElement("span", _object_spread_props(_object_spread({}, props.attributes), {
|
|
@@ -415,6 +456,11 @@ var MLeafComponent = function(props) {
|
|
|
415
456
|
onDragStart: dragStart,
|
|
416
457
|
onClick: function(e) {
|
|
417
458
|
var _props_fncProps;
|
|
459
|
+
// 在手机上,如果是 fnc,阻止点击事件(使用长按代替)
|
|
460
|
+
if (isMobile && hasFnc) {
|
|
461
|
+
e.preventDefault();
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
418
464
|
if (e.detail === 2) {
|
|
419
465
|
selectFormat();
|
|
420
466
|
}
|
|
@@ -422,6 +468,9 @@ var MLeafComponent = function(props) {
|
|
|
422
468
|
props.fncProps.onOriginUrlClick(leaf === null || leaf === void 0 ? void 0 : leaf.identifier);
|
|
423
469
|
}
|
|
424
470
|
},
|
|
471
|
+
onTouchStart: hasFnc ? handleTouchStart : undefined,
|
|
472
|
+
onTouchEnd: hasFnc ? handleTouchEnd : undefined,
|
|
473
|
+
onTouchCancel: hasFnc ? handleTouchCancel : undefined,
|
|
425
474
|
contentEditable: leaf.fnc ? false : undefined,
|
|
426
475
|
"data-fnc": leaf.fnc || leaf.identifier ? 'fnc' : undefined,
|
|
427
476
|
"data-fnd": leaf.fnd ? 'fnd' : undefined,
|
|
@@ -470,17 +470,31 @@ import partialJsonParse from "../json-parse";
|
|
|
470
470
|
var isComment = commentValue.trim().startsWith('<!--') && commentValue.trim().endsWith('-->');
|
|
471
471
|
// 检查是否是 otherProps 序列化生成的 JSON 注释
|
|
472
472
|
// 这些注释应该被跳过,不应该被解析为 HTML 代码块
|
|
473
|
+
// 但是,如果注释包含图表配置(chartType),应该保留为 code 节点以便表格解析器使用
|
|
473
474
|
if (isComment) {
|
|
474
475
|
try {
|
|
476
|
+
var _parsed_;
|
|
475
477
|
var commentContent = commentValue.replace('<!--', '').replace('-->', '').trim();
|
|
476
478
|
var parsed = JSON.parse(commentContent);
|
|
477
|
-
//
|
|
478
|
-
|
|
479
|
-
//
|
|
479
|
+
// 检查是否是图表配置
|
|
480
|
+
var isChartConfig = // 对象格式:{"chartType": ...}
|
|
481
|
+
(typeof parsed === "undefined" ? "undefined" : _type_of(parsed)) === 'object' && parsed !== null && !Array.isArray(parsed) && parsed.chartType || // 数组格式:[{"chartType": ...}]
|
|
482
|
+
Array.isArray(parsed) && parsed.length > 0 && _type_of(parsed[0]) === 'object' && ((_parsed_ = parsed[0]) === null || _parsed_ === void 0 ? void 0 : _parsed_.chartType);
|
|
483
|
+
// 如果能够成功解析为 JSON 对象,且是对象类型(不是数组或基本类型)
|
|
484
|
+
// 注意:对象格式的图表配置已经在 handleHtml 中转换为数组格式了
|
|
485
|
+
// 这里只处理非图表配置的对象格式注释
|
|
480
486
|
if ((typeof parsed === "undefined" ? "undefined" : _type_of(parsed)) === 'object' && parsed !== null && !Array.isArray(parsed)) {
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
487
|
+
// 如果包含 chartType 字段,说明是图表配置,应该已经在 handleHtml 中转换为数组格式
|
|
488
|
+
// 这里不应该再匹配到对象格式的图表配置,继续正常处理
|
|
489
|
+
if (isChartConfig && parsed.chartType) {
|
|
490
|
+
// 继续正常处理,创建 code 节点(此时应该已经是数组格式了)
|
|
491
|
+
} else {
|
|
492
|
+
// 否则认为是 otherProps 序列化生成的注释,应该返回空文本
|
|
493
|
+
// 这些注释应该在 parserMarkdownToSlateNode 中被跳过
|
|
494
|
+
return {
|
|
495
|
+
text: ''
|
|
496
|
+
};
|
|
497
|
+
}
|
|
484
498
|
}
|
|
485
499
|
} catch (e) {
|
|
486
500
|
// 解析失败,不是 JSON 格式的注释,继续正常处理
|
|
@@ -704,6 +718,26 @@ import partialJsonParse from "../json-parse";
|
|
|
704
718
|
var trimmedValue = (currentElement === null || currentElement === void 0 ? void 0 : (_currentElement_value = currentElement.value) === null || _currentElement_value === void 0 ? void 0 : _currentElement_value.trim()) || '';
|
|
705
719
|
var isUnclosedComment = trimmedValue.startsWith('<!--') && !trimmedValue.endsWith('-->');
|
|
706
720
|
var processedValue = isUnclosedComment ? trimmedValue + '-->' : (currentElement === null || currentElement === void 0 ? void 0 : currentElement.value) || '';
|
|
721
|
+
// 检查是否是对象格式的图表配置,如果是则转换为数组格式
|
|
722
|
+
var isComment = processedValue.trim().startsWith('<!--') && processedValue.trim().endsWith('-->');
|
|
723
|
+
if (isComment) {
|
|
724
|
+
try {
|
|
725
|
+
var commentContent = processedValue.replace('<!--', '').replace('-->', '').trim();
|
|
726
|
+
var parsed = JSON.parse(commentContent);
|
|
727
|
+
// 如果是对象格式且包含 chartType,转换为数组格式
|
|
728
|
+
if ((typeof parsed === "undefined" ? "undefined" : _type_of(parsed)) === 'object' && parsed !== null && !Array.isArray(parsed) && parsed.chartType) {
|
|
729
|
+
var arrayFormat = [
|
|
730
|
+
parsed
|
|
731
|
+
];
|
|
732
|
+
var convertedContent = JSON.stringify(arrayFormat);
|
|
733
|
+
processedValue = "<!--".concat(convertedContent, "-->");
|
|
734
|
+
// 同时更新 currentElement.value,以便后续处理使用
|
|
735
|
+
currentElement.value = processedValue;
|
|
736
|
+
}
|
|
737
|
+
} catch (e) {
|
|
738
|
+
// 解析失败,不是 JSON 格式的注释,继续正常处理
|
|
739
|
+
}
|
|
740
|
+
}
|
|
707
741
|
var value = (processedValue === null || processedValue === void 0 ? void 0 : processedValue.replace('<!--', '').replace('-->', '').trim()) || '{}';
|
|
708
742
|
var contextProps = parseCommentContextProps(value, processedValue);
|
|
709
743
|
var isBlockLevel = !parent || [
|
|
@@ -150,11 +150,7 @@ var myRemark = {
|
|
|
150
150
|
*/ export var parseTableOrChart = function(table, preNode, plugins, parseNodes, parserConfig) {
|
|
151
151
|
var _table_children, _tableHeader_children, _table_children_slice, _table_children1, _table_align, _chartConfig_, _config_at, _config_at1;
|
|
152
152
|
var keyMap = new Map();
|
|
153
|
-
|
|
154
|
-
var config = // @ts-ignore
|
|
155
|
-
(preNode === null || preNode === void 0 ? void 0 : preNode.type) === 'code' && // @ts-ignore
|
|
156
|
-
(preNode === null || preNode === void 0 ? void 0 : preNode.language) === 'html' && (// @ts-ignore
|
|
157
|
-
preNode === null || preNode === void 0 ? void 0 : preNode.otherProps) ? preNode === null || preNode === void 0 ? void 0 : preNode.otherProps : {};
|
|
153
|
+
var config = (preNode === null || preNode === void 0 ? void 0 : preNode.type) === 'code' && (preNode === null || preNode === void 0 ? void 0 : preNode.language) === 'html' && (preNode === null || preNode === void 0 ? void 0 : preNode.otherProps) ? preNode === null || preNode === void 0 ? void 0 : preNode.otherProps : parserConfig || {};
|
|
158
154
|
var tableHeader = table === null || table === void 0 ? void 0 : (_table_children = table.children) === null || _table_children === void 0 ? void 0 : _table_children.at(0);
|
|
159
155
|
var columns = (tableHeader === null || tableHeader === void 0 ? void 0 : (_tableHeader_children = tableHeader.children) === null || _tableHeader_children === void 0 ? void 0 : _tableHeader_children.map(function(node) {
|
|
160
156
|
var _myRemark_stringify;
|
|
@@ -239,7 +235,7 @@ var myRemark = {
|
|
|
239
235
|
chartConfig = convertObjectToArray(chartConfig);
|
|
240
236
|
var isChart = (chartConfig === null || chartConfig === void 0 ? void 0 : chartConfig.chartType) || Array.isArray(chartConfig) && (chartConfig === null || chartConfig === void 0 ? void 0 : (_chartConfig_ = chartConfig[0]) === null || _chartConfig_ === void 0 ? void 0 : _chartConfig_.chartType) || (config === null || config === void 0 ? void 0 : config.chartType) || (config === null || config === void 0 ? void 0 : (_config_at1 = config.at) === null || _config_at1 === void 0 ? void 0 : (_config_at = _config_at1.call(config, 0)) === null || _config_at === void 0 ? void 0 : _config_at.chartType);
|
|
241
237
|
// 计算合并单元格信息
|
|
242
|
-
var mergeCells = config.mergeCells || [];
|
|
238
|
+
var mergeCells = (config === null || config === void 0 ? void 0 : config.mergeCells) || [];
|
|
243
239
|
// 创建合并单元格映射,用于快速查找
|
|
244
240
|
var mergeMap = new Map();
|
|
245
241
|
mergeCells === null || mergeCells === void 0 ? void 0 : mergeCells.forEach(function(param) {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Elements } from '../../el';
|
|
2
|
+
/**
|
|
3
|
+
* Markdown 解析缓存类
|
|
4
|
+
*
|
|
5
|
+
* 使用 Map 存储 markdown 块到 schema 的映射,避免重复解析相同的 markdown 内容
|
|
6
|
+
*/
|
|
7
|
+
export declare class ParseCache {
|
|
8
|
+
private cache;
|
|
9
|
+
/**
|
|
10
|
+
* 从缓存中获取解析结果
|
|
11
|
+
*
|
|
12
|
+
* @param md - markdown 字符串
|
|
13
|
+
* @returns 如果缓存中存在则返回解析结果,否则返回 null
|
|
14
|
+
*/
|
|
15
|
+
get(md: string): Elements[] | null;
|
|
16
|
+
/**
|
|
17
|
+
* 将解析结果存入缓存
|
|
18
|
+
*
|
|
19
|
+
* @param md - markdown 字符串
|
|
20
|
+
* @param schema - 解析后的 schema 数组
|
|
21
|
+
*/
|
|
22
|
+
set(md: string, schema: Elements[]): void;
|
|
23
|
+
/**
|
|
24
|
+
* 检查缓存中是否存在指定的 markdown
|
|
25
|
+
*
|
|
26
|
+
* @param md - markdown 字符串
|
|
27
|
+
* @returns 是否存在
|
|
28
|
+
*/
|
|
29
|
+
has(md: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* 清空缓存
|
|
32
|
+
*/
|
|
33
|
+
clear(): void;
|
|
34
|
+
/**
|
|
35
|
+
* 获取缓存大小
|
|
36
|
+
*
|
|
37
|
+
* @returns 缓存中存储的条目数
|
|
38
|
+
*/
|
|
39
|
+
size(): number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 按 \n\n 切分 markdown,但保护不应被切分的结构
|
|
43
|
+
*
|
|
44
|
+
* 切分规则:
|
|
45
|
+
* 1. 按 \n\n(双换行)切分 markdown
|
|
46
|
+
* 2. 保护代码块(```code```):代码块内部的 \n\n 不作为分隔符
|
|
47
|
+
* 3. 保护 HTML 注释(<!-- -->):注释内部的 \n\n 不作为分隔符
|
|
48
|
+
* 4. 保护 HTML 标签(<tag>...</tag>):标签内部的 \n\n 不作为分隔符
|
|
49
|
+
*
|
|
50
|
+
* @param md - 要切分的 markdown 字符串
|
|
51
|
+
* @returns 切分后的 markdown 块数组
|
|
52
|
+
*/
|
|
53
|
+
export declare function splitMarkdownIntoBlocks(md: string): string[];
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
function _class_call_check(instance, Constructor) {
|
|
2
|
+
if (!(instance instanceof Constructor)) {
|
|
3
|
+
throw new TypeError("Cannot call a class as a function");
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
function _defineProperties(target, props) {
|
|
7
|
+
for(var i = 0; i < props.length; i++){
|
|
8
|
+
var descriptor = props[i];
|
|
9
|
+
descriptor.enumerable = descriptor.enumerable || false;
|
|
10
|
+
descriptor.configurable = true;
|
|
11
|
+
if ("value" in descriptor) descriptor.writable = true;
|
|
12
|
+
Object.defineProperty(target, descriptor.key, descriptor);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function _create_class(Constructor, protoProps, staticProps) {
|
|
16
|
+
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
|
17
|
+
if (staticProps) _defineProperties(Constructor, staticProps);
|
|
18
|
+
return Constructor;
|
|
19
|
+
}
|
|
20
|
+
function _define_property(obj, key, value) {
|
|
21
|
+
if (key in obj) {
|
|
22
|
+
Object.defineProperty(obj, key, {
|
|
23
|
+
value: value,
|
|
24
|
+
enumerable: true,
|
|
25
|
+
configurable: true,
|
|
26
|
+
writable: true
|
|
27
|
+
});
|
|
28
|
+
} else {
|
|
29
|
+
obj[key] = value;
|
|
30
|
+
}
|
|
31
|
+
return obj;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Markdown 解析缓存类
|
|
35
|
+
*
|
|
36
|
+
* 使用 Map 存储 markdown 块到 schema 的映射,避免重复解析相同的 markdown 内容
|
|
37
|
+
*/ export var ParseCache = /*#__PURE__*/ function() {
|
|
38
|
+
"use strict";
|
|
39
|
+
function ParseCache() {
|
|
40
|
+
_class_call_check(this, ParseCache);
|
|
41
|
+
_define_property(this, "cache", new Map());
|
|
42
|
+
}
|
|
43
|
+
_create_class(ParseCache, [
|
|
44
|
+
{
|
|
45
|
+
/**
|
|
46
|
+
* 从缓存中获取解析结果
|
|
47
|
+
*
|
|
48
|
+
* @param md - markdown 字符串
|
|
49
|
+
* @returns 如果缓存中存在则返回解析结果,否则返回 null
|
|
50
|
+
*/ key: "get",
|
|
51
|
+
value: function get(md) {
|
|
52
|
+
return this.cache.get(md) || null;
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
/**
|
|
57
|
+
* 将解析结果存入缓存
|
|
58
|
+
*
|
|
59
|
+
* @param md - markdown 字符串
|
|
60
|
+
* @param schema - 解析后的 schema 数组
|
|
61
|
+
*/ key: "set",
|
|
62
|
+
value: function set(md, schema) {
|
|
63
|
+
this.cache.set(md, schema);
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
/**
|
|
68
|
+
* 检查缓存中是否存在指定的 markdown
|
|
69
|
+
*
|
|
70
|
+
* @param md - markdown 字符串
|
|
71
|
+
* @returns 是否存在
|
|
72
|
+
*/ key: "has",
|
|
73
|
+
value: function has(md) {
|
|
74
|
+
return this.cache.has(md);
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
/**
|
|
79
|
+
* 清空缓存
|
|
80
|
+
*/ key: "clear",
|
|
81
|
+
value: function clear() {
|
|
82
|
+
this.cache.clear();
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
/**
|
|
87
|
+
* 获取缓存大小
|
|
88
|
+
*
|
|
89
|
+
* @returns 缓存中存储的条目数
|
|
90
|
+
*/ key: "size",
|
|
91
|
+
value: function size() {
|
|
92
|
+
return this.cache.size;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
]);
|
|
96
|
+
return ParseCache;
|
|
97
|
+
}();
|
|
98
|
+
/**
|
|
99
|
+
* 获取代码块围栏的长度
|
|
100
|
+
*/ function getFenceLength(md, start, fenceChar) {
|
|
101
|
+
var length = 0;
|
|
102
|
+
while(start + length < md.length && md[start + length] === fenceChar){
|
|
103
|
+
length++;
|
|
104
|
+
}
|
|
105
|
+
return length;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 查找 HTML 注释的结束位置
|
|
109
|
+
* 返回结束位置(包含 -->),如果未找到则返回 -1
|
|
110
|
+
*/ function findHtmlCommentEnd(md, start) {
|
|
111
|
+
if (md.slice(start, start + 4) !== '<!--') {
|
|
112
|
+
return -1;
|
|
113
|
+
}
|
|
114
|
+
for(var i = start + 4; i < md.length - 2; i++){
|
|
115
|
+
if (md.slice(i, i + 3) === '-->') {
|
|
116
|
+
return i + 3;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return -1;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* 查找 HTML 标签信息
|
|
123
|
+
* 返回标签信息对象,如果未找到则返回 null
|
|
124
|
+
*/ function findHtmlTagInfo(md, start) {
|
|
125
|
+
if (md[start] !== '<') {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
var i = start + 1;
|
|
129
|
+
// 跳过可能的 /(结束标签)
|
|
130
|
+
if (i < md.length && md[i] === '/') {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
// 提取标签名
|
|
134
|
+
var tagName = '';
|
|
135
|
+
while(i < md.length && /[a-zA-Z0-9-]/.test(md[i])){
|
|
136
|
+
tagName += md[i];
|
|
137
|
+
i++;
|
|
138
|
+
}
|
|
139
|
+
if (!tagName) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
// 跳过空白和属性,查找 > 或 />
|
|
143
|
+
// 需要处理属性值中的引号
|
|
144
|
+
var inQuotes = false;
|
|
145
|
+
var quoteChar = '';
|
|
146
|
+
while(i < md.length){
|
|
147
|
+
var char = md[i];
|
|
148
|
+
// 处理引号(检查前一个字符是否是转义字符)
|
|
149
|
+
if (char === '"' || char === "'") {
|
|
150
|
+
var prevChar = i > 0 ? md[i - 1] : '';
|
|
151
|
+
if (prevChar !== '\\') {
|
|
152
|
+
if (!inQuotes) {
|
|
153
|
+
inQuotes = true;
|
|
154
|
+
quoteChar = char;
|
|
155
|
+
} else if (char === quoteChar) {
|
|
156
|
+
inQuotes = false;
|
|
157
|
+
quoteChar = '';
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// 只有在引号外部才检查标签结束
|
|
162
|
+
if (!inQuotes) {
|
|
163
|
+
if (char === '>') {
|
|
164
|
+
return {
|
|
165
|
+
name: tagName.toLowerCase(),
|
|
166
|
+
end: i + 1,
|
|
167
|
+
isSelfClosing: false
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
if (i < md.length - 1 && md.slice(i, i + 2) === '/>') {
|
|
171
|
+
return {
|
|
172
|
+
name: tagName.toLowerCase(),
|
|
173
|
+
end: i + 2,
|
|
174
|
+
isSelfClosing: true
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
i++;
|
|
179
|
+
}
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* 查找 HTML 结束标签的位置
|
|
184
|
+
* 返回结束位置(包含 >),如果未找到则返回 -1
|
|
185
|
+
*/ function findHtmlClosingTagEnd(md, start, tagName) {
|
|
186
|
+
if (md.slice(start, start + 2) !== '</') {
|
|
187
|
+
return -1;
|
|
188
|
+
}
|
|
189
|
+
// 检查标签名是否匹配
|
|
190
|
+
var expectedTag = "</".concat(tagName);
|
|
191
|
+
if (md.slice(start, start + expectedTag.length).toLowerCase() !== expectedTag.toLowerCase()) {
|
|
192
|
+
return -1;
|
|
193
|
+
}
|
|
194
|
+
// 查找 >
|
|
195
|
+
var i = start + expectedTag.length;
|
|
196
|
+
while(i < md.length && /\s/.test(md[i])){
|
|
197
|
+
i++;
|
|
198
|
+
}
|
|
199
|
+
if (i < md.length && md[i] === '>') {
|
|
200
|
+
return i + 1;
|
|
201
|
+
}
|
|
202
|
+
return -1;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* 检查是否应该保护此分隔符(不切分)
|
|
206
|
+
* 返回 true 如果:
|
|
207
|
+
* 1. HTML 注释后紧跟着表格行
|
|
208
|
+
* 2. 当前块包含表格行,且后面也是表格行
|
|
209
|
+
*/ function shouldProtectSeparator(md, separatorIndex, currentBlock) {
|
|
210
|
+
// 跳过 \n\n 和后续的换行符,查找下一行的开始
|
|
211
|
+
var nextLineStart = separatorIndex + 2;
|
|
212
|
+
while(nextLineStart < md.length && md[nextLineStart] === '\n'){
|
|
213
|
+
nextLineStart++;
|
|
214
|
+
}
|
|
215
|
+
// 检查下一行是否以 | 开头(表格行)
|
|
216
|
+
if (nextLineStart >= md.length || md[nextLineStart] !== '|') {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
// 情况1:当前块以 HTML 注释结尾,后面是表格行
|
|
220
|
+
var trimmedBlock = currentBlock.trim();
|
|
221
|
+
if (trimmedBlock.endsWith('-->')) {
|
|
222
|
+
var commentStart = trimmedBlock.lastIndexOf('<!--');
|
|
223
|
+
if (commentStart !== -1) {
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// 情况2:当前块包含表格行(检查最后几行是否包含表格行)
|
|
228
|
+
var lines = currentBlock.split('\n');
|
|
229
|
+
for(var i = lines.length - 1; i >= Math.max(0, lines.length - 5); i--){
|
|
230
|
+
var line = lines[i].trim();
|
|
231
|
+
if (line.startsWith('|') && line.endsWith('|')) {
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* 按 \n\n 切分 markdown,但保护不应被切分的结构
|
|
239
|
+
*
|
|
240
|
+
* 切分规则:
|
|
241
|
+
* 1. 按 \n\n(双换行)切分 markdown
|
|
242
|
+
* 2. 保护代码块(```code```):代码块内部的 \n\n 不作为分隔符
|
|
243
|
+
* 3. 保护 HTML 注释(<!-- -->):注释内部的 \n\n 不作为分隔符
|
|
244
|
+
* 4. 保护 HTML 标签(<tag>...</tag>):标签内部的 \n\n 不作为分隔符
|
|
245
|
+
*
|
|
246
|
+
* @param md - 要切分的 markdown 字符串
|
|
247
|
+
* @returns 切分后的 markdown 块数组
|
|
248
|
+
*/ export function splitMarkdownIntoBlocks(md) {
|
|
249
|
+
if (!md) {
|
|
250
|
+
return [];
|
|
251
|
+
}
|
|
252
|
+
var blocks = [];
|
|
253
|
+
var currentBlock = '';
|
|
254
|
+
var i = 0;
|
|
255
|
+
var inCodeBlock = false;
|
|
256
|
+
var codeBlockFence = '';
|
|
257
|
+
var inHtmlTag = false;
|
|
258
|
+
var htmlTagName = '';
|
|
259
|
+
while(i < md.length){
|
|
260
|
+
var char = md[i];
|
|
261
|
+
var nextChar = i + 1 < md.length ? md[i + 1] : null;
|
|
262
|
+
// 检测代码块开始:``` 或 ~~~
|
|
263
|
+
if (!inCodeBlock && !inHtmlTag && (char === '`' || char === '~')) {
|
|
264
|
+
var fenceLength = getFenceLength(md, i, char);
|
|
265
|
+
if (fenceLength >= 3) {
|
|
266
|
+
inCodeBlock = true;
|
|
267
|
+
codeBlockFence = char.repeat(fenceLength);
|
|
268
|
+
currentBlock += codeBlockFence;
|
|
269
|
+
i += fenceLength;
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
// 检测代码块结束
|
|
274
|
+
if (inCodeBlock && md.slice(i, i + codeBlockFence.length) === codeBlockFence) {
|
|
275
|
+
currentBlock += codeBlockFence;
|
|
276
|
+
i += codeBlockFence.length;
|
|
277
|
+
inCodeBlock = false;
|
|
278
|
+
codeBlockFence = '';
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
// 检测 HTML 注释开始:<!--
|
|
282
|
+
if (!inCodeBlock && !inHtmlTag && md.slice(i, i + 4) === '<!--') {
|
|
283
|
+
var commentEnd = findHtmlCommentEnd(md, i);
|
|
284
|
+
if (commentEnd > i) {
|
|
285
|
+
currentBlock += md.slice(i, commentEnd);
|
|
286
|
+
i = commentEnd;
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
// 检测 HTML 标签开始:<tag
|
|
291
|
+
if (!inCodeBlock && !inHtmlTag && char === '<') {
|
|
292
|
+
var tagInfo = findHtmlTagInfo(md, i);
|
|
293
|
+
if (tagInfo) {
|
|
294
|
+
if (tagInfo.isSelfClosing) {
|
|
295
|
+
// 自闭合标签,直接添加并跳过
|
|
296
|
+
currentBlock += md.slice(i, tagInfo.end);
|
|
297
|
+
i = tagInfo.end;
|
|
298
|
+
continue;
|
|
299
|
+
} else {
|
|
300
|
+
// 开始标签,查找对应的结束标签
|
|
301
|
+
inHtmlTag = true;
|
|
302
|
+
htmlTagName = tagInfo.name;
|
|
303
|
+
currentBlock += md.slice(i, tagInfo.end);
|
|
304
|
+
i = tagInfo.end;
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
// 检测 HTML 标签结束:</tag>
|
|
310
|
+
if (inHtmlTag && md.slice(i, i + 2) === '</') {
|
|
311
|
+
var closingTagEnd = findHtmlClosingTagEnd(md, i, htmlTagName);
|
|
312
|
+
if (closingTagEnd > i) {
|
|
313
|
+
currentBlock += md.slice(i, closingTagEnd);
|
|
314
|
+
i = closingTagEnd;
|
|
315
|
+
inHtmlTag = false;
|
|
316
|
+
htmlTagName = '';
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
// 检测块分隔符 \n\n(仅在代码块、HTML 注释和 HTML 标签外部)
|
|
321
|
+
if (!inCodeBlock && !inHtmlTag && char === '\n' && nextChar === '\n') {
|
|
322
|
+
// 检查是否应该保护此分隔符(HTML 注释后跟着表格,或表格行之间)
|
|
323
|
+
if (shouldProtectSeparator(md, i, currentBlock)) {
|
|
324
|
+
// 不切分,继续添加到当前块
|
|
325
|
+
currentBlock += '\n\n';
|
|
326
|
+
i += 2;
|
|
327
|
+
while(i < md.length && md[i] === '\n'){
|
|
328
|
+
currentBlock += '\n';
|
|
329
|
+
i++;
|
|
330
|
+
}
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
if (currentBlock.trim().length > 0) {
|
|
334
|
+
blocks.push(currentBlock.trim());
|
|
335
|
+
}
|
|
336
|
+
currentBlock = '';
|
|
337
|
+
// 跳过连续的换行符
|
|
338
|
+
i += 2;
|
|
339
|
+
while(i < md.length && md[i] === '\n'){
|
|
340
|
+
i++;
|
|
341
|
+
}
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
// 普通字符,添加到当前块
|
|
345
|
+
currentBlock += char;
|
|
346
|
+
i++;
|
|
347
|
+
}
|
|
348
|
+
// 处理最后一个块
|
|
349
|
+
if (currentBlock.trim().length > 0) {
|
|
350
|
+
blocks.push(currentBlock.trim());
|
|
351
|
+
}
|
|
352
|
+
return blocks.filter(function(block) {
|
|
353
|
+
return block.trim().length > 0;
|
|
354
|
+
});
|
|
355
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Elements } from '../../el';
|
|
1
|
+
import { ChartTypeConfig, Elements } from '../../el';
|
|
2
2
|
import { MarkdownEditorPlugin } from '../../plugin';
|
|
3
3
|
/**
|
|
4
4
|
* 解析Markdown字符串的配置选项
|
|
@@ -10,6 +10,7 @@ export interface ParserMarkdownToSlateNodeConfig {
|
|
|
10
10
|
paragraphTag?: string;
|
|
11
11
|
/** 是否正在输入中(打字机模式) */
|
|
12
12
|
typing?: boolean;
|
|
13
|
+
config?: ChartTypeConfig[];
|
|
13
14
|
}
|
|
14
15
|
/**
|
|
15
16
|
* Markdown 到 Slate 节点解析器类
|
|
@@ -18,7 +19,7 @@ export interface ParserMarkdownToSlateNodeConfig {
|
|
|
18
19
|
* 使用类形式可以避免在函数调用链中传递配置参数和插件。
|
|
19
20
|
*/
|
|
20
21
|
export declare class MarkdownToSlateParser {
|
|
21
|
-
private
|
|
22
|
+
private config;
|
|
22
23
|
private readonly plugins;
|
|
23
24
|
constructor(config?: ParserMarkdownToSlateNodeConfig, plugins?: MarkdownEditorPlugin[]);
|
|
24
25
|
/**
|
|
@@ -162,6 +162,11 @@ import mdastParser from "./remarkParse";
|
|
|
162
162
|
// 对齐注释(如 {"align":"center"})不包含这些属性,应该被保留
|
|
163
163
|
isOtherPropsComment = hasCodeMetadataProps;
|
|
164
164
|
}
|
|
165
|
+
if (Array.isArray(htmlCommentProps)) {
|
|
166
|
+
htmlCommentProps = {
|
|
167
|
+
config: htmlCommentProps
|
|
168
|
+
};
|
|
169
|
+
}
|
|
165
170
|
} catch (e) {
|
|
166
171
|
// 解析失败,不是 JSON 格式的注释,可能是真正的 HTML 注释
|
|
167
172
|
isOtherPropsComment = false;
|
|
@@ -237,6 +242,9 @@ import mdastParser from "./remarkParse";
|
|
|
237
242
|
}
|
|
238
243
|
}
|
|
239
244
|
}
|
|
245
|
+
if (Object.keys(config).length > 0) {
|
|
246
|
+
_this.config = _object_spread({}, _this.config, config);
|
|
247
|
+
}
|
|
240
248
|
// 如果插件没有处理,使用默认处理逻辑
|
|
241
249
|
if (!pluginHandled) {
|
|
242
250
|
// 使用统一的处理函数,通过 this 访问配置和插件
|
|
@@ -305,7 +305,7 @@ import { getPointStrOffset, getSelectionFromDomSelection } from "../../utils/edi
|
|
|
305
305
|
key: "comment",
|
|
306
306
|
className: classnames("".concat(baseClassName, "-item"), hashId),
|
|
307
307
|
onClick: function() {
|
|
308
|
-
var _i18n_locale;
|
|
308
|
+
var _i18n_locale, _editorProps_comment, _i18n_locale1;
|
|
309
309
|
if (typeof window === 'undefined') return;
|
|
310
310
|
var domSelection = window.getSelection();
|
|
311
311
|
var editor = markdownEditorRef.current;
|
|
@@ -376,6 +376,7 @@ import { getPointStrOffset, getSelectionFromDomSelection } from "../../utils/edi
|
|
|
376
376
|
height: 100,
|
|
377
377
|
resize: 'none'
|
|
378
378
|
},
|
|
379
|
+
placeholder: (editorProps === null || editorProps === void 0 ? void 0 : (_editorProps_comment = editorProps.comment) === null || _editorProps_comment === void 0 ? void 0 : _editorProps_comment.placeholder) || (editorProps === null || editorProps === void 0 ? void 0 : editorProps.titlePlaceholderContent) || ((_i18n_locale1 = i18n.locale) === null || _i18n_locale1 === void 0 ? void 0 : _i18n_locale1.inputPlaceholder) || '请输入内容...',
|
|
379
380
|
onChange: function(e) {
|
|
380
381
|
comment.content = e.target.value;
|
|
381
382
|
}
|
|
@@ -17,7 +17,14 @@ export type CodeNode<T = Record<string, any>> = {
|
|
|
17
17
|
className?: string;
|
|
18
18
|
language?: string;
|
|
19
19
|
render?: boolean;
|
|
20
|
+
mergeCells?: Array<{
|
|
21
|
+
row: number;
|
|
22
|
+
col: number;
|
|
23
|
+
rowSpan: number;
|
|
24
|
+
colSpan: number;
|
|
25
|
+
}>;
|
|
20
26
|
frontmatter?: boolean;
|
|
27
|
+
config?: Record<string, any>[];
|
|
21
28
|
} & T;
|
|
22
29
|
children: [{
|
|
23
30
|
text: string;
|
|
@@ -280,6 +280,11 @@ export type MarkdownEditorProps = {
|
|
|
280
280
|
onEdit?: (id: string | number, comment: CommentDataType) => void;
|
|
281
281
|
deleteConfirmText?: string;
|
|
282
282
|
mentionsPlaceholder?: string;
|
|
283
|
+
/**
|
|
284
|
+
* 评论输入框占位符
|
|
285
|
+
* @description 评论输入框的占位符文本,如果不提供则使用 titlePlaceholderContent
|
|
286
|
+
*/
|
|
287
|
+
placeholder?: string;
|
|
283
288
|
listItemRender?: (defaultDom: {
|
|
284
289
|
checkbox: React.JSX.Element | null;
|
|
285
290
|
mentionsUser: React.JSX.Element | null;
|
|
@@ -254,6 +254,7 @@ import React, { useCallback, useContext, useEffect, useImperativeHandle, useMemo
|
|
|
254
254
|
import { useRefFunction } from "../Hooks/useRefFunction";
|
|
255
255
|
import { BaseMarkdownEditor } from "../MarkdownEditor";
|
|
256
256
|
import { upLoadFileToServer } from "./AttachmentButton";
|
|
257
|
+
import { isMobileDevice } from "./AttachmentButton/utils";
|
|
257
258
|
import { AttachmentFileList } from "./AttachmentButton/AttachmentFileList";
|
|
258
259
|
import { getFileListFromDataTransferItems } from "./FilePaste";
|
|
259
260
|
import { useFileUploadManager } from "./FileUploadManager";
|
|
@@ -642,6 +643,10 @@ import { useVoiceInputManager } from "./VoiceInputManager";
|
|
|
642
643
|
var isEnter = e.key === 'Enter';
|
|
643
644
|
var isMod = e.ctrlKey || e.metaKey;
|
|
644
645
|
var isShift = e.shiftKey;
|
|
646
|
+
// 手机端禁用 Enter 键发送
|
|
647
|
+
if (isEnter && !isMod && !isShift && isMobileDevice()) {
|
|
648
|
+
return; // 让编辑器正常处理换行
|
|
649
|
+
}
|
|
645
650
|
// Enter 发送,Shift+Enter 换行
|
|
646
651
|
if (!isEnter || isMod) return;
|
|
647
652
|
if (isShift) return; // Shift+Enter 时让编辑器处理换行
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* 提供图表组件相关的 React Hooks
|
|
4
4
|
* @author Chart Plugin Team
|
|
5
5
|
*/
|
|
6
|
-
export type { ChartStatisticConfig, StatisticConfigType } from './useChartStatistic';
|
|
7
6
|
export { useChartDataFilter } from './useChartDataFilter';
|
|
7
|
+
export type { ChartStatisticConfig, StatisticConfigType, } from './useChartStatistic';
|
|
8
8
|
export { useChartStatistics } from './useChartStatistics';
|
|
9
9
|
export { useChartTheme } from './useChartTheme';
|
|
10
10
|
export { useResponsiveSize } from './useResponsiveSize';
|
|
@@ -304,4 +304,4 @@ export declare const isConfigEqual: (config1: any, config2: any) => boolean;
|
|
|
304
304
|
* @since 1.0.0
|
|
305
305
|
*/
|
|
306
306
|
export declare const hexToRgba: (hex: string, alpha: number) => string;
|
|
307
|
-
export { registerChartComponents, registerLineChartComponents,
|
|
307
|
+
export { registerBarChartComponents, registerChartComponents, registerLineChartComponents, } from './utils/registerChart';
|
|
@@ -462,4 +462,4 @@ var intl = new Intl.NumberFormat('en-US', {
|
|
|
462
462
|
return "rgba(".concat(r, ", ").concat(g, ", ").concat(b, ", ").concat(a, ")");
|
|
463
463
|
};
|
|
464
464
|
// 导出 Chart.js 注册相关函数
|
|
465
|
-
export { registerChartComponents, registerLineChartComponents
|
|
465
|
+
export { registerBarChartComponents, registerChartComponents, registerLineChartComponents } from "./utils/registerChart";
|