UNPKG

neumorphic-peripheral

Version:

A lightweight, framework-agnostic JavaScript/TypeScript library for beautiful neumorphic styling

300 lines (295 loc) 10.6 kB
"use strict"; /** * Zod Validation Adapter for Neumorphic Peripheral * * This adapter allows you to use Zod schemas for validation * Install: npm install zod * * Usage: * import { z } from 'zod' * import { zodAdapter } from 'neumorphic-peripheral/adapters/zod' * * const schema = z.string().email().min(5) * np.input(element, { validate: zodAdapter(schema) }) */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.examples = exports.zodIntegration = exports.ZodFormValidator = exports.zodSchemas = void 0; exports.zodAdapter = zodAdapter; exports.zodAdapterDetailed = zodAdapterDetailed; exports.createZodFormValidator = createZodFormValidator; /** * Creates a validation function from a Zod schema */ function zodAdapter(schema) { return (value) => { try { schema.parse(value); return null; // Valid } catch (error) { // Extract first error message from Zod error if (error?.errors && Array.isArray(error.errors) && error.errors.length > 0) { return error.errors[0].message; } return 'Invalid value'; } }; } /** * Creates a comprehensive validation function that returns all errors */ function zodAdapterDetailed(schema) { return (value) => { try { schema.parse(value); return { isValid: true, errors: [] }; } catch (error) { const errors = []; if (error?.errors && Array.isArray(error.errors)) { errors.push(...error.errors.map((err) => err.message)); } else { errors.push('Invalid value'); } return { isValid: false, errors }; } }; } /** * Schema builder utilities for common patterns */ exports.zodSchemas = { email: () => { // Dynamic import to avoid bundling issues return Promise.resolve().then(() => __importStar(require('zod'))).then(({ z }) => z.string().email('Please enter a valid email address')); }, password: (minLength = 8) => { return Promise.resolve().then(() => __importStar(require('zod'))).then(({ z }) => z.string() .min(minLength, `Password must be at least ${minLength} characters`) .regex(/[A-Z]/, 'Password must contain at least one uppercase letter') .regex(/[a-z]/, 'Password must contain at least one lowercase letter') .regex(/[0-9]/, 'Password must contain at least one number') .regex(/[^A-Za-z0-9]/, 'Password must contain at least one special character')); }, phone: () => { return Promise.resolve().then(() => __importStar(require('zod'))).then(({ z }) => z.string().regex(/^\+?[1-9]\d{1,14}$/, 'Please enter a valid phone number')); }, url: () => { return Promise.resolve().then(() => __importStar(require('zod'))).then(({ z }) => z.string().url('Please enter a valid URL')); }, required: (message = 'This field is required') => { return Promise.resolve().then(() => __importStar(require('zod'))).then(({ z }) => z.string().min(1, message)); } }; /** * Form-level validation using Zod */ class ZodFormValidator { constructor(schema) { this.fields = new Map(); this.schema = schema; } /** * Register a field with its schema key */ registerField(element, key) { this.fields.set(element, key); } /** * Validate a specific field */ validateField(element) { const key = this.fields.get(element); if (!key) { return { isValid: true, errors: [] }; } const value = this.getElementValue(element); try { // Validate just this field by picking from schema const fieldSchema = this.schema.pick({ [key]: true }); fieldSchema.parse({ [key]: value }); return { isValid: true, errors: [] }; } catch (error) { const errors = []; if (error?.errors && Array.isArray(error.errors)) { errors.push(...error.errors.map((err) => err.message)); } return { isValid: false, errors }; } } /** * Validate entire form */ validateForm() { const formData = {}; const errors = {}; // Collect all field values this.fields.forEach((key, element) => { formData[key] = this.getElementValue(element); }); try { const validatedData = this.schema.parse(formData); return { isValid: true, errors: {}, data: validatedData }; } catch (error) { if (error?.errors && Array.isArray(error.errors)) { error.errors.forEach((err) => { const path = err.path.join('.'); if (!errors[path]) { errors[path] = []; } errors[path].push(err.message); }); } return { isValid: false, errors }; } } getElementValue(element) { if (element instanceof HTMLInputElement) { if (element.type === 'checkbox') { return element.checked; } if (element.type === 'number') { return element.value ? Number(element.value) : undefined; } return element.value; } if (element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement) { return element.value; } return element.textContent || ''; } } exports.ZodFormValidator = ZodFormValidator; /** * Helper function to create form validator */ function createZodFormValidator(schema) { return new ZodFormValidator(schema); } /** * Integration with neumorphic components */ exports.zodIntegration = { /** * Setup form validation with Zod schema */ async setupForm(formElement, schema, components) { const validator = new ZodFormValidator(schema); // Register all components with their field names Object.entries(components).forEach(([key, component]) => { if (component && component.element) { validator.registerField(component.element, key); // Setup real-time validation component.element.addEventListener('blur', () => { const result = validator.validateField(component.element); if (!result.isValid && component.clearErrors && component.validate) { component.clearErrors(); // Create a validation function that returns the Zod result component.validate = () => result; } }); } }); // Setup form submission validation formElement.addEventListener('submit', (e) => { e.preventDefault(); const result = validator.validateForm(); if (result.isValid) { // Form is valid, can submit const event = new CustomEvent('np:form-valid', { detail: { data: result.data } }); formElement.dispatchEvent(event); } else { // Show field-specific errors Object.entries(result.errors).forEach(([fieldName, fieldErrors]) => { const component = components[fieldName]; if (component && component.clearErrors) { component.clearErrors(); // Set custom validation result component._validationResult = { isValid: false, errors: fieldErrors }; component.updateValidationState?.(); } }); const event = new CustomEvent('np:form-invalid', { detail: { errors: result.errors } }); formElement.dispatchEvent(event); } }); return validator; } }; // Example usage documentation exports.examples = { basicField: ` import { z } from 'zod' import { zodAdapter } from 'neumorphic-peripheral/adapters/zod' const emailSchema = z.string().email().min(5) np.input(emailElement, { validate: zodAdapter(emailSchema) }) `, complexForm: ` import { z } from 'zod' import { zodIntegration } from 'neumorphic-peripheral/adapters/zod' const formSchema = z.object({ email: z.string().email(), password: z.string().min(8), confirmPassword: z.string() }).refine(data => data.password === data.confirmPassword, { message: "Passwords don't match", path: ["confirmPassword"] }) const components = { email: np.input(emailEl), password: np.password(passwordEl), confirmPassword: np.password(confirmEl) } const validator = await zodIntegration.setupForm( formElement, formSchema, components ) ` };