From 015bf636a5362a629cfa4082a570b81174f8c3a6 Mon Sep 17 00:00:00 2001 From: Shrey Purohit <91727034+ShreyPurohit@users.noreply.github.com> Date: Thu, 5 Sep 2024 20:43:11 +0530 Subject: [PATCH] Add files via upload --- README.md | 162 +++++++++++++-------------------- package-lock.json | 4 +- package.json | 5 +- src/assets/interfaces.ts | 29 +++++- src/components/DynamicForm.tsx | 135 +++++++++++++++------------ src/index.ts | 4 +- 6 files changed, 172 insertions(+), 167 deletions(-) diff --git a/README.md b/README.md index 104a71b..72a0f29 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Dynamic Form Component +# Customized Dynamic Form Component -A highly customizable and easy-to-use dynamic form component built with React, TypeScript, and React Hook Form. This component allows you to generate a form dynamically based on an array of field configurations, making it suitable for various use cases. Compatible with Tailwind CSS And Bootstrap. +This package provides a fully customizable dynamic form component for React, built to support various input types and customizable layouts, including support for both Tailwind and Bootstrap. Users can pass an array of form fields and control various form behaviors, CSS classes, validation rules, and form submission handlers. ## Output ![Dynamic Form Output](https://github.com/user-attachments/assets/c7dee211-25c4-4d89-bb80-f06a0618a773) @@ -13,8 +13,6 @@ npm install dynamic-form-component ## Peer Dependencies Ensure you have the following peer dependencies installed: -* `react` -* `react-dom` * `react-hook-form` * `react-icons` @@ -23,10 +21,18 @@ You can install them with: npm install react react-dom react-hook-form react-icons ``` +## Features +* __Flexible Input Types:__ Supports `text`, `number`, `email`, `password`, `checkbox`, `radio`, `select`, and `textarea` fields. +* __Customizable Layouts:__ Customize CSS classes for each field component (wrapper, label, input, icon, error). +* __Icons:__ Supports React icons or any custom icons. +* __Validation:__ Leverage React Hook Form’s validation for comprehensive form validation rules. +* __Custom Buttons:__ Fully customizable submit or action buttons. +* __CSS Framework Support:__ Compatible with both `Tailwind CSS` and `Bootstrap` + ## Usage ### Importing The Component ```bash -import DynamicForm, { IFormField } from 'dynamic-form-component'; +import DynamicForm, { IFormField, ISubmitButtonProps } from 'dynamic-form-component'; ``` ### Example Usage @@ -45,18 +51,20 @@ export default { Below is an example of how to use the `DynamicForm` component in your react project: ```js -import DynamicForm, { IFormField } from 'dynamic-form-component'; -import { AiOutlineLock, AiOutlineMail, AiOutlineNumber, AiOutlineUser } from 'react-icons/ai'; +import { AiOutlineUser } from 'react-icons/ai'; +import DynamicForm, { IFormField, IButtonProps } from 'your-dynamic-form-package'; -const App = () => { +function App() { const formFields: IFormField[] = [ { id: 'name', - errorId: 'nameErr', label: 'Name', + error: { + id: "nameErr", + css: "text-danger" // Add Bootstrap Or Tailwind CSS here + }, type: 'text', placeholder: 'Enter your name', - required: true, validation: { required: 'Name is required', maxLength: { @@ -64,107 +72,61 @@ const App = () => { message: 'Name must be less than 20 characters', }, }, - icon: - }, - { - id: 'email', - errorId: 'emailErr', - label: 'Email', - type: 'email', - placeholder: 'Enter your email', - validation: { - required: 'Email is required', - pattern: { - value: /^\S+@\S+$/i, - message: 'Enter a valid email address', - }, - }, - icon: - }, - { - id: 'age', - errorId: 'ageError', - label: 'Age', - type: 'number', - placeholder: 'Enter your age', - validation: { - min: { - value: 18, - message: 'You must be at least 18 years old', - }, - }, - icon: - }, - { - id: 'password', - errorId: 'passwordErr', - label: 'Password', - type: 'password', - placeholder: 'Enter your Password', - validation: { - required: 'Password is required', - }, - icon: - }, - { - id: 'hobbies', - errorId: 'subscriptionErr', - label: 'Hobbies', - type: 'checkbox', - options: [ - { value: 'reading', label: "Reading" }, - { value: 'sports', label: "Sports" }, - { value: 'music', label: "Music" }, - { value: 'travelling', label: "Travelling" }, - ], - validation: {}, - }, - { - id: 'gender', - errorId: 'genderErr', - label: 'Gender', - type: 'select', - options: [ - { value: 'male', label: 'Male' }, - { value: 'female', label: 'Female' }, - { value: 'other', label: 'Other' }, - ], - validation: { - required: 'Gender is required', + icon: , + css: { // Add Bootstrap Or Tailwind CSS here + wrapper: 'flex items-center p-1 border', + label: 'block text-gray-700 text-lg font-bold mb-2', + input: 'rounded w-full py-2 px-3 text-gray-700', + icon: 'ml-2', + error: 'text-red-500 text-sm', }, }, + // Add more form fields here ]; - // Form Submission Function - const handleFormSubmit = (data: Record) => { - console.log('Form Data:', data); + const button: IButtonProps = { + label: 'Submit', + type: 'submit', + css: 'btn btn-primary', //Css For Your Button + disabled: false,, + onClick?: () => {console.log("Form Button Clicked")} + }; + + const handleSubmit = (data: Record) => { + console.log('Form data:', data); }; - // Return Based On Type Of CSS ('Tailwind CSS' || 'Bootstrap') - return ( -
-

