@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.
@@ -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, isFinished = props.isFinished, beforeContent = props.beforeContent, afterContent = props.afterContent;
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
- Transforms.insertNodes(editor, op.node, {
1536
- at: op.path
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':
@@ -59,6 +59,7 @@ declare function convertToParagraph(editor: Editor): void;
59
59
  *
60
60
  * 将当前段落或标题节点转换为指定级别的标题。
61
61
  * 如果级别为4,则转换为普通段落。
62
+ * 如果存在选中文本,则只将选中的部分转换为标题,并拆分段落。
62
63
  *
63
64
  * @param editor Slate 编辑器实例
64
65
  * @param level 标题级别(1-3)或4(表示普通段落)
@@ -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 _getCurrentNodes = _sliced_to_array(getCurrentNodes(editor), 1), node = _getCurrentNodes[0];
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.10",
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",