@lumia-ui/forms
v0.1.0
Published
Form validation utilities for Lumia DS
Downloads
85
Readme
@lumia-ui/forms
Validation helpers and React Hook Form wiring for Lumia components.
Install
pnpm add @lumia-ui/forms react-hook-formValidationRule
import type { ValidationRule, ValidationContext } from '@lumia-ui/forms';
type EmailCtx = ValidationContext & { blockedDomains: string[] };
export const emailNotBlocked: ValidationRule<string, EmailCtx> = {
name: 'email-not-blocked',
message: 'Domain is blocked',
validate: async (value, ctx) => {
const domain = value.split('@')[1];
return domain ? !ctx?.blockedDomains.includes(domain) : false;
},
};name: unique identifier for the rule.message: user-facing error text.validate(value, ctx?): returnsboolean | Promise<boolean>;ctxcarries cross-field data.
Built-in validation helpers
import {
required,
minLength,
maxLength,
email,
regex,
zodRule,
} from '@lumia-ui/forms';
import { z } from 'zod';
// All helpers accept an optional custom message
const mustHaveName = required();
const atLeast3Chars = minLength(3);
const upTo10Chars = maxLength(10);
const mustBeEmail = email();
const postalCodePattern = regex(/^[A-Z]{3}\\d{2}$/);
const mustMatchSchema = zodRule(z.object({ name: z.string().min(1) }));required(message?): fails fornull,undefined, trimmed empty strings, or empty arrays.minLength(len, message?): passes whenvalue.length >= len.maxLength(len, message?): passes whenvalue.length <= len.email(message?): basic email format check.regex(pattern, message?): runspattern.teston string values (stateful regexes are reset per call).zodRule(schema, message?): usesschema.safeParse(value); returnsfalsewhen parsing fails and reports the provided message or"Invalid value."by default.
LumiaForm (react-hook-form)
@lumia-ui/forms ships a <LumiaForm> wrapper and re-exports React Hook Form helpers to wire DS inputs into react-hook-form.
import {
Controller,
LumiaForm,
SubmitHandler,
ValidatedInput,
required,
useForm,
} from '@lumia-ui/forms';
type ProfileForm = { email: string };
const methods = useForm<ProfileForm>({
defaultValues: { email: '' },
});
const onSubmit: SubmitHandler<ProfileForm> = (values) => {
console.log(values);
};
<LumiaForm methods={methods} onSubmit={onSubmit}>
{({ control }) => (
<>
<Controller
name="email"
control={control}
rules={{ required: 'Email is required' }}
render={({ field, fieldState }) => (
<ValidatedInput
{...field}
ref={field.ref}
value={field.value ?? ''}
onChange={(next) => field.onChange(next)}
onBlur={field.onBlur}
errorMessage={fieldState.error?.message}
hint="Work email"
rules={[required('Email is required')]}
/>
)}
/>
<button type="submit">Submit</button>
</>
)}
</LumiaForm>;LumiaFormwrapsFormProviderunder the hood and wiresonSubmit/onErrorintohandleSubmit.- Types such as
SubmitHandlerplus utilities likeuseFormandControllerare re-exported from@lumia-ui/forms.
ValidatedInput
ValidatedInput wraps the DS Input component and runs a list of ValidationRules on change/blur, showing the first failing rule's message as the error hint.
import { ValidatedInput, required, minLength } from '@lumia-ui/forms';
const rules = [required('Name is required'), minLength(3, 'Too short')];
<ValidatedInput
value={name}
onChange={setName}
rules={rules}
placeholder="Full name"
hint="Enter your full legal name"
/>;- Props:
value: string,onChange(value: string), optionalrules?: ValidationRule[], plus all pass-through DSInputprops exceptvalue,onChange,invalid, andhint. - When any rule fails,
invalidis set on the underlyingInputand the failing rule message is shown in place of the hint. - When all rules pass, the hint (if provided) is restored and
invalidis cleared. - Provide
errorMessageto surface external errors (e.g., fromreact-hook-formsubmissions); it overrides inline validation and toggles theinvalidstate.
