├── .gitignore ├── Documentation ├── Examples │ ├── EmployeeFeeback.md │ ├── README.md │ └── SudentRegistration.md └── MultiStep │ └── README.md ├── README.md ├── babel.config.json ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── src ├── App.tsx ├── index.tsx └── llama │ ├── components │ ├── Fields │ │ ├── CheckBoxField.tsx │ │ ├── DropDownField.tsx │ │ ├── FileUploadField.tsx │ │ ├── InputField.tsx │ │ ├── RadioField.tsx │ │ └── TextAreaField.tsx │ ├── Form │ │ ├── multipleForm.tsx │ │ ├── renderForm.tsx │ │ └── singleForm.tsx │ ├── Loader.tsx │ └── Progress.tsx │ └── index.tsx ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | /dist 14 | 15 | # misc 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | -------------------------------------------------------------------------------- /Documentation/Examples/EmployeeFeeback.md: -------------------------------------------------------------------------------- 1 |

Employee Feedback Form with llama-forms-react

2 | 3 | ```JS 4 | import LlamaForm from "llama-forms-react"; 5 | 6 | export default function Example() { 7 | 8 | const handleSubmit = (data) => { 9 | console.log("Registration data,", data) 10 | } 11 | return ( 12 |
13 | 147 |
148 | ); 149 | } 150 | ``` 151 | -------------------------------------------------------------------------------- /Documentation/Examples/README.md: -------------------------------------------------------------------------------- 1 |

React Form using llama-forms-react

2 | -------------------------------------------------------------------------------- /Documentation/Examples/SudentRegistration.md: -------------------------------------------------------------------------------- 1 |

Student Registration Form with llama-forms-react

2 | 3 | ```JS 4 | import LlamaForm from "llama-forms-react"; 5 | 6 | export default function Example() { 7 | 8 | const handleRegistration = (data) => { 9 | console.log("Registration data,", data) 10 | } 11 | return ( 12 |
13 | 159 |
160 | ); 161 | } 162 | ``` 163 | -------------------------------------------------------------------------------- /Documentation/MultiStep/README.md: -------------------------------------------------------------------------------- 1 |

Multi Step form with llama-forms-react

2 | 3 | ```js 4 | import LlamaForm from "llama-forms-react"; 5 | export default function Example() { 6 | return ( 7 | 164 | ); 165 | } 166 | ``` 167 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Welcome to llama-forms-react 👋

2 |

3 | 4 | Version 5 | 6 | 7 | Documentation 8 | 9 | 10 | Maintenance 11 | 12 |

