Skip to content

Commit

Permalink
feat(useSelect): focus toggle on label click (#1561)
Browse files Browse the repository at this point in the history
* feat(useSelect): focus toggle on label click

* add types

* add documentation
  • Loading branch information
silviuaavram committed Dec 29, 2023
1 parent 4edfc30 commit 53dd723
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 8 deletions.
4 changes: 4 additions & 0 deletions src/hooks/useSelect/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,10 @@ described below.
- `Click`: It will select the item and close the menu.
- `MouseOver`: It will highlight the item.

#### Label

- `Click`: It will move focus to the toggle element.

### Customizing Handlers

You can provide your own event handlers to `useSelect` which will be called
Expand Down
55 changes: 53 additions & 2 deletions src/hooks/useSelect/__tests__/getLabelProps.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {renderUseSelect} from '../testUtils'
import {defaultIds} from '../../testUtils'
import {act, screen} from '@testing-library/react'
import {renderSelect, renderUseSelect} from '../testUtils'
import {defaultIds, getToggleButton, user} from '../../testUtils'

describe('getLabelProps', () => {
test('should have a default id assigned', () => {
Expand Down Expand Up @@ -36,4 +37,54 @@ describe('getLabelProps', () => {

expect(labelProps).toEqual(expect.objectContaining({foo: 'bar'}))
})

test('on click moves focus to the toggle button', async () => {
renderSelect()

await user.click(
screen.getByText('Choose an element:', {selector: 'label'}),
)

expect(getToggleButton()).toHaveFocus()
})

test('event handler onClick is called along with downshift handler', () => {
const userOnClick = jest.fn()
const mockToggleButton = {focus: jest.fn()}
const {result} = renderUseSelect()

act(() => {
const {onClick} = result.current.getLabelProps({
onClick: userOnClick,
})
const {ref} = result.current.getToggleButtonProps()
ref(mockToggleButton)

onClick({})
})

expect(userOnClick).toHaveBeenCalledTimes(1)
expect(mockToggleButton.focus).toHaveBeenCalledTimes(1)
})

test("the downshift handler is not called if 'preventDownshiftDefault' is passed in user event", () => {
const userOnClick = jest.fn(event => {
event.preventDownshiftDefault = true
})
const mockToggleButton = {focus: jest.fn()}
const {result} = renderUseSelect()

act(() => {
const {onClick} = result.current.getLabelProps({
onClick: userOnClick,
})
const {ref} = result.current.getToggleButtonProps()
ref(mockToggleButton)

onClick({})
})

expect(userOnClick).toHaveBeenCalledTimes(1)
expect(mockToggleButton.focus).not.toHaveBeenCalled()
})
})
17 changes: 12 additions & 5 deletions src/hooks/useSelect/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -322,11 +322,18 @@ function useSelect(userProps = {}) {
)
// Getter functions.
const getLabelProps = useCallback(
labelProps => ({
id: elementIds.labelId,
htmlFor: elementIds.toggleButtonId,
...labelProps,
}),
({onClick, ...labelProps} = {}) => {
const labelHandleClick = () => {
toggleButtonRef.current?.focus()
}

return {
id: elementIds.labelId,
htmlFor: elementIds.toggleButtonId,
onClick: callAllEventHandlers(onClick, labelHandleClick),
...labelProps,
}
},
[elementIds],
)
const getMenuProps = useCallback(
Expand Down
4 changes: 3 additions & 1 deletion typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,9 @@ export interface UseSelectGetToggleButtonReturnValue
tabIndex: 0
}

export interface UseSelectGetLabelPropsOptions extends GetLabelPropsOptions {}
export interface UseSelectGetLabelPropsOptions extends GetLabelPropsOptions {
onClick: React.MouseEventHandler
}
export interface UseSelectGetLabelPropsReturnValue
extends GetLabelPropsReturnValue {}

Expand Down

0 comments on commit 53dd723

Please sign in to comment.