@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.
Files changed (61) hide show
  1. package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.d.ts +8 -0
  2. package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.js +66 -11
  3. package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.js.map +2 -2
  4. package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/styles.js +21 -0
  5. package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/styles.js.map +2 -2
  6. package/dist/cjs/components/XAdkChatbot/index.js +29 -10
  7. package/dist/cjs/components/XAdkChatbot/index.js.map +2 -2
  8. package/dist/cjs/components/XAdkProvider/compound/DefaultLayout.d.ts +6 -2
  9. package/dist/cjs/components/XAdkProvider/compound/DefaultLayout.js +59 -15
  10. package/dist/cjs/components/XAdkProvider/compound/DefaultLayout.js.map +2 -2
  11. package/dist/cjs/components/XAdkProvider/compound/Sender.d.ts +2 -1
  12. package/dist/cjs/components/XAdkProvider/compound/Sender.js.map +2 -2
  13. package/dist/cjs/components/XAdkProvider/compound/styles.d.ts +1 -0
  14. package/dist/cjs/components/XAdkProvider/compound/styles.js +16 -0
  15. package/dist/cjs/components/XAdkProvider/compound/styles.js.map +2 -2
  16. package/dist/cjs/components/XAdkSender/InlineTagInput.js +132 -2
  17. package/dist/cjs/components/XAdkSender/InlineTagInput.js.map +2 -2
  18. package/dist/cjs/components/XAdkSender/index.js +21 -55
  19. package/dist/cjs/components/XAdkSender/index.js.map +2 -2
  20. package/dist/cjs/hooks/useADKChat.js +5 -1
  21. package/dist/cjs/hooks/useADKChat.js.map +2 -2
  22. package/dist/cjs/index.d.ts +2 -2
  23. package/dist/cjs/index.js +4 -0
  24. package/dist/cjs/index.js.map +2 -2
  25. package/dist/cjs/types/XAdkSender.d.ts +10 -3
  26. package/dist/cjs/types/XAdkSender.js.map +1 -1
  27. package/dist/cjs/utils/markdownResource.d.ts +4 -1
  28. package/dist/cjs/utils/markdownResource.js +46 -0
  29. package/dist/cjs/utils/markdownResource.js.map +2 -2
  30. package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.d.ts +8 -0
  31. package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.js +67 -11
  32. package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.js.map +1 -1
  33. package/dist/esm/components/XAdkChatbot/components/MarkdownRender/styles.js +1 -1
  34. package/dist/esm/components/XAdkChatbot/components/MarkdownRender/styles.js.map +1 -1
  35. package/dist/esm/components/XAdkChatbot/index.js +20 -2
  36. package/dist/esm/components/XAdkChatbot/index.js.map +1 -1
  37. package/dist/esm/components/XAdkProvider/compound/DefaultLayout.d.ts +6 -2
  38. package/dist/esm/components/XAdkProvider/compound/DefaultLayout.js +55 -12
  39. package/dist/esm/components/XAdkProvider/compound/DefaultLayout.js.map +1 -1
  40. package/dist/esm/components/XAdkProvider/compound/Sender.d.ts +2 -1
  41. package/dist/esm/components/XAdkProvider/compound/Sender.js +2 -1
  42. package/dist/esm/components/XAdkProvider/compound/Sender.js.map +1 -1
  43. package/dist/esm/components/XAdkProvider/compound/styles.d.ts +1 -0
  44. package/dist/esm/components/XAdkProvider/compound/styles.js +3 -2
  45. package/dist/esm/components/XAdkProvider/compound/styles.js.map +1 -1
  46. package/dist/esm/components/XAdkSender/InlineTagInput.js +154 -4
  47. package/dist/esm/components/XAdkSender/InlineTagInput.js.map +1 -1
  48. package/dist/esm/components/XAdkSender/index.js +25 -58
  49. package/dist/esm/components/XAdkSender/index.js.map +1 -1
  50. package/dist/esm/hooks/useADKChat.js +8 -2
  51. package/dist/esm/hooks/useADKChat.js.map +1 -1
  52. package/dist/esm/index.d.ts +2 -2
  53. package/dist/esm/index.js +2 -2
  54. package/dist/esm/index.js.map +1 -1
  55. package/dist/esm/types/XAdkSender.d.ts +10 -3
  56. package/dist/esm/types/XAdkSender.js.map +1 -1
  57. package/dist/esm/utils/markdownResource.d.ts +4 -1
  58. package/dist/esm/utils/markdownResource.js +59 -0
  59. package/dist/esm/utils/markdownResource.js.map +1 -1
  60. package/dist/umd/chat-sdk.min.js +1 -1
  61. 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 = allowUpload && draggable;
61
- const handleDropFiles = (0, import_react.useCallback)((info) => {
63
+ const enableDragUpload = draggable;
64
+ const handleFiles = (0, import_react.useCallback)((files) => {
62
65
  var _a;
63
- const rawFiles = info.fileList.map((f) => f.originFileObj).filter(Boolean);
64
- if (rawFiles.length > 0) {
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.jsx)(
200
- import_Sender.default,
201
- {
202
- ref: senderRef,
203
- allowUpload,
204
- draggable: !enableDragUpload,
205
- clearBtnShow
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 /** 是否允许上传文件 */\n allowUpload?: boolean;\n /** 是否启用拖拽上传,拖拽区域为整个聊天区域(不含侧边栏),需 allowUpload 为 true */\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 [dropFileList, setDropFileList] = useState<UploadFile[]>([]);\n\n // 拖拽上传是否启用\n const enableDragUpload = allowUpload && draggable;\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 if (rawFiles.length > 0) {\n senderRef.current?.addFiles(rawFiles);\n }\n // 清空 Attachments 文件列表,避免累积\n setDropFileList([]);\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 <Sender\n ref={senderRef}\n allowUpload={allowUpload}\n draggable={!enableDragUpload}\n clearBtnShow={clearBtnShow}\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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",
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 * allowUpload={true}\n * clearBtnShow={true}\n * uploadRequest={myUploadHandler}\n * />\n * </XAdkProvider>\n * ```\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;AAmCzB;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;",
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
  }
@@ -1,6 +1,7 @@
1
1
  export declare const useStyles: () => {
2
2
  logoText: string;
3
3
  sendWrapper: string;
4
+ uploadButton: string;
4
5
  } & {
5
6
  w: (width: string | number) => string;
6
7
  h: (height: string | number) => string;
@@ -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;AAMf,EAAE;",
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 = !value && mentions.length === 0;
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;