@zjlab-fe/data-hub-ui 0.32.6 → 0.33.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 (73) hide show
  1. package/dist/types/components/FileUploader/UploadStoreProvider/UploadStoreProvider.d.ts +4 -1
  2. package/dist/types/components/SDK-modal/document-link.d.ts +1 -3
  3. package/dist/types/components/SDK-modal/index.d.ts +4 -0
  4. package/dist/types/components/SDK-modal/inner-modal.d.ts +9 -0
  5. package/dist/types/components/SDK-modal/types.d.ts +4 -3
  6. package/dist/types/components/apply-perm-modal/index.d.ts +14 -5
  7. package/dist/types/components/confirm-again/index.d.ts +8 -1
  8. package/dist/types/components/copy/index.d.ts +9 -4
  9. package/dist/types/components/limit-credit-modal/index.d.ts +9 -3
  10. package/dist/types/components/tag-group-filter/dataSizeFilter.d.ts +0 -1
  11. package/dist/types/components/tag-group-filter/index.d.ts +4 -1
  12. package/dist/types/index.d.ts +7 -5
  13. package/dist/types/locale/index.d.ts +18 -0
  14. package/dist/types/locale/modalHolder.d.ts +11 -0
  15. package/dist/types/locale/resolveLocale.d.ts +9 -0
  16. package/dist/types/locale/translations.d.ts +808 -0
  17. package/dist/types/locale/types.d.ts +32 -0
  18. package/es/components/FileUploader/Locale/useTranslate.js +34 -11
  19. package/es/components/FileUploader/UploadStoreProvider/UploadStoreProvider.js +5 -3
  20. package/es/components/FileUploader/hooks/useOnMountedResumeUnfinished.js +6 -3
  21. package/es/components/SDK-modal/document-link.js +5 -2
  22. package/es/components/SDK-modal/index.js +29 -2
  23. package/es/components/SDK-modal/inner-modal.js +23 -12
  24. package/es/components/apply-perm-modal/index.js +20 -8
  25. package/es/components/confirm-again/index.js +12 -2
  26. package/es/components/copy/index.js +21 -7
  27. package/es/components/data-table/index.js +15 -4
  28. package/es/components/dataset-batch-action/index.js +48 -25
  29. package/es/components/file-preview/data-table/index.js +4 -3
  30. package/es/components/file-preview/index.js +5 -4
  31. package/es/components/file-uploader/components/uploader-drop-zone.js +4 -2
  32. package/es/components/file-uploader/components/uploader-file-item.js +12 -9
  33. package/es/components/file-uploader/components/uploader-file-list.js +6 -3
  34. package/es/components/file-uploader/components/uploader.js +4 -2
  35. package/es/components/file-uploader/components/uploading-status.js +18 -12
  36. package/es/components/header/index.js +3 -1
  37. package/es/components/input-tag/index.js +5 -2
  38. package/es/components/limit-credit-modal/index.js +38 -19
  39. package/es/components/menu/index.js +5 -2
  40. package/es/components/notion-editor/code-block/languages.js +1 -1
  41. package/es/components/notion-editor/index.js +23 -13
  42. package/es/components/operator-chain/components/AddButton.js +3 -1
  43. package/es/components/operator-chain/components/IOCard.js +4 -1
  44. package/es/components/operator-chain/components/VirtualDropdown.js +6 -3
  45. package/es/components/permission-editor/index.js +1 -0
  46. package/es/components/permission-editor/permissionEditModal/index.js +7 -4
  47. package/es/components/permission-editor/permissionEditor/index.js +40 -75
  48. package/es/components/permission-editor/permissionViewPopover/index.js +5 -2
  49. package/es/components/tag-group-filter/dataSizeFilter.js +6 -3
  50. package/es/components/tag-group-filter/index.js +2 -2
  51. package/es/components/tip-tap/bubble-menu.js +8 -3
  52. package/es/components/tip-tap/editor.js +5 -2
  53. package/es/components/tip-tap/extensions/index.js +1 -1
  54. package/es/components/tip-tap/toolbar/components/color-picker.js +3 -1
  55. package/es/components/tip-tap/toolbar/components/heading-dropdown.js +8 -5
  56. package/es/components/tip-tap/toolbar/components/link-button.js +4 -1
  57. package/es/components/tip-tap/toolbar/components/table-button.js +5 -2
  58. package/es/components/tip-tap/toolbar/index.js +4 -1
  59. package/es/components/uploadDrawer/fileUploadDrawer.js +6 -2
  60. package/es/components/uploadDrawer/fileUploadDrawerList.js +4 -1
  61. package/es/components/uploadDrawer/fileUploadDrawerListProgressButton.js +4 -2
  62. package/es/components/uploadDrawer/hooks/useCancelUpload.js +3 -1
  63. package/es/components/uploadDrawer/hooks/useFilterFiles.js +7 -4
  64. package/es/components/uploadDrawer/hooks/useFormatFiles.js +3 -1
  65. package/es/components/uploadDrawer/hooks/useResumeUnfinishedUploads.js +7 -6
  66. package/es/components/uploadDrawer/index.js +4 -2
  67. package/es/index.js +6 -5
  68. package/es/locale/index.js +64 -0
  69. package/es/locale/modalHolder.js +21 -0
  70. package/es/locale/resolveLocale.js +73 -0
  71. package/es/locale/translations.js +273 -0
  72. package/lib/index.js +1 -1
  73. package/package.json +7 -3
@@ -3,8 +3,11 @@ import { jsx } from 'react/jsx-runtime';
3
3
  import { useState, useEffect } from 'react';
4
4
  import { Modal, Button, message } from 'antd';
5
5
  import PermissionEditor from '../permissionEditor/index.js';
6
+ import { useLocale } from '../../../locale/index.js';
6
7
 
7
8
  const PermissionEditModal = ({ open, onCancel, onSave, initialPermissions = [], }) => {
9
+ const { locale } = useLocale();
10
+ const texts = locale.PermissionEditor;
8
11
  const [selectedPermissions, setSelectedPermissions] = useState(initialPermissions);
9
12
  const [loading, setLoading] = useState(false);
10
13
  // 当 modal 打开时重置权限状态
@@ -19,7 +22,7 @@ const PermissionEditModal = ({ open, onCancel, onSave, initialPermissions = [],
19
22
  onCancel();
20
23
  }
21
24
  catch (error) {
22
- message.error('权限更新失败');
25
+ message.error(texts.updateFailed);
23
26
  console.error('保存权限失败:', error);
24
27
  }
25
28
  });
