TelegramPWA/src/components/middle/composer/hooks/useKeyboardNavigation.ts
2024-04-19 13:37:34 +04:00

88 lines
2.9 KiB
TypeScript

import { useEffect, useState } from '../../../../lib/teact/teact';
import captureKeyboardListeners from '../../../../util/captureKeyboardListeners';
import cycleRestrict from '../../../../util/cycleRestrict';
import useLastCallback from '../../../../hooks/useLastCallback';
export function useKeyboardNavigation({
isActive,
isHorizontal,
shouldSaveSelectionOnUpdateItems,
shouldRemoveSelectionOnReset,
noArrowNavigation,
items,
shouldSelectOnTab,
onSelect,
onClose,
}: {
isActive: boolean;
isHorizontal?: boolean;
shouldSaveSelectionOnUpdateItems?: boolean;
shouldRemoveSelectionOnReset?: boolean;
noArrowNavigation?: boolean;
items?: any[];
shouldSelectOnTab?: boolean;
onSelect: (item: any) => void | boolean;
onClose: NoneToVoidFunction;
}) {
const [selectedItemIndex, setSelectedItemIndex] = useState(-1);
const getSelectedIndex = useLastCallback((newIndex: number) => {
if (!items) {
return -1;
}
return cycleRestrict(items.length, newIndex);
});
const handleArrowKey = useLastCallback((value: number, e: KeyboardEvent) => {
e.preventDefault();
setSelectedItemIndex((index) => (getSelectedIndex(index + value)));
});
const handleItemSelect = useLastCallback((e: KeyboardEvent) => {
// Prevent action on key combinations
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return false;
if (!isActive) return false;
if (items && items.length && selectedItemIndex > -1) {
const item = items[selectedItemIndex];
if (item) {
if (onSelect(item) === false) {
return false;
}
e.preventDefault();
}
}
return true;
});
useEffect(() => {
if (!isActive) setSelectedItemIndex(shouldRemoveSelectionOnReset ? -1 : 0);
}, [isActive, shouldRemoveSelectionOnReset]);
const isSelectionOutOfRange = !items || selectedItemIndex > items.length - 1;
useEffect(() => {
if (!shouldSaveSelectionOnUpdateItems || isSelectionOutOfRange) {
setSelectedItemIndex(shouldRemoveSelectionOnReset ? -1 : 0);
}
}, [isSelectionOutOfRange, shouldRemoveSelectionOnReset, shouldSaveSelectionOnUpdateItems]);
useEffect(() => (isActive ? captureKeyboardListeners({
onEsc: onClose,
onUp: noArrowNavigation || isHorizontal ? undefined : (e: KeyboardEvent) => handleArrowKey(-1, e),
onDown: noArrowNavigation || isHorizontal ? undefined : (e: KeyboardEvent) => handleArrowKey(1, e),
onLeft: noArrowNavigation || !isHorizontal ? undefined : (e: KeyboardEvent) => handleArrowKey(-1, e),
onRight: noArrowNavigation || !isHorizontal ? undefined : (e: KeyboardEvent) => handleArrowKey(1, e),
onTab: shouldSelectOnTab ? handleItemSelect : undefined,
onEnter: handleItemSelect,
}) : undefined), [
noArrowNavigation, handleArrowKey, handleItemSelect, isActive, isHorizontal, onClose, shouldSelectOnTab,
]);
return selectedItemIndex;
}