diff --git a/src/components/form/select/Select.test.tsx b/src/components/form/select/Select.test.tsx index 4f4551fa..b4c6054a 100644 --- a/src/components/form/select/Select.test.tsx +++ b/src/components/form/select/Select.test.tsx @@ -128,3 +128,100 @@ it("can be registered as a React Hook Form uncontrolled component", async () => name: optionToChoose, }); }); + +it("displays a placeholder option that is chosen by default if placeholder is provided", () => { + const placeholder = "Select from the MANY options below!"; + render( + + ); + const placeholderOption = screen.getByRole("option", { name: placeholder }); + expect(placeholderOption).toBeInTheDocument(); + const select = screen.getByRole("combobox"); + expect(select.firstChild?.isEqualNode(placeholderOption)).toEqual(true); + expect(select).toHaveValue(""); +}); + +it("does not display a placeholder option if placeholder is not provided", () => { + render( + + ); + const select = screen.getByRole("combobox"); + const optionA = screen.getByRole("option", { name: "A" }); + expect(select).toHaveValue("A"); + expect(select.firstChild?.isEqualNode(optionA)).toEqual(true); +}); + +it("hides the placeholder option if the user chose a valid option", () => { + const placeholder = "Select from the MANY options below!"; + render( + + ); + const placeholderOption = screen.getByRole("option", { name: placeholder }); + expect(placeholderOption).toBeInTheDocument(); + expect(placeholderOption).toBeVisible(); + expect(screen.getAllByRole("option")).toHaveLength(3); + const select = screen.getByRole("combobox"); + expect(select.firstChild?.isEqualNode(placeholderOption)).toEqual(true); + expect(select).toHaveValue(""); + user.selectOptions(select, ["A"]); + const removedPlaceholderOption = screen.queryByRole("option", { + name: placeholder, + }); + expect(removedPlaceholderOption).toBeNull(); + expect(screen.getAllByRole("option")).toHaveLength(2); +}); + +it("does not hide the placeholder option if the user chose a valid option but hiding was disabled", () => { + const placeholder = "Select from the MANY options below!"; + render( + + ); + const placeholderOption = screen.getByRole("option", { name: placeholder }); + expect(placeholderOption).toBeInTheDocument(); + expect(placeholderOption).toBeVisible(); + expect(screen.getAllByRole("option")).toHaveLength(3); + const select = screen.getByRole("combobox"); + expect(select.firstChild?.isEqualNode(placeholderOption)).toEqual(true); + expect(select).toHaveValue(""); + user.selectOptions(select, ["A"]); + const removedPlaceholderOption = screen.queryByRole("option", { + name: placeholder, + }); + expect(removedPlaceholderOption).not.toBeNull(); + expect(screen.getAllByRole("option")).toHaveLength(3); +}); + +it("does not hide the placeholder option if the user chose a valid option by default", () => { + const placeholder = "Select from the MANY options below!"; + render( + + ); + const placeholderOption = screen.getByRole("option", { name: placeholder }); + expect(placeholderOption).toBeInTheDocument(); + expect(placeholderOption).toBeVisible(); + expect(screen.getAllByRole("option")).toHaveLength(3); + const select = screen.getByRole("combobox"); + expect(select.firstChild?.isEqualNode(placeholderOption)).toEqual(true); + expect(select).toHaveValue(""); + user.selectOptions(select, ["A"]); + const removedPlaceholderOption = screen.queryByRole("option", { + name: placeholder, + }); + expect(removedPlaceholderOption).not.toBeNull(); + expect(screen.getAllByRole("option")).toHaveLength(3); +}); diff --git a/src/components/form/select/Select.tsx b/src/components/form/select/Select.tsx index a884a1a2..8a4c8c1f 100644 --- a/src/components/form/select/Select.tsx +++ b/src/components/form/select/Select.tsx @@ -1,4 +1,4 @@ -import { SelectHTMLAttributes } from "react"; +import { SelectHTMLAttributes, useState } from "react"; import { UseFormRegisterReturn } from "react-hook-form"; import { CommonFormInputAttributes, Size } from "../../../types"; import { @@ -16,6 +16,7 @@ export type SelectProps = HTMLSelectAttributes & CommonFormInputAttributes & { size?: Size; register?: UseFormRegisterReturn; + hidePlaceholderAfterChange?: boolean; }; const classNameMap: ClassNameTransformMap = new Map([ @@ -32,14 +33,29 @@ export const Select = ({ describedBy, register, invalid = false, + placeholder, + hidePlaceholderAfterChange, ...props }: SelectProps): JSX.Element => { + const [interactedWith, setInteractedWith] = useState(false); const className = createClassNameFromProps( classNameMap, { color, size, multiple } as Partial, ["select"] ); + const onInput = () => { + if (hidePlaceholderAfterChange) { + setInteractedWith(true); + } + }; + + const placeholderOption = placeholder && ( + + ); + return (
diff --git a/src/stories/form/Select.stories.tsx b/src/stories/form/Select.stories.tsx index 53a08440..7ade4585 100644 --- a/src/stories/form/Select.stories.tsx +++ b/src/stories/form/Select.stories.tsx @@ -25,6 +25,11 @@ export default { type: "boolean", }, }, + placeholder: { + control: { + type: "text", + }, + }, }, } as Meta;