diff --git a/packages/client/ui-conversation/tests/assembly-surfaces.spec.tsx b/packages/client/ui-conversation/tests/assembly-surfaces.spec.tsx index 5d7f4c05e7..74336315d3 100644 --- a/packages/client/ui-conversation/tests/assembly-surfaces.spec.tsx +++ b/packages/client/ui-conversation/tests/assembly-surfaces.spec.tsx @@ -97,7 +97,7 @@ describe('todo_write assembly (product registrations, no outlet twins)', () => { const view = runtime.renderRoot() // Keyed toolview registration took the row (summary derived from args). - const row = view.container.querySelector('[data-sample="todo-row"]') + const row = view.container.querySelector('[data-tool="todo_write"]') expect(row).not.toBeNull() expect(row!.textContent).toContain('1/3 已完成 · 实现 fixture 样本') @@ -117,7 +117,7 @@ describe('todo_write assembly (product registrations, no outlet twins)', () => { await waitFor(() => { expect(view.container.querySelector('[data-testid="todo-panel"]')).toBeNull() }) - expect(view.container.querySelector('[data-sample="todo-row"]')).not.toBeNull() + expect(view.container.querySelector('[data-tool="todo_write"]')).not.toBeNull() await runtime.dispose() }) }) diff --git a/packages/client/ui-question/src/client/QuestionComposer.tsx b/packages/client/ui-question/src/client/QuestionComposer.tsx index db1c2ec353..d8ae56d502 100644 --- a/packages/client/ui-question/src/client/QuestionComposer.tsx +++ b/packages/client/ui-question/src/client/QuestionComposer.tsx @@ -1,4 +1,4 @@ -import { useMemo, useState, type KeyboardEvent } from 'react' +import { useMemo, useState, type ChangeEvent, type KeyboardEvent } from 'react' import clsx from 'clsx' import { Button, IconCheckOutline14, IconChevronLeftOutline14, IconChevronRightOutline14, @@ -149,6 +149,23 @@ function QuestionFlow({ pending, t, useLocale }: { submitDrafts(drafts) } + // Shared by the inline custom input and the optionless textarea: typing a + // custom draft clears any selection, and Enter continues the flow + // (Shift+Enter stays a newline in the textarea; on the single-line input it + // is inert either way). + const draftCustom = (event: ChangeEvent): void => { + const value = event.target.value + updateDraft(current => ({ + ...current, selected: [], custom: value, skipped: false, + })) + } + + const continueFromCustom = (event: KeyboardEvent): void => { + if (event.key !== 'Enter' || event.shiftKey || isComposing(event)) return + event.preventDefault() + continueFlow() + } + const skipQuestion = (): void => { const nextDrafts = drafts.map((item, itemIndex) => itemIndex === index ? { selected: [], custom: '', skipped: true } @@ -247,18 +264,8 @@ function QuestionFlow({ pending, t, useLocale }: { value={draft.custom} disabled={busy !== null} placeholder={t('custom.placeholder')} - onChange={(event) => { - const value = event.target.value - updateDraft(current => ({ - ...current, selected: [], custom: value, skipped: false, - })) - }} - onKeyDown={(event) => { - if (event.key === 'Enter' && !isComposing(event)) { - event.preventDefault() - continueFlow() - } - }} + onChange={draftCustom} + onKeyDown={continueFromCustom} /> ) @@ -270,18 +277,8 @@ function QuestionFlow({ pending, t, useLocale }: { disabled={busy !== null} rows={2} placeholder={t('custom.placeholder')} - onChange={(event) => { - const value = event.target.value - updateDraft(current => ({ - ...current, selected: [], custom: value, skipped: false, - })) - }} - onKeyDown={(event) => { - if (event.key === 'Enter' && !event.shiftKey && !isComposing(event)) { - event.preventDefault() - continueFlow() - } - }} + onChange={draftCustom} + onKeyDown={continueFromCustom} /> )}