UNPKG

easy-form-handler

Version:

A powerful, lightweight React form handling library with built-in validation, customizable styling, and intuitive components.

667 lines (649 loc) 39.2 kB
'use strict'; var React = require('react'); function styleInject(css, ref) { if ( ref === void 0 ) ref = {}; var insertAt = ref.insertAt; if (!css || typeof document === 'undefined') { return; } var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.type = 'text/css'; if (insertAt === 'top') { if (head.firstChild) { head.insertBefore(style, head.firstChild); } else { head.appendChild(style); } } else { head.appendChild(style); } if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } } var css_248z$1 = "@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');\n*{\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n font-family: \"Poppins\", sans-serif;\n}\n:root{\n --primary_color: #3f51b5;\n --error_color: #f50057;\n --background_color: #f5f5f5;\n --text_color: #333;\n --white: #fff;\n --black: #000;\n --gray: #808080;\n --light_gray: #d3d3d3;\n --dark_gray: #696969;\n --blue: #2196f3;\n --light_blue: #70b8ff;\n --dark_blue: #1976d2;\n --green: #4caf50;\n --light_green: #c8e6c9;\n --dark_green: #388e3c;\n --red: #f44336;\n --light_red: #ef9a9a;\n --dark_red: #d32f2f;\n --yellow: #ffeb3b;\n --light_yellow: #fff9c4;\n --dark_yellow: #fbc02d;\n --purple: #9c27b0;\n --light_purple: #e1bee7;\n --dark_purple: #8e24aa;\n --pink: #e91e63;\n --light_pink: #f8bbd0;\n --dark_pink: #d81b60;\n --orange: #ff9800;\n --light_orange: #ffe0b2;\n --dark_orange: #f57c00;\n --teal: #009688;\n --light_teal: #b2dfdb;\n --dark_teal: #00796b;\n --cyan: #00bcd4;\n --light_cyan: #b2ebf2;\n --dark_cyan: #0097a7;\n --indigo: #3f51b5;\n --light_indigo: #c5cae9;\n --dark_indigo: #303f9f;\n --brown: #795548;\n --light_brown: #d7ccc8;\n --dark_brown: #5d4037;\n --amber: #ffc107;\n --light_amber: #ffe57f;\n --dark_amber: #ff8f00;\n --lime: #cddc39;\n --light_lime: #f0e68c;\n --dark_lime: #c0ca33;\n --deep_orange: #ff5722; \n --light_deep_orange: #ffccbc;\n --dark_deep_orange: #e64a19;\n --deep_purple: #673ab7;\n --light_deep_purple: #d1c4e9;\n --dark_deep_purple: #512da8;\n --light_gray: #d3d3d3;\n --dark_gray: #696969;\n /* --light_blue: #bbdefb; */\n --dark_blue: #1976d2;\n --light_green: #c8e6c9;\n --dark_green: #388e3c;\n --light_red: #ef9a9a;\n --dark_red: #d32f2f;\n --light_yellow: #fff9c4;\n --dark_yellow: #fbc02d;\n --light_purple: #e1bee7;\n --dark_purple: #8e24aa; \n --light_pink: #f8bbd0;\n --dark_pink: #d81b60;\n --light_orange: #ffe0b2; \n}\n\n.index_App__N3uO9{\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100vh;\n}"; styleInject(css_248z$1); var css_248z = ".Form-module_Form__JzhAc {\r\n border: 1px solid var(--light_gray);\r\n width: fit-content;\r\n padding: 20px;\r\n padding-top: 35px;\r\n border-radius: 10px;\r\n width: 450px;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n gap: 20px;\r\n flex-direction: column;\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_heading__X4bMW {\r\n font-size: 28px;\r\n font-weight: 500;\r\n color: var(--text_color);\r\n text-align: center;\r\n margin-bottom: 10px;\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_inputContainer__aMSM2 {\r\n width: 100%;\r\n /* border: 1px solid red; */\r\n display: flex;\r\n justify-content: center;\r\n align-items: start;\r\n flex-direction: column;\r\n gap: 5px;\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_inputContainer__aMSM2 label {\r\n font-size: 15px;\r\n font-weight: 500;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n gap: 5px;\r\n color: var(--text_color);\r\n margin-bottom: 5px;\r\n}\r\n.Form-module_Form__JzhAc .Form-module_inputContainer__aMSM2 label span {\r\n font-size: 15px;\r\n font-weight: 400;\r\n color: var(--red);\r\n}\r\n.Form-module_Form__JzhAc .Form-module_inputContainer__aMSM2 label:hover {\r\n cursor: pointer;\r\n}\r\n.Form-module_Form__JzhAc .Form-module_inputContainer__aMSM2 input {\r\n width: 100%;\r\n padding: 10px;\r\n font-size: 15px;\r\n border-radius: 5px;\r\n border: 2px solid var(--light_gray);\r\n transition: all 0.2s ease-in-out;\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_inputContainer__aMSM2 input:focus {\r\n outline: none;\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_inputContainer__aMSM2 input:focus-within {\r\n border: 2px solid var(--blue);\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_submit__8sV37 {\r\n background-color: var(--blue);\r\n /* border: 1px solid red; */\r\n width: 100%;\r\n padding: 8px 20px;\r\n font-size: 18px;\r\n border-radius: 5px;\r\n border: none;\r\n cursor: pointer;\r\n color: var(--white);\r\n font-weight: 400;\r\n transition: all 0.2s ease-in-out;\r\n}\r\n.Form-module_Form__JzhAc .Form-module_submit__8sV37:hover {\r\n background-color: var(--light_blue);\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_error__E28cD {\r\n font-size: 12px;\r\n font-weight: 400;\r\n color: var(--red);\r\n margin-top: 5px;\r\n text-align: left;\r\n width: 100%;\r\n gap: 5px;\r\n}\r\n.Form-module_inputContainer__aMSM2.Form-module_inputError__iBZiD input:focus-within {\r\n border: 2px solid var(--red);\r\n}\r\n.Form-module_inputContainer__aMSM2.Form-module_inputErrorBlur__-tOTg input {\r\n border: 2px solid var(--red);\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_passwordContainer__Hyfhn {\r\n width: 100%;\r\n /* border: 1px solid red; */\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n gap: 5px;\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_eye__8iqBD {\r\n height: 46.4px;\r\n width: 50px;\r\n border: 2px solid var(--light_gray);\r\n border-radius: 5px;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n cursor: pointer;\r\n transition: all 0.2s ease-in-out;\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_eye__8iqBD svg {\r\n height: 20px;\r\n width: 20px;\r\n color: var(--text_color);\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_eye__8iqBD:hover {\r\n background-color: var(--light_gray);\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_eye__8iqBD.Form-module_active__7GtwM {\r\n /* color: var(--blue); */\r\n border: 2px solid var(--blue);\r\n}\r\n.Form-module_Form__JzhAc .Form-module_eye__8iqBD.Form-module_active__7GtwM svg {\r\n color: var(--blue);\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_selectContainer__GEd3r {\r\n width: 100%;\r\n position: relative;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 5px;\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_selectContainer__GEd3r .Form-module_selectedOption__7CtTy {\r\n width: 100%;\r\n padding: 10px;\r\n font-size: 15px;\r\n border-radius: 5px;\r\n border: 2px solid var(--light_gray);\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n cursor: pointer;\r\n transition: all 0.2s ease-in-out;\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_selectContainer__GEd3r .Form-module_selectedOption__7CtTy:hover {\r\n background-color: var(--light_gray);\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_selectContainer__GEd3r .Form-module_dropdown__c-mnY {\r\n position: absolute;\r\n top: 100%;\r\n left: 0;\r\n width: 100%;\r\n background-color: var(--white);\r\n border: 2px solid var(--light_gray);\r\n border-radius: 5px;\r\n margin-top: 5px;\r\n z-index: 10;\r\n max-height: 200px;\r\n overflow-y: auto;\r\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_selectContainer__GEd3r .Form-module_dropdownItem__HTPjT {\r\n padding: 10px;\r\n font-size: 15px;\r\n color: var(--text_color);\r\n cursor: pointer;\r\n transition: all 0.2s ease-in-out;\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_selectContainer__GEd3r .Form-module_dropdownItem__HTPjT:hover {\r\n background-color: var(--light_gray);\r\n}\r\n\r\n.Form-module_Form__JzhAc .Form-module_selectContainer__GEd3r .Form-module_dropdownItem__HTPjT.Form-module_active__7GtwM {\r\n background-color: var(--blue);\r\n color: var(--white);\r\n}"; var Style = {"Form":"Form-module_Form__JzhAc","heading":"Form-module_heading__X4bMW","inputContainer":"Form-module_inputContainer__aMSM2","submit":"Form-module_submit__8sV37","error":"Form-module_error__E28cD","inputError":"Form-module_inputError__iBZiD","inputErrorBlur":"Form-module_inputErrorBlur__-tOTg","passwordContainer":"Form-module_passwordContainer__Hyfhn","eye":"Form-module_eye__8iqBD","active":"Form-module_active__7GtwM"}; styleInject(css_248z); function Form({ children, isActiveDefaultStyle = true, className = "", onSubmit, ...props }) { const handleSubmit = (e) => { e.preventDefault(); const data = {}; const form = Array.from(e.target.elements); for (const element of form) { if (element.tagName === 'INPUT' && element.type !== 'submit') { // console.log(`${element.name}: ${element.value}`); data[element.name] = element.value; } if (element.tagName === 'SELECT') { // console.log(`${element}: ${element}`); data[element.name] = element.value; } if (element.tagName === 'TEXTAREA') { data[element.name] = element.value; } if (element.tagName === 'FIELDSET') { const inputs = Array.from(element.elements); inputs.forEach(input => { if (input.name) { data[input.name] = input.value; } }); } if (element.tagName === 'LEGEND') { // LEGEND typically doesn't hold data, so it can be skipped or logged if needed console.log(`Legend: ${element.textContent}`); } if (element.tagName === 'DATALIST') { const options = Array.from(element.children); options.forEach(option => { if (option.value) { data[element.id] = option.value; // Assuming the datalist has an id } }); } } onSubmit(data); }; return (React.createElement(React.Fragment, null, React.createElement("form", { onSubmit: handleSubmit, className: `${isActiveDefaultStyle ? Style.Form : ""} ${className}`, ...props }, children))); } const Heading = ({ value, className = "", children, ...props }) => { return (React.createElement(React.Fragment, null, React.createElement("h1", { className: `${Style.heading} ${className}`, ...props }, value, children))); }; function validate(data, error, rule) { const errors = {}; for (const key in rule) { const rules = rule[key]; const value = data[key]; for (const ruleKey in rules) { const ruleValue = rules[ruleKey]; // Presence rules if (ruleKey === 'required' && (!value || value === '')) { errors[key] = `${key} is required`; break; } if (ruleKey === 'required_if') { const [field, expectedValue] = ruleValue.split(','); if (data[field] === expectedValue && (!value || value === '')) { errors[key] = `${key} is required when ${field} is ${expectedValue}`; break; } } if (ruleKey === 'required_unless') { const [field, expectedValue] = ruleValue.split(','); if (data[field] !== expectedValue && (!value || value === '')) { errors[key] = `${key} is required unless ${field} is ${expectedValue}`; break; } } if (ruleKey === 'required_with') { const fields = ruleValue.split(','); if (fields.some((f) => data[f] !== undefined) && (!value || value === '')) { errors[key] = `${key} is required when any of ${fields.join(', ')} is present`; break; } } if (ruleKey === 'required_without') { const fields = ruleValue.split(','); if (fields.some((f) => data[f] === undefined) && (!value || value === '')) { errors[key] = `${key} is required when any of ${fields.join(', ')} is missing`; break; } } if (ruleKey === 'present' && !(key in data)) { errors[key] = `${key} must be present`; break; } if (ruleKey === 'filled' && (!value || value === '')) { errors[key] = `${key} must be present and not empty if present`; break; } // String rules if (ruleKey === 'isAlpha' && (typeof value !== 'string' || !/^[a-zA-Z]+$/.test(value))) { errors[key] = `${key} must contain only alphabetic characters`; break; } if (ruleKey === 'noSpecialChars' && /[^a-zA-Z0-9]/.test(value)) { errors[key] = `${key} must not contain any special characters`; break; } if (ruleKey === 'string' && typeof value !== 'string') { errors[key] = `${key} must be a string`; break; } // Size rules if (ruleKey === 'min') { const min = parseInt(ruleValue, 10); if (typeof value === 'string' && value.length < min) { errors[key] = `${key} must be at least ${min} characters long`; break; } if (typeof value === 'number' && value < min) { errors[key] = `${key} must be at least ${min}`; break; } } if (ruleKey === 'max') { const max = parseInt(ruleValue, 10); if (typeof value === 'string' && value.length > max) { errors[key] = `${key} must not exceed ${max} characters`; break; } if (typeof value === 'number' && value > max) { errors[key] = `${key} must not exceed ${max}`; break; } } if (ruleKey === 'between') { const [min, max] = ruleValue.split(',').map(Number); if (typeof value === 'string' && (value.length < min || value.length > max)) { errors[key] = `${key} must be between ${min} and ${max} characters long`; break; } if (typeof value === 'number' && (value < min || value > max)) { errors[key] = `${key} must be between ${min} and ${max}`; break; } } if (ruleKey === 'size') { const size = parseInt(ruleValue, 10); if (typeof value === 'string' && value.length !== size) { errors[key] = `${key} must be exactly ${size} characters long`; break; } if (typeof value === 'number' && value !== size) { errors[key] = `${key} must be exactly ${size}`; break; } if (Array.isArray(value) && value.length !== size) { errors[key] = `${key} must contain exactly ${size} items`; break; } } if (ruleKey === 'length') { const length = parseInt(ruleValue, 10); if (typeof value === 'string' && value.length !== length) { errors[key] = `${key} must be exactly ${length} characters long`; break; } } // Type rules if (ruleKey === 'numeric' && typeof value !== 'number') { errors[key] = `${key} must be a number`; break; } if (ruleKey === 'integer' && !Number.isInteger(value)) { errors[key] = `${key} must be an integer`; break; } if (ruleKey === 'boolean' && typeof value !== 'boolean' && value !== 0 && value !== 1) { errors[key] = `${key} must be true/false, 0/1`; break; } if (ruleKey === 'array' && !Array.isArray(value)) { errors[key] = `${key} must be an array`; break; } if (ruleKey === 'date' && isNaN(Date.parse(value))) { errors[key] = `${key} must be a valid date`; break; } if (ruleKey === 'file' && (typeof value !== 'string' || !value.trim())) { errors[key] = `${key} must be a valid file path`; break; } if (ruleKey === 'image' && Array.isArray(value)) { const invalidFiles = value.filter((file) => !/\.(jpeg|jpg|png|bmp|gif|svg|webp)$/i.test(file)); if (invalidFiles.length > 0) { errors[key] = `${key} contains invalid image files. Allowed extensions are: jpeg, jpg, png, bmp, gif, svg, webp`; break; } break; } if (ruleKey === 'mimes') { const mimes = Array.isArray(rules[ruleKey]) ? rules[ruleKey] : rules[ruleKey].split(','); const ext = value.split('.').pop(); if (!mimes.includes(ext)) { errors[key] = `${key} must be a file of type: ${mimes.join(', ')}`; break; } } // Format rules if (ruleKey === 'email' && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) { errors[key] = `${key} must be a valid email address`; break; } if (ruleKey === 'url' && !/^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/.test(value)) { errors[key] = `${key} must be a valid URL`; break; } if (ruleKey === 'uuid' && !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)) { errors[key] = `${key} must be a valid UUID`; break; } if (ruleKey === 'ip' && !/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(value)) { errors[key] = `${key} must be a valid IP address`; break; } if (ruleKey === 'json') { try { JSON.parse(value); } catch { errors[key] = `${key} must be a valid JSON string`; break; } } if (ruleKey === 'regex') { const regex = new RegExp(ruleValue); if (!regex.test(value)) { errors[key] = `${key} must satisfy the regex pattern: ${ruleValue}`; break; } } if (ruleKey === 'contains') { const substrings = Array.isArray(ruleValue) ? ruleValue : ruleValue.split(','); if (typeof value !== 'string' || !substrings.some((substring) => value.includes(substring))) { errors[key] = `${key} must contain at least one of the following: ${substrings.join(', ')}`; break; } } if (ruleKey === 'in') { const options = Array.isArray(ruleValue) ? ruleValue : ruleValue.split(','); if (!options.includes(value)) { errors[key] = `${key} must be one of the following: ${options.join(', ')}`; break; } } if (ruleKey === 'not_in') { const options = Array.isArray(ruleValue) ? ruleValue : ruleValue.split(','); if (options.includes(value)) { errors[key] = `${key} must not be one of the following: ${options.join(', ')}`; break; } } if (ruleKey === 'same') { const otherField = ruleValue; if (data[otherField] !== value) { errors[key] = `${key} must be the same as ${otherField}`; break; } } if (ruleKey === 'different') { const otherField = ruleValue; if (data[otherField] === value) { errors[key] = `${key} must be different from ${otherField}`; break; } } if (ruleKey === 'not_regex') { const regexPattern = ruleValue; const regex = new RegExp(regexPattern); if (regex.test(value)) { errors[key] = `${key} must not satisfy the regex pattern: ${regexPattern}`; break; } } if (ruleKey === 'not_contains') { const substrings = Array.isArray(ruleValue) ? ruleValue : ruleValue.split(','); if (typeof value !== 'string' || substrings.some((substring) => value.includes(substring))) { errors[key] = `${key} must not contain any of the following: ${substrings.join(', ')}`; break; } } if (ruleKey === 'not_in') { const options = Array.isArray(ruleValue) ? ruleValue : ruleValue.split(','); if (options.includes(value)) { errors[key] = `${key} must not be one of the following: ${options.join(', ')}`; break; } } if (ruleKey === 'not_same') { const otherField = ruleValue; if (data[otherField] === value) { errors[key] = `${key} must not be the same as ${otherField}`; break; } } if (ruleKey === 'not_different') { const otherField = ruleValue; if (data[otherField] !== value) { errors[key] = `${key} must not be different from ${otherField}`; break; } } if (ruleKey === 'not_present' && (key in data)) { errors[key] = `${key} must not be present`; break; } if (ruleKey === 'not_filled' && (typeof value === 'string' && value.trim())) { errors[key] = `${key} must not be filled`; break; } if (ruleKey === 'not_required' && (typeof value !== 'undefined' && value !== null)) { errors[key] = `${key} must not be required`; break; } if (ruleKey === 'not_string' && typeof value === 'string') { errors[key] = `${key} must not be a string`; break; } if (ruleKey === 'not_numeric' && typeof value === 'number') { errors[key] = `${key} must not be a number`; break; } if (ruleKey === 'not_integer' && Number.isInteger(value)) { errors[key] = `${key} must not be an integer`; break; } if (ruleKey === 'not_boolean' && (typeof value === 'boolean' || value === 0 || value === 1)) { errors[key] = `${key} must not be true/false, 0/1`; break; } if (ruleKey === 'not_array' && Array.isArray(value)) { errors[key] = `${key} must not be an array`; break; } if (ruleKey === 'not_date' && !isNaN(Date.parse(value))) { errors[key] = `${key} must not be a valid date`; break; } if (ruleKey === 'not_file' && (typeof value === 'string' && value.trim())) { errors[key] = `${key} must not be a valid file path`; break; } if (ruleKey === 'not_image' && Array.isArray(value)) { const invalidFiles = value.filter((file) => !/\.(jpeg|jpg|png|bmp|gif|svg|webp)$/i.test(file)); if (invalidFiles.length > 0) { errors[key] = `${key} contains invalid image files. Allowed extensions are: jpeg, jpg, png, bmp, gif, svg, webp`; break; } break; } if (ruleKey === 'not_mimes') { const mimes = Array.isArray(ruleValue) ? ruleValue : ruleValue.split(','); const ext = value.split('.').pop(); if (!mimes.includes(ext)) { errors[key] = `${key} must not be a file of type: ${mimes.join(', ')}`; break; } } if (ruleKey === 'not_email' && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) { errors[key] = `${key} must not be a valid email address`; break; } if (ruleKey === 'not_url' && /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/.test(value)) { errors[key] = `${key} must not be a valid URL`; break; } if (ruleKey === 'not_uuid' && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)) { errors[key] = `${key} must not be a valid UUID`; break; } if (ruleKey === 'not_ip' && /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(value)) { errors[key] = `${key} must not be a valid IP address`; break; } if (ruleKey === 'not_json') { try { JSON.parse(value); } catch { errors[key] = `${key} must not be a valid JSON string`; break; } } if (ruleKey === 'not_regex') { const regexPattern = ruleValue; const regex = new RegExp(regexPattern); if (regex.test(value)) { errors[key] = `${key} must not satisfy the regex pattern: ${regexPattern}`; break; } } if (ruleKey === 'not_in') { const options = Array.isArray(ruleValue) ? ruleValue : ruleValue.split(','); if (options.includes(value)) { errors[key] = `${key} must not be one of the following: ${options.join(', ')}`; break; } } if (ruleKey === 'not_same') { const otherField = ruleValue; if (data[otherField] === value) { errors[key] = `${key} must not be the same as ${otherField}`; break; } } if (ruleKey === 'not_different') { const otherField = ruleValue; if (data[otherField] !== value) { errors[key] = `${key} must not be different from ${otherField}`; break; } } if (ruleKey === 'not_present' && (key in data)) { errors[key] = `${key} must not be present`; break; } if (ruleKey === 'not_filled' && (typeof value === 'string' && value.trim())) { errors[key] = `${key} must not be filled`; break; } if (ruleKey === 'not_required' && (typeof value !== 'undefined' && value !== null)) { errors[key] = `${key} must not be required`; break; } if (ruleKey === 'not_string' && typeof value === 'string') { errors[key] = `${key} must not be a string`; break; } if (ruleKey === 'not_numeric' && typeof value === 'number') { errors[key] = `${key} must not be a number`; break; } if (ruleKey === 'not_integer' && Number.isInteger(value)) { errors[key] = `${key} must not be an integer`; break; } if (ruleKey === 'not_boolean' && (typeof value === 'boolean' || value === 0 || value === 1)) { errors[key] = `${key} must not be true/false, 0/1`; break; } if (ruleKey === 'not_array' && Array.isArray(value)) { errors[key] = `${key} must not be an array`; break; } if (ruleKey === 'not_date' && !isNaN(Date.parse(value))) { errors[key] = `${key} must not be a valid date`; break; } if (ruleKey === 'not_file' && (typeof value === 'string' && value.trim())) { errors[key] = `${key} must not be a valid file path`; break; } if (ruleKey === 'not_image' && Array.isArray(value)) { const invalidFiles = value.filter((file) => !/\.(jpeg|jpg|png|bmp|gif|svg|webp)$/i.test(file)); if (invalidFiles.length > 0) { errors[key] = `${key} contains invalid image files. Allowed extensions are: jpeg, jpg, png, bmp, gif, svg, webp`; break; } break; } if (ruleKey === 'not_mimes') { const mimes = Array.isArray(ruleValue) ? ruleValue : ruleValue.split(','); const ext = value.split('.').pop(); if (!mimes.includes(ext)) { errors[key] = `${key} must not be a file of type: ${mimes.join(', ')}`; break; } } if (ruleKey === 'not_email' && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) { errors[key] = `${key} must not be a valid email address`; break; } if (ruleKey === 'not_url' && /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/.test(value)) { errors[key] = `${key} must not be a valid URL`; break; } if (ruleKey === 'not_uuid' && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)) { errors[key] = `${key} must not be a valid UUID`; break; } if (ruleKey === 'not_ip' && /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(value)) { errors[key] = `${key} must not be a valid IP address`; break; } if (ruleKey === 'not_json') { try { JSON.parse(value); } catch { errors[key] = `${key} must not be a valid JSON string`; break; } } if (ruleKey === 'not_regex') { const regexPattern = ruleValue; const regex = new RegExp(regexPattern); if (regex.test(value)) { errors[key] = `${key} must not satisfy the regex pattern: ${regexPattern}`; break; } } } } error(errors); return errors; } const Input = ({ name, type, label, value, watch, error, className, required, placeholder, rule, checkRuleOnBlur, autoComplete, ...props }) => { const id = React.useId(); const [inputError, setInputError] = React.useState({}); const [blur, setBlur] = React.useState(!checkRuleOnBlur); const [eye, setEye] = React.useState(false); const [inputType, setInputType] = React.useState(type); const handleBlur = (e) => { if (name && rule && checkRuleOnBlur) { validate({ [name]: e.target.value }, setInputError, { [name]: rule }); setBlur(true); } else { setBlur(false); } }; const handleChange = (e) => { if (watch && name && type !== "submit") { watch((prev) => ({ ...prev, [name]: e.target.value, })); } if (rule) { if (name && rule && !blur) { validate({ [name]: e.target.value }, setInputError, { [name]: rule }); } } }; return (React.createElement("div", { className: `${Style.inputContainer} ${className} ${Object.keys(inputError).length > 0 && name && !checkRuleOnBlur ? Style.inputError : ""} ${error ? Style.inputError : ""} ${blur && name && inputError[name] ? Style.inputErrorBlur : ""} `, key: id, ...props }, label && (React.createElement("label", { htmlFor: id }, label, required && React.createElement("span", { className: Style.required }, "*"))), React.createElement("input", { type: inputType, id: id, className: "text-input", name: name, value: value, onChange: handleChange, required: required, placeholder: placeholder, onBlur: handleBlur, onFocus: () => setBlur(false), autoComplete: autoComplete }), error && React.createElement("span", { className: Style.error }, error), React.createElement("span", { className: Style.error }, inputError && name && !checkRuleOnBlur ? inputError[name] : "", blur && name && inputError[name] ? inputError[name] : ""))); }; const Password = ({ name, type, label, value, watch, error, className, required, placeholder, rule, checkRuleOnBlur, autoComplete, ...props }) => { const id = React.useId(); const [inputError, setInputError] = React.useState({}); const [blur, setBlur] = React.useState(!checkRuleOnBlur); const [eye, setEye] = React.useState(false); const [inputType, setInputType] = React.useState(type); const handleEye = () => { setEye(!eye); setInputType(!eye ? "text" : "password"); }; const handleBlur = (e) => { if (name && rule && checkRuleOnBlur) { validate({ [name]: e.target.value }, setInputError, { [name]: rule }); setBlur(true); } else { setBlur(false); } }; const handleChange = (e) => { if (watch && name && type !== "submit") { watch((prev) => ({ ...prev, [name]: e.target.value, })); } if (rule) { if (name && rule && !blur) { validate({ [name]: e.target.value }, setInputError, { [name]: rule }); } } }; return (React.createElement("div", { className: `${Style.inputContainer} ${className} ${Object.keys(inputError).length > 0 && name && !checkRuleOnBlur ? Style.inputError : ""} ${error ? Style.inputError : ""} ${blur && name && inputError[name] ? Style.inputErrorBlur : ""} `, key: id, ...props }, label && (React.createElement("label", { htmlFor: id }, label, required && React.createElement("span", { className: Style.required }, "*"))), React.createElement("div", { className: Style.passwordContainer }, React.createElement("input", { type: inputType, id: id, className: "text-input", name: name, value: value, onChange: handleChange, required: required, placeholder: placeholder, onBlur: handleBlur, onFocus: () => setBlur(false), autoComplete: autoComplete }), React.createElement("span", { className: `${Style.eye} ${eye ? Style.active : ""}`, onClick: handleEye }, eye ? (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", fill: "currentColor", className: "bi bi-eye", viewBox: "0 0 16 16" }, React.createElement("path", { d: "M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8M1.173 8a13 13 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5s3.879 1.168 5.168 2.457A13 13 0 0 1 14.828 8q-.086.13-.195.288c-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5s-3.879-1.168-5.168-2.457A13 13 0 0 1 1.172 8z" }), React.createElement("path", { d: "M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5M4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0" }))) : (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", fill: "currentColor", className: "bi bi-eye-slash", viewBox: "0 0 16 16" }, React.createElement("path", { d: "M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7 7 0 0 0-2.79.588l.77.771A6 6 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13 13 0 0 1 14.828 8q-.086.13-.195.288c-.335.48-.83 1.12-1.465 1.755q-.247.248-.517.486z" }), React.createElement("path", { d: "M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829zm-2.943 1.299.822.822a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829" }), React.createElement("path", { d: "M3.35 5.47q-.27.24-.518.487A13 13 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7 7 0 0 1 8 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238l.708.709zm10.296 8.884-12-12 .708-.708 12 12z" }))))), error && React.createElement("span", { className: Style.error }, error), React.createElement("span", { className: Style.error }, inputError && name && !checkRuleOnBlur ? inputError[name] : "", blur && name && inputError[name] ? inputError[name] : ""))); }; const Submit = ({ className, value, children, ...props }) => { return (React.createElement(React.Fragment, null, React.createElement("button", { type: "submit", ...props, className: `${Style.submit} ${className}` }, value, children))); }; exports.Form = Form; exports.Heading = Heading; exports.Input = Input; exports.Password = Password; exports.Submit = Submit; exports.validate = validate;