import TextField, { TextFieldProps } from "@material-ui/core/TextField" import { FormikContextType } from "formik" import React from "react" import { PasswordField } from "../PasswordField/PasswordField" /** * FormFieldProps are required props for creating form fields using a factory. */ export interface FormFieldProps { /** * form is a reference to a form or subform and is used to compute common * states such as error and helper text */ form: FormikContextType /** * formFieldName is a field name associated with the form schema. */ formFieldName: keyof T } /** * FormTextFieldProps extends form-related MUI TextFieldProps with Formik * props. The passed in form is used to compute error states and configure * change handlers. `formFieldName` represents the key of a Formik value * that's associated to this component. */ export interface FormTextFieldProps extends Pick< TextFieldProps, | "autoComplete" | "autoFocus" | "children" | "className" | "disabled" | "fullWidth" | "helperText" | "id" | "InputLabelProps" | "InputProps" | "inputProps" | "label" | "margin" | "multiline" | "onChange" | "placeholder" | "required" | "rows" | "select" | "SelectProps" | "style" | "type" >, FormFieldProps { /** * eventTransform is an optional transformer on the event data before it is * processed by formik. * * @example * { * return str.replace(" ", "-") * }} * /> */ eventTransform?: (value: string) => string /** * isPassword uses a PasswordField component when `true`; otherwise a * TextField component is used. */ isPassword?: boolean /** * displayValueOverride allows displaying a different value in the field * without changing the actual underlying value. */ displayValueOverride?: string variant?: "outlined" | "filled" | "standard" } /** * Factory function for creating a formik TextField * * @example * interface FormValues { * username: string * } * * // Use the factory to create a FormTextField associated to this form * const FormTextField = formTextFieldFactory() * * const MyComponent: React.FC = () => { * const form = useFormik() * * return ( * * ) * } */ export const FormTextField = ({ children, disabled, displayValueOverride, eventTransform, form, formFieldName, helperText, isPassword = false, InputProps, onChange, type, variant = "outlined", ...rest }: FormTextFieldProps): React.ReactElement => { const isError = form.touched[formFieldName] && Boolean(form.errors[formFieldName]) // Conversion to a string primitive is necessary as formFieldName is an in // indexable type such as a string, number or enum. const fieldId = String(formFieldName) const Component = isPassword ? PasswordField : TextField const inputType = isPassword ? undefined : type return ( { if (typeof onChange !== "undefined") { onChange(e) } const event = e if (typeof eventTransform !== "undefined" && typeof event.target.value === "string") { event.target.value = eventTransform(e.target.value) } form.handleChange(event) }} type={inputType} value={displayValueOverride || form.values[formFieldName]} > {children} ) }