@@ -28,9 +31,9 @@ const PermissionEditModal = ({ open, onCancel, onSave, initialPermissions = [],
28
31
  setSelectedPermissions(initialPermissions);
29
32
  onCancel();
30
33
  };
31
- return (jsx(Modal, { title: `编辑权限`, open: open, onCancel: handleCancel, width: 600, destroyOnClose: true, footer: [
32
- jsx(Button, { onClick: handleCancel, children: "\u53D6\u6D88" }, "cancel"),
33
- jsx(Button, { type: "primary", loading: loading, onClick: handleSave, children: "\u4FDD\u5B58" }, "save"),
34
+ return (jsx(Modal, { title: texts.title, open: open, onCancel: handleCancel, width: 600, destroyOnClose: true, footer: [
35
+ jsx(Button, { onClick: handleCancel, children: texts.cancel }, "cancel"),
36
+ jsx(Button, { type: "primary", loading: loading, onClick: handleSave, children: texts.save }, "save"),
34
37
  ], children: jsx("div", { style: { padding: '16px 0' }, children: jsx(PermissionEditor, { initialPermissions: selectedPermissions, onChange: setSelectedPermissions, editable: true }) }) }));
35
38
  };
36
39
 
@@ -3,103 +3,67 @@ import React from 'react';
3
3
  import { Tag, Flex } from 'antd';
4
4
  import { unEditable, tagReadonly } from './index.module.scss.js';
5
5
  import { CheckCircleOutlined } from '@ant-design/icons';
6
+ import { useLocale } from '../../../locale/index.js';
6
7
 
7
8
  const permissionTags = [
8
9
  {
9
- label: '数据权限',
10
10
  value: 'agentic',
11
11
  readOnly: false,
12
- children: [
13
- {
14
- label: '检索智能体',
15
- value: '13',
16
- readOnly: false,
17
- },
18
- ],
12
+ children: [{ value: '13', readOnly: false }],
19
13
  },
20
14
  {
21
- label: '工作台权限',
22
15
  value: 'workbench',
23
16
  readOnly: false,
24
17
  children: [
25
- {
26
- label: '语料生产服务',
27
- value: '20',
28
- readOnly: false,
29
- },
30
- {
31
- label: '语料质量评估',
32
- value: '18',
33
- readOnly: false,
34
- },
35
- {
36
- label: '可视化工作流',
37
- value: '1',
38
- readOnly: false,
39
- },
40
- {
41
- label: '文档标注',
42
- value: '8',
43
- readOnly: false,
44
- },
45
- {
46
- label: '模型训练',
47
- value: '19',
48
- readOnly: false,
49
- },
50
- {
51
- label: '计量中心',
52
- value: '23',
53
- readOnly: false,
54
- },
55
- {
56
- label: '模型部署',
57
- value: '21',
58
- readOnly: true,
59
- },
60
- {
61
- label: '模型管理',
62
- value: '22',
63
- readOnly: true,
64
- },
18
+ { value: '20', readOnly: false },
19
+ { value: '18', readOnly: false },
20
+ { value: '1', readOnly: false },
21
+ { value: '8', readOnly: false },
22
+ { value: '19', readOnly: false },
23
+ { value: '23', readOnly: false },
24
+ { value: '21', readOnly: true },
25
+ { value: '22', readOnly: true },
65
26
  ],
66
27
  },
67
28
  {
68
- label: '语料检索权限',
69
29
  value: 'corpus_index',
70
30
  readOnly: false,
71
31
  children: [
72
- {
73
- label: '文献语料检索',
74
- value: '14',
75
- readOnly: false,
76
- },
77
- {
78
- label: '网页语料筛选',
79
- value: '15',
80
- readOnly: false,
81
- },
32
+ { value: '14', readOnly: false },
33
+ { value: '15', readOnly: false },
82
34
  ],
83
35
  },
84
36
  {
85
- label: '语料生产权限',
86
37
  value: 'corpus_product',
87
38
  readOnly: false,
88
39
  children: [
89
- {
90
- label: '文档语料生产',
91
- value: '16',
92
- readOnly: false,
93
- },
94
- {
95
- label: '网页语料生产',
96
- value: '17',
97
- readOnly: false,
98
- },
40
+ { value: '16', readOnly: false },
41
+ { value: '17', readOnly: false },
99
42
  ],
100
43
  },
101
44
  ];
45
+ const PERMISSION_LABEL_KEY = {
46
+ agentic: 'agentic',
47
+ '13': 'agenticSearch',
48
+ workbench: 'workbench',
49
+ '20': 'corpusProductionService',
50
+ '18': 'corpusQuality',
51
+ '1': 'visualWorkflow',
52
+ '8': 'documentAnnotation',
53
+ '19': 'modelTraining',
54
+ '23': 'meteringCenter',
55
+ '21': 'modelDeploy',
56
+ '22': 'modelManage',
57
+ corpus_index: 'corpusIndex',
58
+ '14': 'literatureSearch',
59
+ '15': 'webFilter',
60
+ corpus_product: 'corpusProduct',
61
+ '16': 'documentProduction',
62
+ '17': 'webProduction',
63
+ };
102
64
  const PermissionEditor = ({ initialPermissions = [], onChange, editable = true, }) => {
65
+ const { locale } = useLocale();
66
+ const texts = locale.PermissionEditor;
103
67
  // 将新格式转换为内部使用的扁平化格式
104
68
  const convertToFlatFormat = (permissions) => {
105
69
  const flatTags = [];
@@ -225,9 +189,9 @@ const PermissionEditor = ({ initialPermissions = [], onChange, editable = true,
225
189
  onChange === null || onChange === void 0 ? void 0 : onChange(modulePermissions);
226
190
  };
227
191
  return (jsx(Fragment, { children: permissionTags.map((tag) => {
228
- var _a;
192
+ var _a, _b;
229
193
  const isSelected = selectedTags.includes(tag.value);
230
- return (jsxs("div", { style: { width: '100%', margin: '8px 0' }, className: !editable ? unEditable : '', children: [jsx("span", { style: { fontSize: '16px', fontWeight: 500, marginRight: 8 }, children: tag.label }), editable && (jsx(Tag.CheckableTag, { checked: isSelected, onChange: (checked) => handleChange(tag.value, checked, tag.readOnly), style: {
194
+ return (jsxs("div", { style: { width: '100%', margin: '8px 0' }, className: !editable ? unEditable : '', children: [jsx("span", { style: { fontSize: '16px', fontWeight: 500, marginRight: 8 }, children: (_a = texts[PERMISSION_LABEL_KEY[tag.value]]) !== null && _a !== void 0 ? _a : tag.value }), editable && (jsx(Tag.CheckableTag, { checked: isSelected, onChange: (checked) => handleChange(tag.value, checked, tag.readOnly), style: {
231
195
  cursor: tag.readOnly ? 'not-allowed' : 'pointer',
232
196
  opacity: tag.readOnly ? 0.7 : 1,
233
197
  margin: '5px 0',
@@ -238,14 +202,15 @@ const PermissionEditor = ({ initialPermissions = [], onChange, editable = true,
238
202
  width: 18,
239
203
  border: 0,
240
204
  borderRadius: '50%',
241
- }, className: tag.readOnly ? tagReadonly : '', children: jsx(CheckCircleOutlined, { style: { fontSize: '18px' }, title: isSelected ? '取消全选' : '全选' }) }, tag.value)), jsx(Flex, { gap: 5, wrap: true, align: "center", children: (_a = tag.children) === null || _a === void 0 ? void 0 : _a.map((child) => {
205
+ }, className: tag.readOnly ? tagReadonly : '', children: jsx(CheckCircleOutlined, { style: { fontSize: '18px' }, title: isSelected ? texts.unselectAll : texts.selectAll }) }, tag.value)), jsx(Flex, { gap: 5, wrap: true, align: "center", children: (_b = tag.children) === null || _b === void 0 ? void 0 : _b.map((child) => {
206
+ var _a;
242
207
  const isChildSelected = selectedTags.includes(child.value);
243
208
  return (jsx(Tag.CheckableTag, { checked: isChildSelected, onChange: (checked) => handleChange(child.value, checked, child.readOnly), style: {
244
209
  cursor: child.readOnly ? 'not-allowed' : 'pointer',
245
210
  opacity: child.readOnly ? 0.7 : 1,
246
211
  margin: '5px 0',
247
212
  border: '1px solid #979797',
248
- }, className: child.readOnly ? tagReadonly : '', children: child.label }, child.value));
213
+ }, className: child.readOnly ? tagReadonly : '', children: (_a = texts[PERMISSION_LABEL_KEY[child.value]]) !== null && _a !== void 0 ? _a : child.value }, child.value));
249
214
  }) })] }, tag.value));
250
215
  }) }));
251
216
  };
@@ -1,9 +1,12 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { Popover } from 'antd';
3
3
  import PermissionEditor from '../permissionEditor/index.js';
4
+ import { useLocale } from '../../../locale/index.js';
4
5
 
5
- const PermissionViewPopover = ({ initialPermissions = [], children, title = '用户权限', width = 400, }) => {
6
- return (jsx(Popover, { content: jsx(PermissionEditor, { initialPermissions: initialPermissions, editable: false }), title: title, overlayStyle: { width }, children: children }));
6
+ const PermissionViewPopover = ({ initialPermissions = [], children, title, width = 400, }) => {
7
+ const { locale } = useLocale();
8
+ const resolvedTitle = title !== null && title !== void 0 ? title : locale.PermissionEditor.viewTitle;
9
+ return (jsx(Popover, { content: jsx(PermissionEditor, { initialPermissions: initialPermissions, editable: false }), title: resolvedTitle, overlayStyle: { width }, children: children }));
7
10
  };
8
11
 
9
12
  export { PermissionViewPopover as default };
@@ -4,6 +4,7 @@ import { Select, Flex, InputNumber } from 'antd';
4
4
  import { dataSizeFilter, iconTagHeader, iconTagContent, header, iconClear } from './index.module.scss.js';
5
5
  import { MinusOutlined } from '@ant-design/icons';
6
6
  import iconTagHeader$1 from '../../assets/icon-tag-header.png.js';
7
+ import { useLocale } from '../../locale/index.js';
7
8
 
8
9
  const { Option } = Select;
9
10
  const DATA_SIZE_UNIT = [
@@ -25,6 +26,8 @@ const transToMB = (value, unit) => {
25
26
  }
26
27
  };
27
28
  function DataSizeFilter(p) {
29
+ const { locale } = useLocale();
30
+ const texts = locale.TagGroupFilter;
28
31
  const [startValue, setStartValue] = React.useState(null);
29
32
  const [startUnit, setStartUnit] = React.useState('kb');
30
33
  const [endValue, setEndValue] = React.useState(null);
@@ -36,10 +39,10 @@ function DataSizeFilter(p) {
36
39
  if (startValue !== null &&
37
40
  endValue !== null &&
38
41
  transToMB(startValue, startUnit) > transToMB(endValue, endUnit)) {
39
- res = p.isEn ? 'The left value can not greater than the right value' : '左侧数值不能大于右侧数值';
42
+ res = texts.rangeError;
40
43
  }
41
44
  return res;
42
- }, [startValue, startUnit, endValue, endUnit, p.isEn]);
45
+ }, [startValue, startUnit, endValue, endUnit, texts.rangeError]);
43
46
  const handleClear = (e) => {
44
47
  e.stopPropagation();
45
48
  p.onChange(['', '']);
@@ -94,7 +97,7 @@ function DataSizeFilter(p) {
94
97
  setEndValue(p.value[1] ? +p.value[1].slice(0, -2) : null);
95
98
  setEndUnit(p.value[1] ? p.value[1].slice(-2) : 'kb');
96
99
  }, [p.value]);
97
- return (jsxs("div", { className: dataSizeFilter, children: [jsx("span", { className: iconTagHeader, style: { backgroundImage: 'url(' + iconTagHeader$1 + ')' } }), jsx("span", { className: iconTagContent }), jsx(Flex, { justify: "space-between", align: "center", className: header, children: jsxs(Flex, { align: "center", children: [jsx("h3", { children: p.isEn ? 'DataVolume' : '数据体量' }), (startValue !== null || endValue !== null) && (jsx("span", { className: iconClear, onClick: handleClear, children: "\uE85E" }))] }) }), jsxs(Fragment, { children: [jsxs(Flex, { align: "center", children: [jsx(InputNumber, { ref: startInputRef, value: startValue, controls: false, placeholder: p.isEn ? 'Min' : '最小', size: "small", style: { fontSize: 12, width: 140 }, addonAfter: jsx(Select, { style: { width: 50 }, popupMatchSelectWidth: false, value: startUnit, onChange: handleStartUnitChange, children: DATA_SIZE_UNIT.map((item, i) => (jsx(Option, { value: item.value, children: item.name }, i))) }), onChange: handleStartValueChange, onPressEnter: handleStartPressEnter, onBlur: handleStartBlur }), jsx(MinusOutlined, { style: { margin: '0 4px' } }), jsx(InputNumber, { ref: endInputRef, value: endValue, controls: false, placeholder: p.isEn ? 'Max' : '最大', size: "small", style: { fontSize: 12, width: 140 }, addonAfter: jsx(Select, { style: { width: 50 }, popupMatchSelectWidth: false, value: endUnit, onChange: handleEndUnitChange, children: DATA_SIZE_UNIT.map((item, i) => (jsx(Option, { value: item.value, children: item.name }, i))) }), onChange: handleEndValueChange, onPressEnter: handleEndPressEnter, onBlur: handleEndBlur })] }), !!errMsg && jsx("div", { style: { color: 'red', marginTop: 4 }, children: errMsg })] })] }));
100
+ return (jsxs("div", { className: dataSizeFilter, children: [jsx("span", { className: iconTagHeader, style: { backgroundImage: 'url(' + iconTagHeader$1 + ')' } }), jsx("span", { className: iconTagContent }), jsx(Flex, { justify: "space-between", align: "center", className: header, children: jsxs(Flex, { align: "center", children: [jsx("h3", { children: texts.dataVolume }), (startValue !== null || endValue !== null) && (jsx("span", { className: iconClear, onClick: handleClear, children: "\uE85E" }))] }) }), jsxs(Fragment, { children: [jsxs(Flex, { align: "center", children: [jsx(InputNumber, { ref: startInputRef, value: startValue, controls: false, placeholder: texts.min, size: "small", style: { fontSize: 12, width: 140 }, addonAfter: jsx(Select, { style: { width: 50 }, popupMatchSelectWidth: false, value: startUnit, onChange: handleStartUnitChange, children: DATA_SIZE_UNIT.map((item, i) => (jsx(Option, { value: item.value, children: item.name }, i))) }), onChange: handleStartValueChange, onPressEnter: handleStartPressEnter, onBlur: handleStartBlur }), jsx(MinusOutlined, { style: { margin: '0 4px' } }), jsx(InputNumber, { ref: endInputRef, value: endValue, controls: false, placeholder: texts.max, size: "small", style: { fontSize: 12, width: 140 }, addonAfter: jsx(Select, { style: { width: 50 }, popupMatchSelectWidth: false, value: endUnit, onChange: handleEndUnitChange, children: DATA_SIZE_UNIT.map((item, i) => (jsx(Option, { value: item.value, children: item.name }, i))) }), onChange: handleEndValueChange, onPressEnter: handleEndPressEnter, onBlur: handleEndBlur })] }), !!errMsg && jsx("div", { style: { color: 'red', marginTop: 4 }, children: errMsg })] })] }));
98
101
  }
99
102
 
100
103
  export { DataSizeFilter as default };
@@ -10,7 +10,7 @@ import { tagGroupFilter } from './index.module.scss.js';
10
10
  * @param tagSelected 标签选中状态
11
11
  * @param needDataSizeFilter 是否需要数据量过滤(可选)
12
12
  * @param dataSizeValue 数据量过滤值(可选)
13
- * @param isEn 是否英文环境(可选)
13
+ * @param isEn 已废弃,语言由 DataHubProvider / antd ConfigProvider 决定
14
14
  * @param tagClassName 标签类名(可选)
15
15
  * @param onTagChange 标签选中状态变化回调
16
16
  * @param onDataSizeChange 数据量过滤值变化回调(可选)
@@ -47,7 +47,7 @@ function TagGroupFilter(p) {
47
47
  React.useEffect(() => {
48
48
  setMenuOpenKeys(p.tagGroupDatas.map((item) => item.key));
49
49
  }, [p.tagGroupDatas]);
50
- return (jsx("div", { className: tagGroupFilter, children: viewTagGroupDatas.map((item, index) => (jsx(React.Fragment, { children: item.key === 'dataSize' ? (jsx(DataSizeFilter, { isEn: p.isEn, value: p.dataSizeValue || [], onChange: handleDataSizeChange })) : (jsx(TagFilter, { title: item.title, list: item.children, selected: p.tagSelected[item.key] || [], isFold: !menuOpenKeys.includes(item.key), onChange: (selectd) => handleTagChange(item.key, selectd), onFoldChange: (isFold) => handleOpenKeysChange(item.key, isFold), tagClassName: p.tagClassName }, item.key)) }, index))) }));
50
+ return (jsx("div", { className: tagGroupFilter, children: viewTagGroupDatas.map((item, index) => (jsx(React.Fragment, { children: item.key === 'dataSize' ? (jsx(DataSizeFilter, { value: p.dataSizeValue || [], onChange: handleDataSizeChange })) : (jsx(TagFilter, { title: item.title, list: item.children, selected: p.tagSelected[item.key] || [], isFold: !menuOpenKeys.includes(item.key), onChange: (selectd) => handleTagChange(item.key, selectd), onFoldChange: (isFold) => handleOpenKeysChange(item.key, isFold), tagClassName: p.tagClassName }, item.key)) }, index))) }));
51
51
  }
52
52
 
53
53
  export { TagGroupFilter as default };
@@ -1,14 +1,19 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { useState, useRef } from 'react';
3
3
  import { IconBold, IconItalic, IconUnderline, IconStrikethrough, IconHighlight, IconCheck, IconTrash, IconLink } from './icons/index.js';
4
+ import { useLocale } from '../../locale/index.js';
4
5
 
5
6
  function TipTapBubbleMenu({ editor }) {
6
- return (jsxs("div", { className: "tip-tap-bubble-menu", children: [jsx(BubbleButton, { icon: jsx(IconBold, {}), onClick: () => editor.chain().focus().toggleBold().run(), active: editor.isActive('bold'), tooltip: "\u7C97\u4F53" }), jsx(BubbleButton, { icon: jsx(IconItalic, {}), onClick: () => editor.chain().focus().toggleItalic().run(), active: editor.isActive('italic'), tooltip: "\u659C\u4F53" }), jsx(BubbleButton, { icon: jsx(IconUnderline, {}), onClick: () => editor.chain().focus().toggleUnderline().run(), active: editor.isActive('underline'), tooltip: "\u4E0B\u5212\u7EBF" }), jsx(BubbleButton, { icon: jsx(IconStrikethrough, {}), onClick: () => editor.chain().focus().toggleStrike().run(), active: editor.isActive('strike'), tooltip: "\u5220\u9664\u7EBF" }), jsx("div", { className: "tip-tap-toolbar__divider" }), jsx(BubbleButton, { icon: jsx(IconHighlight, {}), onClick: () => editor.chain().focus().toggleHighlight().run(), active: editor.isActive('highlight'), tooltip: "\u9AD8\u4EAE" }), jsx("div", { className: "tip-tap-toolbar__divider" }), jsx(BubbleLinkButton, { editor: editor })] }));
7
+ const { locale } = useLocale();
8
+ const texts = locale.TipTap;
9
+ return (jsxs("div", { className: "tip-tap-bubble-menu", children: [jsx(BubbleButton, { icon: jsx(IconBold, {}), onClick: () => editor.chain().focus().toggleBold().run(), active: editor.isActive('bold'), tooltip: texts.bold }), jsx(BubbleButton, { icon: jsx(IconItalic, {}), onClick: () => editor.chain().focus().toggleItalic().run(), active: editor.isActive('italic'), tooltip: texts.italic }), jsx(BubbleButton, { icon: jsx(IconUnderline, {}), onClick: () => editor.chain().focus().toggleUnderline().run(), active: editor.isActive('underline'), tooltip: texts.underline }), jsx(BubbleButton, { icon: jsx(IconStrikethrough, {}), onClick: () => editor.chain().focus().toggleStrike().run(), active: editor.isActive('strike'), tooltip: texts.strike }), jsx("div", { className: "tip-tap-toolbar__divider" }), jsx(BubbleButton, { icon: jsx(IconHighlight, {}), onClick: () => editor.chain().focus().toggleHighlight().run(), active: editor.isActive('highlight'), tooltip: texts.highlightShort }), jsx("div", { className: "tip-tap-toolbar__divider" }), jsx(BubbleLinkButton, { editor: editor })] }));
7
10
  }
8
11
  function BubbleButton({ icon, onClick, active = false, tooltip, }) {
9
12
  return (jsx("button", { className: `tip-tap-btn ${active ? 'tip-tap-btn--active' : ''}`, onClick: onClick, type: "button", title: tooltip, children: icon }));
10
13
  }
11
14
  function BubbleLinkButton({ editor }) {
15
+ const { locale } = useLocale();
16
+ const texts = locale.TipTap;
12
17
  const [showInput, setShowInput] = useState(false);
13
18
  const [url, setUrl] = useState('');
14
19
  const inputRef = useRef(null);
@@ -34,14 +39,14 @@ function BubbleLinkButton({ editor }) {
34
39
  setUrl('');
35
40
  }
36
41
  if (showInput) {
37
- return (jsxs("div", { className: "tip-tap-link-popup", style: { boxShadow: 'none', border: 'none', padding: 0, margin: 0 }, children: [jsx("input", { ref: inputRef, type: "text", className: "tip-tap-link-popup__input", style: { width: '160px', padding: '4px 8px', fontSize: '13px' }, placeholder: "\u8F93\u5165\u94FE\u63A5...", value: url, onChange: (e) => setUrl(e.target.value), onKeyDown: (e) => {
42
+ return (jsxs("div", { className: "tip-tap-link-popup", style: { boxShadow: 'none', border: 'none', padding: 0, margin: 0 }, children: [jsx("input", { ref: inputRef, type: "text", className: "tip-tap-link-popup__input", style: { width: '160px', padding: '4px 8px', fontSize: '13px' }, placeholder: texts.linkPlaceholder, value: url, onChange: (e) => setUrl(e.target.value), onKeyDown: (e) => {
38
43
  if (e.key === 'Enter')
39
44
  handleSubmit();
40
45
  if (e.key === 'Escape')
41
46
  setShowInput(false);
42
47
  } }), jsx("button", { className: "tip-tap-btn", onClick: handleSubmit, type: "button", style: { width: '24px', height: '24px' }, children: jsx(IconCheck, {}) }), editor.isActive('link') && (jsx("button", { className: "tip-tap-btn", onClick: handleRemove, type: "button", style: { width: '24px', height: '24px', color: '#dc2626' }, children: jsx(IconTrash, {}) }))] }));
43
48
  }
44
- return (jsx(BubbleButton, { icon: jsx(IconLink, {}), onClick: handleOpenInput, active: editor.isActive('link'), tooltip: "\u94FE\u63A5" }));
49
+ return (jsx(BubbleButton, { icon: jsx(IconLink, {}), onClick: handleOpenInput, active: editor.isActive('link'), tooltip: texts.link }));
45
50
  }
46
51
 
47
52
  export { TipTapBubbleMenu as default };
@@ -6,11 +6,14 @@ import { forwardRef, useImperativeHandle } from 'react';
6
6
  import { editorExtensions } from './extensions/index.js';
7
7
  import Toolbar from './toolbar/index.js';
8
8
  import TipTapBubbleMenu from './bubble-menu.js';
9
+ import { useLocale } from '../../locale/index.js';
9
10
 
10
11
  useStyle();
11
- var editor = forwardRef(function TipTapEditor({ content = '', placeholder = '开始输入内容...', editable = true, autofocus = false, className = '', toolbarClassName = '', onChange, }, ref) {
12
+ var editor = forwardRef(function TipTapEditor({ content = '', placeholder, editable = true, autofocus = false, className = '', toolbarClassName = '', onChange, }, ref) {
13
+ const { locale } = useLocale();
14
+ const resolvedPlaceholder = placeholder !== null && placeholder !== void 0 ? placeholder : locale.TipTap.placeholder;
12
15
  const editor = useEditor({
13
- extensions: editorExtensions(placeholder),
16
+ extensions: editorExtensions(resolvedPlaceholder),
14
17
  content,
15
18
  editable,
16
19
  autofocus,
@@ -33,7 +33,7 @@ const editorExtensions = (placeholder) => [
33
33
  },
34
34
  }),
35
35
  Placeholder.configure({
36
- placeholder: placeholder || '开始输入内容...',
36
+ placeholder: placeholder || undefined,
37
37
  emptyEditorClass: 'is-editor-empty',
38
38
  }),
39
39
  TextStyle,
@@ -2,8 +2,10 @@ import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { useEditorState } from '@tiptap/react';
3
3
  import { useState, useRef, useEffect } from 'react';
4
4
  import { IconBold, IconHighlight } from '../../icons/index.js';
5
+ import { useLocale } from '../../../../locale/index.js';
5
6
 
6
7
  function ColorPicker({ editor, type, tooltip }) {
8
+ const { locale } = useLocale();
7
9
  const [isOpen, setIsOpen] = useState(false);
8
10
  const dropdownRef = useRef(null);
9
11
  const colors = [
@@ -70,7 +72,7 @@ function ColorPicker({ editor, type, tooltip }) {
70
72
  }
71
73
  setIsOpen(false);
72
74
  }
73
- return (jsxs("div", { className: `tip-tap-dropdown ${isOpen ? 'tip-tap-dropdown--open' : ''}`, ref: dropdownRef, children: [jsxs("button", { className: `tip-tap-btn ${(editorState === null || editorState === void 0 ? void 0 : editorState.isActive) ? 'tip-tap-btn--active' : ''}`, onClick: () => setIsOpen(!isOpen), type: "button", style: type === 'textColor' && (editorState === null || editorState === void 0 ? void 0 : editorState.color) ? { color: editorState.color } : {}, children: [type === 'textColor' ? (jsx(IconBold, { style: { borderBottom: `3px solid ${(editorState === null || editorState === void 0 ? void 0 : editorState.color) || '#000'}` } })) : (jsx(IconHighlight, {})), jsx("span", { className: "tip-tap-tooltip", children: tooltip })] }), jsx("div", { className: "tip-tap-dropdown__menu", children: jsxs("div", { className: "tip-tap-color-picker", children: [jsx("button", { className: "tip-tap-color-picker__swatch tip-tap-color-picker__swatch--reset", onClick: () => handleColorSelect(null), title: "\u79FB\u9664\u989C\u8272", type: "button" }), colors.map((color) => (jsx("button", { className: "tip-tap-color-picker__swatch", style: { background: color }, onClick: () => handleColorSelect(color), type: "button" }, color)))] }) })] }));
75
+ return (jsxs("div", { className: `tip-tap-dropdown ${isOpen ? 'tip-tap-dropdown--open' : ''}`, ref: dropdownRef, children: [jsxs("button", { className: `tip-tap-btn ${(editorState === null || editorState === void 0 ? void 0 : editorState.isActive) ? 'tip-tap-btn--active' : ''}`, onClick: () => setIsOpen(!isOpen), type: "button", style: type === 'textColor' && (editorState === null || editorState === void 0 ? void 0 : editorState.color) ? { color: editorState.color } : {}, children: [type === 'textColor' ? (jsx(IconBold, { style: { borderBottom: `3px solid ${(editorState === null || editorState === void 0 ? void 0 : editorState.color) || '#000'}` } })) : (jsx(IconHighlight, {})), jsx("span", { className: "tip-tap-tooltip", children: tooltip })] }), jsx("div", { className: "tip-tap-dropdown__menu", children: jsxs("div", { className: "tip-tap-color-picker", children: [jsx("button", { className: "tip-tap-color-picker__swatch tip-tap-color-picker__swatch--reset", onClick: () => handleColorSelect(null), title: locale.TipTap.removeColor, type: "button" }), colors.map((color) => (jsx("button", { className: "tip-tap-color-picker__swatch", style: { background: color }, onClick: () => handleColorSelect(color), type: "button" }, color)))] }) })] }));
74
76
  }
75
77
 
76
78
  export { ColorPicker };
@@ -2,15 +2,18 @@ import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import { useEditorState } from '@tiptap/react';
3
3
  import { useState, useRef, useEffect } from 'react';
4
4
  import { IconParagraph, IconH1, IconH2, IconH3, IconChevronDown } from '../../icons/index.js';
5
+ import { useLocale } from '../../../../locale/index.js';
5
6
 
6
7
  function HeadingDropdown({ editor }) {
8
+ const { locale } = useLocale();
9
+ const texts = locale.TipTap;
7
10
  const [isOpen, setIsOpen] = useState(false);
8
11
  const dropdownRef = useRef(null);
9
12
  const headings = [
10
- { level: 0, label: '正文', icon: jsx(IconParagraph, {}) },
11
- { level: 1, label: '标题 1', icon: jsx(IconH1, {}) },
12
- { level: 2, label: '标题 2', icon: jsx(IconH2, {}) },
13
- { level: 3, label: '标题 3', icon: jsx(IconH3, {}) },
13
+ { level: 0, label: texts.paragraph, icon: jsx(IconParagraph, {}) },
14
+ { level: 1, label: texts.heading1, icon: jsx(IconH1, {}) },
15
+ { level: 2, label: texts.heading2, icon: jsx(IconH2, {}) },
16
+ { level: 3, label: texts.heading3, icon: jsx(IconH3, {}) },
14
17
  ];
15
18
  // 使用 useEditorState 来同步编辑器状态
16
19
  const editorState = useEditorState({
@@ -38,7 +41,7 @@ function HeadingDropdown({ editor }) {
38
41
  }
39
42
  setIsOpen(false);
40
43
  }
41
- return (jsxs("div", { className: `tip-tap-dropdown ${isOpen ? 'tip-tap-dropdown--open' : ''}`, ref: dropdownRef, children: [jsxs("button", { className: `tip-tap-dropdown__trigger ${editorState && editorState.level !== 0 ? 'tip-tap-dropdown__trigger--active' : ''}`, onClick: () => setIsOpen(!isOpen), type: "button", children: [(editorState === null || editorState === void 0 ? void 0 : editorState.icon) || jsx(IconParagraph, {}), jsx("span", { children: (editorState === null || editorState === void 0 ? void 0 : editorState.label) || '正文' }), jsx(IconChevronDown, { className: "tip-tap-dropdown__arrow" })] }), jsx("div", { className: "tip-tap-dropdown__menu", children: headings.map(({ level, label, icon }) => (jsxs("button", { className: `tip-tap-dropdown__item ${(editorState === null || editorState === void 0 ? void 0 : editorState.level) === level ? 'tip-tap-dropdown__item--active' : ''}`, onClick: () => handleSelect(level), type: "button", children: [jsx("span", { className: "tip-tap-dropdown__item-icon", children: icon }), label] }, level))) })] }));
44
+ return (jsxs("div", { className: `tip-tap-dropdown ${isOpen ? 'tip-tap-dropdown--open' : ''}`, ref: dropdownRef, children: [jsxs("button", { className: `tip-tap-dropdown__trigger ${editorState && editorState.level !== 0 ? 'tip-tap-dropdown__trigger--active' : ''}`, onClick: () => setIsOpen(!isOpen), type: "button", children: [(editorState === null || editorState === void 0 ? void 0 : editorState.icon) || jsx(IconParagraph, {}), jsx("span", { children: (editorState === null || editorState === void 0 ? void 0 : editorState.label) || texts.paragraph }), jsx(IconChevronDown, { className: "tip-tap-dropdown__arrow" })] }), jsx("div", { className: "tip-tap-dropdown__menu", children: headings.map(({ level, label, icon }) => (jsxs("button", { className: `tip-tap-dropdown__item ${(editorState === null || editorState === void 0 ? void 0 : editorState.level) === level ? 'tip-tap-dropdown__item--active' : ''}`, onClick: () => handleSelect(level), type: "button", children: [jsx("span", { className: "tip-tap-dropdown__item-icon", children: icon }), label] }, level))) })] }));
42
45
  }
43
46
 
44
47
  export { HeadingDropdown };
@@ -3,8 +3,11 @@ import { useEditorState } from '@tiptap/react';
3
3
  import { getMarkRange } from '@tiptap/core';
4
4
  import { useState, useRef, useEffect } from 'react';
5
5
  import { IconLink, IconCheck, IconTrash } from '../../icons/index.js';
6
+ import { useLocale } from '../../../../locale/index.js';
6
7
 
7
8
  function LinkButton({ editor }) {
9
+ const { locale } = useLocale();
10
+ const texts = locale.TipTap;
8
11
  const [isOpen, setIsOpen] = useState(false);
9
12
  const [label, setLabel] = useState('');
10
13
  const [url, setUrl] = useState('');
@@ -101,7 +104,7 @@ function LinkButton({ editor }) {
101
104
  setLabel('');
102
105
  setUrl('');
103
106
  }
104
- return (jsxs("div", { className: `tip-tap-dropdown ${isOpen ? 'tip-tap-dropdown--open' : ''}`, ref: dropdownRef, children: [jsxs("button", { className: `tip-tap-btn ${(editorState === null || editorState === void 0 ? void 0 : editorState.isActive) ? 'tip-tap-btn--active' : ''}`, onClick: handleToggleOpen, type: "button", children: [jsx(IconLink, {}), jsx("span", { className: "tip-tap-tooltip", children: "\u94FE\u63A5" })] }), jsx("div", { className: "tip-tap-dropdown__menu", style: { width: 'auto', padding: 0 }, children: jsxs("div", { className: "tip-tap-link-popup", style: { flexDirection: 'column', alignItems: 'stretch' }, children: [jsx("input", { ref: labelInputRef, type: "text", className: "tip-tap-link-popup__input", placeholder: "\u8F93\u5165\u94FE\u63A5\u6587\u672C...", value: label, onChange: (e) => setLabel(e.target.value), onKeyDown: (e) => e.key === 'Enter' && handleSubmit(), style: { marginBottom: '8px' } }), jsx("input", { type: "text", className: "tip-tap-link-popup__input", placeholder: "\u8F93\u5165\u94FE\u63A5\u5730\u5740...", value: url, onChange: (e) => setUrl(e.target.value), onKeyDown: (e) => e.key === 'Enter' && handleSubmit() }), jsxs("div", { style: { display: 'flex', gap: '4px', marginTop: '8px' }, children: [jsx("button", { className: "tip-tap-link-popup__btn", onClick: handleSubmit, type: "button", children: jsx(IconCheck, {}) }), (editorState === null || editorState === void 0 ? void 0 : editorState.isActive) && (jsx("button", { className: "tip-tap-link-popup__btn tip-tap-link-popup__btn--danger", onClick: handleRemove, type: "button", children: jsx(IconTrash, {}) }))] })] }) })] }));
107
+ return (jsxs("div", { className: `tip-tap-dropdown ${isOpen ? 'tip-tap-dropdown--open' : ''}`, ref: dropdownRef, children: [jsxs("button", { className: `tip-tap-btn ${(editorState === null || editorState === void 0 ? void 0 : editorState.isActive) ? 'tip-tap-btn--active' : ''}`, onClick: handleToggleOpen, type: "button", children: [jsx(IconLink, {}), jsx("span", { className: "tip-tap-tooltip", children: texts.link })] }), jsx("div", { className: "tip-tap-dropdown__menu", style: { width: 'auto', padding: 0 }, children: jsxs("div", { className: "tip-tap-link-popup", style: { flexDirection: 'column', alignItems: 'stretch' }, children: [jsx("input", { ref: labelInputRef, type: "text", className: "tip-tap-link-popup__input", placeholder: texts.linkText, value: label, onChange: (e) => setLabel(e.target.value), onKeyDown: (e) => e.key === 'Enter' && handleSubmit(), style: { marginBottom: '8px' } }), jsx("input", { type: "text", className: "tip-tap-link-popup__input", placeholder: texts.linkUrl, value: url, onChange: (e) => setUrl(e.target.value), onKeyDown: (e) => e.key === 'Enter' && handleSubmit() }), jsxs("div", { style: { display: 'flex', gap: '4px', marginTop: '8px' }, children: [jsx("button", { className: "tip-tap-link-popup__btn", onClick: handleSubmit, type: "button", children: jsx(IconCheck, {}) }), (editorState === null || editorState === void 0 ? void 0 : editorState.isActive) && (jsx("button", { className: "tip-tap-link-popup__btn tip-tap-link-popup__btn--danger", onClick: handleRemove, type: "button", children: jsx(IconTrash, {}) }))] })] }) })] }));
105
108
  }
106
109
 
107
110
  export { LinkButton };
@@ -2,8 +2,11 @@ import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { useEditorState } from '@tiptap/react';
3
3
  import { useState, useRef, useEffect } from 'react';
4
4
  import { IconTable } from '../../icons/index.js';
5
+ import { useLocale } from '../../../../locale/index.js';
5
6
 
6
7
  function TableButton({ editor }) {
8
+ const { locale } = useLocale();
9
+ const texts = locale.TipTap;
7
10
  const [isOpen, setIsOpen] = useState(false);
8
11
  const [hoveredCell, setHoveredCell] = useState({ row: 0, col: 0 });
9
12
  const dropdownRef = useRef(null);
@@ -27,11 +30,11 @@ function TableButton({ editor }) {
27
30
  editor.chain().focus().insertTable({ rows, cols, withHeaderRow: true }).run();
28
31
  setIsOpen(false);
29
32
  }
30
- return (jsxs("div", { className: `tip-tap-dropdown ${isOpen ? 'tip-tap-dropdown--open' : ''}`, ref: dropdownRef, children: [jsxs("button", { className: `tip-tap-btn ${(editorState === null || editorState === void 0 ? void 0 : editorState.isActive) ? 'tip-tap-btn--active' : ''}`, onClick: () => setIsOpen(!isOpen), type: "button", children: [jsx(IconTable, {}), jsx("span", { className: "tip-tap-tooltip", children: "\u63D2\u5165\u8868\u683C" })] }), jsx("div", { className: "tip-tap-dropdown__menu", style: { padding: 0 }, children: jsxs("div", { className: "tip-tap-table-menu", children: [jsx("div", { className: "tip-tap-table-menu__label", children: "\u9009\u62E9\u8868\u683C\u5927\u5C0F" }), jsx("div", { className: "tip-tap-table-menu__grid", children: Array.from({ length: 36 }, (_, i) => {
33
+ return (jsxs("div", { className: `tip-tap-dropdown ${isOpen ? 'tip-tap-dropdown--open' : ''}`, ref: dropdownRef, children: [jsxs("button", { className: `tip-tap-btn ${(editorState === null || editorState === void 0 ? void 0 : editorState.isActive) ? 'tip-tap-btn--active' : ''}`, onClick: () => setIsOpen(!isOpen), type: "button", children: [jsx(IconTable, {}), jsx("span", { className: "tip-tap-tooltip", children: texts.insertTable })] }), jsx("div", { className: "tip-tap-dropdown__menu", style: { padding: 0 }, children: jsxs("div", { className: "tip-tap-table-menu", children: [jsx("div", { className: "tip-tap-table-menu__label", children: texts.selectTableSize }), jsx("div", { className: "tip-tap-table-menu__grid", children: Array.from({ length: 36 }, (_, i) => {
31
34
  const row = Math.floor(i / 6) + 1;
32
35
  const col = (i % 6) + 1;
33
36
  return (jsx("button", { className: `tip-tap-table-menu__cell ${row <= hoveredCell.row && col <= hoveredCell.col ? 'tip-tap-table-menu__cell--active' : ''}`, onMouseEnter: () => setHoveredCell({ row, col }), onClick: () => handleInsertTable(row, col), type: "button" }, i));
34
- }) }), jsx("div", { className: "tip-tap-table-menu__size", children: hoveredCell.row > 0 ? `${hoveredCell.row} × ${hoveredCell.col}` : '选择大小' })] }) })] }));
37
+ }) }), jsx("div", { className: "tip-tap-table-menu__size", children: hoveredCell.row > 0 ? `${hoveredCell.row} × ${hoveredCell.col}` : texts.selectSize })] }) })] }));
35
38
  }
36
39
 
37
40
  export { TableButton };
@@ -7,8 +7,11 @@ import { ColorPicker } from './components/color-picker.js';
7
7
  import { LinkButton } from './components/link-button.js';
8
8
  import { ImageButton } from './components/image-button.js';
9
9
  import { TableButton } from './components/table-button.js';
10
+ import { useLocale } from '../../../locale/index.js';
10
11
 
11
12
  function Toolbar({ editor, className = '' }) {
13
+ const { locale } = useLocale();
14
+ const texts = locale.TipTap;
12
15
  // 使用 useEditorState 来同步编辑器状态
13
16
  const editorState = useEditorState({
14
17
  editor,
@@ -33,7 +36,7 @@ function Toolbar({ editor, className = '' }) {
33
36
  canRedo: ctx.editor.can().redo(),
34
37
  }),
35
38
  });
36
- return (jsxs("div", { className: `tip-tap-toolbar ${className}`, children: [jsxs("div", { className: "tip-tap-toolbar__group", children: [jsx(ToolbarButton, { icon: jsx(IconUndo, {}), tooltip: "\u64A4\u9500", onClick: () => editor.chain().focus().undo().run(), disabled: !(editorState === null || editorState === void 0 ? void 0 : editorState.canUndo) }), jsx(ToolbarButton, { icon: jsx(IconRedo, {}), tooltip: "\u91CD\u505A", onClick: () => editor.chain().focus().redo().run(), disabled: !(editorState === null || editorState === void 0 ? void 0 : editorState.canRedo) })] }), jsx("div", { className: "tip-tap-toolbar__divider" }), jsxs("div", { className: "tip-tap-toolbar__group", children: [jsx(ToolbarButton, { icon: jsx(IconBold, {}), tooltip: "\u7C97\u4F53", onClick: () => editor.chain().focus().toggleBold().run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isBold }), jsx(ToolbarButton, { icon: jsx(IconItalic, {}), tooltip: "\u659C\u4F53", onClick: () => editor.chain().focus().toggleItalic().run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isItalic }), jsx(ToolbarButton, { icon: jsx(IconUnderline, {}), tooltip: "\u4E0B\u5212\u7EBF", onClick: () => editor.chain().focus().toggleUnderline().run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isUnderline }), jsx(ToolbarButton, { icon: jsx(IconStrikethrough, {}), tooltip: "\u5220\u9664\u7EBF", onClick: () => editor.chain().focus().toggleStrike().run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isStrike })] }), jsx("div", { className: "tip-tap-toolbar__divider" }), jsx(HeadingDropdown, { editor: editor }), jsx("div", { className: "tip-tap-toolbar__divider" }), jsxs("div", { className: "tip-tap-toolbar__group", children: [jsx(ColorPicker, { editor: editor, type: "textColor", tooltip: "\u6587\u5B57\u989C\u8272" }), jsx(ColorPicker, { editor: editor, type: "highlight", tooltip: "\u80CC\u666F\u9AD8\u4EAE" })] }), jsx("div", { className: "tip-tap-toolbar__divider" }), jsxs("div", { className: "tip-tap-toolbar__group", children: [jsx(ToolbarButton, { icon: jsx(IconAlignLeft, {}), tooltip: "\u5DE6\u5BF9\u9F50", onClick: () => editor.chain().focus().setTextAlign('left').run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isAlignLeft }), jsx(ToolbarButton, { icon: jsx(IconAlignCenter, {}), tooltip: "\u5C45\u4E2D\u5BF9\u9F50", onClick: () => editor.chain().focus().setTextAlign('center').run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isAlignCenter }), jsx(ToolbarButton, { icon: jsx(IconAlignRight, {}), tooltip: "\u53F3\u5BF9\u9F50", onClick: () => editor.chain().focus().setTextAlign('right').run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isAlignRight })] }), jsx("div", { className: "tip-tap-toolbar__divider" }), jsxs("div", { className: "tip-tap-toolbar__group", children: [jsx(ToolbarButton, { icon: jsx(IconListBullet, {}), tooltip: "\u65E0\u5E8F\u5217\u8868", onClick: () => editor.chain().focus().toggleBulletList().run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isBulletList }), jsx(ToolbarButton, { icon: jsx(IconListNumbered, {}), tooltip: "\u6709\u5E8F\u5217\u8868", onClick: () => editor.chain().focus().toggleOrderedList().run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isOrderedList })] }), jsx("div", { className: "tip-tap-toolbar__divider" }), jsxs("div", { className: "tip-tap-toolbar__group", children: [jsx(ToolbarButton, { icon: jsx(IconQuote, {}), tooltip: "\u5F15\u7528", onClick: () => editor.chain().focus().toggleBlockquote().run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isBlockquote }), jsx(ToolbarButton, { icon: jsx(IconCode, {}), tooltip: "\u4EE3\u7801\u5757", onClick: () => editor.chain().focus().toggleCodeBlock().run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isCodeBlock }), jsx(ToolbarButton, { icon: jsx(IconMinus, {}), tooltip: "\u5206\u5272\u7EBF", onClick: () => editor.chain().focus().setHorizontalRule().run() })] }), jsx("div", { className: "tip-tap-toolbar__divider" }), jsxs("div", { className: "tip-tap-toolbar__group", children: [jsx(LinkButton, { editor: editor }), jsx(ImageButton, { editor: editor }), jsx(TableButton, { editor: editor })] })] }));
39
+ return (jsxs("div", { className: `tip-tap-toolbar ${className}`, children: [jsxs("div", { className: "tip-tap-toolbar__group", children: [jsx(ToolbarButton, { icon: jsx(IconUndo, {}), tooltip: texts.undo, onClick: () => editor.chain().focus().undo().run(), disabled: !(editorState === null || editorState === void 0 ? void 0 : editorState.canUndo) }), jsx(ToolbarButton, { icon: jsx(IconRedo, {}), tooltip: texts.redo, onClick: () => editor.chain().focus().redo().run(), disabled: !(editorState === null || editorState === void 0 ? void 0 : editorState.canRedo) })] }), jsx("div", { className: "tip-tap-toolbar__divider" }), jsxs("div", { className: "tip-tap-toolbar__group", children: [jsx(ToolbarButton, { icon: jsx(IconBold, {}), tooltip: texts.bold, onClick: () => editor.chain().focus().toggleBold().run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isBold }), jsx(ToolbarButton, { icon: jsx(IconItalic, {}), tooltip: texts.italic, onClick: () => editor.chain().focus().toggleItalic().run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isItalic }), jsx(ToolbarButton, { icon: jsx(IconUnderline, {}), tooltip: texts.underline, onClick: () => editor.chain().focus().toggleUnderline().run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isUnderline }), jsx(ToolbarButton, { icon: jsx(IconStrikethrough, {}), tooltip: texts.strike, onClick: () => editor.chain().focus().toggleStrike().run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isStrike })] }), jsx("div", { className: "tip-tap-toolbar__divider" }), jsx(HeadingDropdown, { editor: editor }), jsx("div", { className: "tip-tap-toolbar__divider" }), jsxs("div", { className: "tip-tap-toolbar__group", children: [jsx(ColorPicker, { editor: editor, type: "textColor", tooltip: texts.textColor }), jsx(ColorPicker, { editor: editor, type: "highlight", tooltip: texts.highlight })] }), jsx("div", { className: "tip-tap-toolbar__divider" }), jsxs("div", { className: "tip-tap-toolbar__group", children: [jsx(ToolbarButton, { icon: jsx(IconAlignLeft, {}), tooltip: texts.alignLeft, onClick: () => editor.chain().focus().setTextAlign('left').run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isAlignLeft }), jsx(ToolbarButton, { icon: jsx(IconAlignCenter, {}), tooltip: texts.alignCenter, onClick: () => editor.chain().focus().setTextAlign('center').run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isAlignCenter }), jsx(ToolbarButton, { icon: jsx(IconAlignRight, {}), tooltip: texts.alignRight, onClick: () => editor.chain().focus().setTextAlign('right').run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isAlignRight })] }), jsx("div", { className: "tip-tap-toolbar__divider" }), jsxs("div", { className: "tip-tap-toolbar__group", children: [jsx(ToolbarButton, { icon: jsx(IconListBullet, {}), tooltip: texts.bulletList, onClick: () => editor.chain().focus().toggleBulletList().run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isBulletList }), jsx(ToolbarButton, { icon: jsx(IconListNumbered, {}), tooltip: texts.orderedList, onClick: () => editor.chain().focus().toggleOrderedList().run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isOrderedList })] }), jsx("div", { className: "tip-tap-toolbar__divider" }), jsxs("div", { className: "tip-tap-toolbar__group", children: [jsx(ToolbarButton, { icon: jsx(IconQuote, {}), tooltip: texts.quote, onClick: () => editor.chain().focus().toggleBlockquote().run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isBlockquote }), jsx(ToolbarButton, { icon: jsx(IconCode, {}), tooltip: texts.codeBlock, onClick: () => editor.chain().focus().toggleCodeBlock().run(), active: editorState === null || editorState === void 0 ? void 0 : editorState.isCodeBlock }), jsx(ToolbarButton, { icon: jsx(IconMinus, {}), tooltip: texts.divider, onClick: () => editor.chain().focus().setHorizontalRule().run() })] }), jsx("div", { className: "tip-tap-toolbar__divider" }), jsxs("div", { className: "tip-tap-toolbar__group", children: [jsx(LinkButton, { editor: editor }), jsx(ImageButton, { editor: editor }), jsx(TableButton, { editor: editor })] })] }));
37
40
  }
38
41
 
39
42
  export { Toolbar as default };
@@ -11,9 +11,13 @@ import { useFormatFiles } from './hooks/useFormatFiles.js';
11
11
  import { useUploadFileToOSS } from './hooks/useUploadFileToOSS.js';
12
12
  import { useResumeUnfinishedUploads } from './hooks/useResumeUnfinishedUploads.js';
13
13
  import { FileUploadDrawerContext } from './index.js';
14
+ import { useLocale } from '../../locale/index.js';
14
15
 
15
- function FileUploadDrawer({ open, identifier, accept, dragAreaDescription, footer, title = '数据上传', showFinished = false, directory = false, onClose, }) {
16
+ function FileUploadDrawer({ open, identifier, accept, dragAreaDescription, footer, title, showFinished = false, directory = false, onClose, }) {
16
17
  var _a, _b;
18
+ const { locale, t } = useLocale();
19
+ const texts = locale.UploadDrawer;
20
+ const resolvedTitle = title !== null && title !== void 0 ? title : texts.title;
17
21
  const uploadStore = useContext(UploadStoreContext);
18
22
  const setUploadsStore = useContext(UploadStoreDispatchContext);
19
23
  const { onSuccess } = useContext(FileUploadDrawerContext);
@@ -47,7 +51,7 @@ function FileUploadDrawer({ open, identifier, accept, dragAreaDescription, foote
47
51
  uploadFileToOSS(fileToUpload, onSuccess);
48
52
  }
49
53
  }, [identifier, onSuccess, uploadFileToOSS, uploadStore]);
50
- return (jsxs(Drawer, { className: "mylib-upload-drawer", open: open, title: title, width: 480, onClose: onClose, footer: footer, children: [jsx(FileUploadDrawerFileDragger, { directory: directory, accept: accept, dragAreaDescription: dragAreaDescription, onFileReceived: onFileReceived }), raws.length === 0 && ((_a = uploadStore[identifier]) === null || _a === void 0 ? void 0 : _a.length) === 0 && (jsx(Empty, { className: "mt-20", description: "\u6682\u65E0\u4E0A\u4F20\u5185\u5BB9" })), raws.length > 0 && (jsxs("div", { className: "flex justify-center gap-4 mt-4", children: [jsx(LoadingOutlined, {}), "\u9884\u68C0\u4E0A\u4F20\u6587\u4EF6\u4E2D(", raws.length, ")"] })), ((_b = uploadStore[identifier]) === null || _b === void 0 ? void 0 : _b.length) > 0 && (jsx(FileUploading, { showFinished: showFinished, identifier: identifier }))] }));
54
+ return (jsxs(Drawer, { className: "mylib-upload-drawer", open: open, title: resolvedTitle, width: 480, onClose: onClose, footer: footer, children: [jsx(FileUploadDrawerFileDragger, { directory: directory, accept: accept, dragAreaDescription: dragAreaDescription, onFileReceived: onFileReceived }), raws.length === 0 && ((_a = uploadStore[identifier]) === null || _a === void 0 ? void 0 : _a.length) === 0 && (jsx(Empty, { className: "mt-20", description: texts.empty })), raws.length > 0 && (jsxs("div", { className: "flex justify-center gap-4 mt-4", children: [jsx(LoadingOutlined, {}), t(texts.prechecking, { count: raws.length })] })), ((_b = uploadStore[identifier]) === null || _b === void 0 ? void 0 : _b.length) > 0 && (jsx(FileUploading, { showFinished: showFinished, identifier: identifier }))] }));
51
55
  function onFileReceived(files) {
52
56
  return __awaiter(this, void 0, void 0, function* () {
53
57
  setRaws((prev) => [...prev, ...files]);
@@ -8,6 +8,7 @@ import FileUploadDrawerListProgressButton from './fileUploadDrawerListProgressBu
8
8
  import { Flex, Button } from 'antd';
9
9
  import { useRetryUpload } from './hooks/useRetryUpload.js';
10
10
  import { useCancelUpload } from './hooks/useCancelUpload.js';
11
+ import { useLocale } from '../../locale/index.js';
11
12
 
12
13
  function FileUploading({ identifier, showFinished, }) {
13
14
  const uploadContext = useContext(UploadStoreContext);
@@ -38,9 +39,11 @@ function FileUploading({ identifier, showFinished, }) {
38
39
  }
39
40
  }
40
41
  function FileListItem({ identifier, file, showFinished, onButtonClick }) {
42
+ const { locale } = useLocale();
43
+ const texts = locale.UploadDrawer;
41
44
  const setUploadsStore = useContext(UploadStoreDispatchContext);
42
45
  const showDelete = typeof showFinished === 'object' && showFinished.withDelete;
43
- return (jsx("div", { className: "mb-2 last:mb-0", children: jsxs("div", { className: "px-4 my-2 relative flex justify-between items-center", children: [jsxs(Flex, { align: "center", gap: ".5rem", title: file.fileName, children: [jsx(FileTextOutlined, {}), jsx("span", { className: "truncate w-40", children: file.fileName })] }), jsxs(Flex, { align: "center", gap: ".5rem", children: [jsx(FileUploadDrawerListProgressButton, { status: file.fileStatus, percent: Number(file.percentage.toFixed(0)), onClick: () => onButtonClick(file) }), file.fileStatus === FILE_UPLOAD_STATUS.FINISHED && showDelete && (jsx(Button, { type: "text", size: "large", className: "px-3", disabled: showDelete.disabled, title: `${showDelete.disabled ? '删除-已禁用' : '删除'}`, onClick: () => onDelete(file, showDelete.onDelete), children: jsx(DeleteOutlined, {}) }))] })] }) }));
46
+ return (jsx("div", { className: "mb-2 last:mb-0", children: jsxs("div", { className: "px-4 my-2 relative flex justify-between items-center", children: [jsxs(Flex, { align: "center", gap: ".5rem", title: file.fileName, children: [jsx(FileTextOutlined, {}), jsx("span", { className: "truncate w-40", children: file.fileName })] }), jsxs(Flex, { align: "center", gap: ".5rem", children: [jsx(FileUploadDrawerListProgressButton, { status: file.fileStatus, percent: Number(file.percentage.toFixed(0)), onClick: () => onButtonClick(file) }), file.fileStatus === FILE_UPLOAD_STATUS.FINISHED && showDelete && (jsx(Button, { type: "text", size: "large", className: "px-3", disabled: showDelete.disabled, title: showDelete.disabled ? texts.removeDisabled : texts.remove, onClick: () => onDelete(file, showDelete.onDelete), children: jsx(DeleteOutlined, {}) }))] })] }) }));
44
47
  function onDelete(file, onDeleteImpl) {
45
48
  return __awaiter(this, void 0, void 0, function* () {
46
49
  const result = yield onDeleteImpl(file.fileName);
@@ -5,6 +5,7 @@ import { useState } from 'react';
5
5
  import { FILE_UPLOAD_STATUS } from './utils/constant.js';
6
6
  import 'tslib';
7
7
  import { useProgressButtonRef } from './hooks/useProgressButtonRef.js';
8
+ import { useLocale } from '../../locale/index.js';
8
9
 
9
10
  // 进度条样式属性
10
11
  const progressStyleProps = {
@@ -14,7 +15,8 @@ const progressStyleProps = {
14
15
  strokeLinecap: 'butt',
15
16
  };
16
17
  function FileUploadDrawerListProgressButton({ percent, status, onClick, }) {
17
- // 使用自定义 hook 获取按钮引用和悬停状态
18
+ const { locale } = useLocale();
19
+ const texts = locale.UploadDrawer;
18
20
  const { progressButtonRef, buttonInHover } = useProgressButtonRef();
19
21
  // 状态用于跟踪是否正在取消上传
20
22
  const [isCanceling, setIsCanceling] = useState(false);
@@ -31,7 +33,7 @@ function FileUploadDrawerListProgressButton({ percent, status, onClick, }) {
31
33
  } })) }));
32
34
  }
33
35
  // 默认情况下显示进度按钮
34
- return (jsx(Button, { type: "text", shape: "circle", disabled: isCanceling, ref: progressButtonRef, title: status === FILE_UPLOAD_STATUS.PAUSED ? '继续下载' : '取消下载', onClick: () => {
36
+ return (jsx(Button, { type: "text", shape: "circle", disabled: isCanceling, ref: progressButtonRef, title: status === FILE_UPLOAD_STATUS.PAUSED ? texts.continue : texts.cancelDownload, onClick: () => {
35
37
  onClick();
36
38
  if (status === FILE_UPLOAD_STATUS.UPLOADING) {
37
39
  setIsCanceling(true);
@@ -5,9 +5,11 @@ import { useContext } from 'react';
5
5
  import { UploadStoreDispatchContext } from '../UploadStoreProvider.js';
6
6
  import { App } from 'antd';
7
7
  import { FileUploadDrawerContext } from '../index.js';
8
+ import { useLocale } from '../../../locale/index.js';
8
9
 
9
10
  function useCancelUpload() {
10
11
  const { message } = App.useApp();
12
+ const { locale } = useLocale();
11
13
  const { identifier, onCancelUpload } = useContext(FileUploadDrawerContext);
12
14
  const uploadsDispatch = useContext(UploadStoreDispatchContext);
13
15
  return function cancelUpload(file) {
@@ -22,7 +24,7 @@ function useCancelUpload() {
22
24
  deleteFile(file);
23
25
  }
24
26
  else {
25
- message.error(result.reason || '取消失败');
27
+ message.error(result.reason || locale.UploadDrawer.cancelFailed);
26
28
  }
27
29
  });
28
30
  };