stoat-for-desktop/components/keybinds/keybindActions.ts

128 lines
3.1 KiB
TypeScript

import { ReactiveSet } from "@solid-primitives/set";
export enum KeybindAction {
/**
* Navigate to channel above current channel
*/
NAVIGATION_CHANNEL_UP = "navigation_channel_up",
/**
* Navigate to channel below current channel
*/
NAVIGATION_CHANNEL_DOWN = "navigation_channel_down",
/**
* Navigate to server above current server
*/
NAVIGATION_SERVER_UP = "navigation_server_up",
/**
* Navigate to server below current server
*/
NAVIGATION_SERVER_DOWN = "navigation_server_down",
/**
* Mark channel as read, jump to the end of conversation, and focus composition
*/
CHAT_JUMP_END = "chat_jump_end",
/**
* Mark server as read
*/
CHAT_MARK_SERVER_AS_READ = "chat_mark_server_as_read",
/**
* Focus the message composition
*/
CHAT_FOCUS_COMPOSITION = "chat_focus_composition",
/**
* Remove attachment or reply from message composition
*/
CHAT_REMOVE_COMPOSITION_ELEMENT = "chat_remove_composition_element",
/**
* Cancel editing the current message
*/
CHAT_CANCEL_EDITING = "chat_cancel_editing",
/**
* Close the currently active modal
*/
CLOSE_MODAL = "close_modal",
/**
* Close the currently floating element
*/
CLOSE_FLOATING = "close_floating",
/**
* Close the open and ephemeral sidebar
*/
CLOSE_SIDEBAR = "close_sidebar",
}
/**
* Priority of actions relative to each other
*/
export const ACTION_PRIORITY: KeybindAction[] = [
// 'Escape' bindings
KeybindAction.CLOSE_FLOATING,
KeybindAction.CLOSE_MODAL,
KeybindAction.CLOSE_SIDEBAR,
KeybindAction.CHAT_CANCEL_EDITING,
KeybindAction.CHAT_REMOVE_COMPOSITION_ELEMENT,
KeybindAction.CHAT_MARK_SERVER_AS_READ,
KeybindAction.CHAT_JUMP_END,
// Navigation conflicts
KeybindAction.NAVIGATION_SERVER_UP,
KeybindAction.NAVIGATION_SERVER_DOWN,
KeybindAction.NAVIGATION_CHANNEL_UP,
KeybindAction.NAVIGATION_CHANNEL_DOWN,
// ... all others
KeybindAction.CHAT_FOCUS_COMPOSITION,
];
/**
* Filter keybinds with special logic
* @param keybind Keybind to filter
* @param currentlyBound Other keybinds currently bound
* @returns Whether to include this keybind
*/
export function keybindFilter(
keybind: KeybindAction,
activeKeys: ReactiveSet<string>,
currentlyBound: Record<KeybindAction, number>,
target: HTMLElement | null,
) {
if (keybind === KeybindAction.CHAT_FOCUS_COMPOSITION) {
// don't allow focusing if modal/floating is open
// or if we're editing a message
if (
currentlyBound[KeybindAction.CLOSE_FLOATING] ||
currentlyBound[KeybindAction.CLOSE_MODAL] ||
currentlyBound[KeybindAction.CHAT_CANCEL_EDITING]
)
return false;
// don't allow focusing if another input element is currently being typed into
if (
target instanceof HTMLInputElement ||
target instanceof HTMLTextAreaElement ||
target?.nodeName === "MDUI-TEXT-FIELD"
)
return false;
// don't allow focusing if modifier key is pressed... except for paste
if (
(activeKeys.has("Control") || activeKeys.has("Meta")) &&
!(activeKeys.has("v") || activeKeys.has("a"))
)
return false;
}
return true;
}