npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@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-form

ValidationRule

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?): returns boolean | Promise<boolean>; ctx carries 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 for null, undefined, trimmed empty strings, or empty arrays.
  • minLength(len, message?): passes when value.length >= len.
  • maxLength(len, message?): passes when value.length <= len.
  • email(message?): basic email format check.
  • regex(pattern, message?): runs pattern.test on string values (stateful regexes are reset per call).
  • zodRule(schema, message?): uses schema.safeParse(value); returns false when 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>;
  • LumiaForm wraps FormProvider under the hood and wires onSubmit/onError into handleSubmit.
  • Types such as SubmitHandler plus utilities like useForm and Controller are 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), optional rules?: ValidationRule[], plus all pass-through DS Input props except value, onChange, invalid, and hint.
  • When any rule fails, invalid is set on the underlying Input and the failing rule message is shown in place of the hint.
  • When all rules pass, the hint (if provided) is restored and invalid is cleared.
  • Provide errorMessage to surface external errors (e.g., from react-hook-form submissions); it overrides inline validation and toggles the invalid state.