-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit b09db3d
Showing
13 changed files
with
562 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
# 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. | ||
|
||
## Installation | ||
To install the package, run: | ||
```bash | ||
npm install dynamic-form-component | ||
``` | ||
|
||
## Peer Dependencies | ||
Ensure you have the following peer dependencies installed: | ||
* `react` | ||
* `react-dom` | ||
* `react-hook-form` | ||
* `react-icons` | ||
|
||
You can install them with: | ||
```bash | ||
npm install react react-dom react-hook-form react-icons | ||
``` | ||
|
||
## Usage | ||
### Importing The Component | ||
```bash | ||
import DynamicForm, { IFormField } from 'dynamic-form-component'; | ||
``` | ||
### Example Usage | ||
Below is an example of how to use the `DynamicForm` component in your react project: | ||
```js | ||
import DynamicForm, { IFormField } from 'dynamic-form-component'; | ||
import { RegisterOptions } from 'react-hook-form'; | ||
import { AiOutlineLock, AiOutlineMail, AiOutlineNumber, AiOutlineUser } from 'react-icons/ai'; | ||
|
||
const App = () => { | ||
const formFields: IFormField[] = [ | ||
{ | ||
id: 'name', | ||
errorId: 'nameErr', | ||
label: 'Name', | ||
type: 'text', | ||
placeholder: 'Enter your name', | ||
required: true, | ||
validation: { | ||
required: 'Name is required', | ||
maxLength: { | ||
value: 20, | ||
message: 'Name must be less than 20 characters', | ||
}, | ||
}, | ||
icon: <AiOutlineUser /> | ||
}, | ||
{ | ||
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: <AiOutlineMail /> | ||
}, | ||
{ | ||
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: <AiOutlineNumber /> | ||
}, | ||
{ | ||
id: 'password', | ||
errorId: 'passwordErr', | ||
label: 'Password', | ||
type: 'password', | ||
placeholder: 'Enter your Password', | ||
validation: { | ||
required: 'Password is required', | ||
}, | ||
icon: <AiOutlineLock /> | ||
}, | ||
{ | ||
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', | ||
}, | ||
}, | ||
]; | ||
|
||
const handleFormSubmit = (data: Record<string, any>) => { | ||
console.log('Form Data:', data); | ||
}; | ||
|
||
return ( | ||
<div> | ||
<h1>Dynamic Form Example</h1> | ||
<DynamicForm fields={formFields} onSubmit={handleFormSubmit} /> | ||
</div> | ||
) | ||
} | ||
|
||
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 Submission | ||
The `onSubmit` function passed to `DynamicForm` will receive the form data as a `Record<string, any>`. You can handle form submission by implementing your own logic in this function. | ||
Example Form Data | ||
```bash | ||
{ | ||
"name": "John Doe", | ||
"email": "[email protected]", | ||
"age": 25, | ||
"password": "password123", | ||
"hobbies": Array ["reading", "travelling"], | ||
"gender": "male" | ||
} | ||
``` | ||
## Contributing | ||
If you have any ideas, suggestions, or issues, feel free to open an issue or contribute with a pull request. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { RegisterOptions, FieldValues } from "react-hook-form"; | ||
export interface IFormField { | ||
id: string; | ||
errorId: string; | ||
label: string; | ||
type: 'text' | 'number' | 'email' | 'password' | 'checkbox' | 'select'; | ||
options?: { | ||
value: string; | ||
label: string; | ||
}[]; | ||
placeholder?: string; | ||
required?: boolean; | ||
validation?: RegisterOptions; | ||
icon?: React.ReactNode; | ||
value?: string; | ||
} | ||
export interface DynamicFormProps { | ||
fields: IFormField[]; | ||
onSubmit: (data: FieldValues) => void; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { DynamicFormProps } from '../assets/interfaces'; | ||
import React from 'react'; | ||
declare const DynamicForm: React.FC<DynamicFormProps>; | ||
export default DynamicForm; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const react_1 = require("react"); | ||
const react_hook_form_1 = require("react-hook-form"); | ||
const ai_1 = require("react-icons/ai"); | ||
const react_2 = __importDefault(require("react")); | ||
const DynamicForm = ({ fields, onSubmit }) => { | ||
const [showPassword, setShowPassword] = (0, react_1.useState)(false); | ||
const { register, handleSubmit, formState: { errors } } = (0, react_hook_form_1.useForm)({ mode: 'all' }); | ||
const renderField = (field) => { | ||
var _a, _b; | ||
const error = (_a = errors[field.id]) === null || _a === void 0 ? void 0 : _a.message; | ||
const isPasswordField = field.type === 'password'; | ||
const inputType = isPasswordField && showPassword ? 'text' : field.type; | ||
return (react_2.default.createElement("div", { id: 'input-wrapper' }, | ||
react_2.default.createElement("div", { id: 'input-container' }, field.type === 'checkbox' && field.options ? (react_2.default.createElement("div", { className: 'grid grid-cols-2 gap-4' }, field.options.map(option => (react_2.default.createElement("div", { key: option.value, className: 'flex gap-1 items-center justify-center' }, | ||
react_2.default.createElement("label", { htmlFor: `${field.id}-${option.value}`, className: 'ml-2 mt-1' }, | ||
option.label, | ||
" :"), | ||
react_2.default.createElement("input", Object.assign({ id: `${field.id}-${option.value}` }, register(field.id, Object.assign({}, field.validation)), { type: field.type, value: option.value, className: 'w-max' }))))))) : field.type === 'select' ? (react_2.default.createElement("select", Object.assign({}, register(field.id, Object.assign({}, field.validation)), { id: field.id }), (_b = field.options) === null || _b === void 0 ? void 0 : _b.map((option) => (react_2.default.createElement("option", { key: option.value, value: option.value }, option.label))))) : (react_2.default.createElement("div", { className: 'flex items-center p-1 border' }, | ||
field.icon && react_2.default.createElement("div", { className: 'ml-2' }, field.icon), | ||
react_2.default.createElement("input", Object.assign({ id: field.id }, register(field.id, Object.assign({}, field.validation)), { type: inputType, placeholder: field.placeholder })), | ||
isPasswordField && (react_2.default.createElement("div", { id: "prop-icon", className: "hover:cursor-pointer mr-3", onClick: () => setShowPassword(!showPassword) }, showPassword ? react_2.default.createElement(ai_1.AiOutlineEye, null) : react_2.default.createElement(ai_1.AiOutlineEyeInvisible, null)))))), | ||
error && react_2.default.createElement("span", { id: field.errorId }, error))); | ||
}; | ||
return (react_2.default.createElement("main", { className: 'md:w-3/4 m-auto md:h-0' }, | ||
react_2.default.createElement("form", { onSubmit: handleSubmit(onSubmit), className: "flex flex-col md:w-1/2 m-auto p-5 gap-5 md:mt-5 md:border border-black" }, | ||
fields.map((field) => (react_2.default.createElement("div", { key: field.id }, | ||
react_2.default.createElement("label", { htmlFor: field.id }, field.label), | ||
renderField(field)))), | ||
react_2.default.createElement("button", { type: 'submit', disabled: Object.keys(errors).length ? true : false, className: 'px-4 py-2 bg-slate-400 hover:bg-slate-600 hover:transition hover:text-white rounded-lg disabled:bg-gray-600 disabled:hover:bg-gray-600' }, "Submit")))); | ||
}; | ||
exports.default = DynamicForm; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import DynamicForm from './components/DynamicForm'; | ||
import { IFormField, DynamicFormProps } from './assets/interfaces'; | ||
export default DynamicForm; | ||
export { IFormField, DynamicFormProps }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const DynamicForm_1 = __importDefault(require("./components/DynamicForm")); | ||
exports.default = DynamicForm_1.default; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.