@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.
- package/dist/cjs/components/FolderTree/DirectoryTree.d.ts +13 -1
- package/dist/cjs/components/FolderTree/DirectoryTree.js +215 -70
- package/dist/cjs/components/FolderTree/DirectoryTree.js.map +2 -2
- package/dist/cjs/components/FolderTree/index.d.ts +3 -3
- package/dist/cjs/components/FolderTree/index.js +102 -5
- package/dist/cjs/components/FolderTree/index.js.map +2 -2
- package/dist/cjs/components/FolderTree/styles.d.ts +5 -0
- package/dist/cjs/components/FolderTree/styles.js +77 -14
- package/dist/cjs/components/FolderTree/styles.js.map +2 -2
- package/dist/cjs/components/FolderTree/types.d.ts +61 -2
- package/dist/cjs/components/FolderTree/types.js.map +1 -1
- package/dist/cjs/components/FolderTree/useFolderDrag.d.ts +53 -0
- package/dist/cjs/components/FolderTree/useFolderDrag.js +309 -0
- package/dist/cjs/components/FolderTree/useFolderDrag.js.map +7 -0
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js.map +2 -2
- package/dist/esm/components/FolderTree/DirectoryTree.d.ts +13 -1
- package/dist/esm/components/FolderTree/DirectoryTree.js +220 -62
- package/dist/esm/components/FolderTree/DirectoryTree.js.map +1 -1
- package/dist/esm/components/FolderTree/index.d.ts +3 -3
- package/dist/esm/components/FolderTree/index.js +149 -31
- package/dist/esm/components/FolderTree/index.js.map +1 -1
- package/dist/esm/components/FolderTree/styles.d.ts +5 -0
- package/dist/esm/components/FolderTree/styles.js +17 -12
- package/dist/esm/components/FolderTree/styles.js.map +1 -1
- package/dist/esm/components/FolderTree/types.d.ts +61 -2
- package/dist/esm/components/FolderTree/types.js.map +1 -1
- package/dist/esm/components/FolderTree/useFolderDrag.d.ts +53 -0
- package/dist/esm/components/FolderTree/useFolderDrag.js +324 -0
- package/dist/esm/components/FolderTree/useFolderDrag.js.map +1 -0
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/umd/chat-sdk.min.js +1 -1
- 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
|
-
|
|
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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
[
|
|
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 =
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (
|
|
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
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const
|
|
163
|
-
if (
|
|
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
|
-
|
|
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
|
-
[
|
|
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)(
|
|
190
|
-
|
|
323
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
324
|
+
"div",
|
|
191
325
|
{
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
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": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,
|
|
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.
|
|
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
|
-
|
|
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
|