13 | 14 | > An HTML-free component for React form creation that employs a JSON structure to support a variety of form fields with a simple user interface. Simply import LlamaForm from llama-form to get a great form that is driven by JSON schema. 15 | 16 | **Content** 17 | 18 | - [Install](#install) 19 | - [Features](#features) 20 | - [Quickstart](#quickstart) 21 | - [Multi Step Form](Documentation/MultiStep/README.md) 22 | - [Examples](#Examples) 23 | - [Documentation](#documentation) 24 | - [Maintainers](#maintainers) 25 | 26 | ## Install 27 | 28 | ```sh 29 | npm i llama-forms-react 30 | ``` 31 | 32 | ## Features 33 | 34 | - Simple to use 35 | - Form based on a schema 36 | - Validation regex support 37 | - Form answer in JSON format 38 | - Submit button with loader that may be customized 39 | - Form submission callback function support 40 | - Custom errorMessage support 41 | - Support for sensitivity validation 42 | - Custom style support 43 | - multi-step form with: 44 | - Progress bar 45 | - Current step count with respective to total step 46 | - User defined initial step (Default is 1) 47 | - Callback function on each step submission 48 | 49 | ## Quickstart 50 | 51 | **Create a Login Form using Llama Form** 52 | 53 | ```js 54 | import LlamaForm from "llama-forms-react"; 55 | 56 | export default function Example() { 57 | const handleLogin = (data) => { 58 | console.log("Login data", data); 59 | }; 60 | 61 | return ( 62 | 108 | ); 109 | } 110 | ``` 111 | 112 | ## Documentation 113 | 114 | ### Main Props 115 | 116 | > **schema:** The form's foundation, where you may provide a json schema for the form's creation. 117 | 118 | > **options:** Field properties for the provided schema. 119 | 120 | > **data:** Form field default values 121 | 122 | > **onSubmit:** A callback that accepts a function and returns the form data. 123 | 124 | ### Schema Props 125 | 126 | 1. **title:** Title of the form. 127 | 2. **description:** Descripton of the form. 128 | 3. **wizard:** Option to enable multi-step form, default is `false`. 129 | 4. **properties:** Dynamic custom field which you want to render in form. 130 | - **required:** Specific field is requirement, default value is false. 131 | - **enum:** For option values, this property is applicable for dropdown fields, checkbox fields, radio fields, etc. 132 | - **step:** Specify the field position on multistep form. For instance, if the step value is 2 then that field will occur on the second step of the form, deafult value is 1. 133 | 134 | ### Options Props 135 | 136 | Here we pass all schema fields properties. Which basically contains an object for each field that we describe in the schema. 137 | 138 | 1. **fields:** 139 | - **type:** Type of input field, as for email we use "type - email". 140 | **Input Field type support by llama-forms-react.** 141 | 1. text - text field 142 | 2. textarea - text area field 143 | 3. email - email field 144 | 4. password - password field 145 | 5. radio - radio button is used to select one option in multiple options. 146 | 6. checkbox - This is used to select multiple options. 147 | 7. dropdown - This is used for dropdown value. Here we pass multiple values. 148 | 8. color - This is used as color picker 149 | 9. file - This is used for uploading files. 150 | 10. number - number filed. 151 | 11. range - This is used to set a range between two values. 152 | 12. tel - This is used for telephone number input. 153 | 13. time - time field 154 | 14. date - date field 155 | 15. datetime-local - This is used for both date and time at a time. 156 | 16. week- week field 157 | 17. month - month field 158 | 18. uri - This is used for input URI. 159 | - **label:** 160 | - **placeholder:** 161 | - **description:** Description of input field. 162 | - **validationRegex:** Custome regex to input field validation. 163 | - **errorMessage:** 164 | - **readOnly:** 165 | - **maxLength:** 166 | - **autoFocus:** 167 | - **autoComplete:** 168 | - **maxFileSize:** 169 | - **minFileSize:** 170 | - **min:** Minimum value of the input field. 171 | - **max:** TMaximum value of the input field. 172 | - **interval:** Applicaple with **range** input field type, we can specify interval between two values. 173 | - **accept:** Applicaple with **file** input field type, we can specify the acceptable file extension. ex - ["jpg", "png", "jpeg"] 174 | 175 | ## Author 176 | 177 | 👤 **NetTantra Technologies React Developers (https://github.com/orgs/nettantra/teams/llama-forms-core)** 178 | 179 | - Website: www.nettantra.com 180 | - Github: [@nettantra](https://github.com/nettantra) 181 | 182 | ## 🤝 Contributing 183 | 184 | Contributions, issues and feature requests are welcome!
Feel free to check [issues page](https://github.com/nettantra/llama-forms-react/issues). 185 | 186 | ## Show your support 187 | 188 | Give a ⭐️ if this [project](https://github.com/nettantra/llama-forms-react) helped you! 189 | 190 | ## 📝 License 191 | 192 | Copyright © 2022 [NetTantra Technologies](https://github.com/nettantra).
193 | This project is [MIT](https://github.com/nettantra/llama-forms-react/blob/master/LICENSE) licensed. 194 | 195 | --- 196 | -------------------------------------------------------------------------------- /babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/env", 5 | { 6 | "targets": { 7 | "edge": "17", 8 | "firefox": "60", 9 | "chrome": "67", 10 | "safari": "11.1" 11 | }, 12 | "useBuiltIns": "usage", 13 | "corejs": "2.5.7" 14 | } 15 | ], 16 | "@babel/preset-react", 17 | "@babel/preset-typescript" 18 | ] 19 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "llama-forms-react", 3 | "version": "1.0.6", 4 | "private": false, 5 | "description": "This is a react form builder where we can implement a number of form fields without using any HTML tags. This comes with a dynamic and user-friendly UI. You just need to import LlamaForm from llama-form and enjoy an amazing form by JSON schema.", 6 | "keywords": [ 7 | "react", 8 | "form", 9 | "llama-react", 10 | "llama-react-form", 11 | "form-builder" 12 | ], 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/nettantra/llama-forms-react.git" 16 | }, 17 | "bugs": { 18 | "url": "https://github.com/nettantra/llama-forms-react/issues", 19 | "email": "nettantra@nettantra.net" 20 | }, 21 | "main": "dist/index.js", 22 | "typings": "dist/index.d.ts", 23 | "files": [ 24 | "dist" 25 | ], 26 | "author": "NetTantra Technologies React Developers (https://github.com/orgs/nettantra/teams/llama-forms-developers)", 27 | "license": "MIT", 28 | "peerDependencies": { 29 | "react": ">=16" 30 | }, 31 | "dependencies": { 32 | "core-js": "2.6.5" 33 | }, 34 | "devDependencies": { 35 | "@types/react": "^18.0.14", 36 | "@types/react-dom": "^18.0.5", 37 | "react": "^18.2.0", 38 | "react-dom": "^18.2.0", 39 | "react-scripts": "5.0.1", 40 | "tsdx": "^0.14.1", 41 | "tslib": "^2.4.0", 42 | "typescript": "^4.7.4" 43 | }, 44 | "scripts": { 45 | "package": "rm -rf dist && tsdx build -i src/llama/index.tsx", 46 | "start": "react-scripts start", 47 | "build": "react-scripts build", 48 | "eject": "react-scripts eject" 49 | }, 50 | "browserslist": { 51 | "production": [ 52 | ">0.2%", 53 | "not dead", 54 | "not op_mini all" 55 | ], 56 | "development": [ 57 | "last 1 chrome version", 58 | "last 1 firefox version", 59 | "last 1 safari version" 60 | ] 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nettantra/llama-forms-react/8013e616d20dacfe852d1dfe9cd88b8245eb029a/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nettantra/llama-forms-react/8013e616d20dacfe852d1dfe9cd88b8245eb029a/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nettantra/llama-forms-react/8013e616d20dacfe852d1dfe9cd88b8245eb029a/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import LlamaForm from './llama/index' 3 | // import {LlamaForm} from "test-react-form"; 4 | 5 | 6 | function App() { 7 | 8 | const login_test = (data:any) => { 9 | console.log("login", data) 10 | } 11 | 12 | return ( 13 |
14 | 299 |
300 | ); 301 | } 302 | 303 | export default App; 304 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import App from './App'; 4 | 5 | const root = ReactDOM.createRoot( 6 | document.getElementById('root') as HTMLElement 7 | ); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | -------------------------------------------------------------------------------- /src/llama/components/Fields/CheckBoxField.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import React from 'react'; 3 | interface Props{ 4 | properties:any, 5 | handleData:any, 6 | name:any, 7 | parentState:any, 8 | 9 | } 10 | 11 | export default function CheckBoxField(props:Props) { 12 | const { properties, handleData, name } = props; 13 | const [chechBoxData, setCheckBoxData]:any = useState(props.parentState[name].value); 14 | 15 | const handleChange = (e:any) => { 16 | let checkObj = { ...chechBoxData, [e.target.value]: e.target.checked} 17 | for (let key in checkObj) { 18 | if (!checkObj[key]) { 19 | delete checkObj[key] 20 | } 21 | } 22 | setCheckBoxData(checkObj); 23 | handleData(checkObj); 24 | }; 25 | 26 | return ( 27 | <> 28 |
29 |

37 | {properties["label"]} 38 |

39 | {properties["values"] && 40 | properties["values"].map((item:any, index:any) => { 41 | return ( 42 |
43 | 54 | 65 |
66 | ); 67 | })} 68 |

76 | {properties["description"]} 77 |

78 |
79 | 80 | 87 | 88 | ); 89 | } 90 | -------------------------------------------------------------------------------- /src/llama/components/Fields/DropDownField.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | interface Props{ 4 | properties:any, 5 | handleData:any, 6 | name:any, 7 | parentState:any, 8 | } 9 | 10 | export default function DropDownField(props:Props) { 11 | const { properties, handleData, name } = props; 12 | 13 | const handleChange = (e:any) => { 14 | handleData(e.target.value); 15 | }; 16 | 17 | 18 | //loop through the values object 19 | const values = properties.values; 20 | let options = []; 21 | for (let key in values) { 22 | options.push( 23 | 26 | ); 27 | } 28 | return ( 29 | <> 30 |
31 |

39 | {properties["label"]} 40 |

41 | 42 |
43 |

51 | {properties["description"]}   52 |

53 |
64 | 84 |
85 |
86 |
87 | 88 | 95 | 96 | ); 97 | } 98 | -------------------------------------------------------------------------------- /src/llama/components/Fields/FileUploadField.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import React from 'react'; 3 | 4 | interface Props{ 5 | properties:any, 6 | handleData:any, 7 | name:any, 8 | parentState:any, 9 | } 10 | 11 | export default function FileUploadField(props:Props) { 12 | const { properties, handleData, name } = props; 13 | const [error, setError] = useState(false); 14 | 15 | function checkFileType(file:any) { 16 | const fileTypes = properties.accept; 17 | if (!fileTypes) { 18 | return true; 19 | } 20 | if (fileTypes.includes(file.type.split("/")[1])) { 21 | if (properties.maxFileSize && file.size > properties.maxFileSize * 1000) { 22 | return false; 23 | } 24 | if (properties.minFileSize && file.size < properties.minFileSize * 1000) { 25 | return false; 26 | } 27 | return true; 28 | } 29 | return false; 30 | } 31 | 32 | const handleChange = (e:any) => { 33 | if (e.target.files && e.target.files[0]) { 34 | if (checkFileType(e.target.files[0])) { 35 | setError(false); 36 | handleData(e.target.files[0]); 37 | } else { 38 | setError(true); 39 | handleData(e.target.files[0], true); 40 | } 41 | } 42 | }; 43 | 44 | return ( 45 | <> 46 |
47 |

55 | {properties["label"]} 56 |

57 | {properties["type"] === "range" ? ( 58 | {props.parentState[name].value} 59 | ) : null} 60 | { 77 | handleChange(e); 78 | }} 79 | /> 80 | 97 | 98 | 99 |
100 |

108 | {properties["description"]} 109 |

110 | {error ? ( 111 |

120 | {properties["errorMessage"] 121 | ? properties["errorMessage"] 122 | : "Invalid file type or size"} 123 |

124 | ) : null} 125 |
126 |
127 | 128 | ); 129 | } 130 | -------------------------------------------------------------------------------- /src/llama/components/Fields/InputField.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useRef, useEffect } from "react"; 2 | 3 | interface LooseObject { 4 | [key: string]: any 5 | } 6 | interface Props { 7 | properties: LooseObject, 8 | handleData: any, 9 | name: any, 10 | parentState: any, 11 | } 12 | 13 | export default function InputField(props: Props) { 14 | const { properties, handleData, name } = props 15 | const [error, setError] = useState(false) 16 | 17 | let capsWarning: any = useRef(); 18 | let inputRef: any = useRef(); 19 | 20 | const regexObject: any = { 21 | email: { regex: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/, errorMessage: "Please enter a valid email" }, 22 | number: { regex: /^[0-9]*$/, errorMessage: "Please enter a valid number" }, 23 | } 24 | 25 | function checkValidation(regex: string, value: string) { 26 | const re = new RegExp(regex); 27 | return re.test(value) 28 | } 29 | //***** 30 | 31 | // const prefix = 'prefix-' 32 | const caseChange = (value: any) => { 33 | if (properties["lowercase"]) return value.toLowerCase(); 34 | if (properties["uppercase"]) return value.toUpperCase(); 35 | return value 36 | } 37 | //it add prefix with input value 38 | const prefixChange = (value: any) => { 39 | if (properties["prefix"]) return value.substring(properties["prefix"].length) 40 | return value 41 | } 42 | //it block invalid character in number 43 | const blockInvalidChar = (e: any) => { 44 | if (properties["type"] === "number") ['e', 'E', '+', '-'].includes(e.key) && e.preventDefault(); 45 | return true 46 | } 47 | // this function check the capsLock event in input field 48 | const handleCapsLockchek = (e: any) => { 49 | if (e.getModifierState("CapsLock")) { 50 | capsWarning.current.hidden = false; 51 | capsWarning.current.style.color = 'red'; 52 | capsWarning.current.innerHTML = properties?.["capsLockMessage"]?.trim() || "WARNING! Caps lock is ON."; 53 | inputRef.current.value = ""; 54 | } else { 55 | capsWarning.current.hidden = true; 56 | } 57 | } 58 | 59 | // const suffixChange = (input) => { 60 | // if(["text", "number"].includes(properties['type'])) return input.replace(/^/g, `${prefix + " "}`) 61 | // // prefix +" "+ input.substring(prefix.length); 62 | // return input 63 | 64 | // } 65 | //*** */ 66 | const handleChange = (e: any) => { 67 | let input = e.target.value 68 | // let n = prefix + j 69 | // let i = input.replace(/^/g, `${prefix + " "}`) 70 | // ["text", "number"].includes(properties['type'])? prefix + input.substring(prefix.length) : input 71 | if (input.length > properties["maxLength"]) { 72 | setError(true) 73 | return false 74 | } 75 | let value = caseChange(input) 76 | value = prefixChange(value) 77 | handleData(value, false) 78 | 79 | if (value.length === 0) { 80 | setError(false) 81 | handleData(value, false) 82 | return 83 | } 84 | if (properties.validationRegex) { 85 | setError(!checkValidation(properties['validationRegex'], value)) 86 | handleData(value, !checkValidation(properties['validationRegex'], value)) 87 | } else if (properties.type in regexObject) { 88 | setError(!checkValidation(regexObject[properties.type]['regex'], value)) 89 | handleData(value, !checkValidation(regexObject[properties.type]['regex'], value)) 90 | } 91 | } 92 | useEffect(() => { 93 | 94 | if (properties?.["className"]?.trim()) { 95 | inputRef.current.style = "" 96 | inputRef.current.className = properties?.["className"] ?? name 97 | } 98 | if (properties["style"]) { 99 | inputRef.current.style = "" 100 | for (let key in properties["style"]) { 101 | inputRef.current.style.setProperty(key, properties["style"][key]); 102 | } 103 | } 104 | }, []); 105 | return ( 106 | <> 107 |
108 |

{properties['label']}

109 | {properties['type'] === 'range' && {props.parentState[name].value ? props.parentState[name].value : 0}} 110 | { handleChange(e) }} 130 | onKeyDown={blockInvalidChar} 131 | onKeyUp={properties["capsLockWaring"] ? handleCapsLockchek : (e) => { console.log("caps lock warning is disabled") }} 132 | ref={inputRef} 133 | // ref={(target)=>{ 134 | // console.log(target.value) 135 | // target.value = prefix 136 | // }} 137 | // ref={(target)=>{ 138 | // target.value = prefix 139 | // }} 140 | // onChange={(e)=>{ 141 | // const input = e.target.value 142 | // e.target.value = prefix + input 143 | // }} 144 | /> 145 |
146 |

