@ai-group/chat-sdk 3.7.1-alpha12 → 3.7.1-alpha14
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/XAdkSender/InlineTagInput.js +8 -0
- package/dist/cjs/components/XAdkSender/InlineTagInput.js.map +2 -2
- package/dist/cjs/components/XAdkSender/index.js +14 -6
- package/dist/cjs/components/XAdkSender/index.js.map +2 -2
- package/dist/esm/components/XAdkSender/InlineTagInput.js +6 -0
- package/dist/esm/components/XAdkSender/InlineTagInput.js.map +1 -1
- package/dist/esm/components/XAdkSender/index.js +14 -6
- package/dist/esm/components/XAdkSender/index.js.map +1 -1
- package/dist/umd/chat-sdk.min.js +1 -1
- package/package.json +1 -1
|
@@ -605,7 +605,15 @@ var InlineTagInput = (0, import_react.forwardRef)(
|
|
|
605
605
|
if (!defaultInputPartsAppliedRef.current && (defaultInputParts == null ? void 0 : defaultInputParts.length) && !value && mentions.length === 0) {
|
|
606
606
|
defaultInputPartsAppliedRef.current = true;
|
|
607
607
|
skipEmptyCleanupOnceRef.current = true;
|
|
608
|
+
latestMentionsRef.current = defaultInputParts.flatMap((part) => {
|
|
609
|
+
if (part.type === "mention")
|
|
610
|
+
return [part.mention];
|
|
611
|
+
if (part.type === "tag")
|
|
612
|
+
return [part.tag];
|
|
613
|
+
return [];
|
|
614
|
+
});
|
|
608
615
|
renderPartsToEditor(defaultInputParts);
|
|
616
|
+
setHasContent(true);
|
|
609
617
|
emitChange();
|
|
610
618
|
return;
|
|
611
619
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/components/XAdkSender/InlineTagInput.tsx"],
|
|
4
|
-
"sourcesContent": ["import React, {\n forwardRef,\n useCallback,\n useEffect,\n useLayoutEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport type {\n InlineTagRenderInfo,\n MentionTag,\n XAdkSenderInputPart,\n XAdkSenderSubmitPart,\n} from \"@/types\";\nimport { useStyles } from \"./styles\";\nimport { parseMarkdownResourceLinksAsParts } from \"@/utils/markdownResource\";\n\nexport interface InlineTagInputRef {\n focus: () => void;\n getText: () => string;\n getParts: () => XAdkSenderSubmitPart[];\n getCursorOffset: () => number;\n deleteTextRange: (range: { start: number; end: number }) => void;\n insertMention: (\n mention: MentionTag,\n replace?: { start: number; end: number },\n ) => void;\n /** @deprecated 请使用 insertMention。 */\n insertTag: (\n mention: MentionTag,\n replace?: { start: number; end: number },\n ) => void;\n}\n\nexport interface InlineTagInputProps {\n value: string;\n mentions: MentionTag[];\n defaultInputParts?: XAdkSenderInputPart[];\n placeholder?: string;\n disabled?: boolean;\n onChange: (value: string) => void;\n onMentionsChange: (mentions: MentionTag[]) => void;\n onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;\n onKeyUp?: React.KeyboardEventHandler<HTMLDivElement>;\n renderMention?: (\n mention: MentionTag,\n info: InlineTagRenderInfo,\n ) => React.ReactNode;\n}\n\nconst MENTION_ATTR = \"data-xadk-inline-mention-id\";\n// contenteditable 无法把光标放进 contenteditable=false 的 Mention 里,需用零宽字符承接“Mention 后方”的光标。\nconst CARET_TEXT = \"\\u200B\";\n\nconst createTextNode = (text: string) => document.createTextNode(text);\nconst useIsomorphicLayoutEffect =\n typeof window === \"undefined\" ? useEffect : useLayoutEffect;\nconst normalizeText = (text: string) =>\n text.replace(/\\u200B/g, \"\").replace(/\\u00a0/g, \" \");\nconst getPlainLength = (text: string) => normalizeText(text).length;\n// DOM 文本里包含零宽光标锚点,快捷键替换和光标定位都要在“用户可见文本 offset”和 DOM raw offset 之间转换。\nconst toRawOffset = (text: string, plainOffset: number) => {\n let current = 0;\n for (let i = 0; i < text.length; i++) {\n if (current >= plainOffset) return i;\n if (text[i] !== CARET_TEXT) current += 1;\n }\n return text.length;\n};\n\n// 内联标签展示逻辑\nconst InlineTagInput = forwardRef<InlineTagInputRef, InlineTagInputProps>(\n (\n {\n value,\n mentions,\n defaultInputParts,\n placeholder,\n disabled,\n onChange,\n onMentionsChange,\n onKeyDown,\n onKeyUp,\n renderMention,\n },\n ref,\n ) => {\n const styles = useStyles();\n const editorRef = useRef<HTMLDivElement>(null);\n const latestMentionsRef = useRef<MentionTag[]>(mentions);\n const tagRootMapRef = useRef<WeakMap<Element, Root>>(new WeakMap());\n const composingRef = useRef(false);\n const lastInsertedCaretRef = useRef<Text | null>(null);\n const savedRangeRef = useRef<Range | null>(null);\n const defaultInputPartsAppliedRef = useRef(false);\n const skipEmptyCleanupOnceRef = useRef(false);\n const structuralCleanupFrameRef = useRef<number | null>(null);\n const [hasContent, setHasContent] = useState(() =>\n Boolean(value || mentions.length),\n );\n const lastEmittedStateRef = useRef({\n value,\n mentionIds: mentions.map((mention) => mention.id).join(\"|\"),\n });\n\n useEffect(() => {\n latestMentionsRef.current = mentions;\n }, [mentions]);\n\n const getOrderedMentions = useCallback(() => {\n const editor = editorRef.current;\n if (!editor) return [];\n const mentionMap = new Map(\n latestMentionsRef.current.map((mention) => [mention.id, mention]),\n );\n return Array.from(editor.querySelectorAll(`[${MENTION_ATTR}]`))\n .map((node) =>\n mentionMap.get(\n (node as HTMLElement).dataset.xadkInlineMentionId || \"\",\n ),\n )\n .filter(Boolean) as MentionTag[];\n }, []);\n\n // 对外只暴露用户输入的纯文本,内部零宽锚点不进入 value。\n const getPlainText = useCallback(() => {\n const editor = editorRef.current;\n if (!editor) return \"\";\n let text = \"\";\n editor.childNodes.forEach((node) => {\n if (node.nodeType === Node.TEXT_NODE) {\n text += node.textContent || \"\";\n }\n });\n return normalizeText(text);\n }, []);\n\n // 提交时需要保留文本与 Mention 的真实顺序;仅靠 value + mentions 无法区分 Mention 在句首、句中还是句尾。\n const getParts = useCallback((): XAdkSenderSubmitPart[] => {\n const editor = editorRef.current;\n if (!editor) return [];\n const mentionMap = new Map(\n latestMentionsRef.current.map((mention) => [mention.id, mention]),\n );\n const parts: XAdkSenderSubmitPart[] = [];\n\n editor.childNodes.forEach((node) => {\n if (node.nodeType === Node.TEXT_NODE) {\n const text = normalizeText(node.textContent || \"\");\n if (text) parts.push({ type: \"text\", text });\n return;\n }\n\n if (node instanceof HTMLElement && node.hasAttribute(MENTION_ATTR)) {\n const mentionId = node.dataset.xadkInlineMentionId || \"\";\n const mention = mentionMap.get(mentionId);\n if (mention) parts.push({ type: \"mention\", mention });\n }\n });\n\n return parts;\n }, []);\n\n const emitChange = useCallback(() => {\n const nextValue = getPlainText();\n const nextMentions = getOrderedMentions();\n setHasContent(Boolean(nextValue || nextMentions.length));\n lastEmittedStateRef.current = {\n value: nextValue,\n mentionIds: nextMentions.map((mention) => mention.id).join(\"|\"),\n };\n onChange(nextValue);\n onMentionsChange(nextMentions);\n }, [getOrderedMentions, getPlainText, onChange, onMentionsChange]);\n\n const removeTextRange = useCallback(\n (node: Text, start: number, end: number) => {\n const text = node.textContent || \"\";\n node.textContent = `${text.slice(0, start)}${text.slice(end)}`;\n if (!node.textContent) node.remove();\n },\n [],\n );\n\n const removeMentionNode = useCallback(\n (node: Element) => {\n const previous = node.previousSibling;\n const next = node.nextSibling;\n\n tagRootMapRef.current.get(node)?.unmount();\n node.remove();\n\n // Mention 后会补一个不可见光标锚点;删除 Mention 时同步清理,避免留下冗余节点。\n if (next?.nodeType === Node.TEXT_NODE) {\n const text = next.textContent || \"\";\n const caretLength = text.match(/^\\u200B+/)?.[0].length || 0;\n if (caretLength > 0) {\n removeTextRange(next as Text, 0, caretLength);\n return;\n }\n }\n\n if (previous?.nodeType === Node.TEXT_NODE) {\n const text = previous.textContent || \"\";\n const spaceLength = text.match(/\\s+$/)?.[0].length || 0;\n if (spaceLength > 0) {\n removeTextRange(\n previous as Text,\n text.length - spaceLength,\n text.length,\n );\n }\n }\n },\n [removeTextRange],\n );\n\n const removeMentionById = useCallback(\n (id: string) => {\n const editor = editorRef.current;\n const node = Array.from(\n editor?.querySelectorAll(`[${MENTION_ATTR}]`) || [],\n ).find(\n (item) => (item as HTMLElement).dataset.xadkInlineMentionId === id,\n );\n if (node) {\n removeMentionNode(node);\n }\n emitChange();\n editor?.focus();\n },\n [emitChange, removeMentionNode],\n );\n\n // Mention 节点本身不可编辑;删除入口通过 onRemove 回到组件内部统一维护 DOM 与 mentions。\n const buildMentionNode = useCallback(\n (mention: MentionTag) => {\n const span = document.createElement(\"span\");\n span.setAttribute(\"contenteditable\", \"false\");\n span.setAttribute(MENTION_ATTR, mention.id);\n span.dataset.xadkInlineMentionId = mention.id;\n span.dataset.xadkInlineMentionType = mention.type;\n span.className = styles.inlineTag;\n\n if (renderMention) {\n const root = createRoot(span);\n tagRootMapRef.current.set(span, root);\n root.render(\n <>\n {renderMention(mention, {\n onRemove: () => removeMentionById(mention.id),\n })}\n </>,\n );\n } else {\n const label = document.createElement(\"span\");\n label.className = \"xadk-inline-tag-label\";\n label.textContent = mention.displayName || mention.label;\n const close = document.createElement(\"span\");\n close.className = \"xadk-inline-tag-close\";\n close.innerHTML = \"×\";\n close.onclick = (event) => {\n event.preventDefault();\n event.stopPropagation();\n removeMentionById(mention.id);\n };\n span.append(label, close);\n }\n return span;\n },\n [removeMentionById, renderMention, styles.inlineTag],\n );\n\n const renderPartsToEditor = useCallback(\n (parts: XAdkSenderInputPart[]) => {\n const editor = editorRef.current;\n if (!editor) return;\n\n editor.querySelectorAll(`[${MENTION_ATTR}]`).forEach((node) => {\n tagRootMapRef.current.get(node)?.unmount();\n });\n editor.innerHTML = \"\";\n\n parts.forEach((part) => {\n if (part.type === \"text\") {\n if (part.text) editor.appendChild(createTextNode(part.text));\n return;\n }\n const mention = part.type === \"mention\" ? part.mention : part.tag;\n editor.append(buildMentionNode(mention), createTextNode(CARET_TEXT));\n });\n },\n [buildMentionNode],\n );\n\n const setCursorAtTextEnd = useCallback((node: Text) => {\n const range = document.createRange();\n const selection = window.getSelection();\n range.setStart(node, node.textContent?.length || 0);\n range.collapse(true);\n selection?.removeAllRanges();\n selection?.addRange(range);\n savedRangeRef.current = range.cloneRange();\n }, []);\n\n const saveSelectionRange = useCallback(() => {\n const editor = editorRef.current;\n const selection = window.getSelection();\n if (!editor || !selection || selection.rangeCount === 0) return;\n const range = selection.getRangeAt(0);\n if (\n !editor.contains(range.startContainer) ||\n !editor.contains(range.endContainer)\n ) {\n return;\n }\n savedRangeRef.current = range.cloneRange();\n }, []);\n\n const restoreCursorAfterInsert = useCallback(\n (node: Text) => {\n const editor = editorRef.current;\n if (!editor || !editor.contains(node)) return;\n editor.focus();\n setCursorAtTextEnd(node);\n },\n [setCursorAtTextEnd],\n );\n\n const isMentionNode = (node: Node | null): node is HTMLElement =>\n node instanceof HTMLElement && node.hasAttribute(MENTION_ATTR);\n\n const isOnlyCaretText = (text: string) => normalizeText(text) === \"\";\n\n // Backspace/Delete 需要跨过零宽锚点识别相邻 Mention,不能只看光标所在文本节点。\n const getMentionBeforeRange = (range: Range) => {\n const container = range.startContainer;\n if (container.nodeType === Node.TEXT_NODE) {\n const text = container.textContent || \"\";\n const beforeCursor = text.slice(0, range.startOffset);\n if (\n isOnlyCaretText(beforeCursor) &&\n isMentionNode(container.previousSibling)\n ) {\n return container.previousSibling;\n }\n }\n\n if (container instanceof HTMLElement) {\n const previous = container.childNodes[range.startOffset - 1];\n if (isMentionNode(previous)) return previous;\n if (\n previous?.nodeType === Node.TEXT_NODE &&\n isOnlyCaretText(previous.textContent || \"\") &&\n isMentionNode(previous.previousSibling)\n ) {\n return previous.previousSibling;\n }\n }\n\n return null;\n };\n\n const getMentionAfterRange = (range: Range) => {\n const container = range.startContainer;\n if (container.nodeType === Node.TEXT_NODE) {\n const text = container.textContent || \"\";\n const afterCursor = text.slice(range.startOffset);\n if (\n isOnlyCaretText(afterCursor) &&\n isMentionNode(container.nextSibling)\n ) {\n return container.nextSibling;\n }\n }\n\n if (container instanceof HTMLElement) {\n const next = container.childNodes[range.startOffset];\n if (isMentionNode(next)) return next;\n if (\n next?.nodeType === Node.TEXT_NODE &&\n isOnlyCaretText(next.textContent || \"\") &&\n isMentionNode(next.nextSibling)\n ) {\n return next.nextSibling;\n }\n }\n\n return null;\n };\n\n const moveCursorAroundMention = useCallback(\n (mention: HTMLElement, direction: \"before\" | \"after\") => {\n const editor = editorRef.current;\n const selection = window.getSelection();\n if (!editor || !selection || !editor.contains(mention)) return;\n\n const range = document.createRange();\n if (direction === \"before\") {\n const previous = mention.previousSibling;\n if (previous?.nodeType === Node.TEXT_NODE) {\n range.setStart(previous, previous.textContent?.length || 0);\n } else {\n range.setStartBefore(mention);\n }\n } else {\n const next = mention.nextSibling;\n if (next?.nodeType === Node.TEXT_NODE) {\n const leadingCaretLength =\n (next.textContent || \"\").match(/^\\u200B+/)?.[0].length || 0;\n range.setStart(next, leadingCaretLength);\n } else {\n range.setStartAfter(mention);\n }\n }\n\n range.collapse(true);\n selection.removeAllRanges();\n selection.addRange(range);\n savedRangeRef.current = range.cloneRange();\n },\n [],\n );\n\n // 读取光标在纯文本中的位置,供快捷键搜索词和 Mention 插入位置复用。\n const getOffsetInEditor = useCallback(() => {\n const editor = editorRef.current;\n const selection = window.getSelection();\n if (!editor || !selection || selection.rangeCount === 0) return 0;\n const range = selection.getRangeAt(0);\n let offset = 0;\n let found = false;\n\n const visit = (node: Node) => {\n if (found) return;\n if (node === range.startContainer) {\n if (node.nodeType === Node.TEXT_NODE) {\n offset += getPlainLength(\n (node.textContent || \"\").slice(0, range.startOffset),\n );\n }\n found = true;\n return;\n }\n if (node instanceof HTMLElement && node.hasAttribute(MENTION_ATTR))\n return;\n if (node.nodeType === Node.TEXT_NODE) {\n offset += getPlainLength(node.textContent || \"\");\n return;\n }\n node.childNodes.forEach(visit);\n };\n\n editor.childNodes.forEach(visit);\n return offset;\n }, []);\n\n const getNodeIndex = (node: Node) => {\n let index = 0;\n let current = node;\n while (current.previousSibling) {\n index += 1;\n current = current.previousSibling;\n }\n return index;\n };\n\n // 删除快捷键触发片段,例如把 “@文档” 替换成一个结构化 Mention,并返回删除位置对应的真实 DOM Range。\n // 注意:纯文本 offset 不包含 Mention,Mention 前后可能都是 offset 0;插入 Mention 必须依赖真实 Range,不能再反推 offset。\n const replaceTextRange = useCallback((start: number, end: number): Range | null => {\n const editor = editorRef.current;\n if (!editor) return null;\n let offset = 0;\n let insertRange: Range | null = null;\n const nodes = Array.from(editor.childNodes);\n nodes.forEach((node) => {\n if (node.nodeType !== Node.TEXT_NODE) return;\n const text = node.textContent || \"\";\n const nodeStart = offset;\n const plainLength = getPlainLength(text);\n const nodeEnd = offset + plainLength;\n offset = nodeEnd;\n if (nodeEnd <= start || nodeStart >= end) return;\n const rawStart = toRawOffset(text, Math.max(0, start - nodeStart));\n const rawEnd = toRawOffset(text, Math.max(0, end - nodeStart));\n const keepLeft = text.slice(0, rawStart);\n const keepRight = text.slice(rawEnd);\n const parent = node.parentNode;\n const nodeIndex = getNodeIndex(node);\n\n node.textContent = `${keepLeft}${keepRight}`;\n if (!insertRange) {\n insertRange = document.createRange();\n if (node.textContent) {\n insertRange.setStart(node, rawStart);\n } else if (parent) {\n insertRange.setStart(parent, nodeIndex);\n }\n insertRange.collapse(true);\n }\n if (!node.textContent) node.remove();\n });\n\n return insertRange;\n }, []);\n\n // 浏览器拆分 Range 后可能留下空文本节点;清理后才能保证后续 Mention 继续 append 在队尾。\n const cleanupCaretTextNodes = useCallback(() => {\n const editor = editorRef.current;\n if (!editor) return;\n Array.from(editor.childNodes).forEach((node) => {\n if (node.nodeType !== Node.TEXT_NODE) return;\n const text = node.textContent || \"\";\n if (!text) {\n node.remove();\n return;\n }\n if (text && normalizeText(text) === \"\") {\n node.textContent = CARET_TEXT;\n }\n });\n }, []);\n\n // Chrome 会把标签前临时输入的文字包进块级节点;文字被删空后,可能留下\n // <div><br></div>。它没有消息语义,却会在 contenteditable 中占据一整行。\n const cleanupEmptyStructuralNodes = useCallback(() => {\n const editor = editorRef.current;\n const selection = window.getSelection();\n if (!editor) return;\n\n Array.from(editor.children).forEach((node) => {\n if (node.hasAttribute(MENTION_ATTR)) return;\n if (node.querySelector(`[${MENTION_ATTR}]`)) return;\n if (normalizeText(node.textContent || \"\")) return;\n\n const range = selection?.rangeCount ? selection.getRangeAt(0) : null;\n const nodeIndex = getNodeIndex(node);\n const containsCursor = Boolean(\n range &&\n range.collapsed &&\n (range.startContainer === node ||\n node.contains(range.startContainer) ||\n (range.startContainer === editor &&\n (range.startOffset === nodeIndex ||\n range.startOffset === nodeIndex + 1))),\n );\n\n if (containsCursor && selection) {\n // 光标紧邻 contenteditable=false 的 Mention 时,单纯删除 <br> 会让 Chrome\n // 再次生成它。替换成零宽文本锚点,既能承接光标,也不会增加行高。\n const caretNode = createTextNode(CARET_TEXT);\n node.replaceWith(caretNode);\n const nextRange = document.createRange();\n nextRange.setStart(caretNode, CARET_TEXT.length);\n nextRange.collapse(true);\n selection.removeAllRanges();\n selection.addRange(nextRange);\n savedRangeRef.current = nextRange.cloneRange();\n return;\n }\n\n node.remove();\n });\n }, []);\n\n useEffect(() => {\n const editor = editorRef.current;\n if (!editor) return;\n\n // 某些业务容器会截断 React 委托事件;直接监听编辑器的原生 input,确保删除事务结束后\n // 仍能清理 Chrome 在不可编辑 Mention 前生成的占行 <br>。仅处理 delete*,不影响 Enter 换行。\n const handleNativeDelete = (event: Event) => {\n if (!(event instanceof InputEvent)) return;\n if (!event.inputType.startsWith(\"delete\")) return;\n if (structuralCleanupFrameRef.current !== null) {\n window.cancelAnimationFrame(structuralCleanupFrameRef.current);\n }\n structuralCleanupFrameRef.current = window.requestAnimationFrame(() => {\n structuralCleanupFrameRef.current = null;\n cleanupEmptyStructuralNodes();\n cleanupCaretTextNodes();\n });\n };\n\n editor.addEventListener(\"input\", handleNativeDelete);\n return () => editor.removeEventListener(\"input\", handleNativeDelete);\n }, [cleanupCaretTextNodes, cleanupEmptyStructuralNodes]);\n\n const insertMention = useCallback(\n (mention: MentionTag, replace?: { start: number; end: number }) => {\n const editor = editorRef.current;\n if (!editor) return;\n // 工具栏/弹窗会先抢走焦点;必须在 focus 之前保存当前 Selection,\n // 否则浏览器新建在输入框开头的 Range 会覆盖最后一次真实光标位置。\n const selectionBeforeFocus = window.getSelection();\n const activeRangeBeforeFocus =\n selectionBeforeFocus?.rangeCount &&\n editor.contains(selectionBeforeFocus.getRangeAt(0).startContainer)\n ? selectionBeforeFocus.getRangeAt(0).cloneRange()\n : null;\n const savedRangeBeforeFocus =\n savedRangeRef.current &&\n editor.contains(savedRangeRef.current.startContainer)\n ? savedRangeRef.current.cloneRange()\n : null;\n const rangeBeforeFocus =\n activeRangeBeforeFocus || savedRangeBeforeFocus;\n\n editor.focus();\n latestMentionsRef.current = [\n ...latestMentionsRef.current.filter((item) => item.id !== mention.id),\n mention,\n ];\n let insertRange: Range | null = null;\n if (replace) {\n insertRange = replaceTextRange(replace.start, replace.end);\n cleanupCaretTextNodes();\n }\n // 浏览器会在空 contenteditable 中生成 <div><br> 等占位块。\n // 空编辑器插入首个 Mention 前先清掉这些无语义节点,避免标签被放进第二个视觉行。\n const isSemanticallyEmpty =\n !getPlainText() && !editor.querySelector(`[${MENTION_ATTR}]`);\n if (isSemanticallyEmpty) {\n editor.innerHTML = \"\";\n savedRangeRef.current = null;\n insertRange = null;\n }\n const mentionNode = buildMentionNode(mention);\n const caretNode = createTextNode(CARET_TEXT);\n const range = insertRange || rangeBeforeFocus;\n if (range && editor.contains(range.startContainer)) {\n // 用 DocumentFragment 一次性插入,避免连续 insertNode 导致 mention/caret 顺序被浏览器 Range 状态打乱。\n const fragment = document.createDocumentFragment();\n fragment.append(mentionNode, caretNode);\n range.insertNode(fragment);\n } else {\n editor.append(mentionNode, caretNode);\n }\n cleanupCaretTextNodes();\n lastInsertedCaretRef.current = caretNode;\n setCursorAtTextEnd(caretNode);\n emitChange();\n\n // 关闭快捷列表和父组件同步 mentions/value 会触发一次 React 更新;\n // 下一帧再恢复到刚插入 Mention 后的零宽锚点,避免光标被 focus 或重渲染带回旧位置。\n window.requestAnimationFrame(() => {\n if (lastInsertedCaretRef.current === caretNode) {\n restoreCursorAfterInsert(caretNode);\n }\n });\n },\n [\n buildMentionNode,\n cleanupCaretTextNodes,\n emitChange,\n getPlainText,\n replaceTextRange,\n restoreCursorAfterInsert,\n setCursorAtTextEnd,\n ],\n );\n\n useEffect(() => {\n document.addEventListener(\"selectionchange\", saveSelectionRange);\n return () => {\n document.removeEventListener(\"selectionchange\", saveSelectionRange);\n };\n }, [saveSelectionRange]);\n\n useEffect(\n () => () => {\n if (structuralCleanupFrameRef.current !== null) {\n window.cancelAnimationFrame(structuralCleanupFrameRef.current);\n }\n },\n [],\n );\n\n useImperativeHandle(\n ref,\n () => ({\n focus: () => editorRef.current?.focus(),\n getText: getPlainText,\n getParts,\n getCursorOffset: getOffsetInEditor,\n deleteTextRange: ({ start, end }) => {\n const range = replaceTextRange(start, end);\n cleanupCaretTextNodes();\n if (range) {\n const selection = window.getSelection();\n selection?.removeAllRanges();\n selection?.addRange(range);\n savedRangeRef.current = range.cloneRange();\n }\n emitChange();\n },\n insertMention,\n insertTag: insertMention,\n }),\n [\n cleanupCaretTextNodes,\n emitChange,\n getOffsetInEditor,\n getParts,\n getPlainText,\n insertMention,\n replaceTextRange,\n ],\n );\n\n useIsomorphicLayoutEffect(() => {\n const editor = editorRef.current;\n if (!editor) return;\n\n // 默认片段只在空输入首次挂载时灌入,避免外部重新渲染覆盖用户正在编辑的内容。\n if (\n !defaultInputPartsAppliedRef.current &&\n defaultInputParts?.length &&\n !value &&\n mentions.length === 0\n ) {\n defaultInputPartsAppliedRef.current = true;\n // emitChange 的受控回写要到下一次 render 才生效;跳过本轮紧随其后的空值清理,\n // 避免刚渲染的默认 Mention 被旧的空 value/mentions 立即移除。\n skipEmptyCleanupOnceRef.current = true;\n renderPartsToEditor(defaultInputParts);\n emitChange();\n return;\n }\n\n const incomingMentionIds = mentions\n .map((mention) => mention.id)\n .join(\"|\");\n const lastEmittedState = lastEmittedStateRef.current;\n const isInternalControlledEcho =\n value === lastEmittedState.value &&\n incomingMentionIds === lastEmittedState.mentionIds;\n\n if (isInternalControlledEcho && editor.childNodes.length > 0) return;\n\n renderPartsToEditor([\n ...(value ? [{ type: \"text\" as const, text: value }] : []),\n ...mentions.map((mention) => ({ type: \"mention\" as const, mention })),\n ]);\n setHasContent(Boolean(value || mentions.length));\n\n // 外部主动写入 value/mentions 后,需要在首帧绘制前同步 DOM;若输入区已有焦点,则把光标放在内容末尾。\n const lastTextNode = Array.from(editor.childNodes)\n .reverse()\n .find((node): node is Text => node.nodeType === Node.TEXT_NODE);\n if (document.activeElement === editor && lastTextNode) {\n setCursorAtTextEnd(lastTextNode);\n }\n }, [\n defaultInputParts,\n emitChange,\n renderPartsToEditor,\n setCursorAtTextEnd,\n mentions,\n value,\n ]);\n\n useIsomorphicLayoutEffect(() => {\n const editor = editorRef.current;\n if (!editor) return;\n if (skipEmptyCleanupOnceRef.current) {\n skipEmptyCleanupOnceRef.current = false;\n return;\n }\n if (!value && mentions.length === 0 && editor.childNodes.length > 0) {\n editor.querySelectorAll(`[${MENTION_ATTR}]`).forEach((node) => {\n tagRootMapRef.current.get(node)?.unmount();\n });\n editor.innerHTML = \"\";\n }\n }, [mentions.length, value]);\n\n const handleInput = () => {\n if (!composingRef.current) {\n cleanupEmptyStructuralNodes();\n cleanupCaretTextNodes();\n emitChange();\n\n // Chrome 可能在 input 回调返回后才补上用于承接光标的 <br>;下一帧再归一化一次。\n if (structuralCleanupFrameRef.current !== null) {\n window.cancelAnimationFrame(structuralCleanupFrameRef.current);\n }\n structuralCleanupFrameRef.current = window.requestAnimationFrame(() => {\n structuralCleanupFrameRef.current = null;\n cleanupEmptyStructuralNodes();\n cleanupCaretTextNodes();\n });\n }\n };\n\n const handlePaste: React.ClipboardEventHandler<HTMLDivElement> = (\n event,\n ) => {\n event.preventDefault();\n const editor = editorRef.current;\n if (!editor) return;\n\n // 始终按 text/plain 粘贴,避免消息气泡的背景色等 HTML 样式进入 contenteditable。\n const text = event.clipboardData.getData(\"text/plain\");\n if (!text) return;\n const parts = parseMarkdownResourceLinksAsParts(text);\n const selection = window.getSelection();\n const range =\n selection?.rangeCount &&\n editor.contains(selection.getRangeAt(0).startContainer)\n ? selection.getRangeAt(0)\n : null;\n const fragment = document.createDocumentFragment();\n let lastTextNode: Text | null = null;\n\n for (const part of parts) {\n if (part.type === \"text\") {\n lastTextNode = createTextNode(part.text);\n fragment.append(lastTextNode);\n continue;\n }\n latestMentionsRef.current = [\n ...latestMentionsRef.current,\n part.mention,\n ];\n fragment.append(buildMentionNode(part.mention));\n lastTextNode = createTextNode(CARET_TEXT);\n fragment.append(lastTextNode);\n }\n\n if (range) {\n range.deleteContents();\n range.insertNode(fragment);\n } else {\n editor.append(fragment);\n }\n cleanupCaretTextNodes();\n if (lastTextNode) setCursorAtTextEnd(lastTextNode);\n emitChange();\n };\n\n const handleKeyDown: React.KeyboardEventHandler<HTMLDivElement> = (\n event,\n ) => {\n if (event.key === \"ArrowLeft\" || event.key === \"ArrowRight\") {\n const selection = window.getSelection();\n if (selection?.rangeCount) {\n const range = selection.getRangeAt(0);\n if (range.collapsed) {\n const targetMention =\n event.key === \"ArrowLeft\"\n ? getMentionBeforeRange(range)\n : getMentionAfterRange(range);\n\n if (targetMention) {\n event.preventDefault();\n moveCursorAroundMention(\n targetMention,\n event.key === \"ArrowLeft\" ? \"before\" : \"after\",\n );\n return;\n }\n }\n }\n }\n\n if (event.key === \"Backspace\" || event.key === \"Delete\") {\n const selection = window.getSelection();\n if (selection?.rangeCount) {\n const range = selection.getRangeAt(0);\n if (range.collapsed) {\n const targetMention =\n event.key === \"Backspace\"\n ? getMentionBeforeRange(range)\n : getMentionAfterRange(range);\n\n if (targetMention) {\n event.preventDefault();\n removeMentionById(\n targetMention.dataset.xadkInlineMentionId || \"\",\n );\n return;\n }\n }\n }\n }\n onKeyDown?.(event);\n };\n\n // placeholder 只由受控 value/mentions 派生,避免从 contenteditable DOM 读取导致外部插入 Mention 后状态滞后一帧。\n const showPlaceholder = !hasContent;\n\n return (\n <div className={styles.inlineInputWrapper}>\n {showPlaceholder && placeholder && (\n <div className={styles.inlinePlaceholder}>{placeholder}</div>\n )}\n <div\n ref={editorRef}\n className={styles.inlineInput}\n contentEditable={!disabled}\n suppressContentEditableWarning\n role=\"textbox\"\n aria-multiline=\"true\"\n onInput={handleInput}\n onPaste={handlePaste}\n onKeyDown={handleKeyDown}\n onKeyUp={(event) => {\n cleanupEmptyStructuralNodes();\n cleanupCaretTextNodes();\n saveSelectionRange();\n onKeyUp?.(event);\n }}\n onMouseUp={saveSelectionRange}\n onFocus={saveSelectionRange}\n onCompositionStart={() => {\n composingRef.current = true;\n // 中文 IME 在 compositionend 前不会触发受控 value 更新;候选输入一出现就应隐藏 placeholder。\n setHasContent(true);\n }}\n onCompositionEnd={() => {\n composingRef.current = false;\n emitChange();\n }}\n data-cursor-offset={getOffsetInEditor()}\n />\n </div>\n );\n },\n);\n\nInlineTagInput.displayName = \"InlineTagInput\";\n\nexport default InlineTagInput;\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAQO;AACP,oBAAsC;AAOtC,oBAA0B;AAC1B,8BAAkD;AAyOtC;AAtMZ,IAAM,eAAe;AAErB,IAAM,aAAa;AAEnB,IAAM,iBAAiB,CAAC,SAAiB,SAAS,eAAe,IAAI;AACrE,IAAM,4BACJ,OAAO,WAAW,cAAc,yBAAY;AAC9C,IAAM,gBAAgB,CAAC,SACrB,KAAK,QAAQ,WAAW,EAAE,EAAE,QAAQ,WAAW,GAAG;AACpD,IAAM,iBAAiB,CAAC,SAAiB,cAAc,IAAI,EAAE;AAE7D,IAAM,cAAc,CAAC,MAAc,gBAAwB;AACzD,MAAI,UAAU;AACd,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,QAAI,WAAW;AAAa,aAAO;AACnC,QAAI,KAAK,CAAC,MAAM;AAAY,iBAAW;AAAA,EACzC;AACA,SAAO,KAAK;AACd;AAGA,IAAM,qBAAiB;AAAA,EACrB,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GACA,QACG;AACH,UAAM,aAAS,yBAAU;AACzB,UAAM,gBAAY,qBAAuB,IAAI;AAC7C,UAAM,wBAAoB,qBAAqB,QAAQ;AACvD,UAAM,oBAAgB,qBAA+B,oBAAI,QAAQ,CAAC;AAClE,UAAM,mBAAe,qBAAO,KAAK;AACjC,UAAM,2BAAuB,qBAAoB,IAAI;AACrD,UAAM,oBAAgB,qBAAqB,IAAI;AAC/C,UAAM,kCAA8B,qBAAO,KAAK;AAChD,UAAM,8BAA0B,qBAAO,KAAK;AAC5C,UAAM,gCAA4B,qBAAsB,IAAI;AAC5D,UAAM,CAAC,YAAY,aAAa,QAAI;AAAA,MAAS,MAC3C,QAAQ,SAAS,SAAS,MAAM;AAAA,IAClC;AACA,UAAM,0BAAsB,qBAAO;AAAA,MACjC;AAAA,MACA,YAAY,SAAS,IAAI,CAAC,YAAY,QAAQ,EAAE,EAAE,KAAK,GAAG;AAAA,IAC5D,CAAC;AAED,gCAAU,MAAM;AACd,wBAAkB,UAAU;AAAA,IAC9B,GAAG,CAAC,QAAQ,CAAC;AAEb,UAAM,yBAAqB,0BAAY,MAAM;AAC3C,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC;AAAQ,eAAO,CAAC;AACrB,YAAM,aAAa,IAAI;AAAA,QACrB,kBAAkB,QAAQ,IAAI,CAAC,YAAY,CAAC,QAAQ,IAAI,OAAO,CAAC;AAAA,MAClE;AACA,aAAO,MAAM,KAAK,OAAO,iBAAiB,IAAI,eAAe,CAAC,EAC3D;AAAA,QAAI,CAAC,SACJ,WAAW;AAAA,UACR,KAAqB,QAAQ,uBAAuB;AAAA,QACvD;AAAA,MACF,EACC,OAAO,OAAO;AAAA,IACnB,GAAG,CAAC,CAAC;AAGL,UAAM,mBAAe,0BAAY,MAAM;AACrC,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC;AAAQ,eAAO;AACpB,UAAI,OAAO;AACX,aAAO,WAAW,QAAQ,CAAC,SAAS;AAClC,YAAI,KAAK,aAAa,KAAK,WAAW;AACpC,kBAAQ,KAAK,eAAe;AAAA,QAC9B;AAAA,MACF,CAAC;AACD,aAAO,cAAc,IAAI;AAAA,IAC3B,GAAG,CAAC,CAAC;AAGL,UAAM,eAAW,0BAAY,MAA8B;AACzD,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC;AAAQ,eAAO,CAAC;AACrB,YAAM,aAAa,IAAI;AAAA,QACrB,kBAAkB,QAAQ,IAAI,CAAC,YAAY,CAAC,QAAQ,IAAI,OAAO,CAAC;AAAA,MAClE;AACA,YAAM,QAAgC,CAAC;AAEvC,aAAO,WAAW,QAAQ,CAAC,SAAS;AAClC,YAAI,KAAK,aAAa,KAAK,WAAW;AACpC,gBAAM,OAAO,cAAc,KAAK,eAAe,EAAE;AACjD,cAAI;AAAM,kBAAM,KAAK,EAAE,MAAM,QAAQ,KAAK,CAAC;AAC3C;AAAA,QACF;AAEA,YAAI,gBAAgB,eAAe,KAAK,aAAa,YAAY,GAAG;AAClE,gBAAM,YAAY,KAAK,QAAQ,uBAAuB;AACtD,gBAAM,UAAU,WAAW,IAAI,SAAS;AACxC,cAAI;AAAS,kBAAM,KAAK,EAAE,MAAM,WAAW,QAAQ,CAAC;AAAA,QACtD;AAAA,MACF,CAAC;AAED,aAAO;AAAA,IACT,GAAG,CAAC,CAAC;AAEL,UAAM,iBAAa,0BAAY,MAAM;AACnC,YAAM,YAAY,aAAa;AAC/B,YAAM,eAAe,mBAAmB;AACxC,oBAAc,QAAQ,aAAa,aAAa,MAAM,CAAC;AACvD,0BAAoB,UAAU;AAAA,QAC5B,OAAO;AAAA,QACP,YAAY,aAAa,IAAI,CAAC,YAAY,QAAQ,EAAE,EAAE,KAAK,GAAG;AAAA,MAChE;AACA,eAAS,SAAS;AAClB,uBAAiB,YAAY;AAAA,IAC/B,GAAG,CAAC,oBAAoB,cAAc,UAAU,gBAAgB,CAAC;AAEjE,UAAM,sBAAkB;AAAA,MACtB,CAAC,MAAY,OAAe,QAAgB;AAC1C,cAAM,OAAO,KAAK,eAAe;AACjC,aAAK,cAAc,GAAG,KAAK,MAAM,GAAG,KAAK,IAAI,KAAK,MAAM,GAAG;AAC3D,YAAI,CAAC,KAAK;AAAa,eAAK,OAAO;AAAA,MACrC;AAAA,MACA,CAAC;AAAA,IACH;AAEA,UAAM,wBAAoB;AAAA,MACxB,CAAC,SAAkB;AA3LzB;AA4LQ,cAAM,WAAW,KAAK;AACtB,cAAM,OAAO,KAAK;AAElB,4BAAc,QAAQ,IAAI,IAAI,MAA9B,mBAAiC;AACjC,aAAK,OAAO;AAGZ,aAAI,6BAAM,cAAa,KAAK,WAAW;AACrC,gBAAM,OAAO,KAAK,eAAe;AACjC,gBAAM,gBAAc,UAAK,MAAM,UAAU,MAArB,mBAAyB,GAAG,WAAU;AAC1D,cAAI,cAAc,GAAG;AACnB,4BAAgB,MAAc,GAAG,WAAW;AAC5C;AAAA,UACF;AAAA,QACF;AAEA,aAAI,qCAAU,cAAa,KAAK,WAAW;AACzC,gBAAM,OAAO,SAAS,eAAe;AACrC,gBAAM,gBAAc,UAAK,MAAM,MAAM,MAAjB,mBAAqB,GAAG,WAAU;AACtD,cAAI,cAAc,GAAG;AACnB;AAAA,cACE;AAAA,cACA,KAAK,SAAS;AAAA,cACd,KAAK;AAAA,YACP;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MACA,CAAC,eAAe;AAAA,IAClB;AAEA,UAAM,wBAAoB;AAAA,MACxB,CAAC,OAAe;AACd,cAAM,SAAS,UAAU;AACzB,cAAM,OAAO,MAAM;AAAA,WACjB,iCAAQ,iBAAiB,IAAI,qBAAoB,CAAC;AAAA,QACpD,EAAE;AAAA,UACA,CAAC,SAAU,KAAqB,QAAQ,wBAAwB;AAAA,QAClE;AACA,YAAI,MAAM;AACR,4BAAkB,IAAI;AAAA,QACxB;AACA,mBAAW;AACX,yCAAQ;AAAA,MACV;AAAA,MACA,CAAC,YAAY,iBAAiB;AAAA,IAChC;AAGA,UAAM,uBAAmB;AAAA,MACvB,CAAC,YAAwB;AACvB,cAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,aAAK,aAAa,mBAAmB,OAAO;AAC5C,aAAK,aAAa,cAAc,QAAQ,EAAE;AAC1C,aAAK,QAAQ,sBAAsB,QAAQ;AAC3C,aAAK,QAAQ,wBAAwB,QAAQ;AAC7C,aAAK,YAAY,OAAO;AAExB,YAAI,eAAe;AACjB,gBAAM,WAAO,0BAAW,IAAI;AAC5B,wBAAc,QAAQ,IAAI,MAAM,IAAI;AACpC,eAAK;AAAA,YACH,2EACG,wBAAc,SAAS;AAAA,cACtB,UAAU,MAAM,kBAAkB,QAAQ,EAAE;AAAA,YAC9C,CAAC,GACH;AAAA,UACF;AAAA,QACF,OAAO;AACL,gBAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,gBAAM,YAAY;AAClB,gBAAM,cAAc,QAAQ,eAAe,QAAQ;AACnD,gBAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,gBAAM,YAAY;AAClB,gBAAM,YAAY;AAClB,gBAAM,UAAU,CAAC,UAAU;AACzB,kBAAM,eAAe;AACrB,kBAAM,gBAAgB;AACtB,8BAAkB,QAAQ,EAAE;AAAA,UAC9B;AACA,eAAK,OAAO,OAAO,KAAK;AAAA,QAC1B;AACA,eAAO;AAAA,MACT;AAAA,MACA,CAAC,mBAAmB,eAAe,OAAO,SAAS;AAAA,IACrD;AAEA,UAAM,0BAAsB;AAAA,MAC1B,CAAC,UAAiC;AAChC,cAAM,SAAS,UAAU;AACzB,YAAI,CAAC;AAAQ;AAEb,eAAO,iBAAiB,IAAI,eAAe,EAAE,QAAQ,CAAC,SAAS;AAxRvE;AAyRU,8BAAc,QAAQ,IAAI,IAAI,MAA9B,mBAAiC;AAAA,QACnC,CAAC;AACD,eAAO,YAAY;AAEnB,cAAM,QAAQ,CAAC,SAAS;AACtB,cAAI,KAAK,SAAS,QAAQ;AACxB,gBAAI,KAAK;AAAM,qBAAO,YAAY,eAAe,KAAK,IAAI,CAAC;AAC3D;AAAA,UACF;AACA,gBAAM,UAAU,KAAK,SAAS,YAAY,KAAK,UAAU,KAAK;AAC9D,iBAAO,OAAO,iBAAiB,OAAO,GAAG,eAAe,UAAU,CAAC;AAAA,QACrE,CAAC;AAAA,MACH;AAAA,MACA,CAAC,gBAAgB;AAAA,IACnB;AAEA,UAAM,yBAAqB,0BAAY,CAAC,SAAe;AAzS3D;AA0SM,YAAM,QAAQ,SAAS,YAAY;AACnC,YAAM,YAAY,OAAO,aAAa;AACtC,YAAM,SAAS,QAAM,UAAK,gBAAL,mBAAkB,WAAU,CAAC;AAClD,YAAM,SAAS,IAAI;AACnB,6CAAW;AACX,6CAAW,SAAS;AACpB,oBAAc,UAAU,MAAM,WAAW;AAAA,IAC3C,GAAG,CAAC,CAAC;AAEL,UAAM,yBAAqB,0BAAY,MAAM;AAC3C,YAAM,SAAS,UAAU;AACzB,YAAM,YAAY,OAAO,aAAa;AACtC,UAAI,CAAC,UAAU,CAAC,aAAa,UAAU,eAAe;AAAG;AACzD,YAAM,QAAQ,UAAU,WAAW,CAAC;AACpC,UACE,CAAC,OAAO,SAAS,MAAM,cAAc,KACrC,CAAC,OAAO,SAAS,MAAM,YAAY,GACnC;AACA;AAAA,MACF;AACA,oBAAc,UAAU,MAAM,WAAW;AAAA,IAC3C,GAAG,CAAC,CAAC;AAEL,UAAM,+BAA2B;AAAA,MAC/B,CAAC,SAAe;AACd,cAAM,SAAS,UAAU;AACzB,YAAI,CAAC,UAAU,CAAC,OAAO,SAAS,IAAI;AAAG;AACvC,eAAO,MAAM;AACb,2BAAmB,IAAI;AAAA,MACzB;AAAA,MACA,CAAC,kBAAkB;AAAA,IACrB;AAEA,UAAM,gBAAgB,CAAC,SACrB,gBAAgB,eAAe,KAAK,aAAa,YAAY;AAE/D,UAAM,kBAAkB,CAAC,SAAiB,cAAc,IAAI,MAAM;AAGlE,UAAM,wBAAwB,CAAC,UAAiB;AAC9C,YAAM,YAAY,MAAM;AACxB,UAAI,UAAU,aAAa,KAAK,WAAW;AACzC,cAAM,OAAO,UAAU,eAAe;AACtC,cAAM,eAAe,KAAK,MAAM,GAAG,MAAM,WAAW;AACpD,YACE,gBAAgB,YAAY,KAC5B,cAAc,UAAU,eAAe,GACvC;AACA,iBAAO,UAAU;AAAA,QACnB;AAAA,MACF;AAEA,UAAI,qBAAqB,aAAa;AACpC,cAAM,WAAW,UAAU,WAAW,MAAM,cAAc,CAAC;AAC3D,YAAI,cAAc,QAAQ;AAAG,iBAAO;AACpC,aACE,qCAAU,cAAa,KAAK,aAC5B,gBAAgB,SAAS,eAAe,EAAE,KAC1C,cAAc,SAAS,eAAe,GACtC;AACA,iBAAO,SAAS;AAAA,QAClB;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAEA,UAAM,uBAAuB,CAAC,UAAiB;AAC7C,YAAM,YAAY,MAAM;AACxB,UAAI,UAAU,aAAa,KAAK,WAAW;AACzC,cAAM,OAAO,UAAU,eAAe;AACtC,cAAM,cAAc,KAAK,MAAM,MAAM,WAAW;AAChD,YACE,gBAAgB,WAAW,KAC3B,cAAc,UAAU,WAAW,GACnC;AACA,iBAAO,UAAU;AAAA,QACnB;AAAA,MACF;AAEA,UAAI,qBAAqB,aAAa;AACpC,cAAM,OAAO,UAAU,WAAW,MAAM,WAAW;AACnD,YAAI,cAAc,IAAI;AAAG,iBAAO;AAChC,aACE,6BAAM,cAAa,KAAK,aACxB,gBAAgB,KAAK,eAAe,EAAE,KACtC,cAAc,KAAK,WAAW,GAC9B;AACA,iBAAO,KAAK;AAAA,QACd;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAEA,UAAM,8BAA0B;AAAA,MAC9B,CAAC,SAAsB,cAAkC;AA1Y/D;AA2YQ,cAAM,SAAS,UAAU;AACzB,cAAM,YAAY,OAAO,aAAa;AACtC,YAAI,CAAC,UAAU,CAAC,aAAa,CAAC,OAAO,SAAS,OAAO;AAAG;AAExD,cAAM,QAAQ,SAAS,YAAY;AACnC,YAAI,cAAc,UAAU;AAC1B,gBAAM,WAAW,QAAQ;AACzB,eAAI,qCAAU,cAAa,KAAK,WAAW;AACzC,kBAAM,SAAS,YAAU,cAAS,gBAAT,mBAAsB,WAAU,CAAC;AAAA,UAC5D,OAAO;AACL,kBAAM,eAAe,OAAO;AAAA,UAC9B;AAAA,QACF,OAAO;AACL,gBAAM,OAAO,QAAQ;AACrB,eAAI,6BAAM,cAAa,KAAK,WAAW;AACrC,kBAAM,uBACH,WAAK,eAAe,IAAI,MAAM,UAAU,MAAxC,mBAA4C,GAAG,WAAU;AAC5D,kBAAM,SAAS,MAAM,kBAAkB;AAAA,UACzC,OAAO;AACL,kBAAM,cAAc,OAAO;AAAA,UAC7B;AAAA,QACF;AAEA,cAAM,SAAS,IAAI;AACnB,kBAAU,gBAAgB;AAC1B,kBAAU,SAAS,KAAK;AACxB,sBAAc,UAAU,MAAM,WAAW;AAAA,MAC3C;AAAA,MACA,CAAC;AAAA,IACH;AAGA,UAAM,wBAAoB,0BAAY,MAAM;AAC1C,YAAM,SAAS,UAAU;AACzB,YAAM,YAAY,OAAO,aAAa;AACtC,UAAI,CAAC,UAAU,CAAC,aAAa,UAAU,eAAe;AAAG,eAAO;AAChE,YAAM,QAAQ,UAAU,WAAW,CAAC;AACpC,UAAI,SAAS;AACb,UAAI,QAAQ;AAEZ,YAAM,QAAQ,CAAC,SAAe;AAC5B,YAAI;AAAO;AACX,YAAI,SAAS,MAAM,gBAAgB;AACjC,cAAI,KAAK,aAAa,KAAK,WAAW;AACpC,sBAAU;AAAA,eACP,KAAK,eAAe,IAAI,MAAM,GAAG,MAAM,WAAW;AAAA,YACrD;AAAA,UACF;AACA,kBAAQ;AACR;AAAA,QACF;AACA,YAAI,gBAAgB,eAAe,KAAK,aAAa,YAAY;AAC/D;AACF,YAAI,KAAK,aAAa,KAAK,WAAW;AACpC,oBAAU,eAAe,KAAK,eAAe,EAAE;AAC/C;AAAA,QACF;AACA,aAAK,WAAW,QAAQ,KAAK;AAAA,MAC/B;AAEA,aAAO,WAAW,QAAQ,KAAK;AAC/B,aAAO;AAAA,IACT,GAAG,CAAC,CAAC;AAEL,UAAM,eAAe,CAAC,SAAe;AACnC,UAAI,QAAQ;AACZ,UAAI,UAAU;AACd,aAAO,QAAQ,iBAAiB;AAC9B,iBAAS;AACT,kBAAU,QAAQ;AAAA,MACpB;AACA,aAAO;AAAA,IACT;AAIA,UAAM,uBAAmB,0BAAY,CAAC,OAAe,QAA8B;AACjF,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC;AAAQ,eAAO;AACpB,UAAI,SAAS;AACb,UAAI,cAA4B;AAChC,YAAM,QAAQ,MAAM,KAAK,OAAO,UAAU;AAC1C,YAAM,QAAQ,CAAC,SAAS;AACtB,YAAI,KAAK,aAAa,KAAK;AAAW;AACtC,cAAM,OAAO,KAAK,eAAe;AACjC,cAAM,YAAY;AAClB,cAAM,cAAc,eAAe,IAAI;AACvC,cAAM,UAAU,SAAS;AACzB,iBAAS;AACT,YAAI,WAAW,SAAS,aAAa;AAAK;AAC1C,cAAM,WAAW,YAAY,MAAM,KAAK,IAAI,GAAG,QAAQ,SAAS,CAAC;AACjE,cAAM,SAAS,YAAY,MAAM,KAAK,IAAI,GAAG,MAAM,SAAS,CAAC;AAC7D,cAAM,WAAW,KAAK,MAAM,GAAG,QAAQ;AACvC,cAAM,YAAY,KAAK,MAAM,MAAM;AACnC,cAAM,SAAS,KAAK;AACpB,cAAM,YAAY,aAAa,IAAI;AAEnC,aAAK,cAAc,GAAG,WAAW;AACjC,YAAI,CAAC,aAAa;AAChB,wBAAc,SAAS,YAAY;AACnC,cAAI,KAAK,aAAa;AACpB,wBAAY,SAAS,MAAM,QAAQ;AAAA,UACrC,WAAW,QAAQ;AACjB,wBAAY,SAAS,QAAQ,SAAS;AAAA,UACxC;AACA,sBAAY,SAAS,IAAI;AAAA,QAC3B;AACA,YAAI,CAAC,KAAK;AAAa,eAAK,OAAO;AAAA,MACrC,CAAC;AAED,aAAO;AAAA,IACT,GAAG,CAAC,CAAC;AAGL,UAAM,4BAAwB,0BAAY,MAAM;AAC9C,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC;AAAQ;AACb,YAAM,KAAK,OAAO,UAAU,EAAE,QAAQ,CAAC,SAAS;AAC9C,YAAI,KAAK,aAAa,KAAK;AAAW;AACtC,cAAM,OAAO,KAAK,eAAe;AACjC,YAAI,CAAC,MAAM;AACT,eAAK,OAAO;AACZ;AAAA,QACF;AACA,YAAI,QAAQ,cAAc,IAAI,MAAM,IAAI;AACtC,eAAK,cAAc;AAAA,QACrB;AAAA,MACF,CAAC;AAAA,IACH,GAAG,CAAC,CAAC;AAIL,UAAM,kCAA8B,0BAAY,MAAM;AACpD,YAAM,SAAS,UAAU;AACzB,YAAM,YAAY,OAAO,aAAa;AACtC,UAAI,CAAC;AAAQ;AAEb,YAAM,KAAK,OAAO,QAAQ,EAAE,QAAQ,CAAC,SAAS;AAC5C,YAAI,KAAK,aAAa,YAAY;AAAG;AACrC,YAAI,KAAK,cAAc,IAAI,eAAe;AAAG;AAC7C,YAAI,cAAc,KAAK,eAAe,EAAE;AAAG;AAE3C,cAAM,SAAQ,uCAAW,cAAa,UAAU,WAAW,CAAC,IAAI;AAChE,cAAM,YAAY,aAAa,IAAI;AACnC,cAAM,iBAAiB;AAAA,UACrB,SACA,MAAM,cACL,MAAM,mBAAmB,QACxB,KAAK,SAAS,MAAM,cAAc,KACjC,MAAM,mBAAmB,WACvB,MAAM,gBAAgB,aACrB,MAAM,gBAAgB,YAAY;AAAA,QAC1C;AAEA,YAAI,kBAAkB,WAAW;AAG/B,gBAAM,YAAY,eAAe,UAAU;AAC3C,eAAK,YAAY,SAAS;AAC1B,gBAAM,YAAY,SAAS,YAAY;AACvC,oBAAU,SAAS,WAAW,WAAW,MAAM;AAC/C,oBAAU,SAAS,IAAI;AACvB,oBAAU,gBAAgB;AAC1B,oBAAU,SAAS,SAAS;AAC5B,wBAAc,UAAU,UAAU,WAAW;AAC7C;AAAA,QACF;AAEA,aAAK,OAAO;AAAA,MACd,CAAC;AAAA,IACH,GAAG,CAAC,CAAC;AAEL,gCAAU,MAAM;AACd,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC;AAAQ;AAIb,YAAM,qBAAqB,CAAC,UAAiB;AAC3C,YAAI,EAAE,iBAAiB;AAAa;AACpC,YAAI,CAAC,MAAM,UAAU,WAAW,QAAQ;AAAG;AAC3C,YAAI,0BAA0B,YAAY,MAAM;AAC9C,iBAAO,qBAAqB,0BAA0B,OAAO;AAAA,QAC/D;AACA,kCAA0B,UAAU,OAAO,sBAAsB,MAAM;AACrE,oCAA0B,UAAU;AACpC,sCAA4B;AAC5B,gCAAsB;AAAA,QACxB,CAAC;AAAA,MACH;AAEA,aAAO,iBAAiB,SAAS,kBAAkB;AACnD,aAAO,MAAM,OAAO,oBAAoB,SAAS,kBAAkB;AAAA,IACrE,GAAG,CAAC,uBAAuB,2BAA2B,CAAC;AAEvD,UAAM,oBAAgB;AAAA,MACpB,CAAC,SAAqB,YAA6C;AACjE,cAAM,SAAS,UAAU;AACzB,YAAI,CAAC;AAAQ;AAGb,cAAM,uBAAuB,OAAO,aAAa;AACjD,cAAM,0BACJ,6DAAsB,eACtB,OAAO,SAAS,qBAAqB,WAAW,CAAC,EAAE,cAAc,IAC7D,qBAAqB,WAAW,CAAC,EAAE,WAAW,IAC9C;AACN,cAAM,wBACJ,cAAc,WACd,OAAO,SAAS,cAAc,QAAQ,cAAc,IAChD,cAAc,QAAQ,WAAW,IACjC;AACN,cAAM,mBACJ,0BAA0B;AAE5B,eAAO,MAAM;AACb,0BAAkB,UAAU;AAAA,UAC1B,GAAG,kBAAkB,QAAQ,OAAO,CAAC,SAAS,KAAK,OAAO,QAAQ,EAAE;AAAA,UACpE;AAAA,QACF;AACA,YAAI,cAA4B;AAChC,YAAI,SAAS;AACX,wBAAc,iBAAiB,QAAQ,OAAO,QAAQ,GAAG;AACzD,gCAAsB;AAAA,QACxB;AAGA,cAAM,sBACJ,CAAC,aAAa,KAAK,CAAC,OAAO,cAAc,IAAI,eAAe;AAC9D,YAAI,qBAAqB;AACvB,iBAAO,YAAY;AACnB,wBAAc,UAAU;AACxB,wBAAc;AAAA,QAChB;AACA,cAAM,cAAc,iBAAiB,OAAO;AAC5C,cAAM,YAAY,eAAe,UAAU;AAC3C,cAAM,QAAQ,eAAe;AAC7B,YAAI,SAAS,OAAO,SAAS,MAAM,cAAc,GAAG;AAElD,gBAAM,WAAW,SAAS,uBAAuB;AACjD,mBAAS,OAAO,aAAa,SAAS;AACtC,gBAAM,WAAW,QAAQ;AAAA,QAC3B,OAAO;AACL,iBAAO,OAAO,aAAa,SAAS;AAAA,QACtC;AACA,8BAAsB;AACtB,6BAAqB,UAAU;AAC/B,2BAAmB,SAAS;AAC5B,mBAAW;AAIX,eAAO,sBAAsB,MAAM;AACjC,cAAI,qBAAqB,YAAY,WAAW;AAC9C,qCAAyB,SAAS;AAAA,UACpC;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,gCAAU,MAAM;AACd,eAAS,iBAAiB,mBAAmB,kBAAkB;AAC/D,aAAO,MAAM;AACX,iBAAS,oBAAoB,mBAAmB,kBAAkB;AAAA,MACpE;AAAA,IACF,GAAG,CAAC,kBAAkB,CAAC;AAEvB;AAAA,MACE,MAAM,MAAM;AACV,YAAI,0BAA0B,YAAY,MAAM;AAC9C,iBAAO,qBAAqB,0BAA0B,OAAO;AAAA,QAC/D;AAAA,MACF;AAAA,MACA,CAAC;AAAA,IACH;AAEA;AAAA,MACE;AAAA,MACA,OAAO;AAAA,QACL,OAAO,MAAG;AA3qBlB;AA2qBqB,iCAAU,YAAV,mBAAmB;AAAA;AAAA,QAChC,SAAS;AAAA,QACT;AAAA,QACA,iBAAiB;AAAA,QACjB,iBAAiB,CAAC,EAAE,OAAO,IAAI,MAAM;AACnC,gBAAM,QAAQ,iBAAiB,OAAO,GAAG;AACzC,gCAAsB;AACtB,cAAI,OAAO;AACT,kBAAM,YAAY,OAAO,aAAa;AACtC,mDAAW;AACX,mDAAW,SAAS;AACpB,0BAAc,UAAU,MAAM,WAAW;AAAA,UAC3C;AACA,qBAAW;AAAA,QACb;AAAA,QACA;AAAA,QACA,WAAW;AAAA,MACb;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,8BAA0B,MAAM;AAC9B,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC;AAAQ;AAGb,UACE,CAAC,4BAA4B,YAC7B,uDAAmB,WACnB,CAAC,SACD,SAAS,WAAW,GACpB;AACA,oCAA4B,UAAU;AAGtC,gCAAwB,UAAU;AAClC,4BAAoB,iBAAiB;AACrC,mBAAW;AACX;AAAA,MACF;AAEA,YAAM,qBAAqB,SACxB,IAAI,CAAC,YAAY,QAAQ,EAAE,EAC3B,KAAK,GAAG;AACX,YAAM,mBAAmB,oBAAoB;AAC7C,YAAM,2BACJ,UAAU,iBAAiB,SAC3B,uBAAuB,iBAAiB;AAE1C,UAAI,4BAA4B,OAAO,WAAW,SAAS;AAAG;AAE9D,0BAAoB;AAAA,QAClB,GAAI,QAAQ,CAAC,EAAE,MAAM,QAAiB,MAAM,MAAM,CAAC,IAAI,CAAC;AAAA,QACxD,GAAG,SAAS,IAAI,CAAC,aAAa,EAAE,MAAM,WAAoB,QAAQ,EAAE;AAAA,MACtE,CAAC;AACD,oBAAc,QAAQ,SAAS,SAAS,MAAM,CAAC;AAG/C,YAAM,eAAe,MAAM,KAAK,OAAO,UAAU,EAC9C,QAAQ,EACR,KAAK,CAAC,SAAuB,KAAK,aAAa,KAAK,SAAS;AAChE,UAAI,SAAS,kBAAkB,UAAU,cAAc;AACrD,2BAAmB,YAAY;AAAA,MACjC;AAAA,IACF,GAAG;AAAA,MACD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,8BAA0B,MAAM;AAC9B,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC;AAAQ;AACb,UAAI,wBAAwB,SAAS;AACnC,gCAAwB,UAAU;AAClC;AAAA,MACF;AACA,UAAI,CAAC,SAAS,SAAS,WAAW,KAAK,OAAO,WAAW,SAAS,GAAG;AACnE,eAAO,iBAAiB,IAAI,eAAe,EAAE,QAAQ,CAAC,SAAS;AApwBvE;AAqwBU,8BAAc,QAAQ,IAAI,IAAI,MAA9B,mBAAiC;AAAA,QACnC,CAAC;AACD,eAAO,YAAY;AAAA,MACrB;AAAA,IACF,GAAG,CAAC,SAAS,QAAQ,KAAK,CAAC;AAE3B,UAAM,cAAc,MAAM;AACxB,UAAI,CAAC,aAAa,SAAS;AACzB,oCAA4B;AAC5B,8BAAsB;AACtB,mBAAW;AAGX,YAAI,0BAA0B,YAAY,MAAM;AAC9C,iBAAO,qBAAqB,0BAA0B,OAAO;AAAA,QAC/D;AACA,kCAA0B,UAAU,OAAO,sBAAsB,MAAM;AACrE,oCAA0B,UAAU;AACpC,sCAA4B;AAC5B,gCAAsB;AAAA,QACxB,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,cAA2D,CAC/D,UACG;AACH,YAAM,eAAe;AACrB,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC;AAAQ;AAGb,YAAM,OAAO,MAAM,cAAc,QAAQ,YAAY;AACrD,UAAI,CAAC;AAAM;AACX,YAAM,YAAQ,2DAAkC,IAAI;AACpD,YAAM,YAAY,OAAO,aAAa;AACtC,YAAM,SACJ,uCAAW,eACX,OAAO,SAAS,UAAU,WAAW,CAAC,EAAE,cAAc,IAClD,UAAU,WAAW,CAAC,IACtB;AACN,YAAM,WAAW,SAAS,uBAAuB;AACjD,UAAI,eAA4B;AAEhC,iBAAW,QAAQ,OAAO;AACxB,YAAI,KAAK,SAAS,QAAQ;AACxB,yBAAe,eAAe,KAAK,IAAI;AACvC,mBAAS,OAAO,YAAY;AAC5B;AAAA,QACF;AACA,0BAAkB,UAAU;AAAA,UAC1B,GAAG,kBAAkB;AAAA,UACrB,KAAK;AAAA,QACP;AACA,iBAAS,OAAO,iBAAiB,KAAK,OAAO,CAAC;AAC9C,uBAAe,eAAe,UAAU;AACxC,iBAAS,OAAO,YAAY;AAAA,MAC9B;AAEA,UAAI,OAAO;AACT,cAAM,eAAe;AACrB,cAAM,WAAW,QAAQ;AAAA,MAC3B,OAAO;AACL,eAAO,OAAO,QAAQ;AAAA,MACxB;AACA,4BAAsB;AACtB,UAAI;AAAc,2BAAmB,YAAY;AACjD,iBAAW;AAAA,IACb;AAEA,UAAM,gBAA4D,CAChE,UACG;AACH,UAAI,MAAM,QAAQ,eAAe,MAAM,QAAQ,cAAc;AAC3D,cAAM,YAAY,OAAO,aAAa;AACtC,YAAI,uCAAW,YAAY;AACzB,gBAAM,QAAQ,UAAU,WAAW,CAAC;AACpC,cAAI,MAAM,WAAW;AACnB,kBAAM,gBACJ,MAAM,QAAQ,cACV,sBAAsB,KAAK,IAC3B,qBAAqB,KAAK;AAEhC,gBAAI,eAAe;AACjB,oBAAM,eAAe;AACrB;AAAA,gBACE;AAAA,gBACA,MAAM,QAAQ,cAAc,WAAW;AAAA,cACzC;AACA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,UAAI,MAAM,QAAQ,eAAe,MAAM,QAAQ,UAAU;AACvD,cAAM,YAAY,OAAO,aAAa;AACtC,YAAI,uCAAW,YAAY;AACzB,gBAAM,QAAQ,UAAU,WAAW,CAAC;AACpC,cAAI,MAAM,WAAW;AACnB,kBAAM,gBACJ,MAAM,QAAQ,cACV,sBAAsB,KAAK,IAC3B,qBAAqB,KAAK;AAEhC,gBAAI,eAAe;AACjB,oBAAM,eAAe;AACrB;AAAA,gBACE,cAAc,QAAQ,uBAAuB;AAAA,cAC/C;AACA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,6CAAY;AAAA,IACd;AAGA,UAAM,kBAAkB,CAAC;AAEzB,WACE,6CAAC,SAAI,WAAW,OAAO,oBACpB;AAAA,yBAAmB,eAClB,4CAAC,SAAI,WAAW,OAAO,mBAAoB,uBAAY;AAAA,MAEzD;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,WAAW,OAAO;AAAA,UAClB,iBAAiB,CAAC;AAAA,UAClB,gCAA8B;AAAA,UAC9B,MAAK;AAAA,UACL,kBAAe;AAAA,UACf,SAAS;AAAA,UACT,SAAS;AAAA,UACT,WAAW;AAAA,UACX,SAAS,CAAC,UAAU;AAClB,wCAA4B;AAC5B,kCAAsB;AACtB,+BAAmB;AACnB,+CAAU;AAAA,UACZ;AAAA,UACA,WAAW;AAAA,UACX,SAAS;AAAA,UACT,oBAAoB,MAAM;AACxB,yBAAa,UAAU;AAEvB,0BAAc,IAAI;AAAA,UACpB;AAAA,UACA,kBAAkB,MAAM;AACtB,yBAAa,UAAU;AACvB,uBAAW;AAAA,UACb;AAAA,UACA,sBAAoB,kBAAkB;AAAA;AAAA,MACxC;AAAA,OACF;AAAA,EAEJ;AACF;AAEA,eAAe,cAAc;AAE7B,IAAO,yBAAQ;",
|
|
4
|
+
"sourcesContent": ["import React, {\n forwardRef,\n useCallback,\n useEffect,\n useLayoutEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport type {\n InlineTagRenderInfo,\n MentionTag,\n XAdkSenderInputPart,\n XAdkSenderSubmitPart,\n} from \"@/types\";\nimport { useStyles } from \"./styles\";\nimport { parseMarkdownResourceLinksAsParts } from \"@/utils/markdownResource\";\n\nexport interface InlineTagInputRef {\n focus: () => void;\n getText: () => string;\n getParts: () => XAdkSenderSubmitPart[];\n getCursorOffset: () => number;\n deleteTextRange: (range: { start: number; end: number }) => void;\n insertMention: (\n mention: MentionTag,\n replace?: { start: number; end: number },\n ) => void;\n /** @deprecated 请使用 insertMention。 */\n insertTag: (\n mention: MentionTag,\n replace?: { start: number; end: number },\n ) => void;\n}\n\nexport interface InlineTagInputProps {\n value: string;\n mentions: MentionTag[];\n defaultInputParts?: XAdkSenderInputPart[];\n placeholder?: string;\n disabled?: boolean;\n onChange: (value: string) => void;\n onMentionsChange: (mentions: MentionTag[]) => void;\n onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;\n onKeyUp?: React.KeyboardEventHandler<HTMLDivElement>;\n renderMention?: (\n mention: MentionTag,\n info: InlineTagRenderInfo,\n ) => React.ReactNode;\n}\n\nconst MENTION_ATTR = \"data-xadk-inline-mention-id\";\n// contenteditable 无法把光标放进 contenteditable=false 的 Mention 里,需用零宽字符承接“Mention 后方”的光标。\nconst CARET_TEXT = \"\\u200B\";\n\nconst createTextNode = (text: string) => document.createTextNode(text);\nconst useIsomorphicLayoutEffect =\n typeof window === \"undefined\" ? useEffect : useLayoutEffect;\nconst normalizeText = (text: string) =>\n text.replace(/\\u200B/g, \"\").replace(/\\u00a0/g, \" \");\nconst getPlainLength = (text: string) => normalizeText(text).length;\n// DOM 文本里包含零宽光标锚点,快捷键替换和光标定位都要在“用户可见文本 offset”和 DOM raw offset 之间转换。\nconst toRawOffset = (text: string, plainOffset: number) => {\n let current = 0;\n for (let i = 0; i < text.length; i++) {\n if (current >= plainOffset) return i;\n if (text[i] !== CARET_TEXT) current += 1;\n }\n return text.length;\n};\n\n// 内联标签展示逻辑\nconst InlineTagInput = forwardRef<InlineTagInputRef, InlineTagInputProps>(\n (\n {\n value,\n mentions,\n defaultInputParts,\n placeholder,\n disabled,\n onChange,\n onMentionsChange,\n onKeyDown,\n onKeyUp,\n renderMention,\n },\n ref,\n ) => {\n const styles = useStyles();\n const editorRef = useRef<HTMLDivElement>(null);\n const latestMentionsRef = useRef<MentionTag[]>(mentions);\n const tagRootMapRef = useRef<WeakMap<Element, Root>>(new WeakMap());\n const composingRef = useRef(false);\n const lastInsertedCaretRef = useRef<Text | null>(null);\n const savedRangeRef = useRef<Range | null>(null);\n const defaultInputPartsAppliedRef = useRef(false);\n const skipEmptyCleanupOnceRef = useRef(false);\n const structuralCleanupFrameRef = useRef<number | null>(null);\n const [hasContent, setHasContent] = useState(() =>\n Boolean(value || mentions.length),\n );\n const lastEmittedStateRef = useRef({\n value,\n mentionIds: mentions.map((mention) => mention.id).join(\"|\"),\n });\n\n useEffect(() => {\n latestMentionsRef.current = mentions;\n }, [mentions]);\n\n const getOrderedMentions = useCallback(() => {\n const editor = editorRef.current;\n if (!editor) return [];\n const mentionMap = new Map(\n latestMentionsRef.current.map((mention) => [mention.id, mention]),\n );\n return Array.from(editor.querySelectorAll(`[${MENTION_ATTR}]`))\n .map((node) =>\n mentionMap.get(\n (node as HTMLElement).dataset.xadkInlineMentionId || \"\",\n ),\n )\n .filter(Boolean) as MentionTag[];\n }, []);\n\n // 对外只暴露用户输入的纯文本,内部零宽锚点不进入 value。\n const getPlainText = useCallback(() => {\n const editor = editorRef.current;\n if (!editor) return \"\";\n let text = \"\";\n editor.childNodes.forEach((node) => {\n if (node.nodeType === Node.TEXT_NODE) {\n text += node.textContent || \"\";\n }\n });\n return normalizeText(text);\n }, []);\n\n // 提交时需要保留文本与 Mention 的真实顺序;仅靠 value + mentions 无法区分 Mention 在句首、句中还是句尾。\n const getParts = useCallback((): XAdkSenderSubmitPart[] => {\n const editor = editorRef.current;\n if (!editor) return [];\n const mentionMap = new Map(\n latestMentionsRef.current.map((mention) => [mention.id, mention]),\n );\n const parts: XAdkSenderSubmitPart[] = [];\n\n editor.childNodes.forEach((node) => {\n if (node.nodeType === Node.TEXT_NODE) {\n const text = normalizeText(node.textContent || \"\");\n if (text) parts.push({ type: \"text\", text });\n return;\n }\n\n if (node instanceof HTMLElement && node.hasAttribute(MENTION_ATTR)) {\n const mentionId = node.dataset.xadkInlineMentionId || \"\";\n const mention = mentionMap.get(mentionId);\n if (mention) parts.push({ type: \"mention\", mention });\n }\n });\n\n return parts;\n }, []);\n\n const emitChange = useCallback(() => {\n const nextValue = getPlainText();\n const nextMentions = getOrderedMentions();\n setHasContent(Boolean(nextValue || nextMentions.length));\n lastEmittedStateRef.current = {\n value: nextValue,\n mentionIds: nextMentions.map((mention) => mention.id).join(\"|\"),\n };\n onChange(nextValue);\n onMentionsChange(nextMentions);\n }, [getOrderedMentions, getPlainText, onChange, onMentionsChange]);\n\n const removeTextRange = useCallback(\n (node: Text, start: number, end: number) => {\n const text = node.textContent || \"\";\n node.textContent = `${text.slice(0, start)}${text.slice(end)}`;\n if (!node.textContent) node.remove();\n },\n [],\n );\n\n const removeMentionNode = useCallback(\n (node: Element) => {\n const previous = node.previousSibling;\n const next = node.nextSibling;\n\n tagRootMapRef.current.get(node)?.unmount();\n node.remove();\n\n // Mention 后会补一个不可见光标锚点;删除 Mention 时同步清理,避免留下冗余节点。\n if (next?.nodeType === Node.TEXT_NODE) {\n const text = next.textContent || \"\";\n const caretLength = text.match(/^\\u200B+/)?.[0].length || 0;\n if (caretLength > 0) {\n removeTextRange(next as Text, 0, caretLength);\n return;\n }\n }\n\n if (previous?.nodeType === Node.TEXT_NODE) {\n const text = previous.textContent || \"\";\n const spaceLength = text.match(/\\s+$/)?.[0].length || 0;\n if (spaceLength > 0) {\n removeTextRange(\n previous as Text,\n text.length - spaceLength,\n text.length,\n );\n }\n }\n },\n [removeTextRange],\n );\n\n const removeMentionById = useCallback(\n (id: string) => {\n const editor = editorRef.current;\n const node = Array.from(\n editor?.querySelectorAll(`[${MENTION_ATTR}]`) || [],\n ).find(\n (item) => (item as HTMLElement).dataset.xadkInlineMentionId === id,\n );\n if (node) {\n removeMentionNode(node);\n }\n emitChange();\n editor?.focus();\n },\n [emitChange, removeMentionNode],\n );\n\n // Mention 节点本身不可编辑;删除入口通过 onRemove 回到组件内部统一维护 DOM 与 mentions。\n const buildMentionNode = useCallback(\n (mention: MentionTag) => {\n const span = document.createElement(\"span\");\n span.setAttribute(\"contenteditable\", \"false\");\n span.setAttribute(MENTION_ATTR, mention.id);\n span.dataset.xadkInlineMentionId = mention.id;\n span.dataset.xadkInlineMentionType = mention.type;\n span.className = styles.inlineTag;\n\n if (renderMention) {\n const root = createRoot(span);\n tagRootMapRef.current.set(span, root);\n root.render(\n <>\n {renderMention(mention, {\n onRemove: () => removeMentionById(mention.id),\n })}\n </>,\n );\n } else {\n const label = document.createElement(\"span\");\n label.className = \"xadk-inline-tag-label\";\n label.textContent = mention.displayName || mention.label;\n const close = document.createElement(\"span\");\n close.className = \"xadk-inline-tag-close\";\n close.innerHTML = \"×\";\n close.onclick = (event) => {\n event.preventDefault();\n event.stopPropagation();\n removeMentionById(mention.id);\n };\n span.append(label, close);\n }\n return span;\n },\n [removeMentionById, renderMention, styles.inlineTag],\n );\n\n const renderPartsToEditor = useCallback(\n (parts: XAdkSenderInputPart[]) => {\n const editor = editorRef.current;\n if (!editor) return;\n\n editor.querySelectorAll(`[${MENTION_ATTR}]`).forEach((node) => {\n tagRootMapRef.current.get(node)?.unmount();\n });\n editor.innerHTML = \"\";\n\n parts.forEach((part) => {\n if (part.type === \"text\") {\n if (part.text) editor.appendChild(createTextNode(part.text));\n return;\n }\n const mention = part.type === \"mention\" ? part.mention : part.tag;\n editor.append(buildMentionNode(mention), createTextNode(CARET_TEXT));\n });\n },\n [buildMentionNode],\n );\n\n const setCursorAtTextEnd = useCallback((node: Text) => {\n const range = document.createRange();\n const selection = window.getSelection();\n range.setStart(node, node.textContent?.length || 0);\n range.collapse(true);\n selection?.removeAllRanges();\n selection?.addRange(range);\n savedRangeRef.current = range.cloneRange();\n }, []);\n\n const saveSelectionRange = useCallback(() => {\n const editor = editorRef.current;\n const selection = window.getSelection();\n if (!editor || !selection || selection.rangeCount === 0) return;\n const range = selection.getRangeAt(0);\n if (\n !editor.contains(range.startContainer) ||\n !editor.contains(range.endContainer)\n ) {\n return;\n }\n savedRangeRef.current = range.cloneRange();\n }, []);\n\n const restoreCursorAfterInsert = useCallback(\n (node: Text) => {\n const editor = editorRef.current;\n if (!editor || !editor.contains(node)) return;\n editor.focus();\n setCursorAtTextEnd(node);\n },\n [setCursorAtTextEnd],\n );\n\n const isMentionNode = (node: Node | null): node is HTMLElement =>\n node instanceof HTMLElement && node.hasAttribute(MENTION_ATTR);\n\n const isOnlyCaretText = (text: string) => normalizeText(text) === \"\";\n\n // Backspace/Delete 需要跨过零宽锚点识别相邻 Mention,不能只看光标所在文本节点。\n const getMentionBeforeRange = (range: Range) => {\n const container = range.startContainer;\n if (container.nodeType === Node.TEXT_NODE) {\n const text = container.textContent || \"\";\n const beforeCursor = text.slice(0, range.startOffset);\n if (\n isOnlyCaretText(beforeCursor) &&\n isMentionNode(container.previousSibling)\n ) {\n return container.previousSibling;\n }\n }\n\n if (container instanceof HTMLElement) {\n const previous = container.childNodes[range.startOffset - 1];\n if (isMentionNode(previous)) return previous;\n if (\n previous?.nodeType === Node.TEXT_NODE &&\n isOnlyCaretText(previous.textContent || \"\") &&\n isMentionNode(previous.previousSibling)\n ) {\n return previous.previousSibling;\n }\n }\n\n return null;\n };\n\n const getMentionAfterRange = (range: Range) => {\n const container = range.startContainer;\n if (container.nodeType === Node.TEXT_NODE) {\n const text = container.textContent || \"\";\n const afterCursor = text.slice(range.startOffset);\n if (\n isOnlyCaretText(afterCursor) &&\n isMentionNode(container.nextSibling)\n ) {\n return container.nextSibling;\n }\n }\n\n if (container instanceof HTMLElement) {\n const next = container.childNodes[range.startOffset];\n if (isMentionNode(next)) return next;\n if (\n next?.nodeType === Node.TEXT_NODE &&\n isOnlyCaretText(next.textContent || \"\") &&\n isMentionNode(next.nextSibling)\n ) {\n return next.nextSibling;\n }\n }\n\n return null;\n };\n\n const moveCursorAroundMention = useCallback(\n (mention: HTMLElement, direction: \"before\" | \"after\") => {\n const editor = editorRef.current;\n const selection = window.getSelection();\n if (!editor || !selection || !editor.contains(mention)) return;\n\n const range = document.createRange();\n if (direction === \"before\") {\n const previous = mention.previousSibling;\n if (previous?.nodeType === Node.TEXT_NODE) {\n range.setStart(previous, previous.textContent?.length || 0);\n } else {\n range.setStartBefore(mention);\n }\n } else {\n const next = mention.nextSibling;\n if (next?.nodeType === Node.TEXT_NODE) {\n const leadingCaretLength =\n (next.textContent || \"\").match(/^\\u200B+/)?.[0].length || 0;\n range.setStart(next, leadingCaretLength);\n } else {\n range.setStartAfter(mention);\n }\n }\n\n range.collapse(true);\n selection.removeAllRanges();\n selection.addRange(range);\n savedRangeRef.current = range.cloneRange();\n },\n [],\n );\n\n // 读取光标在纯文本中的位置,供快捷键搜索词和 Mention 插入位置复用。\n const getOffsetInEditor = useCallback(() => {\n const editor = editorRef.current;\n const selection = window.getSelection();\n if (!editor || !selection || selection.rangeCount === 0) return 0;\n const range = selection.getRangeAt(0);\n let offset = 0;\n let found = false;\n\n const visit = (node: Node) => {\n if (found) return;\n if (node === range.startContainer) {\n if (node.nodeType === Node.TEXT_NODE) {\n offset += getPlainLength(\n (node.textContent || \"\").slice(0, range.startOffset),\n );\n }\n found = true;\n return;\n }\n if (node instanceof HTMLElement && node.hasAttribute(MENTION_ATTR))\n return;\n if (node.nodeType === Node.TEXT_NODE) {\n offset += getPlainLength(node.textContent || \"\");\n return;\n }\n node.childNodes.forEach(visit);\n };\n\n editor.childNodes.forEach(visit);\n return offset;\n }, []);\n\n const getNodeIndex = (node: Node) => {\n let index = 0;\n let current = node;\n while (current.previousSibling) {\n index += 1;\n current = current.previousSibling;\n }\n return index;\n };\n\n // 删除快捷键触发片段,例如把 “@文档” 替换成一个结构化 Mention,并返回删除位置对应的真实 DOM Range。\n // 注意:纯文本 offset 不包含 Mention,Mention 前后可能都是 offset 0;插入 Mention 必须依赖真实 Range,不能再反推 offset。\n const replaceTextRange = useCallback((start: number, end: number): Range | null => {\n const editor = editorRef.current;\n if (!editor) return null;\n let offset = 0;\n let insertRange: Range | null = null;\n const nodes = Array.from(editor.childNodes);\n nodes.forEach((node) => {\n if (node.nodeType !== Node.TEXT_NODE) return;\n const text = node.textContent || \"\";\n const nodeStart = offset;\n const plainLength = getPlainLength(text);\n const nodeEnd = offset + plainLength;\n offset = nodeEnd;\n if (nodeEnd <= start || nodeStart >= end) return;\n const rawStart = toRawOffset(text, Math.max(0, start - nodeStart));\n const rawEnd = toRawOffset(text, Math.max(0, end - nodeStart));\n const keepLeft = text.slice(0, rawStart);\n const keepRight = text.slice(rawEnd);\n const parent = node.parentNode;\n const nodeIndex = getNodeIndex(node);\n\n node.textContent = `${keepLeft}${keepRight}`;\n if (!insertRange) {\n insertRange = document.createRange();\n if (node.textContent) {\n insertRange.setStart(node, rawStart);\n } else if (parent) {\n insertRange.setStart(parent, nodeIndex);\n }\n insertRange.collapse(true);\n }\n if (!node.textContent) node.remove();\n });\n\n return insertRange;\n }, []);\n\n // 浏览器拆分 Range 后可能留下空文本节点;清理后才能保证后续 Mention 继续 append 在队尾。\n const cleanupCaretTextNodes = useCallback(() => {\n const editor = editorRef.current;\n if (!editor) return;\n Array.from(editor.childNodes).forEach((node) => {\n if (node.nodeType !== Node.TEXT_NODE) return;\n const text = node.textContent || \"\";\n if (!text) {\n node.remove();\n return;\n }\n if (text && normalizeText(text) === \"\") {\n node.textContent = CARET_TEXT;\n }\n });\n }, []);\n\n // Chrome 会把标签前临时输入的文字包进块级节点;文字被删空后,可能留下\n // <div><br></div>。它没有消息语义,却会在 contenteditable 中占据一整行。\n const cleanupEmptyStructuralNodes = useCallback(() => {\n const editor = editorRef.current;\n const selection = window.getSelection();\n if (!editor) return;\n\n Array.from(editor.children).forEach((node) => {\n if (node.hasAttribute(MENTION_ATTR)) return;\n if (node.querySelector(`[${MENTION_ATTR}]`)) return;\n if (normalizeText(node.textContent || \"\")) return;\n\n const range = selection?.rangeCount ? selection.getRangeAt(0) : null;\n const nodeIndex = getNodeIndex(node);\n const containsCursor = Boolean(\n range &&\n range.collapsed &&\n (range.startContainer === node ||\n node.contains(range.startContainer) ||\n (range.startContainer === editor &&\n (range.startOffset === nodeIndex ||\n range.startOffset === nodeIndex + 1))),\n );\n\n if (containsCursor && selection) {\n // 光标紧邻 contenteditable=false 的 Mention 时,单纯删除 <br> 会让 Chrome\n // 再次生成它。替换成零宽文本锚点,既能承接光标,也不会增加行高。\n const caretNode = createTextNode(CARET_TEXT);\n node.replaceWith(caretNode);\n const nextRange = document.createRange();\n nextRange.setStart(caretNode, CARET_TEXT.length);\n nextRange.collapse(true);\n selection.removeAllRanges();\n selection.addRange(nextRange);\n savedRangeRef.current = nextRange.cloneRange();\n return;\n }\n\n node.remove();\n });\n }, []);\n\n useEffect(() => {\n const editor = editorRef.current;\n if (!editor) return;\n\n // 某些业务容器会截断 React 委托事件;直接监听编辑器的原生 input,确保删除事务结束后\n // 仍能清理 Chrome 在不可编辑 Mention 前生成的占行 <br>。仅处理 delete*,不影响 Enter 换行。\n const handleNativeDelete = (event: Event) => {\n if (!(event instanceof InputEvent)) return;\n if (!event.inputType.startsWith(\"delete\")) return;\n if (structuralCleanupFrameRef.current !== null) {\n window.cancelAnimationFrame(structuralCleanupFrameRef.current);\n }\n structuralCleanupFrameRef.current = window.requestAnimationFrame(() => {\n structuralCleanupFrameRef.current = null;\n cleanupEmptyStructuralNodes();\n cleanupCaretTextNodes();\n });\n };\n\n editor.addEventListener(\"input\", handleNativeDelete);\n return () => editor.removeEventListener(\"input\", handleNativeDelete);\n }, [cleanupCaretTextNodes, cleanupEmptyStructuralNodes]);\n\n const insertMention = useCallback(\n (mention: MentionTag, replace?: { start: number; end: number }) => {\n const editor = editorRef.current;\n if (!editor) return;\n // 工具栏/弹窗会先抢走焦点;必须在 focus 之前保存当前 Selection,\n // 否则浏览器新建在输入框开头的 Range 会覆盖最后一次真实光标位置。\n const selectionBeforeFocus = window.getSelection();\n const activeRangeBeforeFocus =\n selectionBeforeFocus?.rangeCount &&\n editor.contains(selectionBeforeFocus.getRangeAt(0).startContainer)\n ? selectionBeforeFocus.getRangeAt(0).cloneRange()\n : null;\n const savedRangeBeforeFocus =\n savedRangeRef.current &&\n editor.contains(savedRangeRef.current.startContainer)\n ? savedRangeRef.current.cloneRange()\n : null;\n const rangeBeforeFocus =\n activeRangeBeforeFocus || savedRangeBeforeFocus;\n\n editor.focus();\n latestMentionsRef.current = [\n ...latestMentionsRef.current.filter((item) => item.id !== mention.id),\n mention,\n ];\n let insertRange: Range | null = null;\n if (replace) {\n insertRange = replaceTextRange(replace.start, replace.end);\n cleanupCaretTextNodes();\n }\n // 浏览器会在空 contenteditable 中生成 <div><br> 等占位块。\n // 空编辑器插入首个 Mention 前先清掉这些无语义节点,避免标签被放进第二个视觉行。\n const isSemanticallyEmpty =\n !getPlainText() && !editor.querySelector(`[${MENTION_ATTR}]`);\n if (isSemanticallyEmpty) {\n editor.innerHTML = \"\";\n savedRangeRef.current = null;\n insertRange = null;\n }\n const mentionNode = buildMentionNode(mention);\n const caretNode = createTextNode(CARET_TEXT);\n const range = insertRange || rangeBeforeFocus;\n if (range && editor.contains(range.startContainer)) {\n // 用 DocumentFragment 一次性插入,避免连续 insertNode 导致 mention/caret 顺序被浏览器 Range 状态打乱。\n const fragment = document.createDocumentFragment();\n fragment.append(mentionNode, caretNode);\n range.insertNode(fragment);\n } else {\n editor.append(mentionNode, caretNode);\n }\n cleanupCaretTextNodes();\n lastInsertedCaretRef.current = caretNode;\n setCursorAtTextEnd(caretNode);\n emitChange();\n\n // 关闭快捷列表和父组件同步 mentions/value 会触发一次 React 更新;\n // 下一帧再恢复到刚插入 Mention 后的零宽锚点,避免光标被 focus 或重渲染带回旧位置。\n window.requestAnimationFrame(() => {\n if (lastInsertedCaretRef.current === caretNode) {\n restoreCursorAfterInsert(caretNode);\n }\n });\n },\n [\n buildMentionNode,\n cleanupCaretTextNodes,\n emitChange,\n getPlainText,\n replaceTextRange,\n restoreCursorAfterInsert,\n setCursorAtTextEnd,\n ],\n );\n\n useEffect(() => {\n document.addEventListener(\"selectionchange\", saveSelectionRange);\n return () => {\n document.removeEventListener(\"selectionchange\", saveSelectionRange);\n };\n }, [saveSelectionRange]);\n\n useEffect(\n () => () => {\n if (structuralCleanupFrameRef.current !== null) {\n window.cancelAnimationFrame(structuralCleanupFrameRef.current);\n }\n },\n [],\n );\n\n useImperativeHandle(\n ref,\n () => ({\n focus: () => editorRef.current?.focus(),\n getText: getPlainText,\n getParts,\n getCursorOffset: getOffsetInEditor,\n deleteTextRange: ({ start, end }) => {\n const range = replaceTextRange(start, end);\n cleanupCaretTextNodes();\n if (range) {\n const selection = window.getSelection();\n selection?.removeAllRanges();\n selection?.addRange(range);\n savedRangeRef.current = range.cloneRange();\n }\n emitChange();\n },\n insertMention,\n insertTag: insertMention,\n }),\n [\n cleanupCaretTextNodes,\n emitChange,\n getOffsetInEditor,\n getParts,\n getPlainText,\n insertMention,\n replaceTextRange,\n ],\n );\n\n useIsomorphicLayoutEffect(() => {\n const editor = editorRef.current;\n if (!editor) return;\n\n // 默认片段只在空输入首次挂载时灌入,避免外部重新渲染覆盖用户正在编辑的内容。\n if (\n !defaultInputPartsAppliedRef.current &&\n defaultInputParts?.length &&\n !value &&\n mentions.length === 0\n ) {\n defaultInputPartsAppliedRef.current = true;\n // emitChange 的受控回写要到下一次 render 才生效;跳过本轮紧随其后的空值清理,\n // 避免刚渲染的默认 Mention 被旧的空 value/mentions 立即移除。\n skipEmptyCleanupOnceRef.current = true;\n latestMentionsRef.current = defaultInputParts.flatMap((part) => {\n if (part.type === \"mention\") return [part.mention];\n if (part.type === \"tag\") return [part.tag];\n return [];\n });\n renderPartsToEditor(defaultInputParts);\n setHasContent(true);\n emitChange();\n return;\n }\n\n const incomingMentionIds = mentions\n .map((mention) => mention.id)\n .join(\"|\");\n const lastEmittedState = lastEmittedStateRef.current;\n const isInternalControlledEcho =\n value === lastEmittedState.value &&\n incomingMentionIds === lastEmittedState.mentionIds;\n\n if (isInternalControlledEcho && editor.childNodes.length > 0) return;\n\n renderPartsToEditor([\n ...(value ? [{ type: \"text\" as const, text: value }] : []),\n ...mentions.map((mention) => ({ type: \"mention\" as const, mention })),\n ]);\n setHasContent(Boolean(value || mentions.length));\n\n // 外部主动写入 value/mentions 后,需要在首帧绘制前同步 DOM;若输入区已有焦点,则把光标放在内容末尾。\n const lastTextNode = Array.from(editor.childNodes)\n .reverse()\n .find((node): node is Text => node.nodeType === Node.TEXT_NODE);\n if (document.activeElement === editor && lastTextNode) {\n setCursorAtTextEnd(lastTextNode);\n }\n }, [\n defaultInputParts,\n emitChange,\n renderPartsToEditor,\n setCursorAtTextEnd,\n mentions,\n value,\n ]);\n\n useIsomorphicLayoutEffect(() => {\n const editor = editorRef.current;\n if (!editor) return;\n if (skipEmptyCleanupOnceRef.current) {\n skipEmptyCleanupOnceRef.current = false;\n return;\n }\n if (!value && mentions.length === 0 && editor.childNodes.length > 0) {\n editor.querySelectorAll(`[${MENTION_ATTR}]`).forEach((node) => {\n tagRootMapRef.current.get(node)?.unmount();\n });\n editor.innerHTML = \"\";\n }\n }, [mentions.length, value]);\n\n const handleInput = () => {\n if (!composingRef.current) {\n cleanupEmptyStructuralNodes();\n cleanupCaretTextNodes();\n emitChange();\n\n // Chrome 可能在 input 回调返回后才补上用于承接光标的 <br>;下一帧再归一化一次。\n if (structuralCleanupFrameRef.current !== null) {\n window.cancelAnimationFrame(structuralCleanupFrameRef.current);\n }\n structuralCleanupFrameRef.current = window.requestAnimationFrame(() => {\n structuralCleanupFrameRef.current = null;\n cleanupEmptyStructuralNodes();\n cleanupCaretTextNodes();\n });\n }\n };\n\n const handlePaste: React.ClipboardEventHandler<HTMLDivElement> = (\n event,\n ) => {\n event.preventDefault();\n const editor = editorRef.current;\n if (!editor) return;\n\n // 始终按 text/plain 粘贴,避免消息气泡的背景色等 HTML 样式进入 contenteditable。\n const text = event.clipboardData.getData(\"text/plain\");\n if (!text) return;\n const parts = parseMarkdownResourceLinksAsParts(text);\n const selection = window.getSelection();\n const range =\n selection?.rangeCount &&\n editor.contains(selection.getRangeAt(0).startContainer)\n ? selection.getRangeAt(0)\n : null;\n const fragment = document.createDocumentFragment();\n let lastTextNode: Text | null = null;\n\n for (const part of parts) {\n if (part.type === \"text\") {\n lastTextNode = createTextNode(part.text);\n fragment.append(lastTextNode);\n continue;\n }\n latestMentionsRef.current = [\n ...latestMentionsRef.current,\n part.mention,\n ];\n fragment.append(buildMentionNode(part.mention));\n lastTextNode = createTextNode(CARET_TEXT);\n fragment.append(lastTextNode);\n }\n\n if (range) {\n range.deleteContents();\n range.insertNode(fragment);\n } else {\n editor.append(fragment);\n }\n cleanupCaretTextNodes();\n if (lastTextNode) setCursorAtTextEnd(lastTextNode);\n emitChange();\n };\n\n const handleKeyDown: React.KeyboardEventHandler<HTMLDivElement> = (\n event,\n ) => {\n if (event.key === \"ArrowLeft\" || event.key === \"ArrowRight\") {\n const selection = window.getSelection();\n if (selection?.rangeCount) {\n const range = selection.getRangeAt(0);\n if (range.collapsed) {\n const targetMention =\n event.key === \"ArrowLeft\"\n ? getMentionBeforeRange(range)\n : getMentionAfterRange(range);\n\n if (targetMention) {\n event.preventDefault();\n moveCursorAroundMention(\n targetMention,\n event.key === \"ArrowLeft\" ? \"before\" : \"after\",\n );\n return;\n }\n }\n }\n }\n\n if (event.key === \"Backspace\" || event.key === \"Delete\") {\n const selection = window.getSelection();\n if (selection?.rangeCount) {\n const range = selection.getRangeAt(0);\n if (range.collapsed) {\n const targetMention =\n event.key === \"Backspace\"\n ? getMentionBeforeRange(range)\n : getMentionAfterRange(range);\n\n if (targetMention) {\n event.preventDefault();\n removeMentionById(\n targetMention.dataset.xadkInlineMentionId || \"\",\n );\n return;\n }\n }\n }\n }\n onKeyDown?.(event);\n };\n\n // placeholder 只由受控 value/mentions 派生,避免从 contenteditable DOM 读取导致外部插入 Mention 后状态滞后一帧。\n const showPlaceholder = !hasContent;\n\n return (\n <div className={styles.inlineInputWrapper}>\n {showPlaceholder && placeholder && (\n <div className={styles.inlinePlaceholder}>{placeholder}</div>\n )}\n <div\n ref={editorRef}\n className={styles.inlineInput}\n contentEditable={!disabled}\n suppressContentEditableWarning\n role=\"textbox\"\n aria-multiline=\"true\"\n onInput={handleInput}\n onPaste={handlePaste}\n onKeyDown={handleKeyDown}\n onKeyUp={(event) => {\n cleanupEmptyStructuralNodes();\n cleanupCaretTextNodes();\n saveSelectionRange();\n onKeyUp?.(event);\n }}\n onMouseUp={saveSelectionRange}\n onFocus={saveSelectionRange}\n onCompositionStart={() => {\n composingRef.current = true;\n // 中文 IME 在 compositionend 前不会触发受控 value 更新;候选输入一出现就应隐藏 placeholder。\n setHasContent(true);\n }}\n onCompositionEnd={() => {\n composingRef.current = false;\n emitChange();\n }}\n data-cursor-offset={getOffsetInEditor()}\n />\n </div>\n );\n },\n);\n\nInlineTagInput.displayName = \"InlineTagInput\";\n\nexport default InlineTagInput;\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAQO;AACP,oBAAsC;AAOtC,oBAA0B;AAC1B,8BAAkD;AAyOtC;AAtMZ,IAAM,eAAe;AAErB,IAAM,aAAa;AAEnB,IAAM,iBAAiB,CAAC,SAAiB,SAAS,eAAe,IAAI;AACrE,IAAM,4BACJ,OAAO,WAAW,cAAc,yBAAY;AAC9C,IAAM,gBAAgB,CAAC,SACrB,KAAK,QAAQ,WAAW,EAAE,EAAE,QAAQ,WAAW,GAAG;AACpD,IAAM,iBAAiB,CAAC,SAAiB,cAAc,IAAI,EAAE;AAE7D,IAAM,cAAc,CAAC,MAAc,gBAAwB;AACzD,MAAI,UAAU;AACd,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,QAAI,WAAW;AAAa,aAAO;AACnC,QAAI,KAAK,CAAC,MAAM;AAAY,iBAAW;AAAA,EACzC;AACA,SAAO,KAAK;AACd;AAGA,IAAM,qBAAiB;AAAA,EACrB,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GACA,QACG;AACH,UAAM,aAAS,yBAAU;AACzB,UAAM,gBAAY,qBAAuB,IAAI;AAC7C,UAAM,wBAAoB,qBAAqB,QAAQ;AACvD,UAAM,oBAAgB,qBAA+B,oBAAI,QAAQ,CAAC;AAClE,UAAM,mBAAe,qBAAO,KAAK;AACjC,UAAM,2BAAuB,qBAAoB,IAAI;AACrD,UAAM,oBAAgB,qBAAqB,IAAI;AAC/C,UAAM,kCAA8B,qBAAO,KAAK;AAChD,UAAM,8BAA0B,qBAAO,KAAK;AAC5C,UAAM,gCAA4B,qBAAsB,IAAI;AAC5D,UAAM,CAAC,YAAY,aAAa,QAAI;AAAA,MAAS,MAC3C,QAAQ,SAAS,SAAS,MAAM;AAAA,IAClC;AACA,UAAM,0BAAsB,qBAAO;AAAA,MACjC;AAAA,MACA,YAAY,SAAS,IAAI,CAAC,YAAY,QAAQ,EAAE,EAAE,KAAK,GAAG;AAAA,IAC5D,CAAC;AAED,gCAAU,MAAM;AACd,wBAAkB,UAAU;AAAA,IAC9B,GAAG,CAAC,QAAQ,CAAC;AAEb,UAAM,yBAAqB,0BAAY,MAAM;AAC3C,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC;AAAQ,eAAO,CAAC;AACrB,YAAM,aAAa,IAAI;AAAA,QACrB,kBAAkB,QAAQ,IAAI,CAAC,YAAY,CAAC,QAAQ,IAAI,OAAO,CAAC;AAAA,MAClE;AACA,aAAO,MAAM,KAAK,OAAO,iBAAiB,IAAI,eAAe,CAAC,EAC3D;AAAA,QAAI,CAAC,SACJ,WAAW;AAAA,UACR,KAAqB,QAAQ,uBAAuB;AAAA,QACvD;AAAA,MACF,EACC,OAAO,OAAO;AAAA,IACnB,GAAG,CAAC,CAAC;AAGL,UAAM,mBAAe,0BAAY,MAAM;AACrC,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC;AAAQ,eAAO;AACpB,UAAI,OAAO;AACX,aAAO,WAAW,QAAQ,CAAC,SAAS;AAClC,YAAI,KAAK,aAAa,KAAK,WAAW;AACpC,kBAAQ,KAAK,eAAe;AAAA,QAC9B;AAAA,MACF,CAAC;AACD,aAAO,cAAc,IAAI;AAAA,IAC3B,GAAG,CAAC,CAAC;AAGL,UAAM,eAAW,0BAAY,MAA8B;AACzD,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC;AAAQ,eAAO,CAAC;AACrB,YAAM,aAAa,IAAI;AAAA,QACrB,kBAAkB,QAAQ,IAAI,CAAC,YAAY,CAAC,QAAQ,IAAI,OAAO,CAAC;AAAA,MAClE;AACA,YAAM,QAAgC,CAAC;AAEvC,aAAO,WAAW,QAAQ,CAAC,SAAS;AAClC,YAAI,KAAK,aAAa,KAAK,WAAW;AACpC,gBAAM,OAAO,cAAc,KAAK,eAAe,EAAE;AACjD,cAAI;AAAM,kBAAM,KAAK,EAAE,MAAM,QAAQ,KAAK,CAAC;AAC3C;AAAA,QACF;AAEA,YAAI,gBAAgB,eAAe,KAAK,aAAa,YAAY,GAAG;AAClE,gBAAM,YAAY,KAAK,QAAQ,uBAAuB;AACtD,gBAAM,UAAU,WAAW,IAAI,SAAS;AACxC,cAAI;AAAS,kBAAM,KAAK,EAAE,MAAM,WAAW,QAAQ,CAAC;AAAA,QACtD;AAAA,MACF,CAAC;AAED,aAAO;AAAA,IACT,GAAG,CAAC,CAAC;AAEL,UAAM,iBAAa,0BAAY,MAAM;AACnC,YAAM,YAAY,aAAa;AAC/B,YAAM,eAAe,mBAAmB;AACxC,oBAAc,QAAQ,aAAa,aAAa,MAAM,CAAC;AACvD,0BAAoB,UAAU;AAAA,QAC5B,OAAO;AAAA,QACP,YAAY,aAAa,IAAI,CAAC,YAAY,QAAQ,EAAE,EAAE,KAAK,GAAG;AAAA,MAChE;AACA,eAAS,SAAS;AAClB,uBAAiB,YAAY;AAAA,IAC/B,GAAG,CAAC,oBAAoB,cAAc,UAAU,gBAAgB,CAAC;AAEjE,UAAM,sBAAkB;AAAA,MACtB,CAAC,MAAY,OAAe,QAAgB;AAC1C,cAAM,OAAO,KAAK,eAAe;AACjC,aAAK,cAAc,GAAG,KAAK,MAAM,GAAG,KAAK,IAAI,KAAK,MAAM,GAAG;AAC3D,YAAI,CAAC,KAAK;AAAa,eAAK,OAAO;AAAA,MACrC;AAAA,MACA,CAAC;AAAA,IACH;AAEA,UAAM,wBAAoB;AAAA,MACxB,CAAC,SAAkB;AA3LzB;AA4LQ,cAAM,WAAW,KAAK;AACtB,cAAM,OAAO,KAAK;AAElB,4BAAc,QAAQ,IAAI,IAAI,MAA9B,mBAAiC;AACjC,aAAK,OAAO;AAGZ,aAAI,6BAAM,cAAa,KAAK,WAAW;AACrC,gBAAM,OAAO,KAAK,eAAe;AACjC,gBAAM,gBAAc,UAAK,MAAM,UAAU,MAArB,mBAAyB,GAAG,WAAU;AAC1D,cAAI,cAAc,GAAG;AACnB,4BAAgB,MAAc,GAAG,WAAW;AAC5C;AAAA,UACF;AAAA,QACF;AAEA,aAAI,qCAAU,cAAa,KAAK,WAAW;AACzC,gBAAM,OAAO,SAAS,eAAe;AACrC,gBAAM,gBAAc,UAAK,MAAM,MAAM,MAAjB,mBAAqB,GAAG,WAAU;AACtD,cAAI,cAAc,GAAG;AACnB;AAAA,cACE;AAAA,cACA,KAAK,SAAS;AAAA,cACd,KAAK;AAAA,YACP;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MACA,CAAC,eAAe;AAAA,IAClB;AAEA,UAAM,wBAAoB;AAAA,MACxB,CAAC,OAAe;AACd,cAAM,SAAS,UAAU;AACzB,cAAM,OAAO,MAAM;AAAA,WACjB,iCAAQ,iBAAiB,IAAI,qBAAoB,CAAC;AAAA,QACpD,EAAE;AAAA,UACA,CAAC,SAAU,KAAqB,QAAQ,wBAAwB;AAAA,QAClE;AACA,YAAI,MAAM;AACR,4BAAkB,IAAI;AAAA,QACxB;AACA,mBAAW;AACX,yCAAQ;AAAA,MACV;AAAA,MACA,CAAC,YAAY,iBAAiB;AAAA,IAChC;AAGA,UAAM,uBAAmB;AAAA,MACvB,CAAC,YAAwB;AACvB,cAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,aAAK,aAAa,mBAAmB,OAAO;AAC5C,aAAK,aAAa,cAAc,QAAQ,EAAE;AAC1C,aAAK,QAAQ,sBAAsB,QAAQ;AAC3C,aAAK,QAAQ,wBAAwB,QAAQ;AAC7C,aAAK,YAAY,OAAO;AAExB,YAAI,eAAe;AACjB,gBAAM,WAAO,0BAAW,IAAI;AAC5B,wBAAc,QAAQ,IAAI,MAAM,IAAI;AACpC,eAAK;AAAA,YACH,2EACG,wBAAc,SAAS;AAAA,cACtB,UAAU,MAAM,kBAAkB,QAAQ,EAAE;AAAA,YAC9C,CAAC,GACH;AAAA,UACF;AAAA,QACF,OAAO;AACL,gBAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,gBAAM,YAAY;AAClB,gBAAM,cAAc,QAAQ,eAAe,QAAQ;AACnD,gBAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,gBAAM,YAAY;AAClB,gBAAM,YAAY;AAClB,gBAAM,UAAU,CAAC,UAAU;AACzB,kBAAM,eAAe;AACrB,kBAAM,gBAAgB;AACtB,8BAAkB,QAAQ,EAAE;AAAA,UAC9B;AACA,eAAK,OAAO,OAAO,KAAK;AAAA,QAC1B;AACA,eAAO;AAAA,MACT;AAAA,MACA,CAAC,mBAAmB,eAAe,OAAO,SAAS;AAAA,IACrD;AAEA,UAAM,0BAAsB;AAAA,MAC1B,CAAC,UAAiC;AAChC,cAAM,SAAS,UAAU;AACzB,YAAI,CAAC;AAAQ;AAEb,eAAO,iBAAiB,IAAI,eAAe,EAAE,QAAQ,CAAC,SAAS;AAxRvE;AAyRU,8BAAc,QAAQ,IAAI,IAAI,MAA9B,mBAAiC;AAAA,QACnC,CAAC;AACD,eAAO,YAAY;AAEnB,cAAM,QAAQ,CAAC,SAAS;AACtB,cAAI,KAAK,SAAS,QAAQ;AACxB,gBAAI,KAAK;AAAM,qBAAO,YAAY,eAAe,KAAK,IAAI,CAAC;AAC3D;AAAA,UACF;AACA,gBAAM,UAAU,KAAK,SAAS,YAAY,KAAK,UAAU,KAAK;AAC9D,iBAAO,OAAO,iBAAiB,OAAO,GAAG,eAAe,UAAU,CAAC;AAAA,QACrE,CAAC;AAAA,MACH;AAAA,MACA,CAAC,gBAAgB;AAAA,IACnB;AAEA,UAAM,yBAAqB,0BAAY,CAAC,SAAe;AAzS3D;AA0SM,YAAM,QAAQ,SAAS,YAAY;AACnC,YAAM,YAAY,OAAO,aAAa;AACtC,YAAM,SAAS,QAAM,UAAK,gBAAL,mBAAkB,WAAU,CAAC;AAClD,YAAM,SAAS,IAAI;AACnB,6CAAW;AACX,6CAAW,SAAS;AACpB,oBAAc,UAAU,MAAM,WAAW;AAAA,IAC3C,GAAG,CAAC,CAAC;AAEL,UAAM,yBAAqB,0BAAY,MAAM;AAC3C,YAAM,SAAS,UAAU;AACzB,YAAM,YAAY,OAAO,aAAa;AACtC,UAAI,CAAC,UAAU,CAAC,aAAa,UAAU,eAAe;AAAG;AACzD,YAAM,QAAQ,UAAU,WAAW,CAAC;AACpC,UACE,CAAC,OAAO,SAAS,MAAM,cAAc,KACrC,CAAC,OAAO,SAAS,MAAM,YAAY,GACnC;AACA;AAAA,MACF;AACA,oBAAc,UAAU,MAAM,WAAW;AAAA,IAC3C,GAAG,CAAC,CAAC;AAEL,UAAM,+BAA2B;AAAA,MAC/B,CAAC,SAAe;AACd,cAAM,SAAS,UAAU;AACzB,YAAI,CAAC,UAAU,CAAC,OAAO,SAAS,IAAI;AAAG;AACvC,eAAO,MAAM;AACb,2BAAmB,IAAI;AAAA,MACzB;AAAA,MACA,CAAC,kBAAkB;AAAA,IACrB;AAEA,UAAM,gBAAgB,CAAC,SACrB,gBAAgB,eAAe,KAAK,aAAa,YAAY;AAE/D,UAAM,kBAAkB,CAAC,SAAiB,cAAc,IAAI,MAAM;AAGlE,UAAM,wBAAwB,CAAC,UAAiB;AAC9C,YAAM,YAAY,MAAM;AACxB,UAAI,UAAU,aAAa,KAAK,WAAW;AACzC,cAAM,OAAO,UAAU,eAAe;AACtC,cAAM,eAAe,KAAK,MAAM,GAAG,MAAM,WAAW;AACpD,YACE,gBAAgB,YAAY,KAC5B,cAAc,UAAU,eAAe,GACvC;AACA,iBAAO,UAAU;AAAA,QACnB;AAAA,MACF;AAEA,UAAI,qBAAqB,aAAa;AACpC,cAAM,WAAW,UAAU,WAAW,MAAM,cAAc,CAAC;AAC3D,YAAI,cAAc,QAAQ;AAAG,iBAAO;AACpC,aACE,qCAAU,cAAa,KAAK,aAC5B,gBAAgB,SAAS,eAAe,EAAE,KAC1C,cAAc,SAAS,eAAe,GACtC;AACA,iBAAO,SAAS;AAAA,QAClB;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAEA,UAAM,uBAAuB,CAAC,UAAiB;AAC7C,YAAM,YAAY,MAAM;AACxB,UAAI,UAAU,aAAa,KAAK,WAAW;AACzC,cAAM,OAAO,UAAU,eAAe;AACtC,cAAM,cAAc,KAAK,MAAM,MAAM,WAAW;AAChD,YACE,gBAAgB,WAAW,KAC3B,cAAc,UAAU,WAAW,GACnC;AACA,iBAAO,UAAU;AAAA,QACnB;AAAA,MACF;AAEA,UAAI,qBAAqB,aAAa;AACpC,cAAM,OAAO,UAAU,WAAW,MAAM,WAAW;AACnD,YAAI,cAAc,IAAI;AAAG,iBAAO;AAChC,aACE,6BAAM,cAAa,KAAK,aACxB,gBAAgB,KAAK,eAAe,EAAE,KACtC,cAAc,KAAK,WAAW,GAC9B;AACA,iBAAO,KAAK;AAAA,QACd;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAEA,UAAM,8BAA0B;AAAA,MAC9B,CAAC,SAAsB,cAAkC;AA1Y/D;AA2YQ,cAAM,SAAS,UAAU;AACzB,cAAM,YAAY,OAAO,aAAa;AACtC,YAAI,CAAC,UAAU,CAAC,aAAa,CAAC,OAAO,SAAS,OAAO;AAAG;AAExD,cAAM,QAAQ,SAAS,YAAY;AACnC,YAAI,cAAc,UAAU;AAC1B,gBAAM,WAAW,QAAQ;AACzB,eAAI,qCAAU,cAAa,KAAK,WAAW;AACzC,kBAAM,SAAS,YAAU,cAAS,gBAAT,mBAAsB,WAAU,CAAC;AAAA,UAC5D,OAAO;AACL,kBAAM,eAAe,OAAO;AAAA,UAC9B;AAAA,QACF,OAAO;AACL,gBAAM,OAAO,QAAQ;AACrB,eAAI,6BAAM,cAAa,KAAK,WAAW;AACrC,kBAAM,uBACH,WAAK,eAAe,IAAI,MAAM,UAAU,MAAxC,mBAA4C,GAAG,WAAU;AAC5D,kBAAM,SAAS,MAAM,kBAAkB;AAAA,UACzC,OAAO;AACL,kBAAM,cAAc,OAAO;AAAA,UAC7B;AAAA,QACF;AAEA,cAAM,SAAS,IAAI;AACnB,kBAAU,gBAAgB;AAC1B,kBAAU,SAAS,KAAK;AACxB,sBAAc,UAAU,MAAM,WAAW;AAAA,MAC3C;AAAA,MACA,CAAC;AAAA,IACH;AAGA,UAAM,wBAAoB,0BAAY,MAAM;AAC1C,YAAM,SAAS,UAAU;AACzB,YAAM,YAAY,OAAO,aAAa;AACtC,UAAI,CAAC,UAAU,CAAC,aAAa,UAAU,eAAe;AAAG,eAAO;AAChE,YAAM,QAAQ,UAAU,WAAW,CAAC;AACpC,UAAI,SAAS;AACb,UAAI,QAAQ;AAEZ,YAAM,QAAQ,CAAC,SAAe;AAC5B,YAAI;AAAO;AACX,YAAI,SAAS,MAAM,gBAAgB;AACjC,cAAI,KAAK,aAAa,KAAK,WAAW;AACpC,sBAAU;AAAA,eACP,KAAK,eAAe,IAAI,MAAM,GAAG,MAAM,WAAW;AAAA,YACrD;AAAA,UACF;AACA,kBAAQ;AACR;AAAA,QACF;AACA,YAAI,gBAAgB,eAAe,KAAK,aAAa,YAAY;AAC/D;AACF,YAAI,KAAK,aAAa,KAAK,WAAW;AACpC,oBAAU,eAAe,KAAK,eAAe,EAAE;AAC/C;AAAA,QACF;AACA,aAAK,WAAW,QAAQ,KAAK;AAAA,MAC/B;AAEA,aAAO,WAAW,QAAQ,KAAK;AAC/B,aAAO;AAAA,IACT,GAAG,CAAC,CAAC;AAEL,UAAM,eAAe,CAAC,SAAe;AACnC,UAAI,QAAQ;AACZ,UAAI,UAAU;AACd,aAAO,QAAQ,iBAAiB;AAC9B,iBAAS;AACT,kBAAU,QAAQ;AAAA,MACpB;AACA,aAAO;AAAA,IACT;AAIA,UAAM,uBAAmB,0BAAY,CAAC,OAAe,QAA8B;AACjF,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC;AAAQ,eAAO;AACpB,UAAI,SAAS;AACb,UAAI,cAA4B;AAChC,YAAM,QAAQ,MAAM,KAAK,OAAO,UAAU;AAC1C,YAAM,QAAQ,CAAC,SAAS;AACtB,YAAI,KAAK,aAAa,KAAK;AAAW;AACtC,cAAM,OAAO,KAAK,eAAe;AACjC,cAAM,YAAY;AAClB,cAAM,cAAc,eAAe,IAAI;AACvC,cAAM,UAAU,SAAS;AACzB,iBAAS;AACT,YAAI,WAAW,SAAS,aAAa;AAAK;AAC1C,cAAM,WAAW,YAAY,MAAM,KAAK,IAAI,GAAG,QAAQ,SAAS,CAAC;AACjE,cAAM,SAAS,YAAY,MAAM,KAAK,IAAI,GAAG,MAAM,SAAS,CAAC;AAC7D,cAAM,WAAW,KAAK,MAAM,GAAG,QAAQ;AACvC,cAAM,YAAY,KAAK,MAAM,MAAM;AACnC,cAAM,SAAS,KAAK;AACpB,cAAM,YAAY,aAAa,IAAI;AAEnC,aAAK,cAAc,GAAG,WAAW;AACjC,YAAI,CAAC,aAAa;AAChB,wBAAc,SAAS,YAAY;AACnC,cAAI,KAAK,aAAa;AACpB,wBAAY,SAAS,MAAM,QAAQ;AAAA,UACrC,WAAW,QAAQ;AACjB,wBAAY,SAAS,QAAQ,SAAS;AAAA,UACxC;AACA,sBAAY,SAAS,IAAI;AAAA,QAC3B;AACA,YAAI,CAAC,KAAK;AAAa,eAAK,OAAO;AAAA,MACrC,CAAC;AAED,aAAO;AAAA,IACT,GAAG,CAAC,CAAC;AAGL,UAAM,4BAAwB,0BAAY,MAAM;AAC9C,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC;AAAQ;AACb,YAAM,KAAK,OAAO,UAAU,EAAE,QAAQ,CAAC,SAAS;AAC9C,YAAI,KAAK,aAAa,KAAK;AAAW;AACtC,cAAM,OAAO,KAAK,eAAe;AACjC,YAAI,CAAC,MAAM;AACT,eAAK,OAAO;AACZ;AAAA,QACF;AACA,YAAI,QAAQ,cAAc,IAAI,MAAM,IAAI;AACtC,eAAK,cAAc;AAAA,QACrB;AAAA,MACF,CAAC;AAAA,IACH,GAAG,CAAC,CAAC;AAIL,UAAM,kCAA8B,0BAAY,MAAM;AACpD,YAAM,SAAS,UAAU;AACzB,YAAM,YAAY,OAAO,aAAa;AACtC,UAAI,CAAC;AAAQ;AAEb,YAAM,KAAK,OAAO,QAAQ,EAAE,QAAQ,CAAC,SAAS;AAC5C,YAAI,KAAK,aAAa,YAAY;AAAG;AACrC,YAAI,KAAK,cAAc,IAAI,eAAe;AAAG;AAC7C,YAAI,cAAc,KAAK,eAAe,EAAE;AAAG;AAE3C,cAAM,SAAQ,uCAAW,cAAa,UAAU,WAAW,CAAC,IAAI;AAChE,cAAM,YAAY,aAAa,IAAI;AACnC,cAAM,iBAAiB;AAAA,UACrB,SACA,MAAM,cACL,MAAM,mBAAmB,QACxB,KAAK,SAAS,MAAM,cAAc,KACjC,MAAM,mBAAmB,WACvB,MAAM,gBAAgB,aACrB,MAAM,gBAAgB,YAAY;AAAA,QAC1C;AAEA,YAAI,kBAAkB,WAAW;AAG/B,gBAAM,YAAY,eAAe,UAAU;AAC3C,eAAK,YAAY,SAAS;AAC1B,gBAAM,YAAY,SAAS,YAAY;AACvC,oBAAU,SAAS,WAAW,WAAW,MAAM;AAC/C,oBAAU,SAAS,IAAI;AACvB,oBAAU,gBAAgB;AAC1B,oBAAU,SAAS,SAAS;AAC5B,wBAAc,UAAU,UAAU,WAAW;AAC7C;AAAA,QACF;AAEA,aAAK,OAAO;AAAA,MACd,CAAC;AAAA,IACH,GAAG,CAAC,CAAC;AAEL,gCAAU,MAAM;AACd,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC;AAAQ;AAIb,YAAM,qBAAqB,CAAC,UAAiB;AAC3C,YAAI,EAAE,iBAAiB;AAAa;AACpC,YAAI,CAAC,MAAM,UAAU,WAAW,QAAQ;AAAG;AAC3C,YAAI,0BAA0B,YAAY,MAAM;AAC9C,iBAAO,qBAAqB,0BAA0B,OAAO;AAAA,QAC/D;AACA,kCAA0B,UAAU,OAAO,sBAAsB,MAAM;AACrE,oCAA0B,UAAU;AACpC,sCAA4B;AAC5B,gCAAsB;AAAA,QACxB,CAAC;AAAA,MACH;AAEA,aAAO,iBAAiB,SAAS,kBAAkB;AACnD,aAAO,MAAM,OAAO,oBAAoB,SAAS,kBAAkB;AAAA,IACrE,GAAG,CAAC,uBAAuB,2BAA2B,CAAC;AAEvD,UAAM,oBAAgB;AAAA,MACpB,CAAC,SAAqB,YAA6C;AACjE,cAAM,SAAS,UAAU;AACzB,YAAI,CAAC;AAAQ;AAGb,cAAM,uBAAuB,OAAO,aAAa;AACjD,cAAM,0BACJ,6DAAsB,eACtB,OAAO,SAAS,qBAAqB,WAAW,CAAC,EAAE,cAAc,IAC7D,qBAAqB,WAAW,CAAC,EAAE,WAAW,IAC9C;AACN,cAAM,wBACJ,cAAc,WACd,OAAO,SAAS,cAAc,QAAQ,cAAc,IAChD,cAAc,QAAQ,WAAW,IACjC;AACN,cAAM,mBACJ,0BAA0B;AAE5B,eAAO,MAAM;AACb,0BAAkB,UAAU;AAAA,UAC1B,GAAG,kBAAkB,QAAQ,OAAO,CAAC,SAAS,KAAK,OAAO,QAAQ,EAAE;AAAA,UACpE;AAAA,QACF;AACA,YAAI,cAA4B;AAChC,YAAI,SAAS;AACX,wBAAc,iBAAiB,QAAQ,OAAO,QAAQ,GAAG;AACzD,gCAAsB;AAAA,QACxB;AAGA,cAAM,sBACJ,CAAC,aAAa,KAAK,CAAC,OAAO,cAAc,IAAI,eAAe;AAC9D,YAAI,qBAAqB;AACvB,iBAAO,YAAY;AACnB,wBAAc,UAAU;AACxB,wBAAc;AAAA,QAChB;AACA,cAAM,cAAc,iBAAiB,OAAO;AAC5C,cAAM,YAAY,eAAe,UAAU;AAC3C,cAAM,QAAQ,eAAe;AAC7B,YAAI,SAAS,OAAO,SAAS,MAAM,cAAc,GAAG;AAElD,gBAAM,WAAW,SAAS,uBAAuB;AACjD,mBAAS,OAAO,aAAa,SAAS;AACtC,gBAAM,WAAW,QAAQ;AAAA,QAC3B,OAAO;AACL,iBAAO,OAAO,aAAa,SAAS;AAAA,QACtC;AACA,8BAAsB;AACtB,6BAAqB,UAAU;AAC/B,2BAAmB,SAAS;AAC5B,mBAAW;AAIX,eAAO,sBAAsB,MAAM;AACjC,cAAI,qBAAqB,YAAY,WAAW;AAC9C,qCAAyB,SAAS;AAAA,UACpC;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,gCAAU,MAAM;AACd,eAAS,iBAAiB,mBAAmB,kBAAkB;AAC/D,aAAO,MAAM;AACX,iBAAS,oBAAoB,mBAAmB,kBAAkB;AAAA,MACpE;AAAA,IACF,GAAG,CAAC,kBAAkB,CAAC;AAEvB;AAAA,MACE,MAAM,MAAM;AACV,YAAI,0BAA0B,YAAY,MAAM;AAC9C,iBAAO,qBAAqB,0BAA0B,OAAO;AAAA,QAC/D;AAAA,MACF;AAAA,MACA,CAAC;AAAA,IACH;AAEA;AAAA,MACE;AAAA,MACA,OAAO;AAAA,QACL,OAAO,MAAG;AA3qBlB;AA2qBqB,iCAAU,YAAV,mBAAmB;AAAA;AAAA,QAChC,SAAS;AAAA,QACT;AAAA,QACA,iBAAiB;AAAA,QACjB,iBAAiB,CAAC,EAAE,OAAO,IAAI,MAAM;AACnC,gBAAM,QAAQ,iBAAiB,OAAO,GAAG;AACzC,gCAAsB;AACtB,cAAI,OAAO;AACT,kBAAM,YAAY,OAAO,aAAa;AACtC,mDAAW;AACX,mDAAW,SAAS;AACpB,0BAAc,UAAU,MAAM,WAAW;AAAA,UAC3C;AACA,qBAAW;AAAA,QACb;AAAA,QACA;AAAA,QACA,WAAW;AAAA,MACb;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,8BAA0B,MAAM;AAC9B,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC;AAAQ;AAGb,UACE,CAAC,4BAA4B,YAC7B,uDAAmB,WACnB,CAAC,SACD,SAAS,WAAW,GACpB;AACA,oCAA4B,UAAU;AAGtC,gCAAwB,UAAU;AAClC,0BAAkB,UAAU,kBAAkB,QAAQ,CAAC,SAAS;AAC9D,cAAI,KAAK,SAAS;AAAW,mBAAO,CAAC,KAAK,OAAO;AACjD,cAAI,KAAK,SAAS;AAAO,mBAAO,CAAC,KAAK,GAAG;AACzC,iBAAO,CAAC;AAAA,QACV,CAAC;AACD,4BAAoB,iBAAiB;AACrC,sBAAc,IAAI;AAClB,mBAAW;AACX;AAAA,MACF;AAEA,YAAM,qBAAqB,SACxB,IAAI,CAAC,YAAY,QAAQ,EAAE,EAC3B,KAAK,GAAG;AACX,YAAM,mBAAmB,oBAAoB;AAC7C,YAAM,2BACJ,UAAU,iBAAiB,SAC3B,uBAAuB,iBAAiB;AAE1C,UAAI,4BAA4B,OAAO,WAAW,SAAS;AAAG;AAE9D,0BAAoB;AAAA,QAClB,GAAI,QAAQ,CAAC,EAAE,MAAM,QAAiB,MAAM,MAAM,CAAC,IAAI,CAAC;AAAA,QACxD,GAAG,SAAS,IAAI,CAAC,aAAa,EAAE,MAAM,WAAoB,QAAQ,EAAE;AAAA,MACtE,CAAC;AACD,oBAAc,QAAQ,SAAS,SAAS,MAAM,CAAC;AAG/C,YAAM,eAAe,MAAM,KAAK,OAAO,UAAU,EAC9C,QAAQ,EACR,KAAK,CAAC,SAAuB,KAAK,aAAa,KAAK,SAAS;AAChE,UAAI,SAAS,kBAAkB,UAAU,cAAc;AACrD,2BAAmB,YAAY;AAAA,MACjC;AAAA,IACF,GAAG;AAAA,MACD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,8BAA0B,MAAM;AAC9B,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC;AAAQ;AACb,UAAI,wBAAwB,SAAS;AACnC,gCAAwB,UAAU;AAClC;AAAA,MACF;AACA,UAAI,CAAC,SAAS,SAAS,WAAW,KAAK,OAAO,WAAW,SAAS,GAAG;AACnE,eAAO,iBAAiB,IAAI,eAAe,EAAE,QAAQ,CAAC,SAAS;AA1wBvE;AA2wBU,8BAAc,QAAQ,IAAI,IAAI,MAA9B,mBAAiC;AAAA,QACnC,CAAC;AACD,eAAO,YAAY;AAAA,MACrB;AAAA,IACF,GAAG,CAAC,SAAS,QAAQ,KAAK,CAAC;AAE3B,UAAM,cAAc,MAAM;AACxB,UAAI,CAAC,aAAa,SAAS;AACzB,oCAA4B;AAC5B,8BAAsB;AACtB,mBAAW;AAGX,YAAI,0BAA0B,YAAY,MAAM;AAC9C,iBAAO,qBAAqB,0BAA0B,OAAO;AAAA,QAC/D;AACA,kCAA0B,UAAU,OAAO,sBAAsB,MAAM;AACrE,oCAA0B,UAAU;AACpC,sCAA4B;AAC5B,gCAAsB;AAAA,QACxB,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,cAA2D,CAC/D,UACG;AACH,YAAM,eAAe;AACrB,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC;AAAQ;AAGb,YAAM,OAAO,MAAM,cAAc,QAAQ,YAAY;AACrD,UAAI,CAAC;AAAM;AACX,YAAM,YAAQ,2DAAkC,IAAI;AACpD,YAAM,YAAY,OAAO,aAAa;AACtC,YAAM,SACJ,uCAAW,eACX,OAAO,SAAS,UAAU,WAAW,CAAC,EAAE,cAAc,IAClD,UAAU,WAAW,CAAC,IACtB;AACN,YAAM,WAAW,SAAS,uBAAuB;AACjD,UAAI,eAA4B;AAEhC,iBAAW,QAAQ,OAAO;AACxB,YAAI,KAAK,SAAS,QAAQ;AACxB,yBAAe,eAAe,KAAK,IAAI;AACvC,mBAAS,OAAO,YAAY;AAC5B;AAAA,QACF;AACA,0BAAkB,UAAU;AAAA,UAC1B,GAAG,kBAAkB;AAAA,UACrB,KAAK;AAAA,QACP;AACA,iBAAS,OAAO,iBAAiB,KAAK,OAAO,CAAC;AAC9C,uBAAe,eAAe,UAAU;AACxC,iBAAS,OAAO,YAAY;AAAA,MAC9B;AAEA,UAAI,OAAO;AACT,cAAM,eAAe;AACrB,cAAM,WAAW,QAAQ;AAAA,MAC3B,OAAO;AACL,eAAO,OAAO,QAAQ;AAAA,MACxB;AACA,4BAAsB;AACtB,UAAI;AAAc,2BAAmB,YAAY;AACjD,iBAAW;AAAA,IACb;AAEA,UAAM,gBAA4D,CAChE,UACG;AACH,UAAI,MAAM,QAAQ,eAAe,MAAM,QAAQ,cAAc;AAC3D,cAAM,YAAY,OAAO,aAAa;AACtC,YAAI,uCAAW,YAAY;AACzB,gBAAM,QAAQ,UAAU,WAAW,CAAC;AACpC,cAAI,MAAM,WAAW;AACnB,kBAAM,gBACJ,MAAM,QAAQ,cACV,sBAAsB,KAAK,IAC3B,qBAAqB,KAAK;AAEhC,gBAAI,eAAe;AACjB,oBAAM,eAAe;AACrB;AAAA,gBACE;AAAA,gBACA,MAAM,QAAQ,cAAc,WAAW;AAAA,cACzC;AACA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,UAAI,MAAM,QAAQ,eAAe,MAAM,QAAQ,UAAU;AACvD,cAAM,YAAY,OAAO,aAAa;AACtC,YAAI,uCAAW,YAAY;AACzB,gBAAM,QAAQ,UAAU,WAAW,CAAC;AACpC,cAAI,MAAM,WAAW;AACnB,kBAAM,gBACJ,MAAM,QAAQ,cACV,sBAAsB,KAAK,IAC3B,qBAAqB,KAAK;AAEhC,gBAAI,eAAe;AACjB,oBAAM,eAAe;AACrB;AAAA,gBACE,cAAc,QAAQ,uBAAuB;AAAA,cAC/C;AACA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,6CAAY;AAAA,IACd;AAGA,UAAM,kBAAkB,CAAC;AAEzB,WACE,6CAAC,SAAI,WAAW,OAAO,oBACpB;AAAA,yBAAmB,eAClB,4CAAC,SAAI,WAAW,OAAO,mBAAoB,uBAAY;AAAA,MAEzD;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,WAAW,OAAO;AAAA,UAClB,iBAAiB,CAAC;AAAA,UAClB,gCAA8B;AAAA,UAC9B,MAAK;AAAA,UACL,kBAAe;AAAA,UACf,SAAS;AAAA,UACT,SAAS;AAAA,UACT,WAAW;AAAA,UACX,SAAS,CAAC,UAAU;AAClB,wCAA4B;AAC5B,kCAAsB;AACtB,+BAAmB;AACnB,+CAAU;AAAA,UACZ;AAAA,UACA,WAAW;AAAA,UACX,SAAS;AAAA,UACT,oBAAoB,MAAM;AACxB,yBAAa,UAAU;AAEvB,0BAAc,IAAI;AAAA,UACpB;AAAA,UACA,kBAAkB,MAAM;AACtB,yBAAa,UAAU;AACvB,uBAAW;AAAA,UACb;AAAA,UACA,sBAAoB,kBAAkB;AAAA;AAAA,MACxC;AAAA,OACF;AAAA,EAEJ;AACF;AAEA,eAAe,cAAc;AAE7B,IAAO,yBAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -119,6 +119,12 @@ var XAdkSender = (0, import_react.forwardRef)(
|
|
|
119
119
|
const [quickKeyKeyword, setQuickKeyKeyword] = (0, import_react.useState)("");
|
|
120
120
|
const [quickKeyTriggerIdx, setQuickKeyTriggerIdx] = (0, import_react.useState)(-1);
|
|
121
121
|
const [quickKeyActiveIndex, setQuickKeyActiveIndex] = (0, import_react.useState)(0);
|
|
122
|
+
const closeQuickKeyList = (0, import_react.useCallback)(() => {
|
|
123
|
+
setActiveQuickKey(null);
|
|
124
|
+
setQuickKeyKeyword("");
|
|
125
|
+
setQuickKeyTriggerIdx(-1);
|
|
126
|
+
setQuickKeyActiveIndex(0);
|
|
127
|
+
}, []);
|
|
122
128
|
const generateId = () => {
|
|
123
129
|
return Date.now().toString(36) + Math.random().toString(36).substr(2);
|
|
124
130
|
};
|
|
@@ -800,6 +806,13 @@ var XAdkSender = (0, import_react.forwardRef)(
|
|
|
800
806
|
{
|
|
801
807
|
ref: containerRef,
|
|
802
808
|
className: containerClass,
|
|
809
|
+
onBlur: (event) => {
|
|
810
|
+
const nextFocusedNode = event.relatedTarget;
|
|
811
|
+
if (nextFocusedNode && event.currentTarget.contains(nextFocusedNode)) {
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
closeQuickKeyList();
|
|
815
|
+
},
|
|
803
816
|
onDragOver: draggable ? handleDragOver : void 0,
|
|
804
817
|
onDragLeave: draggable ? handleDragLeave : void 0,
|
|
805
818
|
onDrop: draggable ? handleDrop : void 0,
|
|
@@ -853,12 +866,7 @@ var XAdkSender = (0, import_react.forwardRef)(
|
|
|
853
866
|
config: activeQuickKeyConfig,
|
|
854
867
|
activeIndex: quickKeyActiveIndex,
|
|
855
868
|
onSelect: handleQuickKeySelect,
|
|
856
|
-
onClose:
|
|
857
|
-
setActiveQuickKey(null);
|
|
858
|
-
setQuickKeyKeyword("");
|
|
859
|
-
setQuickKeyTriggerIdx(-1);
|
|
860
|
-
setQuickKeyActiveIndex(0);
|
|
861
|
-
},
|
|
869
|
+
onClose: closeQuickKeyList,
|
|
862
870
|
visible: true
|
|
863
871
|
}
|
|
864
872
|
) }),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/components/XAdkSender/index.tsx"],
|
|
4
|
-
"sourcesContent": ["import React, {\n useState,\n useRef,\n useCallback,\n forwardRef,\n useImperativeHandle,\n useMemo,\n useEffect,\n} from \"react\";\nimport { Popconfirm, message, Tooltip, Input, Modal } from \"antd\";\nimport {\n ClearOutlined,\n LoadingOutlined,\n ArrowUpOutlined,\n} from \"@ant-design/icons\";\nimport {\n XAdkSenderProps,\n XAdkSenderHandle,\n ServerFile,\n LocalFile,\n ActionsComponents,\n FileValidator,\n UploadFileResult,\n MentionTag,\n XAdkSenderSubmitData,\n XAdkSenderSubmitFormat,\n XAdkSenderSubmitPart,\n} from \"@/types\";\nimport { useStyles } from \"./styles\";\nimport FileGallery from \"../FileGallery\";\nimport InputSuggestionList from \"./InputSuggestionList\";\nimport InputTags from \"./InputTags\";\nimport InlineTagInput, { InlineTagInputRef } from \"./InlineTagInput\";\nimport { getExt } from \"@/utils/file\";\n\nconst XAdkSender = forwardRef<XAdkSenderHandle, XAdkSenderProps>(\n (\n {\n clearBtnShow = true,\n draggable = false,\n onFileSelect,\n loading = false,\n disabled = false,\n value: controlledValue,\n defaultValue = \"\",\n uploadRequest = () => {},\n onClear,\n onChange,\n onSubmit,\n onStop,\n onFilesChange,\n onUploadSuccess,\n onUploadError,\n maxFileSize = 10,\n placeholder = \"\",\n validators: customValidators = [],\n allowedFileTypes = [],\n maxFiles = Infinity,\n sendButtonRender,\n suffix,\n header,\n prefix,\n footer,\n footerLeft,\n quickKeys = [],\n inlineTags = false,\n renderMention,\n renderTag,\n mentions: controlledMentions,\n tags: controlledTags,\n defaultMentions,\n defaultTags = [],\n defaultInputParts,\n onMentionsChange,\n onTagsChange,\n onQuickKeyTrigger,\n submitFormat = \"text\",\n formatMention,\n formatTag,\n transformSubmitData,\n },\n ref,\n ) => {\n const styles = useStyles();\n const isControlled = controlledValue !== undefined;\n const [internalValue, setInternalValue] = useState<string>(defaultValue);\n const value = isControlled ? controlledValue : internalValue;\n const setValue = (newValue: string) => {\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onChange?.(newValue);\n };\n\n // mentions 支持受控/非受控两种模式;inlineTags 打开时会和输入内容混排。\n const resolvedControlledMentions = controlledMentions ?? controlledTags;\n const initialMentions = defaultMentions ?? defaultTags;\n const isMentionsControlled = resolvedControlledMentions !== undefined;\n const [internalMentions, setInternalMentions] =\n useState<MentionTag[]>(initialMentions);\n const mentions = isMentionsControlled\n ? resolvedControlledMentions!\n : internalMentions;\n const setMentions = (newMentions: MentionTag[]) => {\n if (!isMentionsControlled) {\n setInternalMentions(newMentions);\n }\n onMentionsChange?.(newMentions);\n onTagsChange?.(newMentions);\n };\n\n const [files, setFiles] = useState<LocalFile[]>([]);\n const [isDragOver, setIsDragOver] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n const textareaRef = useRef<any>(null);\n const inlineInputRef = useRef<InlineTagInputRef>(null);\n\n // 快捷键弹层状态:记录触发字符、关键词,以及触发字符在纯文本中的位置。\n // SDK 不内置搜索框;业务方可在 onQuickKeyTrigger 中根据 keyword 自行更新 quickKeys.options。\n const [activeQuickKey, setActiveQuickKey] = useState<string | null>(null);\n const [quickKeyKeyword, setQuickKeyKeyword] = useState(\"\");\n const [quickKeyTriggerIdx, setQuickKeyTriggerIdx] = useState(-1);\n const [quickKeyActiveIndex, setQuickKeyActiveIndex] = useState(0);\n\n // 生成唯一ID\n const generateId = () => {\n return Date.now().toString(36) + Math.random().toString(36).substr(2);\n };\n\n const normalizeUploadResponse = (response: any): UploadFileResult => {\n const data = response?.data ?? response;\n return (Array.isArray(data) ? data[0] : data) ?? {};\n };\n\n const escapeXml = (text: string) =>\n text\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n\n const escapeMarkdownLabel = (text: string) =>\n text.replace(/\\\\/g, \"\\\\\\\\\").replace(/\\]/g, \"\\\\]\");\n\n const getMentionSubmitValue = (mention: MentionTag) =>\n String(\n mention.value ??\n mention.uri ??\n mention.data?.uri ??\n mention.data?.value ??\n mention.data?.name ??\n mention.targetId ??\n mention.displayName ??\n mention.label ??\n \"\",\n );\n\n const defaultFormatMention = (\n mention: MentionTag,\n format: Exclude<XAdkSenderSubmitFormat, \"structured\">,\n index: number,\n ) => {\n const value = getMentionSubmitValue(mention);\n if (format === \"xml\") {\n return `<mention type=\"${escapeXml(mention.type)}\" id=\"${escapeXml(mention.id)}\" label=\"${escapeXml(mention.label)}\" value=\"${escapeXml(value)}\" />`;\n }\n\n if (format === \"markdown\") {\n const href =\n mention.uri ||\n (value.includes(\"://\")\n ? value\n : `xadk-mention://${encodeURIComponent(mention.type)}/${encodeURIComponent(mention.id)}`);\n return `[@${escapeMarkdownLabel(mention.displayName || mention.label)}](${href})`;\n }\n\n return `@${mention.displayName || value || `mention-${index + 1}`}`;\n };\n\n const serializeMention = (\n mention: MentionTag,\n format: Exclude<XAdkSenderSubmitFormat, \"structured\">,\n index: number,\n ) =>\n formatMention?.(mention, { format, index }) ??\n formatTag?.(mention, { format, index }) ??\n defaultFormatMention(mention, format, index);\n\n const getSubmitParts = useCallback((): XAdkSenderSubmitPart[] => {\n if (inlineTags) {\n const parts = inlineInputRef.current?.getParts() || [];\n if (parts.length > 0) return parts;\n }\n\n const textParts: XAdkSenderSubmitPart[] = value ? [{ type: \"text\", text: value }] : [];\n const mentionParts = mentions.map((mention) => ({\n type: \"mention\" as const,\n mention,\n }));\n return [...mentionParts, ...textParts];\n }, [inlineTags, mentions, value]);\n\n const serializeParts = (\n parts: XAdkSenderSubmitPart[],\n format: XAdkSenderSubmitFormat,\n ) => {\n if (format === \"structured\") {\n return parts.reduce(\n (content, part) => content + (part.type === \"text\" ? part.text : \"\"),\n \"\",\n );\n }\n\n let tagIndex = 0;\n return parts\n .map((part) => {\n if (part.type === \"text\") return part.text;\n const result = serializeMention(part.mention, format, tagIndex);\n tagIndex += 1;\n return result;\n })\n .join(\"\");\n };\n\n const createSubmitData = (formattedFiles: ServerFile[]): XAdkSenderSubmitData => {\n const parts = getSubmitParts();\n const rawText = parts.reduce(\n (content, part) => content + (part.type === \"text\" ? part.text : \"\"),\n \"\",\n );\n const standardData: Omit<XAdkSenderSubmitData, \"payload\"> = {\n text: serializeParts(parts, submitFormat),\n rawText,\n format: submitFormat,\n parts,\n files: formattedFiles,\n mentions,\n tags: mentions,\n };\n\n return {\n ...standardData,\n payload: transformSubmitData?.(standardData),\n };\n };\n\n // 检查文件类型\n const checkFileType = (file: File): boolean => {\n if (allowedFileTypes?.length > 0) {\n const ext = getExt(file);\n\n return allowedFileTypes.some((type) => {\n if (type.includes(\"/\")) {\n if (type.endsWith(\"/*\")) {\n return file.type.startsWith(type.split(\"/\")[0]);\n }\n return file.type === type;\n }\n\n if (type.startsWith(\".\")) {\n return ext === type.slice(1);\n }\n\n return false;\n });\n }\n return true;\n };\n\n // 重复文件检测\n const isDuplicateFile = (file: File, files: LocalFile[]) => {\n return files.some((f) => f.name === file.name && f.size === file.size);\n };\n\n // 内置校验器集合\n const builtInValidators: FileValidator[] = [\n (_file, { files }) => {\n if (files.length >= maxFiles) {\n return `最多只能上传 ${maxFiles} 个文件`;\n }\n return null;\n },\n (file) => {\n const maxSize = maxFileSize * 1024 * 1024;\n if (file.size > maxSize) {\n return `文件大小不能超过 ${maxFileSize}MB`;\n }\n return null;\n },\n (file) => {\n if (!checkFileType(file)) {\n return \"不支持的文件类型\";\n }\n return null;\n },\n (file, { files }) => {\n if (isDuplicateFile(file, files)) {\n return \"文件已存在\";\n }\n return null;\n },\n ];\n\n const allValidators = [...builtInValidators, ...customValidators];\n\n // 验证文件\n const validateFile = (file: File): { valid: boolean; message?: string } => {\n for (const validator of allValidators) {\n const error = validator(file, { files });\n if (error) {\n return { valid: false, message: error };\n }\n }\n return { valid: true };\n };\n\n // 处理文件选择\n const handleFileSelect = useCallback(\n (selectedFiles: File[]) => {\n const fileArray = Array.from(selectedFiles);\n\n if (files.length + fileArray.length > maxFiles) {\n message.error(`最多只能上传 ${maxFiles} 个文件`);\n return;\n }\n\n const validFiles: LocalFile[] = [];\n\n fileArray.forEach((file) => {\n const validation = validateFile(file);\n\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) => {\n const next = [...prev, ...validFiles];\n onFilesChange?.(next);\n return next;\n });\n uploadFiles(validFiles);\n }\n },\n [files, maxFiles, maxFileSize, allowedFileTypes],\n );\n\n // 暴露给业务工具栏调用的命令式能力;外部 Popover 选择标签时可插入到当前光标位置。\n useImperativeHandle(\n ref,\n () => ({\n addFiles: (rawFiles: File[]) => {\n handleFileSelect(rawFiles);\n },\n insertMention: (mention: MentionTag) => {\n if (inlineTags) {\n inlineInputRef.current?.insertMention(mention);\n return;\n }\n setMentions([...mentions, mention]);\n },\n insertTag: (mention: MentionTag) => {\n if (inlineTags) {\n inlineInputRef.current?.insertMention(mention);\n return;\n }\n setMentions([...mentions, mention]);\n },\n focus: () => {\n inlineTags ? inlineInputRef.current?.focus() : textareaRef.current?.focus();\n },\n }),\n [handleFileSelect, inlineTags, setMentions, mentions],\n );\n\n // 上传文件\n const uploadFiles = async (fileList: LocalFile[]) => {\n for (const localFile of fileList) {\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 const responseData = normalizeUploadResponse(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 fileId: responseData.fileId || responseData.id,\n tempUrl:\n responseData.tempUrl ||\n responseData.fileUrl ||\n responseData.url,\n }\n : f,\n ),\n );\n\n onUploadSuccess?.({\n ...localFile,\n status: \"success\",\n response,\n fileId: responseData.fileId || responseData.id,\n tempUrl:\n responseData.tempUrl ||\n responseData.fileUrl ||\n responseData.url,\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 onUploadError?.(localFile, error);\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 handleRemoveFile = (id: string) => {\n setFiles((prev) => {\n const next = prev.filter((file) => file.id !== id);\n onFilesChange?.(next);\n return next;\n });\n };\n\n // 处理拖拽事件\n const handleDragOver = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (draggable) {\n setIsDragOver(true);\n }\n },\n [draggable],\n );\n\n const handleDragLeave = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (draggable) {\n setIsDragOver(false);\n }\n },\n [draggable],\n );\n\n const handleDrop = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragOver(false);\n\n if (\n draggable &&\n e.dataTransfer.files &&\n e.dataTransfer.files.length > 0\n ) {\n // 内核不再自行处理文件,交给外层(DefaultLayout/业务)通过 onFileSelect 决定\n onFileSelect?.(Array.from(e.dataTransfer.files));\n }\n },\n [draggable, onFileSelect],\n );\n\n // 删除标签\n const handleRemoveMention = useCallback(\n (id: string) => {\n setMentions(mentions.filter((item) => item.id !== id));\n },\n [mentions, setMentions],\n );\n\n // 查找当前活跃的快捷键配置\n const activeQuickKeyConfig = useMemo(() => {\n if (!activeQuickKey) return null;\n return quickKeys.find((qk) => qk.key === activeQuickKey) || null;\n }, [activeQuickKey, quickKeys]);\n\n const activeQuickKeyOptionsLength = activeQuickKeyConfig?.options.length || 0;\n\n useEffect(() => {\n setQuickKeyActiveIndex(0);\n }, [activeQuickKey]);\n\n useEffect(() => {\n if (activeQuickKeyOptionsLength <= 0) {\n setQuickKeyActiveIndex(0);\n return;\n }\n\n // 业务方可能在 onQuickKeyTrigger 中动态更新 options;\n // 这里只做越界归一化,不重置有效索引,避免键盘高亮移动后又跳回第一项。\n setQuickKeyActiveIndex(\n (prev) => ((prev % activeQuickKeyOptionsLength) + activeQuickKeyOptionsLength) %\n activeQuickKeyOptionsLength,\n );\n }, [activeQuickKeyOptionsLength]);\n\n const getNextQuickKeyIndex = useCallback(\n (current: number, step: number) => {\n if (activeQuickKeyOptionsLength <= 0) return 0;\n return (\n (current + step + activeQuickKeyOptionsLength) %\n activeQuickKeyOptionsLength\n );\n },\n [activeQuickKeyOptionsLength],\n );\n\n // 从当前光标前的连续文本片段中查找最近的快捷键,例如 abc@doc 会触发 @。\n const detectQuickKey = useCallback(\n (text: string, cursorPos: number) => {\n const quickKeyChars = quickKeys.map((qk) => qk.key);\n if (quickKeyChars.length === 0) return;\n\n const textBeforeCursor = text.slice(0, cursorPos);\n let found = false;\n for (let i = textBeforeCursor.length - 1; i >= 0; i--) {\n const char = textBeforeCursor[i];\n if (/\\s/.test(char)) break;\n if (quickKeyChars.includes(char)) {\n const keyword = textBeforeCursor.slice(i + 1);\n setActiveQuickKey(char);\n setQuickKeyKeyword(keyword);\n setQuickKeyTriggerIdx(i);\n setQuickKeyActiveIndex(0);\n onQuickKeyTrigger?.(char, keyword);\n found = true;\n break;\n }\n }\n\n if (!found && activeQuickKey) {\n const triggerChar = text[quickKeyTriggerIdx];\n const keyword = text.slice(quickKeyTriggerIdx + 1, cursorPos);\n if (\n quickKeyTriggerIdx < 0 ||\n !triggerChar ||\n !quickKeyChars.includes(triggerChar) ||\n /\\s/.test(keyword)\n ) {\n setActiveQuickKey(null);\n setQuickKeyKeyword(\"\");\n setQuickKeyTriggerIdx(-1);\n setQuickKeyActiveIndex(0);\n } else {\n setQuickKeyKeyword(keyword);\n }\n }\n },\n [activeQuickKey, onQuickKeyTrigger, quickKeyTriggerIdx, quickKeys],\n );\n\n // 选择快捷项后转成结构化 Mention;inline 模式会替换掉触发字符和关键词。\n const handleQuickKeySelect = useCallback(\n (option: any) => {\n const mentionType =\n activeQuickKeyConfig?.mentionType ||\n activeQuickKeyConfig?.tagType ||\n activeQuickKey ||\n \"unknown\";\n const newMention: MentionTag = {\n id: generateId(),\n label: option.label,\n type: mentionType,\n value: option.value ?? option.uri ?? option.name ?? option.label,\n uri: option.uri,\n targetId: option.targetId ?? option.skillNo ?? option.pluginNo,\n displayName: option.displayName ?? option.label,\n trigger: activeQuickKey || undefined,\n icon: option.icon,\n data: option,\n };\n option.onSelect?.(option);\n activeQuickKeyConfig?.onSelect?.(option);\n\n if (option.action === \"command\") {\n if (inlineTags) {\n inlineInputRef.current?.deleteTextRange({\n start: quickKeyTriggerIdx,\n end: quickKeyTriggerIdx + 1 + quickKeyKeyword.length,\n });\n } else if (quickKeyTriggerIdx >= 0) {\n setValue(\n value.slice(0, quickKeyTriggerIdx) +\n value.slice(quickKeyTriggerIdx + 1 + quickKeyKeyword.length),\n );\n }\n } else if (inlineTags) {\n inlineInputRef.current?.insertMention(newMention, {\n start: quickKeyTriggerIdx,\n end: quickKeyTriggerIdx + 1 + quickKeyKeyword.length,\n });\n } else {\n setMentions([...mentions, newMention]);\n\n // 从输入框中删除快捷键字符和关键词\n if (quickKeyTriggerIdx >= 0) {\n const newValue =\n value.slice(0, quickKeyTriggerIdx) +\n value.slice(quickKeyTriggerIdx + 1 + quickKeyKeyword.length);\n setValue(newValue);\n }\n }\n\n setActiveQuickKey(null);\n setQuickKeyKeyword(\"\");\n setQuickKeyTriggerIdx(-1);\n setQuickKeyActiveIndex(0);\n inlineTags\n ? inlineInputRef.current?.focus()\n : textareaRef.current?.focus();\n },\n [\n activeQuickKey,\n activeQuickKeyConfig,\n inlineTags,\n mentions,\n setMentions,\n value,\n quickKeyTriggerIdx,\n quickKeyKeyword,\n setValue,\n ],\n );\n\n // 处理输入框变化(含快捷键检测)\n const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n const newValue = e.target.value;\n setValue(newValue);\n\n // 检测快捷键触发\n detectQuickKey(newValue, e.target.selectionStart || 0);\n };\n\n const handleInlineInputChange = (newValue: string) => {\n setValue(newValue);\n // contenteditable 的 selection 不一定和 React state 同步,需实时读取内部光标 offset。\n detectQuickKey(\n newValue,\n inlineInputRef.current?.getCursorOffset() || newValue.length,\n );\n };\n\n const handleQuickKeyByText = (text: string, cursorPos: number) => {\n const quickKeyChars = quickKeys.map((qk) => qk.key);\n if (quickKeyChars.length === 0) return;\n\n const textBeforeCursor = text.slice(0, cursorPos);\n\n // 检测刚输入的字符是否是快捷键\n const lastChar = textBeforeCursor[cursorPos - 1];\n if (lastChar && quickKeyChars.includes(lastChar)) {\n // 上下键导航后会触发 keyup,此时光标前仍是同一个快捷键字符;\n // 如果重复重置 activeIndex,视觉上会“移动一下又回到第一项”。\n if (activeQuickKey === lastChar && quickKeyTriggerIdx === cursorPos - 1) {\n return;\n }\n setActiveQuickKey(lastChar);\n setQuickKeyKeyword(\"\");\n setQuickKeyTriggerIdx(cursorPos - 1);\n setQuickKeyActiveIndex(0);\n onQuickKeyTrigger?.(lastChar, \"\");\n }\n };\n\n // onChange 负责更新搜索词;onKeyUp 兜底捕获刚输入的快捷键字符。\n const isQuickListControlKey = (key: string) =>\n key === \"ArrowDown\" || key === \"ArrowUp\" || key === \"Enter\" || key === \"Escape\";\n\n const handleKeyUp = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (activeQuickKey && isQuickListControlKey(e.key)) return;\n const target = e.target as HTMLTextAreaElement;\n handleQuickKeyByText(target.value || \"\", target.selectionStart || 0);\n };\n\n const handleInlineKeyUp = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (activeQuickKey && isQuickListControlKey(e.key)) return;\n // inline 输入区不是 textarea,不能读 event.target.value,只能从 ref 取纯文本。\n const text = inlineInputRef.current?.getText() || \"\";\n const cursorPos =\n inlineInputRef.current?.getCursorOffset() || text.length;\n handleQuickKeyByText(text, cursorPos);\n };\n\n // 处理提交\n const handleSubmit = () => {\n // 生成期间允许继续编辑下一条消息,但停止按钮仍代表当前唯一可执行动作。\n if (loading) return;\n if (!value.trim() && files.length === 0 && mentions.length === 0) {\n message.warning(\"请输入消息或选择文件\");\n return;\n }\n\n const successFiles = files.filter((file) => file.status === \"success\");\n const uploadingFiles = files.filter(\n (file) => file.status === \"uploading\",\n );\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(createSubmitData(formattedFiles));\n }\n\n setValue(\"\");\n setMentions([]);\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(createSubmitData(formattedFiles));\n }\n\n setValue(\"\");\n setMentions([]);\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)\n .map((file) => {\n const responseData = normalizeUploadResponse(file.response);\n\n return {\n fileName: responseData.fileName || file.name,\n fileId: responseData.fileId || responseData.id || \"\",\n tempUrl:\n responseData.tempUrl ||\n responseData.fileUrl ||\n responseData.url ||\n \"\",\n type: responseData.fileType || responseData.type || getExt(file),\n size: responseData.fileSize || responseData.size || file.size,\n mimeType: responseData.mimeType || file.type,\n raw: {\n ...responseData,\n },\n };\n });\n };\n\n // 处理回车键\n const handleKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {\n // 输入法候选阶段的 Enter 用于确认候选词,不能触发快捷项选择或消息发送。\n if (e.nativeEvent.isComposing || e.keyCode === 229) return;\n\n const quickKeyOptions = activeQuickKeyConfig?.options || [];\n\n if (activeQuickKey && quickKeyOptions.length > 0) {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setQuickKeyActiveIndex((prev) => getNextQuickKeyIndex(prev, 1));\n return;\n }\n\n if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setQuickKeyActiveIndex((prev) => getNextQuickKeyIndex(prev, -1));\n return;\n }\n\n if (e.key === \"Enter\") {\n e.preventDefault();\n handleQuickKeySelect(\n quickKeyOptions[\n Math.min(quickKeyActiveIndex, quickKeyOptions.length - 1)\n ],\n );\n return;\n }\n\n if (e.key === \"Escape\") {\n e.preventDefault();\n setActiveQuickKey(null);\n setQuickKeyKeyword(\"\");\n setQuickKeyTriggerIdx(-1);\n setQuickKeyActiveIndex(0);\n return;\n }\n }\n\n if (e.key === \"Enter\" && !e.shiftKey && !activeQuickKey) {\n e.preventDefault();\n handleSubmit();\n }\n };\n\n // 渲染文件列表\n const renderFileList = () => {\n if (files.length === 0) return null;\n\n return (\n <div className={styles.contextFiles}>\n {files.map((file) => (\n <FileGallery\n key={file.id}\n file={file}\n size=\"small\"\n removable\n onRemove={handleRemoveFile}\n />\n ))}\n </div>\n );\n };\n\n const containerClass = `${styles.container} ${isDragOver ? \"drag-over\" : \"\"}`;\n const uploading = files.some((f) => f.status === \"uploading\");\n const controlsDisabled = disabled || uploading || loading;\n const inputDisabled = disabled || uploading;\n const hasContent = value.trim().length > 0;\n const hasFiles = files.some((f) => f.status === \"success\");\n const hasMentions = mentions.length > 0;\n const canSend = hasContent || hasFiles || hasMentions;\n\n // 定义按钮组件\n const SendButton = (props: any) => {\n if (sendButtonRender) {\n return (\n <>\n {sendButtonRender({\n loading,\n disabled: uploading || disabled,\n canSend,\n onSend: handleSubmit,\n onStop,\n })}\n </>\n );\n }\n return (\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 spin /> : <ArrowUpOutlined />}\n </button>\n </Tooltip>\n );\n };\n\n const ClearButton = (props: any) => (\n <Popconfirm\n title=\"确定要清空聊天记录吗?\"\n onConfirm={onClear}\n placement=\"top\"\n okText=\"确定\"\n cancelText=\"取消\"\n disabled={controlsDisabled}\n >\n <button\n className={`${styles.iconButton} ${styles.clearButton}`}\n disabled={controlsDisabled}\n aria-label=\"清空聊天记录\"\n {...props}\n >\n <ClearOutlined />\n </button>\n </Popconfirm>\n );\n\n const actionsComponents: ActionsComponents = {\n SendButton,\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 const headerNode = renderSlot(header, false);\n const fileListNode = files.length > 0 ? renderFileList() : null;\n\n // 默认后缀仅保留发送/停止按钮;上传与清空统一放到底部 actionBar,方便业务扩展左侧按钮组。\n const defaultSuffix = (\n <div className={styles.buttonGroup}>\n {sendButtonRender ? (\n sendButtonRender({\n loading,\n disabled: uploading || disabled,\n canSend,\n onSend: handleSubmit,\n onStop,\n })\n ) : (\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 >\n {loading ? <LoadingOutlined spin /> : <ArrowUpOutlined />}\n </button>\n </Tooltip>\n )}\n </div>\n );\n\n const defaultActionBar = (\n <div className={styles.actionBar}>\n <div className={styles.actionBarLeft}>\n {renderSlot(footerLeft, false)}\n </div>\n <div className={styles.actionBarRight}>\n {clearBtnShow && <ClearButton />}\n {renderSlot(suffix, defaultSuffix)}\n </div>\n </div>\n );\n\n return (\n <div\n ref={containerRef}\n className={containerClass}\n onDragOver={draggable ? handleDragOver : undefined}\n onDragLeave={draggable ? handleDragLeave : undefined}\n onDrop={draggable ? handleDrop : undefined}\n >\n <div className={styles.mainArea}>\n <div className={styles.senderWrap}>\n {(headerNode || fileListNode) && (\n <div className={styles.contextBar}>\n {/* 头部插槽与附件共享上下文行,便于知识库、文件等输入上下文统一展示。 */}\n {headerNode && (\n <div className={styles.contextHeader}>{headerNode}</div>\n )}\n {fileListNode}\n </div>\n )}\n\n {/* textarea 模式下保留历史标签展示;inlineTags 模式标签直接混排在输入区内 */}\n {!inlineTags && (\n <InputTags mentions={mentions} onRemove={handleRemoveMention} />\n )}\n\n <div className={styles.inputAndButtons}>\n {/* 前缀插槽 */}\n {renderSlot(prefix, false)}\n\n {inlineTags ? (\n <InlineTagInput\n ref={inlineInputRef}\n value={value}\n mentions={mentions}\n defaultInputParts={defaultInputParts}\n placeholder={placeholder}\n disabled={inputDisabled}\n onChange={handleInlineInputChange}\n onMentionsChange={setMentions}\n onKeyDown={handleKeyDown as any}\n onKeyUp={handleInlineKeyUp}\n renderMention={renderMention ?? renderTag}\n />\n ) : (\n <div className={styles.textAreaWrapper}>\n <Input.TextArea\n ref={textareaRef}\n className={styles.textArea}\n value={value}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n onKeyUp={handleKeyUp}\n placeholder={placeholder}\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 </div>\n\n {/* 快捷键弹出列表 */}\n {activeQuickKey && activeQuickKeyConfig && (\n <div className={styles.quickListWrapper}>\n <InputSuggestionList\n config={activeQuickKeyConfig}\n activeIndex={quickKeyActiveIndex}\n onSelect={handleQuickKeySelect}\n onClose={() => {\n setActiveQuickKey(null);\n setQuickKeyKeyword(\"\");\n setQuickKeyTriggerIdx(-1);\n setQuickKeyActiveIndex(0);\n }}\n visible={true}\n />\n </div>\n )}\n\n {/* 底部操作行:左侧上传/业务按钮,右侧清空/发送按钮 */}\n {footer === false\n ? defaultActionBar\n : renderSlot(footer, defaultActionBar)}\n </div>\n </div>\n\n {/* 提示文案 */}\n {!footer && (\n <div className={styles.tip}>\n 内容由AI生成,无法确保真实准确,仅供参考\n </div>\n )}\n </div>\n );\n },\n);\n\nXAdkSender.displayName = \"XAdkSender\";\nexport default XAdkSender;\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import React, {\n useState,\n useRef,\n useCallback,\n forwardRef,\n useImperativeHandle,\n useMemo,\n useEffect,\n} from \"react\";\nimport { Popconfirm, message, Tooltip, Input, Modal } from \"antd\";\nimport {\n ClearOutlined,\n LoadingOutlined,\n ArrowUpOutlined,\n} from \"@ant-design/icons\";\nimport {\n XAdkSenderProps,\n XAdkSenderHandle,\n ServerFile,\n LocalFile,\n ActionsComponents,\n FileValidator,\n UploadFileResult,\n MentionTag,\n XAdkSenderSubmitData,\n XAdkSenderSubmitFormat,\n XAdkSenderSubmitPart,\n} from \"@/types\";\nimport { useStyles } from \"./styles\";\nimport FileGallery from \"../FileGallery\";\nimport InputSuggestionList from \"./InputSuggestionList\";\nimport InputTags from \"./InputTags\";\nimport InlineTagInput, { InlineTagInputRef } from \"./InlineTagInput\";\nimport { getExt } from \"@/utils/file\";\n\nconst XAdkSender = forwardRef<XAdkSenderHandle, XAdkSenderProps>(\n (\n {\n clearBtnShow = true,\n draggable = false,\n onFileSelect,\n loading = false,\n disabled = false,\n value: controlledValue,\n defaultValue = \"\",\n uploadRequest = () => {},\n onClear,\n onChange,\n onSubmit,\n onStop,\n onFilesChange,\n onUploadSuccess,\n onUploadError,\n maxFileSize = 10,\n placeholder = \"\",\n validators: customValidators = [],\n allowedFileTypes = [],\n maxFiles = Infinity,\n sendButtonRender,\n suffix,\n header,\n prefix,\n footer,\n footerLeft,\n quickKeys = [],\n inlineTags = false,\n renderMention,\n renderTag,\n mentions: controlledMentions,\n tags: controlledTags,\n defaultMentions,\n defaultTags = [],\n defaultInputParts,\n onMentionsChange,\n onTagsChange,\n onQuickKeyTrigger,\n submitFormat = \"text\",\n formatMention,\n formatTag,\n transformSubmitData,\n },\n ref,\n ) => {\n const styles = useStyles();\n const isControlled = controlledValue !== undefined;\n const [internalValue, setInternalValue] = useState<string>(defaultValue);\n const value = isControlled ? controlledValue : internalValue;\n const setValue = (newValue: string) => {\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onChange?.(newValue);\n };\n\n // mentions 支持受控/非受控两种模式;inlineTags 打开时会和输入内容混排。\n const resolvedControlledMentions = controlledMentions ?? controlledTags;\n const initialMentions = defaultMentions ?? defaultTags;\n const isMentionsControlled = resolvedControlledMentions !== undefined;\n const [internalMentions, setInternalMentions] =\n useState<MentionTag[]>(initialMentions);\n const mentions = isMentionsControlled\n ? resolvedControlledMentions!\n : internalMentions;\n const setMentions = (newMentions: MentionTag[]) => {\n if (!isMentionsControlled) {\n setInternalMentions(newMentions);\n }\n onMentionsChange?.(newMentions);\n onTagsChange?.(newMentions);\n };\n\n const [files, setFiles] = useState<LocalFile[]>([]);\n const [isDragOver, setIsDragOver] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n const textareaRef = useRef<any>(null);\n const inlineInputRef = useRef<InlineTagInputRef>(null);\n\n // 快捷键弹层状态:记录触发字符、关键词,以及触发字符在纯文本中的位置。\n // SDK 不内置搜索框;业务方可在 onQuickKeyTrigger 中根据 keyword 自行更新 quickKeys.options。\n const [activeQuickKey, setActiveQuickKey] = useState<string | null>(null);\n const [quickKeyKeyword, setQuickKeyKeyword] = useState(\"\");\n const [quickKeyTriggerIdx, setQuickKeyTriggerIdx] = useState(-1);\n const [quickKeyActiveIndex, setQuickKeyActiveIndex] = useState(0);\n\n const closeQuickKeyList = useCallback(() => {\n setActiveQuickKey(null);\n setQuickKeyKeyword(\"\");\n setQuickKeyTriggerIdx(-1);\n setQuickKeyActiveIndex(0);\n }, []);\n\n // 生成唯一ID\n const generateId = () => {\n return Date.now().toString(36) + Math.random().toString(36).substr(2);\n };\n\n const normalizeUploadResponse = (response: any): UploadFileResult => {\n const data = response?.data ?? response;\n return (Array.isArray(data) ? data[0] : data) ?? {};\n };\n\n const escapeXml = (text: string) =>\n text\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n\n const escapeMarkdownLabel = (text: string) =>\n text.replace(/\\\\/g, \"\\\\\\\\\").replace(/\\]/g, \"\\\\]\");\n\n const getMentionSubmitValue = (mention: MentionTag) =>\n String(\n mention.value ??\n mention.uri ??\n mention.data?.uri ??\n mention.data?.value ??\n mention.data?.name ??\n mention.targetId ??\n mention.displayName ??\n mention.label ??\n \"\",\n );\n\n const defaultFormatMention = (\n mention: MentionTag,\n format: Exclude<XAdkSenderSubmitFormat, \"structured\">,\n index: number,\n ) => {\n const value = getMentionSubmitValue(mention);\n if (format === \"xml\") {\n return `<mention type=\"${escapeXml(mention.type)}\" id=\"${escapeXml(mention.id)}\" label=\"${escapeXml(mention.label)}\" value=\"${escapeXml(value)}\" />`;\n }\n\n if (format === \"markdown\") {\n const href =\n mention.uri ||\n (value.includes(\"://\")\n ? value\n : `xadk-mention://${encodeURIComponent(mention.type)}/${encodeURIComponent(mention.id)}`);\n return `[@${escapeMarkdownLabel(mention.displayName || mention.label)}](${href})`;\n }\n\n return `@${mention.displayName || value || `mention-${index + 1}`}`;\n };\n\n const serializeMention = (\n mention: MentionTag,\n format: Exclude<XAdkSenderSubmitFormat, \"structured\">,\n index: number,\n ) =>\n formatMention?.(mention, { format, index }) ??\n formatTag?.(mention, { format, index }) ??\n defaultFormatMention(mention, format, index);\n\n const getSubmitParts = useCallback((): XAdkSenderSubmitPart[] => {\n if (inlineTags) {\n const parts = inlineInputRef.current?.getParts() || [];\n if (parts.length > 0) return parts;\n }\n\n const textParts: XAdkSenderSubmitPart[] = value\n ? [{ type: \"text\", text: value }]\n : [];\n const mentionParts = mentions.map((mention) => ({\n type: \"mention\" as const,\n mention,\n }));\n return [...mentionParts, ...textParts];\n }, [inlineTags, mentions, value]);\n\n const serializeParts = (\n parts: XAdkSenderSubmitPart[],\n format: XAdkSenderSubmitFormat,\n ) => {\n if (format === \"structured\") {\n return parts.reduce(\n (content, part) => content + (part.type === \"text\" ? part.text : \"\"),\n \"\",\n );\n }\n\n let tagIndex = 0;\n return parts\n .map((part) => {\n if (part.type === \"text\") return part.text;\n const result = serializeMention(part.mention, format, tagIndex);\n tagIndex += 1;\n return result;\n })\n .join(\"\");\n };\n\n const createSubmitData = (\n formattedFiles: ServerFile[],\n ): XAdkSenderSubmitData => {\n const parts = getSubmitParts();\n const rawText = parts.reduce(\n (content, part) => content + (part.type === \"text\" ? part.text : \"\"),\n \"\",\n );\n const standardData: Omit<XAdkSenderSubmitData, \"payload\"> = {\n text: serializeParts(parts, submitFormat),\n rawText,\n format: submitFormat,\n parts,\n files: formattedFiles,\n mentions,\n tags: mentions,\n };\n\n return {\n ...standardData,\n payload: transformSubmitData?.(standardData),\n };\n };\n\n // 检查文件类型\n const checkFileType = (file: File): boolean => {\n if (allowedFileTypes?.length > 0) {\n const ext = getExt(file);\n\n return allowedFileTypes.some((type) => {\n if (type.includes(\"/\")) {\n if (type.endsWith(\"/*\")) {\n return file.type.startsWith(type.split(\"/\")[0]);\n }\n return file.type === type;\n }\n\n if (type.startsWith(\".\")) {\n return ext === type.slice(1);\n }\n\n return false;\n });\n }\n return true;\n };\n\n // 重复文件检测\n const isDuplicateFile = (file: File, files: LocalFile[]) => {\n return files.some((f) => f.name === file.name && f.size === file.size);\n };\n\n // 内置校验器集合\n const builtInValidators: FileValidator[] = [\n (_file, { files }) => {\n if (files.length >= maxFiles) {\n return `最多只能上传 ${maxFiles} 个文件`;\n }\n return null;\n },\n (file) => {\n const maxSize = maxFileSize * 1024 * 1024;\n if (file.size > maxSize) {\n return `文件大小不能超过 ${maxFileSize}MB`;\n }\n return null;\n },\n (file) => {\n if (!checkFileType(file)) {\n return \"不支持的文件类型\";\n }\n return null;\n },\n (file, { files }) => {\n if (isDuplicateFile(file, files)) {\n return \"文件已存在\";\n }\n return null;\n },\n ];\n\n const allValidators = [...builtInValidators, ...customValidators];\n\n // 验证文件\n const validateFile = (file: File): { valid: boolean; message?: string } => {\n for (const validator of allValidators) {\n const error = validator(file, { files });\n if (error) {\n return { valid: false, message: error };\n }\n }\n return { valid: true };\n };\n\n // 处理文件选择\n const handleFileSelect = useCallback(\n (selectedFiles: File[]) => {\n const fileArray = Array.from(selectedFiles);\n\n if (files.length + fileArray.length > maxFiles) {\n message.error(`最多只能上传 ${maxFiles} 个文件`);\n return;\n }\n\n const validFiles: LocalFile[] = [];\n\n fileArray.forEach((file) => {\n const validation = validateFile(file);\n\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) => {\n const next = [...prev, ...validFiles];\n onFilesChange?.(next);\n return next;\n });\n uploadFiles(validFiles);\n }\n },\n [files, maxFiles, maxFileSize, allowedFileTypes],\n );\n\n // 暴露给业务工具栏调用的命令式能力;外部 Popover 选择标签时可插入到当前光标位置。\n useImperativeHandle(\n ref,\n () => ({\n addFiles: (rawFiles: File[]) => {\n handleFileSelect(rawFiles);\n },\n insertMention: (mention: MentionTag) => {\n if (inlineTags) {\n inlineInputRef.current?.insertMention(mention);\n return;\n }\n setMentions([...mentions, mention]);\n },\n insertTag: (mention: MentionTag) => {\n if (inlineTags) {\n inlineInputRef.current?.insertMention(mention);\n return;\n }\n setMentions([...mentions, mention]);\n },\n focus: () => {\n inlineTags\n ? inlineInputRef.current?.focus()\n : textareaRef.current?.focus();\n },\n }),\n [handleFileSelect, inlineTags, setMentions, mentions],\n );\n\n // 上传文件\n const uploadFiles = async (fileList: LocalFile[]) => {\n for (const localFile of fileList) {\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 const responseData = normalizeUploadResponse(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 fileId: responseData.fileId || responseData.id,\n tempUrl:\n responseData.tempUrl ||\n responseData.fileUrl ||\n responseData.url,\n }\n : f,\n ),\n );\n\n onUploadSuccess?.({\n ...localFile,\n status: \"success\",\n response,\n fileId: responseData.fileId || responseData.id,\n tempUrl:\n responseData.tempUrl ||\n responseData.fileUrl ||\n responseData.url,\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 onUploadError?.(localFile, error);\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 handleRemoveFile = (id: string) => {\n setFiles((prev) => {\n const next = prev.filter((file) => file.id !== id);\n onFilesChange?.(next);\n return next;\n });\n };\n\n // 处理拖拽事件\n const handleDragOver = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (draggable) {\n setIsDragOver(true);\n }\n },\n [draggable],\n );\n\n const handleDragLeave = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (draggable) {\n setIsDragOver(false);\n }\n },\n [draggable],\n );\n\n const handleDrop = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragOver(false);\n\n if (\n draggable &&\n e.dataTransfer.files &&\n e.dataTransfer.files.length > 0\n ) {\n // 内核不再自行处理文件,交给外层(DefaultLayout/业务)通过 onFileSelect 决定\n onFileSelect?.(Array.from(e.dataTransfer.files));\n }\n },\n [draggable, onFileSelect],\n );\n\n // 删除标签\n const handleRemoveMention = useCallback(\n (id: string) => {\n setMentions(mentions.filter((item) => item.id !== id));\n },\n [mentions, setMentions],\n );\n\n // 查找当前活跃的快捷键配置\n const activeQuickKeyConfig = useMemo(() => {\n if (!activeQuickKey) return null;\n return quickKeys.find((qk) => qk.key === activeQuickKey) || null;\n }, [activeQuickKey, quickKeys]);\n\n const activeQuickKeyOptionsLength =\n activeQuickKeyConfig?.options.length || 0;\n\n useEffect(() => {\n setQuickKeyActiveIndex(0);\n }, [activeQuickKey]);\n\n useEffect(() => {\n if (activeQuickKeyOptionsLength <= 0) {\n setQuickKeyActiveIndex(0);\n return;\n }\n\n // 业务方可能在 onQuickKeyTrigger 中动态更新 options;\n // 这里只做越界归一化,不重置有效索引,避免键盘高亮移动后又跳回第一项。\n setQuickKeyActiveIndex(\n (prev) =>\n ((prev % activeQuickKeyOptionsLength) + activeQuickKeyOptionsLength) %\n activeQuickKeyOptionsLength,\n );\n }, [activeQuickKeyOptionsLength]);\n\n const getNextQuickKeyIndex = useCallback(\n (current: number, step: number) => {\n if (activeQuickKeyOptionsLength <= 0) return 0;\n return (\n (current + step + activeQuickKeyOptionsLength) %\n activeQuickKeyOptionsLength\n );\n },\n [activeQuickKeyOptionsLength],\n );\n\n // 从当前光标前的连续文本片段中查找最近的快捷键,例如 abc@doc 会触发 @。\n const detectQuickKey = useCallback(\n (text: string, cursorPos: number) => {\n const quickKeyChars = quickKeys.map((qk) => qk.key);\n if (quickKeyChars.length === 0) return;\n\n const textBeforeCursor = text.slice(0, cursorPos);\n let found = false;\n for (let i = textBeforeCursor.length - 1; i >= 0; i--) {\n const char = textBeforeCursor[i];\n if (/\\s/.test(char)) break;\n if (quickKeyChars.includes(char)) {\n const keyword = textBeforeCursor.slice(i + 1);\n setActiveQuickKey(char);\n setQuickKeyKeyword(keyword);\n setQuickKeyTriggerIdx(i);\n setQuickKeyActiveIndex(0);\n onQuickKeyTrigger?.(char, keyword);\n found = true;\n break;\n }\n }\n\n if (!found && activeQuickKey) {\n const triggerChar = text[quickKeyTriggerIdx];\n const keyword = text.slice(quickKeyTriggerIdx + 1, cursorPos);\n if (\n quickKeyTriggerIdx < 0 ||\n !triggerChar ||\n !quickKeyChars.includes(triggerChar) ||\n /\\s/.test(keyword)\n ) {\n setActiveQuickKey(null);\n setQuickKeyKeyword(\"\");\n setQuickKeyTriggerIdx(-1);\n setQuickKeyActiveIndex(0);\n } else {\n setQuickKeyKeyword(keyword);\n }\n }\n },\n [activeQuickKey, onQuickKeyTrigger, quickKeyTriggerIdx, quickKeys],\n );\n\n // 选择快捷项后转成结构化 Mention;inline 模式会替换掉触发字符和关键词。\n const handleQuickKeySelect = useCallback(\n (option: any) => {\n const mentionType =\n activeQuickKeyConfig?.mentionType ||\n activeQuickKeyConfig?.tagType ||\n activeQuickKey ||\n \"unknown\";\n const newMention: MentionTag = {\n id: generateId(),\n label: option.label,\n type: mentionType,\n value: option.value ?? option.uri ?? option.name ?? option.label,\n uri: option.uri,\n targetId: option.targetId ?? option.skillNo ?? option.pluginNo,\n displayName: option.displayName ?? option.label,\n trigger: activeQuickKey || undefined,\n icon: option.icon,\n data: option,\n };\n option.onSelect?.(option);\n activeQuickKeyConfig?.onSelect?.(option);\n\n if (option.action === \"command\") {\n if (inlineTags) {\n inlineInputRef.current?.deleteTextRange({\n start: quickKeyTriggerIdx,\n end: quickKeyTriggerIdx + 1 + quickKeyKeyword.length,\n });\n } else if (quickKeyTriggerIdx >= 0) {\n setValue(\n value.slice(0, quickKeyTriggerIdx) +\n value.slice(quickKeyTriggerIdx + 1 + quickKeyKeyword.length),\n );\n }\n } else if (inlineTags) {\n inlineInputRef.current?.insertMention(newMention, {\n start: quickKeyTriggerIdx,\n end: quickKeyTriggerIdx + 1 + quickKeyKeyword.length,\n });\n } else {\n setMentions([...mentions, newMention]);\n\n // 从输入框中删除快捷键字符和关键词\n if (quickKeyTriggerIdx >= 0) {\n const newValue =\n value.slice(0, quickKeyTriggerIdx) +\n value.slice(quickKeyTriggerIdx + 1 + quickKeyKeyword.length);\n setValue(newValue);\n }\n }\n\n setActiveQuickKey(null);\n setQuickKeyKeyword(\"\");\n setQuickKeyTriggerIdx(-1);\n setQuickKeyActiveIndex(0);\n inlineTags\n ? inlineInputRef.current?.focus()\n : textareaRef.current?.focus();\n },\n [\n activeQuickKey,\n activeQuickKeyConfig,\n inlineTags,\n mentions,\n setMentions,\n value,\n quickKeyTriggerIdx,\n quickKeyKeyword,\n setValue,\n ],\n );\n\n // 处理输入框变化(含快捷键检测)\n const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n const newValue = e.target.value;\n setValue(newValue);\n\n // 检测快捷键触发\n detectQuickKey(newValue, e.target.selectionStart || 0);\n };\n\n const handleInlineInputChange = (newValue: string) => {\n setValue(newValue);\n // contenteditable 的 selection 不一定和 React state 同步,需实时读取内部光标 offset。\n detectQuickKey(\n newValue,\n inlineInputRef.current?.getCursorOffset() || newValue.length,\n );\n };\n\n const handleQuickKeyByText = (text: string, cursorPos: number) => {\n const quickKeyChars = quickKeys.map((qk) => qk.key);\n if (quickKeyChars.length === 0) return;\n\n const textBeforeCursor = text.slice(0, cursorPos);\n\n // 检测刚输入的字符是否是快捷键\n const lastChar = textBeforeCursor[cursorPos - 1];\n if (lastChar && quickKeyChars.includes(lastChar)) {\n // 上下键导航后会触发 keyup,此时光标前仍是同一个快捷键字符;\n // 如果重复重置 activeIndex,视觉上会“移动一下又回到第一项”。\n if (\n activeQuickKey === lastChar &&\n quickKeyTriggerIdx === cursorPos - 1\n ) {\n return;\n }\n setActiveQuickKey(lastChar);\n setQuickKeyKeyword(\"\");\n setQuickKeyTriggerIdx(cursorPos - 1);\n setQuickKeyActiveIndex(0);\n onQuickKeyTrigger?.(lastChar, \"\");\n }\n };\n\n // onChange 负责更新搜索词;onKeyUp 兜底捕获刚输入的快捷键字符。\n const isQuickListControlKey = (key: string) =>\n key === \"ArrowDown\" ||\n key === \"ArrowUp\" ||\n key === \"Enter\" ||\n key === \"Escape\";\n\n const handleKeyUp = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (activeQuickKey && isQuickListControlKey(e.key)) return;\n const target = e.target as HTMLTextAreaElement;\n handleQuickKeyByText(target.value || \"\", target.selectionStart || 0);\n };\n\n const handleInlineKeyUp = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (activeQuickKey && isQuickListControlKey(e.key)) return;\n // inline 输入区不是 textarea,不能读 event.target.value,只能从 ref 取纯文本。\n const text = inlineInputRef.current?.getText() || \"\";\n const cursorPos =\n inlineInputRef.current?.getCursorOffset() || text.length;\n handleQuickKeyByText(text, cursorPos);\n };\n\n // 处理提交\n const handleSubmit = () => {\n // 生成期间允许继续编辑下一条消息,但停止按钮仍代表当前唯一可执行动作。\n if (loading) return;\n if (!value.trim() && files.length === 0 && mentions.length === 0) {\n message.warning(\"请输入消息或选择文件\");\n return;\n }\n\n const successFiles = files.filter((file) => file.status === \"success\");\n const uploadingFiles = files.filter(\n (file) => file.status === \"uploading\",\n );\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(createSubmitData(formattedFiles));\n }\n\n setValue(\"\");\n setMentions([]);\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(createSubmitData(formattedFiles));\n }\n\n setValue(\"\");\n setMentions([]);\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)\n .map((file) => {\n const responseData = normalizeUploadResponse(file.response);\n\n return {\n fileName: responseData.fileName || file.name,\n fileId: responseData.fileId || responseData.id || \"\",\n tempUrl:\n responseData.tempUrl ||\n responseData.fileUrl ||\n responseData.url ||\n \"\",\n type: responseData.fileType || responseData.type || getExt(file),\n size: responseData.fileSize || responseData.size || file.size,\n mimeType: responseData.mimeType || file.type,\n raw: {\n ...responseData,\n },\n };\n });\n };\n\n // 处理回车键\n const handleKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {\n // 输入法候选阶段的 Enter 用于确认候选词,不能触发快捷项选择或消息发送。\n if (e.nativeEvent.isComposing || e.keyCode === 229) return;\n\n const quickKeyOptions = activeQuickKeyConfig?.options || [];\n\n if (activeQuickKey && quickKeyOptions.length > 0) {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setQuickKeyActiveIndex((prev) => getNextQuickKeyIndex(prev, 1));\n return;\n }\n\n if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setQuickKeyActiveIndex((prev) => getNextQuickKeyIndex(prev, -1));\n return;\n }\n\n if (e.key === \"Enter\") {\n e.preventDefault();\n handleQuickKeySelect(\n quickKeyOptions[\n Math.min(quickKeyActiveIndex, quickKeyOptions.length - 1)\n ],\n );\n return;\n }\n\n if (e.key === \"Escape\") {\n e.preventDefault();\n setActiveQuickKey(null);\n setQuickKeyKeyword(\"\");\n setQuickKeyTriggerIdx(-1);\n setQuickKeyActiveIndex(0);\n return;\n }\n }\n\n if (e.key === \"Enter\" && !e.shiftKey && !activeQuickKey) {\n e.preventDefault();\n handleSubmit();\n }\n };\n\n // 渲染文件列表\n const renderFileList = () => {\n if (files.length === 0) return null;\n\n return (\n <div className={styles.contextFiles}>\n {files.map((file) => (\n <FileGallery\n key={file.id}\n file={file}\n size=\"small\"\n removable\n onRemove={handleRemoveFile}\n />\n ))}\n </div>\n );\n };\n\n const containerClass = `${styles.container} ${isDragOver ? \"drag-over\" : \"\"}`;\n const uploading = files.some((f) => f.status === \"uploading\");\n const controlsDisabled = disabled || uploading || loading;\n const inputDisabled = disabled || uploading;\n const hasContent = value.trim().length > 0;\n const hasFiles = files.some((f) => f.status === \"success\");\n const hasMentions = mentions.length > 0;\n const canSend = hasContent || hasFiles || hasMentions;\n\n // 定义按钮组件\n const SendButton = (props: any) => {\n if (sendButtonRender) {\n return (\n <>\n {sendButtonRender({\n loading,\n disabled: uploading || disabled,\n canSend,\n onSend: handleSubmit,\n onStop,\n })}\n </>\n );\n }\n return (\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 spin /> : <ArrowUpOutlined />}\n </button>\n </Tooltip>\n );\n };\n\n const ClearButton = (props: any) => (\n <Popconfirm\n title=\"确定要清空聊天记录吗?\"\n onConfirm={onClear}\n placement=\"top\"\n okText=\"确定\"\n cancelText=\"取消\"\n disabled={controlsDisabled}\n >\n <button\n className={`${styles.iconButton} ${styles.clearButton}`}\n disabled={controlsDisabled}\n aria-label=\"清空聊天记录\"\n {...props}\n >\n <ClearOutlined />\n </button>\n </Popconfirm>\n );\n\n const actionsComponents: ActionsComponents = {\n SendButton,\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 const headerNode = renderSlot(header, false);\n const fileListNode = files.length > 0 ? renderFileList() : null;\n\n // 默认后缀仅保留发送/停止按钮;上传与清空统一放到底部 actionBar,方便业务扩展左侧按钮组。\n const defaultSuffix = (\n <div className={styles.buttonGroup}>\n {sendButtonRender ? (\n sendButtonRender({\n loading,\n disabled: uploading || disabled,\n canSend,\n onSend: handleSubmit,\n onStop,\n })\n ) : (\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 >\n {loading ? <LoadingOutlined spin /> : <ArrowUpOutlined />}\n </button>\n </Tooltip>\n )}\n </div>\n );\n\n const defaultActionBar = (\n <div className={styles.actionBar}>\n <div className={styles.actionBarLeft}>\n {renderSlot(footerLeft, false)}\n </div>\n <div className={styles.actionBarRight}>\n {clearBtnShow && <ClearButton />}\n {renderSlot(suffix, defaultSuffix)}\n </div>\n </div>\n );\n\n return (\n <div\n ref={containerRef}\n className={containerClass}\n onBlur={(event) => {\n const nextFocusedNode = event.relatedTarget as Node | null;\n if (\n nextFocusedNode &&\n event.currentTarget.contains(nextFocusedNode)\n ) {\n return;\n }\n closeQuickKeyList();\n }}\n onDragOver={draggable ? handleDragOver : undefined}\n onDragLeave={draggable ? handleDragLeave : undefined}\n onDrop={draggable ? handleDrop : undefined}\n >\n <div className={styles.mainArea}>\n <div className={styles.senderWrap}>\n {(headerNode || fileListNode) && (\n <div className={styles.contextBar}>\n {/* 头部插槽与附件共享上下文行,便于知识库、文件等输入上下文统一展示。 */}\n {headerNode && (\n <div className={styles.contextHeader}>{headerNode}</div>\n )}\n {fileListNode}\n </div>\n )}\n\n {/* textarea 模式下保留历史标签展示;inlineTags 模式标签直接混排在输入区内 */}\n {!inlineTags && (\n <InputTags mentions={mentions} onRemove={handleRemoveMention} />\n )}\n\n <div className={styles.inputAndButtons}>\n {/* 前缀插槽 */}\n {renderSlot(prefix, false)}\n\n {inlineTags ? (\n <InlineTagInput\n ref={inlineInputRef}\n value={value}\n mentions={mentions}\n defaultInputParts={defaultInputParts}\n placeholder={placeholder}\n disabled={inputDisabled}\n onChange={handleInlineInputChange}\n onMentionsChange={setMentions}\n onKeyDown={handleKeyDown as any}\n onKeyUp={handleInlineKeyUp}\n renderMention={renderMention ?? renderTag}\n />\n ) : (\n <div className={styles.textAreaWrapper}>\n <Input.TextArea\n ref={textareaRef}\n className={styles.textArea}\n value={value}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n onKeyUp={handleKeyUp}\n placeholder={placeholder}\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 </div>\n\n {/* 快捷键弹出列表 */}\n {activeQuickKey && activeQuickKeyConfig && (\n <div className={styles.quickListWrapper}>\n <InputSuggestionList\n config={activeQuickKeyConfig}\n activeIndex={quickKeyActiveIndex}\n onSelect={handleQuickKeySelect}\n onClose={closeQuickKeyList}\n visible={true}\n />\n </div>\n )}\n\n {/* 底部操作行:左侧上传/业务按钮,右侧清空/发送按钮 */}\n {footer === false\n ? defaultActionBar\n : renderSlot(footer, defaultActionBar)}\n </div>\n </div>\n\n {/* 提示文案 */}\n {!footer && (\n <div className={styles.tip}>\n 内容由AI生成,无法确保真实准确,仅供参考\n </div>\n )}\n </div>\n );\n },\n);\n\nXAdkSender.displayName = \"XAdkSender\";\nexport default XAdkSender;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["value", "files", "FileGallery", "InputTags", "InlineTagInput", "InputSuggestionList"]
|
|
7
7
|
}
|
|
@@ -568,7 +568,13 @@ var InlineTagInput = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
568
568
|
// emitChange 的受控回写要到下一次 render 才生效;跳过本轮紧随其后的空值清理,
|
|
569
569
|
// 避免刚渲染的默认 Mention 被旧的空 value/mentions 立即移除。
|
|
570
570
|
skipEmptyCleanupOnceRef.current = true;
|
|
571
|
+
latestMentionsRef.current = defaultInputParts.flatMap(function (part) {
|
|
572
|
+
if (part.type === "mention") return [part.mention];
|
|
573
|
+
if (part.type === "tag") return [part.tag];
|
|
574
|
+
return [];
|
|
575
|
+
});
|
|
571
576
|
renderPartsToEditor(defaultInputParts);
|
|
577
|
+
setHasContent(true);
|
|
572
578
|
emitChange();
|
|
573
579
|
return;
|
|
574
580
|
}
|