{"_id":"@ahrowe/form-validation","name":"@ahrowe/form-validation","dist-tags":{"latest":"0.2.0"},"versions":{"0.2.0":{"name":"@ahrowe/form-validation","version":"0.2.0","publishConfig":{"access":"public"},"description":"Framework-agnostic form validation core (FormValidator, FormValidatorGroup, validators) — the validation engine behind @ahrowe/ui","author":{"name":"AndreasWeinzierl"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/AndreasWeinzierl/ahrowe-form-validation.git"},"homepage":"https://github.com/AndreasWeinzierl/ahrowe-form-validation#readme","type":"module","main":"./dist/index.cjs","module":"./dist/esm/index.mjs","types":"./dist/types/index.d.ts","sideEffects":false,"exports":{".":{"import":"./dist/esm/index.mjs","require":"./dist/index.cjs","types":"./dist/types/index.d.ts"}},"scripts":{"build":"vite build --config vite.lib.config.ts","test":"vitest run","test:watch":"vitest","lint":"eslint .","lint:fix":"eslint . --fix","format":"prettier --write .","format:check":"prettier --check .","changeset":"changeset","release":"bash scripts/release.sh","verify-package":"bash scripts/verify-package.sh"},"peerDependencies":{"react":">=18.0.0"},"devDependencies":{"@changesets/cli":"^2.31.0","@eslint/js":"^9.39.4","@testing-library/react":"^16.3.2","@types/node":"^25.9.1","@types/react":"^19.2.15","@vitejs/plugin-react":"^6.0.2","eslint":"^9.39.4","eslint-config-prettier":"^10.1.8","eslint-plugin-react":"^7.37.5","eslint-plugin-react-hooks":"^7.1.1","globals":"^16.5.0","jsdom":"^29.1.1","prettier":"^3.8.3","react":"^19.2.6","typescript":"^6.0.3","typescript-eslint":"^8.60.0","vite":"^8.0.14","vite-plugin-dts":"^5.0.1","vitest":"^4.1.7"},"gitHead":"61fc083987fb026ec870e6997b0f56533984a2c7","_id":"@ahrowe/form-validation@0.2.0","bugs":{"url":"https://github.com/AndreasWeinzierl/ahrowe-form-validation/issues"},"_nodeVersion":"24.14.0","_npmVersion":"11.9.0","dist":{"integrity":"sha512-p1UA0KdHcQIkWtamfOkFV7XxypLaP9DNo+G8xxH1d/6Q0//47louOHHErjKIQyjWEyMdzCMID0HvKEWI5YHXug==","shasum":"96c29b7019bd19a75c75cd5d00c59366c1787b63","tarball":"https://registry.npmjs.org/@ahrowe/form-validation/-/form-validation-0.2.0.tgz","fileCount":28,"unpackedSize":114795,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBxhrtpk0hGQk2Ka0bPZr4/RNC8Sojv/SDIVyo+zwfeHAiEA70EwOFnzFIK3GG8qh7pqNcX2eMwIKOzLb7xy/HEpPqc="}]},"_npmUser":{"name":"plaguedoctor19","email":"ahrowe.dev@gmail.com"},"directories":{},"maintainers":[{"name":"plaguedoctor19","email":"ahrowe.dev@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/form-validation_0.2.0_1784138634516_0.545442908275726"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-15T18:03:54.235Z","0.2.0":"2026-07-15T18:03:54.669Z","modified":"2026-07-15T18:03:55.384Z"},"maintainers":[{"name":"plaguedoctor19","email":"ahrowe.dev@gmail.com"}],"description":"Framework-agnostic form validation core (FormValidator, FormValidatorGroup, validators) — the validation engine behind @ahrowe/ui","homepage":"https://github.com/AndreasWeinzierl/ahrowe-form-validation#readme","repository":{"type":"git","url":"git+https://github.com/AndreasWeinzierl/ahrowe-form-validation.git"},"author":{"name":"AndreasWeinzierl"},"bugs":{"url":"https://github.com/AndreasWeinzierl/ahrowe-form-validation/issues"},"license":"MIT","readme":"# @ahrowe/form-validation\n\nFramework-agnostic form validation core — `FormValidator`, `FormValidatorGroup`, built-in `Validators`, and the `useFormValidator` / `useFormValidatorGroup` hooks. This is the validation engine behind [`@ahrowe/ui`](https://github.com/AndreasWeinzierl/ahrowe-ui); it has no dependency on any UI component library and can be used standalone.\n\n```bash\nnpm install @ahrowe/form-validation\n```\n\n```ts\nimport { FormValidator, Validators } from '@ahrowe/form-validation';\n\nconst nameValidator = new FormValidator('', [Validators.required(), Validators.minLength(2)]);\n```\n\n### FormValidatorGroup\n\n```ts\nimport { FormValidator, FormValidatorGroup, Validators } from '@ahrowe/form-validation';\n\nconst userForm = new FormValidatorGroup(\n  {\n    name: new FormValidator('', [Validators.required()]),\n    email: new FormValidator('', [Validators.required(), Validators.email()]),\n  },\n  null, // class component instance, or null when not using class components\n  {\n    initialValues: { name: 'Jane' },\n    onSubmit: async (values) => {\n      await api.saveUser(values); // values: { name: string; email: string }\n    },\n  }\n);\n\nuserForm.group.name.set('Jane Doe');\nawait userForm.submit(); // validates all fields, then calls onSubmit if there are no errors\n```\n\n### useFormValidator\n\n```tsx\nimport { FormValidator, Validators, useFormValidator } from '@ahrowe/form-validation';\nimport { useRef } from 'react';\n\nfunction EmailField() {\n  const email = useFormValidator(\n    useRef(new FormValidator('', [Validators.required(), Validators.email()])).current\n  );\n\n  return (\n    <div>\n      {/* {...email.bind()} spreads name/value/onChange/onBlur directly onto the input */}\n      <input {...email.bind()} />\n      {email.touched && email.hasError() && <span>{email.getCurrentErrorMessage()}</span>}\n    </div>\n  );\n}\n```\n\n`bind()` (on `FormValidator`) returns props spreadable directly onto a native `input`/`textarea`/`select`, react-hook-form-`register`-style: `name`, `onChange`, `onBlur`, and either `value` or — for boolean fields such as checkboxes — `checked`. It also coerces numeric fields (`FormValidator<number>`) and reads `<select multiple>` as `string[]`. It doesn't support radio groups (each option needs its own `checked`, derived by equality) — wire those by hand.\n\n```tsx\nconst agreedToTerms = new FormValidator(false);\n\n<input type=\"checkbox\" {...agreedToTerms.bind('agreedToTerms')} />\n// checked=false, value omitted; name is required here since agreedToTerms\n// isn't in a FormValidatorGroup (which is what defaults `label`, and\n// therefore `bind()`'s default name, to the group key)\n\nconst email = new FormValidator('');\n\n<input {...email.bind('email')} />\n// value='', checked omitted; name defaults to `label` if omitted\n```\n\n### useFormValidatorGroup\n\n```tsx\nimport { FormValidator, Validators, useFormValidatorGroup } from '@ahrowe/form-validation';\n\nfunction SignupForm() {\n  const userForm = useFormValidatorGroup(\n    {\n      name: new FormValidator('', [Validators.required()]),\n      email: new FormValidator('', [Validators.required(), Validators.email()]),\n    },\n    {\n      onSubmit: async (values) => {\n        await api.saveUser(values);\n      },\n    }\n  );\n\n  return (\n    <form onSubmit={userForm.submit}>\n      <input\n        value={userForm.group.name.value}\n        onChange={(e) => userForm.group.name.set(e.target.value)}\n      />\n      <input\n        value={userForm.group.email.value}\n        onChange={(e) => userForm.group.email.set(e.target.value)}\n      />\n      <button type=\"submit\" disabled={userForm.isSubmitting}>Submit</button>\n    </form>\n  );\n}\n```\n\nSee `CLAUDE.md` for conventions and `src/index.ts` for the full public API.\n\n## Scripts\n\n```bash\nnpm test          # single run\nnpm run test:watch\nnpm run build      # emits dist/ (esm + cjs + d.ts)\nnpm run lint\n```\n\n## Relationship to @ahrowe/ui\n\n`@ahrowe/ui` re-exports everything here plus a thin adapter layer (`ValidatableComponent`, a toast-and-`.Form`-wired `FormValidatorGroup`) that depends on its own UI components (`Tooltip`, `showToast`).\n","readmeFilename":"README.md","_rev":"1-720ef80ee3ab5874ab15841d8c6262ff"}