@ai-group/chat-sdk 3.7.1-alpha5 → 3.7.1-alpha7
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/XAdkChatbot/components/MarkdownRender/index.d.ts +8 -0
- package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.js +66 -11
- package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.js.map +2 -2
- package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/styles.js +21 -0
- package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/styles.js.map +2 -2
- package/dist/cjs/components/XAdkChatbot/index.js +29 -10
- package/dist/cjs/components/XAdkChatbot/index.js.map +2 -2
- package/dist/cjs/components/XAdkProvider/compound/DefaultLayout.d.ts +6 -2
- package/dist/cjs/components/XAdkProvider/compound/DefaultLayout.js +59 -15
- package/dist/cjs/components/XAdkProvider/compound/DefaultLayout.js.map +2 -2
- package/dist/cjs/components/XAdkProvider/compound/Sender.d.ts +2 -1
- package/dist/cjs/components/XAdkProvider/compound/Sender.js.map +2 -2
- package/dist/cjs/components/XAdkProvider/compound/styles.d.ts +1 -0
- package/dist/cjs/components/XAdkProvider/compound/styles.js +16 -0
- package/dist/cjs/components/XAdkProvider/compound/styles.js.map +2 -2
- package/dist/cjs/components/XAdkSender/InlineTagInput.js +132 -2
- package/dist/cjs/components/XAdkSender/InlineTagInput.js.map +2 -2
- package/dist/cjs/components/XAdkSender/index.js +21 -55
- package/dist/cjs/components/XAdkSender/index.js.map +2 -2
- package/dist/cjs/hooks/useADKChat.js +5 -1
- package/dist/cjs/hooks/useADKChat.js.map +2 -2
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.js +4 -0
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/types/XAdkSender.d.ts +10 -3
- package/dist/cjs/types/XAdkSender.js.map +1 -1
- package/dist/cjs/utils/markdownResource.d.ts +4 -1
- package/dist/cjs/utils/markdownResource.js +46 -0
- package/dist/cjs/utils/markdownResource.js.map +2 -2
- package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.d.ts +8 -0
- package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.js +67 -11
- package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.js.map +1 -1
- package/dist/esm/components/XAdkChatbot/components/MarkdownRender/styles.js +1 -1
- package/dist/esm/components/XAdkChatbot/components/MarkdownRender/styles.js.map +1 -1
- package/dist/esm/components/XAdkChatbot/index.js +20 -2
- package/dist/esm/components/XAdkChatbot/index.js.map +1 -1
- package/dist/esm/components/XAdkProvider/compound/DefaultLayout.d.ts +6 -2
- package/dist/esm/components/XAdkProvider/compound/DefaultLayout.js +55 -12
- package/dist/esm/components/XAdkProvider/compound/DefaultLayout.js.map +1 -1
- package/dist/esm/components/XAdkProvider/compound/Sender.d.ts +2 -1
- package/dist/esm/components/XAdkProvider/compound/Sender.js +2 -1
- package/dist/esm/components/XAdkProvider/compound/Sender.js.map +1 -1
- package/dist/esm/components/XAdkProvider/compound/styles.d.ts +1 -0
- package/dist/esm/components/XAdkProvider/compound/styles.js +3 -2
- package/dist/esm/components/XAdkProvider/compound/styles.js.map +1 -1
- package/dist/esm/components/XAdkSender/InlineTagInput.js +154 -4
- package/dist/esm/components/XAdkSender/InlineTagInput.js.map +1 -1
- package/dist/esm/components/XAdkSender/index.js +25 -58
- package/dist/esm/components/XAdkSender/index.js.map +1 -1
- package/dist/esm/hooks/useADKChat.js +8 -2
- package/dist/esm/hooks/useADKChat.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/XAdkSender.d.ts +10 -3
- package/dist/esm/types/XAdkSender.js.map +1 -1
- package/dist/esm/utils/markdownResource.d.ts +4 -1
- package/dist/esm/utils/markdownResource.js +59 -0
- package/dist/esm/utils/markdownResource.js.map +1 -1
- package/dist/umd/chat-sdk.min.js +1 -1
- package/package.json +1 -1
|
@@ -34,6 +34,8 @@ __export(DefaultLayout_exports, {
|
|
|
34
34
|
module.exports = __toCommonJS(DefaultLayout_exports);
|
|
35
35
|
var import_react = require("react");
|
|
36
36
|
var import_x = require("@ant-design/x");
|
|
37
|
+
var import_antd = require("antd");
|
|
38
|
+
var import_icons = require("@ant-design/icons");
|
|
37
39
|
var import_ChatStateContext = require("../context/ChatStateContext");
|
|
38
40
|
var import_Sidebar = __toESM(require("./Sidebar"));
|
|
39
41
|
var import_Messages = __toESM(require("./Messages"));
|
|
@@ -56,16 +58,45 @@ var DefaultLayout = ({
|
|
|
56
58
|
const styles = (0, import_styles.useStyles)();
|
|
57
59
|
const chatAreaRef = (0, import_react.useRef)(null);
|
|
58
60
|
const senderRef = (0, import_react.useRef)(null);
|
|
61
|
+
const fileInputRef = (0, import_react.useRef)(null);
|
|
59
62
|
const [dropFileList, setDropFileList] = (0, import_react.useState)([]);
|
|
60
|
-
const enableDragUpload =
|
|
61
|
-
const
|
|
63
|
+
const enableDragUpload = draggable;
|
|
64
|
+
const handleFiles = (0, import_react.useCallback)((files) => {
|
|
62
65
|
var _a;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
(_a = senderRef.current) == null ? void 0 : _a.addFiles(rawFiles);
|
|
66
|
+
if (files.length > 0) {
|
|
67
|
+
(_a = senderRef.current) == null ? void 0 : _a.addFiles(files);
|
|
66
68
|
}
|
|
67
|
-
setDropFileList([]);
|
|
68
69
|
}, []);
|
|
70
|
+
const handleDropFiles = (0, import_react.useCallback)((info) => {
|
|
71
|
+
const rawFiles = info.fileList.map((f) => f.originFileObj).filter(Boolean);
|
|
72
|
+
handleFiles(rawFiles);
|
|
73
|
+
setDropFileList([]);
|
|
74
|
+
}, [handleFiles]);
|
|
75
|
+
const handleFileInputChange = (0, import_react.useCallback)(
|
|
76
|
+
(e) => {
|
|
77
|
+
if (e.target.files) {
|
|
78
|
+
handleFiles(Array.from(e.target.files));
|
|
79
|
+
e.target.value = "";
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
[handleFiles]
|
|
83
|
+
);
|
|
84
|
+
const renderUploadButton = (0, import_react.useCallback)(
|
|
85
|
+
() => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_antd.Tooltip, { title: "上传文件", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
86
|
+
"button",
|
|
87
|
+
{
|
|
88
|
+
type: "button",
|
|
89
|
+
className: styles.uploadButton,
|
|
90
|
+
onClick: () => {
|
|
91
|
+
var _a;
|
|
92
|
+
return (_a = fileInputRef.current) == null ? void 0 : _a.click();
|
|
93
|
+
},
|
|
94
|
+
"aria-label": "上传文件",
|
|
95
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.PaperClipOutlined, {})
|
|
96
|
+
}
|
|
97
|
+
) }),
|
|
98
|
+
[styles]
|
|
99
|
+
);
|
|
69
100
|
const isEmpty = messages.length === 0 && !prologue && (!suggestions || suggestions.length === 0);
|
|
70
101
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
71
102
|
"div",
|
|
@@ -196,15 +227,28 @@ var DefaultLayout = ({
|
|
|
196
227
|
padding: isEmpty ? "0 24px" : "0",
|
|
197
228
|
transition: "all 0.4s cubic-bezier(0.4, 0, 0.2, 1)"
|
|
198
229
|
},
|
|
199
|
-
children: footer || /* @__PURE__ */ (0, import_jsx_runtime.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
230
|
+
children: footer || /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
231
|
+
allowUpload && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
232
|
+
"input",
|
|
233
|
+
{
|
|
234
|
+
ref: fileInputRef,
|
|
235
|
+
type: "file",
|
|
236
|
+
multiple: true,
|
|
237
|
+
hidden: true,
|
|
238
|
+
onChange: handleFileInputChange
|
|
239
|
+
}
|
|
240
|
+
),
|
|
241
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
242
|
+
import_Sender.default,
|
|
243
|
+
{
|
|
244
|
+
ref: senderRef,
|
|
245
|
+
draggable: false,
|
|
246
|
+
onFileSelect: handleFiles,
|
|
247
|
+
clearBtnShow,
|
|
248
|
+
footerLeft: allowUpload ? renderUploadButton : void 0
|
|
249
|
+
}
|
|
250
|
+
)
|
|
251
|
+
] })
|
|
208
252
|
}
|
|
209
253
|
),
|
|
210
254
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/components/XAdkProvider/compound/DefaultLayout.tsx"],
|
|
4
|
-
"sourcesContent": ["import React, { useRef, useCallback, useState } from \"react\";\nimport { Attachments } from \"@ant-design/x\";\nimport type { UploadFile } from \"antd\";\nimport { useChatState } from \"../context/ChatStateContext\";\nimport Sidebar from \"./Sidebar\";\nimport Messages from \"./Messages\";\nimport Welcome from \"./Welcome\";\nimport Sender from \"./Sender\";\nimport { useStyles } from \"./styles\";\nimport type { ChatStrategies } from \"@/types\";\nimport type { XAdkSenderHandle } from \"@/types/XAdkSender\";\n\n/**\n * XAdkProvider 默认布局\n *\n * 提供类似 ChatGPT/DeepSeek 的默认布局:\n * - 左侧: 会话列表侧边栏 (可选,支持展开/收起)\n * - 右侧: 聊天区域 (标题 + 消息 + 输入框,居中显示,最大宽度800px)\n */\nexport interface DefaultLayoutProps {\n /** 是否显示会话列表 */\n showSessionList?: boolean;\n /** 自定义头部 */\n header?: React.ReactNode;\n /** 自定义底部 (替代默认 Sender) */\n footer?: React.ReactNode;\n
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAqD;AACrD,eAA4B;
|
|
4
|
+
"sourcesContent": ["import React, { useRef, useCallback, useState } from \"react\";\nimport { Attachments } from \"@ant-design/x\";\nimport { Tooltip } from \"antd\";\nimport { PaperClipOutlined } from \"@ant-design/icons\";\nimport type { UploadFile } from \"antd\";\nimport { useChatState } from \"../context/ChatStateContext\";\nimport Sidebar from \"./Sidebar\";\nimport Messages from \"./Messages\";\nimport Welcome from \"./Welcome\";\nimport Sender from \"./Sender\";\nimport { useStyles } from \"./styles\";\nimport type { ChatStrategies } from \"@/types\";\nimport type { XAdkSenderHandle } from \"@/types/XAdkSender\";\n\n/**\n * XAdkProvider 默认布局\n *\n * 提供类似 ChatGPT/DeepSeek 的默认布局:\n * - 左侧: 会话列表侧边栏 (可选,支持展开/收起)\n * - 右侧: 聊天区域 (标题 + 消息 + 输入框,居中显示,最大宽度800px)\n */\nexport interface DefaultLayoutProps {\n /** 是否显示会话列表 */\n showSessionList?: boolean;\n /** 自定义头部 */\n header?: React.ReactNode;\n /** 自定义底部 (替代默认 Sender) */\n footer?: React.ReactNode;\n /**\n * 是否启用内置上传入口(上传按钮 + 隐藏 file input + 拖拽)。\n * 内核 XAdkSender 不再内置上传逻辑,上传能力统一由 DefaultLayout 管理。\n * 业务方自定义 footer 时可自行控制上传。\n */\n allowUpload?: boolean;\n /** 是否启用拖拽上传,拖拽区域为整个聊天区域(不含侧边栏) */\n draggable?: boolean;\n /** 是否显示清空按钮 */\n clearBtnShow?: boolean;\n /** 是否显示函数调用详情 */\n showFnCallDetail?: boolean;\n /** 自定义消息 Footer */\n messagesFooter?: (msg: any) => React.ReactNode;\n /** 自定义工具调用渲染函数,返回 null 则降级使用默认渲染 */\n renderFunctionCall?: (\n msg: import(\"@/types\").IMessage,\n ) => React.ReactNode | null;\n /** 局部策略覆盖,优先级高于 Provider preset/strategies */\n strategies?: ChatStrategies;\n}\n\nconst DefaultLayout: React.FC<DefaultLayoutProps> = ({\n showSessionList = false,\n header,\n footer,\n allowUpload = false,\n draggable = true,\n clearBtnShow = true,\n showFnCallDetail,\n renderFunctionCall,\n strategies,\n}) => {\n const { appInfo, messages, prologue, suggestions } = useChatState();\n const styles = useStyles();\n const chatAreaRef = useRef<HTMLDivElement>(null);\n const senderRef = useRef<XAdkSenderHandle>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const [dropFileList, setDropFileList] = useState<UploadFile[]>([]);\n\n // 拖拽上传是否启用(与 allowUpload 解耦,由 draggable 独立控制)\n const enableDragUpload = draggable;\n\n // 文件注入到 Sender(按钮点击 + 拖拽统一走这里)\n const handleFiles = useCallback((files: File[]) => {\n if (files.length > 0) {\n senderRef.current?.addFiles(files);\n }\n }, []);\n\n // Attachments 拖拽文件后的回调\n const handleDropFiles = useCallback((info: { fileList: UploadFile[] }) => {\n const rawFiles = info.fileList\n .map((f) => f.originFileObj)\n .filter(Boolean) as File[];\n handleFiles(rawFiles);\n // 清空 Attachments 文件列表,避免累积\n setDropFileList([]);\n }, [handleFiles]);\n\n // 隐藏 file input 的 change 回调\n const handleFileInputChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n if (e.target.files) {\n handleFiles(Array.from(e.target.files));\n e.target.value = \"\";\n }\n },\n [handleFiles],\n );\n\n // 内置上传按钮:点击触发隐藏 file input\n const renderUploadButton = useCallback(\n () => (\n <Tooltip title=\"上传文件\">\n <button\n type=\"button\"\n className={styles.uploadButton}\n onClick={() => fileInputRef.current?.click()}\n aria-label=\"上传文件\"\n >\n <PaperClipOutlined />\n </button>\n </Tooltip>\n ),\n [styles],\n );\n\n // 判断是否为空状态(展示Welcome)\n const isEmpty =\n messages.length === 0 &&\n !prologue &&\n (!suggestions || suggestions.length === 0);\n\n return (\n <div\n style={{\n display: \"flex\",\n height: \"100%\",\n width: \"100%\",\n position: \"relative\",\n overflow: \"hidden\",\n }}\n >\n {/* 左侧会话列表 - XAiConversations 组件会处理展开/收起 */}\n {showSessionList && <Sidebar isNarrow={false} />}\n\n {/* 右侧聊天区域 - 使用 flex: 1 自动占据剩余空间 */}\n <div\n ref={chatAreaRef}\n style={{\n flex: 1,\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n flexDirection: \"column\",\n overflow: \"hidden\",\n position: \"relative\",\n }}\n >\n {/* 居中容器 - 最大宽度 800px */}\n <div\n style={{\n width: \"100%\",\n maxWidth: \"800px\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n }}\n >\n {/* 头部 */}\n {header ||\n (appInfo && (\n <div\n style={{\n padding: \"16px 24px\",\n display: \"flex\",\n justifyContent: \"center\",\n background: \"white\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"12px\",\n }}\n >\n {appInfo.appName && (\n <div>\n <div\n style={{\n fontSize: \"16px\",\n fontWeight: 500,\n color: \"#000\",\n }}\n >\n {appInfo.appName}\n </div>\n </div>\n )}\n </div>\n </div>\n ))}\n\n {/* 消息区域或Welcome区域 */}\n <div\n style={{\n flex: 1,\n overflow: \"hidden\",\n display: \"flex\",\n flexDirection: \"column\",\n }}\n >\n {/* 上方弹性占位 - Welcome状态时占据空间 */}\n <div\n style={{\n flex: isEmpty ? 1 : 0,\n transition: \"flex 0.4s cubic-bezier(0.4, 0, 0.2, 1)\",\n }}\n />\n\n {/* Welcome 组件 - 只在空状态显示 */}\n {isEmpty && (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n padding: \"0 24px\",\n marginBottom: \"24px\",\n }}\n >\n <Welcome />\n </div>\n )}\n\n {/* Messages 组件 - 只在非空状态显示 */}\n {!isEmpty && (\n <div\n style={{\n flex: 1,\n overflow: \"hidden\",\n position: \"relative\",\n }}\n >\n <Messages\n showFnCallDetail={showFnCallDetail}\n renderFunctionCall={renderFunctionCall}\n strategies={strategies}\n />\n </div>\n )}\n {/* 输入区域 - 始终存在,通过样式控制位置 */}\n <div\n className={styles.sendWrapper}\n style={{\n maxWidth: isEmpty ? \"600px\" : \"100%\",\n alignSelf: \"center\",\n padding: isEmpty ? \"0 24px\" : \"0\",\n transition: \"all 0.4s cubic-bezier(0.4, 0, 0.2, 1)\",\n }}\n >\n {footer || (\n <>\n {/* 隐藏的原生 file input - 由 DefaultLayout 管理 */}\n {allowUpload && (\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n hidden\n onChange={handleFileInputChange}\n />\n )}\n <Sender\n ref={senderRef}\n draggable={false}\n onFileSelect={handleFiles}\n clearBtnShow={clearBtnShow}\n footerLeft={allowUpload ? renderUploadButton : undefined}\n />\n </>\n )}\n </div>\n\n {/* 下方弹性占位 - Welcome状态时占据更多空间,让内容偏上 */}\n <div\n style={{\n flex: isEmpty ? 1.5 : 0,\n transition: \"flex 0.4s cubic-bezier(0.4, 0, 0.2, 1)\",\n }}\n />\n </div>\n </div>\n\n {/* Attachments 拖拽遮罩 - 仅用于拖拽上传功能 */}\n {enableDragUpload && (\n <Attachments\n style={{ display: \"none\" }}\n items={dropFileList}\n getDropContainer={() => chatAreaRef.current}\n multiple\n beforeUpload={() => false}\n onChange={handleDropFiles}\n />\n )}\n </div>\n </div>\n );\n};\n\nDefaultLayout.displayName = \"XAdkProvider.DefaultLayout\";\n\nexport default DefaultLayout;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["Sidebar", "Welcome", "Messages", "Sender"]
|
|
7
7
|
}
|
|
@@ -10,12 +10,13 @@ import type { XAdkSenderProps, XAdkSenderHandle } from "../../../types";
|
|
|
10
10
|
* ```tsx
|
|
11
11
|
* <XAdkProvider url="..." token="...">
|
|
12
12
|
* <XAdkProvider.Sender
|
|
13
|
-
* allowUpload={true}
|
|
14
13
|
* clearBtnShow={true}
|
|
15
14
|
* uploadRequest={myUploadHandler}
|
|
16
15
|
* />
|
|
17
16
|
* </XAdkProvider>
|
|
18
17
|
* ```
|
|
18
|
+
*
|
|
19
|
+
* 提示:如需内置上传按钮与拖拽上传,请使用 XAdkProvider.DefaultLayout 并设置 allowUpload。
|
|
19
20
|
*/
|
|
20
21
|
export interface XAdkSenderCompoundProps extends Partial<Omit<XAdkSenderProps, "loading" | "onSubmit" | "onStop" | "onClear">> {
|
|
21
22
|
/** 额外的样式 */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/components/XAdkProvider/compound/Sender.tsx"],
|
|
4
|
-
"sourcesContent": ["import React, { forwardRef } from \"react\";\nimport XAdkSender from \"@/components/XAdkSender\";\nimport { useChatSenderState } from \"../context/ChatSenderStateContext\";\nimport { useChatActions } from \"../context/ChatActionContext\";\nimport type { XAdkSenderProps, XAdkSenderHandle } from \"@/types\";\n\n/**\n * XAdkProvider.Sender - 输入框组件\n *\n * 从 Context 获取聊天动作并提供输入界面\n * 基于 XAdkSender 组件实现\n *\n * @example\n * ```tsx\n * <XAdkProvider url=\"...\" token=\"...\">\n * <XAdkProvider.Sender\n *
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAkC;AAClC,wBAAuB;AACvB,oCAAmC;AACnC,+BAA+B;
|
|
4
|
+
"sourcesContent": ["import React, { forwardRef } from \"react\";\nimport XAdkSender from \"@/components/XAdkSender\";\nimport { useChatSenderState } from \"../context/ChatSenderStateContext\";\nimport { useChatActions } from \"../context/ChatActionContext\";\nimport type { XAdkSenderProps, XAdkSenderHandle } from \"@/types\";\n\n/**\n * XAdkProvider.Sender - 输入框组件\n *\n * 从 Context 获取聊天动作并提供输入界面\n * 基于 XAdkSender 组件实现\n *\n * @example\n * ```tsx\n * <XAdkProvider url=\"...\" token=\"...\">\n * <XAdkProvider.Sender\n * clearBtnShow={true}\n * uploadRequest={myUploadHandler}\n * />\n * </XAdkProvider>\n * ```\n *\n * 提示:如需内置上传按钮与拖拽上传,请使用 XAdkProvider.DefaultLayout 并设置 allowUpload。\n */\nexport interface XAdkSenderCompoundProps extends Partial<\n Omit<XAdkSenderProps, \"loading\" | \"onSubmit\" | \"onStop\" | \"onClear\">\n> {\n /** 额外的样式 */\n style?: React.CSSProperties;\n /** 额外的类名 */\n className?: string;\n}\n\nconst Sender = forwardRef<XAdkSenderHandle, XAdkSenderCompoundProps>(\n (props, ref) => {\n const { loading, uploadRequest, senderValue, setSenderValue } = useChatSenderState();\n const { chat, stopChat, clearChat } = useChatActions();\n\n return (\n <XAdkSender\n ref={ref}\n {...props}\n loading={loading}\n value={senderValue}\n onChange={setSenderValue}\n onSubmit={chat}\n onStop={stopChat}\n onClear={clearChat}\n uploadRequest={uploadRequest}\n />\n );\n },\n);\n\nSender.displayName = \"XAdkProvider.Sender\";\n\nexport default Sender;\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAkC;AAClC,wBAAuB;AACvB,oCAAmC;AACnC,+BAA+B;AAoCzB;AANN,IAAM,aAAS;AAAA,EACb,CAAC,OAAO,QAAQ;AACd,UAAM,EAAE,SAAS,eAAe,aAAa,eAAe,QAAI,kDAAmB;AACnF,UAAM,EAAE,MAAM,UAAU,UAAU,QAAI,yCAAe;AAErD,WACE;AAAA,MAAC,kBAAAA;AAAA,MAAA;AAAA,QACC;AAAA,QACC,GAAG;AAAA,QACJ;AAAA,QACA,OAAO;AAAA,QACP,UAAU;AAAA,QACV,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,SAAS;AAAA,QACT;AAAA;AAAA,IACF;AAAA,EAEJ;AACF;AAEA,OAAO,cAAc;AAErB,IAAO,iBAAQ;",
|
|
6
6
|
"names": ["XAdkSender"]
|
|
7
7
|
}
|
|
@@ -46,6 +46,22 @@ var useStyles = (0, import_common.withBasicStyles)(() => ({
|
|
|
46
46
|
width: 100%;
|
|
47
47
|
align-self: center;
|
|
48
48
|
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
|
49
|
+
`,
|
|
50
|
+
uploadButton: import_css.css`
|
|
51
|
+
border: 0;
|
|
52
|
+
background: transparent;
|
|
53
|
+
cursor: pointer;
|
|
54
|
+
display: flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
justify-content: center;
|
|
57
|
+
padding: 6px;
|
|
58
|
+
border-radius: 50%;
|
|
59
|
+
color: #6b7280;
|
|
60
|
+
transition: background 0.2s;
|
|
61
|
+
|
|
62
|
+
&:hover {
|
|
63
|
+
background: rgba(0, 0, 0, 0.04);
|
|
64
|
+
}
|
|
49
65
|
`
|
|
50
66
|
}));
|
|
51
67
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/components/XAdkProvider/compound/styles.tsx"],
|
|
4
|
-
"sourcesContent": ["import { css } from \"@emotion/css\";\nimport { withBasicStyles } from \"@/styles/common\";\n\nexport const useStyles = withBasicStyles(() => ({\n logoText: css`\n font-size: 30px;\n line-height: 36px;\n font-weight: 800;\n width: 100%;\n min-width: 330px;\n margin-top: 30px;\n color: transparent;\n background: linear-gradient(to right, #ff69b4, #4169e1);\n background-clip: text;\n width: 0;\n overflow: hidden;\n text-overflow: unset;\n white-space: nowrap;\n animation: typewiriter 1s forwards;\n `,\n\n sendWrapper: css`\n position: relative;\n width: 100%;\n align-self: center;\n transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);\n `,\n}));\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAoB;AACpB,oBAAgC;AAEzB,IAAM,gBAAY,+BAAgB,OAAO;AAAA,EAC9C,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBV,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import { css } from \"@emotion/css\";\nimport { withBasicStyles } from \"@/styles/common\";\n\nexport const useStyles = withBasicStyles(() => ({\n logoText: css`\n font-size: 30px;\n line-height: 36px;\n font-weight: 800;\n width: 100%;\n min-width: 330px;\n margin-top: 30px;\n color: transparent;\n background: linear-gradient(to right, #ff69b4, #4169e1);\n background-clip: text;\n width: 0;\n overflow: hidden;\n text-overflow: unset;\n white-space: nowrap;\n animation: typewiriter 1s forwards;\n `,\n\n sendWrapper: css`\n position: relative;\n width: 100%;\n align-self: center;\n transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);\n `,\n\n uploadButton: css`\n border: 0;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 6px;\n border-radius: 50%;\n color: #6b7280;\n transition: background 0.2s;\n\n &:hover {\n background: rgba(0, 0, 0, 0.04);\n }\n `,\n}));\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAoB;AACpB,oBAAgC;AAEzB,IAAM,gBAAY,+BAAgB,OAAO;AAAA,EAC9C,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBV,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOb,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBhB,EAAE;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -25,6 +25,7 @@ module.exports = __toCommonJS(InlineTagInput_exports);
|
|
|
25
25
|
var import_react = require("react");
|
|
26
26
|
var import_client = require("react-dom/client");
|
|
27
27
|
var import_styles = require("./styles");
|
|
28
|
+
var import_markdownResource = require("../../utils/markdownResource");
|
|
28
29
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
29
30
|
var MENTION_ATTR = "data-xadk-inline-mention-id";
|
|
30
31
|
var CARET_TEXT = "";
|
|
@@ -63,6 +64,11 @@ var InlineTagInput = (0, import_react.forwardRef)(
|
|
|
63
64
|
const lastInsertedCaretRef = (0, import_react.useRef)(null);
|
|
64
65
|
const savedRangeRef = (0, import_react.useRef)(null);
|
|
65
66
|
const defaultInputPartsAppliedRef = (0, import_react.useRef)(false);
|
|
67
|
+
const skipEmptyCleanupOnceRef = (0, import_react.useRef)(false);
|
|
68
|
+
const structuralCleanupFrameRef = (0, import_react.useRef)(null);
|
|
69
|
+
const [hasContent, setHasContent] = (0, import_react.useState)(
|
|
70
|
+
() => Boolean(value || mentions.length)
|
|
71
|
+
);
|
|
66
72
|
const lastEmittedStateRef = (0, import_react.useRef)({
|
|
67
73
|
value,
|
|
68
74
|
mentionIds: mentions.map((mention) => mention.id).join("|")
|
|
@@ -120,6 +126,7 @@ var InlineTagInput = (0, import_react.forwardRef)(
|
|
|
120
126
|
const emitChange = (0, import_react.useCallback)(() => {
|
|
121
127
|
const nextValue = getPlainText();
|
|
122
128
|
const nextMentions = getOrderedMentions();
|
|
129
|
+
setHasContent(Boolean(nextValue || nextMentions.length));
|
|
123
130
|
lastEmittedStateRef.current = {
|
|
124
131
|
value: nextValue,
|
|
125
132
|
mentionIds: nextMentions.map((mention) => mention.id).join("|")
|
|
@@ -395,6 +402,58 @@ var InlineTagInput = (0, import_react.forwardRef)(
|
|
|
395
402
|
}
|
|
396
403
|
});
|
|
397
404
|
}, []);
|
|
405
|
+
const cleanupEmptyStructuralNodes = (0, import_react.useCallback)(() => {
|
|
406
|
+
const editor = editorRef.current;
|
|
407
|
+
const selection = window.getSelection();
|
|
408
|
+
if (!editor)
|
|
409
|
+
return;
|
|
410
|
+
Array.from(editor.children).forEach((node) => {
|
|
411
|
+
if (node.hasAttribute(MENTION_ATTR))
|
|
412
|
+
return;
|
|
413
|
+
if (node.querySelector(`[${MENTION_ATTR}]`))
|
|
414
|
+
return;
|
|
415
|
+
if (normalizeText(node.textContent || ""))
|
|
416
|
+
return;
|
|
417
|
+
const range = (selection == null ? void 0 : selection.rangeCount) ? selection.getRangeAt(0) : null;
|
|
418
|
+
const nodeIndex = getNodeIndex(node);
|
|
419
|
+
const containsCursor = Boolean(
|
|
420
|
+
range && range.collapsed && (range.startContainer === node || node.contains(range.startContainer) || range.startContainer === editor && (range.startOffset === nodeIndex || range.startOffset === nodeIndex + 1))
|
|
421
|
+
);
|
|
422
|
+
if (containsCursor && selection) {
|
|
423
|
+
const caretNode = createTextNode(CARET_TEXT);
|
|
424
|
+
node.replaceWith(caretNode);
|
|
425
|
+
const nextRange = document.createRange();
|
|
426
|
+
nextRange.setStart(caretNode, CARET_TEXT.length);
|
|
427
|
+
nextRange.collapse(true);
|
|
428
|
+
selection.removeAllRanges();
|
|
429
|
+
selection.addRange(nextRange);
|
|
430
|
+
savedRangeRef.current = nextRange.cloneRange();
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
node.remove();
|
|
434
|
+
});
|
|
435
|
+
}, []);
|
|
436
|
+
(0, import_react.useEffect)(() => {
|
|
437
|
+
const editor = editorRef.current;
|
|
438
|
+
if (!editor)
|
|
439
|
+
return;
|
|
440
|
+
const handleNativeDelete = (event) => {
|
|
441
|
+
if (!(event instanceof InputEvent))
|
|
442
|
+
return;
|
|
443
|
+
if (!event.inputType.startsWith("delete"))
|
|
444
|
+
return;
|
|
445
|
+
if (structuralCleanupFrameRef.current !== null) {
|
|
446
|
+
window.cancelAnimationFrame(structuralCleanupFrameRef.current);
|
|
447
|
+
}
|
|
448
|
+
structuralCleanupFrameRef.current = window.requestAnimationFrame(() => {
|
|
449
|
+
structuralCleanupFrameRef.current = null;
|
|
450
|
+
cleanupEmptyStructuralNodes();
|
|
451
|
+
cleanupCaretTextNodes();
|
|
452
|
+
});
|
|
453
|
+
};
|
|
454
|
+
editor.addEventListener("input", handleNativeDelete);
|
|
455
|
+
return () => editor.removeEventListener("input", handleNativeDelete);
|
|
456
|
+
}, [cleanupCaretTextNodes, cleanupEmptyStructuralNodes]);
|
|
398
457
|
const insertMention = (0, import_react.useCallback)(
|
|
399
458
|
(mention, replace) => {
|
|
400
459
|
const editor = editorRef.current;
|
|
@@ -410,6 +469,12 @@ var InlineTagInput = (0, import_react.forwardRef)(
|
|
|
410
469
|
insertRange = replaceTextRange(replace.start, replace.end);
|
|
411
470
|
cleanupCaretTextNodes();
|
|
412
471
|
}
|
|
472
|
+
const isSemanticallyEmpty = !getPlainText() && !editor.querySelector(`[${MENTION_ATTR}]`);
|
|
473
|
+
if (isSemanticallyEmpty) {
|
|
474
|
+
editor.innerHTML = "";
|
|
475
|
+
savedRangeRef.current = null;
|
|
476
|
+
insertRange = null;
|
|
477
|
+
}
|
|
413
478
|
const mentionNode = buildMentionNode(mention);
|
|
414
479
|
const caretNode = createTextNode(CARET_TEXT);
|
|
415
480
|
const selection = window.getSelection();
|
|
@@ -436,6 +501,7 @@ var InlineTagInput = (0, import_react.forwardRef)(
|
|
|
436
501
|
buildMentionNode,
|
|
437
502
|
cleanupCaretTextNodes,
|
|
438
503
|
emitChange,
|
|
504
|
+
getPlainText,
|
|
439
505
|
replaceTextRange,
|
|
440
506
|
restoreCursorAfterInsert,
|
|
441
507
|
setCursorAtTextEnd
|
|
@@ -447,6 +513,14 @@ var InlineTagInput = (0, import_react.forwardRef)(
|
|
|
447
513
|
document.removeEventListener("selectionchange", saveSelectionRange);
|
|
448
514
|
};
|
|
449
515
|
}, [saveSelectionRange]);
|
|
516
|
+
(0, import_react.useEffect)(
|
|
517
|
+
() => () => {
|
|
518
|
+
if (structuralCleanupFrameRef.current !== null) {
|
|
519
|
+
window.cancelAnimationFrame(structuralCleanupFrameRef.current);
|
|
520
|
+
}
|
|
521
|
+
},
|
|
522
|
+
[]
|
|
523
|
+
);
|
|
450
524
|
(0, import_react.useImperativeHandle)(ref, () => ({
|
|
451
525
|
focus: () => {
|
|
452
526
|
var _a;
|
|
@@ -464,6 +538,7 @@ var InlineTagInput = (0, import_react.forwardRef)(
|
|
|
464
538
|
return;
|
|
465
539
|
if (!defaultInputPartsAppliedRef.current && (defaultInputParts == null ? void 0 : defaultInputParts.length) && !value && mentions.length === 0) {
|
|
466
540
|
defaultInputPartsAppliedRef.current = true;
|
|
541
|
+
skipEmptyCleanupOnceRef.current = true;
|
|
467
542
|
renderPartsToEditor(defaultInputParts);
|
|
468
543
|
emitChange();
|
|
469
544
|
return;
|
|
@@ -477,6 +552,7 @@ var InlineTagInput = (0, import_react.forwardRef)(
|
|
|
477
552
|
...value ? [{ type: "text", text: value }] : [],
|
|
478
553
|
...mentions.map((mention) => ({ type: "mention", mention }))
|
|
479
554
|
]);
|
|
555
|
+
setHasContent(Boolean(value || mentions.length));
|
|
480
556
|
const lastTextNode = Array.from(editor.childNodes).reverse().find((node) => node.nodeType === Node.TEXT_NODE);
|
|
481
557
|
if (document.activeElement === editor && lastTextNode) {
|
|
482
558
|
setCursorAtTextEnd(lastTextNode);
|
|
@@ -493,6 +569,10 @@ var InlineTagInput = (0, import_react.forwardRef)(
|
|
|
493
569
|
const editor = editorRef.current;
|
|
494
570
|
if (!editor)
|
|
495
571
|
return;
|
|
572
|
+
if (skipEmptyCleanupOnceRef.current) {
|
|
573
|
+
skipEmptyCleanupOnceRef.current = false;
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
496
576
|
if (!value && mentions.length === 0 && editor.childNodes.length > 0) {
|
|
497
577
|
editor.querySelectorAll(`[${MENTION_ATTR}]`).forEach((node) => {
|
|
498
578
|
var _a;
|
|
@@ -502,8 +582,54 @@ var InlineTagInput = (0, import_react.forwardRef)(
|
|
|
502
582
|
}
|
|
503
583
|
}, [mentions.length, value]);
|
|
504
584
|
const handleInput = () => {
|
|
505
|
-
if (!composingRef.current)
|
|
585
|
+
if (!composingRef.current) {
|
|
586
|
+
cleanupEmptyStructuralNodes();
|
|
587
|
+
cleanupCaretTextNodes();
|
|
506
588
|
emitChange();
|
|
589
|
+
if (structuralCleanupFrameRef.current !== null) {
|
|
590
|
+
window.cancelAnimationFrame(structuralCleanupFrameRef.current);
|
|
591
|
+
}
|
|
592
|
+
structuralCleanupFrameRef.current = window.requestAnimationFrame(() => {
|
|
593
|
+
structuralCleanupFrameRef.current = null;
|
|
594
|
+
cleanupEmptyStructuralNodes();
|
|
595
|
+
cleanupCaretTextNodes();
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
};
|
|
599
|
+
const handlePaste = (event) => {
|
|
600
|
+
event.preventDefault();
|
|
601
|
+
const editor = editorRef.current;
|
|
602
|
+
if (!editor)
|
|
603
|
+
return;
|
|
604
|
+
const text = event.clipboardData.getData("text/plain");
|
|
605
|
+
if (!text)
|
|
606
|
+
return;
|
|
607
|
+
const parts = (0, import_markdownResource.parseMarkdownResourceLinksAsParts)(text);
|
|
608
|
+
const selection = window.getSelection();
|
|
609
|
+
const range = (selection == null ? void 0 : selection.rangeCount) && editor.contains(selection.getRangeAt(0).startContainer) ? selection.getRangeAt(0) : null;
|
|
610
|
+
const fragment = document.createDocumentFragment();
|
|
611
|
+
let lastTextNode = null;
|
|
612
|
+
for (const part of parts) {
|
|
613
|
+
if (part.type === "text") {
|
|
614
|
+
lastTextNode = createTextNode(part.text);
|
|
615
|
+
fragment.append(lastTextNode);
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
latestMentionsRef.current = [...latestMentionsRef.current, part.mention];
|
|
619
|
+
fragment.append(buildMentionNode(part.mention));
|
|
620
|
+
lastTextNode = createTextNode(CARET_TEXT);
|
|
621
|
+
fragment.append(lastTextNode);
|
|
622
|
+
}
|
|
623
|
+
if (range) {
|
|
624
|
+
range.deleteContents();
|
|
625
|
+
range.insertNode(fragment);
|
|
626
|
+
} else {
|
|
627
|
+
editor.append(fragment);
|
|
628
|
+
}
|
|
629
|
+
cleanupCaretTextNodes();
|
|
630
|
+
if (lastTextNode)
|
|
631
|
+
setCursorAtTextEnd(lastTextNode);
|
|
632
|
+
emitChange();
|
|
507
633
|
};
|
|
508
634
|
const handleKeyDown = (event) => {
|
|
509
635
|
if (event.key === "Backspace" || event.key === "Delete") {
|
|
@@ -522,7 +648,7 @@ var InlineTagInput = (0, import_react.forwardRef)(
|
|
|
522
648
|
}
|
|
523
649
|
onKeyDown == null ? void 0 : onKeyDown(event);
|
|
524
650
|
};
|
|
525
|
-
const showPlaceholder = !
|
|
651
|
+
const showPlaceholder = !hasContent;
|
|
526
652
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.inlineInputWrapper, children: [
|
|
527
653
|
showPlaceholder && placeholder && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.inlinePlaceholder, children: placeholder }),
|
|
528
654
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -535,8 +661,11 @@ var InlineTagInput = (0, import_react.forwardRef)(
|
|
|
535
661
|
role: "textbox",
|
|
536
662
|
"aria-multiline": "true",
|
|
537
663
|
onInput: handleInput,
|
|
664
|
+
onPaste: handlePaste,
|
|
538
665
|
onKeyDown: handleKeyDown,
|
|
539
666
|
onKeyUp: (event) => {
|
|
667
|
+
cleanupEmptyStructuralNodes();
|
|
668
|
+
cleanupCaretTextNodes();
|
|
540
669
|
saveSelectionRange();
|
|
541
670
|
onKeyUp == null ? void 0 : onKeyUp(event);
|
|
542
671
|
},
|
|
@@ -544,6 +673,7 @@ var InlineTagInput = (0, import_react.forwardRef)(
|
|
|
544
673
|
onFocus: saveSelectionRange,
|
|
545
674
|
onCompositionStart: () => {
|
|
546
675
|
composingRef.current = true;
|
|
676
|
+
setHasContent(true);
|
|
547
677
|
},
|
|
548
678
|
onCompositionEnd: () => {
|
|
549
679
|
composingRef.current = false;
|