@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.
Files changed (37) hide show
  1. package/dist/Bubble/List/PureBubbleList.d.ts +32 -0
  2. package/dist/Bubble/List/PureBubbleList.js +143 -0
  3. package/dist/Bubble/List/index.d.ts +1 -0
  4. package/dist/Bubble/List/index.js +2 -0
  5. package/dist/Bubble/PureBubble.d.ts +15 -0
  6. package/dist/Bubble/PureBubble.js +350 -0
  7. package/dist/Bubble/index.d.ts +2 -0
  8. package/dist/Bubble/index.js +6 -0
  9. package/dist/History/components/HistoryEmpty.js +3 -3
  10. package/dist/History/components/LoadMoreComponent.js +7 -3
  11. package/dist/History/components/SearchComponent.js +8 -13
  12. package/dist/History/hooks/useHistory.js +1 -1
  13. package/dist/History/index.d.ts +1 -0
  14. package/dist/History/index.js +26 -23
  15. package/dist/History/types/index.d.ts +2 -0
  16. package/dist/Hooks/useLanguage.d.ts +1 -0
  17. package/dist/I18n/locales.d.ts +1 -0
  18. package/dist/I18n/locales.js +2 -0
  19. package/dist/MarkdownEditor/BaseMarkdownEditor.js +6 -2
  20. package/dist/MarkdownEditor/editor/store.d.ts +4 -2
  21. package/dist/MarkdownEditor/editor/store.js +8 -3
  22. package/dist/MarkdownEditor/editor/utils/markdownToHtml.d.ts +6 -2
  23. package/dist/MarkdownEditor/editor/utils/markdownToHtml.js +44 -11
  24. package/dist/MarkdownEditor/types.d.ts +5 -0
  25. package/dist/MarkdownInputField/AttachmentButton/index.js +6 -4
  26. package/dist/MarkdownInputField/FileUploadManager/index.js +9 -0
  27. package/dist/Workspace/File/FileComponent.d.ts +3 -50
  28. package/dist/Workspace/File/FileComponent.js +52 -9
  29. package/dist/Workspace/File/PreviewComponent.d.ts +2 -9
  30. package/dist/Workspace/File/PreviewComponent.js +14 -0
  31. package/dist/Workspace/File/style.js +13 -0
  32. package/dist/Workspace/RealtimeFollow/index.js +2 -1
  33. package/dist/Workspace/RealtimeFollow/style.js +15 -4
  34. package/dist/Workspace/index.d.ts +2 -42
  35. package/dist/Workspace/index.js +1 -4
  36. package/dist/Workspace/types.d.ts +9 -0
  37. 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);
@@ -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(当没有历史记录时)
@@ -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, _i, _j, _k, _l;
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 ? props.emptyRender ? props.emptyRender() : /* @__PURE__ */ React.createElement(HistoryEmpty, null) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
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
- ), ((_i = props.agent) == null ? void 0 : _i.enabled) && !!((_j = props.agent) == null ? void 0 : _j.onLoadMore) && /* @__PURE__ */ React.createElement(
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" }, props.emptyRender ? props.emptyRender() : /* @__PURE__ */ React.createElement(HistoryEmpty, null)) : /* @__PURE__ */ React.createElement(
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
- ), ((_k = props.agent) == null ? void 0 : _k.enabled) && !!((_l = props.agent) == null ? void 0 : _l.onLoadMore) && !props.loading && /* @__PURE__ */ React.createElement(
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;
@@ -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;
@@ -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(markdownEditorRef, props.plugins),
175
- [props.plugins]
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
- return markdownToHtmlSync(markdown);
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 markdownToHtml = (markdown) => __async(void 0, null, function* () {
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 unified().use(remarkParse).use(remarkGfm).use(fixStrongWithSpecialChars).use(remarkMath, {
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 processor = unified().use(remarkParse).use(remarkGfm).use(fixStrongWithSpecialChars).use(remarkMath, {
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 = (fileCount, props) => {
58
+ var validateFileCount = (newFileCount, existingFileCount, props) => {
59
59
  var _a, _b;
60
- if (props.maxFileCount && fileCount > props.maxFileCount) {
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 && fileCount < 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 = ({ file, onClick, onDownload, onPreview, onShare, prefixCls, hashId }) => {
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>;