Skip to content

Commit

Permalink
Add optional onClose callback to Combobox component (#3122)
Browse files Browse the repository at this point in the history
* add optional `onClose` callback to `Combobox` component

* update changelog

* add tests to ensure `onClose` is called when `Combobox` closes
  • Loading branch information
RobinMalfait authored Apr 23, 2024
1 parent 6c9e4b2 commit d2b7345
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 2 deletions.
1 change: 1 addition & 0 deletions packages/@headlessui-react/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Ensure anchored components are properly stacked on top of `Dialog` components ([#3111](https://github.com/tailwindlabs/headlessui/pull/3111))
- Move focus to `ListboxOptions` and `MenuItems` when they are rendered later ([#3112](https://github.com/tailwindlabs/headlessui/pull/3112))
- Ensure anchored components are always rendered in a stacking context ([#3115](https://github.com/tailwindlabs/headlessui/pull/3115))
- Add optional `onClose` callback to `Combobox` component ([#3122](https://github.com/tailwindlabs/headlessui/pull/3122))

### Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -542,14 +542,15 @@ describe('Rendering', () => {
it(
'should close the Combobox when the input is blurred',
suppressConsoleLogs(async () => {
let closeHandler = jest.fn()
let data = [
{ id: 1, name: 'alice', label: 'Alice' },
{ id: 2, name: 'bob', label: 'Bob' },
{ id: 3, name: 'charlie', label: 'Charlie' },
]

render(
<Combobox<(typeof data)[number]> name="assignee" by="id">
<Combobox<(typeof data)[number]> name="assignee" by="id" onClose={closeHandler}>
<Combobox.Input onChange={NOOP} />
<Combobox.Button />
<Combobox.Options>
Expand All @@ -569,7 +570,9 @@ describe('Rendering', () => {
assertComboboxList({ state: ComboboxState.Visible })

// Close the combobox
expect(closeHandler).toHaveBeenCalledTimes(0)
await blur(getComboboxInput())
expect(closeHandler).toHaveBeenCalledTimes(1)

// Verify it is closed
assertComboboxList({ state: ComboboxState.InvisibleUnmounted })
Expand Down Expand Up @@ -2825,6 +2828,7 @@ describe.each([{ virtual: true }, { virtual: false }])(
'should be possible to close the combobox with Enter and choose the active combobox option',
suppressConsoleLogs(async () => {
let handleChange = jest.fn()
let closeHandler = jest.fn()

function Example() {
let [value, setValue] = useState<string | undefined>(undefined)
Expand All @@ -2833,6 +2837,7 @@ describe.each([{ virtual: true }, { virtual: false }])(
<MyCombobox
comboboxProps={{
value,
onClose: closeHandler,
onChange(value: string | undefined) {
setValue(value)
handleChange(value)
Expand Down Expand Up @@ -2861,7 +2866,9 @@ describe.each([{ virtual: true }, { virtual: false }])(
await mouseMove(options[0])

// Choose option, and close combobox
expect(closeHandler).toHaveBeenCalledTimes(0)
await press(Keys.Enter)
expect(closeHandler).toHaveBeenCalledTimes(1)

// Verify it is closed
assertComboboxButton({ state: ComboboxState.InvisibleUnmounted })
Expand Down Expand Up @@ -4883,15 +4890,18 @@ describe.each([{ virtual: true }, { virtual: false }])('Mouse interactions %s',
it(
'should be possible to click outside of the combobox which should close the combobox (even if we press the combobox button)',
suppressConsoleLogs(async () => {
render(<MyCombobox />)
let closeHandler = jest.fn()
render(<MyCombobox comboboxProps={{ onClose: closeHandler }} />)

// Open combobox
await click(getComboboxButton())
assertComboboxList({ state: ComboboxState.Visible })
assertActiveElement(getComboboxInput())

// Click the combobox button again
expect(closeHandler).toHaveBeenCalledTimes(0)
await click(getComboboxButton())
expect(closeHandler).toHaveBeenCalledTimes(1)

// Should be closed now
assertComboboxList({ state: ComboboxState.InvisibleUnmounted })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,8 @@ export type ComboboxProps<
disabled?: (value: NoInfer<TValue>) => boolean
} | null

onClose?(): void

__demoMode?: boolean
}
>
Expand All @@ -605,6 +607,7 @@ function ComboboxFn<TValue, TTag extends ElementType = typeof DEFAULT_COMBOBOX_T
name,
by,
disabled = providedDisabled || false,
onClose,
__demoMode = false,
multiple = false,
immediate = false,
Expand Down Expand Up @@ -771,6 +774,7 @@ function ComboboxFn<TValue, TTag extends ElementType = typeof DEFAULT_COMBOBOX_T
let closeCombobox = useEvent(() => {
dispatch({ type: ActionTypes.CloseCombobox })
defaultToFirstOption.current = false
onClose?.()
})

let goToOption = useEvent((focus, idx, trigger) => {
Expand Down

0 comments on commit d2b7345

Please sign in to comment.