mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-10-15 22:55:42 -04:00
fix(web): ignore title shortcuts while a dialog or menu is open
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
3 files changed
+81
-11
No files matched your search
@@ -2,10 +2,16 @@ import { useHotkey } from "@tanstack/react-hotkeys";
|
||||
import { useAtomValue } from "jotai";
|
||||
|
||||
import { commandPaletteOpenAtom } from "@/lib/atoms/command-palette";
|
||||
import { isOverlayOpen } from "@/lib/overlays";
|
||||
|
||||
import { useTitleContext, useTitleUserInfo } from "./title-context";
|
||||
import { useTitleActions } from "./use-title-actions";
|
||||
|
||||
const whenNoOverlay = (fn: () => void) => () => {
|
||||
if (isOverlayOpen()) return;
|
||||
fn();
|
||||
};
|
||||
|
||||
export function TitleKeyboardShortcuts() {
|
||||
const { titleType } = useTitleContext();
|
||||
const { userStatus } = useTitleUserInfo();
|
||||
@@ -16,12 +22,16 @@ export function TitleKeyboardShortcuts() {
|
||||
const enabled = !commandPaletteOpen;
|
||||
|
||||
// W: toggle watchlist (add if not in library, remove if in library)
|
||||
useHotkey("W", () => handleStatusChange(userStatus ? null : "watchlist"), {
|
||||
enabled,
|
||||
});
|
||||
useHotkey(
|
||||
"W",
|
||||
whenNoOverlay(() => handleStatusChange(userStatus ? null : "watchlist")),
|
||||
{
|
||||
enabled,
|
||||
},
|
||||
);
|
||||
useHotkey(
|
||||
"M",
|
||||
() => {
|
||||
whenNoOverlay(() => {
|
||||
if (titleType === "movie") {
|
||||
if (userStatus === "completed") {
|
||||
handleUnwatchMovie();
|
||||
@@ -29,16 +39,40 @@ export function TitleKeyboardShortcuts() {
|
||||
handleWatchMovie();
|
||||
}
|
||||
}
|
||||
},
|
||||
}),
|
||||
{ enabled },
|
||||
);
|
||||
useHotkey(
|
||||
"Escape",
|
||||
whenNoOverlay(() => window.history.back()),
|
||||
{ enabled },
|
||||
);
|
||||
useHotkey("Escape", () => window.history.back(), { enabled });
|
||||
|
||||
useHotkey("1", () => handleRating(1), { enabled });
|
||||
useHotkey("2", () => handleRating(2), { enabled });
|
||||
useHotkey("3", () => handleRating(3), { enabled });
|
||||
useHotkey("4", () => handleRating(4), { enabled });
|
||||
useHotkey("5", () => handleRating(5), { enabled });
|
||||
useHotkey(
|
||||
"1",
|
||||
whenNoOverlay(() => handleRating(1)),
|
||||
{ enabled },
|
||||
);
|
||||
useHotkey(
|
||||
"2",
|
||||
whenNoOverlay(() => handleRating(2)),
|
||||
{ enabled },
|
||||
);
|
||||
useHotkey(
|
||||
"3",
|
||||
whenNoOverlay(() => handleRating(3)),
|
||||
{ enabled },
|
||||
);
|
||||
useHotkey(
|
||||
"4",
|
||||
whenNoOverlay(() => handleRating(4)),
|
||||
{ enabled },
|
||||
);
|
||||
useHotkey(
|
||||
"5",
|
||||
whenNoOverlay(() => handleRating(5)),
|
||||
{ enabled },
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { afterEach, describe, expect, test } from "vitest";
|
||||
|
||||
import { isOverlayOpen } from "./overlays";
|
||||
|
||||
describe("isOverlayOpen", () => {
|
||||
const added: HTMLElement[] = [];
|
||||
|
||||
function add(role: string) {
|
||||
const el = document.createElement("div");
|
||||
el.setAttribute("role", role);
|
||||
document.body.appendChild(el);
|
||||
added.push(el);
|
||||
return el;
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
for (const el of added.splice(0)) el.remove();
|
||||
});
|
||||
|
||||
test("false when nothing is open", () => {
|
||||
expect(isOverlayOpen()).toBe(false);
|
||||
});
|
||||
|
||||
test.each(["dialog", "alertdialog", "menu"])("true with role=%s", (role) => {
|
||||
const el = add(role);
|
||||
expect(isOverlayOpen()).toBe(true);
|
||||
el.remove();
|
||||
expect(isOverlayOpen()).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
const OVERLAY_SELECTOR = '[role="dialog"], [role="alertdialog"], [role="menu"]';
|
||||
|
||||
/** True while any dialog, alert dialog, popover or menu is open on the page. */
|
||||
export function isOverlayOpen(root: ParentNode = document): boolean {
|
||||
return root.querySelector(OVERLAY_SELECTOR) !== null;
|
||||
}
|
||||
Reference in new issue
Block a user