{"_id":"@carlosot2/react-form-control","_rev":"7-32adb11b3847e3942d61227255b15fce","name":"@carlosot2/react-form-control","dist-tags":{"latest":"1.0.6"},"versions":{"1.0.0":{"name":"@carlosot2/react-form-control","version":"1.0.0","keywords":["react","form","forms","query","hooks","typescript"],"license":"MIT","_id":"@carlosot2/react-form-control@1.0.0","maintainers":[{"name":"carlosot2","email":"vinicv07@gmail.com"}],"dist":{"shasum":"9eb49da1bf4041b00e788cef12cf7aa56b9770de","tarball":"https://registry.npmjs.org/@carlosot2/react-form-control/-/react-form-control-1.0.0.tgz","fileCount":15,"integrity":"sha512-ncFDBnw4k8U3EAz/e20+41ToVs+j/dJQwBqvQEvLYqZ2sicrsmiR+pq8RTz5rwJ7L2XWeqi7rfET4mT+xB/b5A==","signatures":[{"sig":"MEUCIQDQBwteC7VRZodDYuPpZ8E+9YrXAwWZFcPIbFkpUopbQgIgbvchjd9KxWq+0rB+BKd/hMxe25wQStPZVG5nveQZFlE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":12871},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","gitHead":"6fa453c32cf3bac148cb5503634654b7ce383ac3","scripts":{"build":"tsc","prepublishOnly":"npm run build"},"_npmUser":{"name":"carlosot2","email":"vinicv07@gmail.com"},"_npmVersion":"11.5.1","description":"React form controller with URL query synchronization.","directories":{},"_nodeVersion":"24.5.0","_hasShrinkwrap":false,"devDependencies":{"react":"^19.0.0","typescript":"^5.0.0","@types/react":"^19.0.0","react-router-dom":"^7.0.0"},"peerDependencies":{"react":">=18","react-router-dom":">=6"},"_npmOperationalInternal":{"tmp":"tmp/react-form-control_1.0.0_1786759738651_0.6041076126963554","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@carlosot2/react-form-control","version":"1.0.1","keywords":["react","form","forms","query","hooks","typescript"],"license":"MIT","_id":"@carlosot2/react-form-control@1.0.1","maintainers":[{"name":"carlosot2","email":"vinicv07@gmail.com"}],"dist":{"shasum":"1e9639f9715051d12cdfa982fea073e007c1f32d","tarball":"https://registry.npmjs.org/@carlosot2/react-form-control/-/react-form-control-1.0.1.tgz","fileCount":15,"integrity":"sha512-8AhxCSWan77v4QHYUup2r/L+vOQaEaJcTD6JLmCOlzZDJ+NRCHQEBZPu2r88ogg9nB7hj48dWT8waRwJ8BB6JA==","signatures":[{"sig":"MEQCIH/J81wjh33LEhc5y+6iV8dFE4weZZWme8AznoXaRuQvAiASqK3loydkvMYZ6L9+OZ+MBWyhzRwQcAHj7aDsC8UUHw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21561},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","gitHead":"946bcb4e46fae9a4826dc302e1a13e63c64a9074","scripts":{"build":"tsc","prepublishOnly":"npm run build"},"_npmUser":{"name":"carlosot2","email":"vinicv07@gmail.com"},"_npmVersion":"11.5.1","description":"React form controller with URL query synchronization.","directories":{},"_nodeVersion":"24.5.0","_hasShrinkwrap":false,"devDependencies":{"react":"^19.0.0","typescript":"^5.0.0","@types/react":"^19.0.0","react-router-dom":"^7.0.0"},"peerDependencies":{"react":">=18","react-router-dom":">=6"},"_npmOperationalInternal":{"tmp":"tmp/react-form-control_1.0.1_1786760384864_0.8340914742059036","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@carlosot2/react-form-control","version":"1.0.2","keywords":["react","form","forms","query","hooks","typescript"],"license":"MIT","_id":"@carlosot2/react-form-control@1.0.2","maintainers":[{"name":"carlosot2","email":"vinicv07@gmail.com"}],"dist":{"shasum":"e7c23e519b3419e28745c510600ece27d6638684","tarball":"https://registry.npmjs.org/@carlosot2/react-form-control/-/react-form-control-1.0.2.tgz","fileCount":15,"integrity":"sha512-9l1eNuF34vXROwQ5FatZCGcrp1q/ltsDns1Vdzj+8QMh4mMpgEPRVJTWOE+vfVze3KjmUze+1X4qremKbeNqqQ==","signatures":[{"sig":"MEYCIQCC98CoC4I6RG5fD2QQx8UDnQCpo3FFpyNfTFPP94BM7gIhANsqCwbEKTKksVMPSxgVytOM6u76f2WUr5rgIcJZpkr9","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21563},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","gitHead":"280d697432c79db7091ada2b2774dff235816f77","scripts":{"build":"tsc","prepublishOnly":"npm run build"},"_npmUser":{"name":"carlosot2","email":"vinicv07@gmail.com"},"_npmVersion":"11.5.1","description":"React form controller with URL query synchronization.","directories":{},"_nodeVersion":"24.5.0","_hasShrinkwrap":false,"devDependencies":{"react":"^19.0.0","typescript":"^5.0.0","@types/react":"^19.0.0","react-router-dom":"^7.0.0"},"peerDependencies":{"react":">=18","react-router-dom":">=6"},"_npmOperationalInternal":{"tmp":"tmp/react-form-control_1.0.2_1786760512869_0.7286404501184642","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@carlosot2/react-form-control","version":"1.0.3","keywords":["react","form","forms","query","hooks","typescript"],"license":"MIT","_id":"@carlosot2/react-form-control@1.0.3","maintainers":[{"name":"carlosot2","email":"vinicv07@gmail.com"}],"dist":{"shasum":"4740c1b9d658776ab9a401be23bda764dda9bd7b","tarball":"https://registry.npmjs.org/@carlosot2/react-form-control/-/react-form-control-1.0.3.tgz","fileCount":15,"integrity":"sha512-1sg0g4kBfDqph8Vk0GrW/zFWQKJI4xKMnrNRpVNvsxHrYFYKiUmppuET5gOX6lv17ozRDnmTbTzva3J1BSTOug==","signatures":[{"sig":"MEYCIQDgVil494Ivp3sqpbD8hf8y3hmJIF5ypMjjkN1hRHA0WQIhAPSMLkgSF0hw9un7TD084E5P9m7OX7TU6RkUYmmRoNuw","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":22583},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","gitHead":"9ebefa3be8b668a9b17b5b3832759e8145ba05fb","scripts":{"build":"tsc","prepublishOnly":"npm run build"},"_npmUser":{"name":"carlosot2","email":"vinicv07@gmail.com"},"_npmVersion":"11.5.1","description":"React form controller with URL query synchronization.","directories":{},"_nodeVersion":"24.5.0","_hasShrinkwrap":false,"devDependencies":{"react":"^19.0.0","typescript":"^5.0.0","@types/react":"^19.0.0","react-router-dom":"^7.0.0"},"peerDependencies":{"react":">=18","react-router-dom":">=6"},"_npmOperationalInternal":{"tmp":"tmp/react-form-control_1.0.3_1786761161048_0.3921323178951015","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@carlosot2/react-form-control","version":"1.0.4","keywords":["react","form","forms","query","hooks","typescript"],"license":"MIT","_id":"@carlosot2/react-form-control@1.0.4","maintainers":[{"name":"carlosot2","email":"vinicv07@gmail.com"}],"dist":{"shasum":"da9293d865e3e711a4ce23171e88e7fd3d5a5050","tarball":"https://registry.npmjs.org/@carlosot2/react-form-control/-/react-form-control-1.0.4.tgz","fileCount":15,"integrity":"sha512-Wlf4wKOadI3RirmBPRETL7QcB9LECvcEpB+kRW8EYk6ETR4GmNd3BBPbUhWAV2KO1ZY+vwZTENmku9DAQ3r7Iw==","signatures":[{"sig":"MEUCIQDd5j6Zy0ZDx1jAo4gpI3tz6VsQTcIaXEhNJIoETfV2wAIgfF0kLGLMQnVHRtonp7iDEWi2nsrLBetVweF83Cjh/1Y=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":22711},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","gitHead":"947f1466502c25181df393a7935fe9e43a79a871","scripts":{"build":"tsc","prepublishOnly":"npm run build"},"_npmUser":{"name":"carlosot2","email":"vinicv07@gmail.com"},"_npmVersion":"11.5.1","description":"React form controller with URL query synchronization.","directories":{},"_nodeVersion":"24.5.0","_hasShrinkwrap":false,"devDependencies":{"react":"^19.0.0","typescript":"^5.0.0","@types/react":"^19.0.0","react-router-dom":"^7.0.0"},"peerDependencies":{"react":">=18","react-router-dom":">=6"},"_npmOperationalInternal":{"tmp":"tmp/react-form-control_1.0.4_1786761509711_0.596728658333775","host":"s3://npm-registry-packages-npm-production"}},"1.0.5":{"name":"@carlosot2/react-form-control","version":"1.0.5","keywords":["react","form","forms","query","hooks","typescript"],"license":"MIT","_id":"@carlosot2/react-form-control@1.0.5","maintainers":[{"name":"carlosot2","email":"vinicv07@gmail.com"}],"dist":{"shasum":"daa571dd243f0edbe48cf6b89429a73bf981a8fa","tarball":"https://registry.npmjs.org/@carlosot2/react-form-control/-/react-form-control-1.0.5.tgz","fileCount":15,"integrity":"sha512-AppcZzm3rhjYgDQQTxvFCkKey5zON1wHMK4x+qIyGBqO1v7tDQYhA8Ci2vt9rosGN6jKelgKmTkV1qfW1d+nKg==","signatures":[{"sig":"MEYCIQC5yT+sHp2Ncz0lRenYZOhfdrKrNt8VBa3udJ0S4XKu1QIhALRQngiR8EUQTT+dLrZhjKgMBzR9G6oF/uELxwQiuTaw","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":22711},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","gitHead":"c017c6fff71ea8f17f0890230d039b001d38308e","scripts":{"build":"tsc","prepublishOnly":"npm run build"},"_npmUser":{"name":"carlosot2","email":"vinicv07@gmail.com"},"_npmVersion":"11.5.1","description":"React form controller with URL query synchronization.","directories":{},"_nodeVersion":"24.5.0","_hasShrinkwrap":false,"devDependencies":{"react":"^19.0.0","typescript":"^5.0.0","@types/react":"^19.0.0","react-router-dom":"^7.0.0"},"peerDependencies":{"react":">=18","react-router-dom":">=6"},"_npmOperationalInternal":{"tmp":"tmp/react-form-control_1.0.5_1788666508197_0.2564959576266621","host":"s3://npm-registry-packages-npm-production"}},"1.0.6":{"name":"@carlosot2/react-form-control","version":"1.0.6","description":"React form controller with URL query synchronization.","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","scripts":{"build":"tsc","prepublishOnly":"npm run build"},"peerDependencies":{"react":">=18","react-router-dom":">=6"},"devDependencies":{"@types/react":"^19.0.0","react":"^19.0.0","react-router-dom":"^7.0.0","typescript":"^5.0.0"},"keywords":["react","form","forms","query","hooks","typescript"],"license":"MIT","_id":"@carlosot2/react-form-control@1.0.6","gitHead":"243bd4c696dd127c2ae9957d5f3ceabf17373aad","_nodeVersion":"24.5.0","_npmVersion":"11.5.1","dist":{"integrity":"sha512-3pkrZSDZhKaAIyCK8pGMbhOvJPNFpSxJMlxkrnpmzwt08GpHA2Cg4hgLVmbCE9r5sZ8rZe9HcuGWTQQwg8ZBHg==","shasum":"db4de696566d45735e2e2a1037ba09dbe9256e44","tarball":"https://registry.npmjs.org/@carlosot2/react-form-control/-/react-form-control-1.0.6.tgz","fileCount":15,"unpackedSize":22743,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIEM/EGtDGOS8EJ//06sQKRoGdwDQkFbpGtpO2lK5JZ7gAiAYy3DvUeqeTdcuo3IsZmKDRrhPQWjUH7Cgs/BVA6IeRA=="}]},"_npmUser":{"name":"carlosot2","email":"vinicv07@gmail.com"},"directories":{},"maintainers":[{"name":"carlosot2","email":"vinicv07@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/react-form-control_1.0.6_1788667293378_0.23432148566030464"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-15T02:08:58.482Z","modified":"2026-09-06T04:01:33.682Z","1.0.0":"2026-08-15T02:08:58.801Z","1.0.1":"2026-08-15T02:19:45.004Z","1.0.2":"2026-08-15T02:21:53.003Z","1.0.3":"2026-08-15T02:32:41.221Z","1.0.4":"2026-08-15T02:38:29.856Z","1.0.5":"2026-09-06T03:48:28.306Z","1.0.6":"2026-09-06T04:01:33.525Z"},"license":"MIT","keywords":["react","form","forms","query","hooks","typescript"],"description":"React form controller with URL query synchronization.","maintainers":[{"name":"carlosot2","email":"vinicv07@gmail.com"}],"readme":"<div align=\"center\">\r\n\r\n# ⚡ React Form Control\r\n\r\n**A form controller for React with TypeScript support and URL query synchronization.**\r\n\r\nManage form state, input changes, submissions, debouncing and query parameters with a straightforward API.\r\n\r\n[![npm version](https://img.shields.io/npm/v/@carlosot2/react-form-control.svg)](https://www.npmjs.com/package/@carlosot2/react-form-control)\r\n[![npm downloads](https://img.shields.io/npm/dm/@carlosot2/react-form-control.svg)](https://www.npmjs.com/package/@carlosot2/react-form-control)\r\n[![GitHub](https://img.shields.io/badge/GitHub-Repository-black?logo=github)](https://github.com/CarlosOT2/react-form-control)\r\n[![license](https://img.shields.io/npm/l/@carlosot2/react-form-control.svg)](LICENSE)\r\n[![TypeScript](https://img.shields.io/badge/TypeScript-ready-3178C6)](https://www.typescriptlang.org/)\r\n\r\n</div>\r\n\r\n---\r\n\r\n## ✨ Features\r\n\r\n- 🎛️ Simple form state management\r\n- ⌨️ Automatic input change handling\r\n- ☑️ Built-in checkbox support with multiple values\r\n- 📤 Form submission controller\r\n- ⏱️ Optional debounced submission with `submitOnChange`\r\n- 🔗 URL query parameter synchronization\r\n- ↩️ Browser back/forward synchronization\r\n- 🧩 Generic TypeScript form types\r\n\r\n---\r\n\r\n## 📦 Installation\r\n\r\n```bash\r\nnpm install @carlosot2/react-form-control\r\n```\r\n\r\n---\r\n\r\n## 🚀 Basic Usage\r\n\r\nDefine the structure of your form:\r\n\r\n```ts\r\ntype SearchForm = {\r\n    name: string\r\n    author: string\r\n}\r\n```\r\n\r\nCreate the form controller:\r\n\r\n```tsx\r\nimport { useFormController } from '@carlosot2/react-form-control'\r\n\r\nfunction Search() {\r\n    const { InputsController, SubmitController } =\r\n        useFormController<SearchForm>({\r\n            handleSubmit\r\n        })\r\n\r\n    async function handleSubmit(data: SearchForm) {\r\n        console.log(data)\r\n    }\r\n\r\n    return (\r\n        <form onSubmit={SubmitController.onSubmit}>\r\n            <input\r\n                type=\"text\"\r\n                name=\"name\"\r\n                value={InputsController.data.name ?? ''}\r\n                onChange={InputsController.onChange}\r\n            />\r\n\r\n            <input\r\n                type=\"text\"\r\n                name=\"author\"\r\n                value={InputsController.data.author ?? ''}\r\n                onChange={InputsController.onChange}\r\n            />\r\n\r\n            <button type=\"submit\">\r\n                Search\r\n            </button>\r\n        </form>\r\n    )\r\n}\r\n```\r\n\r\nThe controller stores values using each input's `name` property.\r\n\r\nFor example:\r\n\r\n```ts\r\nInputsController.data\r\n```\r\n\r\ncould contain:\r\n\r\n```ts\r\n{\r\n    name: 'Dandadan',\r\n    author: 'Yukinobu Tatsu'\r\n}\r\n```\r\n\r\n---\r\n\r\n## 🎛️ InputsController\r\n\r\n`InputsController` is responsible for reading and updating form values.\r\n\r\n```ts\r\nconst { InputsController } = useFormController(...)\r\n```\r\n\r\nIt provides:\r\n\r\n```ts\r\nInputsController.data\r\nInputsController.onChange\r\nInputsController.changeValue\r\n```\r\n\r\n### `data`\r\n\r\nContains the current form values.\r\n\r\n```ts\r\nInputsController.data.name\r\nInputsController.data.author\r\n```\r\n\r\n### `onChange`\r\n\r\nPass it directly to supported inputs:\r\n\r\n```tsx\r\n<input\r\n    name=\"name\"\r\n    value={InputsController.data.name ?? ''}\r\n    onChange={InputsController.onChange}\r\n/>\r\n```\r\n\r\nThe input `name` is used as the key inside the form data.\r\n\r\n### `changeValue`\r\n\r\nUpdates a value manually without requiring an input event.\r\n\r\n```ts\r\nInputsController.changeValue('name', 'Dandadan')\r\n```\r\n\r\nThis is useful for:\r\n\r\n- custom components\r\n- clearing fields\r\n- buttons\r\n- manually controlled values\r\n- external state changes\r\n\r\nExample:\r\n\r\n```tsx\r\n<button\r\n    type=\"button\"\r\n    onClick={() => InputsController.changeValue('name', '')}\r\n>\r\n    Clear\r\n</button>\r\n```\r\n\r\n---\r\n\r\n## ☑️ Checkbox Support\r\n\r\nReact Form Control automatically handles checkbox values as arrays.\r\n\r\nUse the same `name` for checkboxes that belong to the same field:\r\n\r\n```tsx\r\n<input\r\n    type=\"checkbox\"\r\n    name=\"genres\"\r\n    value=\"action\"\r\n    checked={InputsController.data.genres?.includes('action') ?? false}\r\n    onChange={InputsController.onChange}\r\n/>\r\n\r\n<input\r\n    type=\"checkbox\"\r\n    name=\"genres\"\r\n    value=\"comedy\"\r\n    checked={InputsController.data.genres?.includes('comedy') ?? false}\r\n    onChange={InputsController.onChange}\r\n/>\r\n```\r\n\r\nWhen both options are selected, the form data will contain:\r\n\r\n```ts\r\n{\r\n    genres: ['action', 'comedy']\r\n}\r\n```\r\n\r\nSelecting an unchecked option adds its value to the array, while selecting an already checked option removes it.\r\n\r\nCheckbox values also work with **Query Control**, where repeated values are represented as repeated URL query parameters:\r\n\r\n```txt\r\n?genres=action&genres=comedy\r\n```\r\n\r\n---\r\n\r\n## 📤 SubmitController\r\n\r\n`SubmitController` provides the form submission handler.\r\n\r\n```tsx\r\n<form onSubmit={SubmitController.onSubmit}>\r\n```\r\n\r\nWhen the form is submitted, the current form data is passed to `handleSubmit`.\r\n\r\n```tsx\r\nconst { InputsController, SubmitController } =\r\n    useFormController<SearchForm>({\r\n        handleSubmit\r\n    })\r\n\r\nasync function handleSubmit(data: SearchForm) {\r\n    console.log(data)\r\n}\r\n```\r\n\r\n---\r\n\r\n## ⏱️ Automatic Submission\r\n\r\nEnable `submitOnChange` to automatically submit the form shortly after its values change.\r\n\r\n```tsx\r\nconst { InputsController } =\r\n    useFormController<SearchForm>({\r\n        handleSubmit,\r\n        submitOnChange: true\r\n    })\r\n```\r\n\r\nExample:\r\n\r\n```ts\r\nasync function handleSubmit(data: SearchForm) {\r\n    const response = await searchTitles(data)\r\n    console.log(response)\r\n}\r\n```\r\n\r\nThis is useful for:\r\n\r\n- search bars\r\n- filters\r\n- live search\r\n- dynamic results\r\n- auto-updating forms\r\n\r\nChanges are debounced to avoid submitting repeatedly while the user is still typing.\r\n\r\n---\r\n\r\n## 🔗 Query Control\r\n\r\nReact Form Control can synchronize form values with the URL query string.\r\n\r\nEnable it with:\r\n\r\n```tsx\r\nconst { InputsController, SubmitController } =\r\n    useFormController<SearchForm>({\r\n        queryControl: true,\r\n        handleQueryChange\r\n    })\r\n```\r\n\r\nThen define what should happen whenever the query changes:\r\n\r\n```ts\r\nasync function handleQueryChange(query: string) {\r\n    console.log(query)\r\n}\r\n```\r\n\r\nA form like:\r\n\r\n```ts\r\n{\r\n    name: 'Dandadan',\r\n    genres: ['action', 'comedy']\r\n}\r\n```\r\n\r\ncan produce:\r\n\r\n```txt\r\n?name=Dandadan&genres=action&genres=comedy\r\n```\r\n\r\n---\r\n\r\n## 🔄 Query Synchronization\r\n\r\nWith `queryControl` enabled, the controller keeps the form synchronized with the URL.\r\n\r\n```text\r\nForm Data\r\n    ↓\r\nURL Query\r\n    ↓\r\nBrowser History\r\n    ↓\r\nForm Data\r\n```\r\n\r\nThis includes browser navigation such as:\r\n\r\n- Back\r\n- Forward\r\n\r\nFor example:\r\n\r\n```txt\r\n/titles?name=naruto\r\n```\r\n\r\nthen:\r\n\r\n```txt\r\n/titles?name=bleach\r\n```\r\n\r\nIf the user presses Back, the form values are synchronized with:\r\n\r\n```txt\r\n?name=naruto\r\n```\r\n\r\n---\r\n\r\n## 🔎 Query Example\r\n\r\n```tsx\r\ntype Filters = {\r\n    name: string\r\n    genresIds: string[]\r\n}\r\n\r\nfunction SearchPage() {\r\n    const { InputsController, SubmitController } =\r\n        useFormController<Filters>({\r\n            queryControl: true,\r\n            handleQueryChange\r\n        })\r\n\r\n    async function handleQueryChange(query: string) {\r\n        const response = await fetch(`/api/titles?${query}`)\r\n        const data = await response.json()\r\n\r\n        console.log(data)\r\n    }\r\n\r\n    return (\r\n        <form onSubmit={SubmitController.onSubmit}>\r\n            <input\r\n                name=\"name\"\r\n                value={InputsController.data.name ?? ''}\r\n                onChange={InputsController.onChange}\r\n            />\r\n\r\n            <input\r\n                type=\"checkbox\"\r\n                name=\"genresIds\"\r\n                value=\"1\"\r\n                checked={\r\n                    InputsController.data.genresIds?.includes('1') ?? false\r\n                }\r\n                onChange={InputsController.onChange}\r\n            />\r\n\r\n            <input\r\n                type=\"checkbox\"\r\n                name=\"genresIds\"\r\n                value=\"2\"\r\n                checked={\r\n                    InputsController.data.genresIds?.includes('2') ?? false\r\n                }\r\n                onChange={InputsController.onChange}\r\n            />\r\n\r\n            <button type=\"submit\">\r\n                Search\r\n            </button>\r\n        </form>\r\n    )\r\n}\r\n```\r\n\r\n---\r\n\r\n## 🧩 TypeScript\r\n\r\nReact Form Control supports generic form types.\r\n\r\n```ts\r\ntype LoginForm = {\r\n    email: string\r\n    password: string\r\n}\r\n```\r\n\r\nPass the type to the hook:\r\n\r\n```ts\r\nconst { InputsController } =\r\n    useFormController<LoginForm>({\r\n        handleSubmit\r\n    })\r\n```\r\n\r\nNow:\r\n\r\n```ts\r\nInputsController.data.email\r\n```\r\n\r\nis typed as:\r\n\r\n```ts\r\nstring\r\n```\r\n\r\nand:\r\n\r\n```ts\r\nInputsController.data.password\r\n```\r\n\r\nis also typed as:\r\n\r\n```ts\r\nstring\r\n```\r\n\r\nThis allows the controller to stay generic while preserving the structure of each form.\r\n\r\n---\r\n\r\n## ⚙️ Configuration\r\n\r\n### Standard form\r\n\r\n```ts\r\nuseFormController({\r\n    handleSubmit\r\n})\r\n```\r\n\r\n### Automatic submit\r\n\r\n```ts\r\nuseFormController({\r\n    handleSubmit,\r\n    submitOnChange: true\r\n})\r\n```\r\n\r\n### Query-controlled form\r\n\r\n```ts\r\nuseFormController({\r\n    queryControl: true,\r\n    handleQueryChange\r\n})\r\n```\r\n\r\n### Query-controlled form with automatic updates\r\n\r\n```ts\r\nuseFormController({\r\n    queryControl: true,\r\n    handleQueryChange,\r\n    submitOnChange: true\r\n})\r\n```\r\n\r\n---\r\n\r\n## 📚 API\r\n\r\n### `useFormController<TData>()`\r\n\r\n```ts\r\nuseFormController<TData>(config)\r\n```\r\n\r\nReturns:\r\n\r\n```ts\r\n{\r\n    InputsController,\r\n    SubmitController\r\n}\r\n```\r\n\r\n### `InputsController`\r\n\r\n```ts\r\n{\r\n    data,\r\n    onChange,\r\n    changeValue\r\n}\r\n```\r\n\r\n### `SubmitController`\r\n\r\n```ts\r\n{\r\n    onSubmit\r\n}\r\n```\r\n\r\n---\r\n\r\n## 📄 License\r\n\r\nDistributed under the MIT License.\r\n","readmeFilename":"README.md"}