Dynamic Form Example

- {/* If You Are Using Bootstrap CSS Then */} - - {/* If You Are Using Tailwind CSS Then */} - -
- ) + return ; } -export default App +export default App; ``` ### Field Configuration -* id: Unique identifier for the field. -* errorId: Identifier for displaying error messages. -* label: Label for the form field. -* type: Type of the field (text, number, email, password, checkbox, select). -* options: (Optional) Array of options for select and checkbox fields. -* placeholder: (Optional) Placeholder text for the input. -* required: (Optional) Boolean indicating if the field is required. -* validation: (Optional) Validation rules based on React Hook Form's RegisterOptions. -* icon: (Optional) Icon component to display alongside the input. +__`Form Input Fields`__ + +| Property | Type | Description | Required | +| ------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | +| `id` | `string` | Unique identifier for the form field. | ✅ | +| `errorId` | `{id: string, css: string}` | Options for ID and CSS for the error message element. | ✅ | +| `label` | `string` | Label text for the form field. | ✅ | +| `type` | `'text'` \| `'number'` \| `'email'` \| `'password'` \| `'checkbox'` \| `'select'` \| `'radio'` \| `'textarea'` | The type of input field, determining how the field will behave and be rendered. | ✅ | +| `options` | `{ value: string; label: string }[]` | Options for `select`, `checkbox`, or `radio` fields. Required when using these field types. | ❌ | +| `placeholder` | `string` | Placeholder text for `text`, `number`, `email`, `password`, and `textarea` input fields. | ❌ | +| `required` | `boolean` | Indicates whether the form field is required to be filled. | ❌ | +| `validation` | `RegisterOptions` | Validation rules for the field using `react-hook-form`'s `RegisterOptions`. This allows you to specify rules like `required`, `maxLength`, etc. | ❌ | +| `icon` | `React.ReactNode` | Optional icon to be displayed with the input field. Can use components from libraries like `react-icons`. | ❌ | +| `value` | `string` | Default value of the field if it needs to be pre-filled. | ❌ | +| `css` | `{ wrapper: string, label?: string, input: string, icon?: string, error?: string }` | An object for defining the CSS classes used for styling different parts of the field, including the wrapper(containing the _icon_, _label_, _input field_), label, input, icon, and error message. | ✅ | + +__`Button Props`__ +| Property | Type | Description | Required | +| ---------- | ------------------------------------- | ------------------------------------------------------------------------------------------- | -------- | +| `type` | `'button'` \| `'submit'` \| `'reset'` | Specifies the type of button, whether it's a normal button, submit button, or reset button. | ✅ | +| `label` | `string` | Text label displayed on the button. | ✅ | +| `onClick` | `() => void` | Function to be called when the button is clicked. | ❌ | +| `disabled` | `boolean` | Specifies whether the button is disabled or not. | ❌ | +| `css` | `{ button: string }` | An object that defines the CSS class for the button. | ✅ | ### Form Submission The `onSubmit` function passed to `DynamicForm` will receive the form data as a `Record`. You can handle form submission by implementing your own logic in this function. diff --git a/package-lock.json b/package-lock.json index 20dceff..5fab638 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "dynamic-form-component", - "version": "1.0.221", + "version": "1.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "dynamic-form-component", - "version": "1.0.221", + "version": "1.1.0", "license": "MIT", "dependencies": { "react": "^18.3.1", diff --git a/package.json b/package.json index 1f89643..45e5afe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dynamic-form-component", - "version": "1.0.221", + "version": "1.1.0", "description": "A dynamic form component for React that renders forms based on provided configuration.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -29,8 +29,9 @@ "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/ShreyPurohit/Medium/tree/main/React-Projects/dynamic-form-medium" + "url": "https://github.com/ShreyPurohit/dynamic-form-component" }, + "homepage": "https://github.com/ShreyPurohit/dynamic-form-component#readme", "keywords": [ "react", "form", diff --git a/src/assets/interfaces.ts b/src/assets/interfaces.ts index aaaa570..0eea3f7 100644 --- a/src/assets/interfaces.ts +++ b/src/assets/interfaces.ts @@ -2,19 +2,38 @@ import { RegisterOptions, FieldValues } from "react-hook-form"; export interface IFormField { id: string; - errorId: string; + error: { + id: string, + css: string + }; label: string; - type: 'text' | 'number' | 'email' | 'password' | 'checkbox' | 'select'; + type: 'text' | 'number' | 'email' | 'password' | 'checkbox' | 'select' | 'textarea' | 'radio'; options?: { value: string; label: string }[]; placeholder?: string; required?: boolean; validation?: RegisterOptions; icon?: React.ReactNode; - value?: string + value?: string, + css: { + wrapper?: string, + label?: string, + input: string, + icon?: string, + error?: string + } +} + +export interface ISubmitButtonProps { + id: string + label: string, + type: 'button' | 'submit' | 'reset', + css: string, + disabled?: boolean, + onClick?: () => void } export interface DynamicFormProps { fields: IFormField[]; - onSubmit: (data: Record) => void; - cssFramework: 'tailwind' | 'bootstrap' + onSubmit: (data: FieldValues) => void; + button: ISubmitButtonProps } \ No newline at end of file diff --git a/src/components/DynamicForm.tsx b/src/components/DynamicForm.tsx index 01d67c9..2614e3d 100644 --- a/src/components/DynamicForm.tsx +++ b/src/components/DynamicForm.tsx @@ -3,7 +3,7 @@ import { useForm } from 'react-hook-form'; import { AiOutlineEye, AiOutlineEyeInvisible } from 'react-icons/ai'; import { DynamicFormProps, IFormField } from '../assets/interfaces'; -const CustomizedDynamicForm: React.FC = ({ fields, onSubmit, cssFramework }) => { +const DynamicForm: React.FC = ({ fields, onSubmit, button }) => { const [showPassword, setShowPassword] = useState(false); const { register, handleSubmit, formState: { errors } } = useForm({ mode: 'all' }); @@ -15,82 +15,105 @@ const CustomizedDynamicForm: React.FC = ({ fields, onSubmit, c const inputType = isPasswordField && showPassword ? 'text' : field.type; return ( -
-
- { - field.type === 'checkbox' && field.options ? ( -
+
+
+ {field.type === 'checkbox' && field.options ? ( +
+ {field.options.map(option => ( +
+ + +
+ ))} +
+ ) : field.type === 'select' ? ( + + ) : field.type === 'textarea' ? + + : (field.type === 'radio' && field.options ? ( +
{field.options.map(option => ( -
- - + +
))} -
- ) : field.type === 'select' ? ( - - ) : ( -
- {field.icon &&
{field.icon}
} - - {isPasswordField && ( -
setShowPassword(!showPassword)} - > - {showPassword ? : } -
- )}
- ) - } + ) : < div className={field.css.wrapper}> + {field.icon &&
{field.icon}
} + + {isPasswordField && ( +
setShowPassword(!showPassword)} + > + {showPassword ? : } +
+ )} +
+ )}
- {error &&
{error}
} + {error && {error}}
); }; return ( -
+ {fields.map((field) => ( -
- +
+ {renderField(field)}
))} ); }; -export default CustomizedDynamicForm; \ No newline at end of file +export default DynamicForm; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 164f884..6e86770 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ import DynamicForm from './components/DynamicForm' -import { IFormField, DynamicFormProps } from './assets/interfaces' +import { IFormField, DynamicFormProps, ISubmitButtonProps } from './assets/interfaces' export default DynamicForm -export { IFormField, DynamicFormProps } \ No newline at end of file +export { IFormField, DynamicFormProps, ISubmitButtonProps } \ No newline at end of file