@ant-design/agentic-ui 2.4.0 → 2.5.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/Bubble/List/PureBubbleList.d.ts +32 -0
- package/dist/Bubble/List/PureBubbleList.js +143 -0
- package/dist/Bubble/List/index.d.ts +1 -0
- package/dist/Bubble/List/index.js +2 -0
- package/dist/Bubble/PureBubble.d.ts +15 -0
- package/dist/Bubble/PureBubble.js +350 -0
- package/dist/Bubble/index.d.ts +2 -0
- package/dist/Bubble/index.js +6 -0
- package/dist/History/components/HistoryEmpty.js +3 -3
- package/dist/History/components/LoadMoreComponent.js +7 -3
- package/dist/History/components/SearchComponent.js +8 -13
- package/dist/History/hooks/useHistory.js +1 -1
- package/dist/History/index.d.ts +1 -0
- package/dist/History/index.js +26 -23
- package/dist/History/types/index.d.ts +2 -0
- package/dist/Hooks/useLanguage.d.ts +1 -0
- package/dist/I18n/locales.d.ts +1 -0
- package/dist/I18n/locales.js +2 -0
- package/dist/MarkdownEditor/BaseMarkdownEditor.js +6 -2
- package/dist/MarkdownEditor/editor/store.d.ts +4 -2
- package/dist/MarkdownEditor/editor/store.js +8 -3
- package/dist/MarkdownEditor/editor/utils/markdownToHtml.d.ts +6 -2
- package/dist/MarkdownEditor/editor/utils/markdownToHtml.js +44 -11
- package/dist/MarkdownEditor/types.d.ts +5 -0
- package/dist/MarkdownInputField/AttachmentButton/index.js +6 -4
- package/dist/MarkdownInputField/FileUploadManager/index.js +9 -0
- package/dist/Workspace/File/FileComponent.d.ts +3 -50
- package/dist/Workspace/File/FileComponent.js +52 -9
- package/dist/Workspace/File/PreviewComponent.d.ts +2 -9
- package/dist/Workspace/File/PreviewComponent.js +14 -0
- package/dist/Workspace/File/style.js +13 -0
- package/dist/Workspace/RealtimeFollow/index.js +2 -1
- package/dist/Workspace/RealtimeFollow/style.js +15 -4
- package/dist/Workspace/index.d.ts +2 -42
- package/dist/Workspace/index.js +1 -4
- package/dist/Workspace/types.d.ts +9 -0
- package/package.json +3 -3
|
@@ -71,7 +71,7 @@ var useHistory = (props) => {
|
|
|
71
71
|
useEffect(() => {
|
|
72
72
|
props.sessionId && setSelectedIds([props.sessionId]);
|
|
73
73
|
loadHistory();
|
|
74
|
-
}, [props.sessionId]);
|
|
74
|
+
}, [props.sessionId, props.request, loadHistory]);
|
|
75
75
|
useEffect(() => {
|
|
76
76
|
if (!searchKeyword.trim()) {
|
|
77
77
|
setFilteredList(chatList);
|
package/dist/History/index.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export * from './utils';
|
|
|
21
21
|
* @param {Function} [props.customDateFormatter] - 日期格式化函数
|
|
22
22
|
* @param {boolean} [props.standalone] - 是否以独立模式显示,为true时直接显示菜单,否则显示为下拉菜单
|
|
23
23
|
* @param {Function} [props.emptyRender] - 空状态渲染函数,当历史记录为空时显示自定义内容
|
|
24
|
+
* @param {Function} [props.loadMoreRender] - 加载更多渲染函数, 用于自定义加载更多按钮的显示内容
|
|
24
25
|
* @param {boolean} [props.loading] - 加载状态,显示在 GroupMenu 区域
|
|
25
26
|
*
|
|
26
27
|
* @returns {React.ReactElement|null} 返回历史记录组件或null(当没有历史记录时)
|
package/dist/History/index.js
CHANGED
|
@@ -42,7 +42,7 @@ export * from "./types";
|
|
|
42
42
|
export * from "./types/HistoryData";
|
|
43
43
|
export * from "./utils";
|
|
44
44
|
var History = (props) => {
|
|
45
|
-
var _a, _b, _c, _d, _e, _f, _g, _h
|
|
45
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
46
46
|
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
|
|
47
47
|
const menuPrefixCls = getPrefixCls("agentic-chat-history-menu");
|
|
48
48
|
const { locale } = useContext(BubbleConfigContext) || {};
|
|
@@ -91,6 +91,27 @@ var History = (props) => {
|
|
|
91
91
|
type: props.type,
|
|
92
92
|
runningId: (_a = props.agent) == null ? void 0 : _a.runningId
|
|
93
93
|
});
|
|
94
|
+
const EmptyComponent = () => searchKeyword ? /* @__PURE__ */ React.createElement(HistoryEmpty, null) : props.emptyRender ? props.emptyRender() : /* @__PURE__ */ React.createElement(React.Fragment, null);
|
|
95
|
+
const LoadMoreComponent = () => {
|
|
96
|
+
var _a2, _b2;
|
|
97
|
+
if (props.loadMoreRender) {
|
|
98
|
+
return props.loadMoreRender();
|
|
99
|
+
}
|
|
100
|
+
const shouldRender = ((_a2 = props.agent) == null ? void 0 : _a2.enabled) && !!((_b2 = props.agent) == null ? void 0 : _b2.onLoadMore) && !props.loading;
|
|
101
|
+
if (!shouldRender) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
return /* @__PURE__ */ React.createElement(
|
|
105
|
+
HistoryLoadMore,
|
|
106
|
+
{
|
|
107
|
+
onLoadMore: handleLoadMore,
|
|
108
|
+
type: props.type,
|
|
109
|
+
className: classNames(`${menuPrefixCls}-load-more`, hashId, {
|
|
110
|
+
chat: props.type !== "task"
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
};
|
|
94
115
|
if (props.standalone) {
|
|
95
116
|
return wrapSSR(
|
|
96
117
|
/* @__PURE__ */ React.createElement(
|
|
@@ -123,7 +144,7 @@ var History = (props) => {
|
|
|
123
144
|
}
|
|
124
145
|
},
|
|
125
146
|
(_h = (_g = props.slots) == null ? void 0 : _g.beforeHistoryList) == null ? void 0 : _h.call(_g, filteredList),
|
|
126
|
-
(items == null ? void 0 : items.length) === 0 && !props.loading ?
|
|
147
|
+
(items == null ? void 0 : items.length) === 0 && !props.loading ? /* @__PURE__ */ React.createElement(EmptyComponent, null) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
127
148
|
GroupMenu,
|
|
128
149
|
{
|
|
129
150
|
selectedKeys: [props.sessionId],
|
|
@@ -132,16 +153,7 @@ var History = (props) => {
|
|
|
132
153
|
className: menuPrefixCls,
|
|
133
154
|
loading: props.loading
|
|
134
155
|
}
|
|
135
|
-
),
|
|
136
|
-
HistoryLoadMore,
|
|
137
|
-
{
|
|
138
|
-
onLoadMore: handleLoadMore,
|
|
139
|
-
type: props.type,
|
|
140
|
-
className: classNames(`${menuPrefixCls}-load-more`, hashId, {
|
|
141
|
-
chat: props.type !== "task"
|
|
142
|
-
})
|
|
143
|
-
}
|
|
144
|
-
))
|
|
156
|
+
), /* @__PURE__ */ React.createElement(LoadMoreComponent, null))
|
|
145
157
|
)
|
|
146
158
|
)
|
|
147
159
|
);
|
|
@@ -161,7 +173,7 @@ var History = (props) => {
|
|
|
161
173
|
border: "1px solid var(--color-gray-border-light)"
|
|
162
174
|
},
|
|
163
175
|
getPopupContainer: (p) => p.parentElement || document.body,
|
|
164
|
-
content: /* @__PURE__ */ React.createElement(React.Fragment, null, (items == null ? void 0 : items.length) === 0 && !(props == null ? void 0 : props.loading) ? /* @__PURE__ */ React.createElement("div", { "data-testid": "empty-state-popover" },
|
|
176
|
+
content: /* @__PURE__ */ React.createElement(React.Fragment, null, (items == null ? void 0 : items.length) === 0 && !(props == null ? void 0 : props.loading) ? /* @__PURE__ */ React.createElement("div", { "data-testid": "empty-state-popover" }, /* @__PURE__ */ React.createElement(EmptyComponent, null)) : /* @__PURE__ */ React.createElement(
|
|
165
177
|
GroupMenu,
|
|
166
178
|
{
|
|
167
179
|
selectedKeys: [props.sessionId],
|
|
@@ -170,16 +182,7 @@ var History = (props) => {
|
|
|
170
182
|
className: menuPrefixCls,
|
|
171
183
|
loading: props.loading
|
|
172
184
|
}
|
|
173
|
-
),
|
|
174
|
-
HistoryLoadMore,
|
|
175
|
-
{
|
|
176
|
-
onLoadMore: handleLoadMore,
|
|
177
|
-
type: props.type,
|
|
178
|
-
className: classNames(`${menuPrefixCls}-load-more`, hashId, {
|
|
179
|
-
chat: props.type !== "task"
|
|
180
|
-
})
|
|
181
|
-
}
|
|
182
|
-
))
|
|
185
|
+
), /* @__PURE__ */ React.createElement(LoadMoreComponent, null))
|
|
183
186
|
},
|
|
184
187
|
/* @__PURE__ */ React.createElement(
|
|
185
188
|
"div",
|
|
@@ -68,6 +68,8 @@ export interface HistoryProps {
|
|
|
68
68
|
loading?: boolean;
|
|
69
69
|
/** 加载状态,显示在 GroupMenu 区域 */
|
|
70
70
|
isLoading?: boolean;
|
|
71
|
+
/** 加载更多渲染函数, 用于自定义加载更多按钮的显示内容 */
|
|
72
|
+
loadMoreRender?: () => React.ReactNode;
|
|
71
73
|
}
|
|
72
74
|
export interface HistoryActionsBoxProps {
|
|
73
75
|
/** 子组件,通常是时间显示或其他内容 */
|
|
@@ -242,6 +242,7 @@ export declare function useLanguage(): {
|
|
|
242
242
|
'workspace.file.download': string;
|
|
243
243
|
'workspace.file.share': string;
|
|
244
244
|
'workspace.file.preview': string;
|
|
245
|
+
'workspace.file.location': string;
|
|
245
246
|
'workspace.file.linkCopied': string;
|
|
246
247
|
'workspace.file.copyFailed': string;
|
|
247
248
|
'markdownInput.fileSizeExceeded': string;
|
package/dist/I18n/locales.d.ts
CHANGED
|
@@ -206,6 +206,7 @@ export declare const cnLabels: {
|
|
|
206
206
|
'workspace.file.download': string;
|
|
207
207
|
'workspace.file.share': string;
|
|
208
208
|
'workspace.file.preview': string;
|
|
209
|
+
'workspace.file.location': string;
|
|
209
210
|
'workspace.file.linkCopied': string;
|
|
210
211
|
'workspace.file.copyFailed': string;
|
|
211
212
|
'markdownInput.fileSizeExceeded': string;
|
package/dist/I18n/locales.js
CHANGED
|
@@ -204,6 +204,7 @@ var cnLabels = {
|
|
|
204
204
|
"workspace.file.download": "下载",
|
|
205
205
|
"workspace.file.share": "分享",
|
|
206
206
|
"workspace.file.preview": "预览",
|
|
207
|
+
"workspace.file.location": "定位",
|
|
207
208
|
"workspace.file.linkCopied": "已复制链接",
|
|
208
209
|
"workspace.file.copyFailed": "复制失败",
|
|
209
210
|
// MarkdownInputField 组件相关
|
|
@@ -557,6 +558,7 @@ var enLabels = {
|
|
|
557
558
|
"workspace.file.download": "Download",
|
|
558
559
|
"workspace.file.share": "Share",
|
|
559
560
|
"workspace.file.preview": "Preview",
|
|
561
|
+
"workspace.file.location": "Location",
|
|
560
562
|
"workspace.file.linkCopied": "Link copied",
|
|
561
563
|
"workspace.file.copyFailed": "Copy failed",
|
|
562
564
|
// MarkdownInputField component related
|
|
@@ -171,8 +171,12 @@ var BaseMarkdownEditor = (props) => {
|
|
|
171
171
|
};
|
|
172
172
|
}, []);
|
|
173
173
|
const store = useMemo(
|
|
174
|
-
() => new EditorStore(
|
|
175
|
-
|
|
174
|
+
() => new EditorStore(
|
|
175
|
+
markdownEditorRef,
|
|
176
|
+
props.plugins,
|
|
177
|
+
props.markdownToHtmlOptions
|
|
178
|
+
),
|
|
179
|
+
[props.plugins, props.markdownToHtmlOptions]
|
|
176
180
|
);
|
|
177
181
|
const initSchemaValue = useMemo(() => {
|
|
178
182
|
var _a2;
|
|
@@ -8,6 +8,7 @@ import { FootnoteDefinitionNode } from '../el';
|
|
|
8
8
|
import type { MarkdownEditorPlugin } from '../plugin';
|
|
9
9
|
import { CommentDataType, MarkdownEditorProps } from '../types';
|
|
10
10
|
import { KeyboardTask, Methods } from './utils';
|
|
11
|
+
import type { MarkdownToHtmlOptions } from './utils/markdownToHtml';
|
|
11
12
|
/**
|
|
12
13
|
* 编辑器上下文接口
|
|
13
14
|
*
|
|
@@ -88,13 +89,14 @@ export declare class EditorStore {
|
|
|
88
89
|
_editor: React.MutableRefObject<BaseEditor & ReactEditor & HistoryEditor>;
|
|
89
90
|
/** 当前 setMDContent 操作的 AbortController */
|
|
90
91
|
private _currentAbortController;
|
|
92
|
+
private markdownToHtmlOptions?;
|
|
91
93
|
/**
|
|
92
94
|
* 获取当前编辑器实例。
|
|
93
95
|
*
|
|
94
96
|
* @returns 当前的 Slate 编辑器实例。
|
|
95
97
|
*/
|
|
96
98
|
get editor(): BaseEditor & ReactEditor & HistoryEditor;
|
|
97
|
-
constructor(_editor: React.MutableRefObject<BaseEditor & ReactEditor & HistoryEditor>, plugins?: MarkdownEditorPlugin[]);
|
|
99
|
+
constructor(_editor: React.MutableRefObject<BaseEditor & ReactEditor & HistoryEditor>, plugins?: MarkdownEditorPlugin[], markdownToHtmlOptions?: MarkdownToHtmlOptions);
|
|
98
100
|
/**
|
|
99
101
|
* 聚焦到编辑器
|
|
100
102
|
*/
|
|
@@ -240,7 +242,7 @@ export declare class EditorStore {
|
|
|
240
242
|
*
|
|
241
243
|
* @returns 转换为 HTML 的当前编辑器内容
|
|
242
244
|
*/
|
|
243
|
-
getHtmlContent(): string;
|
|
245
|
+
getHtmlContent(options?: MarkdownToHtmlOptions): string;
|
|
244
246
|
/**
|
|
245
247
|
* 使用节点列表设置编辑器内容
|
|
246
248
|
*
|
|
@@ -52,7 +52,7 @@ var useEditorStore = () => {
|
|
|
52
52
|
};
|
|
53
53
|
var SUPPORT_TYPING_TAG = ["table-cell", "paragraph", "head"];
|
|
54
54
|
var EditorStore = class {
|
|
55
|
-
constructor(_editor, plugins) {
|
|
55
|
+
constructor(_editor, plugins, markdownToHtmlOptions) {
|
|
56
56
|
/** 高亮缓存映射表 */
|
|
57
57
|
this.highlightCache = /* @__PURE__ */ new Map();
|
|
58
58
|
/** 允许进入的元素类型集合 */
|
|
@@ -83,6 +83,7 @@ var EditorStore = class {
|
|
|
83
83
|
this.dragStart = this.dragStart.bind(this);
|
|
84
84
|
this._editor = _editor;
|
|
85
85
|
this.plugins = plugins;
|
|
86
|
+
this.markdownToHtmlOptions = markdownToHtmlOptions;
|
|
86
87
|
}
|
|
87
88
|
/**
|
|
88
89
|
* 获取当前编辑器实例。
|
|
@@ -629,9 +630,13 @@ var EditorStore = class {
|
|
|
629
630
|
*
|
|
630
631
|
* @returns 转换为 HTML 的当前编辑器内容
|
|
631
632
|
*/
|
|
632
|
-
getHtmlContent() {
|
|
633
|
+
getHtmlContent(options) {
|
|
633
634
|
const markdown = this.getMDContent();
|
|
634
|
-
|
|
635
|
+
const appliedOptions = options != null ? options : this.markdownToHtmlOptions;
|
|
636
|
+
if (options) {
|
|
637
|
+
this.markdownToHtmlOptions = options;
|
|
638
|
+
}
|
|
639
|
+
return markdownToHtmlSync(markdown, appliedOptions);
|
|
635
640
|
}
|
|
636
641
|
/**
|
|
637
642
|
* 使用节点列表设置编辑器内容
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import type { Plugin } from 'unified';
|
|
2
|
+
export type MarkdownRemarkPlugin = Plugin | [Plugin, ...unknown[]];
|
|
3
|
+
export type MarkdownToHtmlOptions = MarkdownRemarkPlugin[];
|
|
4
|
+
export declare const DEFAULT_MARKDOWN_REMARK_PLUGINS: readonly MarkdownRemarkPlugin[];
|
|
1
5
|
/**
|
|
2
6
|
* 将 Markdown 内容转换为 HTML(异步版本)
|
|
3
7
|
*
|
|
@@ -19,7 +23,7 @@
|
|
|
19
23
|
*
|
|
20
24
|
* @throws {Error} 当转换过程中发生错误时返回空字符串
|
|
21
25
|
*/
|
|
22
|
-
export declare const markdownToHtml: (markdown: string) => Promise<string>;
|
|
26
|
+
export declare const markdownToHtml: (markdown: string, plugins?: MarkdownToHtmlOptions) => Promise<string>;
|
|
23
27
|
/**
|
|
24
28
|
* 将 Markdown 内容转换为 HTML(同步版本)
|
|
25
29
|
*
|
|
@@ -41,4 +45,4 @@ export declare const markdownToHtml: (markdown: string) => Promise<string>;
|
|
|
41
45
|
* - 建议在可能的情况下使用异步版本 `markdownToHtml`
|
|
42
46
|
* - 同步版本可能影响用户界面响应性
|
|
43
47
|
*/
|
|
44
|
-
export declare const markdownToHtmlSync: (markdown: string) => string;
|
|
48
|
+
export declare const markdownToHtmlSync: (markdown: string, plugins?: MarkdownToHtmlOptions) => string;
|
|
@@ -30,25 +30,57 @@ import remarkParse from "remark-parse";
|
|
|
30
30
|
import remarkRehype from "remark-rehype";
|
|
31
31
|
import { unified } from "unified";
|
|
32
32
|
import { fixStrongWithSpecialChars } from "../parser/remarkParse";
|
|
33
|
-
var
|
|
33
|
+
var INLINE_MATH_WITH_SINGLE_DOLLAR = { singleDollarTextMath: true };
|
|
34
|
+
var FRONTMATTER_LANGUAGES = ["yaml"];
|
|
35
|
+
var remarkRehypePlugin = remarkRehype;
|
|
36
|
+
var DEFAULT_MARKDOWN_REMARK_PLUGINS = [
|
|
37
|
+
remarkParse,
|
|
38
|
+
remarkGfm,
|
|
39
|
+
fixStrongWithSpecialChars,
|
|
40
|
+
[remarkMath, INLINE_MATH_WITH_SINGLE_DOLLAR],
|
|
41
|
+
[remarkFrontmatter, FRONTMATTER_LANGUAGES],
|
|
42
|
+
[remarkRehypePlugin, { allowDangerousHtml: true }]
|
|
43
|
+
];
|
|
44
|
+
var DEFAULT_REMARK_PLUGINS = [
|
|
45
|
+
...DEFAULT_MARKDOWN_REMARK_PLUGINS
|
|
46
|
+
];
|
|
47
|
+
var applyPlugins = (processor, plugins) => {
|
|
48
|
+
const extendedProcessor = processor;
|
|
49
|
+
plugins.forEach((entry) => {
|
|
50
|
+
if (Array.isArray(entry)) {
|
|
51
|
+
const [plugin, ...pluginOptions] = entry;
|
|
52
|
+
extendedProcessor.use(plugin, ...pluginOptions);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
extendedProcessor.use(entry);
|
|
56
|
+
});
|
|
57
|
+
return processor;
|
|
58
|
+
};
|
|
59
|
+
var resolveRemarkPlugins = (plugins) => {
|
|
60
|
+
if (!plugins || plugins.length === 0) {
|
|
61
|
+
return DEFAULT_REMARK_PLUGINS;
|
|
62
|
+
}
|
|
63
|
+
return plugins;
|
|
64
|
+
};
|
|
65
|
+
var createMarkdownProcessor = (plugins) => {
|
|
66
|
+
const processor = unified();
|
|
67
|
+
const remarkPlugins = resolveRemarkPlugins(plugins);
|
|
68
|
+
applyPlugins(processor, remarkPlugins);
|
|
69
|
+
processor.use(rehypeRaw).use(rehypeKatex).use(rehypeStringify);
|
|
70
|
+
return processor;
|
|
71
|
+
};
|
|
72
|
+
var markdownToHtml = (markdown, plugins) => __async(void 0, null, function* () {
|
|
34
73
|
try {
|
|
35
|
-
const htmlContent = yield
|
|
36
|
-
singleDollarTextMath: true
|
|
37
|
-
// 允许单美元符号渲染内联数学公式
|
|
38
|
-
}).use(remarkFrontmatter, ["yaml"]).use(remarkRehype, { allowDangerousHtml: true }).use(rehypeRaw).use(rehypeKatex).use(rehypeStringify).process(markdown);
|
|
74
|
+
const htmlContent = yield createMarkdownProcessor(plugins).process(markdown);
|
|
39
75
|
return String(htmlContent);
|
|
40
76
|
} catch (error) {
|
|
41
77
|
console.error("Error converting markdown to HTML:", error);
|
|
42
78
|
return "";
|
|
43
79
|
}
|
|
44
80
|
});
|
|
45
|
-
var markdownToHtmlSync = (markdown) => {
|
|
81
|
+
var markdownToHtmlSync = (markdown, plugins) => {
|
|
46
82
|
try {
|
|
47
|
-
const
|
|
48
|
-
singleDollarTextMath: true
|
|
49
|
-
// 允许单美元符号渲染内联数学公式
|
|
50
|
-
}).use(remarkFrontmatter, ["yaml"]).use(remarkRehype, { allowDangerousHtml: true }).use(rehypeRaw).use(rehypeKatex).use(rehypeStringify);
|
|
51
|
-
const file = processor.processSync(markdown);
|
|
83
|
+
const file = createMarkdownProcessor(plugins).processSync(markdown);
|
|
52
84
|
return String(file);
|
|
53
85
|
} catch (error) {
|
|
54
86
|
console.error("Error converting markdown to HTML:", error);
|
|
@@ -56,6 +88,7 @@ var markdownToHtmlSync = (markdown) => {
|
|
|
56
88
|
}
|
|
57
89
|
};
|
|
58
90
|
export {
|
|
91
|
+
DEFAULT_MARKDOWN_REMARK_PLUGINS,
|
|
59
92
|
markdownToHtml,
|
|
60
93
|
markdownToHtmlSync
|
|
61
94
|
};
|
|
@@ -4,6 +4,7 @@ import React from 'react';
|
|
|
4
4
|
import { BaseEditor, Selection } from 'slate';
|
|
5
5
|
import { HistoryEditor } from 'slate-history';
|
|
6
6
|
import { ReactEditor, RenderElementProps } from 'slate-react';
|
|
7
|
+
import type { MarkdownToHtmlOptions } from './editor/utils/markdownToHtml';
|
|
7
8
|
import { TagPopupProps } from './editor/elements/TagPopup';
|
|
8
9
|
import { EditorStore } from './editor/store';
|
|
9
10
|
import { InsertAutocompleteProps } from './editor/tools/InsertAutocomplete';
|
|
@@ -292,6 +293,10 @@ export type MarkdownEditorProps = {
|
|
|
292
293
|
onFocus?: (value: string, schema: Elements[], e: React.FocusEvent<HTMLDivElement, Element>) => void;
|
|
293
294
|
onBlur?: (value: string, schema: Elements[], e: React.MouseEvent<HTMLDivElement, Element>) => void;
|
|
294
295
|
onPaste?: (e: React.ClipboardEvent<HTMLDivElement>) => void;
|
|
296
|
+
/**
|
|
297
|
+
* 自定义 markdown 转 HTML 的 remark 插件配置,格式类似 Babel 插件数组
|
|
298
|
+
*/
|
|
299
|
+
markdownToHtmlOptions?: MarkdownToHtmlOptions;
|
|
295
300
|
/**
|
|
296
301
|
* 其他属性
|
|
297
302
|
*/
|
|
@@ -55,16 +55,17 @@ var prepareFile = (file) => {
|
|
|
55
55
|
var getLocaleMessage = (locale, key, defaultMsg) => {
|
|
56
56
|
return (locale == null ? void 0 : locale[key]) || defaultMsg;
|
|
57
57
|
};
|
|
58
|
-
var validateFileCount = (
|
|
58
|
+
var validateFileCount = (newFileCount, existingFileCount, props) => {
|
|
59
59
|
var _a, _b;
|
|
60
|
-
|
|
60
|
+
const totalFileCount = newFileCount + existingFileCount;
|
|
61
|
+
if (props.maxFileCount && totalFileCount > props.maxFileCount) {
|
|
61
62
|
const msg = ((_a = props.locale) == null ? void 0 : _a["markdownInput.maxFileCountExceeded"]) ? compileTemplate(props.locale["markdownInput.maxFileCountExceeded"], {
|
|
62
63
|
maxFileCount: String(props.maxFileCount)
|
|
63
64
|
}) : DEFAULT_MESSAGES.maxFileCountExceeded(props.maxFileCount);
|
|
64
65
|
message.error(msg);
|
|
65
66
|
return false;
|
|
66
67
|
}
|
|
67
|
-
if (props.minFileCount &&
|
|
68
|
+
if (props.minFileCount && totalFileCount < props.minFileCount) {
|
|
68
69
|
const msg = ((_b = props.locale) == null ? void 0 : _b["markdownInput.minFileCountRequired"]) ? compileTemplate(props.locale["markdownInput.minFileCountRequired"], {
|
|
69
70
|
minFileCount: String(props.minFileCount)
|
|
70
71
|
}) : DEFAULT_MESSAGES.minFileCountRequired(props.minFileCount);
|
|
@@ -158,13 +159,14 @@ var processFile = (file, index, map, props) => __async(void 0, null, function* (
|
|
|
158
159
|
});
|
|
159
160
|
var upLoadFileToServer = (files, props) => __async(void 0, null, function* () {
|
|
160
161
|
const map = props.fileMap || /* @__PURE__ */ new Map();
|
|
162
|
+
const existingFileCount = map.size;
|
|
161
163
|
const hideLoading = message.loading(
|
|
162
164
|
getLocaleMessage(props.locale, "uploading", DEFAULT_MESSAGES.uploading)
|
|
163
165
|
);
|
|
164
166
|
const fileList = Array.from(files);
|
|
165
167
|
fileList.forEach(prepareFile);
|
|
166
168
|
fileList.forEach((file) => updateFileMap(map, file, props.onFileMapChange));
|
|
167
|
-
if (!validateFileCount(fileList.length, props)) {
|
|
169
|
+
if (!validateFileCount(fileList.length, existingFileCount, props)) {
|
|
168
170
|
hideLoading();
|
|
169
171
|
return;
|
|
170
172
|
}
|
|
@@ -72,6 +72,15 @@ var useFileUploadManager = ({
|
|
|
72
72
|
if (isUploading) {
|
|
73
73
|
return;
|
|
74
74
|
}
|
|
75
|
+
const currentFileCount = (fileMap == null ? void 0 : fileMap.size) || 0;
|
|
76
|
+
if ((attachment == null ? void 0 : attachment.maxFileCount) && currentFileCount >= attachment.maxFileCount) {
|
|
77
|
+
const errorMsg = (locale == null ? void 0 : locale["markdownInput.maxFileCountExceeded"]) ? locale["markdownInput.maxFileCountExceeded"].replace(
|
|
78
|
+
"${maxFileCount}",
|
|
79
|
+
String(attachment.maxFileCount)
|
|
80
|
+
) : `最多只能上传 ${attachment.maxFileCount} 个文件`;
|
|
81
|
+
message.error(errorMsg);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
75
84
|
const input = document.createElement("input");
|
|
76
85
|
input.id = "uploadImage_" + Math.random();
|
|
77
86
|
input.type = "file";
|
|
@@ -1,62 +1,13 @@
|
|
|
1
1
|
import React, { type FC } from 'react';
|
|
2
2
|
import type { MarkdownEditorProps } from '../../MarkdownEditor';
|
|
3
3
|
import type { FileNode, FileProps } from '../types';
|
|
4
|
-
/**
|
|
5
|
-
* FileComponent 组件 - 文件管理组件
|
|
6
|
-
*
|
|
7
|
-
* 该组件提供一个完整的文件管理界面,支持文件列表显示、分组管理、
|
|
8
|
-
* 文件预览、下载等功能。支持多种文件类型的预览和自定义预览内容。
|
|
9
|
-
*
|
|
10
|
-
* @component
|
|
11
|
-
* @description 文件管理组件,支持文件列表、预览、下载等功能
|
|
12
|
-
* @param {Object} props - 组件属性
|
|
13
|
-
* @param {FileNode[]} props.nodes - 文件节点列表
|
|
14
|
-
* @param {(files: FileNode[], groupType: FileType) => void} [props.onGroupDownload] - 分组下载回调
|
|
15
|
-
* @param {(file: FileNode) => void} [props.onDownload] - 单个文件下载回调
|
|
16
|
-
* @param {(file: FileNode) => void} [props.onFileClick] - 文件点击回调
|
|
17
|
-
* @param {(type: FileType, collapsed: boolean) => void} [props.onToggleGroup] - 分组折叠/展开回调
|
|
18
|
-
* @param {(file: FileNode) => Promise<React.ReactNode | FileNode>} [props.onPreview] - 文件预览回调
|
|
19
|
-
* @param {Partial<MarkdownEditorProps>} [props.markdownEditorProps] - Markdown编辑器配置
|
|
20
|
-
* @param {React.ReactNode | (() => React.ReactNode)} [props.emptyRender] - 自定义空状态渲染
|
|
21
|
-
* @param {string} [props.keyword] - 搜索关键字(受控)
|
|
22
|
-
* @param {(keyword: string) => void} [props.onChange] - 搜索关键字变化回调
|
|
23
|
-
* @param {boolean} [props.showSearch] - 是否显示搜索框,默认显示
|
|
24
|
-
* @param {string} [props.searchPlaceholder] - 搜索框占位符
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* ```tsx
|
|
28
|
-
* <FileComponent
|
|
29
|
-
* nodes={fileNodes}
|
|
30
|
-
* onDownload={(file) => console.log('下载文件:', file.name)}
|
|
31
|
-
* onPreview={async (file) => {
|
|
32
|
-
* // 自定义预览逻辑
|
|
33
|
-
* return <div>预览内容</div>;
|
|
34
|
-
* }}
|
|
35
|
-
* markdownEditorProps={{
|
|
36
|
-
* theme: 'dark'
|
|
37
|
-
* }}
|
|
38
|
-
* emptyRender={<MyEmpty />}
|
|
39
|
-
* keyword={keyword}
|
|
40
|
-
* onChange={setKeyword}
|
|
41
|
-
* />
|
|
42
|
-
* ```
|
|
43
|
-
*
|
|
44
|
-
* @returns {React.ReactElement|null} 渲染的文件管理组件,无文件时返回null
|
|
45
|
-
*
|
|
46
|
-
* @remarks
|
|
47
|
-
* - 支持文件分组显示和折叠/展开
|
|
48
|
-
* - 支持多种文件类型的预览(图片、文档、代码等)
|
|
49
|
-
* - 支持自定义预览内容和头部
|
|
50
|
-
* - 提供文件下载和分组下载功能
|
|
51
|
-
* - 支持Markdown文件的编辑器预览
|
|
52
|
-
* - 处理异步预览的竞态条件
|
|
53
|
-
*/
|
|
54
4
|
export declare const FileComponent: FC<{
|
|
55
5
|
nodes: FileProps['nodes'];
|
|
56
6
|
onGroupDownload?: FileProps['onGroupDownload'];
|
|
57
7
|
onDownload?: FileProps['onDownload'];
|
|
58
8
|
onShare?: FileProps['onShare'];
|
|
59
9
|
onFileClick?: FileProps['onFileClick'];
|
|
10
|
+
onLocate?: FileProps['onLocate'];
|
|
60
11
|
onToggleGroup?: FileProps['onToggleGroup'];
|
|
61
12
|
onPreview?: FileProps['onPreview'];
|
|
62
13
|
onBack?: FileProps['onBack'];
|
|
@@ -84,4 +35,6 @@ export declare const FileComponent: FC<{
|
|
|
84
35
|
showSearch?: boolean;
|
|
85
36
|
/** 搜索框占位符 */
|
|
86
37
|
searchPlaceholder?: string;
|
|
38
|
+
/** 是否在元素上绑定 DOM id(默认 false) */
|
|
39
|
+
bindDomId?: FileProps['bindDomId'];
|
|
87
40
|
}>;
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
ChevronDown as DownIcon,
|
|
46
46
|
Download as DownloadIcon,
|
|
47
47
|
Eye as EyeIcon,
|
|
48
|
+
Locate,
|
|
48
49
|
ChevronRight as RightIcon,
|
|
49
50
|
Search,
|
|
50
51
|
SquareArrowOutUpRight as ShareIcon
|
|
@@ -130,10 +131,12 @@ var AccessibleButton = ({
|
|
|
130
131
|
icon,
|
|
131
132
|
onClick,
|
|
132
133
|
className,
|
|
133
|
-
ariaLabel
|
|
134
|
+
ariaLabel,
|
|
135
|
+
id
|
|
134
136
|
}) => /* @__PURE__ */ React.createElement(
|
|
135
137
|
"div",
|
|
136
138
|
{
|
|
139
|
+
id,
|
|
137
140
|
className,
|
|
138
141
|
onClick,
|
|
139
142
|
role: "button",
|
|
@@ -170,7 +173,17 @@ var SearchInput = React.memo(
|
|
|
170
173
|
}
|
|
171
174
|
);
|
|
172
175
|
SearchInput.displayName = "SearchInput";
|
|
173
|
-
var FileItemComponent = ({
|
|
176
|
+
var FileItemComponent = ({
|
|
177
|
+
file,
|
|
178
|
+
onClick,
|
|
179
|
+
onDownload,
|
|
180
|
+
onPreview,
|
|
181
|
+
onShare,
|
|
182
|
+
onLocate,
|
|
183
|
+
prefixCls,
|
|
184
|
+
hashId,
|
|
185
|
+
bindDomId = false
|
|
186
|
+
}) => {
|
|
174
187
|
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
|
|
175
188
|
const { locale } = useContext(I18nContext);
|
|
176
189
|
const finalPrefixCls = prefixCls || getPrefixCls("workspace-file");
|
|
@@ -223,6 +236,11 @@ var FileItemComponent = ({ file, onClick, onDownload, onPreview, onShare, prefix
|
|
|
223
236
|
return onPreview && (isImageFile(fileWithId) ? !!(fileWithId.url || fileWithId.previewUrl) : fileTypeProcessor.processFile(fileWithId).canPreview);
|
|
224
237
|
})();
|
|
225
238
|
const showShareButton = fileWithId.canShare === true;
|
|
239
|
+
const showLocationButton = fileWithId.canLocate === true;
|
|
240
|
+
const handleLocate = (e) => {
|
|
241
|
+
e.stopPropagation();
|
|
242
|
+
onLocate == null ? void 0 : onLocate(fileWithId);
|
|
243
|
+
};
|
|
226
244
|
return /* @__PURE__ */ React.createElement(
|
|
227
245
|
AccessibleButton,
|
|
228
246
|
{
|
|
@@ -297,6 +315,19 @@ var FileItemComponent = ({ file, onClick, onDownload, onPreview, onShare, prefix
|
|
|
297
315
|
},
|
|
298
316
|
/* @__PURE__ */ React.createElement(EyeIcon, null)
|
|
299
317
|
),
|
|
318
|
+
showLocationButton && /* @__PURE__ */ React.createElement(
|
|
319
|
+
ActionIconBox,
|
|
320
|
+
{
|
|
321
|
+
title: (locale == null ? void 0 : locale["workspace.file.location"]) || "定位",
|
|
322
|
+
onClick: handleLocate,
|
|
323
|
+
tooltipProps: { mouseEnterDelay: 0.3 },
|
|
324
|
+
className: classNames(
|
|
325
|
+
`${finalPrefixCls}-item-action-btn`,
|
|
326
|
+
hashId
|
|
327
|
+
)
|
|
328
|
+
},
|
|
329
|
+
/* @__PURE__ */ React.createElement(Locate, null)
|
|
330
|
+
),
|
|
300
331
|
showShareButton && /* @__PURE__ */ React.createElement(
|
|
301
332
|
ActionIconBox,
|
|
302
333
|
{
|
|
@@ -326,7 +357,8 @@ var FileItemComponent = ({ file, onClick, onDownload, onPreview, onShare, prefix
|
|
|
326
357
|
)),
|
|
327
358
|
onClick: handleClick,
|
|
328
359
|
className: classNames(`${finalPrefixCls}-item`, hashId),
|
|
329
|
-
ariaLabel: `${(locale == null ? void 0 : locale["workspace.file"]) || "文件"}:${fileWithId.name}
|
|
360
|
+
ariaLabel: `${(locale == null ? void 0 : locale["workspace.file"]) || "文件"}:${fileWithId.name}`,
|
|
361
|
+
id: bindDomId ? fileWithId.id : void 0
|
|
330
362
|
}
|
|
331
363
|
);
|
|
332
364
|
};
|
|
@@ -434,8 +466,10 @@ var FileGroupComponent = ({
|
|
|
434
466
|
onFileClick,
|
|
435
467
|
onPreview,
|
|
436
468
|
onShare,
|
|
469
|
+
onLocate,
|
|
437
470
|
prefixCls,
|
|
438
|
-
hashId
|
|
471
|
+
hashId,
|
|
472
|
+
bindDomId
|
|
439
473
|
}) => {
|
|
440
474
|
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
|
|
441
475
|
const finalPrefixCls = prefixCls || getPrefixCls("workspace-file");
|
|
@@ -457,8 +491,10 @@ var FileGroupComponent = ({
|
|
|
457
491
|
onDownload,
|
|
458
492
|
onPreview,
|
|
459
493
|
onShare,
|
|
494
|
+
onLocate,
|
|
460
495
|
prefixCls: finalPrefixCls,
|
|
461
|
-
hashId
|
|
496
|
+
hashId,
|
|
497
|
+
bindDomId: !!bindDomId
|
|
462
498
|
}
|
|
463
499
|
))));
|
|
464
500
|
};
|
|
@@ -468,6 +504,7 @@ var FileComponent = ({
|
|
|
468
504
|
onDownload,
|
|
469
505
|
onShare,
|
|
470
506
|
onFileClick,
|
|
507
|
+
onLocate,
|
|
471
508
|
onToggleGroup,
|
|
472
509
|
onPreview,
|
|
473
510
|
onBack,
|
|
@@ -481,7 +518,8 @@ var FileComponent = ({
|
|
|
481
518
|
keyword,
|
|
482
519
|
onChange,
|
|
483
520
|
showSearch = false,
|
|
484
|
-
searchPlaceholder
|
|
521
|
+
searchPlaceholder,
|
|
522
|
+
bindDomId = false
|
|
485
523
|
}) => {
|
|
486
524
|
const [previewFile, setPreviewFile] = useState(null);
|
|
487
525
|
const [customPreviewContent, setCustomPreviewContent] = useState(null);
|
|
@@ -590,7 +628,7 @@ var FileComponent = ({
|
|
|
590
628
|
download: () => handleDownloadInPreview(file),
|
|
591
629
|
share: () => {
|
|
592
630
|
if (onShare) {
|
|
593
|
-
onShare(file);
|
|
631
|
+
onShare(file, void 0);
|
|
594
632
|
} else {
|
|
595
633
|
handleDefaultShare(file, locale);
|
|
596
634
|
}
|
|
@@ -705,6 +743,7 @@ var FileComponent = ({
|
|
|
705
743
|
handleDefaultShare(file, locale);
|
|
706
744
|
}
|
|
707
745
|
},
|
|
746
|
+
onLocate,
|
|
708
747
|
customContent: customPreviewContent || void 0,
|
|
709
748
|
customHeader: customPreviewHeader || void 0,
|
|
710
749
|
customActions: typeof customActions === "function" ? customActions(previewFile) : customActions,
|
|
@@ -740,8 +779,10 @@ var FileComponent = ({
|
|
|
740
779
|
onFileClick,
|
|
741
780
|
onPreview: handlePreview,
|
|
742
781
|
onShare,
|
|
782
|
+
onLocate,
|
|
743
783
|
prefixCls,
|
|
744
|
-
hashId
|
|
784
|
+
hashId,
|
|
785
|
+
bindDomId
|
|
745
786
|
}
|
|
746
787
|
);
|
|
747
788
|
}
|
|
@@ -754,8 +795,10 @@ var FileComponent = ({
|
|
|
754
795
|
onDownload,
|
|
755
796
|
onShare,
|
|
756
797
|
onPreview: handlePreview,
|
|
798
|
+
onLocate,
|
|
757
799
|
prefixCls,
|
|
758
|
-
hashId
|
|
800
|
+
hashId,
|
|
801
|
+
bindDomId
|
|
759
802
|
}
|
|
760
803
|
);
|
|
761
804
|
});
|
|
@@ -22,6 +22,8 @@ export interface PreviewComponentProps {
|
|
|
22
22
|
anchorEl?: HTMLElement;
|
|
23
23
|
origin?: string;
|
|
24
24
|
}) => void;
|
|
25
|
+
/** 定位回调 */
|
|
26
|
+
onLocate?: (file: FileNode) => void;
|
|
25
27
|
/** Markdown 编辑器配置 */
|
|
26
28
|
markdownEditorProps?: Partial<Omit<MarkdownEditorProps, 'editorRef' | 'initValue' | 'readonly'>>;
|
|
27
29
|
/** 头部文件信息覆盖 */
|
|
@@ -29,14 +31,5 @@ export interface PreviewComponentProps {
|
|
|
29
31
|
}
|
|
30
32
|
/**
|
|
31
33
|
* 文件预览组件
|
|
32
|
-
*
|
|
33
|
-
* @example
|
|
34
|
-
* ```tsx
|
|
35
|
-
* <PreviewComponent
|
|
36
|
-
* file={fileNode}
|
|
37
|
-
* onBack={() => setPreviewFile(null)}
|
|
38
|
-
* customActions={<Button icon={<EditIcon />}>编辑</Button>}
|
|
39
|
-
* />
|
|
40
|
-
* ```
|
|
41
34
|
*/
|
|
42
35
|
export declare const PreviewComponent: FC<PreviewComponentProps>;
|