Radarr/frontend/src/Components/keyboardShortcuts.tsx
Mark McDowall 937557e214 Convert Page components to TypeScript
(cherry picked from commit f35a27449d253260ba9c9fae28909cec8a87b4fe)
2025-04-27 19:45:03 +03:00

179 lines
3.7 KiB
TypeScript

import Mousetrap, { MousetrapInstance } from 'mousetrap';
import React, { Component, ComponentType } from 'react';
import translate from 'Utilities/String/translate';
export interface Shortcut {
key: string;
name: string;
}
interface BindingOptions {
isGlobal?: boolean;
}
interface KeyboardShortcutsProps {
bindShortcut: (
key: string,
callback: (e: Mousetrap.ExtendedKeyboardEvent, combo: string) => void,
options?: BindingOptions
) => void;
unbindShortcut: (key: string) => void;
}
export const shortcuts: Record<string, Shortcut> = {
OPEN_KEYBOARD_SHORTCUTS_MODAL: {
key: '?',
get name() {
return translate('KeyboardShortcutsOpenModal');
},
},
CLOSE_MODAL: {
key: 'Esc',
get name() {
return translate('KeyboardShortcutsCloseModal');
},
},
ACCEPT_CONFIRM_MODAL: {
key: 'Enter',
get name() {
return translate('KeyboardShortcutsConfirmModal');
},
},
MOVIE_SEARCH_INPUT: {
key: 's',
get name() {
return translate('KeyboardShortcutsFocusSearchBox');
},
},
SAVE_SETTINGS: {
key: 'mod+s',
get name() {
return translate('KeyboardShortcutsSaveSettings');
},
},
SCROLL_TOP: {
key: 'mod+home',
get name() {
return translate('KeyboardShortcutsMovieIndexScrollTop');
},
},
SCROLL_BOTTOM: {
key: 'mod+end',
get name() {
return translate('KeyboardShortcutsMovieIndexScrollBottom');
},
},
DETAILS_NEXT: {
key: '→',
get name() {
return translate('KeyboardShortcutsMovieDetailsNextMovie');
},
},
DETAILS_PREVIOUS: {
key: '←',
get name() {
return translate('KeyboardShortcutsMovieDetailsPreviousMovie');
},
},
};
function keyboardShortcuts(
WrappedComponent: ComponentType<KeyboardShortcutsProps>
) {
class KeyboardShortcuts extends Component {
//
// Lifecycle
constructor(props: never) {
super(props);
this._mousetrapBindings = {};
this._mousetrap = new Mousetrap();
this._mousetrap.stopCallback = this.stopCallback;
}
componentWillUnmount() {
this.unbindAllShortcuts();
this._mousetrap = null;
}
_mousetrap: MousetrapInstance | null;
_mousetrapBindings: Record<string, BindingOptions>;
//
// Control
bindShortcut = (
key: string,
callback: (e: Mousetrap.ExtendedKeyboardEvent, combo: string) => void,
options: BindingOptions = {}
) => {
this._mousetrap?.bind(key, callback);
this._mousetrapBindings[key] = options;
};
unbindShortcut = (key: string) => {
if (this._mousetrap != null) {
delete this._mousetrapBindings[key];
this._mousetrap.unbind(key);
}
};
unbindAllShortcuts = () => {
const keys = Object.keys(this._mousetrapBindings);
if (!keys.length) {
return;
}
keys.forEach((binding) => {
this._mousetrap?.unbind(binding);
});
this._mousetrapBindings = {};
};
stopCallback = (
_e: Mousetrap.ExtendedKeyboardEvent,
element: Element,
combo: string
) => {
const binding = this._mousetrapBindings[combo];
if (!binding || binding.isGlobal) {
return false;
}
return (
element.tagName === 'INPUT' ||
element.tagName === 'SELECT' ||
element.tagName === 'TEXTAREA' ||
('contentEditable' in element && element.contentEditable === 'true')
);
};
//
// Render
render() {
return (
<WrappedComponent
{...this.props}
bindShortcut={this.bindShortcut}
unbindShortcut={this.unbindShortcut}
/>
);
}
}
return KeyboardShortcuts;
}
export default keyboardShortcuts;