@ai-group/chat-sdk 3.5.13 → 3.6.0-alpha.1

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 (52) hide show
  1. package/dist/cjs/components/FileGallery/index.js +1 -1
  2. package/dist/cjs/components/FileGallery/index.js.map +1 -1
  3. package/dist/cjs/components/FolderTree/DirectoryTree.d.ts +6 -0
  4. package/dist/cjs/components/FolderTree/DirectoryTree.js +5 -2
  5. package/dist/cjs/components/FolderTree/DirectoryTree.js.map +2 -2
  6. package/dist/cjs/components/FolderTree/index.js +28 -27
  7. package/dist/cjs/components/FolderTree/index.js.map +2 -2
  8. package/dist/cjs/components/FolderTree/styles.js +4 -1
  9. package/dist/cjs/components/FolderTree/styles.js.map +2 -2
  10. package/dist/cjs/components/FolderTree/types.d.ts +5 -0
  11. package/dist/cjs/components/FolderTree/types.js.map +1 -1
  12. package/dist/cjs/components/XAdkProvider/index.js +2 -0
  13. package/dist/cjs/components/XAdkProvider/index.js.map +2 -2
  14. package/dist/cjs/components/XAdkThoughtChain/index.js +75 -39
  15. package/dist/cjs/components/XAdkThoughtChain/index.js.map +2 -2
  16. package/dist/cjs/components/XAdkThoughtChain/styles.js +27 -26
  17. package/dist/cjs/components/XAdkThoughtChain/styles.js.map +2 -2
  18. package/dist/cjs/index.d.ts +2 -1
  19. package/dist/cjs/index.js +9 -0
  20. package/dist/cjs/index.js.map +2 -2
  21. package/dist/cjs/styles/tokens.d.ts +27 -0
  22. package/dist/cjs/styles/tokens.js +72 -0
  23. package/dist/cjs/styles/tokens.js.map +7 -0
  24. package/dist/cjs/types/XAdkThoughtChain.d.ts +13 -0
  25. package/dist/cjs/types/XAdkThoughtChain.js.map +1 -1
  26. package/dist/esm/components/FileGallery/index.js +1 -1
  27. package/dist/esm/components/FileGallery/index.js.map +1 -1
  28. package/dist/esm/components/FolderTree/DirectoryTree.d.ts +6 -0
  29. package/dist/esm/components/FolderTree/DirectoryTree.js +6 -2
  30. package/dist/esm/components/FolderTree/DirectoryTree.js.map +1 -1
  31. package/dist/esm/components/FolderTree/index.js +32 -28
  32. package/dist/esm/components/FolderTree/index.js.map +1 -1
  33. package/dist/esm/components/FolderTree/styles.js +2 -2
  34. package/dist/esm/components/FolderTree/styles.js.map +1 -1
  35. package/dist/esm/components/FolderTree/types.d.ts +5 -0
  36. package/dist/esm/components/FolderTree/types.js.map +1 -1
  37. package/dist/esm/components/XAdkProvider/index.js +3 -2
  38. package/dist/esm/components/XAdkProvider/index.js.map +1 -1
  39. package/dist/esm/components/XAdkThoughtChain/index.js +100 -50
  40. package/dist/esm/components/XAdkThoughtChain/index.js.map +1 -1
  41. package/dist/esm/components/XAdkThoughtChain/styles.js +20 -19
  42. package/dist/esm/components/XAdkThoughtChain/styles.js.map +1 -1
  43. package/dist/esm/index.d.ts +2 -1
  44. package/dist/esm/index.js +3 -0
  45. package/dist/esm/index.js.map +1 -1
  46. package/dist/esm/styles/tokens.d.ts +27 -0
  47. package/dist/esm/styles/tokens.js +42 -0
  48. package/dist/esm/styles/tokens.js.map +1 -0
  49. package/dist/esm/types/XAdkThoughtChain.d.ts +13 -0
  50. package/dist/esm/types/XAdkThoughtChain.js.map +1 -1
  51. package/dist/umd/chat-sdk.min.js +1 -1
  52. package/package.json +1 -1
