From 04ab3306e26d29c39d627799642597538624bac8 Mon Sep 17 00:00:00 2001 From: Nathan Vasse Date: Mon, 26 Feb 2024 14:41:15 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(react)=20add=20onSearchInputChange=20?= =?UTF-8?q?callback=20to=20searchable=20select?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to be able to notify an event when the search term of the searchable select gets updated. --- .changeset/warm-roses-push.md | 5 ++ .../src/components/Forms/Select/index.tsx | 3 + .../Forms/Select/mono-searchable.tsx | 4 ++ .../src/components/Forms/Select/mono.mdx | 2 + .../src/components/Forms/Select/mono.spec.tsx | 58 ++++++++++++++++++ .../Forms/Select/multi-searchable.tsx | 10 ++- .../src/components/Forms/Select/multi.mdx | 2 + .../components/Forms/Select/multi.spec.tsx | 61 +++++++++++++++++++ 8 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 .changeset/warm-roses-push.md diff --git a/.changeset/warm-roses-push.md b/.changeset/warm-roses-push.md new file mode 100644 index 0000000..cd8ba1b --- /dev/null +++ b/.changeset/warm-roses-push.md @@ -0,0 +1,5 @@ +--- +"@openfun/cunningham-react": minor +--- + +add onSearchInputChange callback to searchable select diff --git a/packages/react/src/components/Forms/Select/index.tsx b/packages/react/src/components/Forms/Select/index.tsx index 1fd78fe..ccd220a 100644 --- a/packages/react/src/components/Forms/Select/index.tsx +++ b/packages/react/src/components/Forms/Select/index.tsx @@ -49,6 +49,9 @@ export type SelectProps = PropsWithChildren & monoline?: boolean; selectedItemsStyle?: "pills" | "text"; menuOptionsStyle?: "plain" | "checkbox"; + onSearchInputChange?: (event: { + target: { value: string | undefined }; + }) => void; }; export const Select = forwardRef((props, ref) => { if (props.defaultValue && props.value) { diff --git a/packages/react/src/components/Forms/Select/mono-searchable.tsx b/packages/react/src/components/Forms/Select/mono-searchable.tsx index 06a4f5c..e4b348d 100644 --- a/packages/react/src/components/Forms/Select/mono-searchable.tsx +++ b/packages/react/src/components/Forms/Select/mono-searchable.tsx @@ -93,6 +93,10 @@ export const SelectMonoSearchable = forwardRef( }, })); + useEffect(() => { + props.onSearchInputChange?.({ target: { value: inputFilter } }); + }, [inputFilter]); + const onInputBlur = () => { setHasInputFocused(false); if (downshiftReturn.selectedItem) { diff --git a/packages/react/src/components/Forms/Select/mono.mdx b/packages/react/src/components/Forms/Select/mono.mdx index c68d7c2..3b19d1c 100644 --- a/packages/react/src/components/Forms/Select/mono.mdx +++ b/packages/react/src/components/Forms/Select/mono.mdx @@ -40,6 +40,8 @@ You can enable the text live filtering simply by using the `searchable` props. +> You can use `onSearchInputChange` to get the value of the input when the user is typing. + ## States You can use the following props to change the state of the Select component by using the `state` props. diff --git a/packages/react/src/components/Forms/Select/mono.spec.tsx b/packages/react/src/components/Forms/Select/mono.spec.tsx index 57a52b1..4193987 100644 --- a/packages/react/src/components/Forms/Select/mono.spec.tsx +++ b/packages/react/src/components/Forms/Select/mono.spec.tsx @@ -959,6 +959,64 @@ describe(" { + searchTerm = e.target.value; + }} + /> + , + ); + + const input = screen.getByRole("combobox", { + name: "City", + }); + + await user.click(input); + expect(searchTerm).toBeUndefined(); + + await user.type(input, "Pa"); + expect(searchTerm).toEqual("Pa"); + + await user.type(input, "r", { skipClick: true }); + expect(searchTerm).toEqual("Par"); + + // Select option. + const option: HTMLLIElement = screen.getByRole("option", { + name: "Paris", + }); + await user.click(option); + expect(searchTerm).toBeUndefined(); + }); }); describe("Simple", () => { diff --git a/packages/react/src/components/Forms/Select/multi-searchable.tsx b/packages/react/src/components/Forms/Select/multi-searchable.tsx index 16587da..f7c08b2 100644 --- a/packages/react/src/components/Forms/Select/multi-searchable.tsx +++ b/packages/react/src/components/Forms/Select/multi-searchable.tsx @@ -16,7 +16,7 @@ import { SelectHandle } from ":/components/Forms/Select/index"; export const SelectMultiSearchable = forwardRef( (props, ref) => { - const [inputValue, setInputValue] = React.useState(""); + const [inputValue, setInputValue] = React.useState(); const inputRef = useRef(null); const options = React.useMemo( () => @@ -75,11 +75,11 @@ export const SelectMultiSearchable = forwardRef( ...props.selectedItems, newSelectedItem, ]); - setInputValue(""); + setInputValue(undefined); } break; case useCombobox.stateChangeTypes.InputChange: - setInputValue(newInputValue ?? ""); + setInputValue(newInputValue); break; default: break; @@ -124,6 +124,10 @@ export const SelectMultiSearchable = forwardRef( }, })); + useEffect(() => { + props.onSearchInputChange?.({ target: { value: inputValue } }); + }, [inputValue]); + return ( +> You can use `onSearchInputChange` to get the value of the input when the user is typing. + ## States You can use the following props to change the state of the Multi-Select component by using the `state` props. diff --git a/packages/react/src/components/Forms/Select/multi.spec.tsx b/packages/react/src/components/Forms/Select/multi.spec.tsx index 8ee97b5..ea92979 100644 --- a/packages/react/src/components/Forms/Select/multi.spec.tsx +++ b/packages/react/src/components/Forms/Select/multi.spec.tsx @@ -1193,6 +1193,67 @@ describe(" { + searchTerm = e.target.value; + }} + /> + , + ); + + const input = screen.getByRole("combobox", { + name: "Cities", + }); + expect(searchTerm).toBeUndefined(); + + await user.click(input); + expect(searchTerm).toBeUndefined(); + + await user.type(input, "Pa"); + expect(searchTerm).toEqual("Pa"); + + await user.type(input, "r"); + expect(searchTerm).toEqual("Par"); + expectOptions(["Paris"]); + + const option: HTMLLIElement = screen.getByRole("option", { + name: "Paris", + }); + await user.click(option); + + expect(searchTerm).toBeUndefined(); + }); + it("selects the option on enter", async () => { const user = userEvent.setup(); render(