@ai-group/chat-sdk 3.0.1-alpha.4 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/FileGallery/index.d.ts +33 -0
- package/dist/cjs/components/FileGallery/index.js +301 -0
- package/dist/cjs/components/FileGallery/index.js.map +7 -0
- package/dist/{esm/components/XAdkChatbot → cjs}/components/FileGallery/styles.d.ts +11 -6
- package/dist/cjs/components/FileGallery/styles.js +188 -0
- package/dist/cjs/components/FileGallery/styles.js.map +7 -0
- package/dist/cjs/components/XAdkChatbot/index.js +1 -1
- package/dist/cjs/components/XAdkChatbot/index.js.map +1 -1
- package/dist/cjs/components/XAdkProvider/XAdkProvider.stories.js +1 -1
- package/dist/cjs/components/XAdkProvider/XAdkProvider.stories.js.map +1 -1
- package/dist/cjs/components/XAdkSender/index.d.ts +2 -2
- package/dist/cjs/components/XAdkSender/index.js +127 -95
- package/dist/cjs/components/XAdkSender/index.js.map +2 -2
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +3 -3
- package/dist/cjs/types/FileGallery.d.ts +54 -0
- package/dist/cjs/types/FileGallery.js +18 -0
- package/dist/cjs/types/FileGallery.js.map +7 -0
- package/dist/cjs/types/index.d.ts +1 -0
- package/dist/cjs/types/index.js +2 -0
- package/dist/cjs/types/index.js.map +2 -2
- package/dist/esm/components/FileGallery/index.d.ts +33 -0
- package/dist/esm/components/FileGallery/index.js +439 -0
- package/dist/esm/components/FileGallery/index.js.map +1 -0
- package/dist/{cjs/components/XAdkChatbot → esm}/components/FileGallery/styles.d.ts +11 -6
- package/dist/esm/components/FileGallery/styles.js +23 -0
- package/dist/esm/components/FileGallery/styles.js.map +1 -0
- package/dist/esm/components/XAdkChatbot/index.js +1 -1
- package/dist/esm/components/XAdkChatbot/index.js.map +1 -1
- package/dist/esm/components/XAdkProvider/XAdkProvider.stories.js +1 -1
- package/dist/esm/components/XAdkProvider/XAdkProvider.stories.js.map +1 -1
- package/dist/esm/components/XAdkSender/index.d.ts +2 -2
- package/dist/esm/components/XAdkSender/index.js +46 -45
- package/dist/esm/components/XAdkSender/index.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/FileGallery.d.ts +54 -0
- package/dist/esm/types/FileGallery.js +2 -0
- package/dist/esm/types/FileGallery.js.map +1 -0
- package/dist/esm/types/index.d.ts +1 -0
- package/dist/esm/types/index.js +1 -0
- package/dist/esm/types/index.js.map +1 -1
- package/dist/umd/chat-sdk.min.js +1 -1
- package/package.json +1 -1
- package/dist/cjs/components/XAdkChatbot/components/FileGallery/index.d.ts +0 -12
- package/dist/cjs/components/XAdkChatbot/components/FileGallery/index.js +0 -92
- package/dist/cjs/components/XAdkChatbot/components/FileGallery/index.js.map +0 -7
- package/dist/cjs/components/XAdkChatbot/components/FileGallery/styles.js +0 -137
- package/dist/cjs/components/XAdkChatbot/components/FileGallery/styles.js.map +0 -7
- package/dist/cjs/components/XAdkSender/FileGallery.d.ts +0 -8
- package/dist/cjs/components/XAdkSender/FileGallery.js +0 -381
- package/dist/cjs/components/XAdkSender/FileGallery.js.map +0 -7
- package/dist/esm/components/XAdkChatbot/components/FileGallery/index.d.ts +0 -12
- package/dist/esm/components/XAdkChatbot/components/FileGallery/index.js +0 -104
- package/dist/esm/components/XAdkChatbot/components/FileGallery/index.js.map +0 -1
- package/dist/esm/components/XAdkChatbot/components/FileGallery/styles.js +0 -20
- package/dist/esm/components/XAdkChatbot/components/FileGallery/styles.js.map +0 -1
- package/dist/esm/components/XAdkSender/FileGallery.d.ts +0 -8
- package/dist/esm/components/XAdkSender/FileGallery.js +0 -236
- package/dist/esm/components/XAdkSender/FileGallery.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/components/XAdkSender/index.tsx"],
|
|
4
|
-
"sourcesContent": ["import React, { useState, useRef, useCallback } from 'react';\nimport {\n Popconfirm, \n message, \n Progress,\n Tooltip,\n Input,\n Modal,\n} from 'antd';\nimport { \n ClearOutlined, \n LoadingOutlined, \n ArrowUpOutlined,\n PaperClipOutlined,\n CloseOutlined,\n} from '@ant-design/icons';\nimport { XAdkSenderProps, ServerFile, LocalFile, ActionsComponents } from '../../types/XAdkSender';\nimport { useStyles } from './styles';\nimport FileGallery from './FileGallery';\n\n\nconst XAdkSender: React.FC<XAdkSenderProps> = ({\n clearBtnShow = true,\n allowUpload = false,\n loading = false,\n disabled = false,\n uploadRequest = () => {},\n onClear,\n onChange,\n onSubmit,\n onStop,\n onFilesChange,\n maxFileSize = 10,\n allowedFileTypes = ['image/*', 'application/pdf', 'text/plain'],\n maxFiles = 5,\n suffix,\n header,\n prefix,\n footer,\n}) => {\n const styles = useStyles();\n const [value, setValue] = useState<string>('');\n const [files, setFiles] = useState<LocalFile[]>([]);\n const [isDragOver, setIsDragOver] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const uploadRef = useRef<any>(null);\n \n // 生成唯一ID\n const generateId = () => {\n return Date.now().toString(36) + Math.random().toString(36).substr(2);\n };\n \n \n // 检查文件类型\n const checkFileType = (file: File): boolean => {\n if (!allowedFileTypes.length) return true;\n \n return allowedFileTypes.some(type => {\n if (type.includes('/*')) {\n const mainType = type.split('/')[0];\n return file.type.startsWith(mainType);\n }\n return file.type === type;\n });\n };\n \n // 检查文件大小\n const checkFileSize = (file: File): boolean => {\n const maxSize = maxFileSize * 1024 * 1024;\n return file.size <= maxSize;\n };\n \n // 验证文件\n const validateFile = (file: File): { valid: boolean; message?: string } => {\n if (files.length >= maxFiles) {\n return { valid: false, message: `最多只能上传 ${maxFiles} 个文件` };\n }\n \n if (!checkFileSize(file)) {\n return { valid: false, message: `文件大小不能超过 ${maxFileSize}MB` };\n }\n \n if (!checkFileType(file)) {\n return { valid: false, message: '不支持的文件类型' };\n }\n \n return { valid: true };\n };\n\n // 获取文件扩展名\n const getFileExtension = (filename: string): string => {\n const ext = filename.split('.').pop();\n return ext ? ext.toLowerCase() : '';\n };\n\n // 处理文件选择\n const handleFileSelect = useCallback((selectedFiles: File[]) => {\n const fileArray = Array.from(selectedFiles);\n const validFiles: LocalFile[] = [];\n \n fileArray.forEach(file => {\n const validation = validateFile(file);\n if (validation.valid) {\n validFiles.push({\n id: generateId(),\n uid: generateId(),\n name: file.name,\n size: file.size,\n type: file.type,\n file,\n progress: 0,\n status: 'pending',\n response: null\n });\n } else {\n message.error(validation.message);\n }\n });\n \n if (validFiles.length > 0) {\n setFiles(prev => [...prev, ...validFiles]);\n uploadFiles(validFiles);\n }\n }, [files.length, maxFiles, maxFileSize, allowedFileTypes]);\n\n // 上传文件\n const uploadFiles = async (fileList: LocalFile[]) => {\n for (const localFile of fileList) {\n // 开始上传\n setFiles(prev => prev.map(f => \n f.id === localFile.id ? { ...f, status: 'uploading' } : f\n ));\n \n try {\n await uploadRequest({\n file: localFile.file,\n onProgress: (e) => {\n setFiles(prev => prev.map(f => \n f.id === localFile.id ? { ...f, progress: e.percent } : f\n ));\n },\n onSuccess: (response) => {\n setFiles(prev => prev.map(f => \n f.id === localFile.id ? { \n ...f, \n status: 'success', \n progress: 100,\n response \n } : f\n ));\n },\n onError: (error) => {\n setFiles(prev => prev.map(f => \n f.id === localFile.id ? { \n ...f, \n status: 'error',\n errorMessage: error.message || '上传失败'\n } : f\n ));\n message.error(`${localFile.name} 上传失败: ${error.message || '未知错误'}`);\n }\n });\n } catch (error) {\n console.error('上传处理错误:', error);\n setFiles(prev => prev.map(f => \n f.id === localFile.id ? { \n ...f, \n status: 'error',\n errorMessage: error instanceof Error ? error.message : '上传处理失败'\n } : f\n ));\n message.error(`${localFile.name} 上传失败`);\n }\n }\n };\n\n // 模拟上传过程\n const simulateUpload = async (uploadFilesList: LocalFile[]) => {\n uploadFilesList.forEach(localFile => {\n let progress = 0;\n const interval = setInterval(() => {\n progress += 10;\n setFiles(prev => prev.map(f => \n f.id === localFile.id ? { ...f, progress } : f\n ));\n \n if (progress >= 100) {\n clearInterval(interval);\n setTimeout(() => {\n // 模拟服务器响应\n const mockResponse = {\n code: 200,\n data: {\n fileId: Math.floor(Math.random() * 1000) + 1,\n tempUrl: `https://example.com/uploads/${localFile.name}`,\n fileName: localFile.name,\n fileType: getFileExtension(localFile.name)\n }\n };\n \n setFiles(prev => prev.map(f => \n f.id === localFile.id ? { \n ...f, \n status: 'success', \n progress: 100,\n response: mockResponse\n } : f\n ));\n }, 300);\n }\n }, 100);\n });\n };\n \n // 删除文件\n const handleRemoveFile = (id: string) => {\n setFiles(prev => prev.filter(file => file.id !== id));\n };\n \n // 触发文件选择\n const triggerFileSelect = () => {\n if (fileInputRef.current) {\n fileInputRef.current.click();\n }\n };\n \n // 处理拖拽事件\n const handleDragOver = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (allowUpload) {\n setIsDragOver(true);\n }\n }, [allowUpload]);\n \n const handleDragLeave = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (allowUpload) {\n setIsDragOver(false);\n }\n }, [allowUpload]);\n \n const handleDrop = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragOver(false);\n \n if (allowUpload && e.dataTransfer.files && e.dataTransfer.files.length > 0) {\n handleFileSelect(Array.from(e.dataTransfer.files));\n }\n }, [allowUpload, handleFileSelect]);\n \n // 处理提交\n const handleSubmit = () => {\n if (!value.trim() && files.length === 0) {\n message.warning('请输入消息或选择文件');\n return;\n }\n\n const successFiles = files.filter(file => file.status === 'success');\n const uploadingFiles = files.filter(file => file.status === 'uploading');\n \n if (uploadingFiles.length > 0) {\n Modal.confirm({\n title: '文件上传中',\n content: `还有 ${uploadingFiles.length} 个文件正在上传,是否继续发送?`,\n okText: '发送已完成的',\n cancelText: '等待全部完成',\n onOk: () => {\n const formattedFiles = formatFilesForServer(successFiles);\n if (onSubmit) {\n onSubmit({ \n text: value, \n files: formattedFiles \n });\n }\n\n setValue('');\n setFiles(prev => prev.filter(f => f.status !== 'success'));\n },\n onCancel: () => {\n message.info('请等待文件上传完成后再发送');\n },\n });\n } else {\n const formattedFiles = formatFilesForServer(successFiles);\n \n if (onSubmit) {\n onSubmit({ \n text: value, \n files: formattedFiles \n });\n }\n \n setValue('');\n setFiles(prev => prev.filter(f => f.status !== 'success'));\n }\n };\n\n // 格式化文件列表为服务端格式\n const formatFilesForServer = (fileList: LocalFile[]): ServerFile[] => {\n return fileList\n .filter(file => file.status === 'success' && file.response?.data)\n .map(file => {\n const responseData = file.response.data;\n \n return {\n fileName: file.name,\n fileId: responseData.fileId || responseData.id || 0,\n tempUrl: responseData.tempUrl || responseData.url || '',\n type: responseData.fileType || getFileExtension(file.name),\n mimeType: file.type\n };\n });\n };\n \n // 处理输入框变化\n const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n const newValue = e.target.value;\n setValue(newValue);\n onChange?.(newValue);\n };\n \n // 处理回车键\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSubmit();\n }\n };\n \n // 渲染文件列表 - 使用新的 FileGallery 组件\n const renderFileList = () => {\n if (files.length === 0) return null;\n\n return (\n <FileGallery\n files={files}\n onRemove={handleRemoveFile}\n />\n );\n };\n \n const containerClass = `${styles.container} ${isDragOver ? 'drag-over' : ''}`;\n const uploading = files.some(f => f.status === 'uploading');\n const isDisabled = disabled || uploading || loading;\n\n // 定义按钮组件\n const SendButton = (props: any) => (\n <Tooltip title={loading ? \"停止生成\" : \"发送消息\"}>\n <button\n className={`${styles.iconButton} ${styles.sendButton} ${loading ? 'stop' : ''}`}\n onClick={loading ? onStop : handleSubmit}\n disabled={uploading || disabled}\n aria-label={loading ? \"停止生成\" : \"发送消息\"}\n {...props}\n >\n {loading ? <LoadingOutlined /> : <ArrowUpOutlined />}\n </button>\n </Tooltip>\n );\n\n const UploadButton = (props: any) => (\n <Tooltip title=\"上传文件\">\n <button\n className={`${styles.iconButton} ${styles.uploadButton}`}\n onClick={triggerFileSelect}\n disabled={isDisabled}\n aria-label=\"上传文件\"\n {...props}\n >\n <PaperClipOutlined />\n </button>\n </Tooltip>\n );\n\n const ClearButton = (props: any) => (\n <Popconfirm\n title=\"确定要清空聊天记录吗?\"\n onConfirm={onClear}\n placement=\"top\"\n okText=\"确定\"\n cancelText=\"取消\"\n disabled={isDisabled}\n >\n <button\n className={`${styles.iconButton} ${styles.clearButton}`}\n disabled={isDisabled}\n aria-label=\"清空聊天记录\"\n {...props}\n >\n <ClearOutlined />\n </button>\n </Popconfirm>\n );\n\n const actionsComponents: ActionsComponents = {\n SendButton,\n UploadButton,\n ClearButton,\n };\n\n // 渲染插槽内容\n const renderSlot = (\n slot: React.ReactNode | false | ((oriNode: React.ReactNode, info: { components: ActionsComponents }) => React.ReactNode | false) | undefined,\n oriNode: React.ReactNode\n ): React.ReactNode | null => {\n if (slot === false) return null;\n if (slot === undefined) return oriNode;\n if (typeof slot === 'function') {\n const result = slot(oriNode, { components: actionsComponents });\n return result === false ? null : result;\n }\n return slot;\n };\n\n // 默认的后缀内容(操作按钮组)\n const defaultSuffix = (\n <div className={styles.buttonGroup}>\n {allowUpload && <UploadButton />}\n <SendButton />\n </div>\n );\n\n return (\n <div\n ref={containerRef}\n className={containerClass}\n onDragOver={allowUpload ? handleDragOver : undefined}\n onDragLeave={allowUpload ? handleDragLeave : undefined}\n onDrop={allowUpload ? handleDrop : undefined}\n >\n {/* 头部插槽 */}\n {renderSlot(header, false)}\n\n {allowUpload && files.length > 0 && renderFileList()}\n\n {/* 隐藏的原生 file input */}\n {allowUpload && (\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n accept={allowedFileTypes.join(',')}\n style={{ display: 'none' }}\n onChange={(e) => {\n if (e.target.files) {\n handleFileSelect(Array.from(e.target.files));\n e.target.value = '';\n }\n }}\n />\n )}\n\n <div className={styles.mainArea}>\n <div className={styles.senderWrap}>\n {/* 清除按钮 */}\n {clearBtnShow && <ClearButton />}\n\n <div className={styles.inputAndButtons}>\n {/* 前缀插槽 */}\n {renderSlot(prefix, false)}\n\n <div className={styles.textAreaWrapper}>\n <Input.TextArea\n className={styles.textArea}\n value={value}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n placeholder=\"请输入消息...\"\n disabled={isDisabled}\n autoSize={{ minRows: 1, maxRows: 4 }}\n style={{\n border: 'none',\n boxShadow: 'none',\n outline: 'none',\n padding: 0,\n }}\n />\n </div>\n\n {/* 后缀插槽(默认显示操作按钮) */}\n {renderSlot(suffix, defaultSuffix)}\n </div>\n </div>\n\n {/* 底部插槽(默认显示提示文字) */}\n {renderSlot(\n footer,\n <div className={styles.tip}>\n 内容由AI生成,无法确保真实准确,仅供参考\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default XAdkSender;\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAqD;AACrD,
|
|
4
|
+
"sourcesContent": ["import React, { useState, useRef, useCallback } from \"react\";\nimport { Popconfirm, message, Progress, Tooltip, Input, Modal } from \"antd\";\nimport {\n ClearOutlined,\n LoadingOutlined,\n ArrowUpOutlined,\n PaperClipOutlined,\n CloseOutlined,\n} from \"@ant-design/icons\";\nimport {\n XAdkSenderProps,\n ServerFile,\n LocalFile,\n ActionsComponents,\n} from \"../../types/XAdkSender\";\nimport { useStyles } from \"./styles\";\nimport FileGallery from \"../FileGallery\";\n\nconst XAdkSender: React.FC<XAdkSenderProps> = ({\n clearBtnShow = true,\n allowUpload = false,\n loading = false,\n disabled = false,\n uploadRequest = () => {},\n onClear,\n onChange,\n onSubmit,\n onStop,\n onFilesChange,\n maxFileSize = 10,\n allowedFileTypes = [\n \"image/*\",\n \"audio/*\",\n \"video/*\",\n \"application/pdf\",\n \"text/plain\",\n \".doc\",\n \".docx\",\n \".xls\",\n \".xlsx\",\n \".ppt\",\n \".pptx\",\n ],\n maxFiles = 5,\n suffix,\n header,\n prefix,\n footer,\n}) => {\n const styles = useStyles();\n const [value, setValue] = useState<string>(\"\");\n const [files, setFiles] = useState<LocalFile[]>([]);\n const [isDragOver, setIsDragOver] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const uploadRef = useRef<any>(null);\n\n // 生成唯一ID\n const generateId = () => {\n return Date.now().toString(36) + Math.random().toString(36).substr(2);\n };\n\n // 检查文件类型\n const checkFileType = (file: File): boolean => {\n if (!allowedFileTypes.length) return true;\n\n return allowedFileTypes.some((type) => {\n if (type.includes(\"/*\")) {\n const mainType = type.split(\"/\")[0];\n return file.type.startsWith(mainType);\n }\n return file.type === type;\n });\n };\n\n // 检查文件大小\n const checkFileSize = (file: File): boolean => {\n const maxSize = maxFileSize * 1024 * 1024;\n return file.size <= maxSize;\n };\n\n // 验证文件\n const validateFile = (file: File): { valid: boolean; message?: string } => {\n if (files.length >= maxFiles) {\n return { valid: false, message: `最多只能上传 ${maxFiles} 个文件` };\n }\n\n if (!checkFileSize(file)) {\n return { valid: false, message: `文件大小不能超过 ${maxFileSize}MB` };\n }\n\n if (!checkFileType(file)) {\n return { valid: false, message: \"不支持的文件类型\" };\n }\n\n return { valid: true };\n };\n\n // 获取文件扩展名\n const getFileExtension = (filename: string): string => {\n const ext = filename.split(\".\").pop();\n return ext ? ext.toLowerCase() : \"\";\n };\n\n // 处理文件选择\n const handleFileSelect = useCallback(\n (selectedFiles: File[]) => {\n const fileArray = Array.from(selectedFiles);\n const validFiles: LocalFile[] = [];\n\n fileArray.forEach((file) => {\n const validation = validateFile(file);\n if (validation.valid) {\n validFiles.push({\n id: generateId(),\n uid: generateId(),\n name: file.name,\n size: file.size,\n type: file.type,\n file,\n progress: 0,\n status: \"pending\",\n response: null,\n });\n } else {\n message.error(validation.message);\n }\n });\n\n if (validFiles.length > 0) {\n setFiles((prev) => [...prev, ...validFiles]);\n uploadFiles(validFiles);\n }\n },\n [files.length, maxFiles, maxFileSize, allowedFileTypes],\n );\n\n // 上传文件\n const uploadFiles = async (fileList: LocalFile[]) => {\n for (const localFile of fileList) {\n // 开始上传\n setFiles((prev) =>\n prev.map((f) =>\n f.id === localFile.id ? { ...f, status: \"uploading\" } : f,\n ),\n );\n\n try {\n await uploadRequest({\n file: localFile.file,\n onProgress: (e) => {\n setFiles((prev) =>\n prev.map((f) =>\n f.id === localFile.id ? { ...f, progress: e.percent } : f,\n ),\n );\n },\n onSuccess: (response) => {\n setFiles((prev) =>\n prev.map((f) =>\n f.id === localFile.id\n ? {\n ...f,\n status: \"success\",\n progress: 100,\n response,\n }\n : f,\n ),\n );\n },\n onError: (error) => {\n setFiles((prev) =>\n prev.map((f) =>\n f.id === localFile.id\n ? {\n ...f,\n status: \"error\",\n errorMessage: error.message || \"上传失败\",\n }\n : f,\n ),\n );\n message.error(\n `${localFile.name} 上传失败: ${error.message || \"未知错误\"}`,\n );\n },\n });\n } catch (error) {\n console.error(\"上传处理错误:\", error);\n setFiles((prev) =>\n prev.map((f) =>\n f.id === localFile.id\n ? {\n ...f,\n status: \"error\",\n errorMessage:\n error instanceof Error ? error.message : \"上传处理失败\",\n }\n : f,\n ),\n );\n message.error(`${localFile.name} 上传失败`);\n }\n }\n };\n\n // 模拟上传过程\n const simulateUpload = async (uploadFilesList: LocalFile[]) => {\n uploadFilesList.forEach((localFile) => {\n let progress = 0;\n const interval = setInterval(() => {\n progress += 10;\n setFiles((prev) =>\n prev.map((f) => (f.id === localFile.id ? { ...f, progress } : f)),\n );\n\n if (progress >= 100) {\n clearInterval(interval);\n setTimeout(() => {\n // 模拟服务器响应\n const mockResponse = {\n code: 200,\n data: {\n fileId: Math.floor(Math.random() * 1000) + 1,\n tempUrl: `https://example.com/uploads/${localFile.name}`,\n fileName: localFile.name,\n fileType: getFileExtension(localFile.name),\n },\n };\n\n setFiles((prev) =>\n prev.map((f) =>\n f.id === localFile.id\n ? {\n ...f,\n status: \"success\",\n progress: 100,\n response: mockResponse,\n }\n : f,\n ),\n );\n }, 300);\n }\n }, 100);\n });\n };\n\n // 删除文件\n const handleRemoveFile = (id: string) => {\n setFiles((prev) => prev.filter((file) => file.id !== id));\n };\n\n // 触发文件选择\n const triggerFileSelect = () => {\n if (fileInputRef.current) {\n fileInputRef.current.click();\n }\n };\n\n // 处理拖拽事件\n const handleDragOver = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (allowUpload) {\n setIsDragOver(true);\n }\n },\n [allowUpload],\n );\n\n const handleDragLeave = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (allowUpload) {\n setIsDragOver(false);\n }\n },\n [allowUpload],\n );\n\n const handleDrop = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragOver(false);\n\n if (\n allowUpload &&\n e.dataTransfer.files &&\n e.dataTransfer.files.length > 0\n ) {\n handleFileSelect(Array.from(e.dataTransfer.files));\n }\n },\n [allowUpload, handleFileSelect],\n );\n\n // 处理提交\n const handleSubmit = () => {\n if (!value.trim() && files.length === 0) {\n message.warning(\"请输入消息或选择文件\");\n return;\n }\n\n const successFiles = files.filter((file) => file.status === \"success\");\n const uploadingFiles = files.filter((file) => file.status === \"uploading\");\n\n if (uploadingFiles.length > 0) {\n Modal.confirm({\n title: \"文件上传中\",\n content: `还有 ${uploadingFiles.length} 个文件正在上传,是否继续发送?`,\n okText: \"发送已完成的\",\n cancelText: \"等待全部完成\",\n onOk: () => {\n const formattedFiles = formatFilesForServer(successFiles);\n if (onSubmit) {\n onSubmit({\n text: value,\n files: formattedFiles,\n });\n }\n\n setValue(\"\");\n setFiles((prev) => prev.filter((f) => f.status !== \"success\"));\n },\n onCancel: () => {\n message.info(\"请等待文件上传完成后再发送\");\n },\n });\n } else {\n const formattedFiles = formatFilesForServer(successFiles);\n\n if (onSubmit) {\n onSubmit({\n text: value,\n files: formattedFiles,\n });\n }\n\n setValue(\"\");\n setFiles((prev) => prev.filter((f) => f.status !== \"success\"));\n }\n };\n\n // 格式化文件列表为服务端格式\n const formatFilesForServer = (fileList: LocalFile[]): ServerFile[] => {\n return fileList\n .filter((file) => file.status === \"success\" && file.response?.data)\n .map((file) => {\n const responseData = file.response.data;\n\n return {\n fileName: file.name,\n fileId: responseData.fileId || responseData.id || 0,\n tempUrl: responseData.tempUrl || responseData.url || \"\",\n type: responseData.fileType || getFileExtension(file.name),\n mimeType: file.type,\n };\n });\n };\n\n // 处理输入框变化\n const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n const newValue = e.target.value;\n setValue(newValue);\n onChange?.(newValue);\n };\n\n // 处理回车键\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSubmit();\n }\n };\n\n // 渲染文件列表 - 使用新的 FileGallery 组件\n const renderFileList = () => {\n if (files.length === 0) return null;\n\n return <FileGallery files={files} removable onRemove={handleRemoveFile} />;\n };\n\n const containerClass = `${styles.container} ${isDragOver ? \"drag-over\" : \"\"}`;\n const uploading = files.some((f) => f.status === \"uploading\");\n const isDisabled = disabled || uploading || loading;\n\n // 定义按钮组件\n const SendButton = (props: any) => (\n <Tooltip title={loading ? \"停止生成\" : \"发送消息\"}>\n <button\n className={`${styles.iconButton} ${styles.sendButton} ${loading ? \"stop\" : \"\"}`}\n onClick={loading ? onStop : handleSubmit}\n disabled={uploading || disabled}\n aria-label={loading ? \"停止生成\" : \"发送消息\"}\n {...props}\n >\n {loading ? <LoadingOutlined /> : <ArrowUpOutlined />}\n </button>\n </Tooltip>\n );\n\n const UploadButton = (props: any) => (\n <Tooltip title=\"上传文件\">\n <button\n className={`${styles.iconButton} ${styles.uploadButton}`}\n onClick={triggerFileSelect}\n disabled={isDisabled}\n aria-label=\"上传文件\"\n {...props}\n >\n <PaperClipOutlined />\n </button>\n </Tooltip>\n );\n\n const ClearButton = (props: any) => (\n <Popconfirm\n title=\"确定要清空聊天记录吗?\"\n onConfirm={onClear}\n placement=\"top\"\n okText=\"确定\"\n cancelText=\"取消\"\n disabled={isDisabled}\n >\n <button\n className={`${styles.iconButton} ${styles.clearButton}`}\n disabled={isDisabled}\n aria-label=\"清空聊天记录\"\n {...props}\n >\n <ClearOutlined />\n </button>\n </Popconfirm>\n );\n\n const actionsComponents: ActionsComponents = {\n SendButton,\n UploadButton,\n ClearButton,\n };\n\n // 渲染插槽内容\n const renderSlot = (\n slot:\n | React.ReactNode\n | false\n | ((\n oriNode: React.ReactNode,\n info: { components: ActionsComponents },\n ) => React.ReactNode | false)\n | undefined,\n oriNode: React.ReactNode,\n ): React.ReactNode | null => {\n if (slot === false) return null;\n if (slot === undefined) return oriNode;\n if (typeof slot === \"function\") {\n const result = slot(oriNode, { components: actionsComponents });\n return result === false ? null : result;\n }\n return slot;\n };\n\n // 默认的后缀内容(操作按钮组)\n const defaultSuffix = (\n <div className={styles.buttonGroup}>\n {allowUpload && <UploadButton />}\n <SendButton />\n </div>\n );\n\n return (\n <div\n ref={containerRef}\n className={containerClass}\n onDragOver={allowUpload ? handleDragOver : undefined}\n onDragLeave={allowUpload ? handleDragLeave : undefined}\n onDrop={allowUpload ? handleDrop : undefined}\n >\n {/* 头部插槽 */}\n {renderSlot(header, false)}\n\n {allowUpload && files.length > 0 && renderFileList()}\n\n {/* 隐藏的原生 file input */}\n {allowUpload && (\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n accept={allowedFileTypes.join(\",\")}\n style={{ display: \"none\" }}\n onChange={(e) => {\n if (e.target.files) {\n handleFileSelect(Array.from(e.target.files));\n e.target.value = \"\";\n }\n }}\n />\n )}\n\n <div className={styles.mainArea}>\n <div className={styles.senderWrap}>\n {/* 清除按钮 */}\n {clearBtnShow && <ClearButton />}\n\n <div className={styles.inputAndButtons}>\n {/* 前缀插槽 */}\n {renderSlot(prefix, false)}\n\n <div className={styles.textAreaWrapper}>\n <Input.TextArea\n className={styles.textArea}\n value={value}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n placeholder=\"请输入消息...\"\n disabled={isDisabled}\n autoSize={{ minRows: 1, maxRows: 4 }}\n style={{\n border: \"none\",\n boxShadow: \"none\",\n outline: \"none\",\n padding: 0,\n }}\n />\n </div>\n\n {/* 后缀插槽(默认显示操作按钮) */}\n {renderSlot(suffix, defaultSuffix)}\n </div>\n </div>\n\n {/* 底部插槽(默认显示提示文字) */}\n {renderSlot(\n footer,\n <div className={styles.tip}>\n 内容由AI生成,无法确保真实准确,仅供参考\n </div>,\n )}\n </div>\n </div>\n );\n};\n\nexport default XAdkSender;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["FileGallery"]
|
|
7
7
|
}
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import XAiProvider from "./components/XAiProvider";
|
|
|
3
3
|
import XAiChatbot from "./components/XAiChatbot";
|
|
4
4
|
import XAiSDK from "./components/XAiSDK";
|
|
5
5
|
import XAiSender from "./components/XAiSender";
|
|
6
|
+
import FileGallery from "./components/FileGallery";
|
|
6
7
|
import XAiConversations from "./components/XAiConversations";
|
|
7
8
|
import XAiThoughtChain from "./components/XAiThoughtChain";
|
|
8
9
|
import useXAiSDK from "./hooks/useXAiSDK";
|
|
@@ -15,10 +16,9 @@ export { useChatState, useChatActions, useSession, } from "./components/XAdkProv
|
|
|
15
16
|
export * from "./types";
|
|
16
17
|
export type { ChatHookResult, ChatHookFactory } from "./types/ChatHook";
|
|
17
18
|
export { useXAi, XAiProvider, XAiChatbot, XAiSDK, XAiSender, XAiConversations, useXAiSDK, request, };
|
|
18
|
-
export { XAdkProvider, XAdkChatbot, XAdkSender, XAiThoughtChain, useADKChat };
|
|
19
|
+
export { XAdkProvider, XAdkChatbot, XAdkSender, FileGallery, XAiThoughtChain, useADKChat, };
|
|
19
20
|
export { default as MarkdownRender } from "./components/XAdkChatbot/components/MarkdownRender";
|
|
20
21
|
export { default as FunctionCallRender } from "./components/XAdkChatbot/components/FunctionCallRender";
|
|
21
|
-
export { default as FileGallery } from "./components/XAdkChatbot/components/FileGallery";
|
|
22
22
|
export { default as ThinkRender } from "./components/XAdkChatbot/components/ThinkRender";
|
|
23
23
|
export type { MarkdownRenderProps } from "./components/XAdkChatbot/components/MarkdownRender";
|
|
24
24
|
export type { FunctionCallRenderProps } from "./components/XAdkChatbot/components/FunctionCallRender";
|
package/dist/cjs/index.js
CHANGED
|
@@ -57,6 +57,7 @@ var import_XAiProvider = __toESM(require("./components/XAiProvider"));
|
|
|
57
57
|
var import_XAiChatbot = __toESM(require("./components/XAiChatbot"));
|
|
58
58
|
var import_XAiSDK = __toESM(require("./components/XAiSDK"));
|
|
59
59
|
var import_XAiSender = __toESM(require("./components/XAiSender"));
|
|
60
|
+
var import_FileGallery = __toESM(require("./components/FileGallery"));
|
|
60
61
|
var import_XAiConversations = __toESM(require("./components/XAiConversations"));
|
|
61
62
|
var import_XAiThoughtChain = __toESM(require("./components/XAiThoughtChain"));
|
|
62
63
|
var import_useXAiSDK = __toESM(require("./hooks/useXAiSDK"));
|
|
@@ -69,7 +70,6 @@ var import_context = require("./components/XAdkProvider/context");
|
|
|
69
70
|
__reExport(src_exports, require("./types"), module.exports);
|
|
70
71
|
var import_MarkdownRender = __toESM(require("./components/XAdkChatbot/components/MarkdownRender"));
|
|
71
72
|
var import_FunctionCallRender = __toESM(require("./components/XAdkChatbot/components/FunctionCallRender"));
|
|
72
|
-
var import_FileGallery = __toESM(require("./components/XAdkChatbot/components/FileGallery"));
|
|
73
73
|
var import_ThinkRender = __toESM(require("./components/XAdkChatbot/components/ThinkRender"));
|
|
74
74
|
// Annotate the CommonJS export names for ESM import in node:
|
|
75
75
|
0 && (module.exports = {
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["// index.ts\nimport { useXAi } from \"./context/AiProviderContext\";\nimport XAiProvider from \"./components/XAiProvider\";\nimport XAiChatbot from \"./components/XAiChatbot\";\nimport XAiSDK from \"./components/XAiSDK\";\nimport XAiSender from \"./components/XAiSender\";\nimport XAiConversations from \"./components/XAiConversations\";\nimport XAiThoughtChain from \"./components/XAiThoughtChain\";\nimport useXAiSDK from \"./hooks/useXAiSDK\";\nimport request from \"./utils/request\";\n\n// 新的 Compound Components 架构\nimport XAdkProvider from \"./components/XAdkProvider\";\nimport XAdkChatbot from \"./components/XAdkChatbot\";\nimport XAdkSender from \"./components/XAdkSender\";\nimport useADKChat from \"./hooks/useADKChat\";\n\n// 导出新的 Context Hooks\nexport {\n useChatState,\n useChatActions,\n useSession,\n} from \"./components/XAdkProvider/context\";\n\nexport * from \"./types\";\n\n// 导出自定义 Hook 相关类型\nexport type { ChatHookResult, ChatHookFactory } from \"./types/ChatHook\";\n\n// 旧 API - 保持向后兼容\nexport {\n useXAi,\n XAiProvider,\n XAiChatbot,\n XAiSDK,\n XAiSender,\n XAiConversations,\n useXAiSDK,\n request,\n};\n\n// 新 API - 推荐使用\nexport {
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,
|
|
6
|
-
"names": ["XAdkChatbot", "XAdkProvider", "XAdkSender", "XAiChatbot", "XAiConversations", "XAiProvider", "XAiSDK", "XAiSender", "XAiThoughtChain", "request", "useADKChat", "useXAiSDK"]
|
|
4
|
+
"sourcesContent": ["// index.ts\nimport { useXAi } from \"./context/AiProviderContext\";\nimport XAiProvider from \"./components/XAiProvider\";\nimport XAiChatbot from \"./components/XAiChatbot\";\nimport XAiSDK from \"./components/XAiSDK\";\nimport XAiSender from \"./components/XAiSender\";\nimport FileGallery from \"./components/FileGallery\";\nimport XAiConversations from \"./components/XAiConversations\";\nimport XAiThoughtChain from \"./components/XAiThoughtChain\";\nimport useXAiSDK from \"./hooks/useXAiSDK\";\nimport request from \"./utils/request\";\n\n// 新的 Compound Components 架构\nimport XAdkProvider from \"./components/XAdkProvider\";\nimport XAdkChatbot from \"./components/XAdkChatbot\";\nimport XAdkSender from \"./components/XAdkSender\";\nimport useADKChat from \"./hooks/useADKChat\";\n\n// 导出新的 Context Hooks\nexport {\n useChatState,\n useChatActions,\n useSession,\n} from \"./components/XAdkProvider/context\";\n\nexport * from \"./types\";\n\n// 导出自定义 Hook 相关类型\nexport type { ChatHookResult, ChatHookFactory } from \"./types/ChatHook\";\n\n// 旧 API - 保持向后兼容\nexport {\n useXAi,\n XAiProvider,\n XAiChatbot,\n XAiSDK,\n XAiSender,\n XAiConversations,\n useXAiSDK,\n request,\n};\n\n// 新 API - 推荐使用\nexport {\n XAdkProvider,\n XAdkChatbot,\n XAdkSender,\n FileGallery,\n XAiThoughtChain,\n useADKChat,\n};\n\n// 基础组件导出 - 供高级用户和业务侧使用\nexport { default as MarkdownRender } from \"./components/XAdkChatbot/components/MarkdownRender\";\nexport { default as FunctionCallRender } from \"./components/XAdkChatbot/components/FunctionCallRender\";\nexport { default as ThinkRender } from \"./components/XAdkChatbot/components/ThinkRender\";\n\n// 基础组件类型导出\nexport type { MarkdownRenderProps } from \"./components/XAdkChatbot/components/MarkdownRender\";\nexport type { FunctionCallRenderProps } from \"./components/XAdkChatbot/components/FunctionCallRender\";\nexport type {\n XAiThoughtChainProps,\n ThoughtChainItemType,\n} from \"./types/XAiThoughtChain\";\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA,wCAAAA;AAAA,EAAA;AAAA;AAAA;AAAA,wCAAAC;AAAA,EAAA,wCAAAC;AAAA,EAAA,oCAAAC;AAAA,EAAA,oCAAAC;AAAA,EAAA,gDAAAC;AAAA,EAAA,sCAAAC;AAAA,EAAA,4BAAAC;AAAA,EAAA,kCAAAC;AAAA,EAAA,8CAAAC;AAAA,EAAA,8BAAAC;AAAA,EAAA,oCAAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,oCAAAC;AAAA;AAAA;AACA,+BAAuB;AACvB,yBAAwB;AACxB,wBAAuB;AACvB,oBAAmB;AACnB,uBAAsB;AACtB,yBAAwB;AACxB,8BAA6B;AAC7B,6BAA4B;AAC5B,uBAAsB;AACtB,qBAAoB;AAGpB,0BAAyB;AACzB,yBAAwB;AACxB,wBAAuB;AACvB,wBAAuB;AAGvB,qBAIO;AAEP,wBAAc,oBAzBd;AAqDA,4BAA0C;AAC1C,gCAA8C;AAC9C,yBAAuC;",
|
|
6
|
+
"names": ["FileGallery", "XAdkChatbot", "XAdkProvider", "XAdkSender", "XAiChatbot", "XAiConversations", "XAiProvider", "XAiSDK", "XAiSender", "XAiThoughtChain", "request", "useADKChat", "useXAiSDK"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
/**
|
|
3
|
+
* 统一的文件数据接口
|
|
4
|
+
* 兼容 LocalFile (XAdkSender) 和 FileData (XadkChatbot)
|
|
5
|
+
*/
|
|
6
|
+
export interface FileItem {
|
|
7
|
+
id?: string;
|
|
8
|
+
uid?: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
displayName?: string;
|
|
11
|
+
size?: number;
|
|
12
|
+
type?: string;
|
|
13
|
+
mimeType?: string;
|
|
14
|
+
file?: File;
|
|
15
|
+
status?: "pending" | "uploading" | "success" | "error";
|
|
16
|
+
progress?: number;
|
|
17
|
+
errorMessage?: string;
|
|
18
|
+
fileUri?: string;
|
|
19
|
+
tempUrl?: string;
|
|
20
|
+
response?: any;
|
|
21
|
+
}
|
|
22
|
+
export interface FileGalleryProps {
|
|
23
|
+
/**
|
|
24
|
+
* 文件列表
|
|
25
|
+
*/
|
|
26
|
+
files: FileItem[];
|
|
27
|
+
/**
|
|
28
|
+
* 对齐方式
|
|
29
|
+
* @default 'left'
|
|
30
|
+
*/
|
|
31
|
+
align?: "left" | "right";
|
|
32
|
+
/**
|
|
33
|
+
* 是否可删除
|
|
34
|
+
* @default false
|
|
35
|
+
*/
|
|
36
|
+
removable?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* 删除文件回调
|
|
39
|
+
*/
|
|
40
|
+
onRemove?: (id: string) => void;
|
|
41
|
+
/**
|
|
42
|
+
* 自定义样式类名
|
|
43
|
+
*/
|
|
44
|
+
className?: string;
|
|
45
|
+
/**
|
|
46
|
+
* 自定义样式
|
|
47
|
+
*/
|
|
48
|
+
style?: React.CSSProperties;
|
|
49
|
+
}
|
|
50
|
+
export interface FileItemComponentProps {
|
|
51
|
+
file: FileItem;
|
|
52
|
+
removable: boolean;
|
|
53
|
+
onRemove: (id: string) => void;
|
|
54
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __copyProps = (to, from, except, desc) => {
|
|
6
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
7
|
+
for (let key of __getOwnPropNames(from))
|
|
8
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
9
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
10
|
+
}
|
|
11
|
+
return to;
|
|
12
|
+
};
|
|
13
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
14
|
+
|
|
15
|
+
// src/types/FileGallery.ts
|
|
16
|
+
var FileGallery_exports = {};
|
|
17
|
+
module.exports = __toCommonJS(FileGallery_exports);
|
|
18
|
+
//# sourceMappingURL=FileGallery.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/types/FileGallery.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * 统一的文件数据接口\n * 兼容 LocalFile (XAdkSender) 和 FileData (XadkChatbot)\n */\nexport interface FileItem {\n // 基础字段\n id?: string;\n uid?: string;\n name?: string;\n displayName?: string;\n size?: number;\n type?: string;\n mimeType?: string;\n\n // 本地文件对象 (XAdkSender)\n file?: File;\n\n // 上传状态 (XAdkSender)\n status?: \"pending\" | \"uploading\" | \"success\" | \"error\";\n progress?: number;\n errorMessage?: string;\n\n // URL 字段\n fileUri?: string; // XadkChatbot\n tempUrl?: string; // XAdkSender\n response?: any;\n}\n\nexport interface FileGalleryProps {\n /**\n * 文件列表\n */\n files: FileItem[];\n\n /**\n * 对齐方式\n * @default 'left'\n */\n align?: \"left\" | \"right\";\n\n /**\n * 是否可删除\n * @default false\n */\n removable?: boolean;\n\n /**\n * 删除文件回调\n */\n onRemove?: (id: string) => void;\n\n /**\n * 自定义样式类名\n */\n className?: string;\n\n /**\n * 自定义样式\n */\n style?: React.CSSProperties;\n}\n\nexport interface FileItemComponentProps {\n file: FileItem;\n removable: boolean;\n onRemove: (id: string) => void;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;AAAA;AAAA;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/cjs/types/index.js
CHANGED
|
@@ -24,6 +24,7 @@ __reExport(types_exports, require("./XAiConversations"), module.exports);
|
|
|
24
24
|
__reExport(types_exports, require("./XAdkProvider"), module.exports);
|
|
25
25
|
__reExport(types_exports, require("./XAdkChatbot"), module.exports);
|
|
26
26
|
__reExport(types_exports, require("./XAiThoughtChain"), module.exports);
|
|
27
|
+
__reExport(types_exports, require("./FileGallery"), module.exports);
|
|
27
28
|
__reExport(types_exports, require("./common"), module.exports);
|
|
28
29
|
// Annotate the CommonJS export names for ESM import in node:
|
|
29
30
|
0 && (module.exports = {
|
|
@@ -35,6 +36,7 @@ __reExport(types_exports, require("./common"), module.exports);
|
|
|
35
36
|
...require("./XAdkProvider"),
|
|
36
37
|
...require("./XAdkChatbot"),
|
|
37
38
|
...require("./XAiThoughtChain"),
|
|
39
|
+
...require("./FileGallery"),
|
|
38
40
|
...require("./common")
|
|
39
41
|
});
|
|
40
42
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/types/index.ts"],
|
|
4
|
-
"sourcesContent": ["export * from \"./XAiChatbot\";\nexport * from \"./XAiMessage\";\nexport * from \"./XAiProvider\";\nexport * from \"./XAiSender\";\nexport * from \"./XAiConversations\";\nexport * from \"./XAdkProvider\";\nexport * from \"./XAdkChatbot\";\nexport * from \"./XAiThoughtChain\";\nexport * from \"./common\";\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;AAAA;AAAA;AAAA,0BAAc,yBAAd;AACA,0BAAc,yBADd;AAEA,0BAAc,0BAFd;AAGA,0BAAc,wBAHd;AAIA,0BAAc,+BAJd;AAKA,0BAAc,2BALd;AAMA,0BAAc,0BANd;AAOA,0BAAc,8BAPd;AAQA,0BAAc,
|
|
4
|
+
"sourcesContent": ["export * from \"./XAiChatbot\";\nexport * from \"./XAiMessage\";\nexport * from \"./XAiProvider\";\nexport * from \"./XAiSender\";\nexport * from \"./XAiConversations\";\nexport * from \"./XAdkProvider\";\nexport * from \"./XAdkChatbot\";\nexport * from \"./XAiThoughtChain\";\nexport * from \"./FileGallery\";\nexport * from \"./common\";\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;AAAA;AAAA;AAAA,0BAAc,yBAAd;AACA,0BAAc,yBADd;AAEA,0BAAc,0BAFd;AAGA,0BAAc,wBAHd;AAIA,0BAAc,+BAJd;AAKA,0BAAc,2BALd;AAMA,0BAAc,0BANd;AAOA,0BAAc,8BAPd;AAQA,0BAAc,0BARd;AASA,0BAAc,qBATd;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { FileGalleryProps } from "../../types";
|
|
3
|
+
/**
|
|
4
|
+
* FileGallery - 通用文件展示组件
|
|
5
|
+
*
|
|
6
|
+
* 功能特性:
|
|
7
|
+
* - 📁 支持多种文件类型展示 (图片、音频、视频、文档等)
|
|
8
|
+
* - 🖼️ 图片支持预览和缩略图
|
|
9
|
+
* - 🎵 音频文件支持内联播放
|
|
10
|
+
* - 🎬 视频文件支持内联播放
|
|
11
|
+
* - 📊 显示文件大小、类型图标
|
|
12
|
+
* - 🗑️ 支持删除操作
|
|
13
|
+
* - 📤 支持上传进度显示
|
|
14
|
+
* - 🎨 支持左右对齐
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* // XAdkSender 场景 - 可删除的本地文件
|
|
18
|
+
* <FileGallery
|
|
19
|
+
* files={localFiles}
|
|
20
|
+
* removable
|
|
21
|
+
* onRemove={handleRemove}
|
|
22
|
+
* align="left"
|
|
23
|
+
* />
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // XadkChatbot 场景 - 只读的远程文件
|
|
27
|
+
* <FileGallery
|
|
28
|
+
* files={remoteFiles}
|
|
29
|
+
* align="right"
|
|
30
|
+
* />
|
|
31
|
+
*/
|
|
32
|
+
declare const FileGallery: React.FC<FileGalleryProps>;
|
|
33
|
+
export default FileGallery;
|