mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-17 03:10:38 +09:00
feat: polish inbox and issue list workflows
This commit is contained in:
parent
548721248e
commit
dab95740be
37 changed files with 1674 additions and 411 deletions
|
|
@ -8,6 +8,7 @@ export const KEYBOARD_SHORTCUT_TEXT_INPUT_SELECTOR = [
|
|||
"[role='combobox']",
|
||||
].join(", ");
|
||||
|
||||
const PAGE_SEARCH_SHORTCUT_SELECTOR = "[data-page-search-target='true']";
|
||||
const MODIFIER_ONLY_KEYS = new Set(["Shift", "Meta", "Control", "Alt"]);
|
||||
|
||||
export type InboxQuickArchiveKeyAction = "ignore" | "archive" | "disarm";
|
||||
|
|
@ -23,6 +24,56 @@ export function hasBlockingShortcutDialog(root: ParentNode = document): boolean
|
|||
return !!root.querySelector("[role='dialog'][aria-modal='true']");
|
||||
}
|
||||
|
||||
function isVisibleShortcutTarget(element: HTMLElement): boolean {
|
||||
if (!element.isConnected) return false;
|
||||
if ("disabled" in element && typeof element.disabled === "boolean" && element.disabled) return false;
|
||||
if (element.closest("[hidden], [aria-hidden='true'], [inert]")) return false;
|
||||
if (element.closest("[role='dialog'][aria-modal='true']")) return false;
|
||||
|
||||
const style = window.getComputedStyle(element);
|
||||
if (style.display === "none" || style.visibility === "hidden") return false;
|
||||
|
||||
return element.getClientRects().length > 0 || element === document.activeElement;
|
||||
}
|
||||
|
||||
export function findPageSearchShortcutTarget(root: ParentNode = document): HTMLElement | null {
|
||||
const candidates = Array.from(root.querySelectorAll<HTMLElement>(PAGE_SEARCH_SHORTCUT_SELECTOR));
|
||||
return candidates.find((candidate) => isVisibleShortcutTarget(candidate)) ?? null;
|
||||
}
|
||||
|
||||
export function focusPageSearchShortcutTarget(root: ParentNode = document): boolean {
|
||||
const target = findPageSearchShortcutTarget(root);
|
||||
if (!target) return false;
|
||||
|
||||
target.focus();
|
||||
if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) {
|
||||
target.select();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function shouldBlurPageSearchOnEnter({
|
||||
key,
|
||||
isComposing,
|
||||
}: {
|
||||
key: string;
|
||||
isComposing: boolean;
|
||||
}): boolean {
|
||||
return key === "Enter" && !isComposing;
|
||||
}
|
||||
|
||||
export function shouldBlurPageSearchOnEscape({
|
||||
key,
|
||||
isComposing,
|
||||
currentValue,
|
||||
}: {
|
||||
key: string;
|
||||
isComposing: boolean;
|
||||
currentValue: string;
|
||||
}): boolean {
|
||||
return key === "Escape" && !isComposing && currentValue.length === 0;
|
||||
}
|
||||
|
||||
export function isModifierOnlyKey(key: string): boolean {
|
||||
return MODIFIER_ONLY_KEYS.has(key);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue