Skip to content

Commit 929a6f9

Browse files
committed
refactor(webapp): capture Option+F with the standard shortcuts hook
The favorite toggle used a raw document keydown listener because Option+F reports event.key as an Option-transformed symbol on macOS ("ƒ"), which an event.key comparison cannot match. The hotkeys library behind useShortcutKeys also matches the physical event.code, so the standard hook captures Option+letter after all. Behavior is unchanged: exact modifier matching keeps the bare f shortcut separate, inputs and content-editable elements are still skipped, and the global shortcuts toggle is respected. Held keys no longer repeat the toggle.
1 parent 8a2eb70 commit 929a6f9

1 file changed

Lines changed: 12 additions & 38 deletions

File tree

apps/webapp/app/components/navigation/FavoritePageButton.tsx

Lines changed: 12 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { StarIcon as StarIconOutline } from "@heroicons/react/24/outline";
22
import { StarIcon as StarIconSolid } from "@heroicons/react/20/solid";
33
import { useFetcher, useLocation, useSearchParams } from "@remix-run/react";
4-
import { useEffect, useRef } from "react";
4+
import { useEffect } from "react";
55
import { useIsImpersonating } from "~/hooks/useOrganizations";
6+
import { useShortcutKeys } from "~/hooks/useShortcutKeys";
67
import { useOptionalUser } from "~/hooks/useUser";
78
import { cn } from "~/utils/cn";
89
import { Button } from "../primitives/Buttons";
910
import { ShortcutKey } from "../primitives/ShortcutKey";
10-
import { useShortcuts } from "../primitives/ShortcutsProvider";
1111
import { SimpleTooltip } from "../primitives/Tooltip";
1212
import {
1313
buildFavoriteLabel,
@@ -35,7 +35,6 @@ export function FavoritePageButton({
3535
const location = useLocation();
3636
const favorites = useFavorites();
3737
const fetcher = useFetcher();
38-
const { areShortcutsEnabled } = useShortcuts();
3938
const [, setSearchParams] = useSearchParams();
4039

4140
// The marker param and pagination position never count toward URL identity, so paging through
@@ -86,44 +85,19 @@ export function FavoritePageButton({
8685
}
8786
};
8887

89-
// The listener reads the latest toggle through a ref so it isn't re-attached every render
90-
const toggleRef = useRef(toggle);
91-
toggleRef.current = toggle;
92-
9388
const showButton = user !== undefined && !isImpersonating;
9489

95-
useEffect(() => {
96-
if (!showButton || !areShortcutsEnabled) return;
97-
98-
const onKeyDown = (event: KeyboardEvent) => {
99-
// Matched on `event.code`: on macOS, Option makes "F" report "ƒ" via `event.key`, so the
100-
// event.key-based useShortcutKeys hook can't capture Option+letter (see GlobalShortcuts).
101-
if (
102-
event.code !== "KeyF" ||
103-
!event.altKey ||
104-
event.metaKey ||
105-
event.ctrlKey ||
106-
event.shiftKey
107-
) {
108-
return;
109-
}
110-
const target = event.target;
111-
if (
112-
target instanceof HTMLElement &&
113-
(target.tagName === "INPUT" ||
114-
target.tagName === "TEXTAREA" ||
115-
target.tagName === "SELECT" ||
116-
target.isContentEditable)
117-
) {
118-
return;
119-
}
90+
// Option+F reports event.key "ƒ" on macOS, but the hotkeys matcher falls back to the physical
91+
// event.code ("KeyF"), so the standard hook captures it; exact modifier matching keeps the
92+
// bare "f" filter shortcut separate.
93+
useShortcutKeys({
94+
shortcut: { key: "f", modifiers: ["alt"] },
95+
action: (event) => {
12096
event.preventDefault();
121-
toggleRef.current();
122-
};
123-
124-
document.addEventListener("keydown", onKeyDown);
125-
return () => document.removeEventListener("keydown", onKeyDown);
126-
}, [showButton, areShortcutsEnabled]);
97+
toggle();
98+
},
99+
disabled: !showButton,
100+
});
127101

128102
if (!showButton) {
129103
return null;

0 commit comments

Comments
 (0)