{"id":25000149,"url":"https://github.com/thinkmill/pragmatic-forms","last_synced_at":"2025-10-10T21:40:22.494Z","repository":{"id":57166284,"uuid":"98831227","full_name":"Thinkmill/pragmatic-forms","owner":"Thinkmill","description":"A pragmatic approach to forms in React","archived":false,"fork":false,"pushed_at":"2019-01-16T05:20:58.000Z","size":298,"stargazers_count":10,"open_issues_count":1,"forks_count":1,"subscribers_count":24,"default_branch":"master","last_synced_at":"2025-10-01T06:38:04.165Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Thinkmill.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-07-30T23:45:00.000Z","updated_at":"2024-01-13T23:57:03.000Z","dependencies_parsed_at":"2022-08-30T14:10:31.139Z","dependency_job_id":null,"html_url":"https://github.com/Thinkmill/pragmatic-forms","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/Thinkmill/pragmatic-forms","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thinkmill%2Fpragmatic-forms","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thinkmill%2Fpragmatic-forms/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thinkmill%2Fpragmatic-forms/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thinkmill%2Fpragmatic-forms/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Thinkmill","download_url":"https://codeload.github.com/Thinkmill/pragmatic-forms/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thinkmill%2Fpragmatic-forms/sbom","scorecard":{"id":140899,"data":{"date":"2025-08-11","repo":{"name":"github.com/Thinkmill/pragmatic-forms","commit":"17255f2cd5458d02e5302cdc0ce9698ade461f9c"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.4,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":1,"reason":"Found 2/15 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 19 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"133 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-6chw-6frg-f759","Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw","Warn: Project is vulnerable to: GHSA-whgm-jr23-g3j9","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-fwr7-v2mv-hh25","Warn: Project is vulnerable to: GHSA-qwcr-r2fm-qrc7","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-cwfw-4gq5-mrqx","Warn: Project is vulnerable to: GHSA-g95f-p29q-9xw4","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-x9w5-v3q2-3rhw","Warn: Project is vulnerable to: GHSA-w8qv-6jwh-64r5","Warn: Project is vulnerable to: GHSA-pxg6-pf52-xh8x","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-p28h-cc7q-c4fg","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-3wcq-x3mq-6r9p","Warn: Project is vulnerable to: GHSA-vh7m-p724-62c2","Warn: Project is vulnerable to: GHSA-r9p9-mrjm-926w","Warn: Project is vulnerable to: GHSA-434g-2637-qmqr","Warn: Project is vulnerable to: GHSA-49q7-c7j4-3p7m","Warn: Project is vulnerable to: GHSA-977x-g7h5-7qgw","Warn: Project is vulnerable to: GHSA-f7q4-pwc6-w24p","Warn: Project is vulnerable to: GHSA-fc9h-whq2-v747","Warn: Project is vulnerable to: GHSA-vjh7-7g9h-fjfh","Warn: Project is vulnerable to: GHSA-4gmj-3p3h-gm8h","Warn: Project is vulnerable to: GHSA-3gx7-xhv7-5mx3","Warn: Project is vulnerable to: GHSA-6h5x-7c5m-7cr7","Warn: Project is vulnerable to: GHSA-rv95-896h-c2vc","Warn: Project is vulnerable to: GHSA-qw6h-vgh9-j6wx","Warn: Project is vulnerable to: GHSA-74fj-2j2h-c42q","Warn: Project is vulnerable to: GHSA-pw2r-vq6v-hr8c","Warn: Project is vulnerable to: GHSA-jchw-25xp-jwwc","Warn: Project is vulnerable to: GHSA-cxjh-pqwp-8mfp","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-8r6j-v8pm-fqw3","Warn: Project is vulnerable to: MAL-2023-462","Warn: Project is vulnerable to: GHSA-q42p-pg8m-cqh6","Warn: Project is vulnerable to: GHSA-w457-6q6x-cgp9","Warn: Project is vulnerable to: GHSA-62gr-4qp9-h98f","Warn: Project is vulnerable to: GHSA-f52g-6jhx-586p","Warn: Project is vulnerable to: GHSA-2cf5-4w76-r9qv","Warn: Project is vulnerable to: GHSA-3cqr-58rm-57f8","Warn: Project is vulnerable to: GHSA-g9r4-xpmj-mj65","Warn: Project is vulnerable to: GHSA-q2c6-c6pm-g3gh","Warn: Project is vulnerable to: GHSA-765h-qjxv-5f44","Warn: Project is vulnerable to: GHSA-f2jv-r9rf-7988","Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj","Warn: Project is vulnerable to: GHSA-pfq8-rq6v-vf5m","Warn: Project is vulnerable to: GHSA-6x33-pw7p-hmpq","Warn: Project is vulnerable to: GHSA-c7qv-q95q-8v27","Warn: Project is vulnerable to: GHSA-qqgx-2p2h-9c37","Warn: Project is vulnerable to: GHSA-78xj-cgh5-2h22","Warn: Project is vulnerable to: GHSA-2p57-rm9w-gvfp","Warn: Project is vulnerable to: GHSA-2pr6-76vf-7546","Warn: Project is vulnerable to: GHSA-8j8c-7jfh-h6hx","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-6c8f-qphg-qjgp","Warn: Project is vulnerable to: GHSA-76p3-8jx3-jpfq","Warn: Project is vulnerable to: GHSA-3rfm-jhwj-7488","Warn: Project is vulnerable to: GHSA-hhq3-ff78-jv3g","Warn: Project is vulnerable to: GHSA-jf85-cpcp-j695","Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-4xcv-9jjx-gfj3","Warn: Project is vulnerable to: GHSA-7wpw-2hjm-89gp","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-fhjf-83wg-r2j9","Warn: Project is vulnerable to: GHSA-r683-j2x4-v87g","Warn: Project is vulnerable to: GHSA-92xj-mqp7-vmcj","Warn: Project is vulnerable to: GHSA-wxgw-qj99-44c2","Warn: Project is vulnerable to: GHSA-5rrq-pxf6-6jx5","Warn: Project is vulnerable to: GHSA-8fr3-hfg3-gpgp","Warn: Project is vulnerable to: GHSA-gf8q-jrpm-jvxq","Warn: Project is vulnerable to: GHSA-2r2c-g63r-vccr","Warn: Project is vulnerable to: GHSA-cfm4-qjh2-4765","Warn: Project is vulnerable to: GHSA-x4jg-mjrx-434g","Warn: Project is vulnerable to: GHSA-5fw9-fq32-wv5p","Warn: Project is vulnerable to: GHSA-rp65-9cf3-cjxr","Warn: Project is vulnerable to: GHSA-76c9-3jph-rj3q","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-9wv6-86v2-598j","Warn: Project is vulnerable to: GHSA-rhx6-c78j-4q9w","Warn: Project is vulnerable to: GHSA-h7cp-r72f-jxh6","Warn: Project is vulnerable to: GHSA-v62p-rq8g-8h59","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-m6fv-jmcg-4jfg","Warn: Project is vulnerable to: GHSA-cm22-4g7w-348p","Warn: Project is vulnerable to: GHSA-4g88-fppr-53pp","Warn: Project is vulnerable to: GHSA-4jqc-8m5r-9rpr","Warn: Project is vulnerable to: GHSA-c9g6-9335-x697","Warn: Project is vulnerable to: GHSA-3jfq-g458-7qm9","Warn: Project is vulnerable to: GHSA-r628-mhmh-qjhw","Warn: Project is vulnerable to: GHSA-9r2w-394v-53qc","Warn: Project is vulnerable to: GHSA-5955-9wpr-37jh","Warn: Project is vulnerable to: GHSA-qq89-hq3f-393p","Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-jgrx-mgxx-jf9v","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-w5p7-h5w8-2hfq","Warn: Project is vulnerable to: GHSA-7p7h-4mm5-852v","Warn: Project is vulnerable to: GHSA-662x-fhqg-9p8v","Warn: Project is vulnerable to: GHSA-394c-5j6w-4xmx","Warn: Project is vulnerable to: GHSA-78cj-fxph-m83p","Warn: Project is vulnerable to: GHSA-fhg7-m89q-25r3","Warn: Project is vulnerable to: GHSA-cf4h-3jhx-xvhq","Warn: Project is vulnerable to: GHSA-46c4-8wrp-j99v","Warn: Project is vulnerable to: GHSA-9m6j-fcg5-2442","Warn: Project is vulnerable to: GHSA-hh27-ffr2-f2jc","Warn: Project is vulnerable to: GHSA-rqff-837h-mm52","Warn: Project is vulnerable to: GHSA-8v38-pw62-9cw2","Warn: Project is vulnerable to: GHSA-hgjh-723h-mx2j","Warn: Project is vulnerable to: GHSA-jf5r-8hm2-f872","Warn: Project is vulnerable to: GHSA-wr3j-pwj9-hqq6","Warn: Project is vulnerable to: GHSA-cf66-xwfp-gvc4","Warn: Project is vulnerable to: GHSA-4v9v-hfq4-rm2v","Warn: Project is vulnerable to: GHSA-9jgg-88mc-972h","Warn: Project is vulnerable to: GHSA-g78m-2chm-r7qv","Warn: Project is vulnerable to: GHSA-6fc8-4gx4-v693","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q","Warn: Project is vulnerable to: GHSA-c4w7-xm78-47vh","Warn: Project is vulnerable to: GHSA-p9pc-299p-vxgp"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-16T08:06:25.960Z","repository_id":57166284,"created_at":"2025-08-16T08:06:25.960Z","updated_at":"2025-08-16T08:06:25.960Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279005419,"owners_count":26083883,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-10T02:00:06.843Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-04T19:31:32.969Z","updated_at":"2025-10-10T21:40:22.465Z","avatar_url":"https://github.com/Thinkmill.png","language":"JavaScript","readme":"# Pragmatic Forms\nA pragmatic approach to forms in React (Web and Native)\n\n![Build Status](https://travis-ci.org/Thinkmill/pragmatic-forms.svg?branch=master)\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n\n- [Goals](#goals)\n- [Example usage](#example-usage)\n- [The Road to release](#the-road-to-release)\n- [API Documentation](#api-documentation)\n  - [`configureForm: function(options:Object)`](#configureform-functionoptionsobject)\n    - [`initFields: Function(props):  { [fieldName: string]: any }`](#initfields-functionprops---fieldname-string-any-)\n    - [`submit: Function(formData, props, formProps): Promise`](#submit-functionformdata-props-formprops-promise)\n    - [`validate?: Function(formData, props, formProps): { [fieldName: string]: any }`](#validate-functionformdata-props-formprops--fieldname-string-any-)\n    - [`onSuccess?: Function(results, props, formProps): void`](#onsuccess-functionresults-props-formprops-void)\n    - [`onError?: Function`](#onerror-function)\n    - [`onChange?: Function(formData, props, formProps): void`](#onchange-functionformdata-props-formprops-void)\n    - [`onFirstInteraction?: Function(formData, props, formProps): void`](#onfirstinteraction-functionformdata-props-formprops-void)\n  - [The `form` Prop](#the-form-prop)\n    - [`form.isLoading: boolean`](#formisloading-boolean)\n    - [`form.isPristine: boolean`](#formispristine-boolean)\n    - [`form.submitError: any`](#formsubmiterror-any)\n    - [`form.submitResult: any`](#formsubmitresult-any)\n    - [`form.errors: { [fieldName: string]: any }`](#formerrors--fieldname-string-any-)\n    - [`form.hasErrors: boolean`](#formhaserrors-boolean)\n    - [`form.fields: Object`](#formfields-object)\n    - [`form.submit: Function(): void`](#formsubmit-function-void)\n    - [`form.reset: Function() :void`](#formreset-function-void)\n    - [`form.onSubmit: Function(event?: any) :void`](#formonsubmit-functionevent-any-void)\n    - [`form.onReset: Function(event?: any) :void`](#formonreset-functionevent-any-void)\n    - [`form.updateField: Function(name:String, value:any) :void`](#formupdatefield-functionnamestring-valueany-void)\n    - [`form.getInputProps: Function(options): InputProps`](#formgetinputprops-functionoptions-inputprops)\n      - [`options`](#options)\n      - [`InputProps`](#inputprops)\n    - [`form.getFieldProps: Function(options): FieldProps`](#formgetfieldprops-functionoptions-fieldprops)\n    - [`state` (Deprecated)](#state-deprecated)\n    - [`actions` (Deprecated)](#actions-deprecated)\n- [Reference material and prior art](#reference-material-and-prior-art)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n# Goals\n- be simple\n- be declarative\n- be un-magical\n- be performant\n- be just react (and modern JS)\n- work with YOUR state management system\n- work in browser and react-native\n\n# Example usage\n\n```js\nimport { configureForm } from '@thinkmill/pragmatic-forms';\n\nconst RegistrationForm = configureForm({\n\tinitFields: () =\u003e ({\n\t\tname: '',\n\t\temail: '',\n\t}),\n\tvalidate: ({ name }) =\u003e {\n\t\tconst errors = {};\n\t\tif (!name) errors.name = 'Please enter a name';\n\t\tif (!name) errors.email = 'Please enter an email';\n\t\treturn errors;\n\t},\n\tsubmit: (formData) =\u003e {\n\t\treturn fetch('/registration', {\n\t\t\tmethod: 'POST',\n\t\t\tbody: JSON.stringify(formData),\n\t\t})\n\t\t.then(res =\u003e res.json());\n\t},\n})(({ form }) =\u003e (\n\t\u003cform.Form\u003e\n\t\t{form.hasErrors \u0026\u0026\n\t\t\t\u003cdiv\u003e\n\t\t\t\t\u003cp style={{ color: 'red' }}\u003ePlease correct the your input\u003c/p\u003e\n\t\t\t\u003c/div\u003e\n\t\t}\n\t\t\u003cinput {...form.getInputProps({ name: 'name', type: 'text' })} /\u003e\n\t\t\u003cinput {...form.getInputProps({ name: 'email', type: 'email' })} /\u003e\n\t\t\u003cbutton\n\t\t\ttype=\"submit\"\n\t\t\tdisabled={form.hasErrors || form.isLoading}\n\t\t\u003e\n\t\t\tSubmit\n\t\t\u003c/button\u003e\n\t\u003c/form.Form\u003e\n));\n```\n\n# API Documentation\n\nWhen working with `pragmatic-forms` you will be interacting with either the\n`configureForm` method or the `form` prop passed to your component.\n\n## `configureForm: function(options:Object)`\n\nThe `pragmatic-forms` module exports a single named function: `configureForm`. This method creates a configured Higher Order Component to wrap a form providing state and event handlers through a single prop named `form`.\n\n`configureForm` accepts an options object and returns a method for creating a higher order component which will wrap your form to provide state and event handlers.\n\n- `initFields: Function`\n- `submit: Function`\n- `validate?: Function`\n- `onSuccess?: Function`\n- `onReset?: Function`\n- `onError?: Function`\n- `onFirstInteraction?: Function`\n\n### `initFields: Function(props):  { [fieldName: string]: any }`\n**required**\n\nThe `initFields` method will receive props as it's only argument. This method should return an object with key/value pairs that provide the default value for each form field in your form.\n\n\u003e Tip: This is a good place to set a default value for a field to avoid the react warning \"changing an uncontrolled input of type text to be controlled\".\n\neg.\n```js\nconst withForm = configureForm({\n\tinitFields: (props) =\u003e ({\n\t\tname: props.name || '',\n\t\temail: props.email || '',\n\t}),\n\t...\n});\n```\n\n### `submit: Function(formData, props, formProps): Promise`\n**required**\n\nThe `submit` method will be called with `formData`, `props` and `formProps` and should return a promise.\n\neg. Trigger a `graphql` mutation using `react-apollo`\n```js\nimport { graphql, gql, compose} from 'react-apollo';\nimport { configureForm } from 'pragmatic-forms';\n\nconst query = gql`\nmutation createUser (\n\t$name: String!\n\t$email: String!\n) {\n\tcreateUser (user: {\n\t\tname: $name\n\t\temail: $email\n\t})\n\t{\n\t\tid\n\t}\n}\n`;\n\nexport const MyForm = compose(\n\tgraphql(query),\n\tconfigureForm({\n\t\tinitFields: () =\u003e ({ name: '', email: '' }),\n\t\tsubmit: (formData, props) =\u003e {\n\t\t\treturn props.mutate({\n\t\t\t\tvariables: {\n\t\t\t\t\tname: formData.name,\n\t\t\t\t\temail: formData.email,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t})\n)(({ form }) =\u003e (\n\t\u003cform onSubmit={form.onSubmit}\u003e\n\t\t{'...'}\n\t\u003c/form\u003e\n));\n```\n\n### `validate?: Function(formData, props, formProps): { [fieldName: string]: any }`\n_optional_\n\nThe `validate` method receives `formData`, `props` and `props` and returns a map (Object) of errors keyed by the relevant fieldName.\n\neg.\n```js\nconst withForm = configureForm({\n\tinitFields: () =\u003e ({ email: '' }),\n\tsubmit: (formData) =\u003e console.log(formData),\n\tvalidate: (formData, props) =\u003e {\n\t\tconst errors = {};\n\t\tif (!formData.email.includes('@')) {\n\t\t\terrors.email = 'Please enter a valid email address';\n\t\t}\n\t\treturn errors;\n\t},\n});\n```\n\n## Callbacks\n\nCallbacks provide a way to act on the result of an operation or event within the form. All callbacks are called with an event specific value plus the `props` passed to the form and the `formProps` object.\n\n### `onSuccess?: Function(results, props, formProps): void`\n_optional_\n\nThe `onSuccess` method is called after `submit` has **resolved**, the form state has been update and `setState` has been called.\n\nIt receives the result of the `submit` method, `props` and `formProps` as arguments.\n\n### `onError?: Function(reason, props, formProps)`\n_optional_\n\nThe `onError` method is called after `submit` has **rejected**, the form state has been update and `setState` has been called.\n\nIt receives the rejection reason of the `submit` method `props` and `formProps` as arguments.\n\n### `onReset?: Function(formData, props, formProps): void`\n_optional_\n\nThe `onReset` method is called on a form `reset` event after the form has been reinitialised, the form state has been update and `setState` has been called.\n\nIt receives the newly re-initialised `formData`, `props` and `formProps` as arguments.\n\n### `onChange?: Function(formData, props, formProps): void`\n_optional_\n\nThe `onChange` method is called after the internal `setState` is complete when any form field has fired it's `onChange` or `onValueChange` event.\n\nIt receives the complete `formData` object, `props` and `formProps` as arguments.\n\n### `onFirstInteraction?: Function(formData, props, formProps): void`\n_optional_\n\nThe `onFirstInteraction` method is called when a form fields `onChange` handler is triggered.\n\nIt receives the current `formData`, `props` and `formProps`.\n\n## The `form` Prop\n**aka `formProps`**\n\nThe `form` prop provides access to the `state` and `methods` provided by `pragmatic-forms` inside your component. The same object is also passed as the last parameter to each of the `configureForm` methods (excluding `initFields`).\n\n### `form.isLoading: boolean`\n\n`true` if the submit method has been called and the promise has not resolved or rejected. Otherwise `false`\n\n### `form.isPristine: boolean`\n\n`true` until a `change` event is triggered on one or more of the forms inputs.\n\n### `form.submitError: any`\n\n`submitError` is populated with the rejection `reason` if the form submit Promise is `rejected`.\n\n### `form.submitResult: any`\n\n`submitResult` is populated with the resolved value (if any) once the forms submit Promise has `resolved`.\n\n### `form.errors: { [fieldName: string]: any }`\n\nKey-value pairs giving the validation errors for each field by field name.\nThe `value` will be whatever was returned in the validation method.\n\n### `form.hasErrors: boolean`\n\n`true` if the validate method returned an `error` object with at least one property.\n\n### `form.fields: Object`\n\nProvides access to the form fields as they are stored internally in `pragmatic-forms`.\n\nEach field will have the following shape:\n\n```js\n[fieldName: string]: {\n\tvalue: 'field value', // :any - whatever you put in here.\n\tisDirty: false, // Boolean - has the field been modified\n\terror: 'some error', // ?String - a field level error message (provided by the `validate` method)\n}\n```\n\n### `form.submit: Function(): void`\n\nCalling `form.submit` will trigger the submit handler directly.\n\nUse cases:\n- have a form which is not wrapped in a form tag\n- trigger form submission programatically (eg. on a timer)\n\neg. Create a delete button\n\n```js\nconst withForm = configureForm({\n\tinitFields: (props) =\u003e ({ id: props.id }),\n\tsubmit: ({ id }) =\u003e {\n\t\treturn fetch(`/item/${id}`, { method: 'delete' });\n\t}\n})\n\nconst DeleteBtn = withForm(({ form }) =\u003e (\n\t\u003cbutton\n\t\ttype=\"button\"\n\t\tonClick={form.submit}\n\t\tdisabled={form.isLoading}\n\t\u003e\n\t\tDelete me\n\t\u003c/button\u003e\n));\n```\n\n### `form.reset: Function() :void`\n\nCalling `form.reset` will reset the form to it's original state.\n\n### `form.onSubmit: Function(event?: any) :void`\n\nThe `submit` event handler. This should be passed as `onSubmit` to a `\u003cform\u003e` component.\n\neg.\n```js\nconst withForm = configureForm({ ... });\nconst MyForm = withForm(({ form }) =\u003e (\n\t\u003cform onSubmit={form.onSubmit}\u003e\n\t\t...\n\t\t\u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n\t\u003c/form\u003e\n));\n```\n\n### `form.onReset: Function(event?: any) :void`\n\nThe `reset` event handler. This should be passed as `onReset` to a `\u003cform\u003e` component. When the `reset` event is triggered, the form will be reset to it's original state.\n\neg.\n```js\nconst withForm = configureForm({ ... });\nconst MyForm = withForm(({ form }) =\u003e (\n\t\u003cform onReset={form.onReset}\u003e\n\t\t...\n\t\t\u003cbutton type=\"reset\"\u003eReset\u003c/button\u003e\n\t\u003c/form\u003e\n));\n```\n\n### `form.updateField: Function(name:String, value:any) :void`\n\nDirectly update the value of a field by name.\n\n### `form.getInputProps: Function(options): InputProps`\n\nReturns an object with props which can be passed to an `input` component.\n\n\u003e NOTE: For checkboxes it is important to provide the correct type. ie. 'checkbox'. This allows the onChange event handler to check the checked state of the input rather than reading the value.\n\n#### `options`\n - `name: string`\n - `type?: string` Defaults to `\"text\"`\n - `value?:any` TODO: Requires explanation.\n - `checked?: boolean` Whether a checkbox is checked. Defaults to `false`\n - `forceType?: 'string' | 'number' | 'boolean'` undefined by default.\n\nIf `forceType` is true, pragmatic-forms will attempt to maintain the primitive type of the initial value of a field. For example, if `initFields` returns a `boolean` for the field `isEnabled` and `onChange` is called with a `string` it will attempt to convert that string back to a boolean. This can be helpful when your Input component converts the value field type to a string.\n\nCurrently `forceType` supports `string`, `number` and `boolean`.\n\n#### `InputProps`\n - `disabled: boolean` `true` while the form `isLoading`\n - `name: string` whatever was provided in `options`.\n - `type: string` whatever was provided in `options`. Defaults to `text`\n - `onChange: (event) =\u003e void` a change handler\n - `checked: boolean` Only for a `checkbox` or `radio`\n - `value` Not provided for a `checkbox`.\n\n### `form.getFieldProps: Function(options): FieldProps`\n\nTakes the same options as `form.getInputProps`.\n\nIn addition to the props provided by `form.getInputProps` this method also returns props which can be used to show more information on a custom component.\n\n - `error?: string` Either a string error message or `null` if there is no error.\n - `isDirty: boolean` `true` when the field has been modified.\n - `onValueChange: (value: any) =\u003e` a special change handler which accepts the value directly rather than via a change event.\n\n# Build and release\n\n`yarn build` will compile the code which can then be either published or `yarn link`ed if you are developing.\n\nTo release a new version of run `yarn publish`. This will run the `build` script and prompt for a new `version number`.\n\n# Reference material and prior art\n\nMany of the ideas in here are not new. This is a list of some of the places I have taken inspiration from.\n\n- https://github.com/jaredpalmer/formik\n- http://redux-form.com/\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthinkmill%2Fpragmatic-forms","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthinkmill%2Fpragmatic-forms","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthinkmill%2Fpragmatic-forms/lists"}