UNPKG

aura-glass

Version:

A comprehensive glassmorphism design system for React applications with 142+ production-ready components

299 lines (297 loc) 8.62 kB
/** * Built-in validation rules */ const validationRules = { required: (message = 'This field is required') => ({ type: 'required', message, validator: value => { if (typeof value === 'string') return value.trim().length > 0; if (Array.isArray(value)) return value.length > 0; return value !== null && value !== undefined; } }), email: (message = 'Please enter a valid email address') => ({ type: 'email', message, validator: value => { if (!value) return true; // Let required rule handle empty values const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(value); } }), minLength: (min, message) => ({ type: 'min', value: min, message: message || `Must be at least ${min} characters`, validator: value => { if (!value) return true; return value.length >= min; } }), maxLength: (max, message) => ({ type: 'max', value: max, message: message || `Must be no more than ${max} characters`, validator: value => { if (!value) return true; return value.length <= max; } }), minValue: (min, message) => ({ type: 'min', value: min, message: message || `Must be at least ${min}`, validator: value => { if (value === null || value === undefined) return true; return value >= min; } }), maxValue: (max, message) => ({ type: 'max', value: max, message: message || `Must be no more than ${max}`, validator: value => { if (value === null || value === undefined) return true; return value <= max; } }), pattern: (regex, message) => ({ type: 'pattern', value: regex, message, validator: value => { if (!value) return true; return regex.test(value); } }), custom: (validator, message) => ({ type: 'custom', message, validator }), // Common patterns phone: (message = 'Please enter a valid phone number') => ({ type: 'pattern', value: /^[\+]?[1-9][\d]{0,15}$/, message, validator: value => { if (!value) return true; return /^[\+]?[1-9][\d]{0,15}$/.test(value.replace(/[\s\-\(\)]/g, '')); } }), url: (message = 'Please enter a valid URL') => ({ type: 'pattern', value: /^https?:\/\/.+/, message, validator: value => { if (!value) return true; try { new URL(value); return true; } catch { return false; } } }), strongPassword: (message = 'Password must contain at least 8 characters, including uppercase, lowercase, number, and special character') => ({ type: 'pattern', value: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/, message, validator: value => { if (!value) return true; return /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/.test(value); } }) }; /** * Validate a single field value against its rules */ const validateField = (value, rules) => { for (const rule of rules) { if (rule.validator && !rule.validator(value)) { return rule.message; } } return null; }; /** * Validate multiple fields */ const validateFields = (values, validation) => { const errors = {}; for (const [fieldId, rules] of Object.entries(validation)) { const fieldValue = values[fieldId]; const error = validateField(fieldValue, rules); if (error) { errors[fieldId] = error; } } return { isValid: Object.keys(errors).length === 0, errors }; }; /** * Common validation schemas */ const commonValidationSchemas = { userRegistration: { firstName: [validationRules.required()], lastName: [validationRules.required()], email: [validationRules.required(), validationRules.email()], password: [validationRules.required(), validationRules.strongPassword()], confirmPassword: [validationRules.required()], terms: [validationRules.required('You must accept the terms and conditions')] }, contactForm: { name: [validationRules.required()], email: [validationRules.required(), validationRules.email()], subject: [validationRules.required()], message: [validationRules.required(), validationRules.minLength(10)] }, profileUpdate: { displayName: [validationRules.required(), validationRules.minLength(2), validationRules.maxLength(50)], bio: [validationRules.maxLength(500)], website: [validationRules.url()], phone: [validationRules.phone()] }, passwordChange: { currentPassword: [validationRules.required()], newPassword: [validationRules.required(), validationRules.strongPassword()], confirmNewPassword: [validationRules.required()] } }; /** * Custom validation functions for common scenarios */ const customValidators = { passwordsMatch: (password, confirmPassword) => { return password === confirmPassword; }, uniqueEmail: async (email, checkFunction) => { if (!email) return true; return await checkFunction(email); }, fileSize: (file, maxSizeInMB) => { if (!file) return true; const maxSizeInBytes = maxSizeInMB * 1024 * 1024; return file.size <= maxSizeInBytes; }, fileType: (file, allowedTypes) => { if (!file) return true; return allowedTypes.some(type => { if (type.startsWith('.')) { return file.name.toLowerCase().endsWith(type.toLowerCase()); } return file.type.startsWith(type); }); }, dateRange: (date, minDate, maxDate) => { if (!date) return true; if (minDate && date < minDate) return false; if (maxDate && date > maxDate) return false; return true; }, creditCard: cardNumber => { if (!cardNumber) return true; // Remove spaces and dashes const cleanNumber = cardNumber.replace(/[\s-]/g, ''); // Check if it's all digits and proper length if (!/^\d{13,19}$/.test(cleanNumber)) return false; // Luhn algorithm let sum = 0; let isEven = false; for (let i = cleanNumber.length - 1; i >= 0; i--) { let digit = parseInt(cleanNumber[i]); if (isEven) { digit *= 2; if (digit > 9) { digit -= 9; } } sum += digit; isEven = !isEven; } return sum % 10 === 0; } }; /** * Async validation utilities */ const asyncValidation = { debounce: (func, delay) => { let timeoutId; return (...args) => { clearTimeout(timeoutId); return new Promise(resolve => { timeoutId = setTimeout(() => resolve(func(...args)), delay); }); }; }, createAsyncValidator: (asyncCheck, message, debounceMs = 500) => { const debouncedCheck = asyncValidation.debounce(asyncCheck, debounceMs); return async value => { if (!value) return null; try { const isValid = await debouncedCheck(value); return isValid ? null : message; } catch (error) { if (process.env.NODE_ENV === 'development') { console.error('Async validation error:', error); } return 'Validation failed. Please try again.'; } }; } }; /** * Form validation state manager */ class FormValidator { constructor(validationSchema = {}) { this.validationSchema = validationSchema; this.asyncValidators = {}; } setValidationSchema(schema) { this.validationSchema = schema; } addAsyncValidator(fieldId, validator) { this.asyncValidators[fieldId] = validator; } async validateForm(values) { // Sync validation const syncResult = validateFields(values, this.validationSchema); // Async validation const asyncErrors = {}; for (const [fieldId, validator] of Object.entries(this.asyncValidators)) { const fieldValue = values[fieldId]; const error = await validator(fieldValue); if (error) { asyncErrors[fieldId] = error; } } const allErrors = { ...syncResult.errors, ...asyncErrors }; return { isValid: Object.keys(allErrors).length === 0, errors: allErrors }; } async validateField(fieldId, value) { // Sync validation const rules = this.validationSchema[fieldId] || []; const syncError = validateField(value, rules); if (syncError) return syncError; // Async validation const asyncValidator = this.asyncValidators[fieldId]; if (asyncValidator) { return await asyncValidator(value); } return null; } } export { FormValidator, asyncValidation, commonValidationSchemas, customValidators, validateField, validateFields, validationRules }; //# sourceMappingURL=FormValidationUtils.js.map