mirror of
https://github.com/stablyai/orca
synced 2026-04-21 14:17:16 +00:00
fix: suppress Enter submit during IME composition in workflow creation popup (#804)
* fix: guard Enter submit against IME composition in workflow creation popup Pressing Enter during Japanese IME conversion was triggering workflow submission instead of only confirming the candidate. Extract shouldSuppressEnterSubmit() and check event.isComposing before submit in NewWorkspaceComposerModal, NewWorkspacePage, and the task search handler. Fixes #742. * fix: use nativeEvent.isComposing for React SyntheticEvent in task search handler * refactor: move new-workspace-enter-guard to src/renderer/src/lib --------- Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
This commit is contained in:
parent
159081c2e6
commit
5d985a6563
4 changed files with 64 additions and 1 deletions
|
|
@ -4,6 +4,7 @@ import { Dialog, DialogContent, DialogDescription, DialogTitle } from '@/compone
|
|||
import NewWorkspaceComposerCard from '@/components/NewWorkspaceComposerCard'
|
||||
import { useComposerState } from '@/hooks/useComposerState'
|
||||
import type { LinkedWorkItemSummary } from '@/lib/new-workspace'
|
||||
import { shouldSuppressEnterSubmit } from '@/lib/new-workspace-enter-guard'
|
||||
|
||||
type ComposerModalData = {
|
||||
prefilledName?: string
|
||||
|
|
@ -102,7 +103,7 @@ function ComposerModalBody({
|
|||
if (createDisabled) {
|
||||
return
|
||||
}
|
||||
if (target instanceof HTMLTextAreaElement && event.shiftKey) {
|
||||
if (shouldSuppressEnterSubmit(event, target instanceof HTMLTextAreaElement)) {
|
||||
return
|
||||
}
|
||||
event.preventDefault()
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import { getLinkedWorkItemSuggestedName, getTaskPresetQuery } from '@/lib/new-wo
|
|||
import type { LinkedWorkItemSummary } from '@/lib/new-workspace'
|
||||
import { isGitRepoKind } from '../../../shared/repo-kind'
|
||||
import type { GitHubWorkItem, TaskViewPresetId } from '../../../shared/types'
|
||||
import { shouldSuppressEnterSubmit } from '@/lib/new-workspace-enter-guard'
|
||||
|
||||
type TaskSource = 'github' | 'linear'
|
||||
type TaskQueryPreset = {
|
||||
|
|
@ -332,6 +333,15 @@ export default function NewWorkspacePage(): React.JSX.Element {
|
|||
const handleTaskSearchKeyDown = useCallback(
|
||||
(event: React.KeyboardEvent<HTMLInputElement>): void => {
|
||||
if (event.key === 'Enter') {
|
||||
// React SyntheticEvent does not expose isComposing; use nativeEvent.
|
||||
if (
|
||||
shouldSuppressEnterSubmit(
|
||||
{ isComposing: event.nativeEvent.isComposing, shiftKey: event.shiftKey },
|
||||
false
|
||||
)
|
||||
) {
|
||||
return
|
||||
}
|
||||
event.preventDefault()
|
||||
handleApplyTaskSearch()
|
||||
}
|
||||
|
|
|
|||
33
src/renderer/src/lib/new-workspace-enter-guard.test.ts
Normal file
33
src/renderer/src/lib/new-workspace-enter-guard.test.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import { describe, it, expect } from 'vitest'
|
||||
import { shouldSuppressEnterSubmit } from './new-workspace-enter-guard'
|
||||
|
||||
function makeEvent(overrides: Partial<{ isComposing: boolean; shiftKey: boolean }>): {
|
||||
isComposing: boolean
|
||||
shiftKey: boolean
|
||||
} {
|
||||
return { isComposing: false, shiftKey: false, ...overrides }
|
||||
}
|
||||
|
||||
describe('shouldSuppressEnterSubmit', () => {
|
||||
it('returns false for a plain Enter with no composition', () => {
|
||||
expect(shouldSuppressEnterSubmit(makeEvent({}), false)).toBe(false)
|
||||
})
|
||||
|
||||
it('returns true when IME composition is active', () => {
|
||||
expect(shouldSuppressEnterSubmit(makeEvent({ isComposing: true }), false)).toBe(true)
|
||||
})
|
||||
|
||||
it('returns true for Shift+Enter inside a textarea', () => {
|
||||
expect(shouldSuppressEnterSubmit(makeEvent({ shiftKey: true }), true)).toBe(true)
|
||||
})
|
||||
|
||||
it('returns false for Shift+Enter inside a non-textarea element', () => {
|
||||
expect(shouldSuppressEnterSubmit(makeEvent({ shiftKey: true }), false)).toBe(false)
|
||||
})
|
||||
|
||||
it('returns true when both isComposing and shiftKey are true (textarea)', () => {
|
||||
expect(shouldSuppressEnterSubmit(makeEvent({ isComposing: true, shiftKey: true }), true)).toBe(
|
||||
true
|
||||
)
|
||||
})
|
||||
})
|
||||
19
src/renderer/src/lib/new-workspace-enter-guard.ts
Normal file
19
src/renderer/src/lib/new-workspace-enter-guard.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* Returns true when an Enter keydown event should be suppressed for submit actions.
|
||||
*
|
||||
* Two cases must be blocked:
|
||||
* 1. IME composition is active — Enter only confirms the conversion candidate.
|
||||
* 2. Shift+Enter inside a textarea — intended as a newline, not a submit.
|
||||
*/
|
||||
export function shouldSuppressEnterSubmit(
|
||||
event: { isComposing: boolean; shiftKey: boolean },
|
||||
isTextarea: boolean
|
||||
): boolean {
|
||||
if (event.isComposing) {
|
||||
return true
|
||||
}
|
||||
if (isTextarea && event.shiftKey) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
Loading…
Reference in a new issue