Match Shift+letter shortcuts (Shift+I, Shift+U) (#399)

comboOf() let a shifted letter encode Shift in its case, so Shift+I
produced "I" and never matched the "shift+i" / "shift+u" bindings for
mark as read / unread. Shifted letters now yield "shift+<letter>";
symbols such as "#" and "!" still carry Shift in the character.

Fixes #398

Co-authored-by: Joe Esteves <[email protected]>
This commit is contained in:
jcoffey
2026-09-18 08:22:13 -07:00
committed by GitHub
co-authored by joeesteves
parent 2740129c6a
commit c118184975
3 changed files with 26 additions and 6 deletions
+21 -2
View File
@@ -11,8 +11,8 @@ import { isTextEntry, keyboard } from "@/lib/input/keyboard";
* swallows a keystroke in the first place.
*/
const pressFrom = (el: Element, key: string) => {
const e = new KeyboardEvent("keydown", { key, bubbles: true, cancelable: true });
const pressFrom = (el: EventTarget, key: string, init?: KeyboardEventInit) => {
const e = new KeyboardEvent("keydown", { key, bubbles: true, cancelable: true, ...init });
el.dispatchEvent(e);
return e;
};
@@ -92,3 +92,22 @@ describe("shortcuts with a checkbox focused", () => {
expect(handler).not.toHaveBeenCalled();
});
});
describe("shifted letter shortcuts", () => {
it("matches Shift+I and Shift+U bindings", () => {
const read = vi.fn();
const unread = vi.fn();
pop = keyboard.pushScope("test", [
{ keys: "shift+i", description: "Mark as read", group: "Actions", handler: read },
{ keys: "shift+u", description: "Mark as unread", group: "Actions", handler: unread },
]);
const readEvent = pressFrom(window, "I", { shiftKey: true });
const unreadEvent = pressFrom(window, "U", { shiftKey: true });
expect(read).toHaveBeenCalledOnce();
expect(unread).toHaveBeenCalledOnce();
expect(readEvent.defaultPrevented).toBe(true);
expect(unreadEvent.defaultPrevented).toBe(true);
});
});
@@ -36,7 +36,7 @@ describe("a keydown with no key", () => {
it("leaves real keys alone", () => {
expect(comboOf(new KeyboardEvent("keydown", { key: "e" }))).toBe("e");
expect(comboOf(new KeyboardEvent("keydown", { key: "E", shiftKey: true }))).toBe("E");
expect(comboOf(new KeyboardEvent("keydown", { key: "E", shiftKey: true }))).toBe("shift+e");
expect(comboOf(new KeyboardEvent("keydown", { key: "Enter", ctrlKey: true }))).toMatch(/enter$/);
});
});