Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional onClose callback to Combobox component #3122

Merged
merged 3 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading