Skip to content

Commit

Permalink
fix(VsSelect): fix autocomplete options closing on space key press (#212
Browse files Browse the repository at this point in the history
)

Co-authored-by: Suyeon Woo <[email protected]>
Co-authored-by: smithoo <[email protected]>
  • Loading branch information
3 people authored Jun 12, 2024
1 parent 9487459 commit 5cfb980
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 99 deletions.
50 changes: 31 additions & 19 deletions packages/vlossom/src/components/vs-select/VsSelect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
ref="triggerRef"
:class="['vs-select', `vs-${computedColorScheme}`, { ...classObj }, stateClasses]"
:style="computedStyleSet"
@click.stop="toggleOptions()"
@click.stop="onClickTrigger()"
>
<div class="vs-select-wrap">
<input
Expand All @@ -41,7 +41,7 @@
@input.stop="onInput"
@focus.stop="onFocus"
@blur.stop="onBlur"
@keydown.stop="onKeyDown"
@keydown.stop="onComboboxKeydown"
@change.stop
/>

Expand Down Expand Up @@ -152,7 +152,6 @@
:aria-multi-selectable="multiple"
:aria-activedescendant="focusedOptionId"
tabindex="-1"
@keydown.stop="onKeyDown"
>
<li
v-for="(option, index) in loadedOptions"
Expand Down Expand Up @@ -460,21 +459,28 @@ export default defineComponent({
focus,
);
const { focusedIndex, hoveredIndex, chasingMouse, onKeyDown, onMouseMove, isChasedOption, focusedOptionId } =
useFocusControl(
disabled,
readonly,
isOpen,
closeOptions,
selectAll,
isAllSelected,
selectedOptions,
filteredOptions,
loadedOptions,
selectOption,
selectAllOptions,
focus,
);
const {
focusedIndex,
focusedOptionId,
hoveredIndex,
chasingMouse,
onComboboxKeydown,
onMouseMove,
isChasedOption,
} = useFocusControl(
disabled,
readonly,
isOpen,
closeOptions,
selectAll,
isAllSelected,
selectedOptions,
filteredOptions,
loadedOptions,
selectOption,
selectAllOptions,
focus,
);
const focusing = ref(false);
Expand Down Expand Up @@ -512,6 +518,11 @@ export default defineComponent({
updateAutocompleteText(target.value);
}
function onClickTrigger() {
focus();
toggleOptions();
}
return {
id,
classObj,
Expand Down Expand Up @@ -549,7 +560,6 @@ export default defineComponent({
focusedIndex,
hoveredIndex,
chasingMouse,
onKeyDown,
onMouseMove,
isChasedOption,
focusedOptionId,
Expand All @@ -560,6 +570,8 @@ export default defineComponent({
blur,
stateClasses,
onInput,
onComboboxKeydown,
onClickTrigger,
};
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ describe('vs-select', () => {
});

describe('keyboard interaction', () => {
it('combobox가 focus를 받은 상태에서 Enter 키, Space 바를 누르면 옵션 리스트를 열고 닫을 수 있다', async () => {
it('combobox가 focus를 받은 상태에서 Enter 키를 누르면 옵션 리스트를 열고 닫을 수 있다', async () => {
// when
await wrapper.find('.vs-select-input').trigger('keydown', { code: 'Enter' });
// then
Expand All @@ -670,21 +670,18 @@ describe('vs-select', () => {
await vi.advanceTimersByTime(500);
// then
expect(wrapper.find('ul.vs-select-options').exists()).toBe(false);
});

it('combobox가 focus를 받은 상태에서 Space 키를 누르면 옵션 리스트를 열 수 있다', async () => {
// when
await wrapper.find('.vs-select-input').trigger('keydown', { code: 'Space' });
// then
expect(wrapper.find('ul.vs-select-options').exists()).toBe(true);

// when
await wrapper.find('.vs-select-input').trigger('keydown', { code: 'Space' });
await vi.advanceTimersByTime(500);
// then
expect(wrapper.find('ul.vs-select-options').exists()).toBe(false);
});

it('combobox가 focus를 받은 상태에서 Arrow Down 키를 누르면 옵션 리스트가 열리고 listbox의 첫번째 옵션으로 focus가 이동한다', async () => {
// when
await wrapper.find('.vs-select-input').trigger('keydown', { code: 'Space' });
await wrapper.find('.vs-select-input').trigger('keydown', { code: 'ArrowDown' });

// then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,58 +33,7 @@ export function useFocusControl(
}
}

function onArrowDownKey(event: KeyboardEvent) {
if (!isOpen.value && focusedIndex.value === -1) {
isOpen.value = true;
}

if (focusedIndex.value < (selectAll.value ? 1 : 0) + loadedOptions.value.length - 1) {
focusedIndex.value += 1;
}

event.preventDefault();
}

function onArrowUpKey(event: KeyboardEvent) {
if (focusedIndex.value > 0) {
focusedIndex.value -= 1;
}

event.preventDefault();
}

function onEnterKey(event: KeyboardEvent) {
if (isOpen.value) {
if (focusedIndex.value !== -1) {
selectFocusedOption();
} else {
closeOptions();
}
} else {
isOpen.value = true;
}

event.preventDefault();
}

function onEscapeKey(event: KeyboardEvent) {
closeOptions();
comboboxFocus();

event.preventDefault();
}

function onTabKey() {
if (isOpen.value) {
if (focusedIndex.value !== -1) {
selectFocusedOption();
}

closeOptions();
}
}

function onKeyDown(event: KeyboardEvent) {
function onComboboxKeydown(event: KeyboardEvent) {
if (disabled.value || readonly.value) {
return;
}
Expand All @@ -94,25 +43,65 @@ export function useFocusControl(
chasingMouse.value = false;
}

switch (event.code) {
case 'ArrowDown':
onArrowDownKey(event);
break;
case 'ArrowUp':
onArrowUpKey(event);
break;
case 'Enter':
case 'Space':
onEnterKey(event);
break;
case 'Escape':
onEscapeKey(event);
break;
case 'Tab':
onTabKey();
break;
default:
break;
if (!isOpen.value) {
switch (event.code) {
case 'Enter':
case 'Space':
case 'ArrowDown':
case 'ArrowUp':
isOpen.value = true;
event.preventDefault();
break;
default:
break;
}
} else {
const lastIndex = (selectAll.value ? 1 : 0) + loadedOptions.value.length - 1;
switch (event.code) {
case 'Enter':
if (focusedIndex.value !== -1) {
selectFocusedOption();
} else {
closeOptions();
}
event.preventDefault();
break;
case 'Escape':
closeOptions();
comboboxFocus();
event.preventDefault();
break;
case 'Space':
if (focusedIndex.value !== -1) {
selectFocusedOption();
event.preventDefault();
}
break;
case 'ArrowDown':
if (focusedIndex.value >= lastIndex) {
focusedIndex.value = -1;
} else {
focusedIndex.value += 1;
}
event.preventDefault();
break;
case 'ArrowUp':
if (focusedIndex.value < 0) {
focusedIndex.value = lastIndex;
} else {
focusedIndex.value -= 1;
}
event.preventDefault();
break;
case 'Tab':
if (focusedIndex.value !== -1) {
selectFocusedOption();
}
closeOptions();
break;
default:
break;
}
}
}

Expand Down Expand Up @@ -181,11 +170,11 @@ export function useFocusControl(

return {
focusedIndex,
focusedOptionId,
hoveredIndex,
chasingMouse,
onKeyDown,
onComboboxKeydown,
onMouseMove,
isChasedOption,
focusedOptionId,
};
}

0 comments on commit 5cfb980

Please sign in to comment.