Skip to content

Commit

Permalink
Merge pull request #29226 from kubabutkiewicz/ts-migration/useKeyboar…
Browse files Browse the repository at this point in the history
…dShortcut/hook

[No QA] [TS migration] Migrate 'useKeyboardShortcut.js' hook to TypeScript
  • Loading branch information
chiragsalian authored Nov 8, 2023
2 parents 8321895 + ba5fb64 commit 130ce1c
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 69 deletions.
8 changes: 1 addition & 7 deletions src/components/Pressable/GenericPressable/types.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
import {ElementRef, RefObject} from 'react';
import {GestureResponderEvent, HostComponent, PressableStateCallbackType, PressableProps as RNPressableProps, StyleProp, ViewStyle} from 'react-native';
import {ValueOf} from 'type-fest';
import {Shortcut} from '@libs/KeyboardShortcut';
import CONST from '@src/CONST';

type StylePropWithFunction = StyleProp<ViewStyle> | ((state: PressableStateCallbackType) => StyleProp<ViewStyle>);

type Shortcut = {
displayName: string;
shortcutKey: string;
descriptionKey: string;
modifiers: string[];
};

type RequiredAccessibilityLabel =
| {
/**
Expand Down
56 changes: 0 additions & 56 deletions src/hooks/useKeyboardShortcut.js

This file was deleted.

61 changes: 61 additions & 0 deletions src/hooks/useKeyboardShortcut.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {useEffect} from 'react';
import {ValueOf} from 'type-fest';
import KeyboardShortcut from '@libs/KeyboardShortcut';
import CONST from '@src/CONST';

type Shortcut = ValueOf<typeof CONST.KEYBOARD_SHORTCUTS>;
type KeyboardShortcutConfig = {
/* Should we capture the event on inputs too? */
captureOnInputs?: boolean;
/* Should we bubble the event? */
shouldBubble?: boolean;
/* The position the callback should take in the stack. 0 means top priority, and 1 means less priority than the most recently added. */
priority?: number;
/* Should call event.preventDefault after callback? */
shouldPreventDefault?: boolean;
/* Do not capture key events targeting excluded nodes (i.e. do not prevent default and let the event bubble) */
excludedNodes?: string[];
/* Is keyboard shortcut is already active */
isActive?: boolean;
};

/**
* Register a keyboard shortcut handler.
* Recommendation: To ensure stability, wrap the `callback` function with the useCallback hook before using it with this hook.
*/
export default function useKeyboardShortcut(shortcut: Shortcut, callback: () => void, config: KeyboardShortcutConfig | Record<string, never> = {}) {
const {
captureOnInputs = true,
shouldBubble = false,
priority = 0,
shouldPreventDefault = true,

// The "excludedNodes" array needs to be stable to prevent the "useEffect" hook from being recreated unnecessarily.
// Hence the use of CONST.EMPTY_ARRAY.
excludedNodes = CONST.EMPTY_ARRAY,
isActive = true,
} = config;

useEffect(() => {
if (!isActive) {
return () => {};
}

const unsubscribe = KeyboardShortcut.subscribe(
shortcut.shortcutKey,
callback,
shortcut.descriptionKey ?? '',
shortcut.modifiers,
captureOnInputs,
shouldBubble,
priority,
shouldPreventDefault,
excludedNodes as string[],
);

return () => {
unsubscribe();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isActive, callback, captureOnInputs, excludedNodes, priority, shortcut.descriptionKey, shortcut.modifiers.join(), shortcut.shortcutKey, shouldBubble, shouldPreventDefault]);
}
14 changes: 8 additions & 6 deletions src/libs/KeyboardShortcut/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ type EventHandler = {
// Handlers for the various keyboard listeners we set up
const eventHandlers: Record<string, EventHandler[]> = {};

type ShortcutModifiers = readonly ['CTRL'] | readonly ['CTRL', 'SHIFT'] | readonly [];

type Shortcut = {
displayName: string;
shortcutKey: string;
descriptionKey: string;
modifiers: string[];
modifiers: ShortcutModifiers;
};

// Documentation information for keyboard shortcuts that are displayed in the keyboard shortcuts informational modal
Expand Down Expand Up @@ -102,13 +104,13 @@ function unsubscribe(displayName: string, callbackID: string) {
/**
* Return platform specific modifiers for keys like Control (CMD on macOS)
*/
function getPlatformEquivalentForKeys(keys: string[]): string[] {
function getPlatformEquivalentForKeys(keys: ShortcutModifiers): string[] {
return keys.map((key) => {
if (!(key in CONST.PLATFORM_SPECIFIC_KEYS)) {
return key;
}

const platformModifiers = CONST.PLATFORM_SPECIFIC_KEYS[key as keyof typeof CONST.PLATFORM_SPECIFIC_KEYS];
const platformModifiers = CONST.PLATFORM_SPECIFIC_KEYS[key];
return platformModifiers?.[operatingSystem as keyof typeof platformModifiers] ?? platformModifiers.DEFAULT ?? key;
});
}
Expand All @@ -130,12 +132,12 @@ function subscribe(
key: string,
callback: (event?: KeyboardEvent) => void,
descriptionKey: string,
modifiers: string[] = ['shift'],
modifiers: ShortcutModifiers = ['CTRL'],
captureOnInputs = false,
shouldBubble = false,
priority = 0,
shouldPreventDefault = true,
excludedNodes = [],
excludedNodes: string[] = [],
shouldStopPropagation = false,
) {
const platformAdjustedModifiers = getPlatformEquivalentForKeys(modifiers);
Expand Down Expand Up @@ -190,4 +192,4 @@ const KeyboardShortcut = {
};

export default KeyboardShortcut;
export type {EventHandler};
export type {EventHandler, Shortcut};

0 comments on commit 130ce1c

Please sign in to comment.