{"_id":"@asnewyla/form","_rev":"3-aad1706a2a8460293566e7c877ccdd9d","name":"@asnewyla/form","dist-tags":{"latest":"0.2.2"},"versions":{"0.2.0":{"name":"@asnewyla/form","version":"0.2.0","keywords":["react","form","validation","accessible"],"license":"MIT","_id":"@asnewyla/form@0.2.0","maintainers":[{"name":"asnewyla","email":"asnewyla@gmail.com"}],"dist":{"shasum":"5f4feaeb0caf6d54e1c74c0960ce80c32668f4d9","tarball":"https://registry.npmjs.org/@asnewyla/form/-/form-0.2.0.tgz","fileCount":9,"integrity":"sha512-EYHbCwKT16fnG5PjSo7WXvbIoQRJBJGY/3CTbayB0ukLEOukt6i/Af59AKMeL2iCHsaCDSio+RS4XTOZ1VuySg==","signatures":[{"sig":"MEUCIQD7oAMCjQIScjsBLx9MFHKUiXcphlciAt/hgDL5xHq2wgIgDxvfI/ASIAXfCtsvYcD8xoj9Q3OLWhm58MEGyvVCAaw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":56308},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"scripts":{"test":"vitest run","build":"tsup","test:watch":"vitest","type-check":"tsc --noEmit","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"asnewyla","email":"asnewyla@gmail.com"},"repository":{"url":"git+https://github.com/xavierDelaFuente/xd-components.git","type":"git","directory":"packages/form"},"description":"Form wrapper with real validation and an accessible error summary","directories":{},"_nodeVersion":"24.19.0","dependencies":{"@asnewyla/input":"0.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.1.0","jsdom":"^24.0.0","react":"^18.3.0","vitest":"^2.0.0","react-dom":"^18.3.0","typescript":"^5.5.0","@vitest/coverage-v8":"^2.0.0","@testing-library/react":"^16.0.0","@testing-library/jest-dom":"^6.4.0","@testing-library/user-event":"^14.5.0"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/form_0.2.0_1787420673171_0.25558180438097544","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@asnewyla/form","version":"0.2.1","keywords":["react","form","validation","accessible"],"license":"MIT","_id":"@asnewyla/form@0.2.1","maintainers":[{"name":"asnewyla","email":"asnewyla@gmail.com"}],"dist":{"shasum":"f0dc6af637ea9cc5fbf3ee5714cb2367dfd0532f","tarball":"https://registry.npmjs.org/@asnewyla/form/-/form-0.2.1.tgz","fileCount":11,"integrity":"sha512-JP3p1Klk8CI/CdiZFDbsymipNjBmkl9+bAXBn3JK+7oKiF1cdkuLNq7ip4xlVZl5NzEOwQz2o9YgQrIOlT5/fQ==","signatures":[{"sig":"MEQCIG3w/s2ZQdUbY2NcBwXFvVZJo0PhLQShZkmfg8IptU4ZAiAauQTWmhdLyUPS5X1S3paEd6znd6W9N/c2jRVle51lgw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":57812},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./styles.css":"./dist/index.css"},"scripts":{"test":"vitest run","build":"tsup","test:watch":"vitest","type-check":"tsc --noEmit","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"asnewyla","email":"asnewyla@gmail.com"},"repository":{"url":"git+https://github.com/xavierDelaFuente/xd-components.git","type":"git","directory":"packages/form"},"description":"Form wrapper with real validation and an accessible error summary","directories":{},"sideEffects":["*.css"],"_nodeVersion":"24.19.0","dependencies":{"@asnewyla/input":"0.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.1.0","jsdom":"^24.0.0","react":"^18.3.0","vitest":"^2.0.0","react-dom":"^18.3.0","typescript":"^5.5.0","@vitest/coverage-v8":"^2.0.0","@testing-library/react":"^16.0.0","@testing-library/jest-dom":"^6.4.0","@testing-library/user-event":"^14.5.0"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/form_0.2.1_1787434555938_0.9483107311968262","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@asnewyla/form","version":"0.2.2","description":"Form wrapper with real validation and an accessible error summary","license":"MIT","repository":{"type":"git","url":"git+https://github.com/xavierDelaFuente/xd-components.git","directory":"packages/form"},"publishConfig":{"access":"public"},"main":"dist/index.js","module":"dist/index.mjs","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./styles.css":"./dist/index.css","./test-utils":{"types":"./dist/test-utils.d.ts","import":"./dist/test-utils.mjs","require":"./dist/test-utils.js"}},"sideEffects":["*.css"],"keywords":["react","form","validation","accessible"],"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0","@testing-library/react":"^16.0.0","@testing-library/user-event":"^14.5.0"},"peerDependenciesMeta":{"@testing-library/react":{"optional":true},"@testing-library/user-event":{"optional":true}},"dependencies":{"@asnewyla/input":"0.2.1"},"devDependencies":{"@testing-library/jest-dom":"^6.4.0","@testing-library/react":"^16.0.0","@testing-library/user-event":"^14.5.0","@vitest/coverage-v8":"^2.0.0","jsdom":"^24.0.0","react":"^18.3.0","react-dom":"^18.3.0","tsup":"^8.1.0","typescript":"^5.5.0","vitest":"^2.0.0"},"scripts":{"build":"tsup","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","type-check":"tsc --noEmit"},"_nodeVersion":"24.19.0","_id":"@asnewyla/form@0.2.2","dist":{"integrity":"sha512-mkFV4t4OV24mN/7kHOTleD7TBeVT6i3kfGonBz0LvAN0+SQoIpUqCmXFovnwnSeYmPsXTNKIvdY8V5xMPv5/ZQ==","shasum":"ff6c307a0383a79a21b8e0ed96345f8664243698","tarball":"https://registry.npmjs.org/@asnewyla/form/-/form-0.2.2.tgz","fileCount":17,"unpackedSize":63557,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCICwnVUoSoxK9gV7m3N8YMbnTuA062NfmhGUjysdskdSWAiEA2ONOXIQgkE+8jfs9N59E4aQQ8SrPbICF4BfNsZQbe0c="}]},"_npmUser":{"name":"asnewyla","email":"asnewyla@gmail.com"},"directories":{},"maintainers":[{"name":"asnewyla","email":"asnewyla@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/form_0.2.2_1787860430093_0.7311396847015941"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-22T17:44:32.999Z","modified":"2026-08-27T19:53:50.412Z","0.2.0":"2026-08-22T17:44:33.318Z","0.2.1":"2026-08-22T21:35:56.102Z","0.2.2":"2026-08-27T19:53:50.233Z"},"license":"MIT","keywords":["react","form","validation","accessible"],"repository":{"type":"git","url":"git+https://github.com/xavierDelaFuente/xd-components.git","directory":"packages/form"},"description":"Form wrapper with real validation and an accessible error summary","maintainers":[{"name":"asnewyla","email":"asnewyla@gmail.com"}],"readme":"# @asnewyla/form\r\n\r\nForm wrapper with real client-side validation, an accessible error summary,\r\nand native `<form>` submission semantics.\r\n\r\n## Install\r\n\r\n```bash\r\nnpm install @asnewyla/form @asnewyla/input\r\n```\r\n\r\n`FormFieldInput` renders `@asnewyla/input`'s `Input` under the hood, so its\r\nstylesheet also needs importing once, alongside `@asnewyla/form`'s own\r\n(which styles the error summary):\r\n\r\n```ts\r\nimport '@asnewyla/form/styles.css';\r\nimport '@asnewyla/input/styles.css';\r\n```\r\n\r\n## Usage\r\n\r\n```tsx\r\nimport { Form, FormFieldInput } from '@asnewyla/form';\r\n\r\n<Form onSubmit={(values) => console.log(values)}>\r\n  <FormFieldInput label=\"Email\" name=\"email\" required pattern=\"^\\S+@\\S+$\" />\r\n  <FormFieldInput label=\"Password\" name=\"password\" required minLength={8} />\r\n  <button type=\"submit\">Submit</button>\r\n</Form>\r\n```\r\n\r\n`Form` validates on blur and on submit, blocks `onSubmit` while any field is\r\ninvalid, and reads submitted values via native `FormData` — there's no\r\nduplicated value state to keep in sync.\r\n\r\n### `FormFieldInput`\r\n\r\nUse `FormFieldInput`, not a plain `Input`, for any field you want `Form` to\r\nregister, validate, and collect. It accepts every `Input` prop plus a\r\nrequired `name` and a small validation-rule vocabulary:\r\n\r\n| Prop | Type | Notes |\r\n|---|---|---|\r\n| `name` | `string` (**required**) | Native `name`, also the key in `onSubmit`'s payload |\r\n| `required` | `boolean \\| string` | A string overrides the default error message |\r\n| `pattern` | `string` | Regex source text, matching the native `<input pattern>` attribute |\r\n| `minLength` / `maxLength` | `number` | |\r\n| `min` / `max` | `string \\| number` | Matching the native `<input min>`/`<input max>` attributes |\r\n| `validate` | `(value: string) => string \\| undefined` | Custom sync validator, runs after every other rule passes |\r\n\r\nRules run in that order — `required` → `pattern` → `minLength` → `maxLength`\r\n→ `min` → `max` → `validate` — and the first one that fails wins; only one\r\nerror message shows per field.\r\n\r\nUsed outside a `Form`, `FormFieldInput` still renders correctly — it's a\r\nnormal `Input` with no ancestor to register with, and the native attributes\r\n(`required`, `pattern`, etc.) still reach the underlying `<input>`.\r\n\r\nA plain `Input` (not `FormFieldInput`) placed inside a `Form` is never\r\nregistered or validated, but its value is still collected into `onSubmit`'s\r\npayload if it has a `name` — `Form` reads values via native `FormData`,\r\nwhich picks up any named form control regardless of registration. This is\r\nintentional, native `<form>` behavior, not a gap `FormFieldInput` needs to\r\nclose.\r\n\r\n### Error display\r\n\r\nBoth an inline message and a summary show for an invalid field, not either:\r\n\r\n- Each `FormFieldInput` shows its own inline error, linked via\r\n  `aria-describedby` — the same as a plain `Input`.\r\n- `Form` additionally renders an error summary once a submit attempt has\r\n  failed: `role=\"alert\"`, one link per invalid field pointing at that\r\n  field's real `id`, and focus moved to the summary on every failed submit.\r\n  Clicking a link moves focus to the corresponding field. The summary stays\r\n  in sync with corrections made afterward (including via blur) and\r\n  disappears once no errors remain — it doesn't require resubmitting to\r\n  update or go away.\r\n\r\nThe summary only appears after a submit has actually been attempted — a\r\nfield that's invalid purely from blur-driven validation (nobody has tried\r\nto submit yet) shows its own inline error only.\r\n\r\n### Props\r\n\r\n| Prop | Type |\r\n|---|---|\r\n| `children` | `React.ReactNode` (**required**) |\r\n| `onSubmit` | `(values: Record<string, string>) => void` (**required**) |\r\n\r\n## License\r\n\r\nMIT\r\n","readmeFilename":""}