@ai-group/chat-sdk 3.5.6 → 3.5.9

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 (34) hide show
  1. package/dist/cjs/components/FolderTree/DirectoryTree.d.ts +13 -1
  2. package/dist/cjs/components/FolderTree/DirectoryTree.js +215 -70
  3. package/dist/cjs/components/FolderTree/DirectoryTree.js.map +2 -2
  4. package/dist/cjs/components/FolderTree/index.d.ts +3 -3
  5. package/dist/cjs/components/FolderTree/index.js +102 -5
  6. package/dist/cjs/components/FolderTree/index.js.map +2 -2
  7. package/dist/cjs/components/FolderTree/styles.d.ts +5 -0
  8. package/dist/cjs/components/FolderTree/styles.js +77 -14
  9. package/dist/cjs/components/FolderTree/styles.js.map +2 -2
  10. package/dist/cjs/components/FolderTree/types.d.ts +61 -2
  11. package/dist/cjs/components/FolderTree/types.js.map +1 -1
  12. package/dist/cjs/components/FolderTree/useFolderDrag.d.ts +53 -0
  13. package/dist/cjs/components/FolderTree/useFolderDrag.js +309 -0
  14. package/dist/cjs/components/FolderTree/useFolderDrag.js.map +7 -0
  15. package/dist/cjs/index.d.ts +1 -1
  16. package/dist/cjs/index.js.map +2 -2
  17. package/dist/esm/components/FolderTree/DirectoryTree.d.ts +13 -1
  18. package/dist/esm/components/FolderTree/DirectoryTree.js +220 -62
  19. package/dist/esm/components/FolderTree/DirectoryTree.js.map +1 -1
  20. package/dist/esm/components/FolderTree/index.d.ts +3 -3
  21. package/dist/esm/components/FolderTree/index.js +149 -31
  22. package/dist/esm/components/FolderTree/index.js.map +1 -1
  23. package/dist/esm/components/FolderTree/styles.d.ts +5 -0
  24. package/dist/esm/components/FolderTree/styles.js +17 -12
  25. package/dist/esm/components/FolderTree/styles.js.map +1 -1
  26. package/dist/esm/components/FolderTree/types.d.ts +61 -2
  27. package/dist/esm/components/FolderTree/types.js.map +1 -1
  28. package/dist/esm/components/FolderTree/useFolderDrag.d.ts +53 -0
  29. package/dist/esm/components/FolderTree/useFolderDrag.js +324 -0
  30. package/dist/esm/components/FolderTree/useFolderDrag.js.map +1 -0
  31. package/dist/esm/index.d.ts +1 -1
  32. package/dist/esm/index.js.map +1 -1
  33. package/dist/umd/chat-sdk.min.js +1 -1
  34. package/package.json +10 -10
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import type { TreeProps } from "antd";
3
- import type { FolderTreeData, FolderTreeProps } from "./types";
3
+ import type { FolderTreeData, FolderTreeProps, EditNodeInfo, CreateNodeContext } from "./types";
4
4
  export interface DirectoryTreeComponentProps {
5
5
  treeData: FolderTreeData[];
6
6
  directoryIcons?: FolderTreeProps["directoryIcons"];
@@ -17,6 +17,18 @@ export interface DirectoryTreeComponentProps {
17
17
  width?: number | string;
18
18
  draggable?: FolderTreeProps["draggable"];
19
19
  onDrop?: FolderTreeProps["onDrop"];
20
+ /** 当前编辑节点信息 */
21
+ editNode?: EditNodeInfo | null;
22
+ /** 编辑值变化回调 */
23
+ onEditValueChange?: (value: string) => void;
24
+ /** 编辑确认回调 */
25
+ onEditConfirm?: () => void;
26
+ /** 编辑取消回调 */
27
+ onEditCancel?: () => void;
28
+ /** 新建上下文 */
29
+ createInfo?: CreateNodeContext | null;
30
+ /** 开始重命名回调(由父组件注入) */
31
+ onStartRename?: (fullPath: string, node: FolderTreeData) => void;
20
32
  }
21
33
  declare const DirectoryTreeComponent: React.FC<DirectoryTreeComponentProps>;
22
34
  export default DirectoryTreeComponent;
@@ -37,6 +37,7 @@ var import_antd = require("antd");
37
37
  var import_icons = require("@ant-design/icons");
38
38
  var import_clsx = __toESM(require("clsx"));
39
39
  var import_styles = require("./styles");
40
+ var import_useFolderDrag = require("./useFolderDrag");
40
41
  var import_jsx_runtime = require("react/jsx-runtime");
41
42
  var { DirectoryTree: AntDirectoryTree } = import_antd.Tree;
42
43
  var DirectoryTreeComponent = ({
@@ -54,7 +55,13 @@ var DirectoryTreeComponent = ({
54
55
  moreActions,
55
56
  width,
56
57
  draggable,
57
- onDrop
58
+ onDrop,
59
+ editNode,
60
+ onEditValueChange,
61
+ onEditConfirm,
62
+ onEditCancel,
63
+ createInfo,
64
+ onStartRename
58
65
  }) => {
59
66
  const styles = (0, import_styles.useStyles)();
60
67
  const isFolder = (node) => {
@@ -91,11 +98,112 @@ var DirectoryTreeComponent = ({
91
98
  },
92
99
  []
93
100
  );
101
+ const renderInlineInput = (0, import_react.useCallback)(
102
+ (value) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: styles.treeNodeTitle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
103
+ import_antd.Input,
104
+ {
105
+ size: "small",
106
+ value,
107
+ onChange: (e) => onEditValueChange == null ? void 0 : onEditValueChange(e.target.value),
108
+ onBlur: () => onEditConfirm == null ? void 0 : onEditConfirm(),
109
+ onPressEnter: () => onEditConfirm == null ? void 0 : onEditConfirm(),
110
+ onKeyDown: (e) => {
111
+ if (e.key === "Escape") {
112
+ e.stopPropagation();
113
+ onEditCancel == null ? void 0 : onEditCancel();
114
+ }
115
+ },
116
+ autoFocus: true,
117
+ className: styles.inlineInput,
118
+ onClick: (e) => e.stopPropagation(),
119
+ onSelect: (e) => e.stopPropagation(),
120
+ onFocus: (e) => e.stopPropagation()
121
+ }
122
+ ) }),
123
+ [onEditValueChange, onEditConfirm, onEditCancel, styles]
124
+ );
125
+ const dragMode = draggable === true ? "file" : draggable || false;
126
+ const handleDragDrop = (0, import_react.useCallback)(
127
+ (dragNode, dropNode, dropPosition) => {
128
+ const dragNd = dragNode;
129
+ const dropNd = dropNode;
130
+ const originalDragNode = dragNd._originalNode;
131
+ const originalDropNode = dropNd._originalNode;
132
+ if (!originalDragNode)
133
+ return;
134
+ const dragKey = String(dragNode.key);
135
+ const dropKey = String(dropNode.key);
136
+ const dragFileName = originalDragNode.path;
137
+ let newPath;
138
+ if (!originalDropNode && dropKey === "__bottom_placeholder__") {
139
+ newPath = dragFileName;
140
+ onDrop == null ? void 0 : onDrop({
141
+ fileName: originalDragNode.title,
142
+ extra: originalDragNode.extra,
143
+ oldPath: dragKey,
144
+ newPath,
145
+ dragNode: originalDragNode,
146
+ dropNode: { title: "", path: "" }
147
+ });
148
+ return;
149
+ }
150
+ if (!originalDropNode)
151
+ return;
152
+ if (!dropNode.isLeaf && dropPosition === 0) {
153
+ newPath = `${dropKey}/${dragFileName}`;
154
+ } else {
155
+ const dropParentPath = dropKey.includes("/") ? dropKey.substring(0, dropKey.lastIndexOf("/")) : "";
156
+ newPath = dropParentPath ? `${dropParentPath}/${dragFileName}` : dragFileName;
157
+ }
158
+ onDrop == null ? void 0 : onDrop({
159
+ fileName: originalDragNode.title,
160
+ extra: originalDragNode.extra,
161
+ oldPath: dragKey,
162
+ newPath,
163
+ dragNode: originalDragNode,
164
+ dropNode: originalDropNode
165
+ });
166
+ },
167
+ [onDrop]
168
+ );
169
+ const handleDragEnterExpand = (0, import_react.useCallback)(
170
+ (nodeKey) => {
171
+ const isExpanded = expandedKeys == null ? void 0 : expandedKeys.includes(nodeKey);
172
+ if (!isExpanded) {
173
+ onExpand == null ? void 0 : onExpand([...expandedKeys || [], nodeKey], {
174
+ node: null,
175
+ expanded: true,
176
+ nativeEvent: null
177
+ });
178
+ }
179
+ },
180
+ [expandedKeys, onExpand]
181
+ );
182
+ const { onDragStart, onDragEnd, onItemDragEnter, onItemDragOver, onItemDragLeave, onItemDrop, onContainerDragOver, onContainerDrop, canDragNode } = (0, import_useFolderDrag.useFolderDrag)({
183
+ dragMode,
184
+ onDrop: handleDragDrop,
185
+ onDragEnterExpand: handleDragEnterExpand
186
+ });
94
187
  const convertToTreeData = (0, import_react.useCallback)(
95
- (nodes, parentSegments = []) => {
96
- return nodes.map((node) => {
188
+ (nodes, parentSegments = [], parentKey = "") => {
189
+ const result = nodes.map((node) => {
97
190
  const pathSegments = buildPathSegments(node, parentSegments);
98
191
  const fullPath = pathSegments.join("/").replace(/^\/+/, "");
192
+ const isEditing = editNode && editNode.key === fullPath;
193
+ const nodeChildren = node.children ? convertToTreeData(node.children, pathSegments, fullPath) : void 0;
194
+ const baseNode = {
195
+ key: fullPath,
196
+ path: fullPath,
197
+ pathSegments,
198
+ icon: getIcon(node),
199
+ isLeaf: !isFolder(node),
200
+ _originalNode: node,
201
+ children: nodeChildren
202
+ };
203
+ if (isEditing) {
204
+ baseNode.title = renderInlineInput(editNode.currentValue);
205
+ return baseNode;
206
+ }
99
207
  const titleContent = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
100
208
  "span",
101
209
  {
@@ -108,7 +216,9 @@ var DirectoryTreeComponent = ({
108
216
  moreActions && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
109
217
  import_antd.Dropdown,
110
218
  {
111
- menu: moreActions(node),
219
+ menu: moreActions(node, {
220
+ startRename: () => onStartRename == null ? void 0 : onStartRename(fullPath, node)
221
+ }),
112
222
  trigger: ["click"],
113
223
  placement: "bottomRight",
114
224
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -124,85 +234,120 @@ var DirectoryTreeComponent = ({
124
234
  ]
125
235
  }
126
236
  );
127
- return {
128
- ...node,
129
- key: fullPath,
130
- path: fullPath,
131
- pathSegments,
132
- title: titleContent,
133
- icon: getIcon(node),
134
- isLeaf: !isFolder(node),
135
- /** 保存原始节点数据用于拖拽回调 */
136
- _originalNode: node,
137
- children: node.children ? convertToTreeData(node.children, pathSegments) : void 0
138
- };
237
+ if (dragMode) {
238
+ const nodeData = baseNode;
239
+ const draggableDiv = canDragNode(nodeData);
240
+ baseNode.title = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
241
+ "div",
242
+ {
243
+ className: (0, import_clsx.default)(
244
+ styles.treeNodeWrapper,
245
+ draggableDiv && styles.dragNodeHandle
246
+ ),
247
+ "data-node-key": fullPath,
248
+ draggable: draggableDiv,
249
+ onDragStart: draggableDiv ? (e) => onDragStart(e, baseNode) : void 0,
250
+ onDragEnd: draggableDiv ? onDragEnd : void 0,
251
+ onDragEnter: (e) => onItemDragEnter(e, baseNode),
252
+ onDragOver: (e) => onItemDragOver(e, baseNode),
253
+ onDragLeave: onItemDragLeave,
254
+ onDrop: (e) => onItemDrop(e, baseNode),
255
+ children: titleContent
256
+ }
257
+ );
258
+ } else {
259
+ baseNode.title = titleContent;
260
+ }
261
+ return baseNode;
139
262
  });
263
+ if (createInfo && editNode && editNode.mode === "create") {
264
+ const targetParentKey = createInfo.parentKey;
265
+ if (targetParentKey === parentKey || targetParentKey === "" && parentKey === "" || targetParentKey === "/" && parentKey === "") {
266
+ const tempNode = {
267
+ key: editNode.key,
268
+ title: renderInlineInput(editNode.currentValue),
269
+ icon: createInfo.type === "folder" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.FolderOutlined, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.FileOutlined, {}),
270
+ isLeaf: createInfo.type === "file",
271
+ path: editNode.key,
272
+ pathSegments: [editNode.key],
273
+ _originalNode: null,
274
+ _isTempNode: true
275
+ };
276
+ result.push(tempNode);
277
+ }
278
+ }
279
+ return result;
140
280
  },
141
- [buildPathSegments, getIcon, moreActions, styles]
281
+ [
282
+ buildPathSegments,
283
+ getIcon,
284
+ moreActions,
285
+ styles,
286
+ editNode,
287
+ renderInlineInput,
288
+ createInfo,
289
+ onStartRename,
290
+ dragMode,
291
+ canDragNode,
292
+ onDragStart,
293
+ onDragEnd,
294
+ onItemDragEnter,
295
+ onItemDragOver,
296
+ onItemDragLeave,
297
+ onItemDrop
298
+ ]
142
299
  );
143
- const treeDataConverted = convertToTreeData(treeData);
144
- const dragMode = draggable === true ? "file" : draggable || false;
145
- const draggableConfig = dragMode ? {
146
- icon: false,
147
- nodeDraggable: (node) => {
148
- if (dragMode === "file")
149
- return !!node.isLeaf;
150
- if (dragMode === "folder")
151
- return !node.isLeaf;
152
- return true;
153
- }
154
- } : false;
155
- const handleDrop = (0, import_react.useCallback)(
156
- (info) => {
157
- if (!onDrop)
300
+ const treeDataConverted = (0, import_react.useMemo)(
301
+ () => convertToTreeData(treeData, [], ""),
302
+ [treeData, convertToTreeData]
303
+ );
304
+ const handleSelect = (0, import_react.useCallback)(
305
+ (keys, info) => {
306
+ var _a;
307
+ if (editNode)
158
308
  return;
159
- const dragNode = info.dragNode;
160
- const dropNode = info.node;
161
- const originalDragNode = dragNode._originalNode;
162
- const originalDropNode = dropNode._originalNode;
163
- if (!originalDragNode || !originalDropNode)
309
+ const node = info.node;
310
+ if (node._isTempNode)
311
+ return;
312
+ const target = (_a = info.nativeEvent) == null ? void 0 : _a.target;
313
+ if (target && (target.closest(".folder-tree-more-icon") || target.closest(".ant-dropdown"))) {
164
314
  return;
165
- const dragKey = String(dragNode.key);
166
- const dropKey = String(dropNode.key);
167
- const dragFileName = originalDragNode.path;
168
- let newPath;
169
- if (!dropNode.isLeaf && info.dropToGap === false) {
170
- newPath = `${dropKey}/${dragFileName}`;
171
- } else {
172
- const dropParentPath = dropKey.includes("/") ? dropKey.substring(0, dropKey.lastIndexOf("/")) : "";
173
- newPath = dropParentPath ? `${dropParentPath}/${dragFileName}` : dragFileName;
174
315
  }
175
- onDrop({
176
- fileName: originalDragNode.title,
177
- extra: originalDragNode.extra,
178
- oldPath: dragKey,
179
- newPath,
180
- dragNode: originalDragNode,
181
- dropNode: originalDropNode
182
- });
316
+ onSelect == null ? void 0 : onSelect(keys, info);
183
317
  },
184
- [onDrop]
318
+ [onSelect, editNode]
185
319
  );
186
320
  const titleNode = directoryTitle === false || directoryTitle === null ? null : typeof directoryTitle === "function" ? directoryTitle() : directoryTitle;
187
321
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_clsx.default)(styles.directoryPanel, className), style: { width }, children: [
188
322
  titleNode && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.directoryTitle, children: titleNode }),
189
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.directoryTreeContent, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
190
- AntDirectoryTree,
323
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
324
+ "div",
191
325
  {
192
- treeData: treeDataConverted,
193
- selectedKeys,
194
- expandedKeys,
195
- onSelect,
196
- onExpand,
197
- multiple: false,
198
- blockNode: true,
199
- showLine,
200
- switcherIcon,
201
- defaultExpandAll,
202
- draggable: draggableConfig,
203
- onDrop: dragMode ? handleDrop : void 0
326
+ className: styles.directoryTreeContent,
327
+ onDragOver: dragMode ? onContainerDragOver : void 0,
328
+ onDrop: dragMode ? onContainerDrop : void 0,
329
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
330
+ AntDirectoryTree,
331
+ {
332
+ style: {
333
+ "--ant-tree-directory-node-selected-bg": "rgba(0,0,0,0.03)",
334
+ "--ant-tree-directory-node-selected-color": "#1a1c1e"
335
+ },
336
+ treeData: treeDataConverted,
337
+ selectedKeys,
338
+ expandedKeys,
339
+ onSelect: handleSelect,
340
+ onExpand,
341
+ multiple: false,
342
+ blockNode: true,
343
+ showLine,
344
+ switcherIcon,
345
+ defaultExpandAll,
346
+ draggable: false
347
+ }
348
+ )
204
349
  }
205
- ) })
350
+ )
206
351
  ] });
207
352
  };
208
353
  var DirectoryTree_default = DirectoryTreeComponent;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/components/FolderTree/DirectoryTree.tsx"],
4
- "sourcesContent": ["import React, { useCallback } from \"react\";\nimport { Tree, Dropdown } from \"antd\";\nimport {\n FileOutlined,\n FolderOutlined,\n MoreOutlined,\n} from \"@ant-design/icons\";\nimport type { TreeProps } from \"antd\";\nimport type { DataNode } from \"antd/es/tree\";\nimport clsx from \"clsx\";\nimport type { FolderTreeData, FolderTreeProps } from \"./types\";\nimport { useStyles } from \"./styles\";\n\nconst { DirectoryTree: AntDirectoryTree } = Tree;\n\nexport interface DirectoryTreeComponentProps {\n treeData: FolderTreeData[];\n directoryIcons?: FolderTreeProps[\"directoryIcons\"];\n selectedKeys?: string[];\n expandedKeys?: string[];\n onSelect?: TreeProps[\"onSelect\"];\n onExpand?: TreeProps[\"onExpand\"];\n showLine?: FolderTreeProps[\"showLine\"];\n switcherIcon?: FolderTreeProps[\"switcherIcon\"];\n defaultExpandAll?: boolean;\n className?: string;\n directoryTitle?: FolderTreeProps[\"directoryTitle\"];\n moreActions?: FolderTreeProps[\"moreActions\"];\n width?: number | string;\n draggable?: FolderTreeProps[\"draggable\"];\n onDrop?: FolderTreeProps[\"onDrop\"];\n}\n\nconst DirectoryTreeComponent: React.FC<DirectoryTreeComponentProps> = ({\n treeData,\n selectedKeys,\n expandedKeys,\n onSelect,\n onExpand,\n showLine = false,\n switcherIcon,\n defaultExpandAll = true,\n className,\n directoryIcons,\n directoryTitle,\n moreActions,\n width,\n draggable,\n onDrop,\n}) => {\n const styles = useStyles();\n\n const isFolder = (node: FolderTreeData): boolean => {\n return !!node.children && node.children.length > 0;\n };\n\n const getIcon = useCallback(\n (node: FolderTreeData) => {\n if (directoryIcons === false || directoryIcons === null) {\n return null;\n }\n if (isFolder(node)) {\n const icon = directoryIcons?.directory;\n if (typeof icon === \"function\") return icon();\n return icon || <FolderOutlined />;\n }\n const filePath = node.path.toLowerCase();\n const extension = filePath.split(\".\").pop();\n if (extension) {\n const icon = directoryIcons?.[extension];\n if (icon) return typeof icon === \"function\" ? icon() : icon;\n }\n return <FileOutlined />;\n },\n [directoryIcons]\n );\n\n const buildPathSegments = useCallback(\n (node: FolderTreeData, parentSegments: string[] = []): string[] => {\n if (node.path === \"/\" && parentSegments.length === 0) {\n return [\"/\"];\n }\n return [...parentSegments, node.path].filter((s) => s !== \"\");\n },\n []\n );\n\n const convertToTreeData = useCallback(\n (nodes: FolderTreeData[], parentSegments: string[] = []): DataNode[] => {\n return nodes.map((node) => {\n const pathSegments = buildPathSegments(node, parentSegments);\n const fullPath = pathSegments.join(\"/\").replace(/^\\/+/, \"\");\n\n const titleContent = (\n <span\n className={clsx(\n styles.treeNodeTitle,\n moreActions && styles.treeNodeTitleHover\n )}\n >\n <span>{node.title}</span>\n {moreActions && (\n <Dropdown\n menu={moreActions(node)}\n trigger={[\"click\"]}\n placement=\"bottomRight\"\n >\n <span\n className={clsx(styles.moreIcon, \"folder-tree-more-icon\")}\n onClick={(e) => e.stopPropagation()}\n >\n <MoreOutlined />\n </span>\n </Dropdown>\n )}\n </span>\n );\n\n return {\n ...node,\n key: fullPath,\n path: fullPath,\n pathSegments,\n title: titleContent,\n icon: getIcon(node),\n isLeaf: !isFolder(node),\n /** 保存原始节点数据用于拖拽回调 */\n _originalNode: node,\n children: node.children\n ? convertToTreeData(node.children, pathSegments)\n : undefined,\n };\n });\n },\n [buildPathSegments, getIcon, moreActions, styles]\n );\n\n const treeDataConverted = convertToTreeData(treeData);\n\n // ====== 拖拽配置 ======\n const dragMode = draggable === true ? \"file\" : draggable || false;\n\n const draggableConfig = dragMode\n ? {\n icon: false,\n nodeDraggable: (node: DataNode) => {\n if (dragMode === \"file\") return !!node.isLeaf;\n if (dragMode === \"folder\") return !node.isLeaf;\n return true; // 'all'\n },\n }\n : false;\n\n const handleDrop: TreeProps[\"onDrop\"] = useCallback(\n (info: Parameters<NonNullable<TreeProps[\"onDrop\"]>>[0]) => {\n if (!onDrop) return;\n\n const dragNode = info.dragNode as DataNode & { _originalNode?: FolderTreeData };\n const dropNode = info.node as DataNode & { _originalNode?: FolderTreeData };\n\n const originalDragNode = dragNode._originalNode;\n const originalDropNode = dropNode._originalNode;\n if (!originalDragNode || !originalDropNode) return;\n\n // dragNode 的原始完整路径\n const dragKey = String(dragNode.key);\n // 计算新路径:如果 drop 到文件夹上(非叶子),新路径为 dropNode路径/dragNode文件名\n // 如果 drop 到文件旁边,新路径为 dropNode 的父路径/dragNode文件名\n const dropKey = String(dropNode.key);\n const dragFileName = originalDragNode.path;\n let newPath: string;\n\n if (!dropNode.isLeaf && info.dropToGap === false) {\n // 拖入文件夹内部\n newPath = `${dropKey}/${dragFileName}`;\n } else {\n // 拖到节点旁边(同级)\n const dropParentPath = dropKey.includes(\"/\")\n ? dropKey.substring(0, dropKey.lastIndexOf(\"/\"))\n : \"\";\n newPath = dropParentPath\n ? `${dropParentPath}/${dragFileName}`\n : dragFileName;\n }\n\n onDrop({\n fileName: originalDragNode.title,\n extra: originalDragNode.extra,\n oldPath: dragKey,\n newPath,\n dragNode: originalDragNode,\n dropNode: originalDropNode,\n });\n },\n [onDrop],\n );\n\n const titleNode =\n directoryTitle === false || directoryTitle === null\n ? null\n : typeof directoryTitle === \"function\"\n ? directoryTitle()\n : directoryTitle;\n\n return (\n <div className={clsx(styles.directoryPanel, className)} style={{ width }}>\n {titleNode && <div className={styles.directoryTitle}>{titleNode}</div>}\n <div className={styles.directoryTreeContent}>\n <AntDirectoryTree\n treeData={treeDataConverted}\n selectedKeys={selectedKeys}\n expandedKeys={expandedKeys}\n onSelect={onSelect}\n onExpand={onExpand}\n multiple={false}\n blockNode\n showLine={showLine as any}\n switcherIcon={switcherIcon}\n defaultExpandAll={defaultExpandAll}\n draggable={draggableConfig}\n onDrop={dragMode ? handleDrop : undefined}\n />\n </div>\n </div>\n );\n};\n\nexport default DirectoryTreeComponent;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import React, { useCallback, useMemo } from \"react\";\nimport { Tree, Dropdown, Input } from \"antd\";\nimport { FileOutlined, FolderOutlined, MoreOutlined } from \"@ant-design/icons\";\nimport type { TreeProps } from \"antd\";\nimport type { DataNode } from \"antd/es/tree\";\nimport clsx from \"clsx\";\nimport type {\n FolderTreeData,\n FolderTreeProps,\n EditNodeInfo,\n CreateNodeContext,\n} from \"./types\";\nimport { useStyles } from \"./styles\";\nimport { useFolderDrag, type DropPosition } from \"./useFolderDrag\";\n\nconst { DirectoryTree: AntDirectoryTree } = Tree;\n\nexport interface DirectoryTreeComponentProps {\n treeData: FolderTreeData[];\n directoryIcons?: FolderTreeProps[\"directoryIcons\"];\n selectedKeys?: string[];\n expandedKeys?: string[];\n onSelect?: TreeProps[\"onSelect\"];\n onExpand?: TreeProps[\"onExpand\"];\n showLine?: FolderTreeProps[\"showLine\"];\n switcherIcon?: FolderTreeProps[\"switcherIcon\"];\n defaultExpandAll?: boolean;\n className?: string;\n directoryTitle?: FolderTreeProps[\"directoryTitle\"];\n moreActions?: FolderTreeProps[\"moreActions\"];\n width?: number | string;\n draggable?: FolderTreeProps[\"draggable\"];\n onDrop?: FolderTreeProps[\"onDrop\"];\n /** 当前编辑节点信息 */\n editNode?: EditNodeInfo | null;\n /** 编辑值变化回调 */\n onEditValueChange?: (value: string) => void;\n /** 编辑确认回调 */\n onEditConfirm?: () => void;\n /** 编辑取消回调 */\n onEditCancel?: () => void;\n /** 新建上下文 */\n createInfo?: CreateNodeContext | null;\n /** 开始重命名回调(由父组件注入) */\n onStartRename?: (fullPath: string, node: FolderTreeData) => void;\n}\n\nconst DirectoryTreeComponent: React.FC<DirectoryTreeComponentProps> = ({\n treeData,\n selectedKeys,\n expandedKeys,\n onSelect,\n onExpand,\n showLine = false,\n switcherIcon,\n defaultExpandAll = true,\n className,\n directoryIcons,\n directoryTitle,\n moreActions,\n width,\n draggable,\n onDrop,\n editNode,\n onEditValueChange,\n onEditConfirm,\n onEditCancel,\n createInfo,\n onStartRename,\n}) => {\n const styles = useStyles();\n\n const isFolder = (node: FolderTreeData): boolean => {\n return !!node.children && node.children.length > 0;\n };\n\n const getIcon = useCallback(\n (node: FolderTreeData) => {\n if (directoryIcons === false || directoryIcons === null) {\n return null;\n }\n if (isFolder(node)) {\n const icon = directoryIcons?.directory;\n if (typeof icon === \"function\") return icon();\n return icon || <FolderOutlined />;\n }\n const filePath = node.path.toLowerCase();\n const extension = filePath.split(\".\").pop();\n if (extension) {\n const icon = directoryIcons?.[extension];\n if (icon) return typeof icon === \"function\" ? icon() : icon;\n }\n return <FileOutlined />;\n },\n [directoryIcons],\n );\n\n const buildPathSegments = useCallback(\n (node: FolderTreeData, parentSegments: string[] = []): string[] => {\n if (node.path === \"/\" && parentSegments.length === 0) {\n return [\"/\"];\n }\n return [...parentSegments, node.path].filter((s) => s !== \"\");\n },\n [],\n );\n\n const renderInlineInput = useCallback(\n (value: string) => (\n <span className={styles.treeNodeTitle}>\n <Input\n size=\"small\"\n value={value}\n onChange={(e) => onEditValueChange?.(e.target.value)}\n onBlur={() => onEditConfirm?.()}\n onPressEnter={() => onEditConfirm?.()}\n onKeyDown={(e) => {\n if (e.key === \"Escape\") {\n e.stopPropagation();\n onEditCancel?.();\n }\n }}\n autoFocus\n className={styles.inlineInput}\n onClick={(e) => e.stopPropagation()}\n onSelect={(e) => e.stopPropagation()}\n onFocus={(e) => e.stopPropagation()}\n />\n </span>\n ),\n [onEditValueChange, onEditConfirm, onEditCancel, styles],\n );\n\n // ====== 拖拽模式 ======\n const dragMode = draggable === true ? \"file\" : draggable || false;\n\n // ====== 自定义拖拽 hook ======\n const handleDragDrop = useCallback(\n (dragNode: DataNode, dropNode: DataNode, dropPosition: DropPosition) => {\n const dragNd = dragNode as DataNode & { _originalNode?: FolderTreeData };\n const dropNd = dropNode as DataNode & { _originalNode?: FolderTreeData };\n const originalDragNode = dragNd._originalNode;\n const originalDropNode = dropNd._originalNode;\n if (!originalDragNode) return;\n\n const dragKey = String(dragNode.key);\n const dropKey = String(dropNode.key);\n const dragFileName = originalDragNode.path;\n let newPath: string;\n\n // 拖到底部 drop zone:放在根级别末尾\n if (!originalDropNode && dropKey === \"__bottom_placeholder__\") {\n newPath = dragFileName;\n onDrop?.({\n fileName: originalDragNode.title,\n extra: originalDragNode.extra,\n oldPath: dragKey,\n newPath,\n dragNode: originalDragNode,\n dropNode: { title: \"\", path: \"\" },\n });\n return;\n }\n\n if (!originalDropNode) return;\n\n if (!dropNode.isLeaf && dropPosition === 0) {\n // 拖入文件夹内部\n newPath = `${dropKey}/${dragFileName}`;\n } else {\n // 拖到节点旁边(同级)\n const dropParentPath = dropKey.includes(\"/\")\n ? dropKey.substring(0, dropKey.lastIndexOf(\"/\"))\n : \"\";\n newPath = dropParentPath\n ? `${dropParentPath}/${dragFileName}`\n : dragFileName;\n }\n\n onDrop?.({\n fileName: originalDragNode.title,\n extra: originalDragNode.extra,\n oldPath: dragKey,\n newPath,\n dragNode: originalDragNode,\n dropNode: originalDropNode,\n });\n },\n [onDrop],\n );\n\n const handleDragEnterExpand = useCallback(\n (nodeKey: string) => {\n const isExpanded = expandedKeys?.includes(nodeKey);\n if (!isExpanded) {\n onExpand?.([...(expandedKeys || []), nodeKey], {\n node: null as any,\n expanded: true,\n nativeEvent: null as any,\n });\n }\n },\n [expandedKeys, onExpand],\n );\n\n const { onDragStart, onDragEnd, onItemDragEnter, onItemDragOver, onItemDragLeave, onItemDrop, onContainerDragOver, onContainerDrop, canDragNode } =\n useFolderDrag({\n dragMode,\n onDrop: handleDragDrop,\n onDragEnterExpand: handleDragEnterExpand,\n });\n\n // ====== 转换树数据 ======\n // 注意:convertToTreeData 不依赖拖拽状态,拖拽效果通过 DOM 操作实现\n const convertToTreeData = useCallback(\n (\n nodes: FolderTreeData[],\n parentSegments: string[] = [],\n parentKey: string = \"\",\n ): DataNode[] => {\n const result = nodes.map((node) => {\n const pathSegments = buildPathSegments(node, parentSegments);\n const fullPath = pathSegments.join(\"/\").replace(/^\\/+/, \"\");\n\n const isEditing = editNode && editNode.key === fullPath;\n\n const nodeChildren = node.children\n ? convertToTreeData(node.children, pathSegments, fullPath)\n : undefined;\n\n const baseNode: any = {\n key: fullPath,\n path: fullPath,\n pathSegments,\n icon: getIcon(node),\n isLeaf: !isFolder(node),\n _originalNode: node,\n children: nodeChildren,\n };\n\n // 编辑态:直接渲染 inline input\n if (isEditing) {\n baseNode.title = renderInlineInput(editNode!.currentValue);\n return baseNode;\n }\n\n // title 内容(按钮、菜单等)\n const titleContent = (\n <span\n className={clsx(\n styles.treeNodeTitle,\n moreActions && styles.treeNodeTitleHover,\n )}\n >\n <span>{node.title}</span>\n {moreActions && (\n <Dropdown\n menu={moreActions(node, {\n startRename: () => onStartRename?.(fullPath, node),\n })}\n trigger={[\"click\"]}\n placement=\"bottomRight\"\n >\n <span\n className={clsx(styles.moreIcon, \"folder-tree-more-icon\")}\n onClick={(e) => e.stopPropagation()}\n >\n <MoreOutlined />\n </span>\n </Dropdown>\n )}\n </span>\n );\n\n // 启用拖拽时:在 title 外层包裹具有 data-node-key 属性的容器,\n // 用于 DOM 查询和事件绑定。拖拽状态通过 CSS class 控制。\n if (dragMode) {\n const nodeData = baseNode as DataNode & {\n _isTempNode?: boolean;\n };\n const draggableDiv = canDragNode(nodeData);\n\n baseNode.title = (\n <div\n className={clsx(\n styles.treeNodeWrapper,\n draggableDiv && styles.dragNodeHandle,\n )}\n data-node-key={fullPath}\n draggable={draggableDiv}\n onDragStart={draggableDiv ? (e) => onDragStart(e, baseNode) : undefined}\n onDragEnd={draggableDiv ? onDragEnd : undefined}\n onDragEnter={(e) => onItemDragEnter(e, baseNode)}\n onDragOver={(e) => onItemDragOver(e, baseNode)}\n onDragLeave={onItemDragLeave}\n onDrop={(e) => onItemDrop(e, baseNode)}\n >\n {titleContent}\n </div>\n );\n } else {\n baseNode.title = titleContent;\n }\n\n return baseNode;\n });\n\n // 新建模式:在目标父节点下插入临时节点\n if (createInfo && editNode && editNode.mode === \"create\") {\n const targetParentKey = createInfo.parentKey;\n if (\n targetParentKey === parentKey ||\n (targetParentKey === \"\" && parentKey === \"\") ||\n (targetParentKey === \"/\" && parentKey === \"\")\n ) {\n const tempNode: any = {\n key: editNode.key,\n title: renderInlineInput(editNode.currentValue),\n icon:\n createInfo.type === \"folder\" ? (\n <FolderOutlined />\n ) : (\n <FileOutlined />\n ),\n isLeaf: createInfo.type === \"file\",\n path: editNode.key,\n pathSegments: [editNode.key],\n _originalNode: null,\n _isTempNode: true,\n };\n result.push(tempNode);\n }\n }\n\n return result;\n },\n [\n buildPathSegments,\n getIcon,\n moreActions,\n styles,\n editNode,\n renderInlineInput,\n createInfo,\n onStartRename,\n dragMode,\n canDragNode,\n onDragStart,\n onDragEnd,\n onItemDragEnter,\n onItemDragOver,\n onItemDragLeave,\n onItemDrop,\n ],\n );\n\n const treeDataConverted = useMemo(\n () => convertToTreeData(treeData, [], \"\"),\n [treeData, convertToTreeData],\n );\n\n const handleSelect: TreeProps[\"onSelect\"] = useCallback(\n (keys: any, info: any) => {\n // 编辑态不响应选中\n if (editNode) return;\n // 临时节点不可选中\n const node = info.node as DataNode & { _isTempNode?: boolean };\n if (node._isTempNode) return;\n // 点击 moreActions 区域不触发选中\n const target = info.nativeEvent?.target as HTMLElement | null;\n if (\n target &&\n (target.closest(\".folder-tree-more-icon\") ||\n target.closest(\".ant-dropdown\"))\n ) {\n return;\n }\n onSelect?.(keys, info);\n },\n [onSelect, editNode],\n );\n\n const titleNode =\n directoryTitle === false || directoryTitle === null\n ? null\n : typeof directoryTitle === \"function\"\n ? directoryTitle()\n : directoryTitle;\n\n return (\n <div className={clsx(styles.directoryPanel, className)} style={{ width }}>\n {titleNode && <div className={styles.directoryTitle}>{titleNode}</div>}\n <div className={styles.directoryTreeContent}\n onDragOver={dragMode ? onContainerDragOver : undefined}\n onDrop={dragMode ? onContainerDrop : undefined}\n >\n <AntDirectoryTree\n style={\n {\n \"--ant-tree-directory-node-selected-bg\": \"rgba(0,0,0,0.03)\",\n \"--ant-tree-directory-node-selected-color\": \"#1a1c1e\",\n } as React.CSSProperties\n }\n treeData={treeDataConverted}\n selectedKeys={selectedKeys}\n expandedKeys={expandedKeys}\n onSelect={handleSelect}\n onExpand={onExpand}\n multiple={false}\n blockNode\n showLine={showLine as any}\n switcherIcon={switcherIcon}\n defaultExpandAll={defaultExpandAll}\n draggable={false}\n />\n </div>\n </div>\n );\n};\n\nexport default DirectoryTreeComponent;"],
5
+ "mappings": "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",
6
6
  "names": ["clsx"]
