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(