diff --git a/packages/radix-vue/src/Listbox/Listbox.test.ts b/packages/radix-vue/src/Listbox/Listbox.test.ts index cb7e02a08..2107c97c9 100644 --- a/packages/radix-vue/src/Listbox/Listbox.test.ts +++ b/packages/radix-vue/src/Listbox/Listbox.test.ts @@ -229,6 +229,95 @@ describe('given multiple `true` Listbox', () => { }) }) +describe('given horizontal Listbox', () => { + const kbd = useKbd() + let wrapper: VueWrapper> + let content: DOMWrapper + let items: DOMWrapper[] + + window.HTMLElement.prototype.releasePointerCapture = vi.fn() + window.HTMLElement.prototype.hasPointerCapture = vi.fn() + window.HTMLElement.prototype.scrollIntoView = vi.fn() + + beforeEach(() => { + document.body.innerHTML = '' + wrapper = mount(Listbox, { attachTo: document.body, props: { orientation: 'horizontal' } }) + content = wrapper.find('[role=listbox]') + items = wrapper.findAll('[role=option]') + }) + + it('should pass axe accessibility tests', async () => { + expect(await axe(wrapper.element)).toHaveNoViolations() + }) + + describe('when focus on content', () => { + beforeEach(async () => { + await content.trigger('focus') + }) + + it('should pass the focus to the first item', () => { + expect(document.activeElement).toBe(items[0].element) + }) + + it('should have highlighted state on first item', () => { + expect(items[0].attributes('data-highlighted')).toBe('') + }) + + it('should emit `highlight` event', () => { + expect(wrapper.emitted('highlight')?.[0]?.[0]).toBeTruthy() + }) + + it('should highlight and select item when clicked', async () => { + const item = items[2] + await item.trigger('click') + expect(item.attributes('aria-selected')).toBe('true') + expect(item.attributes('data-state')).toBe('checked') + }) + + describe('after pressing `Enter`', async () => { + beforeEach(async () => { + await content.trigger('keydown', { key: kbd.ENTER }) + }) + + it('should select the highlighted item', () => { + const item = items[0] + expect(item.attributes('data-highlighted')).toBe('') + expect(item.attributes('aria-selected')).toBe('true') + expect(item.attributes('data-state')).toBe('checked') + }) + + it('should emit `update:modelValue` event', () => { + expect(wrapper.emitted('update:modelValue')?.[0]?.[0]).toBe(items[0].text()) + }) + + it('should deselect after pressing `Enter`', async () => { + await content.trigger('keydown', { key: kbd.ENTER }) + const item = items[0] + expect(item.attributes('data-highlighted')).toBe('') + expect(item.attributes('aria-selected')).toBe('false') + expect(item.attributes('data-state')).toBe('unchecked') + }) + + describe('after selecting other item and press `Enter`', async () => { + beforeEach(async () => { + await content.trigger('keydown', { key: kbd.ARROW_RIGHT }) + await content.trigger('keydown', { key: kbd.ARROW_RIGHT }) + await content.trigger('keydown', { key: kbd.ENTER }) + }) + + it('should select the third item', () => { + const item = items[0] + const newItem = items[2] + expect(item.attributes('aria-selected')).toBe('false') + expect(item.attributes('data-state')).toBe('unchecked') + expect(newItem.attributes('aria-selected')).toBe('true') + expect(newItem.attributes('data-state')).toBe('checked') + }) + }) + }) + }) +}) + describe('given Listbox in a form', async () => { let items: DOMWrapper[] diff --git a/packages/radix-vue/src/Listbox/ListboxContent.vue b/packages/radix-vue/src/Listbox/ListboxContent.vue index dd98b1986..5d7b97f12 100644 --- a/packages/radix-vue/src/Listbox/ListboxContent.vue +++ b/packages/radix-vue/src/Listbox/ListboxContent.vue @@ -30,7 +30,7 @@ const isClickFocus = refAutoReset(false, 10) return rootContext.onEnter(ev) }" - @keydown.down.up.home.end.prevent="(event) => { + @keydown.down.up.left.right.home.end.prevent="(event) => { rootContext.focusable.value ? rootContext.onKeydownNavigation(event) : undefined }" @keydown.enter="rootContext.onKeydownEnter" diff --git a/packages/radix-vue/src/Listbox/ListboxFilter.vue b/packages/radix-vue/src/Listbox/ListboxFilter.vue index f8cc7a88c..122da2349 100644 --- a/packages/radix-vue/src/Listbox/ListboxFilter.vue +++ b/packages/radix-vue/src/Listbox/ListboxFilter.vue @@ -57,7 +57,7 @@ onMounted(() => { :disabled="rootContext.disabled.value ? '' : undefined" :data-disabled="rootContext.disabled.value ? '' : undefined" type="text" - @keydown.down.up.home.end.prevent="rootContext.onKeydownNavigation" + @keydown.down.up.left.right.home.end.prevent="rootContext.onKeydownNavigation" @keydown.enter="rootContext.onKeydownEnter" @input="(event: InputEvent) => { modelValue = (event.target as HTMLInputElement).value diff --git a/packages/radix-vue/src/Listbox/story/ListboxChromatic.story.vue b/packages/radix-vue/src/Listbox/story/ListboxChromatic.story.vue index a92174c4f..88d467345 100644 --- a/packages/radix-vue/src/Listbox/story/ListboxChromatic.story.vue +++ b/packages/radix-vue/src/Listbox/story/ListboxChromatic.story.vue @@ -172,5 +172,23 @@ const multipleControl = ref() + + + + + + {{ i }} + + + +