7
7
  }
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import type { FolderTreeProps } from "./types";
3
- export type { FolderTreeData, FolderTreeProps, FileContentService, } from "./types";
4
- declare const FolderTree: React.FC<FolderTreeProps>;
2
+ import type { FolderTreeProps, FolderTreeRef } from "./types";
3
+ export type { FolderTreeData, FolderTreeProps, FileContentService, FolderTreeRef, } from "./types";
4
+ declare const FolderTree: React.ForwardRefExoticComponent<FolderTreeProps & React.RefAttributes<FolderTreeRef>>;
5
5
  export default FolderTree;
@@ -38,7 +38,7 @@ var import_DirectoryTree = __toESM(require("./DirectoryTree"));
38
38
  var import_FilePreview = __toESM(require("./FilePreview"));
39
39
  var import_styles = require("./styles");
40
40
  var import_jsx_runtime = require("react/jsx-runtime");
41
- var FolderTree = (props) => {
41
+ var FolderTree = (0, import_react.forwardRef)((props, ref) => {
42
42
  const {
43
43
  className,
44
44
  style,
@@ -65,9 +65,15 @@ var FolderTree = (props) => {
65
65
  switcherIcon,
66
66
  showPreview = true,
67
67
  draggable,
68
- onDrop
68
+ onDrop,
69
+ onRename,
70
+ onCreate
69
71
  } = props;
70
72
  const styles = (0, import_styles.useStyles)();
73
+ const [editNode, setEditNode] = (0, import_react.useState)(null);
74
+ const [createContext, setCreateContext] = (0, import_react.useState)(
75
+ null
76
+ );
71
77
  const findNodeAndValidate = (0, import_react.useCallback)(
72
78
  (path, validateAsFile = false) => {
73
79
  if (!path)
@@ -93,6 +99,58 @@ var FolderTree = (props) => {
93
99
  [treeData]
94
100
  );
95
101
  const isValidSelectedFile = (filePath) => !!(filePath && filePath.length > 0 && findNodeAndValidate(filePath, true).isValid);
102
+ (0, import_react.useEffect)(() => {
103
+ if (!editNode)
104
+ return;
105
+ const { node } = findNodeAndValidate(editNode.key);
106
+ if (!node) {
107
+ setEditNode(null);
108
+ setCreateContext(null);
109
+ }
110
+ }, [treeData]);
111
+ const handleEditValueChange = (0, import_react.useCallback)((value) => {
112
+ setEditNode((prev) => prev ? { ...prev, currentValue: value } : null);
113
+ }, []);
114
+ const handleEditConfirm = (0, import_react.useCallback)(() => {
115
+ if (!editNode)
116
+ return;
117
+ const newValue = editNode.currentValue.trim();
118
+ if (editNode.mode === "rename") {
119
+ const { node } = findNodeAndValidate(editNode.key);
120
+ onRename == null ? void 0 : onRename({
121
+ key: editNode.key,
122
+ oldTitle: editNode.originalTitle,
123
+ newTitle: newValue,
124
+ node
125
+ });
126
+ } else if (editNode.mode === "create" && createContext) {
127
+ onCreate == null ? void 0 : onCreate({
128
+ parentKey: createContext.parentKey,
129
+ name: newValue,
130
+ type: createContext.type,
131
+ extra: createContext.extra
132
+ });
133
+ }
134
+ setEditNode(null);
135
+ setCreateContext(null);
136
+ }, [editNode, createContext, findNodeAndValidate, onRename, onCreate]);
137
+ const handleEditCancel = (0, import_react.useCallback)(() => {
138
+ setEditNode(null);
139
+ setCreateContext(null);
140
+ }, []);
141
+ const handleStartRename = (0, import_react.useCallback)(
142
+ (fullPath, node) => {
143
+ const titleStr = typeof node.title === "string" ? node.title : String(node.path);
144
+ setCreateContext(null);
145
+ setEditNode({
146
+ key: fullPath,
147
+ originalTitle: titleStr,
148
+ currentValue: titleStr,
149
+ mode: "rename"
150
+ });
151
+ },
152
+ []
153
+ );
96
154
  const [selectedFileState, setSelectedFileState] = (0, import_react.useState)(
97
155
  () => isValidSelectedFile(selectedFile || defaultSelectedFile) ? selectedFile || defaultSelectedFile || [] : []
98
156
  );
@@ -190,11 +248,43 @@ var FolderTree = (props) => {
190
248
  );
191
249
  }
192
250
  };
251
+ const isExpandedControlled = expandedPaths !== void 0;
193
252
  const handleExpand = (keys) => {
194
253
  const newPaths = keys;
195
- setExpandedPaths(newPaths);
254
+ if (isExpandedControlled) {
255
+ setExpandedPaths(newPaths);
256
+ }
196
257
  onExpandedPathsChange == null ? void 0 : onExpandedPathsChange(newPaths);
197
258
  };
259
+ (0, import_react.useImperativeHandle)(
260
+ ref,
261
+ () => ({
262
+ createNode: (parentPath, options) => {
263
+ const defaultName = options.defaultName || (options.type === "folder" ? "新建文件夹" : "新建文件");
264
+ const tempKey = `__create__${parentPath || "root"}__${Date.now()}`;
265
+ setCreateContext({
266
+ parentKey: parentPath,
267
+ type: options.type,
268
+ extra: options.extra
269
+ });
270
+ setEditNode({
271
+ key: tempKey,
272
+ originalTitle: "",
273
+ currentValue: defaultName,
274
+ mode: "create"
275
+ });
276
+ if (isExpandedControlled && parentPath && parentPath !== "/") {
277
+ setExpandedPaths((prev) => {
278
+ const current = prev || [];
279
+ if (current.includes(parentPath))
280
+ return current;
281
+ return [...current, parentPath];
282
+ });
283
+ }
284
+ }
285
+ }),
286
+ []
287
+ );
198
288
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
199
289
  "div",
200
290
  {
@@ -219,7 +309,7 @@ var FolderTree = (props) => {
219
309
  treeData,
220
310
  directoryIcons,
221
311
  selectedKeys: selectable && selectedFileState && validSelectedFile ? [selectedFileState.join("/")] : [],
222
- expandedKeys: expandedPathsState,
312
+ expandedKeys: isExpandedControlled ? expandedPathsState : void 0,
223
313
  onSelect: handleSelect,
224
314
  onExpand: handleExpand,
225
315
  defaultExpandAll,
@@ -229,6 +319,12 @@ var FolderTree = (props) => {
229
319
  switcherIcon,
230
320
  width: directoryTreeWidth,
231
321
  draggable,
322
+ editNode,
323
+ onEditValueChange: handleEditValueChange,
324
+ onEditConfirm: handleEditConfirm,
325
+ onEditCancel: handleEditCancel,
326
+ createInfo: createContext,
327
+ onStartRename: handleStartRename,
232
328
  onDrop
233
329
  }
234
330
  ),
@@ -252,6 +348,7 @@ var FolderTree = (props) => {
252
348
  ]
253
349
  }
254
350
  );
255
- };
351
+ });
352
+ FolderTree.displayName = "FolderTree";
256
353
  var FolderTree_default = FolderTree;
257
354
  //# sourceMappingURL=index.js.map