diff --git a/.changeset/dirty-moles-refuse.md b/.changeset/dirty-moles-refuse.md new file mode 100644 index 0000000000..5a73d0c78f --- /dev/null +++ b/.changeset/dirty-moles-refuse.md @@ -0,0 +1,5 @@ +--- +"@nextui-org/autocomplete": patch +--- + +Clicking the clear button clears the selected value without closing the dropdown. (#3788) \ No newline at end of file diff --git a/packages/components/autocomplete/__tests__/autocomplete.test.tsx b/packages/components/autocomplete/__tests__/autocomplete.test.tsx index ab4f6d381f..fb6162007c 100644 --- a/packages/components/autocomplete/__tests__/autocomplete.test.tsx +++ b/packages/components/autocomplete/__tests__/autocomplete.test.tsx @@ -223,7 +223,7 @@ describe("Autocomplete", () => { expect(clearButton).not.toBeNull(); - // select the target item + // click the clear button await act(async () => { await userEvent.click(clearButton); }); @@ -235,6 +235,55 @@ describe("Autocomplete", () => { expect(autocomplete).toHaveFocus(); }); + it("should keep the ListBox open after clicking clear button", async () => { + const wrapper = render( + + + Penguin + + + Zebra + + + Shark + + , + ); + + const autocomplete = wrapper.getByTestId("autocomplete"); + + // open the select listbox + await act(async () => { + await userEvent.click(autocomplete); + }); + + // assert that the autocomplete listbox is open + expect(autocomplete).toHaveAttribute("aria-expanded", "true"); + + let options = wrapper.getAllByRole("option"); + + // select the target item + await act(async () => { + await userEvent.click(options[0]); + }); + + const {container} = wrapper; + + const clearButton = container.querySelector( + "[data-slot='inner-wrapper'] button:nth-of-type(1)", + )!; + + expect(clearButton).not.toBeNull(); + + // click the clear button + await act(async () => { + await userEvent.click(clearButton); + }); + + // assert that the autocomplete listbox is open + expect(autocomplete).toHaveAttribute("aria-expanded", "true"); + }); + it("should clear value after clicking clear button (controlled)", async () => { const wrapper = render( @@ -267,7 +316,7 @@ describe("Autocomplete", () => { expect(clearButton).not.toBeNull(); - // select the target item + /// click the clear button await act(async () => { await userEvent.click(clearButton); }); @@ -279,6 +328,47 @@ describe("Autocomplete", () => { expect(autocomplete).toHaveFocus(); }); + it("should keep the ListBox open after clicking clear button (controlled)", async () => { + const wrapper = render( + + {(item) => {item.value}} + , + ); + + const autocomplete = wrapper.getByTestId("autocomplete"); + + // open the select listbox + await act(async () => { + await userEvent.click(autocomplete); + }); + + // assert that the autocomplete listbox is open + expect(autocomplete).toHaveAttribute("aria-expanded", "true"); + + let options = wrapper.getAllByRole("option"); + + // select the target item + await act(async () => { + await userEvent.click(options[0]); + }); + + const {container} = wrapper; + + const clearButton = container.querySelector( + "[data-slot='inner-wrapper'] button:nth-of-type(1)", + )!; + + expect(clearButton).not.toBeNull(); + + // click the clear button + await act(async () => { + await userEvent.click(clearButton); + }); + + // assert that the autocomplete listbox is open + expect(autocomplete).toHaveAttribute("aria-expanded", "true"); + }); + it("should open and close listbox by clicking selector button", async () => { const wrapper = render( diff --git a/packages/components/autocomplete/src/use-autocomplete.ts b/packages/components/autocomplete/src/use-autocomplete.ts index d1cae053f3..b6a9cae1ab 100644 --- a/packages/components/autocomplete/src/use-autocomplete.ts +++ b/packages/components/autocomplete/src/use-autocomplete.ts @@ -385,16 +385,15 @@ export function useAutocomplete(originalProps: UseAutocomplete }, onPress: (e: PressEvent) => { slotsProps.clearButtonProps?.onPress?.(e); - if (state.selectedItem) { state.setInputValue(""); state.setSelectedKey(null); } else { if (allowsCustomValue) { state.setInputValue(""); - state.close(); } } + state.open(); }, "data-visible": !!state.selectedItem || state.inputValue?.length > 0, className: slots.clearButton({