nexus/ui/src/lib/keyboardShortcuts.ts
dotta ad1ef6a8c6 fix(ui): address final Greptile follow-up
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-02 12:21:35 -05:00

54 lines
1.5 KiB
TypeScript

export const KEYBOARD_SHORTCUT_TEXT_INPUT_SELECTOR = [
"input",
"textarea",
"select",
"[contenteditable='true']",
"[contenteditable='plaintext-only']",
"[role='textbox']",
"[role='combobox']",
].join(", ");
const MODIFIER_ONLY_KEYS = new Set(["Shift", "Meta", "Control", "Alt"]);
export type InboxQuickArchiveKeyAction = "ignore" | "archive" | "disarm";
export function isKeyboardShortcutTextInputTarget(target: EventTarget | null): boolean {
if (!(target instanceof HTMLElement)) return false;
if (target.isContentEditable) return true;
return !!target.closest(KEYBOARD_SHORTCUT_TEXT_INPUT_SELECTOR);
}
export function hasBlockingShortcutDialog(root: ParentNode = document): boolean {
return !!root.querySelector("[role='dialog'][aria-modal='true']");
}
export function isModifierOnlyKey(key: string): boolean {
return MODIFIER_ONLY_KEYS.has(key);
}
export function resolveInboxQuickArchiveKeyAction({
armed,
defaultPrevented,
key,
metaKey,
ctrlKey,
altKey,
target,
hasOpenDialog,
}: {
armed: boolean;
defaultPrevented: boolean;
key: string;
metaKey: boolean;
ctrlKey: boolean;
altKey: boolean;
target: EventTarget | null;
hasOpenDialog: boolean;
}): InboxQuickArchiveKeyAction {
if (!armed) return "ignore";
if (defaultPrevented) return "disarm";
if (metaKey || ctrlKey || altKey || isModifierOnlyKey(key)) return "ignore";
if (hasOpenDialog || isKeyboardShortcutTextInputTarget(target)) return "disarm";
if (key === "y") return "archive";
return "disarm";
}