diff --git a/packages/docs/src/pages/components/sender/demo/slot-format-result.vue b/packages/docs/src/pages/components/sender/demo/slot-format-result.vue new file mode 100644 index 0000000..00a6c42 --- /dev/null +++ b/packages/docs/src/pages/components/sender/demo/slot-format-result.vue @@ -0,0 +1,79 @@ + + + + + +通过 `formatResult` 格式化所有词槽类型的最终输出,包括可编辑的 `content` 词槽。 + + + +Use `formatResult` to format the final output of every slot type, including editable `content` slots. + diff --git a/packages/docs/src/pages/components/sender/index.en-US.md b/packages/docs/src/pages/components/sender/index.en-US.md index 122e2d6..12c432f 100644 --- a/packages/docs/src/pages/components/sender/index.en-US.md +++ b/packages/docs/src/pages/components/sender/index.en-US.md @@ -14,6 +14,7 @@ description: A chat input component for sending messages. Basic Usage Feature Toggle Slot Mode +Slot Format Result Instance Methods Submit Methods Voice Input @@ -144,11 +145,11 @@ interface SenderFocusOptions extends FocusOptions { #### SlotConfigType -| Property | Description | Type | -| ------------ | ------------------------------------------------------------ | ----------------------------------------------------------------- | -| type | Node type, determines the rendering component type, required | `'text' \| 'input' \| 'select' \| 'tag' \| 'content' \| 'custom'` | -| key | Unique identifier, can be omitted when type is `text` | `string` | -| formatResult | Format the final result | `(value: any) => string` | +| Property | Description | Type | +| ------------ | ----------------------------------------------------------------------- | ----------------------------------------------------------------- | +| type | Node type, determines the rendering component type, required | `'text' \| 'input' \| 'select' \| 'tag' \| 'content' \| 'custom'` | +| key | Unique identifier, can be omitted when type is `text` | `string` | +| formatResult | Format the final result; applies to all slot types, including `content` | `(value: any) => string` | ##### text node properties diff --git a/packages/docs/src/pages/components/sender/index.zh-CN.md b/packages/docs/src/pages/components/sender/index.zh-CN.md index a9b5242..15c084c 100644 --- a/packages/docs/src/pages/components/sender/index.zh-CN.md +++ b/packages/docs/src/pages/components/sender/index.zh-CN.md @@ -14,6 +14,7 @@ description: 用于聊天的输入框组件。 基本用法 功能开关 词槽模式 +词槽格式化 实例方法 提交方式 语音输入 @@ -144,11 +145,11 @@ interface SenderFocusOptions extends FocusOptions { #### SlotConfigType -| 属性 | 说明 | 类型 | -| ------------ | --------------------------------- | ----------------------------------------------------------------- | -| type | 节点类型,决定渲染组件类型,必填 | `'text' \| 'input' \| 'select' \| 'tag' \| 'content' \| 'custom'` | -| key | 唯一标识,type 为 `text` 时可省略 | `string` | -| formatResult | 格式化最终结果 | `(value: any) => string` | +| 属性 | 说明 | 类型 | +| ------------ | -------------------------------------------------- | ----------------------------------------------------------------- | +| type | 节点类型,决定渲染组件类型,必填 | `'text' \| 'input' \| 'select' \| 'tag' \| 'content' \| 'custom'` | +| key | 唯一标识,type 为 `text` 时可省略 | `string` | +| formatResult | 格式化最终结果,对所有词槽类型(含 `content`)生效 | `(value: any) => string` | ##### text 节点属性 diff --git a/packages/x/components/sender/__tests__/index.test.tsx b/packages/x/components/sender/__tests__/index.test.tsx index b49a18f..2d1f8c5 100644 --- a/packages/x/components/sender/__tests__/index.test.tsx +++ b/packages/x/components/sender/__tests__/index.test.tsx @@ -290,6 +290,101 @@ describe("Sender", () => { ); }); + it("should format content slots using the latest DOM text", async () => { + const formatResult = vi.fn((value: any) => `[formatted:${value}]`); + const wrapper = mount(Sender, { + props: { + slotConfig: [ + { + type: "content", + key: "content", + props: { defaultValue: "Initial Value" }, + formatResult, + }, + ], + }, + }); + await wrapper.vm.$nextTick(); + + const contentSlot = wrapper.find(".antd-sender-slot-content"); + contentSlot.element.innerText = "Edited Value"; + await wrapper.find(".antd-sender-input-slot").trigger("input"); + + expect(formatResult).toHaveBeenLastCalledWith("Edited Value"); + expect((wrapper.vm as any).getValue()).toEqual( + expect.objectContaining({ + value: " [formatted:Edited Value] ", + slotConfig: [ + expect.objectContaining({ + key: "content", + type: "content", + value: "[formatted:Edited Value]", + }), + ], + }), + ); + }); + + it("should return raw content slot text without formatResult", async () => { + const wrapper = mount(Sender, { + props: { + slotConfig: [ + { + type: "content", + key: "content", + props: { defaultValue: "Content Value" }, + }, + ], + }, + }); + await wrapper.vm.$nextTick(); + + expect((wrapper.vm as any).getValue().value).toBe(" Content Value "); + expect((wrapper.vm as any).getValue().slotConfig).toEqual([ + expect.objectContaining({ + key: "content", + type: "content", + value: "Content Value", + }), + ]); + }); + + it("should format content and other slot types together", async () => { + const wrapper = mount(Sender, { + props: { + slotConfig: [ + { type: "text", value: 'Translate "' }, + { + type: "content", + key: "content", + props: { defaultValue: "Hello" }, + formatResult: (value: any) => `[${value}]`, + }, + { type: "text", value: '" from ' }, + { + type: "select", + key: "language", + props: { + defaultValue: "English", + options: ["English", "Chinese"], + }, + formatResult: (value: any) => `{${value}}`, + }, + ], + }, + }); + await wrapper.vm.$nextTick(); + + const result = (wrapper.vm as any).getValue(); + expect(result.value).toBe('Translate " [Hello] " from {English}'); + expect(result.slotConfig).toEqual( + expect.arrayContaining([ + expect.objectContaining({ type: "content", value: "[Hello]" }), + expect.objectContaining({ type: "select", value: "{English}" }), + ]), + ); + }); + it("should support slot insert and getValue on ref", async () => { const wrapper = mount(Sender, { props: { diff --git a/packages/x/components/sender/components/SlotTextArea.tsx b/packages/x/components/sender/components/SlotTextArea.tsx index bb6cd38..febcbfd 100644 --- a/packages/x/components/sender/components/SlotTextArea.tsx +++ b/packages/x/components/sender/components/SlotTextArea.tsx @@ -211,11 +211,14 @@ export default defineComponent({ } const config = nodeInfo.slotConfig; - if (!config || config.type === "content") { + if (!config) { return element.innerText || ""; } - const rawValue = slotValues.value[nodeInfo.slotKey]; + const rawValue = + config.type === "content" + ? element.innerText || "" + : slotValues.value[nodeInfo.slotKey]; const formatted = config.formatResult?.(rawValue); return formatted ?? stringifyValue(rawValue); }