diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index f336fe659074..b08d2106ff93 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -109,6 +109,9 @@ function EmojiPickerMenu({forwardedRef, onEmojiSelected, activeEmoji}) { initialFocusedIndex: -1, disableCyclicTraversal: true, onFocusedIndexChange, + disableHorizontalKeys: isFocused, + // We pass true without checking visibility of the component because if the popover is not visible this picker won't be mounted + isActive: true, }); const filterEmojis = _.throttle((searchTerm) => { diff --git a/src/hooks/useArrowKeyFocusManager.ts b/src/hooks/useArrowKeyFocusManager.ts index 352734c92e8d..78ffc7f87209 100644 --- a/src/hooks/useArrowKeyFocusManager.ts +++ b/src/hooks/useArrowKeyFocusManager.ts @@ -11,6 +11,7 @@ type Config = { isActive?: boolean; itemsPerRow?: number; disableCyclicTraversal?: boolean; + disableHorizontalKeys?: boolean; }; type UseArrowKeyFocusManager = [number, (index: number) => void]; @@ -28,6 +29,7 @@ type UseArrowKeyFocusManager = [number, (index: number) => void]; * @param [config.isActive] – Whether the component is ready and should subscribe to KeyboardShortcut * @param [config.itemsPerRow] – The number of items per row. If provided, the arrow keys will move focus horizontally as well as vertically * @param [config.disableCyclicTraversal] – Whether to disable cyclic traversal of the list. If true, the arrow keys will have no effect when the first or last item is focused + * @param [config.disableHorizontalKeys] – Whether to disable the right/left keys */ export default function useArrowKeyFocusManager({ maxIndex, @@ -41,6 +43,7 @@ export default function useArrowKeyFocusManager({ isActive, itemsPerRow, disableCyclicTraversal = false, + disableHorizontalKeys = false, }: Config): UseArrowKeyFocusManager { const allowHorizontalArrowKeys = !!itemsPerRow; const [focusedIndex, setFocusedIndex] = useState(initialFocusedIndex); @@ -52,6 +55,14 @@ export default function useArrowKeyFocusManager({ [isActive, shouldExcludeTextAreaNodes], ); + const horizontalArrowConfig = useMemo( + () => ({ + excludedNodes: shouldExcludeTextAreaNodes ? ['TEXTAREA'] : [], + isActive: isActive && !disableHorizontalKeys, + }), + [isActive, shouldExcludeTextAreaNodes, disableHorizontalKeys], + ); + // eslint-disable-next-line react-hooks/exhaustive-deps useEffect(() => onFocusedIndexChange(focusedIndex), [focusedIndex]); @@ -155,7 +166,7 @@ export default function useArrowKeyFocusManager({ }); }, [allowHorizontalArrowKeys, disableCyclicTraversal, disabledIndexes, maxIndex]); - useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ARROW_LEFT, arrowLeftCallback, arrowConfig); + useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ARROW_LEFT, arrowLeftCallback, horizontalArrowConfig); const arrowRightCallback = useCallback(() => { if (maxIndex < 0 || !allowHorizontalArrowKeys) { @@ -182,7 +193,7 @@ export default function useArrowKeyFocusManager({ }); }, [allowHorizontalArrowKeys, disableCyclicTraversal, disabledIndexes, maxIndex]); - useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ARROW_RIGHT, arrowRightCallback, arrowConfig); + useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ARROW_RIGHT, arrowRightCallback, horizontalArrowConfig); // Note: you don't need to manually manage focusedIndex in the parent. setFocusedIndex is only exposed in case you want to reset focusedIndex or focus a specific item return [focusedIndex, setFocusedIndex];