{properties['description']}

147 | 148 | {error ?

{properties['errorMessage'] ? properties['errorMessage'] : (properties.type in regexObject) ? regexObject[properties.type]['errorMessage'] : null}

: null} 149 |
150 |
151 | 152 | ) 153 | } -------------------------------------------------------------------------------- /src/llama/components/Fields/RadioField.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | interface Props{ 4 | properties:any, 5 | handleData:any, 6 | name:any, 7 | parentState:any, 8 | } 9 | export default function RadioField(props:Props) { 10 | const { properties, handleData, name } = props; 11 | 12 | const handleChange = (e:any) => { 13 | handleData(e.target.value); 14 | }; 15 | 16 | return ( 17 | <> 18 |
19 |

27 | {properties["label"]} 28 |

29 | {properties["values"].map((value:any, index:any) => { 30 | return ( 31 |
32 | { 39 | handleChange(e); 40 | }} 41 | disabled={ 42 | properties["readOnly"] ? properties["readOnly"] : false 43 | } 44 | /> 45 | 56 |
57 | ); 58 | })} 59 |

{properties["description"]}

66 |
67 | 68 | 120 | 121 | ); 122 | } 123 | -------------------------------------------------------------------------------- /src/llama/components/Fields/TextAreaField.tsx: -------------------------------------------------------------------------------- 1 | import React,{ useEffect, useRef, useState } from "react"; 2 | 3 | interface Props{ 4 | properties:any, 5 | handleData:any, 6 | name:any, 7 | parentState:any, 8 | } 9 | 10 | export default function TextAreaField(props:Props) { 11 | const { properties, handleData, name } = props; 12 | let textareaRef : any = useRef() 13 | //******** 14 | const caseChange = (value:any) => { 15 | if (properties["lowercase"]) return value.toLowerCase(); 16 | if (properties["uppercase"]) return value.toUpperCase(); 17 | return value 18 | } 19 | //**** */ 20 | const handleChange = (e:any) => { 21 | const value = caseChange(e.target.value) 22 | handleData(value); 23 | }; 24 | 25 | useEffect(() => { 26 | if (properties?.["className"]?.trim()) { 27 | textareaRef.current.style = "" 28 | textareaRef.current.className = properties?.["className"] ?? name 29 | } 30 | if (properties["style"]) { 31 | textareaRef.current.style = "" 32 | for (let key in properties["style"]) { 33 | textareaRef.current.style.setProperty(key, properties["style"][key]); 34 | } 35 | } 36 | }, []); 37 | 38 | return ( 39 | <> 40 |
41 |

49 | {properties["label"]} 50 |

51 |