feat(app): make the New tab launcher keyboard-first
Cmd/Ctrl+T now opens the focused pane's launcher, while explicit target shortcuts bypass the menu. Dispatcher ownership is scoped to the app tree so retained workspaces cannot intercept commands.
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
import {
|
||||
keyboardActionDispatcher,
|
||||
type KeyboardActionDefinition,
|
||||
type KeyboardActionId,
|
||||
import type {
|
||||
KeyboardActionDefinition,
|
||||
KeyboardActionId,
|
||||
} from "@/keyboard/keyboard-action-dispatcher";
|
||||
import { useKeyboardActionDispatcher } from "@/keyboard/keyboard-action-dispatcher-context";
|
||||
|
||||
interface UseKeyboardActionHandlerInput {
|
||||
handlerId: string;
|
||||
@@ -37,6 +37,7 @@ interface UseKeyboardActionHandlerInput {
|
||||
* registration and would otherwise go stale).
|
||||
*/
|
||||
export function useKeyboardActionHandler(input: UseKeyboardActionHandlerInput) {
|
||||
const keyboardActionDispatcher = useKeyboardActionDispatcher();
|
||||
const inputRef = useRef(input);
|
||||
inputRef.current = input;
|
||||
|
||||
@@ -58,5 +59,5 @@ export function useKeyboardActionHandler(input: UseKeyboardActionHandlerInput) {
|
||||
},
|
||||
handle: (action) => inputRef.current.handle(action),
|
||||
});
|
||||
}, [input.handlerId, input.priority, actionsKey]);
|
||||
}, [actionsKey, input.handlerId, input.priority, keyboardActionDispatcher]);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useKeyboardShortcutsStore } from "@/stores/keyboard-shortcuts-store";
|
||||
import { setCommandCenterFocusRestoreElement } from "@/utils/command-center-focus-restore";
|
||||
import { getResidentBrowserWebview } from "@/desktop/browser/resident-webviews";
|
||||
import { navigateToWorkspace } from "@/stores/navigation-active-workspace-store";
|
||||
import { keyboardActionDispatcher } from "@/keyboard/keyboard-action-dispatcher";
|
||||
import { useKeyboardActionDispatcher } from "@/keyboard/keyboard-action-dispatcher-context";
|
||||
import {
|
||||
type ChordState,
|
||||
type KeyboardShortcutInput,
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
navigateToLastWorkspace,
|
||||
useActiveWorkspaceSelection,
|
||||
} from "@/stores/navigation-active-workspace-store";
|
||||
import { dispatchTopWebOverlayKeyDown } from "@/lib/overlay-root";
|
||||
|
||||
export function useKeyboardShortcuts({
|
||||
enabled,
|
||||
@@ -55,6 +56,7 @@ export function useKeyboardShortcuts({
|
||||
exitFocusMode: () => void;
|
||||
cycleTheme?: () => void;
|
||||
}) {
|
||||
const keyboardActionDispatcher = useKeyboardActionDispatcher();
|
||||
const pathname = usePathname();
|
||||
const router = useRouter();
|
||||
const resetModifiers = useKeyboardShortcutsStore((s) => s.resetModifiers);
|
||||
@@ -269,7 +271,6 @@ export function useKeyboardShortcuts({
|
||||
},
|
||||
bindings,
|
||||
});
|
||||
|
||||
chordStateRef.current = result.nextChordState;
|
||||
if (
|
||||
shouldPublishBrowserShortcutPolicy({
|
||||
@@ -313,6 +314,10 @@ export function useKeyboardShortcuts({
|
||||
return;
|
||||
}
|
||||
|
||||
if (dispatchTopWebOverlayKeyDown(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// During IME composition, Enter confirms the candidate selection and must
|
||||
// not route through global shortcuts like message send.
|
||||
if (isImeComposingKeyboardEvent(event)) {
|
||||
@@ -405,6 +410,7 @@ export function useKeyboardShortcuts({
|
||||
isMac,
|
||||
isMobile,
|
||||
isWorkspaceFocusModeEnabled,
|
||||
keyboardActionDispatcher,
|
||||
openProjectPickerAction,
|
||||
pathname,
|
||||
publishBrowserShortcutPolicy,
|
||||
|
||||
Reference in New Issue
Block a user