neumorphic-peripheral
Version:
A lightweight, framework-agnostic JavaScript/TypeScript library for beautiful neumorphic styling
300 lines (295 loc) • 10.6 kB
JavaScript
;
/**
* 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
)
`
};