UNPKG

form-input-fields

Version:

A customizable form field components built with TypeScript

1,698 lines (1,434 loc) 53 kB
# Form Fields Components A collection of Material-UI form field components with Formik integration. More control in the progress of development. ## Installation ### Prerequisites Before installing the form-fields package, make sure you have the following peer dependencies installed in your project: - React 16.8.0 or later - React DOM 16.8.0 or later - Material-UI (MUI) 5.0.0 or later - Formik 2.0.0 or later - @mui/x-date-pickers 6.0.0 or later - dayjs 1.11.0 or later ### Using npm ```bash npm install form-fields @mui/material @emotion/react @emotion/styled formik @mui/x-date-pickers dayjs ``` ### Using yarn ```bash yarn add @your-org/form-fields @mui/material @emotion/react @emotion/styled formik @mui/x-date-pickers dayjs ``` ### Using pnpm ```bash pnpm add form-input-fields @mui/material @emotion/react @emotion/styled formik @mui/x-date-pickers dayjs ``` ### Peer Dependencies Make sure your project includes these peer dependencies: ```json { "devDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", "@mui/material": "^5.0.0", "@emotion/react": "^11.0.0", "@emotion/styled": "^11.0.0", "formik": "^2.0.0", "@mui/x-date-pickers": "^6.0.0", "dayjs": "^1.11.0" } } ``` ### TypeScript This package includes TypeScript type definitions. No additional type packages are needed. ### Browser Support The form fields support all modern browsers including: - Chrome (latest 2 versions) - Firefox (latest 2 versions) - Safari (latest 2 versions) - Edge (latest 2 versions) For Internet Explorer 11 support, you'll need to include polyfills. See [Browser Support](#browser-support) for more details. ### Next Steps After installation, you can import and use the components in your application: ```tsx import { FormTextField, FormDateField, FormMaskField, FormSwitch } from 'form-input-fields'; ``` ### Troubleshooting If you encounter any issues during installation, try the following: 1. Clear your package manager's cache: ```bash npm cache clean --force # or yarn cache clean # or pnpm store prune ``` 2. Delete `node_modules` and `package-lock.json` (or `yarn.lock`/`pnpm-lock.yaml`) 3. Reinstall dependencies: ```bash npm install # or yarn install # or pnpm install ``` If you're still experiencing issues, please reach me at vladimir.vorobiev@gmail.com with details about your environment and the error message you're seeing. ## Table of Contents - [FormTextField](#formtextfield) - [Features](#features) - [Basic Usage](#basic-usage) - [Props](#props) - [Examples](#examples) - [Basic Text Input](#basic-text-input) - [Text Field with Formik](#text-field-with-formik) - [Custom Validation](#custom-validation) - [FormDropDownField](#formdropdownfield) - [Features](#features-4) - [Basic Usage](#basic-usage-4) - [Props](#props-4) - [Examples](#examples-4) - [Basic Dropdown](#basic-dropdown) - [Dropdown with Default Selection](#dropdown-with-default-selection) - [Required Dropdown with Validation](#required-dropdown-with-validation) - [FormDateField](#formdatefield) - [Features](#features) - [Available Date Formats](#available-date-formats) - [Importing Date Constants](#importing-date-constants) - [Usage with Formik](#usage-with-formik) - [Props](#props) - [Examples](#examples) - [Basic Date Input](#basic-date-input) - [Date with Validation](#date-with-validation) - [Appointment Scheduler](#appointment-scheduler) - [Read-Only Date Display](#read-only-date-display) - [Custom Change Handler](#custom-change-handler) - [FormMaskField](#formmaskfield) - [Features](#features-1) - [Installation](#installation) - [Basic Usage](#basic-usage) - [Available Masks](#available-masks) - [Props](#props-1) - [Examples](#examples-1) - [Phone Number](#phone-number) - [Date Input](#date-input) - [Product Code (Uppercase)](#product-code-uppercase) - [Credit Card](#credit-card) - [Custom Change Handler](#custom-change-handler-1) - [Show Mask Pattern](#show-mask-pattern) - [Show Placeholder](#show-placeholder) - [Custom Mask with Validation](#custom-mask-with-validation) - [FormCheckboxField](#formcheckboxfield) - [Features](#features-2) - [Basic Usage](#basic-usage-1) - [Props](#props-2) - [Examples](#examples-2) - [Basic Checkbox](#basic-checkbox) - [Checkbox with Formik](#checkbox-with-formik) - [Custom Styled Checkbox](#custom-styled-checkbox) - [FormSwitch](#formswitch) - [Features](#features-5) - [Basic Usage](#basic-usage-5) - [Props](#props-5) - [Examples](#examples-5) - [Basic Switch](#basic-switch) - [Switch with Formik](#switch-with-formik) - [Custom Styled Switch](#custom-styled-switch) - [FormDateTextField](#formdatetextfield) - [Features](#features-3) - [Available Date Formats](#available-date-formats-1) - [Basic Usage](#basic-usage-3) - [Props](#props-3) - [Examples](#examples-3) - [Basic Date Text Input](#basic-date-text-input) - [Date Text Field with Formik](#date-text-field-with-formik) - [Custom Date Format](#custom-date-format) - [History](#history) --- ## FormTextField A versatile text input field component that integrates Material-UI's TextField with Formik form handling. ### Features - **Seamless Formik Integration**: Automatically handles form state, validation, and error messages - **Material-UI Styling**: Consistent look and feel with Material Design - **TypeScript Support**: Fully typed component with proper type definitions - **Flexible Props**: Supports all standard TextField props from Material-UI - **Error Handling**: Built-in error state management with Formik - **Responsive Design**: Works well across different screen sizes ### Basic Usage ```tsx import { Formik, Field } from 'formik'; import { FormTextField } from 'form-fields'; <Formik initialValues={{ username: '' }} onSubmit={(values) => console.log(values)} > <Field component={FormTextField} name="username" label="Username" placeholder="Enter your username" /> </Formik> ``` ### Props The FormTextField component accepts all props from `FormTextFieldProps`, `FieldProps` (Formik), and Material-UI's `TextFieldProps`. #### FormTextFieldProps Interface | Prop | Type | Default | Description | |------------|------------|---------|-----------------------------------------------| | `onChange` | `function` | - | Custom change handler that overrides Formik's | | `onBlur` | `function` | - | Custom blur handler that overrides Formik's | | `variant` | `'standard' | 'outlined' | 'filled'` | 'standard' | The variant of the MUI TextField. | #### Common Props (from FieldProps & TextFieldProps) | Prop | Type | Required | Description | |--------------|------------------|----------|-----------------------------------------------| | `name` | `string` | Yes | Field name in Formik values | | `label` | `string` | No | Field label | | `helperText` | `string` | No | Custom helper text | | `error` | `boolean` | No | Error state (auto-managed by Formik) | | `disabled` | `boolean` | No | Disabled state | | `required` | `boolean` | No | Required field indicator | | `type` | `string` | 'text' | Input type (text, email, password, etc.) | | Other | `TextFieldProps` | No | All Material-UI TextField props are supported | ### Examples #### Basic Text Input ```tsx <Field component={FormTextField} name="username" label="Username" placeholder="Enter your username" fullWidth margin="normal" variant="outlined" // <-- Example with outlined variant /> ``` #### Text Field with Formik ```tsx <Formik initialValues={{ email: '' }} validate={values => { const errors = {}; if (!values.email) { errors.email = 'Required'; } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) { errors.email = 'Invalid email address'; } return errors; }} onSubmit={(values) => console.log(values)} > {({ errors, touched }) => ( <Field component={FormTextField} name="email" label="Email" type="email" error={touched.email && Boolean(errors.email)} helperText={touched.email && errors.email} required /> )} </Formik> ``` #### Custom Validation ```tsx <Field component={FormTextField} name="password" label="Password" type="password" inputProps={{ minLength: 8, pattern: "(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}" }} helperText="Must contain at least 8 characters, including uppercase, lowercase, and numbers" required /> ``` --- ## FormDropDownField A customizable dropdown/select component that integrates Material-UI's Select with Formik form handling. ### Features - **Seamless Formik Integration**: Automatically handles form state, validation, and error messages - **Material-UI Styling**: Consistent look and feel with Material Design - **TypeScript Support**: Fully typed component with proper type definitions - **Flexible Data Binding**: Works with array of objects with `id` and `description` properties - **Optional Default Selection**: Add a default "Select" option with customizable text - **Form Validation**: Built-in error state management with Formik - **Responsive Design**: Works well across different screen sizes ### Basic Usage ```tsx import { Formik, Field } from 'formik'; import { FormDropDownField } from 'form-input-fields'; const items = [ { id: '1', description: 'Option 1' }, { id: '2', description: 'Option 2' }, { id: '3', description: 'Option 3' }, ]; <Formik initialValues={{ category: '' }} onSubmit={(values) => console.log(values)} > <Field component={FormDropDownField} name="category" label="Category" items={items} addInputSelect={true} /> </Formik> ``` ### Props The FormDropDownField component accepts all props from `FormDropDownFieldProps`, `FieldProps` (Formik), and Material-UI's `TextFieldProps` (with some exceptions). #### FormDropDownFieldProps Interface | Prop | Type | Default | Description | |------|------|---------|-------------| | `items` | `Array<{ id: string | number; description: string }>` | `[]` | Array of items to display in the dropdown | | `addInputSelect` | `boolean` | `false` | Whether to show a default "Select" option as the first item | | `selectText` | `string` | `'Select'` | Text to display for the default "Select" option | | `required` | `boolean` | `false` | Whether the field is required | | `disabled` | `boolean` | `false` | Whether the field is disabled | | `className` | `string` | - | Custom class name for the root element | | `helperText` | `string` | - | Helper text to display below the field | | `error` | `boolean` | - | Error state of the field (overrides Formik error state) | | `onChange` | `(value: any) => void` | - | Custom change handler | | `onBlur` | `(event: React.FocusEvent<HTMLInputElement>) => void` | - | Custom blur handler | | `variant` | `'standard' | 'outlined' | 'filled'` | 'standard' | The variant of the MUI TextField. | ### Examples #### Basic Dropdown ```tsx const items = [ { id: 'us', description: 'United States' }, { id: 'ca', description: 'Canada' }, { id: 'uk', description: 'United Kingdom' }, ]; <Field component={FormDropDownField} name="country" label="Country" items={items} fullWidth variant="outlined" // <-- Example with outlined variant /> ``` #### Dropdown with Default Selection ```tsx <Field component={FormDropDownField} name="category" label="Category" items={categories} addInputSelect={true} selectText="Select a category" helperText="Please select a category from the list" /> ``` #### Required Dropdown with Validation ```tsx <Formik initialValues={{ department: '' }} validationSchema={Yup.object({ department: Yup.string().required('Department is required'), })} onSubmit={(values) => console.log(values)} > {({ errors, touched }) => ( <Form> <Field component={FormDropDownField} name="department" label="Department" items={departments} addInputSelect={true} required error={touched.department && Boolean(errors.department)} helperText={touched.department && errors.department} /> <Button type="submit" variant="contained" color="primary"> Submit </Button> </Form> )} </Formik> ``` --- ## FormDateField A date input field component with Material-UI and Formik integration, powered by MUI X Date Pickers. ### Features - **Material-UI Integration**: Consistent styling with other form components - **Formik Integration**: Seamless form state management with error handling - **Day.js Support**: Lightweight date library for date manipulation - **Custom Date Formatting**: Flexible date display formats - **Date Validation**: Built-in min/max date validation - **Read-Only Support**: Can be configured as read-only - **TypeScript Support**: Full type safety with exported interfaces - **Helper Text Display**: Show date format or custom helper text - **Today Button**: Optional today button in date picker ### Available Date Formats The component uses predefined date format constants from `date.ts`: #### FORM_DATE_FORMAT ```typescript export const FORM_DATE_FORMAT = { short: "YYYY-MM-DD", long: "MM/DD/YYYY hh:mm A", custom: "DD MMMM YYYY hh:mm A", }; ``` #### DATE_PICKER_DATE_FORMAT ```typescript export const DATE_PICKER_DATE_FORMAT = { short: "DD/MM/YYYY", }; ``` #### DATE_PICKER_MONTH_YEAR_FORMAT ```typescript export const DATE_PICKER_MONTH_YEAR_FORMAT = { short: "MM/YYYY", long: "MMMM YYYY", }; ``` ### Importing Date Constants ```tsx import { FORM_DATE_FORMAT, DATE_PICKER_DATE_FORMAT, DATE_PICKER_MONTH_YEAR_FORMAT } from "form-input-mask-field/date"; // Use predefined formats <Field component={FormDateField} name="birthDate" format={FORM_DATE_FORMAT.short} // 'YYYY-MM-DD' /> // Or use custom format <Field component={FormDateField} name="eventDate" format="DD/MM/YYYY HH:mm" // Custom format /> ``` ### Usage with Formik ```tsx import { Formik, Field } from "formik"; import { FormDateField, FormDateFieldProps } from "form-input-mask-field"; import { FORM_DATE_FORMAT } from "form-input-mask-field/date"; import dayjs from "dayjs"; <Formik initialValues={{ birthDate: null, appointmentDate: null }} onSubmit={(values) => console.log(values)} > {/* Basic usage */} <Field component={FormDateField} name="birthDate" label="Birth Date" format={FORM_DATE_FORMAT.short} /> {/* Advanced usage with validation */} <Field component={FormDateField} name="appointmentDate" label="Appointment Date" format="DD/MM/YYYY" minDate={dayjs()} disablePast={true} showTodayButton={true} showDateFormat={true} onChange={(value, context) => { console.log("Selected date:", value); console.log("Formatted value:", context.formattedValue); }} /> </Formik>; ``` ### Props The FormDateField component accepts all props from `FormDateFieldProps`, `FieldProps`, and `TextFieldProps`. #### FormDateFieldProps Interface | Prop | Type | Default | Description | | ----------------- | ---------- | ------------------------ | --------------------------------------------- | | `format` | `string` | `FORM_DATE_FORMAT.short` | Date format string using dayjs format tokens | | `minDate` | `Dayjs` | - | Minimum selectable date | | `maxDate` | `Dayjs` | - | Maximum selectable date | | `disablePast` | `boolean` | `false` | Disable past dates | | `disableFuture` | `boolean` | `false` | Disable future dates | | `showTodayButton` | `boolean` | `false` | Show today button in the picker | | `readOnly` | `boolean` | `false` | Make the field read-only | | `showDateFormat` | `boolean` | `false` | Show the date format as helper text | | `onChange` | `function` | - | Custom change handler with additional context | #### Common Props (from FieldProps & TextFieldProps) | Prop | Type | Required | Description | | ------------ | ---------------- | -------- | --------------------------------------------- | | `name` | `string` | Yes | Field name in Formik values | | `label` | `string` | No | Field label | | `helperText` | `string` | No | Custom helper text | | `error` | `boolean` | No | Error state | | `disabled` | `boolean` | No | Disabled state | | Other | `TextFieldProps` | No | All Material-UI TextField props are supported | ### Examples #### Basic Date Input ```tsx <Field component={FormDateField} name="birthDate" label="Birth Date" format="DD/MM/YYYY" /> ``` #### Date with Validation ```tsx <Field component={FormDateField} name="startDate" label="Start Date" minDate={dayjs()} disablePast={true} showDateFormat={true} helperText="Select a future date" /> ``` #### Appointment Scheduler ```tsx <Field component={FormDateField} name="appointmentDate" label="Appointment Date" format="DD MMMM YYYY" minDate={dayjs().add(1, "day")} maxDate={dayjs().add(3, "month")} showTodayButton={true} showDateFormat={true} /> ``` #### Read-Only Date Display ```tsx <Field component={FormDateField} name="createdDate" label="Created Date" format="DD/MM/YYYY HH:mm" readOnly={true} /> ``` #### Custom Change Handler ```tsx <Field component={FormDateField} name="eventDate" label="Event Date" format="YYYY-MM-DD" onChange={(value, context) => { console.log("Selected date:", value); console.log("Formatted value:", context.formattedValue); console.log("Validation error:", context.validationError); // Custom logic here if (value && value.day() === 0) { alert("Events cannot be scheduled on Sundays"); } }} /> ``` #### Date Range (Start/End Dates) ```tsx <Field component={FormDateField} name="startDate" label="Start Date" format="DD/MM/YYYY" maxDate={values.endDate ? dayjs(values.endDate) : undefined} /> <Field component={FormDateField} name="endDate" label="End Date" format="DD/MM/YYYY" minDate={values.startDate ? dayjs(values.startDate) : undefined} /> ``` ## FormCheckboxField A customizable checkbox component with Material-UI and Formik integration, providing consistent styling and behavior across your application. ### Features - **Material-UI Integration**: Consistent styling with Material-UI's design system - **Formik Integration**: Seamless form state management with error handling - **Custom Styling**: Easy customization through Material-UI's styling system - **TypeScript Support**: Full type safety with exported interfaces - **Accessibility**: Built with accessibility in mind, following WAI-ARIA guidelines - **Responsive Design**: Works well on all screen sizes ### Basic Usage ```tsx import { Formik, Field } from 'formik'; import { FormCheckboxField } from 'form-input-mask-field'; // Basic usage <FormCheckboxField id="terms" label="I agree to the terms and conditions" checked={false} onChange={(e) => console.log('Checked:', e.target.checked)} /> // With Formik <Formik initialValues={{ termsAccepted: false }} onSubmit={(values) => console.log(values)} > {({ values }) => ( <Field name="termsAccepted" component={({ field, form }) => ( <FormCheckboxField {...field} label="I agree to the terms and conditions" checked={field.value} onChange={(e) => { form.setFieldValue(field.name, e.target.checked); }} /> )} /> )} </Formik> ``` ### Props The FormCheckboxField component accepts all props from `FormCheckboxFieldProps` and Material-UI's `CheckboxProps`. #### FormCheckboxFieldProps Interface | Prop | Type | Default | Description | | -------------- | --------- | ------- | ------------------------------------------------ | | `id` | `string` | - | Unique identifier for the checkbox | | `label` | `string` | - | Label text displayed next to the checkbox | | `checked` | `boolean` | `false` | Whether the checkbox is checked | | `onChange` | `function`| - | Callback when checkbox state changes | | `disabled` | `boolean` | `false` | Disable the checkbox | | `required` | `boolean` | `false` | Mark the field as required | | `color` | `string` | 'primary'| Color of the checkbox when checked | | `size` | `string` | 'medium'| Size of the checkbox ('small' or 'medium') | | `labelPlacement`| `string` | 'end' | Position of the label ('end', 'start', 'top', 'bottom') | ### Examples #### Basic Checkbox ```tsx <FormCheckboxField id="notifications" label="Enable email notifications" checked={notificationsEnabled} onChange={(e) => setNotificationsEnabled(e.target.checked)} color="secondary" /> ``` #### Checkbox with Formik ```tsx <Formik initialValues={{ termsAccepted: false, newsletter: true, notifications: false }} onSubmit={(values) => console.log('Form values:', values)} > {({ values }) => ( <Form> <Field name="termsAccepted" component={({ field, form }) => ( <FormCheckboxField {...field} label="I agree to the terms and conditions" checked={field.value} onChange={(e) => form.setFieldValue(field.name, e.target.checked)} required /> )} /> <Field name="newsletter" component={({ field, form }) => ( <FormCheckboxField {...field} label="Subscribe to newsletter" checked={field.value} onChange={(e) => form.setFieldValue(field.name, e.target.checked)} color="secondary" /> )} /> <Button type="submit" variant="contained" color="primary"> Submit </Button> </Form> )} </Formik> ``` #### Custom Styled Checkbox ```tsx import { makeStyles } from '@mui/styles'; const useStyles = makeStyles((theme) => ({ root: { margin: theme.spacing(1), }, labelRoot: { color: theme.palette.primary.main, fontWeight: 500, }, })); function CustomCheckbox() { const classes = useStyles(); return ( <FormCheckboxField id="custom-checkbox" label="Custom Styled Checkbox" checked={false} onChange={() => {}} classes={{ root: classes.root, label: classes.labelRoot, }} color="primary" /> ); } ``` ## FormSwitch A customizable switch component with Material-UI and Formik integration, providing consistent styling and behavior for boolean inputs across your application. ### Features - **Material-UI Integration**: Consistent styling with Material-UI's design system - **Formik Integration**: Seamless form state management with error handling - **Flexible Label Placement**: Support for different label positions - **TypeScript Support**: Full type safety with exported interfaces - **Accessibility**: Built with accessibility in mind, following WAI-ARIA guidelines - **Error Handling**: Built-in error state management with Formik - **Responsive Design**: Works well on all screen sizes ### Basic Usage ```tsx import { Formik, Field } from 'formik'; import { FormSwitch } from 'form-input-fields'; // Basic usage <FormSwitch label="Enable Notifications" checked={notificationsEnabled} onChange={(e, checked) => setNotificationsEnabled(checked)} /> // With Formik <Formik initialValues={{ notifications: false }} onSubmit={(values) => console.log(values)} > <Field component={FormSwitch} name="notifications" label="Enable Notifications" helperText="Receive email notifications" /> </Formik> ``` ### Props The FormSwitch component accepts all props from `FormSwitchProps`, `FieldProps` (Formik), and Material-UI's `SwitchProps`. #### FormSwitchProps Interface | Prop | Type | Default | Description | | ---------------- | ---------- | ------- | ------------------------------------------------ | | `label` | `string` | - | Label text displayed next to the switch | | `labelPlacement` | `string` | 'end' | Position of label ('top', 'start', 'bottom', 'end') | | `color` | `string` | 'primary'| Switch color ('primary', 'secondary', 'error', 'info', 'success', 'warning', 'default') | | `size` | `string` | 'medium'| Switch size ('small' or 'medium') | | `disabled` | `boolean` | `false` | Disable the switch | | `required` | `boolean` | `false` | Mark the field as required | | `onChange` | `function` | - | Custom change handler with context data | | `onBlur` | `function` | - | Custom blur handler | | `helperText` | `string` | - | Helper text to display below the switch | | `error` | `boolean` | `false` | Error state of the switch | | `className` | `string` | - | Custom class name for the root element | #### Common Props (from FieldProps & SwitchProps) | Prop | Type | Required | Description | |--------------|------------------|----------|-----------------------------------------------| | `name` | `string` | Yes | Field name in Formik values | | `label` | `string` | No | Field label | | `helperText` | `string` | No | Custom helper text | | `error` | `boolean` | No | Error state (auto-managed by Formik) | | `disabled` | `boolean` | No | Disabled state | | `required` | `boolean` | No | Required field indicator | | Other | `SwitchProps` | No | All Material-UI Switch props are supported | ### Examples #### Basic Switch ```tsx <FormSwitch label="Enable Dark Mode" checked={darkModeEnabled} onChange={(e, checked) => setDarkModeEnabled(checked)} color="secondary" size="small" /> ``` #### Switch with Formik ```tsx <Formik initialValues={{ notifications: false, darkMode: true, autoSave: false }} onSubmit={(values) => console.log('Form values:', values)} > <Form> <Field component={FormSwitch} name="notifications" label="Enable Notifications" helperText="Receive email notifications" color="primary" /> <Field component={FormSwitch} name="darkMode" label="Dark Mode" helperText="Use dark theme" color="secondary" labelPlacement="start" /> <Field component={FormSwitch} name="autoSave" label="Auto Save" helperText="Automatically save changes" color="success" size="small" /> <Button type="submit" variant="contained" color="primary"> Save Settings </Button> </Form> </Formik> ``` #### Custom Styled Switch ```tsx <FormSwitch label="Custom Styled Switch" checked={false} onChange={(e, checked) => console.log('Switch toggled:', checked)} className="custom-switch-class" color="warning" labelPlacement="top" helperText="This is a custom styled switch" /> ``` #### Switch with Custom Change Handler ```tsx <Field component={FormSwitch} name="advancedMode" label="Advanced Mode" onChange={(e, checked, context) => { console.log('Field name:', context.fieldName); console.log('Formik value:', context.formikValue); // Custom logic here }} helperText="Enable advanced features" /> ``` #### Switch with Validation ```tsx <Formik initialValues={{ termsAccepted: false }} validate={(values) => { const errors = {}; if (!values.termsAccepted) { errors.termsAccepted = 'You must accept the terms to continue'; } return errors; }} onSubmit={(values) => console.log(values)} > <Form> <Field component={FormSwitch} name="termsAccepted" label="I accept the terms and conditions" helperText="Please read and accept the terms" required /> <Button type="submit" variant="contained" color="primary"> Continue </Button> </Form> </Formik> ``` ## FormDateTextField A versatile date input field component that provides a text-based date picker with Formik integration and Material-UI styling. ### Features - **Formik Integration**: Seamlessly works with Formik for form state management - **Material-UI Styling**: Consistent look and feel with Material Design - **Flexible Date Formatting**: Supports custom date formats using day.js - **TypeScript Support**: Fully typed component with proper type definitions - **Responsive Design**: Works well across different screen sizes - **Accessibility**: Built with accessibility in mind ### Available Date Formats The component uses predefined date format constants from `date.ts`: #### FORM_DATE_FORMAT ```typescript export const FORM_DATE_FORMAT = { short: "YYYY-MM-DD", long: "MM/DD/YYYY hh:mm A", custom: "DD MMMM YYYY hh:mm A" }; ``` #### DATE_PICKER_DATE_FORMAT ```typescript export const DATE_PICKER_DATE_FORMAT = { short: "DD/MM/YYYY" }; ``` #### DATE_PICKER_MONTH_YEAR_FORMAT ```typescript export const DATE_PICKER_MONTH_YEAR_FORMAT = { short: "MM/YYYY", long: "MMMM YYYY" }; ``` ### Basic Usage ```tsx import { Formik, Field } from 'formik'; import { FormDateTextField } from 'form-fields'; <Formik initialValues={{ eventDate: '' }} onSubmit={(values) => console.log(values)} > <Field component={FormDateTextField} name="eventDate" label="Event Date" format="MM/DD/YYYY" /> </Formik> ``` ### Props The FormDateTextField component accepts all props from `FormDateTextFieldProps`, `FieldProps` (Formik), and Material-UI's `TextFieldProps` (with some exclusions). #### FormDateTextFieldProps Interface | Prop | Type | Default | Description | |------|------|---------|-------------| | `format` | `string` | `FORM_DATE_FORMAT.long` | Date format string using day.js tokens | | `required` | `boolean` | `false` | Whether the field is required | | `disabled` | `boolean` | `false` | Whether the field is disabled | | `className` | `string` | - | Custom class name for the root element | | `helperText` | `string` | - | Helper text to display below the field | | `error` | `boolean` | - | Error state of the field | | `onChange` | `(value: Dayjs \| null) => void` | - | Custom change handler | | `onBlur` | `(event: React.FocusEvent<HTMLInputElement>) => void` | - | Custom blur handler | #### Common Props (from FieldProps & TextFieldProps) | Prop | Type | Required | Description | |------|------|----------|-------------| | `name` | `string` | Yes | Field name in Formik values | | `label` | `string` | No | Label for the input field | | `placeholder` | `string` | No | Placeholder text | | `fullWidth` | `boolean` | No | If true, the input will take up the full width of its container | | `margin` | `'none' \| 'dense' \| 'normal'` | No | If 'dense' or 'normal', will adjust vertical spacing | | `size` | `'small' \| 'medium'` | No | The size of the text field | ### Examples #### Basic Date Text Input ```tsx <FormDateTextField name="birthDate" label="Birth Date" format="YYYY-MM-DD" helperText="Enter your date of birth" required /> ``` #### Date Text Field with Formik ```tsx import { Formik, Form, Field } from 'formik'; import { FormDateTextField, FormTextField } from 'form-fields'; import { Button } from '@mui/material'; const EventForm = () => ( <Formik initialValues={{ eventName: '', eventDate: '', }} onSubmit={(values) => { console.log('Form submitted:', values); }} > {({ isSubmitting }) => ( <Form> <Field name="eventName" label="Event Name" component={FormTextField} fullWidth margin="normal" /> <Field component={FormDateTextField} name="eventDate" label="Event Date" format="MM/DD/YYYY" required helperText="Select the event date" margin="normal" /> <Button type="submit" variant="contained" color="primary" disabled={isSubmitting} > Submit </Button> </Form> )} </Formik> ); ``` #### Custom Date Format ```tsx <FormDateTextField name="appointmentTime" label="Appointment Time" format="dddd, MMMM D, YYYY h:mm A" helperText="Example: Monday, January 1, 2023 2:30 PM" required /> ``` #### Disabled State ```tsx <FormDateTextField name="purchaseDate" label="Purchase Date" value="2023-05-15" disabled helperText="This field cannot be modified" /> ``` #### With Error State ```tsx <FormDateTextField name="expiryDate" label="Expiry Date" error={!!errors.expiryDate && touched.expiryDate} helperText={touched.expiryDate && errors.expiryDate} format="MM/DD/YYYY" required /> ``` ## FormMaskField A flexible form field component with advanced text masking capabilities. ### Features - **Material-UI Integration**: Consistent styling with other form components - **Formik Integration**: Seamless form state management - **Flexible Masking**: Pattern-based input masking with multiple character types - **Uppercase Conversion**: Automatic text transformation - **TypeScript Support**: Full type safety and IntelliSense - **Clean Value Option**: Return masked or unmasked values to form state ### Usage with Formik ```tsx import { Formik, Field } from "formik"; import { FormMaskField } from "form-input-mask-field"; <Formik initialValues={{ phoneNumber: "", gameCode: "" }} onSubmit={(values) => console.log(values)} > <Field component={FormMaskField} name="phoneNumber" label="Phone Number" mask="(999) 999-9999" placeholder="Enter phone number" /> <Field component={FormMaskField} name="gameCode" label="Game Code" mask="AAAAA" toUpperCase={true} returnCleanValue={true} /> </Formik>; ``` ### Mask Pattern Characters | Character | Description | Example | | --------- | ---------------------------- | ------------------------ | | `9` | Digit (0-9) | `999-99-9999` for SSN | | `A` | Letter (a-z, A-Z) | `AAA` for country code | | `*` | Alphanumeric (a-z, A-Z, 0-9) | `***-***` for mixed code | | `a` | Lowercase letter (a-z) | `aaa` for lowercase only | | `Z` | Uppercase letter (A-Z) | `ZZZ` for uppercase only | | `#` | Hexadecimal (0-9, A-F, a-f) | `######` for hex color | | Any other | Literal character | `-`, `(`, `)`, `/`, etc. | ### Props | Prop | Type | Default | Description | | ------------------ | ---------- | ------- | -------------------------------------------------------------- | | `mask` | `string` | - | Mask pattern using the characters above | | `placeholderChar` | `string` | `'_'` | Character shown in placeholder for mask positions | | `toUpperCase` | `boolean` | `false` | Convert input to uppercase automatically | | `returnCleanValue` | `boolean` | `false` | Return unmasked value to Formik (true) or masked value (false) | | `showMaskPattern` | `boolean` | `false` | Show the mask pattern as helper text below the input field | | `showPlaceholder` | `boolean` | `false` | Show placeholder text with mask pattern in the input field | | `onChange` | `function` | - | Custom change handler with masked, clean, and raw values | | `variant` | `'standard' | 'outlined' | 'filled'` | 'standard' | The variant of the MUI TextField. | Plus all standard Material-UI TextField props and Formik FieldProps. ### Examples #### Phone Number ```tsx <Field component={FormMaskField} name="phone" label="Phone Number" mask="(999) 999-9999" placeholder="(555) 123-4567" variant="outlined" // <-- Example with outlined variant /> ``` #### Date Input ```tsx <Field component={FormMaskField} name="date" label="Date" mask="99/99/9999" placeholder="MM/DD/YYYY" /> ``` #### Product Code (Uppercase) ```tsx <Field component={FormMaskField} name="productCode" label="Product Code" mask="AAA-999-AAA" toUpperCase={true} returnCleanValue={true} /> ``` #### Credit Card ```tsx <Field component={FormMaskField} name="creditCard" label="Credit Card" mask="9999 9999 9999 9999" placeholder="1234 5678 9012 3456" /> ``` #### Custom Change Handler ```tsx <Field component={FormMaskField} name="customField" label="Custom Field" mask="999-AAA" onChange={(event) => { console.log("Masked value:", event.target.value); console.log("Clean value:", event.target.cleanValue); console.log("Raw input:", event.target.rawValue); }} variant="outlined" // <-- Example with outlined variant /> ``` #### Show Mask Pattern ```tsx <Field component={FormMaskField} name="gameCode" label="Game Code" mask="AAA-999" showMaskPattern={true} toUpperCase={true} /> // This will show "Pattern: AAA-999" as helper text below the input ``` #### Show Placeholder ```tsx <Field component={FormMaskField} name="phoneNumber" label="Phone Number" mask="(999) 999-9999" showPlaceholder={true} /> // This will show "(___) ___-____" as placeholder text in the input field ``` ## Complete Example Application Here's a comprehensive example showing how to build a complete form application using FormMaskField with Material-UI and Formik: ### App.tsx ```tsx import React from "react"; import { Formik, Form, Field, FormikHelpers, FormikErrors } from "formik"; import Container from "@mui/material/Container"; import Typography from "@mui/material/Typography"; import Box from "@mui/material/Box"; import Button from "@mui/material/Button"; import { Grid } from "@mui/material"; import Paper from "@mui/material/Paper"; import Alert from "@mui/material/Alert"; import { ThemeProvider, createTheme } from "@mui/material/styles"; import CssBaseline from "@mui/material/CssBaseline"; import { FormMaskField } from "form-input-mask-field"; import "./App.css"; interface FormValues { phone: string; date: string; creditCard: string; licensePlate: string; hexColor: string; customCode: string; socialSecurity: string; postalCode: string; } interface FormFieldEvent extends Omit<React.ChangeEvent<HTMLInputElement>, "target"> { target: HTMLInputElement & { value: string; cleanValue: string; rawValue: string; name: string; }; } // Create a Material-UI theme const theme = createTheme({ palette: { primary: { main: "#1976d2", }, secondary: { main: "#dc004e", }, }, }); // Validation schema const validateForm = (values: FormValues): FormikErrors<FormValues> => { const errors: Partial<FormValues> = {}; if (!values.phone) { errors.phone = "Phone number is required"; } else if (values.phone.replace(/\D/g, "").length < 10) { errors.phone = "Phone number must be 10 digits"; } if (!values.date) { errors.date = "Date is required"; } if (!values.creditCard) { errors.creditCard = "Credit card is required"; } else if (values.creditCard.replace(/\D/g, "").length < 16) { errors.creditCard = "Credit card must be 16 digits"; } if (!values.licensePlate) { errors.licensePlate = "License plate is required"; } return errors; }; function App() { const initialValues: FormValues = { phone: "", date: "", creditCard: "", licensePlate: "", hexColor: "", customCode: "", socialSecurity: "", postalCode: "", }; const handleSubmit = ( values: FormValues, { setSubmitting }: FormikHelpers<FormValues> ) => { console.log("Form Values:", values); setTimeout(() => { alert("Form submitted! Check console for values."); setSubmitting(false); }, 400); }; const handleCustomChange = (fieldName: keyof FormValues) => (event: FormFieldEvent) => { console.log(`${fieldName} changed:`, { masked: event.target.value, clean: event.target.cleanValue, raw: event.target.rawValue, }); return event; }; return ( <ThemeProvider theme={theme}> <CssBaseline /> <Container maxWidth="lg" sx={{ py: 4 }}> <Typography variant="h3" component="h1" gutterBottom align="center"> FormMaskField Demo </Typography> <Typography variant="subtitle1" align="center" color="text.secondary" paragraph > A comprehensive example showcasing the FormMaskField component with various mask patterns and configurations </Typography> <Formik initialValues={initialValues} validate={validateForm} onSubmit={handleSubmit} > {({ values, isSubmitting, errors, touched }) => ( <Form> <Grid container spacing={3}> {/* Basic Masks Section */} <Grid> <Paper elevation={2} sx={{ p: 3 }}> <Typography variant="h5" gutterBottom> Basic Input Masks </Typography> <Grid container spacing={2}> <Grid> <Field name="phone" component={FormMaskField} label="Phone Number" mask="(999) 999-9999" showMaskPattern={true} showPlaceholder={true} helperText="US phone number format" onChange={handleCustomChange("phone")} variant="outlined" // <-- Example with outlined variant /> </Grid> <Grid> <Field name="date" component={FormMaskField} label="Date" mask="99/99/9999" showMaskPattern={true} showPlaceholder={true} helperText="MM/DD/YYYY format" /> </Grid> <Grid> <Field name="socialSecurity" component={FormMaskField} label="Social Security Number" mask="999-99-9999" showMaskPattern={true} showPlaceholder={true} returnCleanValue={true} helperText="Clean value returned (no dashes)" /> </Grid> <Grid> <Field name="postalCode" component={FormMaskField} label="ZIP Code" mask="99999-9999" showMaskPattern={true} showPlaceholder={true} helperText="US ZIP+4 format" /> </Grid> </Grid> </Paper> </Grid> {/* Advanced Masks Section */} <Grid> <Paper elevation={2} sx={{ p: 3 }}> <Typography variant="h5" gutterBottom> Advanced Input Masks </Typography> <Grid container spacing={2}> <Grid> <Field name="creditCard" component={FormMaskField} label="Credit Card Number" mask="9999-9999-9999-9999" showMaskPattern={true} showPlaceholder={true} helperText="16-digit credit card number" onChange={handleCustomChange("creditCard")} /> </Grid> <Grid> <Field name="licensePlate" component={FormMaskField} label="License Plate" mask="AAA-999" toUpperCase={true} showMaskPattern={true} showPlaceholder={true} helperText="3 letters + 3 numbers (auto uppercase)" onChange={handleCustomChange("licensePlate")} /> </Grid> <Grid> <Field name="hexColor" component={FormMaskField} label="Hex Color Code" mask="#######" toUpperCase={true} showMaskPattern={true} showPlaceholder={true} placeholderChar="0" helperText="6-digit hex color code" /> </Grid> <Grid> <Field name="customCode" component={FormMaskField} label="Custom Code" mask="**-999-AA" toUpperCase={true} returnCleanValue={true} showMaskPattern={true} showPlaceholder={true} helperText="Alphanumeric + digits + letters" onChange={handleCustomChange("customCode")} /> </Grid> </Grid> </Paper> </Grid> {/* Current Values Display */} <Grid> <Paper elevation={2} sx={{ p: 3 }}> <Typography variant="h5" gutterBottom> Current Form Values </Typography> <Box sx={{ mt: 2 }}> <Typography variant="body2" component="pre" sx={{ backgroundColor: "#f5f5f5", p: 2, borderRadius: 1, overflow: "auto", fontSize: "0.875rem", }} > {JSON.stringify(values, null, 2)} </Typography> </Box> </Paper> </Grid> {/* Form Errors Display */} {Object.keys(errors).length > 0 && Object.keys(touched).length > 0 && ( <Grid> <Alert severity="error"> <Typography variant="h6" gutterBottom> Form Validation Errors: </Typography> <ul> {Object.entries(errors).map( ([field, error]) => touched[field] && ( <li key={field}> <strong>{field}:</strong> {error} </li> ) )} </ul> </Alert> </Grid> )} {/* Submit Button */} <Grid> <Box sx={{ display: "flex", justifyContent: "center", mt: 2 }} > <Button type="submit" variant