@@ -163,7 +163,7 @@ var FileGallery = ({
163
163
  {
164
164
  src: url,
165
165
  alt: fileName,
166
- fallback: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mN8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==",
166
+ fallback: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg==",
167
167
  preview: onClick ? false : { src: url }
168
168
  }
169
169
  ),
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/components/FileGallery/index.tsx"],
4
- "sourcesContent": ["import React, { useState, useEffect } from \"react\";\nimport { Image, Tooltip, Progress } from \"antd\";\nimport {\n FileOutlined,\n FilePdfOutlined,\n FileWordOutlined,\n FileExcelOutlined,\n FilePptOutlined,\n FileImageOutlined,\n CloseOutlined,\n AudioOutlined,\n FileZipOutlined,\n VideoCameraOutlined,\n FileMarkdownOutlined,\n} from \"@ant-design/icons\";\nimport { FileItem, FileGalleryProps } from \"@/types\";\nimport { useStyles } from \"./styles\";\n\n// ==================== 工具函数 ====================\n\n/**\n * 获取文件名\n */\nconst getFileName = (file: FileItem): string => {\n return file.displayName || file.name || \"\";\n};\n\n/**\n * 获取文件大小\n */\nconst getFileSize = (file: FileItem): number => {\n return file.size || 0;\n};\n\n/**\n * 获取文件 MIME 类型\n */\nconst getMimeType = (file: FileItem): string => {\n return file.mimeType || file.type || \"\";\n};\n\n/**\n * 获取文件 URL\n */\nconst getFileUrl = (file: FileItem): string => {\n return (\n file.fileUri ||\n file.response?.fileUrl ||\n file.response?.tempUrl ||\n file.tempUrl ||\n \"\"\n );\n};\n\n/**\n * 获取文件唯一标识\n */\nconst getFileId = (file: FileItem): string => {\n return file.id || file.uid || \"\";\n};\n\n/**\n * 判断是否是图片文件\n */\nconst isImageFile = (file: FileItem): boolean => {\n const mimeType = getMimeType(file);\n if (mimeType && mimeType.startsWith(\"image/\")) return true;\n\n const fileName = getFileName(file);\n if (fileName && fileName.match(/\\.(jpg|jpeg|png|gif|webp|bmp|svg)$/i))\n return true;\n\n const url = getFileUrl(file);\n if (url && url.match(/\\.(jpg|jpeg|png|gif|webp|bmp|svg)(\\?.*)?$/i))\n return true;\n\n return false;\n};\n\n/**\n * 判断是否是音频文件\n */\nconst isAudioFile = (file: FileItem): boolean => {\n const mimeType = getMimeType(file);\n if (mimeType && mimeType.startsWith(\"audio/\")) return true;\n\n const fileName = getFileName(file);\n return !!fileName?.match(/\\.(mp3|wav|m4a|aac|ogg|flac)$/i);\n};\n\n/**\n * 判断是否是视频文件\n */\nconst isVideoFile = (file: FileItem): boolean => {\n const mimeType = getMimeType(file);\n if (mimeType && mimeType.startsWith(\"video/\")) return true;\n\n const fileName = getFileName(file);\n return !!fileName?.match(/\\.(mp4|mov|webm|mkv|avi)$/i);\n};\n\n/**\n * 判断是否是压缩包文件\n */\nconst isZipFile = (file: FileItem): boolean => {\n const fileName = getFileName(file);\n return !!fileName?.match(/\\.(zip|rar|7z|tar|gz|bz2|xz|tgz)$/i);\n};\n\n/**\n * 判断是否是 Markdown 文件\n */\nconst isMarkdownFile = (file: FileItem): boolean => {\n const fileName = getFileName(file);\n return !!fileName?.match(/\\.(md|markdown)$/i);\n};\n\n/**\n * 获取文件扩展名\n */\nconst getFileExtension = (filename: string): string => {\n const ext = filename.split(\".\").pop();\n return ext ? ext.toLowerCase() : \"\";\n};\n\n/**\n * 获取文件图标和颜色\n */\nconst getFileIcon = (\n file: FileItem,\n): { icon: React.ReactNode; color: string } => {\n const ext = getFileExtension(getFileName(file));\n\n // PDF\n if (ext === \"pdf\") {\n return { icon: <FilePdfOutlined />, color: \"#ff4d4f\" };\n }\n\n // Word\n if ([\"doc\", \"docx\"].includes(ext)) {\n return { icon: <FileWordOutlined />, color: \"#1677ff\" };\n }\n\n // Excel\n if ([\"xls\", \"xlsx\", \"csv\"].includes(ext)) {\n return { icon: <FileExcelOutlined />, color: \"#22b35e\" };\n }\n\n // PPT\n if ([\"ppt\", \"pptx\"].includes(ext)) {\n return { icon: <FilePptOutlined />, color: \"#ff6e31\" };\n }\n\n // Audio\n if ([\"mp3\", \"wav\", \"m4a\", \"aac\", \"ogg\", \"flac\"].includes(ext)) {\n return { icon: <AudioOutlined />, color: \"#722ed1\" };\n }\n\n // Video\n if ([\"mp4\", \"mov\", \"webm\", \"mkv\", \"avi\"].includes(ext)) {\n return { icon: <VideoCameraOutlined />, color: \"#fa8c16\" };\n }\n\n // 压缩包\n if ([\"zip\", \"rar\", \"7z\", \"tar\", \"gz\", \"bz2\", \"xz\", \"tgz\"].includes(ext)) {\n return { icon: <FileZipOutlined />, color: \"#eb2f96\" };\n }\n\n // Markdown\n if ([\"md\", \"markdown\"].includes(ext)) {\n return { icon: <FileMarkdownOutlined />, color: \"#13c2c2\" };\n }\n\n // 图片\n if (isImageFile(file)) {\n return { icon: <FileImageOutlined />, color: \"#8c8c8c\" };\n }\n\n // 默认\n return { icon: <FileOutlined />, color: \"#8c8c8c\" };\n};\n\n/**\n * 格式化文件大小\n */\nconst formatFileSize = (bytes: number): string => {\n if (bytes < 1024) return bytes + \" B\";\n if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + \" KB\";\n return (bytes / (1024 * 1024)).toFixed(1) + \" MB\";\n};\n\nconst styles = useStyles();\n\n/**\n * FileGallery - 单文件展示组件\n *\n * 功能特性:\n * - 📁 支持多种文件类型展示 (图片、音频、视频、文档等)\n * - 🖼️ 图片支持预览和缩略图\n * - 🎵 音频文件支持内联播放\n * - 🎬 视频文件支持内联播放\n * - 📊 显示文件大小、类型图标\n * - 🗑️ 支持删除操作\n * - 📤 支持上传进度显示\n * - 🎨 支持卡片内部布局控制(align:图标和信息的排列方式)\n *\n * @example\n * // XAdkSender 场景 - 可删除的本地文件\n * {files.map(file => (\n * <FileGallery\n * key={file.id}\n * file={file}\n * removable\n * onRemove={handleRemove}\n * />\n * ))}\n *\n * @example\n * // XadkChatbot 场景 - 只读的远程文件\n * {files.map(file => (\n * <FileGallery key={file.id} file={file} />\n * ))}\n */\nconst FileGallery: React.FC<FileGalleryProps> = ({\n file,\n align = \"left\",\n removable = false,\n onRemove = () => {},\n className,\n style,\n onClick,\n}) => {\n const [objectUrl, setObjectUrl] = useState(\"\");\n\n useEffect(() => {\n if (!file?.file) return;\n\n const url = URL.createObjectURL(file.file);\n setObjectUrl(url);\n\n return () => URL.revokeObjectURL(url);\n }, [file?.file]);\n\n if (!file) return null;\n\n const isImage = isImageFile(file);\n const isAudio = isAudioFile(file);\n const isVideo = isVideoFile(file);\n const isZip = isZipFile(file);\n const isMarkdown = isMarkdownFile(file);\n const fileName = getFileName(file);\n const fileSize = getFileSize(file);\n const fileId = getFileId(file);\n const url = getFileUrl(file) || objectUrl;\n\n // 图片文件\n if (isImage) {\n return (\n <div\n className={`${styles.fileCard} ${align === \"right\" ? \"align-right\" : \"\"} ${className || \"\"}`}\n style={{ ...style, cursor: onClick ? \"pointer\" : undefined }}\n onClick={() => onClick?.(file)}\n >\n {/* 图片缩略图 */}\n <div className={styles.imageThumbnail}>\n <Image\n src={url}\n alt={fileName}\n fallback=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mN8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==\"\n preview={onClick ? false : { src: url }}\n />\n\n {/* 上传进度遮罩 */}\n {file.status === \"uploading\" && (\n <div className={styles.imageOverlay}>\n <Progress\n type=\"circle\"\n percent={file.progress}\n size={30}\n strokeColor=\"#1677ff\"\n />\n </div>\n )}\n </div>\n\n {/* 文件信息 */}\n <div className={styles.fileInfo}>\n <Tooltip title={fileName}>\n <div className={styles.fileName}>\n {fileName.length > 15\n ? `${fileName.substring(0, 15)}...`\n : fileName}\n </div>\n </Tooltip>\n {Number(file?.size) > 0 && (\n <div className={styles.fileSize}>{formatFileSize(fileSize)}</div>\n )}\n </div>\n\n {/* 删除按钮 */}\n {removable && (\n <button\n className={styles.fileRemoveBtn}\n onClick={() => onRemove(fileId)}\n disabled={file.status === \"uploading\"}\n aria-label=\"删除文件\"\n >\n <CloseOutlined />\n </button>\n )}\n </div>\n );\n }\n\n // 音频文件\n if (isAudio) {\n return (\n <div\n className={`${styles.fileCard} ${align === \"right\" ? \"align-right\" : \"\"} ${className || \"\"}`}\n style={style}\n >\n <div className={styles.fileIcon} style={{ color: \"#722ed1\" }}>\n <AudioOutlined />\n </div>\n\n <div className={styles.fileInfo}>\n <Tooltip title={fileName}>\n <div className={styles.fileName}>{fileName}</div>\n </Tooltip>\n\n <audio\n src={url}\n controls\n className={styles.mediaWrapper}\n style={{ width: \"100%\", height: 28 }}\n />\n </div>\n\n {removable && (\n <button\n className={styles.fileRemoveBtn}\n onClick={() => onRemove(fileId)}\n disabled={file.status === \"uploading\"}\n aria-label=\"删除文件\"\n >\n <CloseOutlined />\n </button>\n )}\n </div>\n );\n }\n\n // 视频文件\n if (isVideo) {\n return (\n <div\n className={`${styles.fileCard} ${align === \"right\" ? \"align-right\" : \"\"} ${className || \"\"}`}\n style={style}\n >\n <div className={styles.fileIcon} style={{ color: \"#fa8c16\" }}>\n <VideoCameraOutlined />\n </div>\n\n <div className={styles.fileInfo}>\n <Tooltip title={fileName}>\n <div className={styles.fileName}>{fileName}</div>\n </Tooltip>\n\n <video\n src={url}\n controls\n className={styles.mediaWrapper}\n style={{ width: \"100%\", height: 40 }}\n />\n </div>\n\n {removable && (\n <button\n className={styles.fileRemoveBtn}\n onClick={() => onRemove(fileId)}\n disabled={file.status === \"uploading\"}\n aria-label=\"删除文件\"\n >\n <CloseOutlined />\n </button>\n )}\n </div>\n );\n }\n\n // 其他文件\n const { icon, color } = getFileIcon(file);\n const isExternalUrl = url && url.startsWith(\"http\");\n\n return (\n <div\n className={`${styles.fileCard} ${align === \"right\" ? \"align-right\" : \"\"} ${className || \"\"}`}\n style={{ ...style, cursor: onClick ? \"pointer\" : undefined }}\n onClick={() => onClick?.(file)}\n >\n <div className={styles.fileIcon} style={{ color }}>\n {icon}\n </div>\n\n <div className={styles.fileInfo}>\n {isExternalUrl && !onClick ? (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={styles.fileLink}\n >\n <Tooltip title={fileName}>\n <div className={styles.fileName}>\n {fileName.length > 15\n ? `${fileName.substring(0, 15)}...`\n : fileName}\n </div>\n </Tooltip>\n </a>\n ) : (\n <Tooltip title={fileName}>\n <div className={styles.fileName}>\n {fileName.length > 15\n ? `${fileName.substring(0, 15)}...`\n : fileName}\n </div>\n </Tooltip>\n )}\n\n {file.status === \"uploading\" ? (\n <Progress\n percent={file.progress}\n size=\"small\"\n showInfo={false}\n strokeColor=\"#1677ff\"\n className={styles.progress}\n />\n ) : (\n fileSize > 0 && (\n <div className={styles.fileSize}>{formatFileSize(fileSize)}</div>\n )\n )}\n\n {file.status === \"error\" && file.errorMessage && (\n <div\n style={{\n fontSize: \"11px\",\n color: \"#ff4d4f\",\n marginTop: \"2px\",\n }}\n >\n {file.errorMessage}\n </div>\n )}\n </div>\n\n {removable && (\n <button\n className={styles.fileRemoveBtn}\n onClick={() => onRemove(fileId)}\n disabled={file.status === \"uploading\"}\n aria-label=\"删除文件\"\n >\n <CloseOutlined />\n </button>\n )}\n </div>\n );\n};\n\nexport default FileGallery;\n"],
4
+ "sourcesContent": ["import React, { useState, useEffect } from \"react\";\nimport { Image, Tooltip, Progress } from \"antd\";\nimport {\n FileOutlined,\n FilePdfOutlined,\n FileWordOutlined,\n FileExcelOutlined,\n FilePptOutlined,\n FileImageOutlined,\n CloseOutlined,\n AudioOutlined,\n FileZipOutlined,\n VideoCameraOutlined,\n FileMarkdownOutlined,\n} from \"@ant-design/icons\";\nimport { FileItem, FileGalleryProps } from \"@/types\";\nimport { useStyles } from \"./styles\";\n\n// ==================== 工具函数 ====================\n\n/**\n * 获取文件名\n */\nconst getFileName = (file: FileItem): string => {\n return file.displayName || file.name || \"\";\n};\n\n/**\n * 获取文件大小\n */\nconst getFileSize = (file: FileItem): number => {\n return file.size || 0;\n};\n\n/**\n * 获取文件 MIME 类型\n */\nconst getMimeType = (file: FileItem): string => {\n return file.mimeType || file.type || \"\";\n};\n\n/**\n * 获取文件 URL\n */\nconst getFileUrl = (file: FileItem): string => {\n return (\n file.fileUri ||\n file.response?.fileUrl ||\n file.response?.tempUrl ||\n file.tempUrl ||\n \"\"\n );\n};\n\n/**\n * 获取文件唯一标识\n */\nconst getFileId = (file: FileItem): string => {\n return file.id || file.uid || \"\";\n};\n\n/**\n * 判断是否是图片文件\n */\nconst isImageFile = (file: FileItem): boolean => {\n const mimeType = getMimeType(file);\n if (mimeType && mimeType.startsWith(\"image/\")) return true;\n\n const fileName = getFileName(file);\n if (fileName && fileName.match(/\\.(jpg|jpeg|png|gif|webp|bmp|svg)$/i))\n return true;\n\n const url = getFileUrl(file);\n if (url && url.match(/\\.(jpg|jpeg|png|gif|webp|bmp|svg)(\\?.*)?$/i))\n return true;\n\n return false;\n};\n\n/**\n * 判断是否是音频文件\n */\nconst isAudioFile = (file: FileItem): boolean => {\n const mimeType = getMimeType(file);\n if (mimeType && mimeType.startsWith(\"audio/\")) return true;\n\n const fileName = getFileName(file);\n return !!fileName?.match(/\\.(mp3|wav|m4a|aac|ogg|flac)$/i);\n};\n\n/**\n * 判断是否是视频文件\n */\nconst isVideoFile = (file: FileItem): boolean => {\n const mimeType = getMimeType(file);\n if (mimeType && mimeType.startsWith(\"video/\")) return true;\n\n const fileName = getFileName(file);\n return !!fileName?.match(/\\.(mp4|mov|webm|mkv|avi)$/i);\n};\n\n/**\n * 判断是否是压缩包文件\n */\nconst isZipFile = (file: FileItem): boolean => {\n const fileName = getFileName(file);\n return !!fileName?.match(/\\.(zip|rar|7z|tar|gz|bz2|xz|tgz)$/i);\n};\n\n/**\n * 判断是否是 Markdown 文件\n */\nconst isMarkdownFile = (file: FileItem): boolean => {\n const fileName = getFileName(file);\n return !!fileName?.match(/\\.(md|markdown)$/i);\n};\n\n/**\n * 获取文件扩展名\n */\nconst getFileExtension = (filename: string): string => {\n const ext = filename.split(\".\").pop();\n return ext ? ext.toLowerCase() : \"\";\n};\n\n/**\n * 获取文件图标和颜色\n */\nconst getFileIcon = (\n file: FileItem,\n): { icon: React.ReactNode; color: string } => {\n const ext = getFileExtension(getFileName(file));\n\n // PDF\n if (ext === \"pdf\") {\n return { icon: <FilePdfOutlined />, color: \"#ff4d4f\" };\n }\n\n // Word\n if ([\"doc\", \"docx\"].includes(ext)) {\n return { icon: <FileWordOutlined />, color: \"#1677ff\" };\n }\n\n // Excel\n if ([\"xls\", \"xlsx\", \"csv\"].includes(ext)) {\n return { icon: <FileExcelOutlined />, color: \"#22b35e\" };\n }\n\n // PPT\n if ([\"ppt\", \"pptx\"].includes(ext)) {\n return { icon: <FilePptOutlined />, color: \"#ff6e31\" };\n }\n\n // Audio\n if ([\"mp3\", \"wav\", \"m4a\", \"aac\", \"ogg\", \"flac\"].includes(ext)) {\n return { icon: <AudioOutlined />, color: \"#722ed1\" };\n }\n\n // Video\n if ([\"mp4\", \"mov\", \"webm\", \"mkv\", \"avi\"].includes(ext)) {\n return { icon: <VideoCameraOutlined />, color: \"#fa8c16\" };\n }\n\n // 压缩包\n if ([\"zip\", \"rar\", \"7z\", \"tar\", \"gz\", \"bz2\", \"xz\", \"tgz\"].includes(ext)) {\n return { icon: <FileZipOutlined />, color: \"#eb2f96\" };\n }\n\n // Markdown\n if ([\"md\", \"markdown\"].includes(ext)) {\n return { icon: <FileMarkdownOutlined />, color: \"#13c2c2\" };\n }\n\n // 图片\n if (isImageFile(file)) {\n return { icon: <FileImageOutlined />, color: \"#8c8c8c\" };\n }\n\n // 默认\n return { icon: <FileOutlined />, color: \"#8c8c8c\" };\n};\n\n/**\n * 格式化文件大小\n */\nconst formatFileSize = (bytes: number): string => {\n if (bytes < 1024) return bytes + \" B\";\n if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + \" KB\";\n return (bytes / (1024 * 1024)).toFixed(1) + \" MB\";\n};\n\nconst styles = useStyles();\n\n/**\n * FileGallery - 单文件展示组件\n *\n * 功能特性:\n * - 📁 支持多种文件类型展示 (图片、音频、视频、文档等)\n * - 🖼️ 图片支持预览和缩略图\n * - 🎵 音频文件支持内联播放\n * - 🎬 视频文件支持内联播放\n * - 📊 显示文件大小、类型图标\n * - 🗑️ 支持删除操作\n * - 📤 支持上传进度显示\n * - 🎨 支持卡片内部布局控制(align:图标和信息的排列方式)\n *\n * @example\n * // XAdkSender 场景 - 可删除的本地文件\n * {files.map(file => (\n * <FileGallery\n * key={file.id}\n * file={file}\n * removable\n * onRemove={handleRemove}\n * />\n * ))}\n *\n * @example\n * // XadkChatbot 场景 - 只读的远程文件\n * {files.map(file => (\n * <FileGallery key={file.id} file={file} />\n * ))}\n */\nconst FileGallery: React.FC<FileGalleryProps> = ({\n file,\n align = \"left\",\n removable = false,\n onRemove = () => {},\n className,\n style,\n onClick,\n}) => {\n const [objectUrl, setObjectUrl] = useState(\"\");\n\n useEffect(() => {\n if (!file?.file) return;\n\n const url = URL.createObjectURL(file.file);\n setObjectUrl(url);\n\n return () => URL.revokeObjectURL(url);\n }, [file?.file]);\n\n if (!file) return null;\n\n const isImage = isImageFile(file);\n const isAudio = isAudioFile(file);\n const isVideo = isVideoFile(file);\n const isZip = isZipFile(file);\n const isMarkdown = isMarkdownFile(file);\n const fileName = getFileName(file);\n const fileSize = getFileSize(file);\n const fileId = getFileId(file);\n const url = getFileUrl(file) || objectUrl;\n\n // 图片文件\n if (isImage) {\n return (\n <div\n className={`${styles.fileCard} ${align === \"right\" ? \"align-right\" : \"\"} ${className || \"\"}`}\n style={{ ...style, cursor: onClick ? \"pointer\" : undefined }}\n onClick={() => onClick?.(file)}\n >\n {/* 图片缩略图 */}\n <div className={styles.imageThumbnail}>\n <Image\n src={url}\n alt={fileName}\n fallback=\"data:image/png;base64,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\"\n preview={onClick ? false : { src: url }}\n />\n\n {/* 上传进度遮罩 */}\n {file.status === \"uploading\" && (\n <div className={styles.imageOverlay}>\n <Progress\n type=\"circle\"\n percent={file.progress}\n size={30}\n strokeColor=\"#1677ff\"\n />\n </div>\n )}\n </div>\n\n {/* 文件信息 */}\n <div className={styles.fileInfo}>\n <Tooltip title={fileName}>\n <div className={styles.fileName}>\n {fileName.length > 15\n ? `${fileName.substring(0, 15)}...`\n : fileName}\n </div>\n </Tooltip>\n {Number(file?.size) > 0 && (\n <div className={styles.fileSize}>{formatFileSize(fileSize)}</div>\n )}\n </div>\n\n {/* 删除按钮 */}\n {removable && (\n <button\n className={styles.fileRemoveBtn}\n onClick={() => onRemove(fileId)}\n disabled={file.status === \"uploading\"}\n aria-label=\"删除文件\"\n >\n <CloseOutlined />\n </button>\n )}\n </div>\n );\n }\n\n // 音频文件\n if (isAudio) {\n return (\n <div\n className={`${styles.fileCard} ${align === \"right\" ? \"align-right\" : \"\"} ${className || \"\"}`}\n style={style}\n >\n <div className={styles.fileIcon} style={{ color: \"#722ed1\" }}>\n <AudioOutlined />\n </div>\n\n <div className={styles.fileInfo}>\n <Tooltip title={fileName}>\n <div className={styles.fileName}>{fileName}</div>\n </Tooltip>\n\n <audio\n src={url}\n controls\n className={styles.mediaWrapper}\n style={{ width: \"100%\", height: 28 }}\n />\n </div>\n\n {removable && (\n <button\n className={styles.fileRemoveBtn}\n onClick={() => onRemove(fileId)}\n disabled={file.status === \"uploading\"}\n aria-label=\"删除文件\"\n >\n <CloseOutlined />\n </button>\n )}\n </div>\n );\n }\n\n // 视频文件\n if (isVideo) {\n return (\n <div\n className={`${styles.fileCard} ${align === \"right\" ? \"align-right\" : \"\"} ${className || \"\"}`}\n style={style}\n >\n <div className={styles.fileIcon} style={{ color: \"#fa8c16\" }}>\n <VideoCameraOutlined />\n </div>\n\n <div className={styles.fileInfo}>\n <Tooltip title={fileName}>\n <div className={styles.fileName}>{fileName}</div>\n </Tooltip>\n\n <video\n src={url}\n controls\n className={styles.mediaWrapper}\n style={{ width: \"100%\", height: 40 }}\n />\n </div>\n\n {removable && (\n <button\n className={styles.fileRemoveBtn}\n onClick={() => onRemove(fileId)}\n disabled={file.status === \"uploading\"}\n aria-label=\"删除文件\"\n >\n <CloseOutlined />\n </button>\n )}\n </div>\n );\n }\n\n // 其他文件\n const { icon, color } = getFileIcon(file);\n const isExternalUrl = url && url.startsWith(\"http\");\n\n return (\n <div\n className={`${styles.fileCard} ${align === \"right\" ? \"align-right\" : \"\"} ${className || \"\"}`}\n style={{ ...style, cursor: onClick ? \"pointer\" : undefined }}\n onClick={() => onClick?.(file)}\n >\n <div className={styles.fileIcon} style={{ color }}>\n {icon}\n </div>\n\n <div className={styles.fileInfo}>\n {isExternalUrl && !onClick ? (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={styles.fileLink}\n >\n <Tooltip title={fileName}>\n <div className={styles.fileName}>\n {fileName.length > 15\n ? `${fileName.substring(0, 15)}...`\n : fileName}\n </div>\n </Tooltip>\n </a>\n ) : (\n <Tooltip title={fileName}>\n <div className={styles.fileName}>\n {fileName.length > 15\n ? `${fileName.substring(0, 15)}...`\n : fileName}\n </div>\n </Tooltip>\n )}\n\n {file.status === \"uploading\" ? (\n <Progress\n percent={file.progress}\n size=\"small\"\n showInfo={false}\n strokeColor=\"#1677ff\"\n className={styles.progress}\n />\n ) : (\n fileSize > 0 && (\n <div className={styles.fileSize}>{formatFileSize(fileSize)}</div>\n )\n )}\n\n {file.status === \"error\" && file.errorMessage && (\n <div\n style={{\n fontSize: \"11px\",\n color: \"#ff4d4f\",\n marginTop: \"2px\",\n }}\n >\n {file.errorMessage}\n </div>\n )}\n </div>\n\n {removable && (\n <button\n className={styles.fileRemoveBtn}\n onClick={() => onRemove(fileId)}\n disabled={file.status === \"uploading\"}\n aria-label=\"删除文件\"\n >\n <CloseOutlined />\n </button>\n )}\n </div>\n );\n};\n\nexport default FileGallery;\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA2C;AAC3C,kBAAyC;AACzC,mBAYO;AAEP,oBAA0B;AAuHP;AAhHnB,IAAM,cAAc,CAAC,SAA2B;AAC9C,SAAO,KAAK,eAAe,KAAK,QAAQ;AAC1C;AAKA,IAAM,cAAc,CAAC,SAA2B;AAC9C,SAAO,KAAK,QAAQ;AACtB;AAKA,IAAM,cAAc,CAAC,SAA2B;AAC9C,SAAO,KAAK,YAAY,KAAK,QAAQ;AACvC;AAKA,IAAM,aAAa,CAAC,SAA2B;AA5C/C;AA6CE,SACE,KAAK,aACL,UAAK,aAAL,mBAAe,cACf,UAAK,aAAL,mBAAe,YACf,KAAK,WACL;AAEJ;AAKA,IAAM,YAAY,CAAC,SAA2B;AAC5C,SAAO,KAAK,MAAM,KAAK,OAAO;AAChC;AAKA,IAAM,cAAc,CAAC,SAA4B;AAC/C,QAAM,WAAW,YAAY,IAAI;AACjC,MAAI,YAAY,SAAS,WAAW,QAAQ;AAAG,WAAO;AAEtD,QAAM,WAAW,YAAY,IAAI;AACjC,MAAI,YAAY,SAAS,MAAM,qCAAqC;AAClE,WAAO;AAET,QAAM,MAAM,WAAW,IAAI;AAC3B,MAAI,OAAO,IAAI,MAAM,4CAA4C;AAC/D,WAAO;AAET,SAAO;AACT;AAKA,IAAM,cAAc,CAAC,SAA4B;AAC/C,QAAM,WAAW,YAAY,IAAI;AACjC,MAAI,YAAY,SAAS,WAAW,QAAQ;AAAG,WAAO;AAEtD,QAAM,WAAW,YAAY,IAAI;AACjC,SAAO,CAAC,EAAC,qCAAU,MAAM;AAC3B;AAKA,IAAM,cAAc,CAAC,SAA4B;AAC/C,QAAM,WAAW,YAAY,IAAI;AACjC,MAAI,YAAY,SAAS,WAAW,QAAQ;AAAG,WAAO;AAEtD,QAAM,WAAW,YAAY,IAAI;AACjC,SAAO,CAAC,EAAC,qCAAU,MAAM;AAC3B;AAKA,IAAM,YAAY,CAAC,SAA4B;AAC7C,QAAM,WAAW,YAAY,IAAI;AACjC,SAAO,CAAC,EAAC,qCAAU,MAAM;AAC3B;AAKA,IAAM,iBAAiB,CAAC,SAA4B;AAClD,QAAM,WAAW,YAAY,IAAI;AACjC,SAAO,CAAC,EAAC,qCAAU,MAAM;AAC3B;AAKA,IAAM,mBAAmB,CAAC,aAA6B;AACrD,QAAM,MAAM,SAAS,MAAM,GAAG,EAAE,IAAI;AACpC,SAAO,MAAM,IAAI,YAAY,IAAI;AACnC;AAKA,IAAM,cAAc,CAClB,SAC6C;AAC7C,QAAM,MAAM,iBAAiB,YAAY,IAAI,CAAC;AAG9C,MAAI,QAAQ,OAAO;AACjB,WAAO,EAAE,MAAM,4CAAC,gCAAgB,GAAI,OAAO,UAAU;AAAA,EACvD;AAGA,MAAI,CAAC,OAAO,MAAM,EAAE,SAAS,GAAG,GAAG;AACjC,WAAO,EAAE,MAAM,4CAAC,iCAAiB,GAAI,OAAO,UAAU;AAAA,EACxD;AAGA,MAAI,CAAC,OAAO,QAAQ,KAAK,EAAE,SAAS,GAAG,GAAG;AACxC,WAAO,EAAE,MAAM,4CAAC,kCAAkB,GAAI,OAAO,UAAU;AAAA,EACzD;AAGA,MAAI,CAAC,OAAO,MAAM,EAAE,SAAS,GAAG,GAAG;AACjC,WAAO,EAAE,MAAM,4CAAC,gCAAgB,GAAI,OAAO,UAAU;AAAA,EACvD;AAGA,MAAI,CAAC,OAAO,OAAO,OAAO,OAAO,OAAO,MAAM,EAAE,SAAS,GAAG,GAAG;AAC7D,WAAO,EAAE,MAAM,4CAAC,8BAAc,GAAI,OAAO,UAAU;AAAA,EACrD;AAGA,MAAI,CAAC,OAAO,OAAO,QAAQ,OAAO,KAAK,EAAE,SAAS,GAAG,GAAG;AACtD,WAAO,EAAE,MAAM,4CAAC,oCAAoB,GAAI,OAAO,UAAU;AAAA,EAC3D;AAGA,MAAI,CAAC,OAAO,OAAO,MAAM,OAAO,MAAM,OAAO,MAAM,KAAK,EAAE,SAAS,GAAG,GAAG;AACvE,WAAO,EAAE,MAAM,4CAAC,gCAAgB,GAAI,OAAO,UAAU;AAAA,EACvD;AAGA,MAAI,CAAC,MAAM,UAAU,EAAE,SAAS,GAAG,GAAG;AACpC,WAAO,EAAE,MAAM,4CAAC,qCAAqB,GAAI,OAAO,UAAU;AAAA,EAC5D;AAGA,MAAI,YAAY,IAAI,GAAG;AACrB,WAAO,EAAE,MAAM,4CAAC,kCAAkB,GAAI,OAAO,UAAU;AAAA,EACzD;AAGA,SAAO,EAAE,MAAM,4CAAC,6BAAa,GAAI,OAAO,UAAU;AACpD;AAKA,IAAM,iBAAiB,CAAC,UAA0B;AAChD,MAAI,QAAQ;AAAM,WAAO,QAAQ;AACjC,MAAI,QAAQ,OAAO;AAAM,YAAQ,QAAQ,MAAM,QAAQ,CAAC,IAAI;AAC5D,UAAQ,SAAS,OAAO,OAAO,QAAQ,CAAC,IAAI;AAC9C;AAEA,IAAM,aAAS,yBAAU;AAgCzB,IAAM,cAA0C,CAAC;AAAA,EAC/C;AAAA,EACA,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,WAAW,MAAM;AAAA,EAAC;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAS,EAAE;AAE7C,8BAAU,MAAM;AACd,QAAI,EAAC,6BAAM;AAAM;AAEjB,UAAMA,OAAM,IAAI,gBAAgB,KAAK,IAAI;AACzC,iBAAaA,IAAG;AAEhB,WAAO,MAAM,IAAI,gBAAgBA,IAAG;AAAA,EACtC,GAAG,CAAC,6BAAM,IAAI,CAAC;AAEf,MAAI,CAAC;AAAM,WAAO;AAElB,QAAM,UAAU,YAAY,IAAI;AAChC,QAAM,UAAU,YAAY,IAAI;AAChC,QAAM,UAAU,YAAY,IAAI;AAChC,QAAM,QAAQ,UAAU,IAAI;AAC5B,QAAM,aAAa,eAAe,IAAI;AACtC,QAAM,WAAW,YAAY,IAAI;AACjC,QAAM,WAAW,YAAY,IAAI;AACjC,QAAM,SAAS,UAAU,IAAI;AAC7B,QAAM,MAAM,WAAW,IAAI,KAAK;AAGhC,MAAI,SAAS;AACX,WACE;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,GAAG,OAAO,YAAY,UAAU,UAAU,gBAAgB,MAAM,aAAa;AAAA,QACxF,OAAO,EAAE,GAAG,OAAO,QAAQ,UAAU,YAAY,OAAU;AAAA,QAC3D,SAAS,MAAM,mCAAU;AAAA,QAGzB;AAAA,uDAAC,SAAI,WAAW,OAAO,gBACrB;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,KAAK;AAAA,gBACL,KAAK;AAAA,gBACL,UAAS;AAAA,gBACT,SAAS,UAAU,QAAQ,EAAE,KAAK,IAAI;AAAA;AAAA,YACxC;AAAA,YAGC,KAAK,WAAW,eACf,4CAAC,SAAI,WAAW,OAAO,cACrB;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS,KAAK;AAAA,gBACd,MAAM;AAAA,gBACN,aAAY;AAAA;AAAA,YACd,GACF;AAAA,aAEJ;AAAA,UAGA,6CAAC,SAAI,WAAW,OAAO,UACrB;AAAA,wDAAC,uBAAQ,OAAO,UACd,sDAAC,SAAI,WAAW,OAAO,UACpB,mBAAS,SAAS,KACf,GAAG,SAAS,UAAU,GAAG,EAAE,SAC3B,UACN,GACF;AAAA,YACC,OAAO,6BAAM,IAAI,IAAI,KACpB,4CAAC,SAAI,WAAW,OAAO,UAAW,yBAAe,QAAQ,GAAE;AAAA,aAE/D;AAAA,UAGC,aACC;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,OAAO;AAAA,cAClB,SAAS,MAAM,SAAS,MAAM;AAAA,cAC9B,UAAU,KAAK,WAAW;AAAA,cAC1B,cAAW;AAAA,cAEX,sDAAC,8BAAc;AAAA;AAAA,UACjB;AAAA;AAAA;AAAA,IAEJ;AAAA,EAEJ;AAGA,MAAI,SAAS;AACX,WACE;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,GAAG,OAAO,YAAY,UAAU,UAAU,gBAAgB,MAAM,aAAa;AAAA,QACxF;AAAA,QAEA;AAAA,sDAAC,SAAI,WAAW,OAAO,UAAU,OAAO,EAAE,OAAO,UAAU,GACzD,sDAAC,8BAAc,GACjB;AAAA,UAEA,6CAAC,SAAI,WAAW,OAAO,UACrB;AAAA,wDAAC,uBAAQ,OAAO,UACd,sDAAC,SAAI,WAAW,OAAO,UAAW,oBAAS,GAC7C;AAAA,YAEA;AAAA,cAAC;AAAA;AAAA,gBACC,KAAK;AAAA,gBACL,UAAQ;AAAA,gBACR,WAAW,OAAO;AAAA,gBAClB,OAAO,EAAE,OAAO,QAAQ,QAAQ,GAAG;AAAA;AAAA,YACrC;AAAA,aACF;AAAA,UAEC,aACC;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,OAAO;AAAA,cAClB,SAAS,MAAM,SAAS,MAAM;AAAA,cAC9B,UAAU,KAAK,WAAW;AAAA,cAC1B,cAAW;AAAA,cAEX,sDAAC,8BAAc;AAAA;AAAA,UACjB;AAAA;AAAA;AAAA,IAEJ;AAAA,EAEJ;AAGA,MAAI,SAAS;AACX,WACE;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,GAAG,OAAO,YAAY,UAAU,UAAU,gBAAgB,MAAM,aAAa;AAAA,QACxF;AAAA,QAEA;AAAA,sDAAC,SAAI,WAAW,OAAO,UAAU,OAAO,EAAE,OAAO,UAAU,GACzD,sDAAC,oCAAoB,GACvB;AAAA,UAEA,6CAAC,SAAI,WAAW,OAAO,UACrB;AAAA,wDAAC,uBAAQ,OAAO,UACd,sDAAC,SAAI,WAAW,OAAO,UAAW,oBAAS,GAC7C;AAAA,YAEA;AAAA,cAAC;AAAA;AAAA,gBACC,KAAK;AAAA,gBACL,UAAQ;AAAA,gBACR,WAAW,OAAO;AAAA,gBAClB,OAAO,EAAE,OAAO,QAAQ,QAAQ,GAAG;AAAA;AAAA,YACrC;AAAA,aACF;AAAA,UAEC,aACC;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,OAAO;AAAA,cAClB,SAAS,MAAM,SAAS,MAAM;AAAA,cAC9B,UAAU,KAAK,WAAW;AAAA,cAC1B,cAAW;AAAA,cAEX,sDAAC,8BAAc;AAAA;AAAA,UACjB;AAAA;AAAA;AAAA,IAEJ;AAAA,EAEJ;AAGA,QAAM,EAAE,MAAM,MAAM,IAAI,YAAY,IAAI;AACxC,QAAM,gBAAgB,OAAO,IAAI,WAAW,MAAM;AAElD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,GAAG,OAAO,YAAY,UAAU,UAAU,gBAAgB,MAAM,aAAa;AAAA,MACxF,OAAO,EAAE,GAAG,OAAO,QAAQ,UAAU,YAAY,OAAU;AAAA,MAC3D,SAAS,MAAM,mCAAU;AAAA,MAEzB;AAAA,oDAAC,SAAI,WAAW,OAAO,UAAU,OAAO,EAAE,MAAM,GAC7C,gBACH;AAAA,QAEA,6CAAC,SAAI,WAAW,OAAO,UACpB;AAAA,2BAAiB,CAAC,UACjB;AAAA,YAAC;AAAA;AAAA,cACC,MAAM;AAAA,cACN,QAAO;AAAA,cACP,KAAI;AAAA,cACJ,WAAW,OAAO;AAAA,cAElB,sDAAC,uBAAQ,OAAO,UACd,sDAAC,SAAI,WAAW,OAAO,UACpB,mBAAS,SAAS,KACf,GAAG,SAAS,UAAU,GAAG,EAAE,SAC3B,UACN,GACF;AAAA;AAAA,UACF,IAEA,4CAAC,uBAAQ,OAAO,UACd,sDAAC,SAAI,WAAW,OAAO,UACpB,mBAAS,SAAS,KACf,GAAG,SAAS,UAAU,GAAG,EAAE,SAC3B,UACN,GACF;AAAA,UAGD,KAAK,WAAW,cACf;AAAA,YAAC;AAAA;AAAA,cACC,SAAS,KAAK;AAAA,cACd,MAAK;AAAA,cACL,UAAU;AAAA,cACV,aAAY;AAAA,cACZ,WAAW,OAAO;AAAA;AAAA,UACpB,IAEA,WAAW,KACT,4CAAC,SAAI,WAAW,OAAO,UAAW,yBAAe,QAAQ,GAAE;AAAA,UAI9D,KAAK,WAAW,WAAW,KAAK,gBAC/B;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,OAAO;AAAA,gBACP,WAAW;AAAA,cACb;AAAA,cAEC,eAAK;AAAA;AAAA,UACR;AAAA,WAEJ;AAAA,QAEC,aACC;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,OAAO;AAAA,YAClB,SAAS,MAAM,SAAS,MAAM;AAAA,YAC9B,UAAU,KAAK,WAAW;AAAA,YAC1B,cAAW;AAAA,YAEX,sDAAC,8BAAc;AAAA;AAAA,QACjB;AAAA;AAAA;AAAA,EAEJ;AAEJ;AAEA,IAAO,sBAAQ;",
6
6
  "names": ["url"]
7
7
  }
@@ -29,6 +29,12 @@ export interface DirectoryTreeComponentProps {
29
29
  createInfo?: CreateNodeContext | null;
30
30
  /** 开始重命名回调(由父组件注入) */
31
31
  onStartRename?: (fullPath: string, node: FolderTreeData) => void;
32
+ /** 创建节点回调(由父组件注入) */
33
+ onCreateNode?: (parentPath: string, options: {
34
+ type: "file" | "folder";
35
+ defaultName?: string;
36
+ extra?: any;
37
+ }) => void;
32
38
  }
33
39
  declare const DirectoryTreeComponent: React.FC<DirectoryTreeComponentProps>;
34
40
  export default DirectoryTreeComponent;
@@ -106,7 +106,8 @@ var DirectoryTreeComponent = ({
106
106
  onEditConfirm,
107
107
  onEditCancel,
108
108
  createInfo,
109
- onStartRename
109
+ onStartRename,
110
+ onCreateNode
110
111
  }) => {
111
112
  const styles = (0, import_styles.useStyles)();
112
113
  const getIcon = (0, import_react.useCallback)(
@@ -262,7 +263,8 @@ var DirectoryTreeComponent = ({
262
263
  import_antd.Dropdown,
263
264
  {
264
265
  menu: moreActions(node, {
265
- startRename: () => onStartRename == null ? void 0 : onStartRename(fullPath, node)
266
+ startRename: () => onStartRename == null ? void 0 : onStartRename(fullPath, node),
267
+ createNode: (options) => onCreateNode == null ? void 0 : onCreateNode(fullPath, options)
266
268
  }),
267
269
  trigger: ["click"],
268
270
  placement: "bottomRight",
@@ -332,6 +334,7 @@ var DirectoryTreeComponent = ({
332
334
  renderInlineInput,
333
335
  createInfo,
334
336
  onStartRename,
337
+ onCreateNode,
335
338
  dragMode,
336
339
  canDragNode,
337
340
  onDragStart,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/components/FolderTree/DirectoryTree.tsx"],
4
- "sourcesContent": ["import React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} 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?: (value?: string) => void;\n /** 编辑取消回调 */\n onEditCancel?: () => void;\n /** 新建上下文 */\n createInfo?: CreateNodeContext | null;\n /** 开始重命名回调(由父组件注入) */\n onStartRename?: (fullPath: string, node: FolderTreeData) => void;\n}\n\ninterface InlineEditInputProps {\n editKey: string;\n value: string;\n className?: string;\n onValueChange?: (value: string) => void;\n onConfirm?: (value?: string) => void;\n onCancel?: () => void;\n}\n\nconst InlineEditInput: React.FC<InlineEditInputProps> = ({\n editKey,\n value,\n className,\n onValueChange,\n onConfirm,\n onCancel,\n}) => {\n const [draft, setDraft] = useState(value);\n const committedRef = useRef(false);\n\n useEffect(() => {\n setDraft(value);\n committedRef.current = false;\n }, [editKey, value]);\n\n const commit = useCallback(() => {\n if (committedRef.current) return;\n committedRef.current = true;\n onValueChange?.(draft);\n onConfirm?.(draft);\n }, [draft, onConfirm, onValueChange]);\n\n return (\n <Input\n size=\"small\"\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n onBlur={commit}\n onPressEnter={commit}\n onKeyDown={(e) => {\n e.stopPropagation();\n if (e.key === \"Escape\") {\n committedRef.current = true;\n onCancel?.();\n }\n }}\n autoFocus\n className={className}\n onClick={(e) => e.stopPropagation()}\n onMouseDown={(e) => e.stopPropagation()}\n onSelect={(e) => e.stopPropagation()}\n onFocus={(e) => e.stopPropagation()}\n />\n );\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 getIcon = useCallback(\n (node: FolderTreeData) => {\n if (directoryIcons === false || directoryIcons === null) {\n return null;\n }\n if (node.type == \"folder\") {\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 (key: string, value: string) => (\n <span className={styles.treeNodeTitle}>\n <InlineEditInput\n editKey={key}\n value={value}\n className={styles.inlineInput}\n onValueChange={onEditValueChange}\n onConfirm={onEditConfirm}\n onCancel={onEditCancel}\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 {\n onDragStart,\n onDragEnd,\n onItemDragEnter,\n onItemDragOver,\n onItemDragLeave,\n onItemDrop,\n onContainerDragOver,\n onContainerDrop,\n 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: !(node.type === \"folder\"),\n _originalNode: node,\n children: nodeChildren,\n };\n\n // 编辑态:直接渲染 inline input\n if (isEditing) {\n baseNode.title = renderInlineInput(\n editNode!.key,\n editNode!.currentValue,\n );\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={\n draggableDiv ? (e) => onDragStart(e, baseNode) : undefined\n }\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.key, 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\n 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;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} 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?: (value?: string) => void;\n /** 编辑取消回调 */\n onEditCancel?: () => void;\n /** 新建上下文 */\n createInfo?: CreateNodeContext | null;\n /** 开始重命名回调(由父组件注入) */\n onStartRename?: (fullPath: string, node: FolderTreeData) => void;\n /** 创建节点回调(由父组件注入) */\n onCreateNode?: (\n parentPath: string,\n options: { type: \"file\" | \"folder\"; defaultName?: string; extra?: any },\n ) => void;\n}\n\ninterface InlineEditInputProps {\n editKey: string;\n value: string;\n className?: string;\n onValueChange?: (value: string) => void;\n onConfirm?: (value?: string) => void;\n onCancel?: () => void;\n}\n\nconst InlineEditInput: React.FC<InlineEditInputProps> = ({\n editKey,\n value,\n className,\n onValueChange,\n onConfirm,\n onCancel,\n}) => {\n const [draft, setDraft] = useState(value);\n const committedRef = useRef(false);\n\n useEffect(() => {\n setDraft(value);\n committedRef.current = false;\n }, [editKey, value]);\n\n const commit = useCallback(() => {\n if (committedRef.current) return;\n committedRef.current = true;\n onValueChange?.(draft);\n onConfirm?.(draft);\n }, [draft, onConfirm, onValueChange]);\n\n return (\n <Input\n size=\"small\"\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n onBlur={commit}\n onPressEnter={commit}\n onKeyDown={(e) => {\n e.stopPropagation();\n if (e.key === \"Escape\") {\n committedRef.current = true;\n onCancel?.();\n }\n }}\n autoFocus\n className={className}\n onClick={(e) => e.stopPropagation()}\n onMouseDown={(e) => e.stopPropagation()}\n onSelect={(e) => e.stopPropagation()}\n onFocus={(e) => e.stopPropagation()}\n />\n );\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 onCreateNode,\n}) => {\n const styles = useStyles();\n\n const getIcon = useCallback(\n (node: FolderTreeData) => {\n if (directoryIcons === false || directoryIcons === null) {\n return null;\n }\n if (node.type == \"folder\") {\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 (key: string, value: string) => (\n <span className={styles.treeNodeTitle}>\n <InlineEditInput\n editKey={key}\n value={value}\n className={styles.inlineInput}\n onValueChange={onEditValueChange}\n onConfirm={onEditConfirm}\n onCancel={onEditCancel}\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 {\n onDragStart,\n onDragEnd,\n onItemDragEnter,\n onItemDragOver,\n onItemDragLeave,\n onItemDrop,\n onContainerDragOver,\n onContainerDrop,\n 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: !(node.type === \"folder\"),\n _originalNode: node,\n children: nodeChildren,\n };\n\n // 编辑态:直接渲染 inline input\n if (isEditing) {\n baseNode.title = renderInlineInput(\n editNode!.key,\n editNode!.currentValue,\n );\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 createNode: (options) => onCreateNode?.(fullPath, options),\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={\n draggableDiv ? (e) => onDragStart(e, baseNode) : undefined\n }\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.key, 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 onCreateNode,\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\n 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;\n"],
5
+ "mappings": "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",
6
6
  "names": ["clsx"]
7
7
  }
@@ -283,37 +283,37 @@ var FolderTree = (0, import_react.forwardRef)((props, ref) => {
283
283
  }
284
284
  onExpandedPathsChange == null ? void 0 : onExpandedPathsChange(newPaths);
285
285
  };
286
- (0, import_react.useImperativeHandle)(
287
- ref,
288
- () => ({
289
- createNode: (parentPath, options) => {
290
- const defaultName = options.defaultName || (options.type === "folder" ? "新建文件夹" : "新建文件");
291
- const tempKey = `__create__${parentPath || "root"}__${Date.now()}`;
292
- setCreateContext({
293
- parentKey: parentPath,
294
- type: options.type,
295
- extra: options.extra
296
- });
297
- setEditNode({
298
- key: tempKey,
299
- type: options.type || "folder",
300
- originalTitle: "",
301
- currentValue: defaultName,
302
- mode: "create"
286
+ const internalCreateNode = (0, import_react.useCallback)(
287
+ (parentPath, options) => {
288
+ const defaultName = options.defaultName || (options.type === "folder" ? "新建文件夹" : "新建文件");
289
+ const tempKey = `__create__${parentPath || "root"}__${Date.now()}`;
290
+ setCreateContext({
291
+ parentKey: parentPath,
292
+ type: options.type,
293
+ extra: options.extra
294
+ });
295
+ setEditNode({
296
+ key: tempKey,
297
+ type: options.type || "folder",
298
+ originalTitle: "",
299
+ currentValue: defaultName,
300
+ mode: "create"
301
+ });
302
+ if (!controlled && parentPath && parentPath !== "/") {
303
+ setExpandedPathsState((prev) => {
304
+ const current = prev || [];
305
+ if (current.includes(parentPath)) {
306
+ return current;
307
+ }
308
+ return [...current, parentPath];
303
309
  });
304
- if (!controlled && parentPath && parentPath !== "/") {
305
- setExpandedPathsState((prev) => {
306
- const current = prev || [];
307
- if (current.includes(parentPath)) {
308
- return current;
309
- }
310
- return [...current, parentPath];
311
- });
312
- }
313
310
  }
314
- }),
311
+ },
315
312
  [controlled]
316
313
  );
314
+ (0, import_react.useImperativeHandle)(ref, () => ({ createNode: internalCreateNode }), [
315
+ internalCreateNode
316
+ ]);
317
317
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
318
318
  "div",
319
319
  {
@@ -354,6 +354,7 @@ var FolderTree = (0, import_react.forwardRef)((props, ref) => {
354
354
  onEditCancel: handleEditCancel,
355
355
  createInfo: createContext,
356
356
  onStartRename: handleStartRename,
357
+ onCreateNode: internalCreateNode,
357
358
  onDrop
358
359
  }
359
360
  ),
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/components/FolderTree/index.tsx"],
4
- "sourcesContent": ["import React, {\n useRef,\n useMemo,\n useCallback,\n useEffect,\n useState,\n forwardRef,\n useImperativeHandle,\n} from \"react\";\nimport type { TreeProps } from \"antd\";\nimport clsx from \"clsx\";\nimport type {\n FolderTreeData,\n FolderTreeProps,\n FolderTreeRef,\n EditNodeInfo,\n CreateNodeContext,\n} from \"./types\";\nimport DirectoryTreeComponent from \"./DirectoryTree\";\nimport FilePreview from \"./FilePreview\";\nimport { useStyles } from \"./styles\";\n\nexport type {\n FolderTreeData,\n FolderTreeProps,\n FileContentService,\n FolderTreeRef,\n} from \"./types\";\n\n// 展开所有节点\nfunction getAllExpandedKeys(\n nodes: FolderTreeData[],\n parentPath = \"\",\n): string[] {\n const keys: string[] = [];\n\n nodes.forEach((node) => {\n const currentPath = parentPath ? `${parentPath}/${node.path}` : node.path;\n\n if (node.children?.length) {\n keys.push(currentPath);\n keys.push(...getAllExpandedKeys(node.children, currentPath));\n }\n });\n\n return keys;\n}\n\n// 格式化数据\nfunction normalizeTreeData(nodes: FolderTreeData[]): FolderTreeData[] {\n return nodes.map((node) => ({\n ...node,\n type: node.type\n ? node.type\n : !!node.children && node.children.length > 0\n ? \"folder\"\n : \"file\",\n children: node.children ? normalizeTreeData(node.children) : undefined,\n }));\n}\n\nconst FolderTree = forwardRef<FolderTreeRef, FolderTreeProps>((props, ref) => {\n const {\n className,\n style,\n treeData,\n directoryIcons,\n previewRender,\n directoryTitle,\n previewTitle,\n selectable = true,\n defaultSelectedFile,\n defaultExpandAll = true,\n selectedFile,\n onSelectedFileChange,\n directoryTreeWidth = 280,\n emptyRender,\n defaultExpandedPaths,\n expandedPaths,\n onExpandedPathsChange,\n onFileClick,\n onFolderClick,\n fileContentService,\n moreActions,\n showLine,\n switcherIcon,\n showPreview = true,\n draggable,\n onDrop,\n onRename,\n onCreate,\n } = props;\n\n const styles = useStyles();\n\n const normalizedTreeData = useMemo(\n () => normalizeTreeData(treeData),\n [treeData],\n );\n\n // ====== 编辑态状态 ======\n const [editNode, setEditNode] = useState<EditNodeInfo | null>(null);\n const [createContext, setCreateContext] = useState<CreateNodeContext | null>(\n null,\n );\n\n // ====== 工具函数 ======\n const findNodeAndValidate = useCallback(\n (\n path: string | string[],\n validateAsFile = false,\n ): { node: FolderTreeData | undefined; isValid: boolean } => {\n if (!path) return { node: undefined, isValid: false };\n const segments = Array.isArray(path)\n ? path.filter(Boolean)\n : path.split(\"/\").filter(Boolean);\n if (segments.length === 0) return { node: undefined, isValid: false };\n\n const findNode = (\n nodes: FolderTreeData[],\n index = 0,\n ): FolderTreeData | undefined => {\n if (index >= segments.length) return undefined;\n const currentSegment = segments[index];\n for (const node of nodes) {\n if (node.path === currentSegment) {\n return index === segments.length - 1\n ? node\n : node.children\n ? findNode(node.children, index + 1)\n : undefined;\n }\n }\n return undefined;\n };\n\n const node = findNode(normalizedTreeData);\n const isValid = validateAsFile\n ? !!node && (!node?.children || node.children.length === 0)\n : !!node;\n return { node, isValid };\n },\n [normalizedTreeData],\n );\n\n const isValidSelectedFile = (filePath?: string[]): boolean =>\n !!(\n filePath &&\n filePath.length > 0 &&\n findNodeAndValidate(filePath, true).isValid\n );\n\n // ====== 编辑态逻辑 ======\n\n // 当 normalizedTreeData 变化时,检查编辑节点是否还存在\n useEffect(() => {\n if (!editNode) return;\n const { node } = findNodeAndValidate(editNode.key);\n if (!node) {\n setEditNode(null);\n setCreateContext(null);\n }\n }, [normalizedTreeData]);\n\n // 编辑值变化\n const handleEditValueChange = useCallback((value: string) => {\n setEditNode((prev) => (prev ? { ...prev, currentValue: value } : null));\n }, []);\n\n // 确认编辑\n const handleEditConfirm = useCallback((value?: string) => {\n if (!editNode) return;\n const newValue = (value ?? editNode.currentValue).trim();\n\n if (editNode.mode === \"rename\") {\n const { node } = findNodeAndValidate(editNode.key);\n onRename?.({\n key: editNode.key,\n oldTitle: editNode.originalTitle,\n newTitle: newValue,\n node: node!,\n });\n } else if (editNode.mode === \"create\" && createContext) {\n onCreate?.({\n parentKey: createContext.parentKey,\n name: newValue,\n type: createContext.type,\n extra: createContext.extra,\n });\n }\n\n setEditNode(null);\n setCreateContext(null);\n }, [editNode, createContext, findNodeAndValidate, onRename, onCreate]);\n\n // 取消编辑\n const handleEditCancel = useCallback(() => {\n setEditNode(null);\n setCreateContext(null);\n }, []);\n\n // 开始重命名\n const handleStartRename = useCallback(\n (fullPath: string, node: FolderTreeData) => {\n const titleStr =\n typeof node.title === \"string\" ? node.title : String(node.path);\n setCreateContext(null);\n setEditNode({\n key: fullPath,\n type: node.type || \"file\",\n originalTitle: titleStr,\n currentValue: titleStr,\n mode: \"rename\",\n });\n },\n [],\n );\n\n // ====== State ======\n const [selectedFileState, setSelectedFileState] = useState<string[]>(() =>\n isValidSelectedFile(selectedFile || defaultSelectedFile)\n ? selectedFile || defaultSelectedFile || []\n : [],\n );\n const controlled = expandedPaths !== undefined;\n\n const [expandedPathsState, setExpandedPathsState] = useState<string[]>(\n defaultExpandedPaths || [],\n );\n const [validSelectedFile, setValidSelectedFile] = useState<boolean>(\n isValidSelectedFile(selectedFile || defaultSelectedFile),\n );\n const [fileContent, setFileContent] = useState<string>(\"\");\n const [loadingContent, setLoadingContent] = useState<boolean>(false);\n const initializedExpandRef = useRef(false);\n\n // 受控模式同步\n useEffect(() => {\n if (selectedFile !== undefined) {\n setSelectedFileState(selectedFile);\n setValidSelectedFile(isValidSelectedFile(selectedFile));\n }\n }, [selectedFile, isValidSelectedFile]);\n\n useEffect(() => {\n if (\n !controlled &&\n defaultExpandAll &&\n !initializedExpandRef.current &&\n normalizedTreeData.length > 0\n ) {\n initializedExpandRef.current = true;\n\n setExpandedPathsState(getAllExpandedKeys(normalizedTreeData));\n }\n }, [controlled, defaultExpandAll, normalizedTreeData]);\n\n useEffect(() => {\n if (controlled) {\n setExpandedPathsState(expandedPaths);\n }\n }, [controlled, expandedPaths]);\n\n // ====== 加载文件内容 ======\n useEffect(() => {\n const loadContent = async () => {\n if (!validSelectedFile || selectedFileState.length === 0) {\n setFileContent(\"\");\n setLoadingContent(false);\n return;\n }\n\n const filePath = selectedFileState.join(\"/\");\n const segments = filePath.split(\"/\").filter((s) => s !== \"\");\n const { node } = findNodeAndValidate(segments);\n\n if (fileContentService) {\n setLoadingContent(true);\n try {\n const content = await fileContentService.loadFileContent(filePath);\n setFileContent(content);\n } catch (error) {\n setFileContent(\n `// 加载错误: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`,\n );\n } finally {\n setLoadingContent(false);\n }\n } else if (node?.content) {\n setFileContent(node.content);\n setLoadingContent(false);\n } else {\n setFileContent(\"\");\n setLoadingContent(false);\n }\n };\n\n loadContent();\n }, [\n validSelectedFile,\n selectedFileState,\n normalizedTreeData,\n fileContentService,\n findNodeAndValidate,\n ]);\n\n // ====== 事件处理 ======\n const handleSelect: TreeProps[\"onSelect\"] = (_keys, info) => {\n const keys = _keys as string[];\n const nodes = Array.isArray(info.selectedNodes)\n ? info.selectedNodes\n : [info.selectedNodes];\n\n const isFolder = nodes.some((node) => !node.isLeaf);\n if (isFolder) {\n if (nodes.length === 1) {\n const node = nodes[0] as unknown as FolderTreeData;\n onFolderClick?.(node.path, node.extra);\n }\n return;\n }\n\n const pathArray = keys[0]?.split(\"/\").filter(Boolean) || [];\n if (pathArray.length === 0) return;\n\n // 从原始 normalizedTreeData 中查找节点,避免拿到 antd 包装后的 JSX title\n const { node: originalNode } = findNodeAndValidate(pathArray);\n const fileName = originalNode?.title;\n const nodeContent = originalNode?.content;\n\n onSelectedFileChange?.({\n path: pathArray,\n title: fileName,\n content: nodeContent,\n extra: originalNode?.extra,\n });\n\n const isControlled = selectedFile !== undefined;\n if (!isControlled) {\n setValidSelectedFile(true);\n setSelectedFileState(pathArray);\n }\n\n if (originalNode) {\n onFileClick?.(keys[0], originalNode.content, originalNode.extra);\n }\n };\n\n const handleExpand: TreeProps[\"onExpand\"] = (keys) => {\n const newPaths = keys as string[];\n\n if (!controlled) {\n setExpandedPathsState(newPaths);\n }\n\n onExpandedPathsChange?.(newPaths);\n };\n\n // ====== 命令式 API ======\n useImperativeHandle(\n ref,\n () => ({\n createNode: (parentPath, options) => {\n const defaultName =\n options.defaultName ||\n (options.type === \"folder\" ? \"新建文件夹\" : \"新建文件\");\n const tempKey = `__create__${parentPath || \"root\"}__${Date.now()}`;\n\n setCreateContext({\n parentKey: parentPath,\n type: options.type,\n extra: options.extra,\n });\n setEditNode({\n key: tempKey,\n type: options.type || \"folder\",\n originalTitle: \"\",\n currentValue: defaultName,\n mode: \"create\",\n });\n\n // 自动展开父文件夹(仅在受控模式下需要,非受控模式由 defaultExpandAll 处理)\n if (!controlled && parentPath && parentPath !== \"/\") {\n setExpandedPathsState((prev) => {\n const current = prev || [];\n\n if (current.includes(parentPath)) {\n return current;\n }\n\n return [...current, parentPath];\n });\n }\n },\n }),\n [controlled],\n );\n\n return (\n <div\n className={clsx(\n styles.container,\n !showPreview && styles.containerNoPreview,\n className,\n )}\n style={{\n ...style,\n ...(style?.background\n ? ({\n \"--folder-tree-directory-bg\": style.background,\n } as React.CSSProperties)\n : {}),\n ...(style?.backgroundColor\n ? ({\n \"--folder-tree-directory-bg\": style.backgroundColor,\n } as React.CSSProperties)\n : {}),\n }}\n >\n <DirectoryTreeComponent\n treeData={normalizedTreeData}\n directoryIcons={directoryIcons}\n selectedKeys={\n selectable && selectedFileState && validSelectedFile\n ? [selectedFileState.join(\"/\")]\n : []\n }\n expandedKeys={controlled ? expandedPaths : expandedPathsState}\n onSelect={handleSelect}\n onExpand={handleExpand}\n defaultExpandAll={defaultExpandAll}\n directoryTitle={directoryTitle}\n moreActions={moreActions}\n showLine={showLine}\n switcherIcon={switcherIcon}\n width={directoryTreeWidth}\n draggable={draggable}\n editNode={editNode}\n onEditValueChange={handleEditValueChange}\n onEditConfirm={handleEditConfirm}\n onEditCancel={handleEditCancel}\n createInfo={createContext}\n onStartRename={handleStartRename}\n onDrop={onDrop}\n />\n {showPreview && (\n <FilePreview\n selectedFile={validSelectedFile ? selectedFileState : []}\n fileContent={fileContent}\n loading={loadingContent}\n previewTitle={previewTitle}\n previewRender={previewRender}\n emptyRender={emptyRender}\n getFileNode={(path) => {\n if (!path || path.length === 0) return undefined;\n const { node } = findNodeAndValidate(path);\n return node\n ? { title: node.title, path: node.path, content: node.content }\n : undefined;\n }}\n />\n )}\n </div>\n );\n});\n\nFolderTree.displayName = \"FolderTree\";\n\nexport default FolderTree;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import React, {\n useRef,\n useMemo,\n useCallback,\n useEffect,\n useState,\n forwardRef,\n useImperativeHandle,\n} from \"react\";\nimport type { TreeProps } from \"antd\";\nimport clsx from \"clsx\";\nimport type {\n FolderTreeData,\n FolderTreeProps,\n FolderTreeRef,\n EditNodeInfo,\n CreateNodeContext,\n} from \"./types\";\nimport DirectoryTreeComponent from \"./DirectoryTree\";\nimport FilePreview from \"./FilePreview\";\nimport { useStyles } from \"./styles\";\n\nexport type {\n FolderTreeData,\n FolderTreeProps,\n FileContentService,\n FolderTreeRef,\n} from \"./types\";\n\n// 展开所有节点\nfunction getAllExpandedKeys(\n nodes: FolderTreeData[],\n parentPath = \"\",\n): string[] {\n const keys: string[] = [];\n\n nodes.forEach((node) => {\n const currentPath = parentPath ? `${parentPath}/${node.path}` : node.path;\n\n if (node.children?.length) {\n keys.push(currentPath);\n keys.push(...getAllExpandedKeys(node.children, currentPath));\n }\n });\n\n return keys;\n}\n\n// 格式化数据\nfunction normalizeTreeData(nodes: FolderTreeData[]): FolderTreeData[] {\n return nodes.map((node) => ({\n ...node,\n type: node.type\n ? node.type\n : !!node.children && node.children.length > 0\n ? \"folder\"\n : \"file\",\n children: node.children ? normalizeTreeData(node.children) : undefined,\n }));\n}\n\nconst FolderTree = forwardRef<FolderTreeRef, FolderTreeProps>((props, ref) => {\n const {\n className,\n style,\n treeData,\n directoryIcons,\n previewRender,\n directoryTitle,\n previewTitle,\n selectable = true,\n defaultSelectedFile,\n defaultExpandAll = true,\n selectedFile,\n onSelectedFileChange,\n directoryTreeWidth = 280,\n emptyRender,\n defaultExpandedPaths,\n expandedPaths,\n onExpandedPathsChange,\n onFileClick,\n onFolderClick,\n fileContentService,\n moreActions,\n showLine,\n switcherIcon,\n showPreview = true,\n draggable,\n onDrop,\n onRename,\n onCreate,\n } = props;\n\n const styles = useStyles();\n\n const normalizedTreeData = useMemo(\n () => normalizeTreeData(treeData),\n [treeData],\n );\n\n // ====== 编辑态状态 ======\n const [editNode, setEditNode] = useState<EditNodeInfo | null>(null);\n const [createContext, setCreateContext] = useState<CreateNodeContext | null>(\n null,\n );\n\n // ====== 工具函数 ======\n const findNodeAndValidate = useCallback(\n (\n path: string | string[],\n validateAsFile = false,\n ): { node: FolderTreeData | undefined; isValid: boolean } => {\n if (!path) return { node: undefined, isValid: false };\n const segments = Array.isArray(path)\n ? path.filter(Boolean)\n : path.split(\"/\").filter(Boolean);\n if (segments.length === 0) return { node: undefined, isValid: false };\n\n const findNode = (\n nodes: FolderTreeData[],\n index = 0,\n ): FolderTreeData | undefined => {\n if (index >= segments.length) return undefined;\n const currentSegment = segments[index];\n for (const node of nodes) {\n if (node.path === currentSegment) {\n return index === segments.length - 1\n ? node\n : node.children\n ? findNode(node.children, index + 1)\n : undefined;\n }\n }\n return undefined;\n };\n\n const node = findNode(normalizedTreeData);\n const isValid = validateAsFile\n ? !!node && (!node?.children || node.children.length === 0)\n : !!node;\n return { node, isValid };\n },\n [normalizedTreeData],\n );\n\n const isValidSelectedFile = (filePath?: string[]): boolean =>\n !!(\n filePath &&\n filePath.length > 0 &&\n findNodeAndValidate(filePath, true).isValid\n );\n\n // ====== 编辑态逻辑 ======\n\n // 当 normalizedTreeData 变化时,检查编辑节点是否还存在\n useEffect(() => {\n if (!editNode) return;\n const { node } = findNodeAndValidate(editNode.key);\n if (!node) {\n setEditNode(null);\n setCreateContext(null);\n }\n }, [normalizedTreeData]);\n\n // 编辑值变化\n const handleEditValueChange = useCallback((value: string) => {\n setEditNode((prev) => (prev ? { ...prev, currentValue: value } : null));\n }, []);\n\n // 确认编辑\n const handleEditConfirm = useCallback((value?: string) => {\n if (!editNode) return;\n const newValue = (value ?? editNode.currentValue).trim();\n\n if (editNode.mode === \"rename\") {\n const { node } = findNodeAndValidate(editNode.key);\n onRename?.({\n key: editNode.key,\n oldTitle: editNode.originalTitle,\n newTitle: newValue,\n node: node!,\n });\n } else if (editNode.mode === \"create\" && createContext) {\n onCreate?.({\n parentKey: createContext.parentKey,\n name: newValue,\n type: createContext.type,\n extra: createContext.extra,\n });\n }\n\n setEditNode(null);\n setCreateContext(null);\n }, [editNode, createContext, findNodeAndValidate, onRename, onCreate]);\n\n // 取消编辑\n const handleEditCancel = useCallback(() => {\n setEditNode(null);\n setCreateContext(null);\n }, []);\n\n // 开始重命名\n const handleStartRename = useCallback(\n (fullPath: string, node: FolderTreeData) => {\n const titleStr =\n typeof node.title === \"string\" ? node.title : String(node.path);\n setCreateContext(null);\n setEditNode({\n key: fullPath,\n type: node.type || \"file\",\n originalTitle: titleStr,\n currentValue: titleStr,\n mode: \"rename\",\n });\n },\n [],\n );\n\n // ====== State ======\n const [selectedFileState, setSelectedFileState] = useState<string[]>(() =>\n isValidSelectedFile(selectedFile || defaultSelectedFile)\n ? selectedFile || defaultSelectedFile || []\n : [],\n );\n const controlled = expandedPaths !== undefined;\n\n const [expandedPathsState, setExpandedPathsState] = useState<string[]>(\n defaultExpandedPaths || [],\n );\n const [validSelectedFile, setValidSelectedFile] = useState<boolean>(\n isValidSelectedFile(selectedFile || defaultSelectedFile),\n );\n const [fileContent, setFileContent] = useState<string>(\"\");\n const [loadingContent, setLoadingContent] = useState<boolean>(false);\n const initializedExpandRef = useRef(false);\n\n // 受控模式同步\n useEffect(() => {\n if (selectedFile !== undefined) {\n setSelectedFileState(selectedFile);\n setValidSelectedFile(isValidSelectedFile(selectedFile));\n }\n }, [selectedFile, isValidSelectedFile]);\n\n useEffect(() => {\n if (\n !controlled &&\n defaultExpandAll &&\n !initializedExpandRef.current &&\n normalizedTreeData.length > 0\n ) {\n initializedExpandRef.current = true;\n\n setExpandedPathsState(getAllExpandedKeys(normalizedTreeData));\n }\n }, [controlled, defaultExpandAll, normalizedTreeData]);\n\n useEffect(() => {\n if (controlled) {\n setExpandedPathsState(expandedPaths);\n }\n }, [controlled, expandedPaths]);\n\n // ====== 加载文件内容 ======\n useEffect(() => {\n const loadContent = async () => {\n if (!validSelectedFile || selectedFileState.length === 0) {\n setFileContent(\"\");\n setLoadingContent(false);\n return;\n }\n\n const filePath = selectedFileState.join(\"/\");\n const segments = filePath.split(\"/\").filter((s) => s !== \"\");\n const { node } = findNodeAndValidate(segments);\n\n if (fileContentService) {\n setLoadingContent(true);\n try {\n const content = await fileContentService.loadFileContent(filePath);\n setFileContent(content);\n } catch (error) {\n setFileContent(\n `// 加载错误: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`,\n );\n } finally {\n setLoadingContent(false);\n }\n } else if (node?.content) {\n setFileContent(node.content);\n setLoadingContent(false);\n } else {\n setFileContent(\"\");\n setLoadingContent(false);\n }\n };\n\n loadContent();\n }, [\n validSelectedFile,\n selectedFileState,\n normalizedTreeData,\n fileContentService,\n findNodeAndValidate,\n ]);\n\n // ====== 事件处理 ======\n const handleSelect: TreeProps[\"onSelect\"] = (_keys, info) => {\n const keys = _keys as string[];\n const nodes = Array.isArray(info.selectedNodes)\n ? info.selectedNodes\n : [info.selectedNodes];\n\n const isFolder = nodes.some((node) => !node.isLeaf);\n if (isFolder) {\n if (nodes.length === 1) {\n const node = nodes[0] as unknown as FolderTreeData;\n onFolderClick?.(node.path, node.extra);\n }\n return;\n }\n\n const pathArray = keys[0]?.split(\"/\").filter(Boolean) || [];\n if (pathArray.length === 0) return;\n\n // 从原始 normalizedTreeData 中查找节点,避免拿到 antd 包装后的 JSX title\n const { node: originalNode } = findNodeAndValidate(pathArray);\n const fileName = originalNode?.title;\n const nodeContent = originalNode?.content;\n\n onSelectedFileChange?.({\n path: pathArray,\n title: fileName,\n content: nodeContent,\n extra: originalNode?.extra,\n });\n\n const isControlled = selectedFile !== undefined;\n if (!isControlled) {\n setValidSelectedFile(true);\n setSelectedFileState(pathArray);\n }\n\n if (originalNode) {\n onFileClick?.(keys[0], originalNode.content, originalNode.extra);\n }\n };\n\n const handleExpand: TreeProps[\"onExpand\"] = (keys) => {\n const newPaths = keys as string[];\n\n if (!controlled) {\n setExpandedPathsState(newPaths);\n }\n\n onExpandedPathsChange?.(newPaths);\n };\n\n // ====== 创建节点核心逻辑(供命令式 API 和 moreActions 共享) ======\n const internalCreateNode = useCallback(\n (\n parentPath: string,\n options: { type: \"file\" | \"folder\"; defaultName?: string; extra?: any },\n ) => {\n const defaultName =\n options.defaultName ||\n (options.type === \"folder\" ? \"新建文件夹\" : \"新建文件\");\n const tempKey = `__create__${parentPath || \"root\"}__${Date.now()}`;\n\n setCreateContext({\n parentKey: parentPath,\n type: options.type,\n extra: options.extra,\n });\n setEditNode({\n key: tempKey,\n type: options.type || \"folder\",\n originalTitle: \"\",\n currentValue: defaultName,\n mode: \"create\",\n });\n\n // 自动展开父文件夹(仅在受控模式下需要,非受控模式由 defaultExpandAll 处理)\n if (!controlled && parentPath && parentPath !== \"/\") {\n setExpandedPathsState((prev) => {\n const current = prev || [];\n\n if (current.includes(parentPath)) {\n return current;\n }\n\n return [...current, parentPath];\n });\n }\n },\n [controlled],\n );\n\n // ====== 命令式 API ======\n useImperativeHandle(ref, () => ({ createNode: internalCreateNode }), [\n internalCreateNode,\n ]);\n\n return (\n <div\n className={clsx(\n styles.container,\n !showPreview && styles.containerNoPreview,\n className,\n )}\n style={{\n ...style,\n ...(style?.background\n ? ({\n \"--folder-tree-directory-bg\": style.background,\n } as React.CSSProperties)\n : {}),\n ...(style?.backgroundColor\n ? ({\n \"--folder-tree-directory-bg\": style.backgroundColor,\n } as React.CSSProperties)\n : {}),\n }}\n >\n <DirectoryTreeComponent\n treeData={normalizedTreeData}\n directoryIcons={directoryIcons}\n selectedKeys={\n selectable && selectedFileState && validSelectedFile\n ? [selectedFileState.join(\"/\")]\n : []\n }\n expandedKeys={controlled ? expandedPaths : expandedPathsState}\n onSelect={handleSelect}\n onExpand={handleExpand}\n defaultExpandAll={defaultExpandAll}\n directoryTitle={directoryTitle}\n moreActions={moreActions}\n showLine={showLine}\n switcherIcon={switcherIcon}\n width={directoryTreeWidth}\n draggable={draggable}\n editNode={editNode}\n onEditValueChange={handleEditValueChange}\n onEditConfirm={handleEditConfirm}\n onEditCancel={handleEditCancel}\n createInfo={createContext}\n onStartRename={handleStartRename}\n onCreateNode={internalCreateNode}\n onDrop={onDrop}\n />\n {showPreview && (\n <FilePreview\n selectedFile={validSelectedFile ? selectedFileState : []}\n fileContent={fileContent}\n loading={loadingContent}\n previewTitle={previewTitle}\n previewRender={previewRender}\n emptyRender={emptyRender}\n getFileNode={(path) => {\n if (!path || path.length === 0) return undefined;\n const { node } = findNodeAndValidate(path);\n return node\n ? { title: node.title, path: node.path, content: node.content }\n : undefined;\n }}\n />\n )}\n </div>\n );\n});\n\nFolderTree.displayName = \"FolderTree\";\n\nexport default FolderTree;\n"],
5
+ "mappings": "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",
6
6
  "names": ["node", "clsx", "DirectoryTreeComponent", "FilePreview"]
7
7
  }
@@ -125,7 +125,7 @@ var useStyles = (0, import_common.withBasicStyles)(() => ({
125
125
  z-index: 10;
126
126
  pointer-events: none;
127
127
  }
128
- `,
128
+ `,
129
129
  /** 自定义拖拽 - 节点可拖拽样式 */
130
130
  dragNodeHandle: import_css.css`
131
131
  cursor: grab;
@@ -199,7 +199,10 @@ var useStyles = (0, import_common.withBasicStyles)(() => ({
199
199
  margin: 2px;
200
200
  color: #999;
201
201
  font-size: 12px;
202
+ line-height: 20px;
202
203
  transition: all 0.2s;
204
+ height: 20px;
205
+ box-sizing: border-box;
203
206
 
204
207
  &:hover {
205
208
  border-radius: 50%;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/components/FolderTree/styles.tsx"],
4
- "sourcesContent": ["import { css } from \"@emotion/css\";\nimport { withBasicStyles } from \"@/styles/common\";\n\nexport const useStyles = withBasicStyles(() => ({\n container: css`\n display: flex;\n width: 100%;\n height: 500px;\n border: 1px solid #e8e8e8;\n border-radius: 8px;\n overflow: hidden;\n background: #fff;\n `,\n containerNoPreview: css`\n height: auto;\n border: none;\n border-radius: 0;\n & > *:first-child {\n border-right: none;\n }\n `,\n directoryPanel: css`\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: auto;\n border-right: 1px solid #e8e8e8;\n background: var(--folder-tree-directory-bg, #fafafa);\n `,\n directoryTitle: css`\n padding: 12px 16px;\n font-weight: 600;\n font-size: 14px;\n border-bottom: 1px solid #e8e8e8;\n color: #333;\n `,\n directoryTreeContent: css`\n padding: 4px 8px;\n flex: 1;\n\n .ant-tree {\n background: transparent;\n height: 100%;\n }\n .ant-tree-switcher {\n margin-right: 0;\n }\n .ant-tree .ant-tree-node-content-wrapper {\n display: inline-flex;\n align-items: center;\n flex: 1;\n min-width: 0;\n padding-left: 0;\n overflow: hidden;\n }\n .ant-tree .ant-tree-title {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n }\n .ant-tree-directory .ant-tree-treenode {\n position: relative;\n &::before {\n border-radius: 4px;\n }\n }\n /* 自定义拖拽样式 — 基于 ant-tree-treenode 定位,覆盖整行 */\n .ant-tree-treenode.folder-tree-drop-before::after {\n content: \"\";\n position: absolute;\n top: -2px;\n left: 0;\n right: 0;\n height: 2px;\n background: transparent;\n border-top: 2px dashed #1677ff;\n z-index: 10;\n pointer-events: none;\n }\n .ant-tree-treenode.folder-tree-drop-inside::after {\n content: \"\";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 2px dashed #1677ff;\n border-radius: 4px;\n background: rgba(22, 119, 255, 0.04);\n z-index: 10;\n pointer-events: none;\n }\n .ant-tree-treenode.folder-tree-drop-after::after {\n content: \"\";\n position: absolute;\n bottom: -2px;\n left: 0;\n right: 0;\n height: 2px;\n background: transparent;\n border-bottom: 2px dashed #1677ff;\n z-index: 10;\n pointer-events: none;\n }\n `,\n\n /** 自定义拖拽 - 节点可拖拽样式 */\n dragNodeHandle: css`\n cursor: grab;\n user-select: none;\n\n &:active {\n cursor: grabbing;\n }\n `,\n /** 树节点容器,用于相对定位 drop indicator */\n treeNodeWrapper: css`\n position: relative;\n min-width: 0;\n overflow: hidden;\n `,\n previewPanel: css`\n flex: 1;\n height: 100%;\n overflow: auto;\n display: flex;\n flex-direction: column;\n `,\n previewTitle: css`\n padding: 10px 16px;\n font-size: 13px;\n font-weight: 500;\n border-bottom: 1px solid #e8e8e8;\n display: flex;\n align-items: center;\n justify-content: space-between;\n color: #333;\n background: #fff;\n `,\n previewContent: css`\n flex: 1;\n overflow: auto;\n padding: 16px;\n font-size: 13px;\n line-height: 1.6;\n `,\n emptyContainer: css`\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n `,\n loadingContainer: css`\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n `,\n treeNodeTitle: css`\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-width: 0;\n overflow: hidden;\n padding-right: 4px;\n\n > span:first-child {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n `,\n moreIcon: css`\n opacity: 0;\n cursor: pointer;\n padding: 0 4px;\n margin: 2px;\n color: #999;\n font-size: 12px;\n transition: all 0.2s;\n\n &:hover {\n border-radius: 50%;\n color: #333;\n background: rgba(0, 0, 0, 0.04);\n }\n `,\n treeNodeTitleHover: css`\n &:hover .folder-tree-more-icon {\n opacity: 1;\n }\n `,\n inlineInput: css`\n width: 100%;\n .ant-input {\n height: 22px;\n font-size: 13px;\n padding: 0 6px;\n border-radius: 4px;\n }\n `,\n copyBtn: css`\n cursor: pointer;\n color: #999;\n font-size: 14px;\n &:hover {\n color: #1677ff;\n }\n `,\n}));\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAoB;AACpB,oBAAgC;AAEzB,IAAM,gBAAY,+BAAgB,OAAO;AAAA,EAC9C,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASX,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQpB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOhB,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuEtB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAShB,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKjB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOd,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWd,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOhB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhB,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlB,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcf,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeV,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKpB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASb,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQX,EAAE;",
4
+ "sourcesContent": ["import { css } from \"@emotion/css\";\nimport { withBasicStyles } from \"@/styles/common\";\n\nexport const useStyles = withBasicStyles(() => ({\n container: css`\n display: flex;\n width: 100%;\n height: 500px;\n border: 1px solid #e8e8e8;\n border-radius: 8px;\n overflow: hidden;\n background: #fff;\n `,\n containerNoPreview: css`\n height: auto;\n border: none;\n border-radius: 0;\n & > *:first-child {\n border-right: none;\n }\n `,\n directoryPanel: css`\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: auto;\n border-right: 1px solid #e8e8e8;\n background: var(--folder-tree-directory-bg, #fafafa);\n `,\n directoryTitle: css`\n padding: 12px 16px;\n font-weight: 600;\n font-size: 14px;\n border-bottom: 1px solid #e8e8e8;\n color: #333;\n `,\n directoryTreeContent: css`\n padding: 4px 8px;\n flex: 1;\n\n .ant-tree {\n background: transparent;\n height: 100%;\n }\n .ant-tree-switcher {\n margin-right: 0;\n }\n .ant-tree .ant-tree-node-content-wrapper {\n display: inline-flex;\n align-items: center;\n flex: 1;\n min-width: 0;\n padding-left: 0;\n overflow: hidden;\n }\n .ant-tree .ant-tree-title {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n }\n .ant-tree-directory .ant-tree-treenode {\n position: relative;\n &::before {\n border-radius: 4px;\n }\n }\n /* 自定义拖拽样式 — 基于 ant-tree-treenode 定位,覆盖整行 */\n .ant-tree-treenode.folder-tree-drop-before::after {\n content: \"\";\n position: absolute;\n top: -2px;\n left: 0;\n right: 0;\n height: 2px;\n background: transparent;\n border-top: 2px dashed #1677ff;\n z-index: 10;\n pointer-events: none;\n }\n .ant-tree-treenode.folder-tree-drop-inside::after {\n content: \"\";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 2px dashed #1677ff;\n border-radius: 4px;\n background: rgba(22, 119, 255, 0.04);\n z-index: 10;\n pointer-events: none;\n }\n .ant-tree-treenode.folder-tree-drop-after::after {\n content: \"\";\n position: absolute;\n bottom: -2px;\n left: 0;\n right: 0;\n height: 2px;\n background: transparent;\n border-bottom: 2px dashed #1677ff;\n z-index: 10;\n pointer-events: none;\n }\n `,\n\n /** 自定义拖拽 - 节点可拖拽样式 */\n dragNodeHandle: css`\n cursor: grab;\n user-select: none;\n\n &:active {\n cursor: grabbing;\n }\n `,\n /** 树节点容器,用于相对定位 drop indicator */\n treeNodeWrapper: css`\n position: relative;\n min-width: 0;\n overflow: hidden;\n `,\n previewPanel: css`\n flex: 1;\n height: 100%;\n overflow: auto;\n display: flex;\n flex-direction: column;\n `,\n previewTitle: css`\n padding: 10px 16px;\n font-size: 13px;\n font-weight: 500;\n border-bottom: 1px solid #e8e8e8;\n display: flex;\n align-items: center;\n justify-content: space-between;\n color: #333;\n background: #fff;\n `,\n previewContent: css`\n flex: 1;\n overflow: auto;\n padding: 16px;\n font-size: 13px;\n line-height: 1.6;\n `,\n emptyContainer: css`\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n `,\n loadingContainer: css`\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n `,\n treeNodeTitle: css`\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-width: 0;\n overflow: hidden;\n padding-right: 4px;\n\n > span:first-child {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n `,\n moreIcon: css`\n opacity: 0;\n cursor: pointer;\n padding: 0 4px;\n margin: 2px;\n color: #999;\n font-size: 12px;\n line-height: 20px;\n transition: all 0.2s;\n height: 20px;\n box-sizing: border-box;\n\n &:hover {\n border-radius: 50%;\n color: #333;\n background: rgba(0, 0, 0, 0.04);\n }\n `,\n treeNodeTitleHover: css`\n &:hover .folder-tree-more-icon {\n opacity: 1;\n }\n `,\n inlineInput: css`\n width: 100%;\n .ant-input {\n height: 22px;\n font-size: 13px;\n padding: 0 6px;\n border-radius: 4px;\n }\n `,\n copyBtn: css`\n cursor: pointer;\n color: #999;\n font-size: 14px;\n &:hover {\n color: #1677ff;\n }\n `,\n}));\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAoB;AACpB,oBAAgC;AAEzB,IAAM,gBAAY,+BAAgB,OAAO;AAAA,EAC9C,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASX,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQpB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOhB,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuEtB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAShB,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKjB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOd,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWd,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOhB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhB,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlB,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcf,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBV,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKpB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASb,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQX,EAAE;",
6
6
  "names": []
7
7
  }
@@ -111,6 +111,11 @@ export interface FolderTreeProps {
111
111
  /** 更多操作菜单,传入节点和操作方法,返回 Dropdown menu 配置 */
112
112
  moreActions?: (node: FolderTreeData, actions?: {
113
113
  startRename: () => void;
114
+ createNode: (options: {
115
+ type: "file" | "folder";
116
+ defaultName?: string;
117
+ extra?: any;
118
+ }) => void;
114
119
  }) => DropdownProps["menu"];
115
120
  /** 是否显示连接线 */
116
121
  showLine?: boolean | {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/components/FolderTree/types.ts"],
4
- "sourcesContent": ["import type { DropdownProps } from \"antd\";\nimport type React from \"react\";\n\n/** 文件树节点数据 */\nexport interface FolderTreeData<T = any> {\n title: React.ReactNode;\n path: string;\n content?: string;\n type?: \"folder\" | \"file\";\n extra?: T;\n children?: FolderTreeData<T>[];\n}\n\n/** 文件内容加载服务 */\nexport interface FileContentService {\n loadFileContent(filePath: string): Promise<string>;\n}\n\n/** 编辑节点信息 */\nexport interface EditNodeInfo {\n /** 完整路径 key */\n key: string;\n /** 原始标题 */\n originalTitle: string;\n /** 文件类型 */\n type: \"folder\" | \"file\";\n /** 当前输入值 */\n currentValue: string;\n /** 编辑模式:重命名或新建 */\n mode: \"rename\" | \"create\";\n}\n\n/** 新建上下文 */\nexport interface CreateNodeContext {\n /** 父节点 key */\n parentKey: string;\n /** 节点类型 */\n type: \"file\" | \"folder\";\n /** 附加数据 */\n extra?: any;\n}\n\n/** FolderTree 命令式 API */\nexport interface FolderTreeRef {\n /**\n * 在指定父路径下新建文件或文件夹\n * @param parentPath - 父节点完整路径(空字符串或 \"/\" 表示根路径)\n * @param options.type - 节点类型\n * @param options.defaultName - 默认名称\n * @param options.extra - 自定义附加数据\n */\n createNode: (\n parentPath: string,\n options: {\n type: \"file\" | \"folder\";\n defaultName?: string;\n extra?: any;\n },\n ) => void;\n}\n\n/** FolderTree 组件属性 */\nexport interface FolderTreeProps {\n /** 自定义类名 */\n className?: string;\n /** 自定义样式 */\n style?: React.CSSProperties;\n\n /** 树形数据 */\n treeData: FolderTreeData[];\n\n /** 自定义文件/文件夹图标,false 禁用图标 */\n directoryIcons?:\n | false\n | Record<\"directory\" | string, React.ReactNode | (() => React.ReactNode)>;\n\n /** 是否可选中文件 */\n selectable?: boolean;\n /** 受控:当前选中的文件路径 */\n selectedFile?: string[];\n /** 默认选中的文件路径 */\n defaultSelectedFile?: string[];\n /** 选中文件变化回调 */\n onSelectedFileChange?: (file: {\n path: string[];\n title?: React.ReactNode;\n content?: string;\n extra?: any;\n }) => void;\n\n /** 受控:展开的路径 */\n expandedPaths?: string[];\n /** 默认展开的路径 */\n defaultExpandedPaths?: string[];\n /** 默认是否展开所有节点 */\n defaultExpandAll?: boolean;\n /** 展开路径变化回调 */\n onExpandedPathsChange?: (paths: string[]) => void;\n\n /** 目录树面板宽度 */\n directoryTreeWidth?: number | string;\n\n /** 文件内容加载服务 */\n fileContentService?: FileContentService;\n\n /** 空状态渲染 */\n emptyRender?: false | React.ReactNode | (() => React.ReactNode);\n /** 自定义文件预览渲染 */\n previewRender?:\n | React.ReactNode\n | ((\n file: {\n content?: string;\n path: string[];\n title?: React.ReactNode;\n language: string;\n },\n info: { originNode: React.ReactNode },\n ) => React.ReactNode);\n\n /** 自定义目录标题 */\n directoryTitle?: false | React.ReactNode | (() => React.ReactNode);\n /** 自定义预览标题 */\n previewTitle?:\n | false\n | React.ReactNode\n | ((info: {\n title: React.ReactNode;\n path: string[];\n content: string;\n }) => React.ReactNode);\n\n /** 文件点击回调 */\n onFileClick?: (filePath: string, content?: string, extra?: any) => void;\n /** 文件夹点击回调 */\n onFolderClick?: (folderPath: string, extra?: any) => void;\n\n /** 更多操作菜单,传入节点和操作方法,返回 Dropdown menu 配置 */\n moreActions?: (\n node: FolderTreeData,\n actions?: { startRename: () => void },\n ) => DropdownProps[\"menu\"];\n\n /** 是否显示连接线 */\n showLine?: boolean | { showLeafIcon?: boolean | React.ReactNode };\n /** 自定义展开/收起图标 */\n switcherIcon?: React.ReactNode | ((props: any) => React.ReactNode);\n\n /** 是否显示文件预览面板,默认 true */\n showPreview?: boolean;\n\n /**\n * 拖拽模式\n * - true | 'file': 只有文件(叶子节点)可拖拽\n * - 'folder': 只有文件夹可拖拽\n * - 'all': 文件和文件夹都可拖拽\n * - false | undefined: 禁用拖拽\n */\n draggable?: boolean | \"file\" | \"folder\" | \"all\";\n\n /** 重命名确认回调,失焦或回车时触发 */\n onRename?: (info: {\n /** 节点完整路径 key */\n key: string;\n /** 原始标题 */\n oldTitle: React.ReactNode;\n /** 新标题 */\n newTitle: string;\n /** 原始节点数据 */\n node: FolderTreeData;\n }) => void;\n\n /** 新建确认回调,失焦或回车时触发 */\n onCreate?: (info: {\n /** 父节点 key */\n parentKey: string;\n /** 用户输入的名称 */\n name: string;\n /** 节点类型 */\n type: \"file\" | \"folder\";\n /** 附加数据 */\n extra?: any;\n }) => void;\n\n /** 拖拽完成回调 */\n onDrop?: (info: {\n /** 被拖拽节点的文件名 */\n fileName: React.ReactNode;\n /** 被拖拽节点的 extra 数据 */\n extra: any;\n /** 拖拽前的完整路径 */\n oldPath: string;\n /** 拖拽完成后的新路径 */\n newPath: string;\n /** 被拖拽的节点 */\n dragNode: FolderTreeData;\n /** 目标节点 */\n dropNode: FolderTreeData;\n }) => void;\n}\n"],
4
+ "sourcesContent": ["import type { DropdownProps } from \"antd\";\nimport type React from \"react\";\n\n/** 文件树节点数据 */\nexport interface FolderTreeData<T = any> {\n title: React.ReactNode;\n path: string;\n content?: string;\n type?: \"folder\" | \"file\";\n extra?: T;\n children?: FolderTreeData<T>[];\n}\n\n/** 文件内容加载服务 */\nexport interface FileContentService {\n loadFileContent(filePath: string): Promise<string>;\n}\n\n/** 编辑节点信息 */\nexport interface EditNodeInfo {\n /** 完整路径 key */\n key: string;\n /** 原始标题 */\n originalTitle: string;\n /** 文件类型 */\n type: \"folder\" | \"file\";\n /** 当前输入值 */\n currentValue: string;\n /** 编辑模式:重命名或新建 */\n mode: \"rename\" | \"create\";\n}\n\n/** 新建上下文 */\nexport interface CreateNodeContext {\n /** 父节点 key */\n parentKey: string;\n /** 节点类型 */\n type: \"file\" | \"folder\";\n /** 附加数据 */\n extra?: any;\n}\n\n/** FolderTree 命令式 API */\nexport interface FolderTreeRef {\n /**\n * 在指定父路径下新建文件或文件夹\n * @param parentPath - 父节点完整路径(空字符串或 \"/\" 表示根路径)\n * @param options.type - 节点类型\n * @param options.defaultName - 默认名称\n * @param options.extra - 自定义附加数据\n */\n createNode: (\n parentPath: string,\n options: {\n type: \"file\" | \"folder\";\n defaultName?: string;\n extra?: any;\n },\n ) => void;\n}\n\n/** FolderTree 组件属性 */\nexport interface FolderTreeProps {\n /** 自定义类名 */\n className?: string;\n /** 自定义样式 */\n style?: React.CSSProperties;\n\n /** 树形数据 */\n treeData: FolderTreeData[];\n\n /** 自定义文件/文件夹图标,false 禁用图标 */\n directoryIcons?:\n | false\n | Record<\"directory\" | string, React.ReactNode | (() => React.ReactNode)>;\n\n /** 是否可选中文件 */\n selectable?: boolean;\n /** 受控:当前选中的文件路径 */\n selectedFile?: string[];\n /** 默认选中的文件路径 */\n defaultSelectedFile?: string[];\n /** 选中文件变化回调 */\n onSelectedFileChange?: (file: {\n path: string[];\n title?: React.ReactNode;\n content?: string;\n extra?: any;\n }) => void;\n\n /** 受控:展开的路径 */\n expandedPaths?: string[];\n /** 默认展开的路径 */\n defaultExpandedPaths?: string[];\n /** 默认是否展开所有节点 */\n defaultExpandAll?: boolean;\n /** 展开路径变化回调 */\n onExpandedPathsChange?: (paths: string[]) => void;\n\n /** 目录树面板宽度 */\n directoryTreeWidth?: number | string;\n\n /** 文件内容加载服务 */\n fileContentService?: FileContentService;\n\n /** 空状态渲染 */\n emptyRender?: false | React.ReactNode | (() => React.ReactNode);\n /** 自定义文件预览渲染 */\n previewRender?:\n | React.ReactNode\n | ((\n file: {\n content?: string;\n path: string[];\n title?: React.ReactNode;\n language: string;\n },\n info: { originNode: React.ReactNode },\n ) => React.ReactNode);\n\n /** 自定义目录标题 */\n directoryTitle?: false | React.ReactNode | (() => React.ReactNode);\n /** 自定义预览标题 */\n previewTitle?:\n | false\n | React.ReactNode\n | ((info: {\n title: React.ReactNode;\n path: string[];\n content: string;\n }) => React.ReactNode);\n\n /** 文件点击回调 */\n onFileClick?: (filePath: string, content?: string, extra?: any) => void;\n /** 文件夹点击回调 */\n onFolderClick?: (folderPath: string, extra?: any) => void;\n\n /** 更多操作菜单,传入节点和操作方法,返回 Dropdown menu 配置 */\n moreActions?: (\n node: FolderTreeData,\n actions?: {\n startRename: () => void;\n createNode: (options: {\n type: \"file\" | \"folder\";\n defaultName?: string;\n extra?: any;\n }) => void;\n },\n ) => DropdownProps[\"menu\"];\n\n /** 是否显示连接线 */\n showLine?: boolean | { showLeafIcon?: boolean | React.ReactNode };\n /** 自定义展开/收起图标 */\n switcherIcon?: React.ReactNode | ((props: any) => React.ReactNode);\n\n /** 是否显示文件预览面板,默认 true */\n showPreview?: boolean;\n\n /**\n * 拖拽模式\n * - true | 'file': 只有文件(叶子节点)可拖拽\n * - 'folder': 只有文件夹可拖拽\n * - 'all': 文件和文件夹都可拖拽\n * - false | undefined: 禁用拖拽\n */\n draggable?: boolean | \"file\" | \"folder\" | \"all\";\n\n /** 重命名确认回调,失焦或回车时触发 */\n onRename?: (info: {\n /** 节点完整路径 key */\n key: string;\n /** 原始标题 */\n oldTitle: React.ReactNode;\n /** 新标题 */\n newTitle: string;\n /** 原始节点数据 */\n node: FolderTreeData;\n }) => void;\n\n /** 新建确认回调,失焦或回车时触发 */\n onCreate?: (info: {\n /** 父节点 key */\n parentKey: string;\n /** 用户输入的名称 */\n name: string;\n /** 节点类型 */\n type: \"file\" | \"folder\";\n /** 附加数据 */\n extra?: any;\n }) => void;\n\n /** 拖拽完成回调 */\n onDrop?: (info: {\n /** 被拖拽节点的文件名 */\n fileName: React.ReactNode;\n /** 被拖拽节点的 extra 数据 */\n extra: any;\n /** 拖拽前的完整路径 */\n oldPath: string;\n /** 拖拽完成后的新路径 */\n newPath: string;\n /** 被拖拽的节点 */\n dragNode: FolderTreeData;\n /** 目标节点 */\n dropNode: FolderTreeData;\n }) => void;\n}\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -40,6 +40,7 @@ var import_ChatActionContext = require("./context/ChatActionContext");
40
40
  var import_SessionContext = require("./context/SessionContext");
41
41
  var import_useADKChat = __toESM(require("../../hooks/useADKChat"));
42
42
  var import_common = require("../../styles/common");
43
+ var import_tokens = require("../../styles/tokens");
43
44
  var import_xGroupAdk = require("../../presets/xGroupAdk");
44
45
  var import_Header = __toESM(require("./compound/Header"));
45
46
  var import_Sidebar = __toESM(require("./compound/Sidebar"));
@@ -238,6 +239,7 @@ var XAdkProviderComponent = (0, import_react.forwardRef)(
238
239
  "div",
239
240
  {
240
241
  style: {
242
+ ...import_tokens.cssVarStyle,
241
243
  display: "flex",
242
244
  height: "100%",
243
245
  width: "100%",