Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/hotkeys-ime-composition.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"reshaped": patch
---

Fixed `useHotkeys` reacting to keys that belong to an IME composition. With a Japanese, Chinese or Korean input method, the Enter that confirms a conversion no longer triggers hotkeys, so `Autocomplete` no longer selects the highlighted option or calls `onEnter` with unfinished text.
3 changes: 3 additions & 0 deletions packages/reshaped/src/hooks/_internal/useSingletonHotkeys.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ const HotkeysProvider: React.FC<{ children: React.ReactNode }> = (props) => {
(e: KeyboardEvent) => {
// Browsers trigger keyboard event without passing e.key when you click on autocomplete
if (!e.key) return;
// Keys handled by an IME are not hotkeys. Safari fires the Enter that confirms
// a composition after compositionend, so only keyCode 229 marks it
if (e.isComposing || e.keyCode === 229) return;

const nextPressedMap = addPressedKey(e) ?? pressedMapRef.current;
globalHotkeyStore.handleKeyDown(nextPressedMap, e);
Expand Down
19 changes: 19 additions & 0 deletions packages/reshaped/src/hooks/tests/useHotkeys.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,22 @@ export const optionModified: StoryObj<{
expect(args.handleHotkey).toHaveBeenCalledTimes(1);
},
};

export const imeComposition: StoryObj<{ handleHotkey: ReturnType<typeof fn> }> = {
name: "ignores IME composition",
args: {
handleHotkey: fn(),
},
render: (args) => <Component hotkeys={{ enter: args.handleHotkey }} />,
play: async ({ args }) => {
window.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter", isComposing: true }));
window.dispatchEvent(new KeyboardEvent("keyup", { key: "Enter" }));
// Safari ends the composition before keydown, so only keyCode 229 marks it
window.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter", keyCode: 229 }));
window.dispatchEvent(new KeyboardEvent("keyup", { key: "Enter" }));
expect(args.handleHotkey).not.toHaveBeenCalled();

await userEvent.keyboard("{Enter}");
expect(args.handleHotkey).toHaveBeenCalledTimes(1);
},
};
Loading