From 95e5c69e8fb75d510d754fa1e2b063628e22fc72 Mon Sep 17 00:00:00 2001 From: John Coffey Date: Thu, 3 Sep 2026 14:38:15 -0700 Subject: [PATCH] Keep shortcuts working after a checkbox is clicked Ticking "select all" disabled every keyboard shortcut until the reader clicked somewhere else (#260). Same for the per-message checkboxes, so selecting a few messages and pressing e to archive them did nothing. The guard that stops "a" archiving while you are typing into the search box tested `tagName === "INPUT"`. That is also true of a checkbox, and a checkbox keeps focus after a click -- correctly, since space should toggle it again. So the guard was suppressing shortcuts for an element that swallows no keystroke: space is handled by the browser before this listener runs. The question is not "is this an input" but "does this input take text", which is what isTextEntry now asks. A ` does, in the sense that matters here: typing a letter jumps to + * the option beginning with it, which a shortcut would steal. + */ +const TEXT_ENTRY_TYPES = new Set([ + "text", "search", "email", "url", "tel", "password", "number", + "date", "datetime-local", "month", "time", "week", +]); + +export function isTextEntry(el: Element | null): boolean { + if (!el) return false; + const node = el as HTMLElement; + if (node.isContentEditable) return true; + const tag = node.tagName; + if (tag === "TEXTAREA" || tag === "SELECT") return true; + if (tag !== "INPUT") return false; + // An with no type attribute is a text field. + const type = (node as HTMLInputElement).type?.toLowerCase() || "text"; + return TEXT_ENTRY_TYPES.has(type); +} + const isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform); export function comboOf(e: KeyboardEvent): string | null {