diff --git a/src/common/components/Form/Select.tsx b/src/common/components/Form/Select.tsx index 8c21dd9..16ed3ee 100644 --- a/src/common/components/Form/Select.tsx +++ b/src/common/components/Form/Select.tsx @@ -1,79 +1,117 @@ -import { InputHTMLAttributes, PropsWithChildren } from 'react'; +import { createContext, PropsWithChildren, useContext, useEffect, useState } from 'react'; import { Control, FieldValues, Path, useController } from 'react-hook-form'; +import noop from 'lodash/noop'; import { cn } from 'common/utils/css'; -import { PropsWithTestId } from 'common/utils/types'; +import { BaseComponentProps } from 'common/utils/types'; import Label from './Label'; import FieldError from './FieldError'; import HelpText from '../Text/HelpText'; +import FAIcon, { FAIconProps } from '../Icon/FAIcon'; +import Backdrop from '../Backdrop/Backdrop'; +import Divider, { DividerProps } from '../Divider/Divider'; + +/** + * The type of value for the select form control. + */ +type SelectValue = boolean | number | string; + +/** + * Defines the attributes of the SelectContext value. + */ +type SelectContextValue = { + isDisabled: boolean; + isError: boolean; + isOpen: boolean; + setIsOpen: (isOpen: boolean) => void; + text?: string; + setText: (text?: string) => void; + value?: SelectValue; + setValue: (val: SelectValue) => void; +}; + +/** + * The SelectContext instance. + */ +const SelectContext = createContext({ + isDisabled: false, + isError: false, + isOpen: false, + setIsOpen: noop, + text: undefined, + setText: noop, + value: undefined, + setValue: noop, +}); /** * Properties for the `Select` component. * @param {Control} control - Object containing methods for registering components * into React Hook Form. + * @param {boolean} [disabled] - Optional. Indicates if the control is disabled. + * Defaults to `false`. * @param {string} [label] - Optional. The text to display. If omitted, the * `value` is displayed. * @param {string} name - Name of the form control. + * @param {boolean} [required] - Optional. Indicates if a value is required. + * Defaults to `false`. * @param {string} [supportingText] - Optional. Help text or instructions. - * @see {@link BaseComponentProps} - * @see {@link PropsWithChildren} - * @see {@link InputHTMLAttributes} */ -export interface SelectProps - extends PropsWithTestId, - PropsWithChildren, - InputHTMLAttributes { +export interface SelectProps extends BaseComponentProps, PropsWithChildren { control: Control; + disabled?: boolean; label?: string; name: string; + required?: boolean; supportingText?: string; } /** - * The `Select` component renders a HTML `select` element. It is used to capture - * one or more values from a curated set of options. - * - * The `children` must contain one or more `option` or `optgroup` elements. - * @param {SelectProps} props - Component properties. - * @returns JSX + * The `Select` component renders a list of options from which a user may select. */ const Select = ({ children, className, control, + disabled = false, label, name, + required = false, supportingText, testId = 'select', - ...props }: SelectProps): JSX.Element => { + const [isOpen, setIsOpen] = useState(false); + const [text, setText] = useState(); const { field, fieldState } = useController({ control, name: name as Path }); - const isDisabled = props.disabled || props.readOnly; + + /** Reset "text" when field value is changed to empty */ + useEffect(() => { + if (!field.value) { + setText(undefined); + } + }, [field.value]); return ( -
+
{!!label && ( -