Skip to content

Commit

Permalink
fix(Listbox): horizontal orientation not working (unovue#1299)
Browse files Browse the repository at this point in the history
* fix: horizontal orientation not working

* chore: add story

* test: add horizontal test case
  • Loading branch information
zernonia authored Sep 18, 2024
1 parent ff5abb0 commit b6c6fbf
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 2 deletions.
89 changes: 89 additions & 0 deletions packages/radix-vue/src/Listbox/Listbox.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,95 @@ describe('given multiple `true` Listbox', () => {
})
})

describe('given horizontal Listbox', () => {
const kbd = useKbd()
let wrapper: VueWrapper<InstanceType<typeof Listbox>>
let content: DOMWrapper<Element>
let items: DOMWrapper<Element>[]

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<Element>[]

Expand Down
2 changes: 1 addition & 1 deletion packages/radix-vue/src/Listbox/ListboxContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion packages/radix-vue/src/Listbox/ListboxFilter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 18 additions & 0 deletions packages/radix-vue/src/Listbox/story/ListboxChromatic.story.vue
Original file line number Diff line number Diff line change
Expand Up @@ -172,5 +172,23 @@ const multipleControl = ref()
</ListboxContent>
</ListboxRoot>
</Variant>

<Variant title="Orientation (Horizontal)">
<ListboxRoot
class="w-64 h-full flex flex-col p-1 rounded-lg border bg-white text-green9 mx-auto overflow-auto"
orientation="horizontal"
>
<ListboxContent class="flex flex-row ">
<ListboxItem
v-for="i in options"
:key="i"
:value="i"
class="w-full py-1 px-2 text-green9 select-none text-sm focus:ring-0 data-[highlighted]:outline-green9 data-[highlighted]:outline-1 data-[highlighted]:outline focus:outline-green9 data-[state=checked]:bg-green9 data-[state=checked]:text-white data-[disabled]:opacity-50 rounded"
>
{{ i }}
</ListboxItem>
</ListboxContent>
</ListboxRoot>
</Variant>
</Story>
</template>

0 comments on commit b6c6fbf

Please sign in to comment.