Skip to content

Commit

Permalink
fix(EbayListboxButton): Show listbox with active descendent on button…
Browse files Browse the repository at this point in the history
… focus (#382)
  • Loading branch information
HenriqueLimas authored Dec 20, 2024
1 parent 872d263 commit 0480411
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 11 deletions.
28 changes: 27 additions & 1 deletion src/ebay-listbox-button/__tests__/index.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/// <reference types="@testing-library/jest-dom" />
import React from 'react'
import { fireEvent, render, screen } from '@testing-library/react'
import { act, fireEvent, render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { eventOfType } from '../../common/event-utils/__tests__/helpers'
import { EbayListboxButton, EbayListboxButtonOption } from '..'

Expand Down Expand Up @@ -37,6 +39,30 @@ describe('<EbayListboxButton>', () => {

expect(buttonElement).not.toHaveAttribute('aria-labelledby')
})

it('should render aria-activedescendant with selected option id', async () => {
await renderListbox()

act(() => {
userEvent.click(screen.getByRole('button'))
})

act(() => {
userEvent.click(screen.getAllByRole('option')[1])
})

expect(screen.getByRole('listbox')).toHaveAttribute('aria-activedescendant', screen.getAllByRole('option')[1].id)
})

it('should render aria-activedescendant on focus of the button', async () => {
await renderListbox()

expect(screen.queryByRole('listbox')).not.toBeInTheDocument()

fireEvent.focus(screen.getByRole('button'))

expect(screen.getByRole('listbox')).toHaveAttribute('aria-activedescendant', screen.getAllByRole('option')[1].id)
})
})

describe('on render', () => {
Expand Down
2 changes: 0 additions & 2 deletions src/ebay-listbox-button/listbox-button-option.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ const ListboxOption: FC<EbayListboxButtonOptionProps> = ({
index,
innerRef,
className,
id,
...rest
}) => {
const wrapperClassName = classNames(`listbox-button__option`, className,
Expand All @@ -27,7 +26,6 @@ const ListboxOption: FC<EbayListboxButtonOptionProps> = ({
{...rest}
className={wrapperClassName}
role="option"
id={id || `listbox_btn_${value}_${index}`}
aria-selected={selected}
ref={innerRef}
onClick={(e) => {onClick(e, value, index)}}
Expand Down
12 changes: 4 additions & 8 deletions src/ebay-listbox-button/listbox-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export type ChangeEventProps = {
wasClicked: boolean;
}

export type EbayListboxButtonProps = Omit<ComponentProps<'input'>, 'onChange'> & {
export type EbayListboxButtonProps = Omit<ComponentProps<'button'>, 'onChange'> & {
selected?: number;
borderless?: boolean;
fluid?: boolean;
Expand Down Expand Up @@ -89,10 +89,6 @@ const ListboxButton: FC<EbayListboxButtonProps> = ({
const getIndexByValue = useCallback((selectedValue) =>
childrenArray.findIndex(({ props }) => props.value === selectedValue), [childrenArray])
const getSelectedOption = (currentIndex: number) => optionsByIndexRef.current.get(currentIndex)
const setActiveDescendant = (index: number) => {
const optionsContainerEle = optionsContainerRef.current
optionsContainerEle?.setAttribute(`aria-activedescendant`, getSelectedOption(index).id)
}

const collapseListbox = () => {
setExpanded(false)
Expand All @@ -117,7 +113,6 @@ const ListboxButton: FC<EbayListboxButtonProps> = ({
setSelectedOption(childrenArray[index])
setSelectedIndex(index)
collapseListbox()
setActiveDescendant(index)
buttonRef.current.focus()
onChange(e, { index, selected: [getSelectedValueByIndex(index)], wasClicked })
setWasClicked(false)
Expand Down Expand Up @@ -160,7 +155,6 @@ const ListboxButton: FC<EbayListboxButtonProps> = ({
makeOptionActive(selectedIndex === undefined || updatedIndex === -1 ? 0 : updatedIndex)
makeOptionInActive(selectedIndex === undefined || selectedIndex === -1 ? 0 : selectedIndex)
scrollOptions(updatedIndex)
setActiveDescendant(updatedIndex)
setSelectedIndex(updatedIndex)
setSelectedOption(childrenArray[updatedIndex])
}
Expand All @@ -169,7 +163,6 @@ const ListboxButton: FC<EbayListboxButtonProps> = ({
setTimeout(() => optionsContainerRef?.current?.focus(focusOptions), 0)
const onButtonClick = () => {
toggleListbox()
setOptionsOpened(true)
focusOptionsContainer({ preventScroll: true })
}
const onButtonKeyup = (e: KeyboardEvent<HTMLButtonElement>) => {
Expand Down Expand Up @@ -233,6 +226,7 @@ const ListboxButton: FC<EbayListboxButtonProps> = ({
index,
key: index,
selected: selectedOption && child.props.value === selectedOption.props.value,
id: child.props.id || `listbox_btn_${child.props.value}_${index}`,
onClick: (e) => onOptionsSelect(e, index),
innerRef: optionNode => !optionNode
? optionsByIndexRef.current.delete(index)
Expand Down Expand Up @@ -261,6 +255,7 @@ const ListboxButton: FC<EbayListboxButtonProps> = ({
<span className={wrapperClassName}>
<button
{...rest}
onFocus={() => setOptionsOpened(true)}
type="button"
className={buttonClassName}
aria-expanded={!!expanded}
Expand All @@ -287,6 +282,7 @@ const ListboxButton: FC<EbayListboxButtonProps> = ({
role="listbox"
tabIndex={expanded ? 0 : -1}
ref={optionsContainerRef}
aria-activedescendant={updateListBoxButtonOptions[selectedIndex]?.props.id}
onKeyDown={(e) => onOptionContainerKeydown(e)}
// adding onMouseDown preventDefault b/c on IE the onClick event is not being fired on each
// option https://stackoverflow.com/questions/17769005/onclick-and-onblur-ordering-issue
Expand Down

0 comments on commit 0480411

Please sign in to comment.