@ant-design/agentic-ui 2.29.10 → 2.29.12
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/MessagesContent/MarkdownPreview.js +1 -12
- package/dist/MarkdownEditor/editor/parser/parserMarkdownToSlateNode.js +4 -4
- package/dist/MarkdownEditor/editor/store.js +7 -4
- package/dist/MarkdownEditor/editor/utils/editorCommands.d.ts +1 -0
- package/dist/MarkdownEditor/editor/utils/editorCommands.js +230 -23
- package/package.json +2 -1
|
@@ -93,21 +93,11 @@ import { MessagesContext } from "./BubbleContext";
|
|
|
93
93
|
* ```
|
|
94
94
|
*/ export var MarkdownPreview = function(props) {
|
|
95
95
|
var _props_originData;
|
|
96
|
-
var content = props.content, extra = props.extra, typing = props.typing, htmlRef = props.htmlRef, fncProps = props.fncProps, docListNode = props.docListNode,
|
|
96
|
+
var content = props.content, extra = props.extra, typing = props.typing, htmlRef = props.htmlRef, fncProps = props.fncProps, docListNode = props.docListNode, beforeContent = props.beforeContent, afterContent = props.afterContent;
|
|
97
97
|
var MarkdownEditorRef = React.useRef(undefined);
|
|
98
98
|
var hidePadding = (useContext(MessagesContext) || {}).hidePadding;
|
|
99
99
|
var _ref = useContext(BubbleConfigContext) || {}, locale = _ref.locale, standalone = _ref.standalone;
|
|
100
100
|
var token = theme.useToken().token;
|
|
101
|
-
useEffect(function() {
|
|
102
|
-
if (isFinished) {
|
|
103
|
-
var _MarkdownEditorRef_current;
|
|
104
|
-
console.log('content', content);
|
|
105
|
-
(_MarkdownEditorRef_current = MarkdownEditorRef.current) === null || _MarkdownEditorRef_current === void 0 ? void 0 : _MarkdownEditorRef_current.store.setContent(parserMdToSchema(content).schema);
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
}, [
|
|
109
|
-
isFinished
|
|
110
|
-
]);
|
|
111
101
|
var isPaddingHidden = useMemo(function() {
|
|
112
102
|
return !!extra;
|
|
113
103
|
}, [
|
|
@@ -116,7 +106,6 @@ import { MessagesContext } from "./BubbleContext";
|
|
|
116
106
|
]);
|
|
117
107
|
useEffect(function() {
|
|
118
108
|
var _MarkdownEditorRef_current;
|
|
119
|
-
console.log("updatecontent", content);
|
|
120
109
|
var schema = parserMdToSchema(content).schema;
|
|
121
110
|
(_MarkdownEditorRef_current = MarkdownEditorRef.current) === null || _MarkdownEditorRef_current === void 0 ? void 0 : _MarkdownEditorRef_current.store.updateNodeList(schema);
|
|
122
111
|
}, [
|
|
@@ -190,10 +190,10 @@ var parseCache = new Map();
|
|
|
190
190
|
var configStr = config ? JSON.stringify(config) : '';
|
|
191
191
|
var pluginsCount = (plugins === null || plugins === void 0 ? void 0 : plugins.length) || 0;
|
|
192
192
|
var configHash = simpleHash("".concat(configStr, "_").concat(pluginsCount));
|
|
193
|
-
return mergedBlocks.map(function(content) {
|
|
193
|
+
return mergedBlocks.map(function(content, index) {
|
|
194
194
|
return {
|
|
195
195
|
content: content,
|
|
196
|
-
hash: "".concat(simpleHash(content), "_").concat(configHash)
|
|
196
|
+
hash: "".concat(simpleHash(content), "_").concat(configHash, "_").concat(index)
|
|
197
197
|
};
|
|
198
198
|
});
|
|
199
199
|
};
|
|
@@ -593,9 +593,9 @@ var removeAnswerTags = function(text) {
|
|
|
593
593
|
var blockHash = ((_blocks_ = blocks[0]) === null || _blocks_ === void 0 ? void 0 : _blocks_.hash) || simpleHash(md || '');
|
|
594
594
|
// 为 schema 元素添加 hash
|
|
595
595
|
return {
|
|
596
|
-
schema: result.schema.map(function(s) {
|
|
596
|
+
schema: result.schema.map(function(s, index) {
|
|
597
597
|
return _object_spread_props(_object_spread({}, s), {
|
|
598
|
-
hash: blockHash
|
|
598
|
+
hash: blockHash + '-' + index
|
|
599
599
|
});
|
|
600
600
|
}),
|
|
601
601
|
links: result.links
|
|
@@ -1522,7 +1522,7 @@ export var EditorStoreContext = createContext(null);
|
|
|
1522
1522
|
*/ function executeOperations(operations) {
|
|
1523
1523
|
var editor = this._editor.current;
|
|
1524
1524
|
if (!editor) return;
|
|
1525
|
-
//
|
|
1525
|
+
// 使用批处理模式执行所有操作,避免中间状态导致路径变化
|
|
1526
1526
|
Editor.withoutNormalizing(editor, function() {
|
|
1527
1527
|
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
1528
1528
|
try {
|
|
@@ -1532,9 +1532,12 @@ export var EditorStoreContext = createContext(null);
|
|
|
1532
1532
|
switch(op.type){
|
|
1533
1533
|
case 'insert':
|
|
1534
1534
|
if (op.node && editor.hasPath(Path.parent(op.path))) {
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1535
|
+
// 检查路径是否仍然有效,避免重复插入
|
|
1536
|
+
if (!editor.hasPath(op.path)) {
|
|
1537
|
+
Transforms.insertNodes(editor, op.node, {
|
|
1538
|
+
at: op.path
|
|
1539
|
+
});
|
|
1540
|
+
}
|
|
1538
1541
|
}
|
|
1539
1542
|
break;
|
|
1540
1543
|
case 'remove':
|
|
@@ -84,7 +84,7 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
84
84
|
if (n === "Map" || n === "Set") return Array.from(n);
|
|
85
85
|
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
|
|
86
86
|
}
|
|
87
|
-
import { Editor, Element, Node, Path, Range, Transforms } from "slate";
|
|
87
|
+
import { Editor, Element, Node, Path, Point, Range, Text, Transforms } from "slate";
|
|
88
88
|
import { NativeTableEditor } from "../../utils/native-table";
|
|
89
89
|
import { getListType, isListType } from "../plugins/withListsPlugin";
|
|
90
90
|
import { EditorUtils } from "./editorUtils";
|
|
@@ -273,21 +273,249 @@ import { EditorUtils } from "./editorUtils";
|
|
|
273
273
|
});
|
|
274
274
|
}
|
|
275
275
|
}
|
|
276
|
+
/**
|
|
277
|
+
* 查找选区内的块级节点
|
|
278
|
+
*
|
|
279
|
+
* @param editor - 编辑器实例
|
|
280
|
+
* @param selection - 当前选区
|
|
281
|
+
* @returns 找到的块级节点数组,每个元素包含 [node, path]
|
|
282
|
+
*/ function findBlockNodesInSelection(editor, selection) {
|
|
283
|
+
if (!selection) {
|
|
284
|
+
return [];
|
|
285
|
+
}
|
|
286
|
+
var blockNodes = Array.from(Editor.nodes(editor, {
|
|
287
|
+
at: selection,
|
|
288
|
+
match: function(n) {
|
|
289
|
+
return Element.isElement(n) && !Editor.isInline(editor, n) && [
|
|
290
|
+
'paragraph',
|
|
291
|
+
'head'
|
|
292
|
+
].includes(n.type);
|
|
293
|
+
}
|
|
294
|
+
}));
|
|
295
|
+
return blockNodes;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* 处理选区并设置标题格式
|
|
299
|
+
*
|
|
300
|
+
* @param editor - 编辑器实例
|
|
301
|
+
* @param selection - 选区范围
|
|
302
|
+
* @param level - 标题级别(1-3)
|
|
303
|
+
*/ function processSelectionForHeading(editor, selection, level) {
|
|
304
|
+
var _Range_edges = _sliced_to_array(Range.edges(selection), 2), selStart = _Range_edges[0], selEnd = _Range_edges[1];
|
|
305
|
+
// 找到所有涉及选中文本的段落/标题节点
|
|
306
|
+
var blockNodes = findBlockNodesInSelection(editor, selection);
|
|
307
|
+
if (blockNodes.length === 0) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
// 使用 withoutNormalizing 确保原子性操作
|
|
311
|
+
Editor.withoutNormalizing(editor, function() {
|
|
312
|
+
// 按路径倒序处理,从后往前,避免路径变化影响
|
|
313
|
+
var sortedNodes = _to_consumable_array(blockNodes).sort(function(a, b) {
|
|
314
|
+
return Path.compare(b[1], a[1]);
|
|
315
|
+
});
|
|
316
|
+
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
317
|
+
try {
|
|
318
|
+
for(var _iterator = sortedNodes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
319
|
+
var _step_value = _sliced_to_array(_step.value, 2), path = _step_value[1];
|
|
320
|
+
if (!Editor.hasPath(editor, path)) {
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
var nodeStart = Editor.start(editor, path);
|
|
324
|
+
var nodeEnd = Editor.end(editor, path);
|
|
325
|
+
// 计算节点内的实际选区范围
|
|
326
|
+
var actualStart = Point.isBefore(selStart, nodeStart) ? nodeStart : Point.isAfter(selStart, nodeEnd) ? nodeEnd : selStart;
|
|
327
|
+
var actualEnd = Point.isAfter(selEnd, nodeEnd) ? nodeEnd : Point.isBefore(selEnd, nodeStart) ? nodeStart : selEnd;
|
|
328
|
+
// 检查是否选中了整个节点
|
|
329
|
+
var isWholeNodeSelected = (Point.isBefore(selStart, nodeStart) || Point.equals(selStart, nodeStart)) && (Point.isAfter(selEnd, nodeEnd) || Point.equals(selEnd, nodeEnd));
|
|
330
|
+
if (isWholeNodeSelected) {
|
|
331
|
+
// 直接转换整个节点
|
|
332
|
+
Transforms.setNodes(editor, {
|
|
333
|
+
type: 'head',
|
|
334
|
+
level: level
|
|
335
|
+
}, {
|
|
336
|
+
at: path
|
|
337
|
+
});
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
// 如果选区不在节点内,跳过
|
|
341
|
+
if (Point.isAfter(actualStart, actualEnd) || Point.equals(actualStart, actualEnd) || Point.isBefore(actualStart, nodeStart) || Point.isAfter(actualEnd, nodeEnd)) {
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
// 情况1: 选中了整个节点(从开始到结束)
|
|
345
|
+
if (Point.equals(actualStart, nodeStart) && Point.equals(actualEnd, nodeEnd)) {
|
|
346
|
+
Transforms.setNodes(editor, {
|
|
347
|
+
type: 'head',
|
|
348
|
+
level: level
|
|
349
|
+
}, {
|
|
350
|
+
at: path
|
|
351
|
+
});
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
// 情况2: 只选中了节点的一部分,需要拆分
|
|
355
|
+
var isAtStart = Point.equals(actualStart, nodeStart);
|
|
356
|
+
var isAtEnd = Point.equals(actualEnd, nodeEnd);
|
|
357
|
+
if (isAtStart && isAtEnd) {
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
// 获取原节点的属性
|
|
361
|
+
var originalNode = Node.get(editor, path);
|
|
362
|
+
if (!Element.isElement(originalNode)) {
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
if (isAtStart) {
|
|
366
|
+
// 选中在开始位置:拆分成两个节点(选中部分 + 剩余部分)
|
|
367
|
+
// 在 actualEnd 位置拆分节点
|
|
368
|
+
Transforms.splitNodes(editor, {
|
|
369
|
+
at: actualEnd
|
|
370
|
+
});
|
|
371
|
+
// 拆分后,原节点包含选中部分,新节点包含剩余部分
|
|
372
|
+
// 将原节点(选中部分)转换为标题
|
|
373
|
+
Transforms.setNodes(editor, {
|
|
374
|
+
type: 'head',
|
|
375
|
+
level: level
|
|
376
|
+
}, {
|
|
377
|
+
at: path
|
|
378
|
+
});
|
|
379
|
+
} else if (isAtEnd) {
|
|
380
|
+
// 选中在结束位置:拆分成两个节点(前面部分 + 选中部分)
|
|
381
|
+
// 在 actualStart 位置拆分节点
|
|
382
|
+
Transforms.splitNodes(editor, {
|
|
383
|
+
at: actualStart
|
|
384
|
+
});
|
|
385
|
+
// 拆分后,原节点包含前面部分,新节点包含选中部分
|
|
386
|
+
// 将新节点(选中部分)转换为标题
|
|
387
|
+
var nextPath = Path.next(path);
|
|
388
|
+
if (Editor.hasPath(editor, nextPath)) {
|
|
389
|
+
Transforms.setNodes(editor, {
|
|
390
|
+
type: 'head',
|
|
391
|
+
level: level
|
|
392
|
+
}, {
|
|
393
|
+
at: nextPath
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
} else {
|
|
397
|
+
// 选中在中间位置:拆分成三个节点(前面部分 + 选中部分 + 后面部分)
|
|
398
|
+
// 计算选中部分的长度(字符偏移量)
|
|
399
|
+
var selectionOffset = actualEnd.offset - actualStart.offset;
|
|
400
|
+
// 第一步:在 actualStart 位置拆分节点
|
|
401
|
+
Transforms.splitNodes(editor, {
|
|
402
|
+
at: actualStart
|
|
403
|
+
});
|
|
404
|
+
// 拆分后,原节点包含前面部分,新节点包含选中部分和后面部分
|
|
405
|
+
// 新节点的路径是 Path.next(path)
|
|
406
|
+
var middlePath = Path.next(path);
|
|
407
|
+
if (!Editor.hasPath(editor, middlePath)) {
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
// 第二步:在新节点内计算拆分点
|
|
411
|
+
// 使用偏移量来计算:在新节点开始位置 + 选中部分的长度
|
|
412
|
+
// 需要找到对应的文本节点和偏移量
|
|
413
|
+
var splitPoint = null;
|
|
414
|
+
// 遍历新节点内的文本节点,计算正确的拆分点
|
|
415
|
+
var textNodes = Array.from(Editor.nodes(editor, {
|
|
416
|
+
at: middlePath,
|
|
417
|
+
match: function(n) {
|
|
418
|
+
return Text.isText(n);
|
|
419
|
+
}
|
|
420
|
+
}));
|
|
421
|
+
var currentOffset = 0;
|
|
422
|
+
var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
|
|
423
|
+
try {
|
|
424
|
+
for(var _iterator1 = textNodes[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
|
|
425
|
+
var _step_value1 = _sliced_to_array(_step1.value, 2), textNode = _step_value1[0], textPath = _step_value1[1];
|
|
426
|
+
if (!Text.isText(textNode)) {
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
var text = textNode.text;
|
|
430
|
+
if (typeof text !== 'string') {
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
var textLength = text.length;
|
|
434
|
+
var nextOffset = currentOffset + textLength;
|
|
435
|
+
// 如果选中结束位置在这个文本节点内
|
|
436
|
+
if (selectionOffset <= nextOffset) {
|
|
437
|
+
var offsetInText = selectionOffset - currentOffset;
|
|
438
|
+
splitPoint = {
|
|
439
|
+
path: textPath,
|
|
440
|
+
offset: offsetInText
|
|
441
|
+
};
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
currentOffset = nextOffset;
|
|
445
|
+
}
|
|
446
|
+
} catch (err) {
|
|
447
|
+
_didIteratorError1 = true;
|
|
448
|
+
_iteratorError1 = err;
|
|
449
|
+
} finally{
|
|
450
|
+
try {
|
|
451
|
+
if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
|
|
452
|
+
_iterator1.return();
|
|
453
|
+
}
|
|
454
|
+
} finally{
|
|
455
|
+
if (_didIteratorError1) {
|
|
456
|
+
throw _iteratorError1;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
// 如果找不到拆分点,使用新节点的结束位置
|
|
461
|
+
if (!splitPoint) {
|
|
462
|
+
var middleNodeEnd = Editor.end(editor, middlePath);
|
|
463
|
+
splitPoint = middleNodeEnd;
|
|
464
|
+
}
|
|
465
|
+
// 在新节点内的 splitPoint 位置拆分
|
|
466
|
+
Transforms.splitNodes(editor, {
|
|
467
|
+
at: splitPoint
|
|
468
|
+
});
|
|
469
|
+
// 拆分后,middlePath 包含选中部分,下一个节点包含后面部分
|
|
470
|
+
// 将 middlePath(选中部分)转换为标题
|
|
471
|
+
Transforms.setNodes(editor, {
|
|
472
|
+
type: 'head',
|
|
473
|
+
level: level
|
|
474
|
+
}, {
|
|
475
|
+
at: middlePath
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
} catch (err) {
|
|
480
|
+
_didIteratorError = true;
|
|
481
|
+
_iteratorError = err;
|
|
482
|
+
} finally{
|
|
483
|
+
try {
|
|
484
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
485
|
+
_iterator.return();
|
|
486
|
+
}
|
|
487
|
+
} finally{
|
|
488
|
+
if (_didIteratorError) {
|
|
489
|
+
throw _iteratorError;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
}
|
|
276
495
|
/**
|
|
277
496
|
* 设置标题级别
|
|
278
497
|
*
|
|
279
498
|
* 将当前段落或标题节点转换为指定级别的标题。
|
|
280
499
|
* 如果级别为4,则转换为普通段落。
|
|
500
|
+
* 如果存在选中文本,则只将选中的部分转换为标题,并拆分段落。
|
|
281
501
|
*
|
|
282
502
|
* @param editor Slate 编辑器实例
|
|
283
503
|
* @param level 标题级别(1-3)或4(表示普通段落)
|
|
284
504
|
*/ export function setHeading(editor, level) {
|
|
285
505
|
var _node_;
|
|
286
|
-
var
|
|
506
|
+
var selection = editor.selection;
|
|
507
|
+
// 如果级别为4,转换为段落
|
|
287
508
|
if (level === 4) {
|
|
288
509
|
convertToParagraph(editor);
|
|
289
510
|
return;
|
|
290
511
|
}
|
|
512
|
+
// 如果有非折叠的选区,处理选中文本
|
|
513
|
+
if (selection && !Range.isCollapsed(selection)) {
|
|
514
|
+
processSelectionForHeading(editor, selection, level);
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
// 如果没有选区,保持原有行为:转换整个节点
|
|
518
|
+
var _getCurrentNodes = _sliced_to_array(getCurrentNodes(editor), 1), node = _getCurrentNodes[0];
|
|
291
519
|
if (node && [
|
|
292
520
|
'paragraph',
|
|
293
521
|
'head'
|
|
@@ -301,27 +529,6 @@ import { EditorUtils } from "./editorUtils";
|
|
|
301
529
|
}
|
|
302
530
|
}
|
|
303
531
|
export { convertToParagraph };
|
|
304
|
-
/**
|
|
305
|
-
* 查找选区内的块级节点
|
|
306
|
-
*
|
|
307
|
-
* @param editor - 编辑器实例
|
|
308
|
-
* @param selection - 当前选区
|
|
309
|
-
* @returns 找到的块级节点数组,每个元素包含 [node, path]
|
|
310
|
-
*/ function findBlockNodesInSelection(editor, selection) {
|
|
311
|
-
if (!selection) {
|
|
312
|
-
return [];
|
|
313
|
-
}
|
|
314
|
-
var blockNodes = Array.from(Editor.nodes(editor, {
|
|
315
|
-
at: selection,
|
|
316
|
-
match: function(n) {
|
|
317
|
-
return Element.isElement(n) && !Editor.isInline(editor, n) && [
|
|
318
|
-
'paragraph',
|
|
319
|
-
'head'
|
|
320
|
-
].includes(n.type);
|
|
321
|
-
}
|
|
322
|
-
}));
|
|
323
|
-
return blockNodes;
|
|
324
|
-
}
|
|
325
532
|
/**
|
|
326
533
|
* 将标题节点转换为段落节点
|
|
327
534
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ant-design/agentic-ui",
|
|
3
|
-
"version": "2.29.
|
|
3
|
+
"version": "2.29.12",
|
|
4
4
|
"description": "面向智能体的 UI 组件库,提供多步推理可视化、工具调用展示、任务执行协同等 Agentic UI 能力",
|
|
5
5
|
"repository": "git@github.com:ant-design/agentic-ui.git",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"lint:css": "stylelint \"{src,test}/**/*.{css,less}\"",
|
|
23
23
|
"lint:es": "eslint \"{src,test}/**/*.{js,jsx,ts,tsx}\"",
|
|
24
24
|
"prepare": "husky install && dumi setup",
|
|
25
|
+
"prepublishOnly": "father doctor && pnpm run test && pnpm run build",
|
|
25
26
|
"prettier": "prettier --write \"{src,docs,test}/**/*.{js,jsx,ts,tsx,css,less,json,md}\"",
|
|
26
27
|
"preview": "pnpm dumi preview",
|
|
27
28
|
"report:demo": "node scripts/generateDemoReport.js",
|