Skip to content

fix(prompt-input): leave a composition-ending Escape to the IME - #164

Open
pratikbuilds wants to merge 3 commits into
corbitsdev:mainfrom
pratikbuilds:claude/i142-claim-escape-ime
Open

pratikbuilds wants to merge 3 commits into
corbitsdev:mainfrom
pratikbuilds:claude/i142-claim-escape-ime

Conversation

@pratikbuilds

@pratikbuilds pratikbuilds commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

While the suggestion list is open, usePromptInput claims Escape from a window-capture listener so an enclosing Radix dialog or popover doesn't dismiss. Safari sends the key that ends a composition with isComposing already false and keyCode 229. Chrome and Firefox send Escape with isComposing still true.

Leaving either key unclaimed is not enough inside a dialog. Radix DismissableLayer listens on document capture and, when key === "Escape" and defaultPrevented === false, calls preventDefault() and dismisses. claimEscape now stopPropagation()s isComposing and keyCode === 229 and does not preventDefault(), so the IME keeps the default action and the event never reaches Radix. A normal Escape is still preventDefault()ed, so the dialog stays and the suggestion list closes.

Verification

  • Unit tests in src/hooks/use-prompt-input.test.ts: with the mention list open, Escape { isComposing: true, keyCode: 27 } and Escape { keyCode: 229, isComposing: false } are not prevented, a document-capture listener does not see them, and the list stays open. A following normal Escape closes the list and is claimed. Once the list is closed, a later Escape is not claimed.
  • bun run check passes (885 unit tests).

Closes #142

While the suggestion list is open, the window-capture claimEscape
listener marks Escape handled so an enclosing Radix layer does not
dismiss. It skipped only `isComposing`, but Safari sends the key that
ends a composition with `isComposing` already false and keyCode 229.
Skip that too, as onKeyDown and the toolbar's useClaimEscape already do.

Follows up the review of corbitsdev#150 (corbitsdev#142 finding 13).
@corbits-triage

corbits-triage Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Triage: Pass

No changes needed from you. A maintainer will review this pull request.

A keyCode 229 Escape was left unclaimed so the IME could take it.
Radix still saw it on document capture, preventDefaulted it, and
dismissed the dialog. Stop that event at the window instead, and
keep preventDefault on a normal Escape so the list closes and the
dialog stays.
An Escape with isComposing still reached document capture, so Radix
preventDefaulted it and dismissed the dialog. Stop that key the same
way as keyCode 229, and keep claiming a normal Escape.

@TheGreatAxios TheGreatAxios left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. A composing Escape and a keyCode 229 Escape stop on the window capture path without preventDefault, so the IME keeps the key and a dialog does not dismiss. A normal Escape is still claimed and closes the suggestion list.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Follow-ups from the conversation PR review

2 participants