From d2b734536fc94640ca6ac0558392ae6fa80b4a65 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Tue, 23 Apr 2024 15:45:22 +0200 Subject: [PATCH] Add optional `onClose` callback to `Combobox` component (#3122) * add optional `onClose` callback to `Combobox` component * update changelog * add tests to ensure `onClose` is called when `Combobox` closes --- packages/@headlessui-react/CHANGELOG.md | 1 + .../src/components/combobox/combobox.test.tsx | 14 ++++++++++++-- .../src/components/combobox/combobox.tsx | 4 ++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/@headlessui-react/CHANGELOG.md b/packages/@headlessui-react/CHANGELOG.md index bf6b51f..2d620e5 100644 --- a/packages/@headlessui-react/CHANGELOG.md +++ b/packages/@headlessui-react/CHANGELOG.md @@ -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 diff --git a/packages/@headlessui-react/src/components/combobox/combobox.test.tsx b/packages/@headlessui-react/src/components/combobox/combobox.test.tsx index 6da3f5e..fed87bd 100644 --- a/packages/@headlessui-react/src/components/combobox/combobox.test.tsx +++ b/packages/@headlessui-react/src/components/combobox/combobox.test.tsx @@ -542,6 +542,7 @@ 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' }, @@ -549,7 +550,7 @@ describe('Rendering', () => { ] render( - name="assignee" by="id"> + name="assignee" by="id" onClose={closeHandler}> @@ -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 }) @@ -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(undefined) @@ -2833,6 +2837,7 @@ describe.each([{ virtual: true }, { virtual: false }])( { - render() + let closeHandler = jest.fn() + render() // Open combobox await click(getComboboxButton()) @@ -4891,7 +4899,9 @@ describe.each([{ virtual: true }, { virtual: false }])('Mouse interactions %s', 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 }) diff --git a/packages/@headlessui-react/src/components/combobox/combobox.tsx b/packages/@headlessui-react/src/components/combobox/combobox.tsx index 8236c8b..0e515da 100644 --- a/packages/@headlessui-react/src/components/combobox/combobox.tsx +++ b/packages/@headlessui-react/src/components/combobox/combobox.tsx @@ -588,6 +588,8 @@ export type ComboboxProps< disabled?: (value: NoInfer) => boolean } | null + onClose?(): void + __demoMode?: boolean } > @@ -605,6 +607,7 @@ function ComboboxFn { dispatch({ type: ActionTypes.CloseCombobox }) defaultToFirstOption.current = false + onClose?.() }) let goToOption = useEvent((focus, idx, trigger) => {