import { Ref } from 'vue';
import { EditableSelectProps, Option, Options } from '../editable-select-types';
import { States } from './use-select';
export interface UseKeyboardSelectReturnType {
onKeydown: (e: KeyboardEvent) => void;
}
const EVENT_CODE = {
tab: 'Tab',
enter: 'Enter',
up: 'ArrowUp',
down: 'ArrowDown',
esc: 'Escape',
};
export function useKeyboardSelect(
props: EditableSelectProps,
states: States,
filteredOptions: Ref<Options>,
scrollToItem: (index: number) => void,
handleOptionSelect: (option: Option, byClick: boolean) => void
): UseKeyboardSelectReturnType {
const updateHoveringIndex = (index: number) => {
states.hoveringIndex = index;
};
const onKeyboardNavigate = (direction: 'ArrowDown' | 'ArrowUp', hoverIndex: number = states.hoveringIndex): void => {
if (!states.visible) {
states.visible = true;
return;
}
if (filteredOptions.value.length === 0 || props.loading) {
return;
}
let newIndex = 0;
if (direction === 'ArrowDown') {
newIndex = hoverIndex + 1;
if (newIndex > filteredOptions.value.length - 1) {
newIndex = 0;
}
} else if (direction === 'ArrowUp') {
newIndex = hoverIndex - 1;
if (newIndex < 0) {
newIndex = filteredOptions.value.length - 1;
}
}
const option = filteredOptions.value[newIndex];
if (option[props.disabledKey]) {
return onKeyboardNavigate(direction, newIndex);
} else {
updateHoveringIndex(newIndex);
scrollToItem(newIndex);
}
};
const onEscOrTab = () => {
states.visible = false;
};
const onKeyboardSelect = () => {
if (!states.visible) {
return (states.visible = true);
}
const option = filteredOptions.value[states.hoveringIndex];
if (option) {
handleOptionSelect(option, false);
}
};
const onKeydown = (e: KeyboardEvent) => {
const keyCode = e.key || e.code;
const { tab, esc, down, up, enter } = EVENT_CODE;
if (keyCode === up || keyCode === down) {
e.preventDefault();
}
switch (keyCode) {
case up:
onKeyboardNavigate('ArrowUp');
break;
case down:
onKeyboardNavigate('ArrowDown');
break;
case esc:
case tab:
onEscOrTab();
break;
case enter:
onKeyboardSelect();
break;
}
};
return {
onKeydown,
};
}