@ant-design/agentic-ui 2.16.1 → 2.18.0
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/Image/index.js +17 -5
- package/dist/MarkdownEditor/editor/elements/Media.js +61 -9
- package/dist/MarkdownEditor/editor/parser/parserMarkdownToSlateNode.js +166 -46
- package/dist/MarkdownEditor/editor/style.js +5 -0
- package/dist/Plugins/chart/components/ChartFilter/ChartFilter.d.ts +1 -1
- package/dist/Plugins/chart/components/ChartFilter/ChartFilter.js +12 -166
- package/package.json +1 -1
|
@@ -248,7 +248,7 @@ function _ts_generator(thisArg, body) {
|
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
250
|
import { BlockOutlined, DeleteFilled, ExclamationCircleOutlined, LoadingOutlined } from "@ant-design/icons";
|
|
251
|
-
import { Image, Modal, Popover, Space } from "antd";
|
|
251
|
+
import { Image, Modal, Popover, Skeleton, Space } from "antd";
|
|
252
252
|
import React, { useCallback, useContext, useLayoutEffect, useMemo, useRef } from "react";
|
|
253
253
|
import { useDebounceFn } from "@ant-design/pro-components";
|
|
254
254
|
import { Rnd } from "react-rnd";
|
|
@@ -315,7 +315,8 @@ import { getMediaType } from "../../utils/dom";
|
|
|
315
315
|
})));
|
|
316
316
|
}
|
|
317
317
|
return /*#__PURE__*/ React.createElement("div", {
|
|
318
|
-
"data-testid": "image-container"
|
|
318
|
+
"data-testid": "image-container",
|
|
319
|
+
"data-be": "image-container"
|
|
319
320
|
}, /*#__PURE__*/ React.createElement(Image, _object_spread_props(_object_spread({}, props), {
|
|
320
321
|
width: Number(props.width) || props.width || 400,
|
|
321
322
|
onError: function() {
|
|
@@ -477,7 +478,7 @@ import { getMediaType } from "../../utils/dom";
|
|
|
477
478
|
};
|
|
478
479
|
export function EditorImage(param) {
|
|
479
480
|
var element = param.element, attributes = param.attributes, children = param.children;
|
|
480
|
-
var _state;
|
|
481
|
+
var _state, _element_otherProps;
|
|
481
482
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
482
483
|
var _useSelStatus = _sliced_to_array(useSelStatus(element), 2), _ = _useSelStatus[0], path = _useSelStatus[1];
|
|
483
484
|
var _useEditorStore = useEditorStore(), markdownEditorRef = _useEditorStore.markdownEditorRef, readonly = _useEditorStore.readonly;
|
|
@@ -550,7 +551,15 @@ export function EditorImage(param) {
|
|
|
550
551
|
element === null || element === void 0 ? void 0 : element.url
|
|
551
552
|
]);
|
|
552
553
|
var imageDom = useMemo(function() {
|
|
553
|
-
var _state, _state1;
|
|
554
|
+
var _element_otherProps, _state, _state1;
|
|
555
|
+
// 检查是否为不完整的图片(loading 状态)
|
|
556
|
+
var isLoading = (element === null || element === void 0 ? void 0 : element.loading) || (element === null || element === void 0 ? void 0 : (_element_otherProps = element.otherProps) === null || _element_otherProps === void 0 ? void 0 : _element_otherProps.loading);
|
|
557
|
+
if (isLoading) {
|
|
558
|
+
// 显示 loading 状态的占位符
|
|
559
|
+
return /*#__PURE__*/ React.createElement(Skeleton.Image, {
|
|
560
|
+
active: true
|
|
561
|
+
});
|
|
562
|
+
}
|
|
554
563
|
// 如果图片加载失败,显示为链接
|
|
555
564
|
if (!state().loadSuccess) {
|
|
556
565
|
var _state2, _state3;
|
|
@@ -622,7 +631,10 @@ export function EditorImage(param) {
|
|
|
622
631
|
(_state = state()) === null || _state === void 0 ? void 0 : _state.url,
|
|
623
632
|
readonly,
|
|
624
633
|
state().selected,
|
|
625
|
-
state().loadSuccess
|
|
634
|
+
state().loadSuccess,
|
|
635
|
+
element === null || element === void 0 ? void 0 : element.loading,
|
|
636
|
+
element === null || element === void 0 ? void 0 : (_element_otherProps = element.otherProps) === null || _element_otherProps === void 0 ? void 0 : _element_otherProps.loading,
|
|
637
|
+
element === null || element === void 0 ? void 0 : element.rawMarkdown
|
|
626
638
|
]);
|
|
627
639
|
return /*#__PURE__*/ React.createElement("div", _object_spread_props(_object_spread({}, attributes), {
|
|
628
640
|
"data-be": "image",
|
|
@@ -224,7 +224,7 @@ function _ts_generator(thisArg, body) {
|
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
226
|
import { DeleteFilled, ExclamationCircleOutlined, EyeOutlined, LoadingOutlined } from "@ant-design/icons";
|
|
227
|
-
import { Modal, Popover } from "antd";
|
|
227
|
+
import { Modal, Popover, Skeleton } from "antd";
|
|
228
228
|
import React, { useCallback, useContext, useLayoutEffect, useMemo, useRef } from "react";
|
|
229
229
|
import { useDebounceFn } from "@ant-design/pro-components";
|
|
230
230
|
import { Rnd } from "react-rnd";
|
|
@@ -379,7 +379,7 @@ import { ImageAndError } from "./Image";
|
|
|
379
379
|
};
|
|
380
380
|
export function Media(param) {
|
|
381
381
|
var element = param.element, attributes = param.attributes, children = param.children;
|
|
382
|
-
var _state, _state1;
|
|
382
|
+
var _state, _element_otherProps, _state1, _element_otherProps1;
|
|
383
383
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
384
384
|
var _useSelStatus = _sliced_to_array(useSelStatus(element), 2), _ = _useSelStatus[0], path = _useSelStatus[1];
|
|
385
385
|
var _useEditorStore = useEditorStore(), markdownEditorRef = _useEditorStore.markdownEditorRef, readonly = _useEditorStore.readonly;
|
|
@@ -483,8 +483,16 @@ export function Media(param) {
|
|
|
483
483
|
element === null || element === void 0 ? void 0 : element.url
|
|
484
484
|
]);
|
|
485
485
|
var imageDom = useMemo(function() {
|
|
486
|
-
var _state, _state1;
|
|
486
|
+
var _element_otherProps, _state, _state1;
|
|
487
487
|
if (state().type !== 'image' && state().type !== 'other') return null;
|
|
488
|
+
// 检查是否为不完整的图片(loading 状态)
|
|
489
|
+
var isLoading = (element === null || element === void 0 ? void 0 : element.loading) || (element === null || element === void 0 ? void 0 : (_element_otherProps = element.otherProps) === null || _element_otherProps === void 0 ? void 0 : _element_otherProps.loading);
|
|
490
|
+
if (isLoading) {
|
|
491
|
+
// 显示 loading 状态的占位符
|
|
492
|
+
return /*#__PURE__*/ React.createElement(Skeleton.Image, {
|
|
493
|
+
active: true
|
|
494
|
+
});
|
|
495
|
+
}
|
|
488
496
|
return !readonly ? /*#__PURE__*/ React.createElement(ResizeImage, {
|
|
489
497
|
defaultSize: {
|
|
490
498
|
width: element.width,
|
|
@@ -528,11 +536,24 @@ export function Media(param) {
|
|
|
528
536
|
state().type,
|
|
529
537
|
(_state = state()) === null || _state === void 0 ? void 0 : _state.url,
|
|
530
538
|
readonly,
|
|
531
|
-
state().selected
|
|
539
|
+
state().selected,
|
|
540
|
+
element === null || element === void 0 ? void 0 : element.loading,
|
|
541
|
+
element === null || element === void 0 ? void 0 : (_element_otherProps = element.otherProps) === null || _element_otherProps === void 0 ? void 0 : _element_otherProps.loading,
|
|
542
|
+
element === null || element === void 0 ? void 0 : element.rawMarkdown
|
|
532
543
|
]);
|
|
533
544
|
var mediaElement = useMemo(function() {
|
|
545
|
+
var _element_otherProps, _element_otherProps1;
|
|
546
|
+
// 检查是否为不完整的媒体(loading 状态)
|
|
547
|
+
var isLoading = (element === null || element === void 0 ? void 0 : element.loading) || (element === null || element === void 0 ? void 0 : (_element_otherProps = element.otherProps) === null || _element_otherProps === void 0 ? void 0 : _element_otherProps.loading);
|
|
548
|
+
var rawMarkdown = (element === null || element === void 0 ? void 0 : element.rawMarkdown) || (element === null || element === void 0 ? void 0 : (_element_otherProps1 = element.otherProps) === null || _element_otherProps1 === void 0 ? void 0 : _element_otherProps1.rawMarkdown);
|
|
534
549
|
if (state().type === 'video') {
|
|
535
550
|
var _state;
|
|
551
|
+
// 如果是 loading 状态,显示 loading 占位符
|
|
552
|
+
if (isLoading) {
|
|
553
|
+
return /*#__PURE__*/ React.createElement(Skeleton.Image, {
|
|
554
|
+
active: true
|
|
555
|
+
});
|
|
556
|
+
}
|
|
536
557
|
if (!state().loadSuccess) {
|
|
537
558
|
var _state1, _state2;
|
|
538
559
|
return /*#__PURE__*/ React.createElement("a", {
|
|
@@ -586,6 +607,34 @@ export function Media(param) {
|
|
|
586
607
|
}
|
|
587
608
|
if (state().type === 'audio') {
|
|
588
609
|
var _state3;
|
|
610
|
+
// 如果是 loading 状态,显示 loading 占位符
|
|
611
|
+
if (isLoading) {
|
|
612
|
+
return /*#__PURE__*/ React.createElement("div", {
|
|
613
|
+
style: {
|
|
614
|
+
display: 'inline-flex',
|
|
615
|
+
alignItems: 'center',
|
|
616
|
+
gap: '8px',
|
|
617
|
+
padding: '12px 16px',
|
|
618
|
+
border: '1px dashed #d9d9d9',
|
|
619
|
+
borderRadius: '6px',
|
|
620
|
+
backgroundColor: '#fafafa',
|
|
621
|
+
minWidth: '200px',
|
|
622
|
+
justifyContent: 'center'
|
|
623
|
+
}
|
|
624
|
+
}, /*#__PURE__*/ React.createElement(LoadingOutlined, {
|
|
625
|
+
style: {
|
|
626
|
+
color: '#1890ff',
|
|
627
|
+
fontSize: '16px'
|
|
628
|
+
},
|
|
629
|
+
spin: true
|
|
630
|
+
}), /*#__PURE__*/ React.createElement("span", {
|
|
631
|
+
style: {
|
|
632
|
+
color: '#666',
|
|
633
|
+
fontSize: '13px',
|
|
634
|
+
wordBreak: 'break-all'
|
|
635
|
+
}
|
|
636
|
+
}, rawMarkdown || (element === null || element === void 0 ? void 0 : element.alt) || '音频加载中...'));
|
|
637
|
+
}
|
|
589
638
|
if (!state().loadSuccess) {
|
|
590
639
|
var _state4, _state5;
|
|
591
640
|
return /*#__PURE__*/ React.createElement("a", {
|
|
@@ -629,7 +678,7 @@ export function Media(param) {
|
|
|
629
678
|
}, "Your browser does not support the", /*#__PURE__*/ React.createElement("code", null, "audio"), " element.");
|
|
630
679
|
}
|
|
631
680
|
if (state().type === 'attachment') {
|
|
632
|
-
var _state6, _element_alt, _element_alt1,
|
|
681
|
+
var _state6, _element_alt, _element_alt1, _element_otherProps2, _element_otherProps_collaborators, _element_otherProps3, _element_otherProps4;
|
|
633
682
|
return /*#__PURE__*/ React.createElement("div", {
|
|
634
683
|
style: {
|
|
635
684
|
padding: 12,
|
|
@@ -678,15 +727,15 @@ export function Media(param) {
|
|
|
678
727
|
display: 'flex',
|
|
679
728
|
justifyContent: 'space-between'
|
|
680
729
|
}
|
|
681
|
-
}, ((
|
|
682
|
-
displayList: ((
|
|
730
|
+
}, ((_element_otherProps2 = element.otherProps) === null || _element_otherProps2 === void 0 ? void 0 : _element_otherProps2.collaborators) ? /*#__PURE__*/ React.createElement("div", null, /*#__PURE__*/ React.createElement(AvatarList, {
|
|
731
|
+
displayList: ((_element_otherProps3 = element.otherProps) === null || _element_otherProps3 === void 0 ? void 0 : (_element_otherProps_collaborators = _element_otherProps3.collaborators) === null || _element_otherProps_collaborators === void 0 ? void 0 : _element_otherProps_collaborators.map(function(item) {
|
|
683
732
|
var _Object_keys, _Object_values;
|
|
684
733
|
return {
|
|
685
734
|
name: (_Object_keys = Object.keys(item)) === null || _Object_keys === void 0 ? void 0 : _Object_keys.at(0),
|
|
686
735
|
collaboratorNumber: ((_Object_values = Object.values(item)) === null || _Object_values === void 0 ? void 0 : _Object_values.at(0)) || 0
|
|
687
736
|
};
|
|
688
737
|
}).slice(0, 5)) || []
|
|
689
|
-
})) : /*#__PURE__*/ React.createElement("div", null), ((
|
|
738
|
+
})) : /*#__PURE__*/ React.createElement("div", null), ((_element_otherProps4 = element.otherProps) === null || _element_otherProps4 === void 0 ? void 0 : _element_otherProps4.updateTime) ? /*#__PURE__*/ React.createElement("div", {
|
|
690
739
|
style: {
|
|
691
740
|
color: 'rgba(0,0,0,0.45)',
|
|
692
741
|
fontSize: 12
|
|
@@ -711,7 +760,10 @@ export function Media(param) {
|
|
|
711
760
|
return null;
|
|
712
761
|
}, [
|
|
713
762
|
state().type,
|
|
714
|
-
(_state1 = state()) === null || _state1 === void 0 ? void 0 : _state1.url
|
|
763
|
+
(_state1 = state()) === null || _state1 === void 0 ? void 0 : _state1.url,
|
|
764
|
+
element === null || element === void 0 ? void 0 : element.loading,
|
|
765
|
+
element === null || element === void 0 ? void 0 : (_element_otherProps1 = element.otherProps) === null || _element_otherProps1 === void 0 ? void 0 : _element_otherProps1.loading,
|
|
766
|
+
element === null || element === void 0 ? void 0 : element.rawMarkdown
|
|
715
767
|
]);
|
|
716
768
|
return /*#__PURE__*/ React.createElement("div", attributes, /*#__PURE__*/ React.createElement("div", {
|
|
717
769
|
"data-be": "media",
|
|
@@ -157,6 +157,7 @@ var INLINE_MATH_SIMPLE_NUMBER_PATTERN = new RegExp("^[+-]?\\d+(?:\\.\\d+)?".conc
|
|
|
157
157
|
// HTML 转义和代码块检测相关的常量
|
|
158
158
|
var NOT_SPACE_START = /^\S*/;
|
|
159
159
|
var ENDING_NEWLINE = /\n$/;
|
|
160
|
+
var FENCED_CODE_REGEX = /^(`{3,}|~{3,})/;
|
|
160
161
|
var shouldTreatInlineMathAsText = function(rawValue) {
|
|
161
162
|
var trimmedValue = rawValue.trim();
|
|
162
163
|
if (!trimmedValue) {
|
|
@@ -715,66 +716,86 @@ export var decodeURIComponentUrl = function(url) {
|
|
|
715
716
|
'listItem',
|
|
716
717
|
'blockquote'
|
|
717
718
|
].includes(parent.type)) {
|
|
718
|
-
//
|
|
719
|
-
var
|
|
720
|
-
if (
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
719
|
+
// 检查是否为不完整的图片标记
|
|
720
|
+
var incompleteImageMatch = currentElement.value.match(/<incomplete-image\s+data-raw="([^"]+)"\s*\/?>/);
|
|
721
|
+
if (incompleteImageMatch) {
|
|
722
|
+
var rawMarkdown = decodeURIComponent(incompleteImageMatch[1]);
|
|
723
|
+
// 直接创建带有 loading 状态的图片节点(不通过 createMediaNode,因为 URL 为空)
|
|
724
|
+
el = EditorUtils.wrapperCardNode({
|
|
725
|
+
type: 'image',
|
|
726
|
+
url: '',
|
|
727
|
+
mediaType: 'image',
|
|
728
|
+
alt: rawMarkdown,
|
|
729
|
+
loading: true,
|
|
730
|
+
rawMarkdown: rawMarkdown,
|
|
726
731
|
children: [
|
|
727
732
|
{
|
|
728
|
-
text:
|
|
733
|
+
text: ''
|
|
729
734
|
}
|
|
730
735
|
]
|
|
731
|
-
};
|
|
736
|
+
});
|
|
732
737
|
} else {
|
|
733
|
-
// 检查是否为 <
|
|
734
|
-
var
|
|
735
|
-
if (
|
|
736
|
-
// 将 <
|
|
738
|
+
// 检查是否为 <think> 标签
|
|
739
|
+
var thinkElement = findThinkElement(currentElement.value);
|
|
740
|
+
if (thinkElement) {
|
|
741
|
+
// 将 <think> 标签转换为 think 类型的代码块
|
|
737
742
|
el = {
|
|
738
|
-
|
|
743
|
+
type: 'code',
|
|
744
|
+
language: 'think',
|
|
745
|
+
value: thinkElement.content,
|
|
746
|
+
children: [
|
|
747
|
+
{
|
|
748
|
+
text: thinkElement.content
|
|
749
|
+
}
|
|
750
|
+
]
|
|
739
751
|
};
|
|
740
752
|
} else {
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
753
|
+
// 检查是否为 <answer> 标签
|
|
754
|
+
var answerElement = findAnswerElement(currentElement.value);
|
|
755
|
+
if (answerElement) {
|
|
756
|
+
// 将 <answer> 标签的内容作为普通文本
|
|
745
757
|
el = {
|
|
746
|
-
|
|
747
|
-
children: [
|
|
748
|
-
{
|
|
749
|
-
text: ''
|
|
750
|
-
}
|
|
751
|
-
]
|
|
758
|
+
text: answerElement.content
|
|
752
759
|
};
|
|
753
|
-
} else if (currentElement.value.match(/^<\/(img|video|iframe)>/)) {
|
|
754
|
-
// 如果是媒体标签的结束标签,跳过处理
|
|
755
|
-
el = null;
|
|
756
760
|
} else {
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
type: 'code',
|
|
764
|
-
language: 'html',
|
|
765
|
-
render: true,
|
|
766
|
-
value: currentElement.value,
|
|
761
|
+
var mediaElement = findImageElement(currentElement.value);
|
|
762
|
+
if (mediaElement) {
|
|
763
|
+
el = createMediaNodeFromElement(mediaElement);
|
|
764
|
+
} else if (currentElement.value === '<br/>') {
|
|
765
|
+
el = {
|
|
766
|
+
type: 'paragraph',
|
|
767
767
|
children: [
|
|
768
768
|
{
|
|
769
|
-
text:
|
|
769
|
+
text: ''
|
|
770
770
|
}
|
|
771
771
|
]
|
|
772
772
|
};
|
|
773
|
+
} else if (currentElement.value.match(/^<\/(img|video|iframe)>/)) {
|
|
774
|
+
// 如果是媒体标签的结束标签,跳过处理
|
|
775
|
+
el = null;
|
|
773
776
|
} else {
|
|
774
|
-
//
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
777
|
+
// 检查是否为注释(注释需要特殊处理以提取配置)
|
|
778
|
+
var isComment = currentElement.value.trim().startsWith('<!--') && currentElement.value.trim().endsWith('-->');
|
|
779
|
+
// 检查是否为标准 HTML 元素或注释
|
|
780
|
+
if (isComment || isStandardHtmlElement(currentElement.value)) {
|
|
781
|
+
// 标准 HTML 元素或注释:按原逻辑处理
|
|
782
|
+
el = currentElement.value.match(/<\/?(table|div|ul|li|ol|p|strong)[^\n>]*?>/) ? htmlToFragmentList(currentElement.value, '') : {
|
|
783
|
+
type: 'code',
|
|
784
|
+
language: 'html',
|
|
785
|
+
render: true,
|
|
786
|
+
value: currentElement.value,
|
|
787
|
+
children: [
|
|
788
|
+
{
|
|
789
|
+
text: currentElement.value
|
|
790
|
+
}
|
|
791
|
+
]
|
|
792
|
+
};
|
|
793
|
+
} else {
|
|
794
|
+
// 非标准元素(如自定义标签):当作普通文本处理
|
|
795
|
+
el = {
|
|
796
|
+
text: currentElement.value
|
|
797
|
+
};
|
|
798
|
+
}
|
|
778
799
|
}
|
|
779
800
|
}
|
|
780
801
|
}
|
|
@@ -820,6 +841,25 @@ export var decodeURIComponentUrl = function(url) {
|
|
|
820
841
|
text: answerElement.content
|
|
821
842
|
};
|
|
822
843
|
}
|
|
844
|
+
// 检查是否为不完整的图片标记
|
|
845
|
+
var incompleteImageMatch = currentElement.value.match(/<incomplete-image\s+data-raw="([^"]+)"\s*\/?>/);
|
|
846
|
+
if (incompleteImageMatch) {
|
|
847
|
+
var rawMarkdown = decodeURIComponent(incompleteImageMatch[1]);
|
|
848
|
+
// 直接创建带有 loading 状态的图片节点(不通过 createMediaNode,因为 URL 为空)
|
|
849
|
+
return EditorUtils.wrapperCardNode({
|
|
850
|
+
type: 'image',
|
|
851
|
+
url: '',
|
|
852
|
+
mediaType: 'image',
|
|
853
|
+
alt: rawMarkdown,
|
|
854
|
+
loading: true,
|
|
855
|
+
rawMarkdown: rawMarkdown,
|
|
856
|
+
children: [
|
|
857
|
+
{
|
|
858
|
+
text: ''
|
|
859
|
+
}
|
|
860
|
+
]
|
|
861
|
+
});
|
|
862
|
+
}
|
|
823
863
|
// 检查是否为非标准 HTML 元素,如果是则直接当作文本
|
|
824
864
|
if (!isStandardHtmlElement(currentElement.value)) {
|
|
825
865
|
return {
|
|
@@ -1653,7 +1693,9 @@ var tableRegex = /^\|.*\|\s*\n\|[-:| ]+\|/m;
|
|
|
1653
1693
|
'menu',
|
|
1654
1694
|
'menuitem',
|
|
1655
1695
|
// 字体
|
|
1656
|
-
'font'
|
|
1696
|
+
'font',
|
|
1697
|
+
// 自定义标签(用于流式渲染)
|
|
1698
|
+
'incomplete-image'
|
|
1657
1699
|
]);
|
|
1658
1700
|
/**
|
|
1659
1701
|
* 检查 HTML 标签是否为标准元素
|
|
@@ -1694,6 +1736,78 @@ var tableRegex = /^\|.*\|\s*\n\|[-:| ]+\|/m;
|
|
|
1694
1736
|
*/ function preprocessThinkTags(markdown) {
|
|
1695
1737
|
return preprocessSpecialTags(markdown, 'think');
|
|
1696
1738
|
}
|
|
1739
|
+
/**
|
|
1740
|
+
* 检测不完整的图片标记
|
|
1741
|
+
* 参考 useStreaming 中的逻辑,检测类似  {
|
|
1745
|
+
// 匹配不完整的图片语法:
|
|
1746
|
+
// 1. ![ 开始但还没有 ]
|
|
1747
|
+
// 2. ![text] 开始但还没有 (
|
|
1748
|
+
// 3. 
|
|
1749
|
+
var incompleteImagePatterns = [
|
|
1750
|
+
/^!\[[^\]\r\n]{0,1000}$/,
|
|
1751
|
+
/^!\[[^\r\n]{0,1000}\]\(*[^)\r\n]{0,1000}$/
|
|
1752
|
+
];
|
|
1753
|
+
return incompleteImagePatterns.some(function(pattern) {
|
|
1754
|
+
return pattern.test(markdown);
|
|
1755
|
+
});
|
|
1756
|
+
}
|
|
1757
|
+
/**
|
|
1758
|
+
* 预处理不完整的图片标记,将其转换为特殊的 HTML 标签
|
|
1759
|
+
* @param markdown - 原始 Markdown 字符串
|
|
1760
|
+
* @returns 处理后的 Markdown 字符串
|
|
1761
|
+
*/ function preprocessIncompleteImages(markdown) {
|
|
1762
|
+
if (!markdown) return markdown;
|
|
1763
|
+
// 按行处理,避免在代码块中处理
|
|
1764
|
+
var lines = markdown.split('\n');
|
|
1765
|
+
var inCodeBlock = false;
|
|
1766
|
+
var codeBlockFence = '';
|
|
1767
|
+
var codeBlockFenceLen = 0;
|
|
1768
|
+
var processedLines = lines.map(function(line) {
|
|
1769
|
+
// 检测代码块开始/结束
|
|
1770
|
+
var fenceMatch = line.match(FENCED_CODE_REGEX);
|
|
1771
|
+
if (fenceMatch) {
|
|
1772
|
+
var currentFence = fenceMatch[1];
|
|
1773
|
+
var char = currentFence[0];
|
|
1774
|
+
var len = currentFence.length;
|
|
1775
|
+
if (!inCodeBlock) {
|
|
1776
|
+
inCodeBlock = true;
|
|
1777
|
+
codeBlockFence = char;
|
|
1778
|
+
codeBlockFenceLen = len;
|
|
1779
|
+
} else if (char === codeBlockFence && len >= codeBlockFenceLen) {
|
|
1780
|
+
inCodeBlock = false;
|
|
1781
|
+
codeBlockFence = '';
|
|
1782
|
+
codeBlockFenceLen = 0;
|
|
1783
|
+
}
|
|
1784
|
+
return line;
|
|
1785
|
+
}
|
|
1786
|
+
// 如果在代码块中,不处理
|
|
1787
|
+
if (inCodeBlock) {
|
|
1788
|
+
return line;
|
|
1789
|
+
}
|
|
1790
|
+
// 检测不完整的图片标记
|
|
1791
|
+
// 匹配行尾的不完整图片语法(避免匹配完整的图片)
|
|
1792
|
+
var trimmedLine = line.trim();
|
|
1793
|
+
// 如果整行就是一个不完整的图片标记
|
|
1794
|
+
if (isIncompleteImage(trimmedLine)) {
|
|
1795
|
+
var encodedRaw = encodeURIComponent(trimmedLine);
|
|
1796
|
+
return '<incomplete-image data-raw="'.concat(encodedRaw, '" />');
|
|
1797
|
+
}
|
|
1798
|
+
// 检测行内不完整的图片标记(在行尾)
|
|
1799
|
+
// 使用负向前瞻确保不是完整图片的一部分
|
|
1800
|
+
return line.replace(/(!\[[^\]]*\]?\(?[^)]*)$/, function(match) {
|
|
1801
|
+
// 检查是否是不完整的图片
|
|
1802
|
+
if (isIncompleteImage(match.trim())) {
|
|
1803
|
+
var encodedRaw = encodeURIComponent(match.trim());
|
|
1804
|
+
return '<incomplete-image data-raw="'.concat(encodedRaw, '" />');
|
|
1805
|
+
}
|
|
1806
|
+
return match;
|
|
1807
|
+
});
|
|
1808
|
+
});
|
|
1809
|
+
return processedLines.join('\n');
|
|
1810
|
+
}
|
|
1697
1811
|
/**
|
|
1698
1812
|
* 预处理所有非标准 HTML 标签,提取其内容(删除标签本身)
|
|
1699
1813
|
* @param markdown - 原始 Markdown 字符串
|
|
@@ -1705,7 +1819,12 @@ var tableRegex = /^\|.*\|\s*\n\|[-:| ]+\|/m;
|
|
|
1705
1819
|
while(hasNonStandardTags){
|
|
1706
1820
|
var before = result;
|
|
1707
1821
|
// 匹配所有 HTML 标签对:<tagname>content</tagname>
|
|
1822
|
+
// 注意:跳过 incomplete-image 标签(它是自闭合标签,需要特殊处理)
|
|
1708
1823
|
result = result.replace(/<(\w+)>([\s\S]*?)<\/\1>/g, function(match, tagName, content) {
|
|
1824
|
+
// 保护 incomplete-image 标签(虽然它是自闭合的,但为了安全起见)
|
|
1825
|
+
if (tagName.toLowerCase() === 'incomplete-image') {
|
|
1826
|
+
return match;
|
|
1827
|
+
}
|
|
1709
1828
|
// 检查是否为标准 HTML 元素
|
|
1710
1829
|
if (STANDARD_HTML_ELEMENTS.has(tagName.toLowerCase())) {
|
|
1711
1830
|
// 标准元素保持不变
|
|
@@ -1765,9 +1884,10 @@ function preprocessMarkdownTableNewlines(markdown) {
|
|
|
1765
1884
|
* @returns 一个包含解析后的元素数组和链接信息的对象
|
|
1766
1885
|
*/ key: "parse",
|
|
1767
1886
|
value: function parse(md) {
|
|
1768
|
-
// 先预处理 <think>
|
|
1887
|
+
// 先预处理 <think> 标签,再预处理不完整的图片,然后预处理其他非标准 HTML 标签,最后处理表格换行
|
|
1769
1888
|
var thinkProcessed = preprocessThinkTags(md || '');
|
|
1770
|
-
var
|
|
1889
|
+
var incompleteImageProcessed = preprocessIncompleteImages(thinkProcessed);
|
|
1890
|
+
var nonStandardProcessed = preprocessNonStandardHtmlTags(incompleteImageProcessed);
|
|
1771
1891
|
var processedMarkdown = mdastParser.parse(preprocessMarkdownTableNewlines(nonStandardProcessed));
|
|
1772
1892
|
var markdownRoot = processedMarkdown.children;
|
|
1773
1893
|
// 使用类的配置和插件,通过 this 访问
|
|
@@ -402,6 +402,11 @@ var genStyle = function(token) {
|
|
|
402
402
|
backgroundColor: 'var(--color-gray-control-fill-secondary)'
|
|
403
403
|
}
|
|
404
404
|
},
|
|
405
|
+
'[data-be="media-container"], [data-be="image-container"]': {
|
|
406
|
+
display: 'flex',
|
|
407
|
+
minWidth: 0,
|
|
408
|
+
maxWidth: '100%'
|
|
409
|
+
},
|
|
405
410
|
'@media screen and (max-width: 600px)': {
|
|
406
411
|
h1: {
|
|
407
412
|
fontSize: '1.5em'
|
|
@@ -18,5 +18,5 @@ export interface ChartFilterProps {
|
|
|
18
18
|
theme?: 'light' | 'dark';
|
|
19
19
|
variant?: 'default' | 'compact';
|
|
20
20
|
}
|
|
21
|
-
declare const ChartFilter: React.
|
|
21
|
+
declare const ChartFilter: React.FC<ChartFilterProps>;
|
|
22
22
|
export default ChartFilter;
|
|
@@ -1,125 +1,13 @@
|
|
|
1
|
-
function _array_like_to_array(arr, len) {
|
|
2
|
-
if (len == null || len > arr.length) len = arr.length;
|
|
3
|
-
for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
|
|
4
|
-
return arr2;
|
|
5
|
-
}
|
|
6
|
-
function _array_with_holes(arr) {
|
|
7
|
-
if (Array.isArray(arr)) return arr;
|
|
8
|
-
}
|
|
9
|
-
function _iterable_to_array_limit(arr, i) {
|
|
10
|
-
var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
|
|
11
|
-
if (_i == null) return;
|
|
12
|
-
var _arr = [];
|
|
13
|
-
var _n = true;
|
|
14
|
-
var _d = false;
|
|
15
|
-
var _s, _e;
|
|
16
|
-
try {
|
|
17
|
-
for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
|
|
18
|
-
_arr.push(_s.value);
|
|
19
|
-
if (i && _arr.length === i) break;
|
|
20
|
-
}
|
|
21
|
-
} catch (err) {
|
|
22
|
-
_d = true;
|
|
23
|
-
_e = err;
|
|
24
|
-
} finally{
|
|
25
|
-
try {
|
|
26
|
-
if (!_n && _i["return"] != null) _i["return"]();
|
|
27
|
-
} finally{
|
|
28
|
-
if (_d) throw _e;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return _arr;
|
|
32
|
-
}
|
|
33
|
-
function _non_iterable_rest() {
|
|
34
|
-
throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
35
|
-
}
|
|
36
|
-
function _sliced_to_array(arr, i) {
|
|
37
|
-
return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
|
|
38
|
-
}
|
|
39
|
-
function _unsupported_iterable_to_array(o, minLen) {
|
|
40
|
-
if (!o) return;
|
|
41
|
-
if (typeof o === "string") return _array_like_to_array(o, minLen);
|
|
42
|
-
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
43
|
-
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
44
|
-
if (n === "Map" || n === "Set") return Array.from(n);
|
|
45
|
-
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
|
|
46
|
-
}
|
|
47
1
|
import { ChevronDown } from "@sofa-design/icons";
|
|
48
2
|
import { Button, ConfigProvider, Dropdown, Segmented } from "antd";
|
|
49
3
|
import classNames from "classnames";
|
|
50
|
-
import React, { useContext,
|
|
4
|
+
import React, { useContext, useMemo, useRef } from "react";
|
|
51
5
|
import { I18nContext } from "../../../../I18n";
|
|
52
6
|
import { debounce } from "../../utils";
|
|
53
7
|
import { useStyle } from "./style";
|
|
54
|
-
/**
|
|
55
|
-
* 比较两个数组是否相等(浅比较)
|
|
56
|
-
*/ var areArraysEqual = function(a, b) {
|
|
57
|
-
if (a === b) return true;
|
|
58
|
-
if (!a || !b) return false;
|
|
59
|
-
if (a.length !== b.length) return false;
|
|
60
|
-
return a.every(function(item, index) {
|
|
61
|
-
var other = b[index];
|
|
62
|
-
if (!other) return false;
|
|
63
|
-
// 比较所有属性
|
|
64
|
-
return Object.keys(item).every(function(key) {
|
|
65
|
-
return item[key] === other[key];
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
};
|
|
69
|
-
/**
|
|
70
|
-
* ChartFilter 组件的 props 比较函数
|
|
71
|
-
* 用于 React.memo 优化,只在真正需要时重新渲染
|
|
72
|
-
*
|
|
73
|
-
* 注意:由于组件内部使用 ref 保存上一次有效的 filterOptions,
|
|
74
|
-
* 即使 filterOptions 暂时为空也不会导致组件消失。
|
|
75
|
-
* 因此比较时,如果当前值为空但之前有值,我们仍然认为它们"相等"(使用稳定值)。
|
|
76
|
-
*/ var arePropsEqual = function(prevProps, nextProps) {
|
|
77
|
-
// 比较基本属性
|
|
78
|
-
if (prevProps.selectedFilter !== nextProps.selectedFilter || prevProps.selectedCustomSelection !== nextProps.selectedCustomSelection || prevProps.className !== nextProps.className || prevProps.theme !== nextProps.theme || prevProps.variant !== nextProps.variant) {
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
// 比较数组属性(filterOptions 和 customOptions)
|
|
82
|
-
// 如果两个都是空或都有效,比较内容
|
|
83
|
-
// 如果一个为空一个有效,认为不相等(需要更新稳定值)
|
|
84
|
-
var prevFilterValid = prevProps.filterOptions && prevProps.filterOptions.length > 1;
|
|
85
|
-
var nextFilterValid = nextProps.filterOptions && nextProps.filterOptions.length > 1;
|
|
86
|
-
// 如果两个都有效,比较内容
|
|
87
|
-
if (prevFilterValid && nextFilterValid) {
|
|
88
|
-
if (!areArraysEqual(prevProps.filterOptions, nextProps.filterOptions)) {
|
|
89
|
-
return false;
|
|
90
|
-
}
|
|
91
|
-
} else if (prevFilterValid !== nextFilterValid) {
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
// 如果两个都无效,认为相等(使用上一次的稳定值)
|
|
95
|
-
var prevCustomValid = prevProps.customOptions && prevProps.customOptions.length > 1;
|
|
96
|
-
var nextCustomValid = nextProps.customOptions && nextProps.customOptions.length > 1;
|
|
97
|
-
if (prevCustomValid && nextCustomValid) {
|
|
98
|
-
if (!areArraysEqual(prevProps.customOptions, nextProps.customOptions)) {
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
} else if (prevCustomValid !== nextCustomValid) {
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
// 回调函数比较
|
|
105
|
-
// 由于我们已经用 ref 处理回调,即使引用变化也不会影响防抖逻辑
|
|
106
|
-
// 为了 memo 优化,我们只检查回调是否存在,不比较引用
|
|
107
|
-
var prevHasFilterChange = prevProps.onFilterChange !== undefined;
|
|
108
|
-
var nextHasFilterChange = nextProps.onFilterChange !== undefined;
|
|
109
|
-
if (prevHasFilterChange !== nextHasFilterChange) {
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
var prevHasSelectionChange = prevProps.onSelectionChange !== undefined;
|
|
113
|
-
var nextHasSelectionChange = nextProps.onSelectionChange !== undefined;
|
|
114
|
-
if (prevHasSelectionChange !== nextHasSelectionChange) {
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
// 所有关键属性都相同,可以跳过重新渲染
|
|
118
|
-
return true;
|
|
119
|
-
};
|
|
120
8
|
var ChartFilterComponent = function(param) {
|
|
121
9
|
var filterOptions = param.filterOptions, selectedFilter = param.selectedFilter, onFilterChange = param.onFilterChange, customOptions = param.customOptions, selectedCustomSelection = param.selectedCustomSelection, onSelectionChange = param.onSelectionChange, _param_className = param.className, className = _param_className === void 0 ? '' : _param_className, _param_theme = param.theme, theme = _param_theme === void 0 ? 'light' : _param_theme, _param_variant = param.variant, variant = _param_variant === void 0 ? 'default' : _param_variant;
|
|
122
|
-
var
|
|
10
|
+
var _customOptions_find, _i18n_locale;
|
|
123
11
|
var getPrefixCls = useContext(ConfigProvider.ConfigContext).getPrefixCls;
|
|
124
12
|
var i18n = useContext(I18nContext);
|
|
125
13
|
var prefixCls = getPrefixCls('chart-filter');
|
|
@@ -161,68 +49,27 @@ var ChartFilterComponent = function(param) {
|
|
|
161
49
|
debouncedFilterChange,
|
|
162
50
|
debouncedSelectionChange
|
|
163
51
|
]);
|
|
164
|
-
// 稳定化 filterOptions 和 customOptions,避免在流式更新时频繁变化导致组件跳动
|
|
165
|
-
// 使用 useState 保存稳定的值,只在内容真正变化时才更新
|
|
166
|
-
var _useState = _sliced_to_array(useState(function() {
|
|
167
|
-
return filterOptions && filterOptions.length > 1 ? filterOptions : undefined;
|
|
168
|
-
}), 2), stableFilterOptions = _useState[0], setStableFilterOptions = _useState[1];
|
|
169
|
-
var _useState1 = _sliced_to_array(useState(function() {
|
|
170
|
-
return customOptions && customOptions.length > 1 ? customOptions : undefined;
|
|
171
|
-
}), 2), stableCustomOptions = _useState1[0], setStableCustomOptions = _useState1[1];
|
|
172
|
-
// 使用 useRef 保存上一次的值用于内容比较
|
|
173
|
-
var prevFilterOptionsRef = useRef(filterOptions);
|
|
174
|
-
var prevCustomOptionsRef = useRef(customOptions);
|
|
175
|
-
// 当 filterOptions 变化时,只在内容真正变化时才更新
|
|
176
|
-
useEffect(function() {
|
|
177
|
-
if (filterOptions && filterOptions.length > 1) {
|
|
178
|
-
// 比较内容是否真的变化
|
|
179
|
-
var contentChanged = !areArraysEqual(prevFilterOptionsRef.current, filterOptions);
|
|
180
|
-
if (contentChanged) {
|
|
181
|
-
// 内容变化,更新稳定值
|
|
182
|
-
setStableFilterOptions(filterOptions);
|
|
183
|
-
prevFilterOptionsRef.current = filterOptions;
|
|
184
|
-
}
|
|
185
|
-
// 如果内容相同,不更新,避免不必要的重新渲染
|
|
186
|
-
} else if (filterOptions && filterOptions.length <= 1) {
|
|
187
|
-
// 如果新值无效(长度 <= 1),但之前有有效值,保持上一次的值(不更新)
|
|
188
|
-
// 这样 filter 不会消失
|
|
189
|
-
}
|
|
190
|
-
// 注意:如果 filterOptions 变为 undefined 或 null,我们不更新稳定值,保持上一次的值
|
|
191
|
-
}, [
|
|
192
|
-
filterOptions
|
|
193
|
-
]);
|
|
194
|
-
useEffect(function() {
|
|
195
|
-
if (customOptions && customOptions.length > 1) {
|
|
196
|
-
var contentChanged = !areArraysEqual(prevCustomOptionsRef.current, customOptions);
|
|
197
|
-
if (contentChanged) {
|
|
198
|
-
setStableCustomOptions(customOptions);
|
|
199
|
-
prevCustomOptionsRef.current = customOptions;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}, [
|
|
203
|
-
customOptions
|
|
204
|
-
]);
|
|
205
52
|
var handleRegionChange = function(region) {
|
|
206
53
|
debouncedSelectionChange(region);
|
|
207
54
|
};
|
|
208
55
|
var handleFilterChange = function(value) {
|
|
209
56
|
debouncedFilterChange(value);
|
|
210
57
|
};
|
|
211
|
-
var hasMain = Array.isArray(
|
|
212
|
-
var hasSecondary = Array.isArray(
|
|
58
|
+
var hasMain = Array.isArray(filterOptions) && filterOptions.length > 1;
|
|
59
|
+
var hasSecondary = Array.isArray(customOptions) && customOptions.length > 1;
|
|
213
60
|
if (!hasMain && !hasSecondary) {
|
|
214
61
|
return null;
|
|
215
62
|
}
|
|
216
|
-
if (!
|
|
63
|
+
if (!filterOptions || filterOptions.length < 2) {
|
|
217
64
|
return null;
|
|
218
65
|
}
|
|
219
66
|
return wrapSSR(/*#__PURE__*/ React.createElement("div", {
|
|
220
67
|
className: classNames(prefixCls, "".concat(prefixCls, "-").concat(theme), "".concat(prefixCls, "-").concat(variant), hashId, className)
|
|
221
|
-
},
|
|
68
|
+
}, customOptions && customOptions.length > 1 && /*#__PURE__*/ React.createElement("div", {
|
|
222
69
|
className: classNames("".concat(prefixCls, "-region-filter"), hashId)
|
|
223
70
|
}, /*#__PURE__*/ React.createElement(Dropdown, {
|
|
224
71
|
menu: {
|
|
225
|
-
items:
|
|
72
|
+
items: customOptions.map(function(item) {
|
|
226
73
|
return {
|
|
227
74
|
key: item.key,
|
|
228
75
|
label: item.label,
|
|
@@ -244,12 +91,12 @@ var ChartFilterComponent = function(param) {
|
|
|
244
91
|
type: "default",
|
|
245
92
|
size: "small",
|
|
246
93
|
className: classNames("".concat(prefixCls, "-region-dropdown-btn"), hashId)
|
|
247
|
-
}, /*#__PURE__*/ React.createElement("span", null, ((
|
|
94
|
+
}, /*#__PURE__*/ React.createElement("span", null, ((_customOptions_find = customOptions.find(function(r) {
|
|
248
95
|
return r.key === selectedCustomSelection;
|
|
249
|
-
})) === null ||
|
|
96
|
+
})) === null || _customOptions_find === void 0 ? void 0 : _customOptions_find.label) || (i18n === null || i18n === void 0 ? void 0 : (_i18n_locale = i18n.locale) === null || _i18n_locale === void 0 ? void 0 : _i18n_locale.all) || '全部'), /*#__PURE__*/ React.createElement(ChevronDown, {
|
|
250
97
|
className: classNames("".concat(prefixCls, "-dropdown-icon"), hashId)
|
|
251
|
-
})))),
|
|
252
|
-
options:
|
|
98
|
+
})))), filterOptions && filterOptions.length > 1 && /*#__PURE__*/ React.createElement(Segmented, {
|
|
99
|
+
options: filterOptions || [],
|
|
253
100
|
value: selectedFilter,
|
|
254
101
|
size: "small",
|
|
255
102
|
className: classNames("".concat(prefixCls, "-segmented-filter"), 'custom-segmented', hashId),
|
|
@@ -258,6 +105,5 @@ var ChartFilterComponent = function(param) {
|
|
|
258
105
|
}
|
|
259
106
|
})));
|
|
260
107
|
};
|
|
261
|
-
|
|
262
|
-
var ChartFilter = /*#__PURE__*/ React.memo(ChartFilterComponent, arePropsEqual);
|
|
108
|
+
var ChartFilter = ChartFilterComponent;
|
|
263
109
|
export default ChartFilter;
|